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
50
51/// destructor
52
54
55std::shared_ptr<const UnwindPlan>
57 std::lock_guard<std::recursive_mutex> guard(m_mutex);
58
59 if (std::shared_ptr<const UnwindPlan> plan_sp =
61 return plan_sp;
62 if (std::shared_ptr<const UnwindPlan> plan_sp =
64 return plan_sp;
65 if (std::shared_ptr<const UnwindPlan> plan_sp =
67 return plan_sp;
68 if (std::shared_ptr<const UnwindPlan> plan_sp = GetEHFrameUnwindPlan(target))
69 return plan_sp;
70 if (std::shared_ptr<const UnwindPlan> plan_sp =
72 return plan_sp;
73 if (std::shared_ptr<const UnwindPlan> plan_sp =
75 return plan_sp;
76
77 return nullptr;
78}
79
80std::shared_ptr<const UnwindPlan>
82 std::lock_guard<std::recursive_mutex> guard(m_mutex);
83 if (m_unwind_plan_compact_unwind.size() > 0)
84 return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact
85 // unwind plans for one func
87 return nullptr;
88
90 // Only continuous functions are supported.
91 if (m_ranges.size() == 1) {
92 Address current_pc(m_ranges[0].GetBaseAddress());
93 CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo();
94 if (compact_unwind) {
95 auto unwind_plan_sp =
96 std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
97 if (compact_unwind->GetUnwindPlan(target, current_pc, *unwind_plan_sp)) {
98 m_unwind_plan_compact_unwind.push_back(unwind_plan_sp);
99 return m_unwind_plan_compact_unwind[0]; // FIXME support multiple
100 // compact unwind plans for one
101 // func
102 }
103 }
104 }
105 return nullptr;
106}
107
108std::shared_ptr<const UnwindPlan>
110 std::lock_guard<std::recursive_mutex> guard(m_mutex);
114
116 if (CallFrameInfo *object_file_frame =
117 m_unwind_table.GetObjectFileUnwindInfo())
119 object_file_frame->GetUnwindPlan(m_ranges, m_addr);
121}
122
123std::shared_ptr<const UnwindPlan>
125 std::lock_guard<std::recursive_mutex> guard(m_mutex);
128
130 if (m_addr.IsValid()) {
131 if (DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo())
132 m_unwind_plan_eh_frame_sp = eh_frame->GetUnwindPlan(m_ranges, m_addr);
133 }
135}
136
137std::shared_ptr<const UnwindPlan>
139 std::lock_guard<std::recursive_mutex> guard(m_mutex);
142
144 if (!m_ranges.empty()) {
145 if (DWARFCallFrameInfo *debug_frame = m_unwind_table.GetDebugFrameInfo())
147 debug_frame->GetUnwindPlan(m_ranges, m_addr);
148 }
150}
151
152std::shared_ptr<const UnwindPlan>
154 std::lock_guard<std::recursive_mutex> guard(m_mutex);
157
159 // Only continuous functions are supported.
160 if (m_ranges.size() == 1) {
161 Address current_pc = m_ranges[0].GetBaseAddress();
162 ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo();
163 if (arm_unwind_info) {
164 auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
165 if (arm_unwind_info->GetUnwindPlan(target, current_pc, *plan_sp))
166 m_unwind_plan_arm_unwind_sp = std::move(plan_sp);
167 }
168 }
170}
171
172namespace {
173class RegisterContextToInfo: public SymbolFile::RegisterInfoResolver {
174public:
175 RegisterContextToInfo(RegisterContext &ctx) : m_ctx(ctx) {}
176
177 const RegisterInfo *ResolveName(llvm::StringRef name) const override {
178 return m_ctx.GetRegisterInfoByName(name);
179 }
180 const RegisterInfo *ResolveNumber(lldb::RegisterKind kind,
181 uint32_t number) const override {
182 return m_ctx.GetRegisterInfo(kind, number);
183 }
184
185private:
186 RegisterContext &m_ctx;
187};
188} // namespace
189
190std::shared_ptr<const UnwindPlan>
192 std::lock_guard<std::recursive_mutex> guard(m_mutex);
195
197 if (SymbolFile *symfile = m_unwind_table.GetSymbolFile();
198 symfile && m_ranges.size() == 1) {
199 m_unwind_plan_symbol_file_sp = symfile->GetUnwindPlan(
200 m_ranges[0].GetBaseAddress(),
201 RegisterContextToInfo(*thread.GetRegisterContext()));
202 }
204}
205
206std::shared_ptr<const UnwindPlan>
208 Thread &thread) {
209 std::lock_guard<std::recursive_mutex> guard(m_mutex);
213
215
216 std::shared_ptr<const UnwindPlan> object_file_unwind_plan =
218 if (!object_file_unwind_plan)
220
221 // Augment the instructions with epilogue descriptions if necessary
222 // so the UnwindPlan can be used at any instruction in the function.
223
224 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
225 // Only continuous functions are supported.
226 if (assembly_profiler_sp && m_ranges.size() == 1) {
227 auto plan_sp = std::make_shared<UnwindPlan>(*object_file_unwind_plan);
228
229 if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_ranges[0], thread,
230 *plan_sp))
231 m_unwind_plan_object_file_augmented_sp = std::move(plan_sp);
232 }
234}
235
236std::shared_ptr<const UnwindPlan>
238 std::lock_guard<std::recursive_mutex> guard(m_mutex);
242
243 // Only supported on x86 architectures where we get eh_frame from the
244 // compiler that describes the prologue instructions perfectly, and sometimes
245 // the epilogue instructions too.
251 }
252
254
255 std::shared_ptr<const UnwindPlan> eh_frame_plan =
256 GetEHFrameUnwindPlan(target);
257 if (!eh_frame_plan)
259
260 // Augment the eh_frame instructions with epilogue descriptions if necessary
261 // so the UnwindPlan can be used at any instruction in the function.
262
263 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
264 // Only continuous functions are supported.
265 if (assembly_profiler_sp && m_ranges.size() == 1) {
266 auto plan_sp = std::make_shared<UnwindPlan>(*eh_frame_plan);
267 if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_ranges[0], thread,
268 *plan_sp))
269 m_unwind_plan_eh_frame_augmented_sp = std::move(plan_sp);
270 }
272}
273
274std::shared_ptr<const UnwindPlan>
276 Thread &thread) {
277 std::lock_guard<std::recursive_mutex> guard(m_mutex);
281
282 // Only supported on x86 architectures where we get debug_frame from the
283 // compiler that describes the prologue instructions perfectly, and sometimes
284 // the epilogue instructions too.
290 }
291
293
294 std::shared_ptr<const UnwindPlan> debug_frame_plan =
296 if (!debug_frame_plan)
298
299 // Augment the debug_frame instructions with epilogue descriptions if
300 // necessary so the UnwindPlan can be used at any instruction in the
301 // function.
302
303 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
304 // Only continuous functions are supported.
305 if (assembly_profiler_sp && m_ranges.size() == 1) {
306 auto plan_sp = std::make_shared<UnwindPlan>(*debug_frame_plan);
307
308 if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_ranges[0], thread,
309 *plan_sp))
310 m_unwind_plan_debug_frame_augmented_sp = std::move(plan_sp);
311 }
313}
314
315std::shared_ptr<const UnwindPlan>
317 std::lock_guard<std::recursive_mutex> guard(m_mutex);
319 !m_unwind_table.GetAllowAssemblyEmulationUnwindPlans()) {
321 }
322
324
325 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
326 // Only continuous functions are supported.
327 if (assembly_profiler_sp && m_ranges.size() == 1) {
328 // Don't analyze more than 10 megabytes of instructions,
329 // if a function is legitimately larger than that, we'll
330 // miss the epilogue instructions, but guard against a
331 // bogusly large function and analyzing large amounts of
332 // non-instruction data.
333 AddressRange range = m_ranges[0];
334 const addr_t func_size =
335 std::min(range.GetByteSize(), (addr_t)1024 * 10 * 10);
336 range.SetByteSize(func_size);
337
338 auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
339 if (assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly(
340 range, thread, *plan_sp))
341 m_unwind_plan_assembly_sp = std::move(plan_sp);
342 }
344}
345
346// This method compares the pc unwind rule in the first row of two UnwindPlans.
347// If they have the same way of getting the pc value (e.g. "CFA - 8" + "CFA is
348// sp"), then it will return LazyBoolTrue.
350 Thread &thread, const std::shared_ptr<const UnwindPlan> &a,
351 const std::shared_ptr<const UnwindPlan> &b) {
352 if (!a || !b)
353 return eLazyBoolCalculate;
354
355 const UnwindPlan::Row *a_first_row = a->GetRowAtIndex(0);
356 const UnwindPlan::Row *b_first_row = b->GetRowAtIndex(0);
357 if (!a_first_row || !b_first_row)
358 return eLazyBoolCalculate;
359
361 uint32_t a_pc_regnum = pc_reg.GetAsKind(a->GetRegisterKind());
362 uint32_t b_pc_regnum = pc_reg.GetAsKind(b->GetRegisterKind());
363
366
367 a_first_row->GetRegisterInfo(a_pc_regnum, a_pc_regloc);
368 b_first_row->GetRegisterInfo(b_pc_regnum, b_pc_regloc);
369
370 if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue())
371 return eLazyBoolNo;
372 if (a_pc_regloc != b_pc_regloc)
373 return eLazyBoolNo;
374
375 return eLazyBoolYes;
376}
377
378std::shared_ptr<const UnwindPlan>
380 std::shared_ptr<const UnwindPlan> eh_frame_sp = GetEHFrameUnwindPlan(target);
381 if (!eh_frame_sp)
382 eh_frame_sp = GetDebugFrameUnwindPlan(target);
383 if (!eh_frame_sp)
384 eh_frame_sp = GetObjectFileUnwindPlan(target);
385 std::shared_ptr<const UnwindPlan> arch_default_at_entry_sp =
387 std::shared_ptr<const UnwindPlan> arch_default_sp =
389 std::shared_ptr<const UnwindPlan> assembly_sp =
390 GetAssemblyUnwindPlan(target, thread);
391
392 // This point of this code is to detect when a function is using a non-
393 // standard ABI, and the eh_frame correctly describes that alternate ABI.
394 // This is addressing a specific situation on x86_64 linux systems where one
395 // function in a library pushes a value on the stack and jumps to another
396 // function. So using an assembly instruction based unwind will not work
397 // when you're in the second function - the stack has been modified in a non-
398 // ABI way. But we have eh_frame that correctly describes how to unwind from
399 // this location. So we're looking to see if the initial pc register save
400 // location from the eh_frame is different from the assembly unwind, the arch
401 // default unwind, and the arch default at initial function entry.
402 //
403 // We may have eh_frame that describes the entire function -- or we may have
404 // eh_frame that only describes the unwind after the prologue has executed --
405 // so we need to check both the arch default (once the prologue has executed)
406 // and the arch default at initial function entry. And we may be running on
407 // a target where we have only some of the assembly/arch default unwind plans
408 // available.
409
411 thread, eh_frame_sp, arch_default_at_entry_sp) == eLazyBoolNo &&
413 thread, eh_frame_sp, arch_default_sp) == eLazyBoolNo &&
415 thread, assembly_sp, arch_default_sp) == eLazyBoolNo) {
416 return eh_frame_sp;
417 }
418
419 if (std::shared_ptr<const UnwindPlan> plan_sp =
421 return plan_sp;
422 if (std::shared_ptr<const UnwindPlan> plan_sp =
423 GetDebugFrameAugmentedUnwindPlan(target, thread))
424 return plan_sp;
425 if (std::shared_ptr<const UnwindPlan> plan_sp =
426 GetEHFrameAugmentedUnwindPlan(target, thread))
427 return plan_sp;
428 if (std::shared_ptr<const UnwindPlan> plan_sp =
429 GetObjectFileAugmentedUnwindPlan(target, thread))
430 return plan_sp;
431
432 return assembly_sp;
433}
434
435std::shared_ptr<const UnwindPlan>
437 std::lock_guard<std::recursive_mutex> guard(m_mutex);
440
441 m_tried_unwind_fast = true;
442
443 UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
444 if (assembly_profiler_sp && m_ranges.size() == 1) {
445 auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
446 if (assembly_profiler_sp->GetFastUnwindPlan(m_ranges[0], thread, *plan_sp))
447 m_unwind_plan_fast_sp = std::move(plan_sp);
448 }
450}
451
452std::shared_ptr<const UnwindPlan>
454 std::lock_guard<std::recursive_mutex> guard(m_mutex);
457
459
460 ProcessSP process_sp(thread.CalculateProcess());
461 if (process_sp) {
462 if (ABI *abi = process_sp->GetABI().get())
463 m_unwind_plan_arch_default_sp = abi->CreateDefaultUnwindPlan();
464 }
465
467}
468
469std::shared_ptr<const UnwindPlan>
471 std::lock_guard<std::recursive_mutex> guard(m_mutex);
475
477
478 Address current_pc;
479 ProcessSP process_sp(thread.CalculateProcess());
480 if (process_sp) {
481 if (ABI *abi = process_sp->GetABI().get()) {
483 abi->CreateFunctionEntryUnwindPlan();
484 }
485 }
486
488}
489
491
494 UnwindAssemblySP assembly_profiler_sp;
495 if (ArchSpec arch = m_unwind_table.GetArchitecture()) {
496 arch.MergeFrom(target.GetArchitecture());
497 assembly_profiler_sp = UnwindAssembly::FindPlugin(arch);
498 }
499 return assembly_profiler_sp;
500}
A class to represent register numbers, and able to convert between different register numbering schem...
uint32_t GetAsKind(lldb::RegisterKind kind)
A section + offset based address range class.
void SetByteSize(lldb::addr_t byte_size)
Set accessor for the byte size of this range.
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
A section + offset based address class.
Definition Address.h:62
An architecture specification class.
Definition ArchSpec.h:31
Core GetCore() const
Definition ArchSpec.h:447
bool GetUnwindPlan(Target &target, const Address &addr, UnwindPlan &unwind_plan)
bool GetUnwindPlan(Target &target, Address addr, UnwindPlan &unwind_plan)
std::shared_ptr< const UnwindPlan > m_unwind_plan_arch_default_sp
std::shared_ptr< const UnwindPlan > GetUnwindPlanFastUnwind(Target &target, lldb_private::Thread &thread)
std::shared_ptr< const UnwindPlan > GetEHFrameAugmentedUnwindPlan(Target &target, Thread &thread)
std::shared_ptr< const UnwindPlan > GetUnwindPlanArchitectureDefault(lldb_private::Thread &thread)
std::shared_ptr< const UnwindPlan > m_unwind_plan_eh_frame_sp
std::shared_ptr< const UnwindPlan > GetAssemblyUnwindPlan(Target &target, Thread &thread)
std::shared_ptr< const UnwindPlan > GetSymbolFileUnwindPlan(Thread &thread)
std::shared_ptr< const UnwindPlan > m_unwind_plan_eh_frame_augmented_sp
std::shared_ptr< const UnwindPlan > GetObjectFileUnwindPlan(Target &target)
const Address & GetFunctionStartAddress() const
std::shared_ptr< const UnwindPlan > m_unwind_plan_object_file_sp
std::shared_ptr< const UnwindPlan > GetObjectFileAugmentedUnwindPlan(Target &target, Thread &thread)
lldb_private::LazyBool CompareUnwindPlansForIdenticalInitialPCLocation(Thread &thread, const std::shared_ptr< const UnwindPlan > &a, const std::shared_ptr< const UnwindPlan > &b)
AddressRanges m_ranges
The address ranges of the function.
std::shared_ptr< const UnwindPlan > m_unwind_plan_object_file_augmented_sp
std::shared_ptr< const UnwindPlan > GetArmUnwindUnwindPlan(Target &target)
std::recursive_mutex m_mutex
std::shared_ptr< const UnwindPlan > GetCompactUnwindUnwindPlan(Target &target)
std::shared_ptr< const UnwindPlan > m_unwind_plan_arch_default_at_func_entry_sp
std::shared_ptr< const UnwindPlan > m_unwind_plan_assembly_sp
std::shared_ptr< const UnwindPlan > m_unwind_plan_fast_sp
std::shared_ptr< const UnwindPlan > m_unwind_plan_debug_frame_sp
std::shared_ptr< const UnwindPlan > GetUnwindPlanAtNonCallSite(Target &target, lldb_private::Thread &thread)
std::shared_ptr< const UnwindPlan > m_unwind_plan_arm_unwind_sp
std::shared_ptr< const UnwindPlan > GetUnwindPlanArchitectureDefaultAtFunctionEntry(lldb_private::Thread &thread)
std::shared_ptr< const UnwindPlan > GetDebugFrameAugmentedUnwindPlan(Target &target, Thread &thread)
std::shared_ptr< const UnwindPlan > m_unwind_plan_debug_frame_augmented_sp
std::vector< std::shared_ptr< const UnwindPlan > > m_unwind_plan_compact_unwind
FuncUnwinders(lldb_private::UnwindTable &unwind_table, Address addr, AddressRanges ranges)
std::shared_ptr< const UnwindPlan > GetEHFrameUnwindPlan(Target &target)
lldb::UnwindAssemblySP GetUnwindAssemblyProfiler(Target &target)
std::shared_ptr< const UnwindPlan > GetUnwindPlanAtCallSite(Target &target, Thread &thread)
std::shared_ptr< const UnwindPlan > GetDebugFrameUnwindPlan(Target &target)
std::shared_ptr< const UnwindPlan > m_unwind_plan_symbol_file_sp
Address m_addr
Start address of the function described by this object.
Provides public interface for all SymbolFiles.
Definition SymbolFile.h:51
const ArchSpec & GetArchitecture() const
Definition Target.h:1067
static lldb::UnwindAssemblySP FindPlugin(const ArchSpec &arch)
const FAValue & GetCFAValue() const
Definition UnwindPlan.h:365
bool GetRegisterInfo(uint32_t reg_num, AbstractRegisterLocation &register_location) const
#define LLDB_REGNUM_GENERIC_PC
A class that represents a running process on the host machine.
std::shared_ptr< lldb_private::Process > ProcessSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::UnwindAssembly > UnwindAssemblySP
RegisterKind
Register numbering types.
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
Every register is described in detail including its name, alternate name (optional),...