brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · 3aca495 Raw
223 lines · cpp
1//===-- UnwindTable.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/UnwindTable.h"10 11#include <cstdio>12#include <optional>13 14#include "lldb/Core/Module.h"15#include "lldb/Core/Section.h"16#include "lldb/Symbol/ArmUnwindInfo.h"17#include "lldb/Symbol/CallFrameInfo.h"18#include "lldb/Symbol/CompactUnwindInfo.h"19#include "lldb/Symbol/DWARFCallFrameInfo.h"20#include "lldb/Symbol/FuncUnwinders.h"21#include "lldb/Symbol/ObjectFile.h"22#include "lldb/Symbol/SymbolContext.h"23#include "lldb/Symbol/SymbolVendor.h"24 25// There is one UnwindTable object per ObjectFile. It contains a list of Unwind26// objects -- one per function, populated lazily -- for the ObjectFile. Each27// Unwind object has multiple UnwindPlans for different scenarios.28 29using namespace lldb;30using namespace lldb_private;31 32UnwindTable::UnwindTable(Module &module)33    : m_module(module), m_unwinds(), m_scanned_all_unwind_sources(false),34      m_mutex(), m_object_file_unwind_up(), m_eh_frame_up(),35      m_compact_unwind_up(), m_arm_unwind_up() {}36 37// We can't do some of this initialization when the ObjectFile is running its38// ctor; delay doing it until needed for something.39void UnwindTable::Initialize() {40  if (m_scanned_all_unwind_sources)41    return;42 43  std::lock_guard<std::mutex> guard(m_mutex);44 45  if (m_scanned_all_unwind_sources) // check again once we've acquired the lock46    return;47 48  ObjectFile *object_file = m_module.GetObjectFile();49  if (!object_file)50    return;51 52  m_scanned_all_unwind_sources = true;53 54  if (!m_object_file_unwind_up)55    m_object_file_unwind_up = object_file->CreateCallFrameInfo();56 57  SectionList *sl = m_module.GetSectionList();58  if (!sl)59    return;60 61  SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);62  if (!m_eh_frame_up && sect)63    m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>(64        *object_file, sect, DWARFCallFrameInfo::EH);65 66  sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);67  if (!m_debug_frame_up && sect)68    m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>(69        *object_file, sect, DWARFCallFrameInfo::DWARF);70 71  sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);72  if (!m_compact_unwind_up && sect)73    m_compact_unwind_up =74        std::make_unique<CompactUnwindInfo>(*object_file, sect);75 76  sect = sl->FindSectionByType(eSectionTypeARMexidx, true);77  if (!m_arm_unwind_up && sect) {78    SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);79    if (sect_extab.get()) {80      m_arm_unwind_up =81          std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab);82    }83  }84}85 86void UnwindTable::ModuleWasUpdated() {87  std::lock_guard<std::mutex> guard(m_mutex);88  m_scanned_all_unwind_sources = false;89  m_unwinds.clear();90}91 92UnwindTable::~UnwindTable() = default;93 94AddressRanges UnwindTable::GetAddressRanges(const Address &addr,95                                            const SymbolContext &sc) {96  AddressRange range;97 98  // First check the unwind info from the object file plugin99  if (m_object_file_unwind_up &&100      m_object_file_unwind_up->GetAddressRange(addr, range))101    return {range};102 103  // Check the symbol context104  AddressRanges result;105  for (size_t idx = 0;106       sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, idx,107                          false, range) &&108       range.GetBaseAddress().IsValid();109       ++idx)110    result.push_back(range);111  if (!result.empty())112    return result;113 114  // Does the eh_frame unwind info has a function bounds for this addr?115  if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))116    return {range};117 118  // Try debug_frame as well119  if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))120    return {range};121 122  return {};123}124 125static Address GetFunctionOrSymbolAddress(const Address &addr,126                                          const SymbolContext &sc) {127  if (Address result = sc.GetFunctionOrSymbolAddress(); result.IsValid())128    return result;129  return addr;130}131 132FuncUnwindersSP133UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,134                                               const SymbolContext &sc) {135  Initialize();136 137  std::lock_guard<std::mutex> guard(m_mutex);138 139  // There is an UnwindTable per object file, so we can safely use file handles140  addr_t file_addr = addr.GetFileAddress();141  iterator insert_pos = m_unwinds.upper_bound(file_addr);142  if (insert_pos != m_unwinds.begin()) {143    auto pos = std::prev(insert_pos);144    if (pos->second->ContainsAddress(addr))145      return pos->second;146  }147 148  Address start_addr = GetFunctionOrSymbolAddress(addr, sc);149  AddressRanges ranges = GetAddressRanges(addr, sc);150  if (ranges.empty())151    return nullptr;152 153  auto func_unwinder_sp =154      std::make_shared<FuncUnwinders>(*this, start_addr, ranges);155  for (const AddressRange &range : ranges)156    m_unwinds.emplace_hint(insert_pos, range.GetBaseAddress().GetFileAddress(),157                           func_unwinder_sp);158  return func_unwinder_sp;159}160 161// Ignore any existing FuncUnwinders for this function, create a new one and162// don't add it to the UnwindTable.  This is intended for use by target modules163// show-unwind where we want to create new UnwindPlans, not re-use existing164// ones.165FuncUnwindersSP UnwindTable::GetUncachedFuncUnwindersContainingAddress(166    const Address &addr, const SymbolContext &sc) {167  Initialize();168 169  Address start_addr = GetFunctionOrSymbolAddress(addr, sc);170  AddressRanges ranges = GetAddressRanges(addr, sc);171  if (ranges.empty())172    return nullptr;173 174  return std::make_shared<FuncUnwinders>(*this, start_addr, std::move(ranges));175}176 177void UnwindTable::Dump(Stream &s) {178  std::lock_guard<std::mutex> guard(m_mutex);179  s.Format("UnwindTable for '{0}':\n", m_module.GetFileSpec());180  const_iterator begin = m_unwinds.begin();181  const_iterator end = m_unwinds.end();182  for (const_iterator pos = begin; pos != end; ++pos) {183    s.Printf("[%u] 0x%16.16" PRIx64 "\n", (unsigned)std::distance(begin, pos),184             pos->first);185  }186  s.EOL();187}188 189lldb_private::CallFrameInfo *UnwindTable::GetObjectFileUnwindInfo() {190  Initialize();191  return m_object_file_unwind_up.get();192}193 194DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() {195  Initialize();196  return m_eh_frame_up.get();197}198 199DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() {200  Initialize();201  return m_debug_frame_up.get();202}203 204CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() {205  Initialize();206  return m_compact_unwind_up.get();207}208 209ArmUnwindInfo *UnwindTable::GetArmUnwindInfo() {210  Initialize();211  return m_arm_unwind_up.get();212}213 214SymbolFile *UnwindTable::GetSymbolFile() { return m_module.GetSymbolFile(); }215 216ArchSpec UnwindTable::GetArchitecture() { return m_module.GetArchitecture(); }217 218bool UnwindTable::GetAllowAssemblyEmulationUnwindPlans() {219  if (ObjectFile *object_file = m_module.GetObjectFile())220    return object_file->AllowAssemblyEmulationUnwindPlans();221  return false;222}223