LLDB mainline
FuncUnwinders.cpp
Go to the documentation of this file.
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
10#include "lldb/Core/Address.h"
20#include "lldb/Target/ABI.h"
22#include "lldb/Target/Process.h"
25#include "lldb/Target/Target.h"
26#include "lldb/Target/Thread.h"
28
29#include <memory>
30
31using namespace lldb;
32using namespace lldb_private;
33
34/// constructor
35
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
59
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
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
86 return UnwindPlanSP();
87
90 Address current_pc(m_range.GetBaseAddress());
92 if (compact_unwind) {
94 if (compact_unwind->GetUnwindPlan(target, current_pc, *unwind_plan_sp)) {
95 m_unwind_plan_compact_unwind.push_back(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
106 std::lock_guard<std::recursive_mutex> guard(m_mutex);
110
114 if (object_file_frame) {
116 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
117 if (!object_file_frame->GetUnwindPlan(m_range,
120 }
121 }
123}
124
126 std::lock_guard<std::recursive_mutex> guard(m_mutex);
129
133 if (eh_frame) {
135 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
138 }
139 }
141}
142
144 std::lock_guard<std::recursive_mutex> guard(m_mutex);
147
151 if (debug_frame) {
153 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
156 }
157 }
159}
160
162 std::lock_guard<std::recursive_mutex> guard(m_mutex);
165
168 Address current_pc(m_range.GetBaseAddress());
169 ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo();
170 if (arm_unwind_info) {
172 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
173 if (!arm_unwind_info->GetUnwindPlan(target, current_pc,
176 }
177 }
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(name);
188 }
189 const RegisterInfo *ResolveNumber(lldb::RegisterKind kind,
190 uint32_t number) const override {
191 return m_ctx.GetRegisterInfo(kind, number);
192 }
193
194private:
195 RegisterContext &m_ctx;
196};
197} // namespace
198
200 std::lock_guard<std::recursive_mutex> guard(m_mutex);
203
205 if (SymbolFile *symfile = m_unwind_table.GetSymbolFile()) {
206 m_unwind_plan_symbol_file_sp = symfile->GetUnwindPlan(
208 RegisterContextToInfo(*thread.GetRegisterContext()));
209 }
211}
212
215 Thread &thread) {
216 std::lock_guard<std::recursive_mutex> guard(m_mutex);
220
222
223 UnwindPlanSP object_file_unwind_plan = GetObjectFileUnwindPlan(target);
224 if (!object_file_unwind_plan)
226
228 std::make_shared<UnwindPlan>(*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(
238 }
239 } else {
241 }
243}
244
246 Thread &thread) {
247 std::lock_guard<std::recursive_mutex> guard(m_mutex);
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.
260 }
261
263
264 UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan(target);
265 if (!eh_frame_plan)
267
269 std::make_shared<UnwindPlan>(*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(
279 }
280 } else {
282 }
284}
285
287 Thread &thread) {
288 std::lock_guard<std::recursive_mutex> guard(m_mutex);
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.
301 }
302
304
305 UnwindPlanSP debug_frame_plan = GetDebugFrameUnwindPlan(target);
306 if (!debug_frame_plan)
308
310 std::make_shared<UnwindPlan>(*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(
321 }
322 } else
325}
326
328 Thread &thread) {
329 std::lock_guard<std::recursive_mutex> guard(m_mutex);
333 }
334
336
337 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
338 if (assembly_profiler_sp) {
340 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
341 if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly(
344 }
345 }
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.
353 Thread &thread, const UnwindPlanSP &a, const UnwindPlanSP &b) {
354 LazyBool plans_are_identical = eLazyBoolCalculate;
355
357 uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind(eRegisterKindLLDB);
358
359 if (a.get() && b.get()) {
360 UnwindPlan::RowSP a_first_row = a->GetRowAtIndex(0);
361 UnwindPlan::RowSP b_first_row = b->GetRowAtIndex(0);
362
363 if (a_first_row.get() && b_first_row.get()) {
366
367 a_first_row->GetRegisterInfo(pc_reg_lldb_regnum, a_pc_regloc);
368 b_first_row->GetRegisterInfo(pc_reg_lldb_regnum, 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
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 =
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
414 thread, eh_frame_sp, arch_default_at_entry_sp) == eLazyBoolNo &&
416 thread, eh_frame_sp, arch_default_sp) == eLazyBoolNo &&
418 thread, assembly_sp, 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
435 Thread &thread) {
436 std::lock_guard<std::recursive_mutex> guard(m_mutex);
439
440 m_tried_unwind_fast = true;
441
442 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
443 if (assembly_profiler_sp) {
445 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
446 if (!assembly_profiler_sp->GetFastUnwindPlan(m_range, thread,
448 m_unwind_plan_fast_sp.reset();
449 }
450 }
452}
453
455 std::lock_guard<std::recursive_mutex> guard(m_mutex);
458
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) {
467 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
470 }
471 }
472 }
473
475}
476
479 std::lock_guard<std::recursive_mutex> guard(m_mutex);
483
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) {
492 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
496 }
497 }
498 }
499
501}
502
504 std::lock_guard<std::recursive_mutex> guard(m_mutex);
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(m_range, exe_ctx,
514}
515
517 return m_range.GetBaseAddress();
518}
519
522 UnwindAssemblySP assembly_profiler_sp;
524 arch.MergeFrom(target.GetArchitecture());
525 assembly_profiler_sp = UnwindAssembly::FindPlugin(arch);
526 }
527 return assembly_profiler_sp;
528}
529
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
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}
A class to represent register numbers, and able to convert between different register numbering schem...
uint32_t GetAsKind(lldb::RegisterKind kind)
virtual bool CreateDefaultUnwindPlan(UnwindPlan &unwind_plan)=0
virtual bool CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan)=0
A section + offset based address range class.
Definition: AddressRange.h:25
Address & GetBaseAddress()
Get accessor for the base address of the range.
Definition: AddressRange.h:211
A section + offset based address class.
Definition: Address.h:62
bool IsValid() const
Check if the object state is valid.
Definition: Address.h:355
An architecture specification class.
Definition: ArchSpec.h:31
Core GetCore() const
Definition: ArchSpec.h:429
bool GetUnwindPlan(Target &target, const Address &addr, UnwindPlan &unwind_plan)
virtual bool GetUnwindPlan(const Address &addr, UnwindPlan &unwind_plan)=0
bool GetUnwindPlan(Target &target, Address addr, UnwindPlan &unwind_plan)
bool GetUnwindPlan(const Address &addr, UnwindPlan &unwind_plan)
Return an UnwindPlan based on the call frame information encoded in the FDE of this DWARFCallFrameInf...
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
Address & GetFirstNonPrologueInsn(Target &target)
lldb::UnwindPlanSP m_unwind_plan_debug_frame_augmented_sp
lldb::UnwindPlanSP GetAssemblyUnwindPlan(Target &target, Thread &thread)
lldb::UnwindPlanSP GetEHFrameUnwindPlan(Target &target)
lldb::UnwindPlanSP GetUnwindPlanFastUnwind(Target &target, lldb_private::Thread &thread)
std::vector< lldb::UnwindPlanSP > m_unwind_plan_compact_unwind
lldb::UnwindPlanSP GetObjectFileAugmentedUnwindPlan(Target &target, Thread &thread)
Address GetLSDAAddress(Target &target)
lldb::UnwindPlanSP m_unwind_plan_object_file_sp
lldb_private::LazyBool CompareUnwindPlansForIdenticalInitialPCLocation(Thread &thread, const lldb::UnwindPlanSP &a, const lldb::UnwindPlanSP &b)
const Address & GetFunctionStartAddress() const
lldb::UnwindPlanSP m_unwind_plan_assembly_sp
lldb::UnwindPlanSP GetEHFrameAugmentedUnwindPlan(Target &target, Thread &thread)
lldb::UnwindPlanSP GetDebugFrameUnwindPlan(Target &target)
lldb::UnwindPlanSP m_unwind_plan_arch_default_sp
lldb::UnwindPlanSP GetUnwindPlanAtNonCallSite(Target &target, lldb_private::Thread &thread)
lldb::UnwindPlanSP m_unwind_plan_debug_frame_sp
FuncUnwinders(lldb_private::UnwindTable &unwind_table, AddressRange range)
constructor
std::recursive_mutex m_mutex
lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp
lldb::UnwindPlanSP m_unwind_plan_eh_frame_sp
lldb::UnwindPlanSP GetDebugFrameAugmentedUnwindPlan(Target &target, Thread &thread)
Address GetPersonalityRoutinePtrAddress(Target &target)
lldb::UnwindPlanSP m_unwind_plan_arch_default_at_func_entry_sp
lldb::UnwindPlanSP m_unwind_plan_arm_unwind_sp
lldb::UnwindPlanSP GetCompactUnwindUnwindPlan(Target &target)
lldb::UnwindPlanSP GetUnwindPlanArchitectureDefault(lldb_private::Thread &thread)
lldb::UnwindPlanSP m_unwind_plan_fast_sp
lldb::UnwindPlanSP m_unwind_plan_symbol_file_sp
lldb::UnwindAssemblySP GetUnwindAssemblyProfiler(Target &target)
lldb::UnwindPlanSP GetArmUnwindUnwindPlan(Target &target)
lldb::UnwindPlanSP GetObjectFileUnwindPlan(Target &target)
lldb::UnwindPlanSP GetUnwindPlanAtCallSite(Target &target, Thread &thread)
lldb::UnwindPlanSP GetUnwindPlanArchitectureDefaultAtFunctionEntry(lldb_private::Thread &thread)
lldb::UnwindPlanSP m_unwind_plan_object_file_augmented_sp
lldb::UnwindPlanSP GetSymbolFileUnwindPlan(Thread &thread)
Provides public interface for all SymbolFiles.
Definition: SymbolFile.h:50
const ArchSpec & GetArchitecture() const
Definition: Target.h:1028
virtual lldb::RegisterContextSP GetRegisterContext()=0
lldb::ProcessSP CalculateProcess() override
Definition: Thread.cpp:1409
static lldb::UnwindAssemblySP FindPlugin(const ArchSpec &arch)
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:410
lldb_private::DWARFCallFrameInfo * GetEHFrameInfo()
bool GetAllowAssemblyEmulationUnwindPlans()
ArmUnwindInfo * GetArmUnwindInfo()
SymbolFile * GetSymbolFile()
lldb_private::DWARFCallFrameInfo * GetDebugFrameInfo()
lldb_private::CompactUnwindInfo * GetCompactUnwindInfo()
lldb_private::CallFrameInfo * GetObjectFileUnwindInfo()
#define LLDB_REGNUM_GENERIC_PC
Definition: lldb-defines.h:56
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:387
std::shared_ptr< lldb_private::UnwindPlan > UnwindPlanSP
Definition: lldb-forward.h:479
std::shared_ptr< lldb_private::UnwindAssembly > UnwindAssemblySP
Definition: lldb-forward.h:478
RegisterKind
Register numbering types.
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
@ eRegisterKindLLDB
lldb's internal register numbers
Every register is described in detail including its name, alternate name (optional),...