1//===-- FuncUnwinders.cpp -------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Symbol/FuncUnwinders.h"
10#include "lldb/Core/Address.h"
11#include "lldb/Core/AddressRange.h"
12#include "lldb/Symbol/ArmUnwindInfo.h"
13#include "lldb/Symbol/CallFrameInfo.h"
14#include "lldb/Symbol/CompactUnwindInfo.h"
15#include "lldb/Symbol/DWARFCallFrameInfo.h"
16#include "lldb/Symbol/ObjectFile.h"
17#include "lldb/Symbol/SymbolFile.h"
18#include "lldb/Symbol/UnwindPlan.h"
19#include "lldb/Symbol/UnwindTable.h"
20#include "lldb/Target/ABI.h"
21#include "lldb/Target/ExecutionContext.h"
22#include "lldb/Target/Process.h"
23#include "lldb/Target/RegisterContext.h"
24#include "lldb/Target/RegisterNumber.h"
25#include "lldb/Target/Target.h"
26#include "lldb/Target/Thread.h"
27#include "lldb/Target/UnwindAssembly.h"
28
29#include <memory>
30
31using namespace lldb;
32using namespace lldb_private;
33
34/// constructor
35
36FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range)
37 : m_unwind_table(unwind_table), m_range(range), m_mutex(),
38 m_unwind_plan_assembly_sp(), m_unwind_plan_eh_frame_sp(),
39 m_unwind_plan_eh_frame_augmented_sp(), m_unwind_plan_compact_unwind(),
40 m_unwind_plan_arm_unwind_sp(), m_unwind_plan_fast_sp(),
41 m_unwind_plan_arch_default_sp(),
42 m_unwind_plan_arch_default_at_func_entry_sp(),
43 m_tried_unwind_plan_assembly(false), m_tried_unwind_plan_eh_frame(false),
44 m_tried_unwind_plan_object_file(false),
45 m_tried_unwind_plan_debug_frame(false),
46 m_tried_unwind_plan_object_file_augmented(false),
47 m_tried_unwind_plan_eh_frame_augmented(false),
48 m_tried_unwind_plan_debug_frame_augmented(false),
49 m_tried_unwind_plan_compact_unwind(false),
50 m_tried_unwind_plan_arm_unwind(false),
51 m_tried_unwind_plan_symbol_file(false), m_tried_unwind_fast(false),
52 m_tried_unwind_arch_default(false),
53 m_tried_unwind_arch_default_at_func_entry(false),
54 m_first_non_prologue_insn() {}
55
56/// destructor
57
58FuncUnwinders::~FuncUnwinders() = default;
59
60UnwindPlanSP FuncUnwinders::GetUnwindPlanAtCallSite(Target &target,
61 Thread &thread) {
62 std::lock_guard<std::recursive_mutex> guard(m_mutex);
63
64 if (UnwindPlanSP plan_sp = GetObjectFileUnwindPlan(target))
65 return plan_sp;
66 if (UnwindPlanSP plan_sp = GetSymbolFileUnwindPlan(thread))
67 return plan_sp;
68 if (UnwindPlanSP plan_sp = GetDebugFrameUnwindPlan(target))
69 return plan_sp;
70 if (UnwindPlanSP plan_sp = GetEHFrameUnwindPlan(target))
71 return plan_sp;
72 if (UnwindPlanSP plan_sp = GetCompactUnwindUnwindPlan(target))
73 return plan_sp;
74 if (UnwindPlanSP plan_sp = GetArmUnwindUnwindPlan(target))
75 return plan_sp;
76
77 return nullptr;
78}
79
80UnwindPlanSP FuncUnwinders::GetCompactUnwindUnwindPlan(Target &target) {
81 std::lock_guard<std::recursive_mutex> guard(m_mutex);
82 if (m_unwind_plan_compact_unwind.size() > 0)
83 return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact
84 // unwind plans for one func
85 if (m_tried_unwind_plan_compact_unwind)
86 return UnwindPlanSP();
87
88 m_tried_unwind_plan_compact_unwind = true;
89 if (m_range.GetBaseAddress().IsValid()) {
90 Address current_pc(m_range.GetBaseAddress());
91 CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo();
92 if (compact_unwind) {
93 UnwindPlanSP unwind_plan_sp(new UnwindPlan(lldb::eRegisterKindGeneric));
94 if (compact_unwind->GetUnwindPlan(target, addr: current_pc, unwind_plan&: *unwind_plan_sp)) {
95 m_unwind_plan_compact_unwind.push_back(x: unwind_plan_sp);
96 return m_unwind_plan_compact_unwind[0]; // FIXME support multiple
97 // compact unwind plans for one
98 // func
99 }
100 }
101 }
102 return UnwindPlanSP();
103}
104
105lldb::UnwindPlanSP FuncUnwinders::GetObjectFileUnwindPlan(Target &target) {
106 std::lock_guard<std::recursive_mutex> guard(m_mutex);
107 if (m_unwind_plan_object_file_sp.get() ||
108 m_tried_unwind_plan_object_file)
109 return m_unwind_plan_object_file_sp;
110
111 m_tried_unwind_plan_object_file = true;
112 if (m_range.GetBaseAddress().IsValid()) {
113 CallFrameInfo *object_file_frame = m_unwind_table.GetObjectFileUnwindInfo();
114 if (object_file_frame) {
115 m_unwind_plan_object_file_sp =
116 std::make_shared<UnwindPlan>(args: lldb::eRegisterKindGeneric);
117 if (!object_file_frame->GetUnwindPlan(range: m_range,
118 unwind_plan&: *m_unwind_plan_object_file_sp))
119 m_unwind_plan_object_file_sp.reset();
120 }
121 }
122 return m_unwind_plan_object_file_sp;
123}
124
125UnwindPlanSP FuncUnwinders::GetEHFrameUnwindPlan(Target &target) {
126 std::lock_guard<std::recursive_mutex> guard(m_mutex);
127 if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame)
128 return m_unwind_plan_eh_frame_sp;
129
130 m_tried_unwind_plan_eh_frame = true;
131 if (m_range.GetBaseAddress().IsValid()) {
132 DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
133 if (eh_frame) {
134 m_unwind_plan_eh_frame_sp =
135 std::make_shared<UnwindPlan>(args: lldb::eRegisterKindGeneric);
136 if (!eh_frame->GetUnwindPlan(range: m_range, unwind_plan&: *m_unwind_plan_eh_frame_sp))
137 m_unwind_plan_eh_frame_sp.reset();
138 }
139 }
140 return m_unwind_plan_eh_frame_sp;
141}
142
143UnwindPlanSP FuncUnwinders::GetDebugFrameUnwindPlan(Target &target) {
144 std::lock_guard<std::recursive_mutex> guard(m_mutex);
145 if (m_unwind_plan_debug_frame_sp || m_tried_unwind_plan_debug_frame)
146 return m_unwind_plan_debug_frame_sp;
147
148 m_tried_unwind_plan_debug_frame = true;
149 if (m_range.GetBaseAddress().IsValid()) {
150 DWARFCallFrameInfo *debug_frame = m_unwind_table.GetDebugFrameInfo();
151 if (debug_frame) {
152 m_unwind_plan_debug_frame_sp =
153 std::make_shared<UnwindPlan>(args: lldb::eRegisterKindGeneric);
154 if (!debug_frame->GetUnwindPlan(range: m_range, unwind_plan&: *m_unwind_plan_debug_frame_sp))
155 m_unwind_plan_debug_frame_sp.reset();
156 }
157 }
158 return m_unwind_plan_debug_frame_sp;
159}
160
161UnwindPlanSP FuncUnwinders::GetArmUnwindUnwindPlan(Target &target) {
162 std::lock_guard<std::recursive_mutex> guard(m_mutex);
163 if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind)
164 return m_unwind_plan_arm_unwind_sp;
165
166 m_tried_unwind_plan_arm_unwind = true;
167 if (m_range.GetBaseAddress().IsValid()) {
168 Address current_pc(m_range.GetBaseAddress());
169 ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo();
170 if (arm_unwind_info) {
171 m_unwind_plan_arm_unwind_sp =
172 std::make_shared<UnwindPlan>(args: lldb::eRegisterKindGeneric);
173 if (!arm_unwind_info->GetUnwindPlan(target, addr: current_pc,
174 unwind_plan&: *m_unwind_plan_arm_unwind_sp))
175 m_unwind_plan_arm_unwind_sp.reset();
176 }
177 }
178 return m_unwind_plan_arm_unwind_sp;
179}
180
181namespace {
182class RegisterContextToInfo: public SymbolFile::RegisterInfoResolver {
183public:
184 RegisterContextToInfo(RegisterContext &ctx) : m_ctx(ctx) {}
185
186 const RegisterInfo *ResolveName(llvm::StringRef name) const override {
187 return m_ctx.GetRegisterInfoByName(reg_name: name);
188 }
189 const RegisterInfo *ResolveNumber(lldb::RegisterKind kind,
190 uint32_t number) const override {
191 return m_ctx.GetRegisterInfo(reg_kind: kind, reg_num: number);
192 }
193
194private:
195 RegisterContext &m_ctx;
196};
197} // namespace
198
199UnwindPlanSP FuncUnwinders::GetSymbolFileUnwindPlan(Thread &thread) {
200 std::lock_guard<std::recursive_mutex> guard(m_mutex);
201 if (m_unwind_plan_symbol_file_sp.get() || m_tried_unwind_plan_symbol_file)
202 return m_unwind_plan_symbol_file_sp;
203
204 m_tried_unwind_plan_symbol_file = true;
205 if (SymbolFile *symfile = m_unwind_table.GetSymbolFile()) {
206 m_unwind_plan_symbol_file_sp = symfile->GetUnwindPlan(
207 address: m_range.GetBaseAddress(),
208 resolver: RegisterContextToInfo(*thread.GetRegisterContext()));
209 }
210 return m_unwind_plan_symbol_file_sp;
211}
212
213UnwindPlanSP
214FuncUnwinders::GetObjectFileAugmentedUnwindPlan(Target &target,
215 Thread &thread) {
216 std::lock_guard<std::recursive_mutex> guard(m_mutex);
217 if (m_unwind_plan_object_file_augmented_sp.get() ||
218 m_tried_unwind_plan_object_file_augmented)
219 return m_unwind_plan_object_file_augmented_sp;
220
221 m_tried_unwind_plan_object_file_augmented = true;
222
223 UnwindPlanSP object_file_unwind_plan = GetObjectFileUnwindPlan(target);
224 if (!object_file_unwind_plan)
225 return m_unwind_plan_object_file_augmented_sp;
226
227 m_unwind_plan_object_file_augmented_sp =
228 std::make_shared<UnwindPlan>(args&: *object_file_unwind_plan);
229
230 // Augment the instructions with epilogue descriptions if necessary
231 // so the UnwindPlan can be used at any instruction in the function.
232
233 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
234 if (assembly_profiler_sp) {
235 if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
236 func&: m_range, thread, unwind_plan&: *m_unwind_plan_object_file_augmented_sp)) {
237 m_unwind_plan_object_file_augmented_sp.reset();
238 }
239 } else {
240 m_unwind_plan_object_file_augmented_sp.reset();
241 }
242 return m_unwind_plan_object_file_augmented_sp;
243}
244
245UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target,
246 Thread &thread) {
247 std::lock_guard<std::recursive_mutex> guard(m_mutex);
248 if (m_unwind_plan_eh_frame_augmented_sp.get() ||
249 m_tried_unwind_plan_eh_frame_augmented)
250 return m_unwind_plan_eh_frame_augmented_sp;
251
252 // Only supported on x86 architectures where we get eh_frame from the
253 // compiler that describes the prologue instructions perfectly, and sometimes
254 // the epilogue instructions too.
255 if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&
256 target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&
257 target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {
258 m_tried_unwind_plan_eh_frame_augmented = true;
259 return m_unwind_plan_eh_frame_augmented_sp;
260 }
261
262 m_tried_unwind_plan_eh_frame_augmented = true;
263
264 UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan(target);
265 if (!eh_frame_plan)
266 return m_unwind_plan_eh_frame_augmented_sp;
267
268 m_unwind_plan_eh_frame_augmented_sp =
269 std::make_shared<UnwindPlan>(args&: *eh_frame_plan);
270
271 // Augment the eh_frame instructions with epilogue descriptions if necessary
272 // so the UnwindPlan can be used at any instruction in the function.
273
274 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
275 if (assembly_profiler_sp) {
276 if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
277 func&: m_range, thread, unwind_plan&: *m_unwind_plan_eh_frame_augmented_sp)) {
278 m_unwind_plan_eh_frame_augmented_sp.reset();
279 }
280 } else {
281 m_unwind_plan_eh_frame_augmented_sp.reset();
282 }
283 return m_unwind_plan_eh_frame_augmented_sp;
284}
285
286UnwindPlanSP FuncUnwinders::GetDebugFrameAugmentedUnwindPlan(Target &target,
287 Thread &thread) {
288 std::lock_guard<std::recursive_mutex> guard(m_mutex);
289 if (m_unwind_plan_debug_frame_augmented_sp.get() ||
290 m_tried_unwind_plan_debug_frame_augmented)
291 return m_unwind_plan_debug_frame_augmented_sp;
292
293 // Only supported on x86 architectures where we get debug_frame from the
294 // compiler that describes the prologue instructions perfectly, and sometimes
295 // the epilogue instructions too.
296 if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&
297 target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&
298 target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {
299 m_tried_unwind_plan_debug_frame_augmented = true;
300 return m_unwind_plan_debug_frame_augmented_sp;
301 }
302
303 m_tried_unwind_plan_debug_frame_augmented = true;
304
305 UnwindPlanSP debug_frame_plan = GetDebugFrameUnwindPlan(target);
306 if (!debug_frame_plan)
307 return m_unwind_plan_debug_frame_augmented_sp;
308
309 m_unwind_plan_debug_frame_augmented_sp =
310 std::make_shared<UnwindPlan>(args&: *debug_frame_plan);
311
312 // Augment the debug_frame instructions with epilogue descriptions if
313 // necessary so the UnwindPlan can be used at any instruction in the
314 // function.
315
316 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
317 if (assembly_profiler_sp) {
318 if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
319 func&: m_range, thread, unwind_plan&: *m_unwind_plan_debug_frame_augmented_sp)) {
320 m_unwind_plan_debug_frame_augmented_sp.reset();
321 }
322 } else
323 m_unwind_plan_debug_frame_augmented_sp.reset();
324 return m_unwind_plan_debug_frame_augmented_sp;
325}
326
327UnwindPlanSP FuncUnwinders::GetAssemblyUnwindPlan(Target &target,
328 Thread &thread) {
329 std::lock_guard<std::recursive_mutex> guard(m_mutex);
330 if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly ||
331 !m_unwind_table.GetAllowAssemblyEmulationUnwindPlans()) {
332 return m_unwind_plan_assembly_sp;
333 }
334
335 m_tried_unwind_plan_assembly = true;
336
337 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
338 if (assembly_profiler_sp) {
339 m_unwind_plan_assembly_sp =
340 std::make_shared<UnwindPlan>(args: lldb::eRegisterKindGeneric);
341 if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly(
342 func&: m_range, thread, unwind_plan&: *m_unwind_plan_assembly_sp)) {
343 m_unwind_plan_assembly_sp.reset();
344 }
345 }
346 return m_unwind_plan_assembly_sp;
347}
348
349// This method compares the pc unwind rule in the first row of two UnwindPlans.
350// If they have the same way of getting the pc value (e.g. "CFA - 8" + "CFA is
351// sp"), then it will return LazyBoolTrue.
352LazyBool FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation(
353 Thread &thread, const UnwindPlanSP &a, const UnwindPlanSP &b) {
354 LazyBool plans_are_identical = eLazyBoolCalculate;
355
356 RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
357 uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind(kind: eRegisterKindLLDB);
358
359 if (a.get() && b.get()) {
360 UnwindPlan::RowSP a_first_row = a->GetRowAtIndex(idx: 0);
361 UnwindPlan::RowSP b_first_row = b->GetRowAtIndex(idx: 0);
362
363 if (a_first_row.get() && b_first_row.get()) {
364 UnwindPlan::Row::RegisterLocation a_pc_regloc;
365 UnwindPlan::Row::RegisterLocation b_pc_regloc;
366
367 a_first_row->GetRegisterInfo(reg_num: pc_reg_lldb_regnum, register_location&: a_pc_regloc);
368 b_first_row->GetRegisterInfo(reg_num: pc_reg_lldb_regnum, register_location&: b_pc_regloc);
369
370 plans_are_identical = eLazyBoolYes;
371
372 if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) {
373 plans_are_identical = eLazyBoolNo;
374 }
375 if (a_pc_regloc != b_pc_regloc) {
376 plans_are_identical = eLazyBoolNo;
377 }
378 }
379 }
380 return plans_are_identical;
381}
382
383UnwindPlanSP FuncUnwinders::GetUnwindPlanAtNonCallSite(Target &target,
384 Thread &thread) {
385 UnwindPlanSP eh_frame_sp = GetEHFrameUnwindPlan(target);
386 if (!eh_frame_sp)
387 eh_frame_sp = GetDebugFrameUnwindPlan(target);
388 if (!eh_frame_sp)
389 eh_frame_sp = GetObjectFileUnwindPlan(target);
390 UnwindPlanSP arch_default_at_entry_sp =
391 GetUnwindPlanArchitectureDefaultAtFunctionEntry(thread);
392 UnwindPlanSP arch_default_sp = GetUnwindPlanArchitectureDefault(thread);
393 UnwindPlanSP assembly_sp = GetAssemblyUnwindPlan(target, thread);
394
395 // This point of this code is to detect when a function is using a non-
396 // standard ABI, and the eh_frame correctly describes that alternate ABI.
397 // This is addressing a specific situation on x86_64 linux systems where one
398 // function in a library pushes a value on the stack and jumps to another
399 // function. So using an assembly instruction based unwind will not work
400 // when you're in the second function - the stack has been modified in a non-
401 // ABI way. But we have eh_frame that correctly describes how to unwind from
402 // this location. So we're looking to see if the initial pc register save
403 // location from the eh_frame is different from the assembly unwind, the arch
404 // default unwind, and the arch default at initial function entry.
405 //
406 // We may have eh_frame that describes the entire function -- or we may have
407 // eh_frame that only describes the unwind after the prologue has executed --
408 // so we need to check both the arch default (once the prologue has executed)
409 // and the arch default at initial function entry. And we may be running on
410 // a target where we have only some of the assembly/arch default unwind plans
411 // available.
412
413 if (CompareUnwindPlansForIdenticalInitialPCLocation(
414 thread, a: eh_frame_sp, b: arch_default_at_entry_sp) == eLazyBoolNo &&
415 CompareUnwindPlansForIdenticalInitialPCLocation(
416 thread, a: eh_frame_sp, b: arch_default_sp) == eLazyBoolNo &&
417 CompareUnwindPlansForIdenticalInitialPCLocation(
418 thread, a: assembly_sp, b: arch_default_sp) == eLazyBoolNo) {
419 return eh_frame_sp;
420 }
421
422 if (UnwindPlanSP plan_sp = GetSymbolFileUnwindPlan(thread))
423 return plan_sp;
424 if (UnwindPlanSP plan_sp = GetDebugFrameAugmentedUnwindPlan(target, thread))
425 return plan_sp;
426 if (UnwindPlanSP plan_sp = GetEHFrameAugmentedUnwindPlan(target, thread))
427 return plan_sp;
428 if (UnwindPlanSP plan_sp = GetObjectFileAugmentedUnwindPlan(target, thread))
429 return plan_sp;
430
431 return assembly_sp;
432}
433
434UnwindPlanSP FuncUnwinders::GetUnwindPlanFastUnwind(Target &target,
435 Thread &thread) {
436 std::lock_guard<std::recursive_mutex> guard(m_mutex);
437 if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
438 return m_unwind_plan_fast_sp;
439
440 m_tried_unwind_fast = true;
441
442 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
443 if (assembly_profiler_sp) {
444 m_unwind_plan_fast_sp =
445 std::make_shared<UnwindPlan>(args: lldb::eRegisterKindGeneric);
446 if (!assembly_profiler_sp->GetFastUnwindPlan(func&: m_range, thread,
447 unwind_plan&: *m_unwind_plan_fast_sp)) {
448 m_unwind_plan_fast_sp.reset();
449 }
450 }
451 return m_unwind_plan_fast_sp;
452}
453
454UnwindPlanSP FuncUnwinders::GetUnwindPlanArchitectureDefault(Thread &thread) {
455 std::lock_guard<std::recursive_mutex> guard(m_mutex);
456 if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default)
457 return m_unwind_plan_arch_default_sp;
458
459 m_tried_unwind_arch_default = true;
460
461 Address current_pc;
462 ProcessSP process_sp(thread.CalculateProcess());
463 if (process_sp) {
464 ABI *abi = process_sp->GetABI().get();
465 if (abi) {
466 m_unwind_plan_arch_default_sp =
467 std::make_shared<UnwindPlan>(args: lldb::eRegisterKindGeneric);
468 if (!abi->CreateDefaultUnwindPlan(unwind_plan&: *m_unwind_plan_arch_default_sp)) {
469 m_unwind_plan_arch_default_sp.reset();
470 }
471 }
472 }
473
474 return m_unwind_plan_arch_default_sp;
475}
476
477UnwindPlanSP
478FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread &thread) {
479 std::lock_guard<std::recursive_mutex> guard(m_mutex);
480 if (m_unwind_plan_arch_default_at_func_entry_sp.get() ||
481 m_tried_unwind_arch_default_at_func_entry)
482 return m_unwind_plan_arch_default_at_func_entry_sp;
483
484 m_tried_unwind_arch_default_at_func_entry = true;
485
486 Address current_pc;
487 ProcessSP process_sp(thread.CalculateProcess());
488 if (process_sp) {
489 ABI *abi = process_sp->GetABI().get();
490 if (abi) {
491 m_unwind_plan_arch_default_at_func_entry_sp =
492 std::make_shared<UnwindPlan>(args: lldb::eRegisterKindGeneric);
493 if (!abi->CreateFunctionEntryUnwindPlan(
494 unwind_plan&: *m_unwind_plan_arch_default_at_func_entry_sp)) {
495 m_unwind_plan_arch_default_at_func_entry_sp.reset();
496 }
497 }
498 }
499
500 return m_unwind_plan_arch_default_at_func_entry_sp;
501}
502
503Address &FuncUnwinders::GetFirstNonPrologueInsn(Target &target) {
504 std::lock_guard<std::recursive_mutex> guard(m_mutex);
505 if (m_first_non_prologue_insn.IsValid())
506 return m_first_non_prologue_insn;
507
508 ExecutionContext exe_ctx(target.shared_from_this(), false);
509 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
510 if (assembly_profiler_sp)
511 assembly_profiler_sp->FirstNonPrologueInsn(func&: m_range, exe_ctx,
512 first_non_prologue_insn&: m_first_non_prologue_insn);
513 return m_first_non_prologue_insn;
514}
515
516const Address &FuncUnwinders::GetFunctionStartAddress() const {
517 return m_range.GetBaseAddress();
518}
519
520lldb::UnwindAssemblySP
521FuncUnwinders::GetUnwindAssemblyProfiler(Target &target) {
522 UnwindAssemblySP assembly_profiler_sp;
523 if (ArchSpec arch = m_unwind_table.GetArchitecture()) {
524 arch.MergeFrom(other: target.GetArchitecture());
525 assembly_profiler_sp = UnwindAssembly::FindPlugin(arch);
526 }
527 return assembly_profiler_sp;
528}
529
530Address FuncUnwinders::GetLSDAAddress(Target &target) {
531 Address lsda_addr;
532
533 UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan(target);
534 if (unwind_plan_sp.get() == nullptr) {
535 unwind_plan_sp = GetCompactUnwindUnwindPlan(target);
536 }
537 if (unwind_plan_sp.get() == nullptr) {
538 unwind_plan_sp = GetObjectFileUnwindPlan(target);
539 }
540 if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid()) {
541 lsda_addr = unwind_plan_sp->GetLSDAAddress();
542 }
543 return lsda_addr;
544}
545
546Address FuncUnwinders::GetPersonalityRoutinePtrAddress(Target &target) {
547 Address personality_addr;
548
549 UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan(target);
550 if (unwind_plan_sp.get() == nullptr) {
551 unwind_plan_sp = GetCompactUnwindUnwindPlan(target);
552 }
553 if (unwind_plan_sp.get() == nullptr) {
554 unwind_plan_sp = GetObjectFileUnwindPlan(target);
555 }
556 if (unwind_plan_sp.get() &&
557 unwind_plan_sp->GetPersonalityFunctionPtr().IsValid()) {
558 personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr();
559 }
560
561 return personality_addr;
562}
563

source code of lldb/source/Symbol/FuncUnwinders.cpp