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