Path: blob/main/contrib/llvm-project/lldb/source/Symbol/UnwindTable.cpp
39587 views
//===-- UnwindTable.cpp ---------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Symbol/UnwindTable.h"910#include <cstdio>11#include <optional>1213#include "lldb/Core/Module.h"14#include "lldb/Core/Section.h"15#include "lldb/Symbol/ArmUnwindInfo.h"16#include "lldb/Symbol/CallFrameInfo.h"17#include "lldb/Symbol/CompactUnwindInfo.h"18#include "lldb/Symbol/DWARFCallFrameInfo.h"19#include "lldb/Symbol/FuncUnwinders.h"20#include "lldb/Symbol/ObjectFile.h"21#include "lldb/Symbol/SymbolContext.h"22#include "lldb/Symbol/SymbolVendor.h"2324// There is one UnwindTable object per ObjectFile. It contains a list of Unwind25// objects -- one per function, populated lazily -- for the ObjectFile. Each26// Unwind object has multiple UnwindPlans for different scenarios.2728using namespace lldb;29using namespace lldb_private;3031UnwindTable::UnwindTable(Module &module)32: m_module(module), m_unwinds(), m_initialized(false), m_mutex(),33m_object_file_unwind_up(), m_eh_frame_up(), m_compact_unwind_up(),34m_arm_unwind_up() {}3536// We can't do some of this initialization when the ObjectFile is running its37// ctor; delay doing it until needed for something.3839void UnwindTable::Initialize() {40if (m_initialized)41return;4243std::lock_guard<std::mutex> guard(m_mutex);4445if (m_initialized) // check again once we've acquired the lock46return;47m_initialized = true;48ObjectFile *object_file = m_module.GetObjectFile();49if (!object_file)50return;5152m_object_file_unwind_up = object_file->CreateCallFrameInfo();5354SectionList *sl = m_module.GetSectionList();55if (!sl)56return;5758SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);59if (sect.get()) {60m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>(61*object_file, sect, DWARFCallFrameInfo::EH);62}6364sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);65if (sect) {66m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>(67*object_file, sect, DWARFCallFrameInfo::DWARF);68}6970sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);71if (sect) {72m_compact_unwind_up =73std::make_unique<CompactUnwindInfo>(*object_file, sect);74}7576sect = sl->FindSectionByType(eSectionTypeARMexidx, true);77if (sect) {78SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);79if (sect_extab.get()) {80m_arm_unwind_up =81std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab);82}83}84}8586void UnwindTable::Update() {87if (!m_initialized)88return Initialize();8990std::lock_guard<std::mutex> guard(m_mutex);9192ObjectFile *object_file = m_module.GetObjectFile();93if (!object_file)94return;9596if (!m_object_file_unwind_up)97m_object_file_unwind_up = object_file->CreateCallFrameInfo();9899SectionList *sl = m_module.GetSectionList();100if (!sl)101return;102103SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);104if (!m_eh_frame_up && sect) {105m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>(106*object_file, sect, DWARFCallFrameInfo::EH);107}108109sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);110if (!m_debug_frame_up && sect) {111m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>(112*object_file, sect, DWARFCallFrameInfo::DWARF);113}114115sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);116if (!m_compact_unwind_up && sect) {117m_compact_unwind_up =118std::make_unique<CompactUnwindInfo>(*object_file, sect);119}120121sect = sl->FindSectionByType(eSectionTypeARMexidx, true);122if (!m_arm_unwind_up && sect) {123SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);124if (sect_extab.get()) {125m_arm_unwind_up =126std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab);127}128}129}130131UnwindTable::~UnwindTable() = default;132133std::optional<AddressRange>134UnwindTable::GetAddressRange(const Address &addr, const SymbolContext &sc) {135AddressRange range;136137// First check the unwind info from the object file plugin138if (m_object_file_unwind_up &&139m_object_file_unwind_up->GetAddressRange(addr, range))140return range;141142// Check the symbol context143if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,144false, range) &&145range.GetBaseAddress().IsValid())146return range;147148// Does the eh_frame unwind info has a function bounds for this addr?149if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))150return range;151152// Try debug_frame as well153if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))154return range;155156return std::nullopt;157}158159FuncUnwindersSP160UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,161SymbolContext &sc) {162Initialize();163164std::lock_guard<std::mutex> guard(m_mutex);165166// There is an UnwindTable per object file, so we can safely use file handles167addr_t file_addr = addr.GetFileAddress();168iterator end = m_unwinds.end();169iterator insert_pos = end;170if (!m_unwinds.empty()) {171insert_pos = m_unwinds.lower_bound(file_addr);172iterator pos = insert_pos;173if ((pos == m_unwinds.end()) ||174(pos != m_unwinds.begin() &&175pos->second->GetFunctionStartAddress() != addr))176--pos;177178if (pos->second->ContainsAddress(addr))179return pos->second;180}181182auto range_or = GetAddressRange(addr, sc);183if (!range_or)184return nullptr;185186FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or));187m_unwinds.insert(insert_pos,188std::make_pair(range_or->GetBaseAddress().GetFileAddress(),189func_unwinder_sp));190return func_unwinder_sp;191}192193// Ignore any existing FuncUnwinders for this function, create a new one and194// don't add it to the UnwindTable. This is intended for use by target modules195// show-unwind where we want to create new UnwindPlans, not re-use existing196// ones.197FuncUnwindersSP UnwindTable::GetUncachedFuncUnwindersContainingAddress(198const Address &addr, const SymbolContext &sc) {199Initialize();200201auto range_or = GetAddressRange(addr, sc);202if (!range_or)203return nullptr;204205return std::make_shared<FuncUnwinders>(*this, *range_or);206}207208void UnwindTable::Dump(Stream &s) {209std::lock_guard<std::mutex> guard(m_mutex);210s.Format("UnwindTable for '{0}':\n", m_module.GetFileSpec());211const_iterator begin = m_unwinds.begin();212const_iterator end = m_unwinds.end();213for (const_iterator pos = begin; pos != end; ++pos) {214s.Printf("[%u] 0x%16.16" PRIx64 "\n", (unsigned)std::distance(begin, pos),215pos->first);216}217s.EOL();218}219220lldb_private::CallFrameInfo *UnwindTable::GetObjectFileUnwindInfo() {221Initialize();222return m_object_file_unwind_up.get();223}224225DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() {226Initialize();227return m_eh_frame_up.get();228}229230DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() {231Initialize();232return m_debug_frame_up.get();233}234235CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() {236Initialize();237return m_compact_unwind_up.get();238}239240ArmUnwindInfo *UnwindTable::GetArmUnwindInfo() {241Initialize();242return m_arm_unwind_up.get();243}244245SymbolFile *UnwindTable::GetSymbolFile() { return m_module.GetSymbolFile(); }246247ArchSpec UnwindTable::GetArchitecture() { return m_module.GetArchitecture(); }248249bool UnwindTable::GetAllowAssemblyEmulationUnwindPlans() {250if (ObjectFile *object_file = m_module.GetObjectFile())251return object_file->AllowAssemblyEmulationUnwindPlans();252return false;253}254255256