501 lines · cpp
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-exception6//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 31using namespace lldb;32using namespace lldb_private;33 34FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, Address addr,35 AddressRanges ranges)36 : m_unwind_table(unwind_table), m_addr(std::move(addr)),37 m_ranges(std::move(ranges)), m_tried_unwind_plan_assembly(false),38 m_tried_unwind_plan_eh_frame(false),39 m_tried_unwind_plan_object_file(false),40 m_tried_unwind_plan_debug_frame(false),41 m_tried_unwind_plan_object_file_augmented(false),42 m_tried_unwind_plan_eh_frame_augmented(false),43 m_tried_unwind_plan_debug_frame_augmented(false),44 m_tried_unwind_plan_compact_unwind(false),45 m_tried_unwind_plan_arm_unwind(false),46 m_tried_unwind_plan_symbol_file(false), m_tried_unwind_fast(false),47 m_tried_unwind_arch_default(false),48 m_tried_unwind_arch_default_at_func_entry(false),49 m_first_non_prologue_insn() {}50 51/// destructor52 53FuncUnwinders::~FuncUnwinders() = default;54 55std::shared_ptr<const UnwindPlan>56FuncUnwinders::GetUnwindPlanAtCallSite(Target &target, Thread &thread) {57 std::lock_guard<std::recursive_mutex> guard(m_mutex);58 59 if (std::shared_ptr<const UnwindPlan> plan_sp =60 GetObjectFileUnwindPlan(target))61 return plan_sp;62 if (std::shared_ptr<const UnwindPlan> plan_sp =63 GetSymbolFileUnwindPlan(thread))64 return plan_sp;65 if (std::shared_ptr<const UnwindPlan> plan_sp =66 GetDebugFrameUnwindPlan(target))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 =71 GetCompactUnwindUnwindPlan(target))72 return plan_sp;73 if (std::shared_ptr<const UnwindPlan> plan_sp =74 GetArmUnwindUnwindPlan(target))75 return plan_sp;76 77 return nullptr;78}79 80std::shared_ptr<const UnwindPlan>81FuncUnwinders::GetCompactUnwindUnwindPlan(Target &target) {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 compact85 // unwind plans for one func86 if (m_tried_unwind_plan_compact_unwind)87 return nullptr;88 89 m_tried_unwind_plan_compact_unwind = true;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 multiple100 // compact unwind plans for one101 // func102 }103 }104 }105 return nullptr;106}107 108std::shared_ptr<const UnwindPlan>109FuncUnwinders::GetObjectFileUnwindPlan(Target &target) {110 std::lock_guard<std::recursive_mutex> guard(m_mutex);111 if (m_unwind_plan_object_file_sp.get() ||112 m_tried_unwind_plan_object_file)113 return m_unwind_plan_object_file_sp;114 115 m_tried_unwind_plan_object_file = true;116 if (CallFrameInfo *object_file_frame =117 m_unwind_table.GetObjectFileUnwindInfo())118 m_unwind_plan_object_file_sp =119 object_file_frame->GetUnwindPlan(m_ranges, m_addr);120 return m_unwind_plan_object_file_sp;121}122 123std::shared_ptr<const UnwindPlan>124FuncUnwinders::GetEHFrameUnwindPlan(Target &target) {125 std::lock_guard<std::recursive_mutex> guard(m_mutex);126 if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame)127 return m_unwind_plan_eh_frame_sp;128 129 m_tried_unwind_plan_eh_frame = true;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 }134 return m_unwind_plan_eh_frame_sp;135}136 137std::shared_ptr<const UnwindPlan>138FuncUnwinders::GetDebugFrameUnwindPlan(Target &target) {139 std::lock_guard<std::recursive_mutex> guard(m_mutex);140 if (m_unwind_plan_debug_frame_sp || m_tried_unwind_plan_debug_frame)141 return m_unwind_plan_debug_frame_sp;142 143 m_tried_unwind_plan_debug_frame = true;144 if (!m_ranges.empty()) {145 if (DWARFCallFrameInfo *debug_frame = m_unwind_table.GetDebugFrameInfo())146 m_unwind_plan_debug_frame_sp =147 debug_frame->GetUnwindPlan(m_ranges, m_addr);148 }149 return m_unwind_plan_debug_frame_sp;150}151 152std::shared_ptr<const UnwindPlan>153FuncUnwinders::GetArmUnwindUnwindPlan(Target &target) {154 std::lock_guard<std::recursive_mutex> guard(m_mutex);155 if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind)156 return m_unwind_plan_arm_unwind_sp;157 158 m_tried_unwind_plan_arm_unwind = true;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 }169 return m_unwind_plan_arm_unwind_sp;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} // namespace189 190std::shared_ptr<const UnwindPlan>191FuncUnwinders::GetSymbolFileUnwindPlan(Thread &thread) {192 std::lock_guard<std::recursive_mutex> guard(m_mutex);193 if (m_unwind_plan_symbol_file_sp.get() || m_tried_unwind_plan_symbol_file)194 return m_unwind_plan_symbol_file_sp;195 196 m_tried_unwind_plan_symbol_file = true;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 }203 return m_unwind_plan_symbol_file_sp;204}205 206std::shared_ptr<const UnwindPlan>207FuncUnwinders::GetObjectFileAugmentedUnwindPlan(Target &target,208 Thread &thread) {209 std::lock_guard<std::recursive_mutex> guard(m_mutex);210 if (m_unwind_plan_object_file_augmented_sp.get() ||211 m_tried_unwind_plan_object_file_augmented)212 return m_unwind_plan_object_file_augmented_sp;213 214 m_tried_unwind_plan_object_file_augmented = true;215 216 std::shared_ptr<const UnwindPlan> object_file_unwind_plan =217 GetObjectFileUnwindPlan(target);218 if (!object_file_unwind_plan)219 return m_unwind_plan_object_file_augmented_sp;220 221 // Augment the instructions with epilogue descriptions if necessary222 // 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 }233 return m_unwind_plan_object_file_augmented_sp;234}235 236std::shared_ptr<const UnwindPlan>237FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target, Thread &thread) {238 std::lock_guard<std::recursive_mutex> guard(m_mutex);239 if (m_unwind_plan_eh_frame_augmented_sp.get() ||240 m_tried_unwind_plan_eh_frame_augmented)241 return m_unwind_plan_eh_frame_augmented_sp;242 243 // Only supported on x86 architectures where we get eh_frame from the244 // compiler that describes the prologue instructions perfectly, and sometimes245 // the epilogue instructions too.246 if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&247 target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&248 target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {249 m_tried_unwind_plan_eh_frame_augmented = true;250 return m_unwind_plan_eh_frame_augmented_sp;251 }252 253 m_tried_unwind_plan_eh_frame_augmented = true;254 255 std::shared_ptr<const UnwindPlan> eh_frame_plan =256 GetEHFrameUnwindPlan(target);257 if (!eh_frame_plan)258 return m_unwind_plan_eh_frame_augmented_sp;259 260 // Augment the eh_frame instructions with epilogue descriptions if necessary261 // 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 }271 return m_unwind_plan_eh_frame_augmented_sp;272}273 274std::shared_ptr<const UnwindPlan>275FuncUnwinders::GetDebugFrameAugmentedUnwindPlan(Target &target,276 Thread &thread) {277 std::lock_guard<std::recursive_mutex> guard(m_mutex);278 if (m_unwind_plan_debug_frame_augmented_sp.get() ||279 m_tried_unwind_plan_debug_frame_augmented)280 return m_unwind_plan_debug_frame_augmented_sp;281 282 // Only supported on x86 architectures where we get debug_frame from the283 // compiler that describes the prologue instructions perfectly, and sometimes284 // the epilogue instructions too.285 if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&286 target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&287 target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {288 m_tried_unwind_plan_debug_frame_augmented = true;289 return m_unwind_plan_debug_frame_augmented_sp;290 }291 292 m_tried_unwind_plan_debug_frame_augmented = true;293 294 std::shared_ptr<const UnwindPlan> debug_frame_plan =295 GetDebugFrameUnwindPlan(target);296 if (!debug_frame_plan)297 return m_unwind_plan_debug_frame_augmented_sp;298 299 // Augment the debug_frame instructions with epilogue descriptions if300 // necessary so the UnwindPlan can be used at any instruction in the301 // 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 }312 return m_unwind_plan_debug_frame_augmented_sp;313}314 315std::shared_ptr<const UnwindPlan>316FuncUnwinders::GetAssemblyUnwindPlan(Target &target, Thread &thread) {317 std::lock_guard<std::recursive_mutex> guard(m_mutex);318 if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly ||319 !m_unwind_table.GetAllowAssemblyEmulationUnwindPlans()) {320 return m_unwind_plan_assembly_sp;321 }322 323 m_tried_unwind_plan_assembly = true;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'll330 // miss the epilogue instructions, but guard against a331 // bogusly large function and analyzing large amounts of332 // 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 }343 return m_unwind_plan_assembly_sp;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 is348// sp"), then it will return LazyBoolTrue.349LazyBool FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation(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 360 RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);361 uint32_t a_pc_regnum = pc_reg.GetAsKind(a->GetRegisterKind());362 uint32_t b_pc_regnum = pc_reg.GetAsKind(b->GetRegisterKind());363 364 UnwindPlan::Row::AbstractRegisterLocation a_pc_regloc;365 UnwindPlan::Row::AbstractRegisterLocation b_pc_regloc;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>379FuncUnwinders::GetUnwindPlanAtNonCallSite(Target &target, Thread &thread) {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 =386 GetUnwindPlanArchitectureDefaultAtFunctionEntry(thread);387 std::shared_ptr<const UnwindPlan> arch_default_sp =388 GetUnwindPlanArchitectureDefault(thread);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 one395 // function in a library pushes a value on the stack and jumps to another396 // function. So using an assembly instruction based unwind will not work397 // 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 from399 // this location. So we're looking to see if the initial pc register save400 // location from the eh_frame is different from the assembly unwind, the arch401 // 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 have404 // 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 on407 // a target where we have only some of the assembly/arch default unwind plans408 // available.409 410 if (CompareUnwindPlansForIdenticalInitialPCLocation(411 thread, eh_frame_sp, arch_default_at_entry_sp) == eLazyBoolNo &&412 CompareUnwindPlansForIdenticalInitialPCLocation(413 thread, eh_frame_sp, arch_default_sp) == eLazyBoolNo &&414 CompareUnwindPlansForIdenticalInitialPCLocation(415 thread, assembly_sp, arch_default_sp) == eLazyBoolNo) {416 return eh_frame_sp;417 }418 419 if (std::shared_ptr<const UnwindPlan> plan_sp =420 GetSymbolFileUnwindPlan(thread))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>436FuncUnwinders::GetUnwindPlanFastUnwind(Target &target, Thread &thread) {437 std::lock_guard<std::recursive_mutex> guard(m_mutex);438 if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)439 return m_unwind_plan_fast_sp;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 }449 return m_unwind_plan_fast_sp;450}451 452std::shared_ptr<const UnwindPlan>453FuncUnwinders::GetUnwindPlanArchitectureDefault(Thread &thread) {454 std::lock_guard<std::recursive_mutex> guard(m_mutex);455 if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default)456 return m_unwind_plan_arch_default_sp;457 458 m_tried_unwind_arch_default = true;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 466 return m_unwind_plan_arch_default_sp;467}468 469std::shared_ptr<const UnwindPlan>470FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread &thread) {471 std::lock_guard<std::recursive_mutex> guard(m_mutex);472 if (m_unwind_plan_arch_default_at_func_entry_sp.get() ||473 m_tried_unwind_arch_default_at_func_entry)474 return m_unwind_plan_arch_default_at_func_entry_sp;475 476 m_tried_unwind_arch_default_at_func_entry = true;477 478 Address current_pc;479 ProcessSP process_sp(thread.CalculateProcess());480 if (process_sp) {481 if (ABI *abi = process_sp->GetABI().get()) {482 m_unwind_plan_arch_default_at_func_entry_sp =483 abi->CreateFunctionEntryUnwindPlan();484 }485 }486 487 return m_unwind_plan_arch_default_at_func_entry_sp;488}489 490const Address &FuncUnwinders::GetFunctionStartAddress() const { return m_addr; }491 492lldb::UnwindAssemblySP493FuncUnwinders::GetUnwindAssemblyProfiler(Target &target) {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}501