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