xref: /openbsd-src/gnu/llvm/lldb/source/Symbol/FuncUnwinders.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1dda28197Spatrick //===-- FuncUnwinders.cpp -------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Symbol/FuncUnwinders.h"
10061da546Spatrick #include "lldb/Core/Address.h"
11061da546Spatrick #include "lldb/Core/AddressRange.h"
12061da546Spatrick #include "lldb/Symbol/ArmUnwindInfo.h"
13061da546Spatrick #include "lldb/Symbol/CallFrameInfo.h"
14061da546Spatrick #include "lldb/Symbol/CompactUnwindInfo.h"
15061da546Spatrick #include "lldb/Symbol/DWARFCallFrameInfo.h"
16061da546Spatrick #include "lldb/Symbol/ObjectFile.h"
17061da546Spatrick #include "lldb/Symbol/SymbolFile.h"
18061da546Spatrick #include "lldb/Symbol/UnwindPlan.h"
19061da546Spatrick #include "lldb/Symbol/UnwindTable.h"
20061da546Spatrick #include "lldb/Target/ABI.h"
21061da546Spatrick #include "lldb/Target/ExecutionContext.h"
22061da546Spatrick #include "lldb/Target/Process.h"
23061da546Spatrick #include "lldb/Target/RegisterContext.h"
24061da546Spatrick #include "lldb/Target/RegisterNumber.h"
25061da546Spatrick #include "lldb/Target/Target.h"
26061da546Spatrick #include "lldb/Target/Thread.h"
27061da546Spatrick #include "lldb/Target/UnwindAssembly.h"
28061da546Spatrick 
29061da546Spatrick #include <memory>
30061da546Spatrick 
31061da546Spatrick using namespace lldb;
32061da546Spatrick using namespace lldb_private;
33061da546Spatrick 
34061da546Spatrick /// constructor
35061da546Spatrick 
FuncUnwinders(UnwindTable & unwind_table,AddressRange range)36061da546Spatrick FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range)
37061da546Spatrick     : m_unwind_table(unwind_table), m_range(range), m_mutex(),
38061da546Spatrick       m_unwind_plan_assembly_sp(), m_unwind_plan_eh_frame_sp(),
39061da546Spatrick       m_unwind_plan_eh_frame_augmented_sp(), m_unwind_plan_compact_unwind(),
40061da546Spatrick       m_unwind_plan_arm_unwind_sp(), m_unwind_plan_fast_sp(),
41061da546Spatrick       m_unwind_plan_arch_default_sp(),
42061da546Spatrick       m_unwind_plan_arch_default_at_func_entry_sp(),
43061da546Spatrick       m_tried_unwind_plan_assembly(false), m_tried_unwind_plan_eh_frame(false),
44061da546Spatrick       m_tried_unwind_plan_object_file(false),
45061da546Spatrick       m_tried_unwind_plan_debug_frame(false),
46061da546Spatrick       m_tried_unwind_plan_object_file_augmented(false),
47061da546Spatrick       m_tried_unwind_plan_eh_frame_augmented(false),
48061da546Spatrick       m_tried_unwind_plan_debug_frame_augmented(false),
49061da546Spatrick       m_tried_unwind_plan_compact_unwind(false),
50061da546Spatrick       m_tried_unwind_plan_arm_unwind(false),
51061da546Spatrick       m_tried_unwind_plan_symbol_file(false), m_tried_unwind_fast(false),
52061da546Spatrick       m_tried_unwind_arch_default(false),
53061da546Spatrick       m_tried_unwind_arch_default_at_func_entry(false),
54061da546Spatrick       m_first_non_prologue_insn() {}
55061da546Spatrick 
56061da546Spatrick /// destructor
57061da546Spatrick 
58*be691f3bSpatrick FuncUnwinders::~FuncUnwinders() = default;
59061da546Spatrick 
GetUnwindPlanAtCallSite(Target & target,Thread & thread)60061da546Spatrick UnwindPlanSP FuncUnwinders::GetUnwindPlanAtCallSite(Target &target,
61061da546Spatrick                                                     Thread &thread) {
62061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
63061da546Spatrick 
64061da546Spatrick   if (UnwindPlanSP plan_sp = GetObjectFileUnwindPlan(target))
65061da546Spatrick     return plan_sp;
66061da546Spatrick   if (UnwindPlanSP plan_sp = GetSymbolFileUnwindPlan(thread))
67061da546Spatrick     return plan_sp;
68061da546Spatrick   if (UnwindPlanSP plan_sp = GetDebugFrameUnwindPlan(target))
69061da546Spatrick     return plan_sp;
70061da546Spatrick   if (UnwindPlanSP plan_sp = GetEHFrameUnwindPlan(target))
71061da546Spatrick     return plan_sp;
72061da546Spatrick   if (UnwindPlanSP plan_sp = GetCompactUnwindUnwindPlan(target))
73061da546Spatrick     return plan_sp;
74061da546Spatrick   if (UnwindPlanSP plan_sp = GetArmUnwindUnwindPlan(target))
75061da546Spatrick     return plan_sp;
76061da546Spatrick 
77061da546Spatrick   return nullptr;
78061da546Spatrick }
79061da546Spatrick 
GetCompactUnwindUnwindPlan(Target & target)80061da546Spatrick UnwindPlanSP FuncUnwinders::GetCompactUnwindUnwindPlan(Target &target) {
81061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
82061da546Spatrick   if (m_unwind_plan_compact_unwind.size() > 0)
83061da546Spatrick     return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact
84061da546Spatrick                                             // unwind plans for one func
85061da546Spatrick   if (m_tried_unwind_plan_compact_unwind)
86061da546Spatrick     return UnwindPlanSP();
87061da546Spatrick 
88061da546Spatrick   m_tried_unwind_plan_compact_unwind = true;
89061da546Spatrick   if (m_range.GetBaseAddress().IsValid()) {
90061da546Spatrick     Address current_pc(m_range.GetBaseAddress());
91061da546Spatrick     CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo();
92061da546Spatrick     if (compact_unwind) {
93061da546Spatrick       UnwindPlanSP unwind_plan_sp(new UnwindPlan(lldb::eRegisterKindGeneric));
94061da546Spatrick       if (compact_unwind->GetUnwindPlan(target, current_pc, *unwind_plan_sp)) {
95061da546Spatrick         m_unwind_plan_compact_unwind.push_back(unwind_plan_sp);
96061da546Spatrick         return m_unwind_plan_compact_unwind[0]; // FIXME support multiple
97061da546Spatrick                                                 // compact unwind plans for one
98061da546Spatrick                                                 // func
99061da546Spatrick       }
100061da546Spatrick     }
101061da546Spatrick   }
102061da546Spatrick   return UnwindPlanSP();
103061da546Spatrick }
104061da546Spatrick 
GetObjectFileUnwindPlan(Target & target)105061da546Spatrick lldb::UnwindPlanSP FuncUnwinders::GetObjectFileUnwindPlan(Target &target) {
106061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
107061da546Spatrick   if (m_unwind_plan_object_file_sp.get() ||
108061da546Spatrick       m_tried_unwind_plan_object_file)
109061da546Spatrick     return m_unwind_plan_object_file_sp;
110061da546Spatrick 
111061da546Spatrick   m_tried_unwind_plan_object_file = true;
112061da546Spatrick   if (m_range.GetBaseAddress().IsValid()) {
113061da546Spatrick     CallFrameInfo *object_file_frame = m_unwind_table.GetObjectFileUnwindInfo();
114061da546Spatrick     if (object_file_frame) {
115061da546Spatrick       m_unwind_plan_object_file_sp =
116061da546Spatrick           std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
117061da546Spatrick       if (!object_file_frame->GetUnwindPlan(m_range,
118061da546Spatrick                                             *m_unwind_plan_object_file_sp))
119061da546Spatrick         m_unwind_plan_object_file_sp.reset();
120061da546Spatrick     }
121061da546Spatrick   }
122061da546Spatrick   return m_unwind_plan_object_file_sp;
123061da546Spatrick }
124061da546Spatrick 
GetEHFrameUnwindPlan(Target & target)125061da546Spatrick UnwindPlanSP FuncUnwinders::GetEHFrameUnwindPlan(Target &target) {
126061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
127061da546Spatrick   if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame)
128061da546Spatrick     return m_unwind_plan_eh_frame_sp;
129061da546Spatrick 
130061da546Spatrick   m_tried_unwind_plan_eh_frame = true;
131061da546Spatrick   if (m_range.GetBaseAddress().IsValid()) {
132061da546Spatrick     DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
133061da546Spatrick     if (eh_frame) {
134061da546Spatrick       m_unwind_plan_eh_frame_sp =
135061da546Spatrick           std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
136061da546Spatrick       if (!eh_frame->GetUnwindPlan(m_range, *m_unwind_plan_eh_frame_sp))
137061da546Spatrick         m_unwind_plan_eh_frame_sp.reset();
138061da546Spatrick     }
139061da546Spatrick   }
140061da546Spatrick   return m_unwind_plan_eh_frame_sp;
141061da546Spatrick }
142061da546Spatrick 
GetDebugFrameUnwindPlan(Target & target)143061da546Spatrick UnwindPlanSP FuncUnwinders::GetDebugFrameUnwindPlan(Target &target) {
144061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
145061da546Spatrick   if (m_unwind_plan_debug_frame_sp || m_tried_unwind_plan_debug_frame)
146061da546Spatrick     return m_unwind_plan_debug_frame_sp;
147061da546Spatrick 
148061da546Spatrick   m_tried_unwind_plan_debug_frame = true;
149061da546Spatrick   if (m_range.GetBaseAddress().IsValid()) {
150061da546Spatrick     DWARFCallFrameInfo *debug_frame = m_unwind_table.GetDebugFrameInfo();
151061da546Spatrick     if (debug_frame) {
152061da546Spatrick       m_unwind_plan_debug_frame_sp =
153061da546Spatrick           std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
154061da546Spatrick       if (!debug_frame->GetUnwindPlan(m_range, *m_unwind_plan_debug_frame_sp))
155061da546Spatrick         m_unwind_plan_debug_frame_sp.reset();
156061da546Spatrick     }
157061da546Spatrick   }
158061da546Spatrick   return m_unwind_plan_debug_frame_sp;
159061da546Spatrick }
160061da546Spatrick 
GetArmUnwindUnwindPlan(Target & target)161061da546Spatrick UnwindPlanSP FuncUnwinders::GetArmUnwindUnwindPlan(Target &target) {
162061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
163061da546Spatrick   if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind)
164061da546Spatrick     return m_unwind_plan_arm_unwind_sp;
165061da546Spatrick 
166061da546Spatrick   m_tried_unwind_plan_arm_unwind = true;
167061da546Spatrick   if (m_range.GetBaseAddress().IsValid()) {
168061da546Spatrick     Address current_pc(m_range.GetBaseAddress());
169061da546Spatrick     ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo();
170061da546Spatrick     if (arm_unwind_info) {
171061da546Spatrick       m_unwind_plan_arm_unwind_sp =
172061da546Spatrick           std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
173061da546Spatrick       if (!arm_unwind_info->GetUnwindPlan(target, current_pc,
174061da546Spatrick                                           *m_unwind_plan_arm_unwind_sp))
175061da546Spatrick         m_unwind_plan_arm_unwind_sp.reset();
176061da546Spatrick     }
177061da546Spatrick   }
178061da546Spatrick   return m_unwind_plan_arm_unwind_sp;
179061da546Spatrick }
180061da546Spatrick 
181061da546Spatrick namespace {
182061da546Spatrick class RegisterContextToInfo: public SymbolFile::RegisterInfoResolver {
183061da546Spatrick public:
RegisterContextToInfo(RegisterContext & ctx)184061da546Spatrick   RegisterContextToInfo(RegisterContext &ctx) : m_ctx(ctx) {}
185061da546Spatrick 
ResolveName(llvm::StringRef name) const186*be691f3bSpatrick   const RegisterInfo *ResolveName(llvm::StringRef name) const override {
187061da546Spatrick     return m_ctx.GetRegisterInfoByName(name);
188061da546Spatrick   }
ResolveNumber(lldb::RegisterKind kind,uint32_t number) const189061da546Spatrick   const RegisterInfo *ResolveNumber(lldb::RegisterKind kind,
190*be691f3bSpatrick                                     uint32_t number) const override {
191061da546Spatrick     return m_ctx.GetRegisterInfo(kind, number);
192061da546Spatrick   }
193061da546Spatrick 
194061da546Spatrick private:
195061da546Spatrick   RegisterContext &m_ctx;
196061da546Spatrick };
197061da546Spatrick } // namespace
198061da546Spatrick 
GetSymbolFileUnwindPlan(Thread & thread)199061da546Spatrick UnwindPlanSP FuncUnwinders::GetSymbolFileUnwindPlan(Thread &thread) {
200061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
201061da546Spatrick   if (m_unwind_plan_symbol_file_sp.get() || m_tried_unwind_plan_symbol_file)
202061da546Spatrick     return m_unwind_plan_symbol_file_sp;
203061da546Spatrick 
204061da546Spatrick   m_tried_unwind_plan_symbol_file = true;
205061da546Spatrick   if (SymbolFile *symfile = m_unwind_table.GetSymbolFile()) {
206061da546Spatrick     m_unwind_plan_symbol_file_sp = symfile->GetUnwindPlan(
207061da546Spatrick         m_range.GetBaseAddress(),
208061da546Spatrick         RegisterContextToInfo(*thread.GetRegisterContext()));
209061da546Spatrick   }
210061da546Spatrick   return m_unwind_plan_symbol_file_sp;
211061da546Spatrick }
212061da546Spatrick 
213061da546Spatrick UnwindPlanSP
GetObjectFileAugmentedUnwindPlan(Target & target,Thread & thread)214061da546Spatrick FuncUnwinders::GetObjectFileAugmentedUnwindPlan(Target &target,
215061da546Spatrick                                                      Thread &thread) {
216061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
217061da546Spatrick   if (m_unwind_plan_object_file_augmented_sp.get() ||
218061da546Spatrick       m_tried_unwind_plan_object_file_augmented)
219061da546Spatrick     return m_unwind_plan_object_file_augmented_sp;
220061da546Spatrick 
221061da546Spatrick   m_tried_unwind_plan_object_file_augmented = true;
222061da546Spatrick 
223061da546Spatrick   UnwindPlanSP object_file_unwind_plan = GetObjectFileUnwindPlan(target);
224061da546Spatrick   if (!object_file_unwind_plan)
225061da546Spatrick     return m_unwind_plan_object_file_augmented_sp;
226061da546Spatrick 
227061da546Spatrick   m_unwind_plan_object_file_augmented_sp =
228061da546Spatrick       std::make_shared<UnwindPlan>(*object_file_unwind_plan);
229061da546Spatrick 
230061da546Spatrick   // Augment the instructions with epilogue descriptions if necessary
231061da546Spatrick   // so the UnwindPlan can be used at any instruction in the function.
232061da546Spatrick 
233061da546Spatrick   UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
234061da546Spatrick   if (assembly_profiler_sp) {
235061da546Spatrick     if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
236061da546Spatrick             m_range, thread, *m_unwind_plan_object_file_augmented_sp)) {
237061da546Spatrick       m_unwind_plan_object_file_augmented_sp.reset();
238061da546Spatrick     }
239061da546Spatrick   } else {
240061da546Spatrick     m_unwind_plan_object_file_augmented_sp.reset();
241061da546Spatrick   }
242061da546Spatrick   return m_unwind_plan_object_file_augmented_sp;
243061da546Spatrick }
244061da546Spatrick 
GetEHFrameAugmentedUnwindPlan(Target & target,Thread & thread)245061da546Spatrick UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target,
246061da546Spatrick                                                           Thread &thread) {
247061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
248061da546Spatrick   if (m_unwind_plan_eh_frame_augmented_sp.get() ||
249061da546Spatrick       m_tried_unwind_plan_eh_frame_augmented)
250061da546Spatrick     return m_unwind_plan_eh_frame_augmented_sp;
251061da546Spatrick 
252061da546Spatrick   // Only supported on x86 architectures where we get eh_frame from the
253061da546Spatrick   // compiler that describes the prologue instructions perfectly, and sometimes
254061da546Spatrick   // the epilogue instructions too.
255061da546Spatrick   if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&
256061da546Spatrick       target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&
257061da546Spatrick       target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {
258061da546Spatrick     m_tried_unwind_plan_eh_frame_augmented = true;
259061da546Spatrick     return m_unwind_plan_eh_frame_augmented_sp;
260061da546Spatrick   }
261061da546Spatrick 
262061da546Spatrick   m_tried_unwind_plan_eh_frame_augmented = true;
263061da546Spatrick 
264061da546Spatrick   UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan(target);
265061da546Spatrick   if (!eh_frame_plan)
266061da546Spatrick     return m_unwind_plan_eh_frame_augmented_sp;
267061da546Spatrick 
268061da546Spatrick   m_unwind_plan_eh_frame_augmented_sp =
269061da546Spatrick       std::make_shared<UnwindPlan>(*eh_frame_plan);
270061da546Spatrick 
271061da546Spatrick   // Augment the eh_frame instructions with epilogue descriptions if necessary
272061da546Spatrick   // so the UnwindPlan can be used at any instruction in the function.
273061da546Spatrick 
274061da546Spatrick   UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
275061da546Spatrick   if (assembly_profiler_sp) {
276061da546Spatrick     if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
277061da546Spatrick             m_range, thread, *m_unwind_plan_eh_frame_augmented_sp)) {
278061da546Spatrick       m_unwind_plan_eh_frame_augmented_sp.reset();
279061da546Spatrick     }
280061da546Spatrick   } else {
281061da546Spatrick     m_unwind_plan_eh_frame_augmented_sp.reset();
282061da546Spatrick   }
283061da546Spatrick   return m_unwind_plan_eh_frame_augmented_sp;
284061da546Spatrick }
285061da546Spatrick 
GetDebugFrameAugmentedUnwindPlan(Target & target,Thread & thread)286061da546Spatrick UnwindPlanSP FuncUnwinders::GetDebugFrameAugmentedUnwindPlan(Target &target,
287061da546Spatrick                                                              Thread &thread) {
288061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
289061da546Spatrick   if (m_unwind_plan_debug_frame_augmented_sp.get() ||
290061da546Spatrick       m_tried_unwind_plan_debug_frame_augmented)
291061da546Spatrick     return m_unwind_plan_debug_frame_augmented_sp;
292061da546Spatrick 
293061da546Spatrick   // Only supported on x86 architectures where we get debug_frame from the
294061da546Spatrick   // compiler that describes the prologue instructions perfectly, and sometimes
295061da546Spatrick   // the epilogue instructions too.
296061da546Spatrick   if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&
297061da546Spatrick       target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&
298061da546Spatrick       target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {
299061da546Spatrick     m_tried_unwind_plan_debug_frame_augmented = true;
300061da546Spatrick     return m_unwind_plan_debug_frame_augmented_sp;
301061da546Spatrick   }
302061da546Spatrick 
303061da546Spatrick   m_tried_unwind_plan_debug_frame_augmented = true;
304061da546Spatrick 
305061da546Spatrick   UnwindPlanSP debug_frame_plan = GetDebugFrameUnwindPlan(target);
306061da546Spatrick   if (!debug_frame_plan)
307061da546Spatrick     return m_unwind_plan_debug_frame_augmented_sp;
308061da546Spatrick 
309061da546Spatrick   m_unwind_plan_debug_frame_augmented_sp =
310061da546Spatrick       std::make_shared<UnwindPlan>(*debug_frame_plan);
311061da546Spatrick 
312061da546Spatrick   // Augment the debug_frame instructions with epilogue descriptions if
313061da546Spatrick   // necessary so the UnwindPlan can be used at any instruction in the
314061da546Spatrick   // function.
315061da546Spatrick 
316061da546Spatrick   UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
317061da546Spatrick   if (assembly_profiler_sp) {
318061da546Spatrick     if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
319061da546Spatrick             m_range, thread, *m_unwind_plan_debug_frame_augmented_sp)) {
320061da546Spatrick       m_unwind_plan_debug_frame_augmented_sp.reset();
321061da546Spatrick     }
322061da546Spatrick   } else
323061da546Spatrick     m_unwind_plan_debug_frame_augmented_sp.reset();
324061da546Spatrick   return m_unwind_plan_debug_frame_augmented_sp;
325061da546Spatrick }
326061da546Spatrick 
GetAssemblyUnwindPlan(Target & target,Thread & thread)327061da546Spatrick UnwindPlanSP FuncUnwinders::GetAssemblyUnwindPlan(Target &target,
328061da546Spatrick                                                   Thread &thread) {
329061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
330061da546Spatrick   if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly ||
331061da546Spatrick       !m_unwind_table.GetAllowAssemblyEmulationUnwindPlans()) {
332061da546Spatrick     return m_unwind_plan_assembly_sp;
333061da546Spatrick   }
334061da546Spatrick 
335061da546Spatrick   m_tried_unwind_plan_assembly = true;
336061da546Spatrick 
337061da546Spatrick   UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
338061da546Spatrick   if (assembly_profiler_sp) {
339061da546Spatrick     m_unwind_plan_assembly_sp =
340061da546Spatrick         std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
341061da546Spatrick     if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly(
342061da546Spatrick             m_range, thread, *m_unwind_plan_assembly_sp)) {
343061da546Spatrick       m_unwind_plan_assembly_sp.reset();
344061da546Spatrick     }
345061da546Spatrick   }
346061da546Spatrick   return m_unwind_plan_assembly_sp;
347061da546Spatrick }
348061da546Spatrick 
349061da546Spatrick // This method compares the pc unwind rule in the first row of two UnwindPlans.
350061da546Spatrick // If they have the same way of getting the pc value (e.g. "CFA - 8" + "CFA is
351061da546Spatrick // sp"), then it will return LazyBoolTrue.
CompareUnwindPlansForIdenticalInitialPCLocation(Thread & thread,const UnwindPlanSP & a,const UnwindPlanSP & b)352061da546Spatrick LazyBool FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation(
353061da546Spatrick     Thread &thread, const UnwindPlanSP &a, const UnwindPlanSP &b) {
354061da546Spatrick   LazyBool plans_are_identical = eLazyBoolCalculate;
355061da546Spatrick 
356061da546Spatrick   RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
357061da546Spatrick   uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind(eRegisterKindLLDB);
358061da546Spatrick 
359061da546Spatrick   if (a.get() && b.get()) {
360061da546Spatrick     UnwindPlan::RowSP a_first_row = a->GetRowAtIndex(0);
361061da546Spatrick     UnwindPlan::RowSP b_first_row = b->GetRowAtIndex(0);
362061da546Spatrick 
363061da546Spatrick     if (a_first_row.get() && b_first_row.get()) {
364061da546Spatrick       UnwindPlan::Row::RegisterLocation a_pc_regloc;
365061da546Spatrick       UnwindPlan::Row::RegisterLocation b_pc_regloc;
366061da546Spatrick 
367061da546Spatrick       a_first_row->GetRegisterInfo(pc_reg_lldb_regnum, a_pc_regloc);
368061da546Spatrick       b_first_row->GetRegisterInfo(pc_reg_lldb_regnum, b_pc_regloc);
369061da546Spatrick 
370061da546Spatrick       plans_are_identical = eLazyBoolYes;
371061da546Spatrick 
372061da546Spatrick       if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) {
373061da546Spatrick         plans_are_identical = eLazyBoolNo;
374061da546Spatrick       }
375061da546Spatrick       if (a_pc_regloc != b_pc_regloc) {
376061da546Spatrick         plans_are_identical = eLazyBoolNo;
377061da546Spatrick       }
378061da546Spatrick     }
379061da546Spatrick   }
380061da546Spatrick   return plans_are_identical;
381061da546Spatrick }
382061da546Spatrick 
GetUnwindPlanAtNonCallSite(Target & target,Thread & thread)383061da546Spatrick UnwindPlanSP FuncUnwinders::GetUnwindPlanAtNonCallSite(Target &target,
384061da546Spatrick                                                        Thread &thread) {
385061da546Spatrick   UnwindPlanSP eh_frame_sp = GetEHFrameUnwindPlan(target);
386061da546Spatrick   if (!eh_frame_sp)
387061da546Spatrick     eh_frame_sp = GetDebugFrameUnwindPlan(target);
388061da546Spatrick   if (!eh_frame_sp)
389061da546Spatrick     eh_frame_sp = GetObjectFileUnwindPlan(target);
390061da546Spatrick   UnwindPlanSP arch_default_at_entry_sp =
391061da546Spatrick       GetUnwindPlanArchitectureDefaultAtFunctionEntry(thread);
392061da546Spatrick   UnwindPlanSP arch_default_sp = GetUnwindPlanArchitectureDefault(thread);
393061da546Spatrick   UnwindPlanSP assembly_sp = GetAssemblyUnwindPlan(target, thread);
394061da546Spatrick 
395061da546Spatrick   // This point of this code is to detect when a function is using a non-
396061da546Spatrick   // standard ABI, and the eh_frame correctly describes that alternate ABI.
397061da546Spatrick   // This is addressing a specific situation on x86_64 linux systems where one
398061da546Spatrick   // function in a library pushes a value on the stack and jumps to another
399061da546Spatrick   // function.  So using an assembly instruction based unwind will not work
400061da546Spatrick   // when you're in the second function - the stack has been modified in a non-
401061da546Spatrick   // ABI way.  But we have eh_frame that correctly describes how to unwind from
402061da546Spatrick   // this location.  So we're looking to see if the initial pc register save
403061da546Spatrick   // location from the eh_frame is different from the assembly unwind, the arch
404061da546Spatrick   // default unwind, and the arch default at initial function entry.
405061da546Spatrick   //
406061da546Spatrick   // We may have eh_frame that describes the entire function -- or we may have
407061da546Spatrick   // eh_frame that only describes the unwind after the prologue has executed --
408061da546Spatrick   // so we need to check both the arch default (once the prologue has executed)
409061da546Spatrick   // and the arch default at initial function entry.  And we may be running on
410061da546Spatrick   // a target where we have only some of the assembly/arch default unwind plans
411061da546Spatrick   // available.
412061da546Spatrick 
413061da546Spatrick   if (CompareUnwindPlansForIdenticalInitialPCLocation(
414061da546Spatrick           thread, eh_frame_sp, arch_default_at_entry_sp) == eLazyBoolNo &&
415061da546Spatrick       CompareUnwindPlansForIdenticalInitialPCLocation(
416061da546Spatrick           thread, eh_frame_sp, arch_default_sp) == eLazyBoolNo &&
417061da546Spatrick       CompareUnwindPlansForIdenticalInitialPCLocation(
418061da546Spatrick           thread, assembly_sp, arch_default_sp) == eLazyBoolNo) {
419061da546Spatrick     return eh_frame_sp;
420061da546Spatrick   }
421061da546Spatrick 
422061da546Spatrick   if (UnwindPlanSP plan_sp = GetSymbolFileUnwindPlan(thread))
423061da546Spatrick     return plan_sp;
424061da546Spatrick   if (UnwindPlanSP plan_sp = GetDebugFrameAugmentedUnwindPlan(target, thread))
425061da546Spatrick     return plan_sp;
426061da546Spatrick   if (UnwindPlanSP plan_sp = GetEHFrameAugmentedUnwindPlan(target, thread))
427061da546Spatrick     return plan_sp;
428061da546Spatrick   if (UnwindPlanSP plan_sp = GetObjectFileAugmentedUnwindPlan(target, thread))
429061da546Spatrick     return plan_sp;
430061da546Spatrick 
431061da546Spatrick   return assembly_sp;
432061da546Spatrick }
433061da546Spatrick 
GetUnwindPlanFastUnwind(Target & target,Thread & thread)434061da546Spatrick UnwindPlanSP FuncUnwinders::GetUnwindPlanFastUnwind(Target &target,
435061da546Spatrick                                                     Thread &thread) {
436061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
437061da546Spatrick   if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
438061da546Spatrick     return m_unwind_plan_fast_sp;
439061da546Spatrick 
440061da546Spatrick   m_tried_unwind_fast = true;
441061da546Spatrick 
442061da546Spatrick   UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
443061da546Spatrick   if (assembly_profiler_sp) {
444061da546Spatrick     m_unwind_plan_fast_sp =
445061da546Spatrick         std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
446061da546Spatrick     if (!assembly_profiler_sp->GetFastUnwindPlan(m_range, thread,
447061da546Spatrick                                                  *m_unwind_plan_fast_sp)) {
448061da546Spatrick       m_unwind_plan_fast_sp.reset();
449061da546Spatrick     }
450061da546Spatrick   }
451061da546Spatrick   return m_unwind_plan_fast_sp;
452061da546Spatrick }
453061da546Spatrick 
GetUnwindPlanArchitectureDefault(Thread & thread)454061da546Spatrick UnwindPlanSP FuncUnwinders::GetUnwindPlanArchitectureDefault(Thread &thread) {
455061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
456061da546Spatrick   if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default)
457061da546Spatrick     return m_unwind_plan_arch_default_sp;
458061da546Spatrick 
459061da546Spatrick   m_tried_unwind_arch_default = true;
460061da546Spatrick 
461061da546Spatrick   Address current_pc;
462061da546Spatrick   ProcessSP process_sp(thread.CalculateProcess());
463061da546Spatrick   if (process_sp) {
464061da546Spatrick     ABI *abi = process_sp->GetABI().get();
465061da546Spatrick     if (abi) {
466061da546Spatrick       m_unwind_plan_arch_default_sp =
467061da546Spatrick           std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
468061da546Spatrick       if (!abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp)) {
469061da546Spatrick         m_unwind_plan_arch_default_sp.reset();
470061da546Spatrick       }
471061da546Spatrick     }
472061da546Spatrick   }
473061da546Spatrick 
474061da546Spatrick   return m_unwind_plan_arch_default_sp;
475061da546Spatrick }
476061da546Spatrick 
477061da546Spatrick UnwindPlanSP
GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread & thread)478061da546Spatrick FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread &thread) {
479061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
480061da546Spatrick   if (m_unwind_plan_arch_default_at_func_entry_sp.get() ||
481061da546Spatrick       m_tried_unwind_arch_default_at_func_entry)
482061da546Spatrick     return m_unwind_plan_arch_default_at_func_entry_sp;
483061da546Spatrick 
484061da546Spatrick   m_tried_unwind_arch_default_at_func_entry = true;
485061da546Spatrick 
486061da546Spatrick   Address current_pc;
487061da546Spatrick   ProcessSP process_sp(thread.CalculateProcess());
488061da546Spatrick   if (process_sp) {
489061da546Spatrick     ABI *abi = process_sp->GetABI().get();
490061da546Spatrick     if (abi) {
491061da546Spatrick       m_unwind_plan_arch_default_at_func_entry_sp =
492061da546Spatrick           std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
493061da546Spatrick       if (!abi->CreateFunctionEntryUnwindPlan(
494061da546Spatrick               *m_unwind_plan_arch_default_at_func_entry_sp)) {
495061da546Spatrick         m_unwind_plan_arch_default_at_func_entry_sp.reset();
496061da546Spatrick       }
497061da546Spatrick     }
498061da546Spatrick   }
499061da546Spatrick 
500061da546Spatrick   return m_unwind_plan_arch_default_at_func_entry_sp;
501061da546Spatrick }
502061da546Spatrick 
GetFirstNonPrologueInsn(Target & target)503061da546Spatrick Address &FuncUnwinders::GetFirstNonPrologueInsn(Target &target) {
504061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
505061da546Spatrick   if (m_first_non_prologue_insn.IsValid())
506061da546Spatrick     return m_first_non_prologue_insn;
507061da546Spatrick 
508061da546Spatrick   ExecutionContext exe_ctx(target.shared_from_this(), false);
509061da546Spatrick   UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
510061da546Spatrick   if (assembly_profiler_sp)
511061da546Spatrick     assembly_profiler_sp->FirstNonPrologueInsn(m_range, exe_ctx,
512061da546Spatrick                                                m_first_non_prologue_insn);
513061da546Spatrick   return m_first_non_prologue_insn;
514061da546Spatrick }
515061da546Spatrick 
GetFunctionStartAddress() const516061da546Spatrick const Address &FuncUnwinders::GetFunctionStartAddress() const {
517061da546Spatrick   return m_range.GetBaseAddress();
518061da546Spatrick }
519061da546Spatrick 
520061da546Spatrick lldb::UnwindAssemblySP
GetUnwindAssemblyProfiler(Target & target)521061da546Spatrick FuncUnwinders::GetUnwindAssemblyProfiler(Target &target) {
522061da546Spatrick   UnwindAssemblySP assembly_profiler_sp;
523061da546Spatrick   if (ArchSpec arch = m_unwind_table.GetArchitecture()) {
524061da546Spatrick     arch.MergeFrom(target.GetArchitecture());
525061da546Spatrick     assembly_profiler_sp = UnwindAssembly::FindPlugin(arch);
526061da546Spatrick   }
527061da546Spatrick   return assembly_profiler_sp;
528061da546Spatrick }
529061da546Spatrick 
GetLSDAAddress(Target & target)530061da546Spatrick Address FuncUnwinders::GetLSDAAddress(Target &target) {
531061da546Spatrick   Address lsda_addr;
532061da546Spatrick 
533061da546Spatrick   UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan(target);
534061da546Spatrick   if (unwind_plan_sp.get() == nullptr) {
535061da546Spatrick     unwind_plan_sp = GetCompactUnwindUnwindPlan(target);
536061da546Spatrick   }
537061da546Spatrick   if (unwind_plan_sp.get() == nullptr) {
538061da546Spatrick     unwind_plan_sp = GetObjectFileUnwindPlan(target);
539061da546Spatrick   }
540061da546Spatrick   if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid()) {
541061da546Spatrick     lsda_addr = unwind_plan_sp->GetLSDAAddress();
542061da546Spatrick   }
543061da546Spatrick   return lsda_addr;
544061da546Spatrick }
545061da546Spatrick 
GetPersonalityRoutinePtrAddress(Target & target)546061da546Spatrick Address FuncUnwinders::GetPersonalityRoutinePtrAddress(Target &target) {
547061da546Spatrick   Address personality_addr;
548061da546Spatrick 
549061da546Spatrick   UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan(target);
550061da546Spatrick   if (unwind_plan_sp.get() == nullptr) {
551061da546Spatrick     unwind_plan_sp = GetCompactUnwindUnwindPlan(target);
552061da546Spatrick   }
553061da546Spatrick   if (unwind_plan_sp.get() == nullptr) {
554061da546Spatrick     unwind_plan_sp = GetObjectFileUnwindPlan(target);
555061da546Spatrick   }
556061da546Spatrick   if (unwind_plan_sp.get() &&
557061da546Spatrick       unwind_plan_sp->GetPersonalityFunctionPtr().IsValid()) {
558061da546Spatrick     personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr();
559061da546Spatrick   }
560061da546Spatrick 
561061da546Spatrick   return personality_addr;
562061da546Spatrick }
563