brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.6 KiB · fffc35d Raw
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