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