Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
39644 views
//===-- DWARFDebugInfoEntry.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 "DWARFDebugInfoEntry.h"910#include <cassert>1112#include <algorithm>13#include <limits>14#include <optional>1516#include "llvm/Support/LEB128.h"1718#include "lldb/Core/Module.h"19#include "lldb/Expression/DWARFExpression.h"20#include "lldb/Symbol/ObjectFile.h"21#include "lldb/Utility/Stream.h"22#include "lldb/Utility/StreamString.h"2324#include "DWARFCompileUnit.h"25#include "DWARFDebugAranges.h"26#include "DWARFDebugInfo.h"27#include "DWARFDebugRanges.h"28#include "DWARFDeclContext.h"29#include "DWARFFormValue.h"30#include "DWARFUnit.h"31#include "SymbolFileDWARF.h"32#include "SymbolFileDWARFDwo.h"3334#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"3536using namespace lldb_private;37using namespace lldb_private::dwarf;38using namespace lldb_private::plugin::dwarf;39extern int g_verbose;4041// Extract a debug info entry for a given DWARFUnit from the data42// starting at the offset in offset_ptr43bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data,44const DWARFUnit &unit,45lldb::offset_t *offset_ptr) {46m_offset = *offset_ptr;47auto report_error = [&](const char *fmt, const auto &...vals) {48unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(49"[{0:x16}]: {1}, please file a bug and "50"attach the file at the start of this error message",51static_cast<uint64_t>(m_offset), llvm::formatv(fmt, vals...));52*offset_ptr = std::numeric_limits<lldb::offset_t>::max();53return false;54};5556m_parent_idx = 0;57m_sibling_idx = 0;58const uint64_t abbr_idx = data.GetULEB128(offset_ptr);59if (abbr_idx > std::numeric_limits<uint16_t>::max())60return report_error("abbreviation code {0} too big", abbr_idx);61m_abbr_idx = abbr_idx;6263if (m_abbr_idx == 0) {64m_tag = llvm::dwarf::DW_TAG_null;65m_has_children = false;66return true; // NULL debug tag entry67}6869const auto *abbrevDecl = GetAbbreviationDeclarationPtr(&unit);70if (abbrevDecl == nullptr)71return report_error("invalid abbreviation code {0}", abbr_idx);7273m_tag = abbrevDecl->getTag();74m_has_children = abbrevDecl->hasChildren();75// Skip all data in the .debug_info or .debug_types for the attributes76for (const auto &attribute : abbrevDecl->attributes()) {77if (DWARFFormValue::SkipValue(attribute.Form, data, offset_ptr, &unit))78continue;7980return report_error("Unsupported DW_FORM_{1:x}", attribute.Form);81}82return true;83}8485static DWARFRangeList GetRangesOrReportError(DWARFUnit &unit,86const DWARFDebugInfoEntry &die,87const DWARFFormValue &value) {88llvm::Expected<DWARFRangeList> expected_ranges =89(value.Form() == DW_FORM_rnglistx)90? unit.FindRnglistFromIndex(value.Unsigned())91: unit.FindRnglistFromOffset(value.Unsigned());92if (expected_ranges)93return std::move(*expected_ranges);9495unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(96"[{0:x16}]: DIE has DW_AT_ranges({1} {2:x16}) attribute, but "97"range extraction failed ({3}), please file a bug "98"and attach the file at the start of this error message",99die.GetOffset(),100llvm::dwarf::FormEncodingString(value.Form()).str().c_str(),101value.Unsigned(), toString(expected_ranges.takeError()).c_str());102return DWARFRangeList();103}104105static void ExtractAttrAndFormValue(106const llvm::DWARFAbbreviationDeclaration::AttributeSpec &attr_spec,107dw_attr_t &attr, DWARFFormValue &form_value) {108attr = attr_spec.Attr;109form_value.FormRef() = attr_spec.Form;110if (attr_spec.isImplicitConst())111form_value.SetSigned(attr_spec.getImplicitConstValue());112}113114// GetDIENamesAndRanges115//116// Gets the valid address ranges for a given DIE by looking for a117// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges attributes.118bool DWARFDebugInfoEntry::GetDIENamesAndRanges(119DWARFUnit *cu, const char *&name, const char *&mangled,120DWARFRangeList &ranges, std::optional<int> &decl_file,121std::optional<int> &decl_line, std::optional<int> &decl_column,122std::optional<int> &call_file, std::optional<int> &call_line,123std::optional<int> &call_column, DWARFExpressionList *frame_base) const {124dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;125dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;126std::vector<DWARFDIE> dies;127bool set_frame_base_loclist_addr = false;128129SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF();130lldb::ModuleSP module = dwarf.GetObjectFile()->GetModule();131132if (const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu)) {133const DWARFDataExtractor &data = cu->GetData();134lldb::offset_t offset = GetFirstAttributeOffset();135136if (!data.ValidOffset(offset))137return false;138139bool do_offset = false;140141for (const auto &attribute : abbrevDecl->attributes()) {142DWARFFormValue form_value(cu);143dw_attr_t attr;144ExtractAttrAndFormValue(attribute, attr, form_value);145146if (form_value.ExtractValue(data, &offset)) {147switch (attr) {148case DW_AT_low_pc:149lo_pc = form_value.Address();150151if (do_offset)152hi_pc += lo_pc;153do_offset = false;154break;155156case DW_AT_entry_pc:157lo_pc = form_value.Address();158break;159160case DW_AT_high_pc:161if (form_value.Form() == DW_FORM_addr ||162form_value.Form() == DW_FORM_addrx ||163form_value.Form() == DW_FORM_GNU_addr_index) {164hi_pc = form_value.Address();165} else {166hi_pc = form_value.Unsigned();167if (lo_pc == LLDB_INVALID_ADDRESS)168do_offset = hi_pc != LLDB_INVALID_ADDRESS;169else170hi_pc += lo_pc; // DWARF 4 introduces <offset-from-lo-pc> to save171// on relocations172}173break;174175case DW_AT_ranges:176ranges = GetRangesOrReportError(*cu, *this, form_value);177break;178179case DW_AT_name:180if (name == nullptr)181name = form_value.AsCString();182break;183184case DW_AT_MIPS_linkage_name:185case DW_AT_linkage_name:186if (mangled == nullptr)187mangled = form_value.AsCString();188break;189190case DW_AT_abstract_origin:191dies.push_back(form_value.Reference());192break;193194case DW_AT_specification:195dies.push_back(form_value.Reference());196break;197198case DW_AT_decl_file:199if (!decl_file)200decl_file = form_value.Unsigned();201break;202203case DW_AT_decl_line:204if (!decl_line)205decl_line = form_value.Unsigned();206break;207208case DW_AT_decl_column:209if (!decl_column)210decl_column = form_value.Unsigned();211break;212213case DW_AT_call_file:214if (!call_file)215call_file = form_value.Unsigned();216break;217218case DW_AT_call_line:219if (!call_line)220call_line = form_value.Unsigned();221break;222223case DW_AT_call_column:224if (!call_column)225call_column = form_value.Unsigned();226break;227228case DW_AT_frame_base:229if (frame_base) {230if (form_value.BlockData()) {231uint32_t block_offset =232form_value.BlockData() - data.GetDataStart();233uint32_t block_length = form_value.Unsigned();234*frame_base =235DWARFExpressionList(module,236DWARFExpression(DataExtractor(237data, block_offset, block_length)),238cu);239} else {240DataExtractor data = cu->GetLocationData();241const dw_offset_t offset = form_value.Unsigned();242if (data.ValidOffset(offset)) {243data = DataExtractor(data, offset, data.GetByteSize() - offset);244if (lo_pc != LLDB_INVALID_ADDRESS) {245assert(lo_pc >= cu->GetBaseAddress());246DWARFExpression::ParseDWARFLocationList(cu, data, frame_base);247frame_base->SetFuncFileAddress(lo_pc);248} else249set_frame_base_loclist_addr = true;250}251}252}253break;254255default:256break;257}258}259}260}261262if (ranges.IsEmpty()) {263if (lo_pc != LLDB_INVALID_ADDRESS) {264if (hi_pc != LLDB_INVALID_ADDRESS && hi_pc > lo_pc)265ranges.Append(DWARFRangeList::Entry(lo_pc, hi_pc - lo_pc));266else267ranges.Append(DWARFRangeList::Entry(lo_pc, 0));268}269}270271if (set_frame_base_loclist_addr) {272dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0);273assert(lowest_range_pc >= cu->GetBaseAddress());274frame_base->SetFuncFileAddress(lowest_range_pc);275}276277if (ranges.IsEmpty() || name == nullptr || mangled == nullptr) {278for (const DWARFDIE &die : dies) {279if (die) {280die.GetDIE()->GetDIENamesAndRanges(die.GetCU(), name, mangled, ranges,281decl_file, decl_line, decl_column,282call_file, call_line, call_column);283}284}285}286return !ranges.IsEmpty();287}288289// Get all attribute values for a given DIE, including following any290// specification or abstract origin attributes and including those in the291// results. Any duplicate attributes will have the first instance take292// precedence (this can happen for declaration attributes).293void DWARFDebugInfoEntry::GetAttributes(DWARFUnit *cu,294DWARFAttributes &attributes,295Recurse recurse,296uint32_t curr_depth) const {297const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu);298if (!abbrevDecl) {299attributes.Clear();300return;301}302303const DWARFDataExtractor &data = cu->GetData();304lldb::offset_t offset = GetFirstAttributeOffset();305306for (const auto &attribute : abbrevDecl->attributes()) {307DWARFFormValue form_value(cu);308dw_attr_t attr;309ExtractAttrAndFormValue(attribute, attr, form_value);310311// If we are tracking down DW_AT_specification or DW_AT_abstract_origin312// attributes, the depth will be non-zero. We need to omit certain313// attributes that don't make sense.314switch (attr) {315case DW_AT_sibling:316case DW_AT_declaration:317if (curr_depth > 0) {318// This attribute doesn't make sense when combined with the DIE that319// references this DIE. We know a DIE is referencing this DIE because320// curr_depth is not zero321break;322}323[[fallthrough]];324default:325attributes.Append(form_value, offset, attr);326break;327}328329if (recurse == Recurse::yes &&330((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin))) {331if (form_value.ExtractValue(data, &offset)) {332DWARFDIE spec_die = form_value.Reference();333if (spec_die)334spec_die.GetDIE()->GetAttributes(spec_die.GetCU(), attributes,335recurse, curr_depth + 1);336}337} else {338const dw_form_t form = form_value.Form();339std::optional<uint8_t> fixed_skip_size =340DWARFFormValue::GetFixedSize(form, cu);341if (fixed_skip_size)342offset += *fixed_skip_size;343else344DWARFFormValue::SkipValue(form, data, &offset, cu);345}346}347}348349// GetAttributeValue350//351// Get the value of an attribute and return the .debug_info or .debug_types352// offset of the attribute if it was properly extracted into form_value,353// or zero if we fail since an offset of zero is invalid for an attribute (it354// would be a compile unit header).355dw_offset_t DWARFDebugInfoEntry::GetAttributeValue(356const DWARFUnit *cu, const dw_attr_t attr, DWARFFormValue &form_value,357dw_offset_t *end_attr_offset_ptr,358bool check_specification_or_abstract_origin) const {359if (const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu)) {360std::optional<uint32_t> attr_idx = abbrevDecl->findAttributeIndex(attr);361362if (attr_idx) {363const DWARFDataExtractor &data = cu->GetData();364lldb::offset_t offset = GetFirstAttributeOffset();365366uint32_t idx = 0;367while (idx < *attr_idx)368DWARFFormValue::SkipValue(abbrevDecl->getFormByIndex(idx++), data,369&offset, cu);370371const dw_offset_t attr_offset = offset;372form_value.SetUnit(cu);373form_value.SetForm(abbrevDecl->getFormByIndex(idx));374if (form_value.ExtractValue(data, &offset)) {375if (end_attr_offset_ptr)376*end_attr_offset_ptr = offset;377return attr_offset;378}379}380}381382if (check_specification_or_abstract_origin) {383if (GetAttributeValue(cu, DW_AT_specification, form_value)) {384DWARFDIE die = form_value.Reference();385if (die) {386dw_offset_t die_offset = die.GetDIE()->GetAttributeValue(387die.GetCU(), attr, form_value, end_attr_offset_ptr, false);388if (die_offset)389return die_offset;390}391}392393if (GetAttributeValue(cu, DW_AT_abstract_origin, form_value)) {394DWARFDIE die = form_value.Reference();395if (die) {396dw_offset_t die_offset = die.GetDIE()->GetAttributeValue(397die.GetCU(), attr, form_value, end_attr_offset_ptr, false);398if (die_offset)399return die_offset;400}401}402}403return 0;404}405406// GetAttributeValueAsString407//408// Get the value of an attribute as a string return it. The resulting pointer409// to the string data exists within the supplied SymbolFileDWARF and will only410// be available as long as the SymbolFileDWARF is still around and it's content411// doesn't change.412const char *DWARFDebugInfoEntry::GetAttributeValueAsString(413const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value,414bool check_specification_or_abstract_origin) const {415DWARFFormValue form_value;416if (GetAttributeValue(cu, attr, form_value, nullptr,417check_specification_or_abstract_origin))418return form_value.AsCString();419return fail_value;420}421422// GetAttributeValueAsUnsigned423//424// Get the value of an attribute as unsigned and return it.425uint64_t DWARFDebugInfoEntry::GetAttributeValueAsUnsigned(426const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,427bool check_specification_or_abstract_origin) const {428DWARFFormValue form_value;429if (GetAttributeValue(cu, attr, form_value, nullptr,430check_specification_or_abstract_origin))431return form_value.Unsigned();432return fail_value;433}434435std::optional<uint64_t>436DWARFDebugInfoEntry::GetAttributeValueAsOptionalUnsigned(437const DWARFUnit *cu, const dw_attr_t attr,438bool check_specification_or_abstract_origin) const {439DWARFFormValue form_value;440if (GetAttributeValue(cu, attr, form_value, nullptr,441check_specification_or_abstract_origin))442return form_value.Unsigned();443return std::nullopt;444}445446// GetAttributeValueAsReference447//448// Get the value of an attribute as reference and fix up and compile unit449// relative offsets as needed.450DWARFDIE DWARFDebugInfoEntry::GetAttributeValueAsReference(451const DWARFUnit *cu, const dw_attr_t attr,452bool check_specification_or_abstract_origin) const {453DWARFFormValue form_value;454if (GetAttributeValue(cu, attr, form_value, nullptr,455check_specification_or_abstract_origin))456return form_value.Reference();457return {};458}459460uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress(461const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,462bool check_specification_or_abstract_origin) const {463DWARFFormValue form_value;464if (GetAttributeValue(cu, attr, form_value, nullptr,465check_specification_or_abstract_origin))466return form_value.Address();467return fail_value;468}469470// GetAttributeHighPC471//472// Get the hi_pc, adding hi_pc to lo_pc when specified as an <offset-from-low-473// pc>.474//475// Returns the hi_pc or fail_value.476dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC(477const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value,478bool check_specification_or_abstract_origin) const {479DWARFFormValue form_value;480if (GetAttributeValue(cu, DW_AT_high_pc, form_value, nullptr,481check_specification_or_abstract_origin)) {482dw_form_t form = form_value.Form();483if (form == DW_FORM_addr || form == DW_FORM_addrx ||484form == DW_FORM_GNU_addr_index)485return form_value.Address();486487// DWARF4 can specify the hi_pc as an <offset-from-lowpc>488return lo_pc + form_value.Unsigned();489}490return fail_value;491}492493// GetAttributeAddressRange494//495// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified as an <offset-496// from-low-pc>.497//498// Returns true or sets lo_pc and hi_pc to fail_value.499bool DWARFDebugInfoEntry::GetAttributeAddressRange(500const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc,501uint64_t fail_value, bool check_specification_or_abstract_origin) const {502lo_pc = GetAttributeValueAsAddress(cu, DW_AT_low_pc, fail_value,503check_specification_or_abstract_origin);504if (lo_pc != fail_value) {505hi_pc = GetAttributeHighPC(cu, lo_pc, fail_value,506check_specification_or_abstract_origin);507if (hi_pc != fail_value)508return true;509}510lo_pc = fail_value;511hi_pc = fail_value;512return false;513}514515DWARFRangeList DWARFDebugInfoEntry::GetAttributeAddressRanges(516DWARFUnit *cu, bool check_hi_lo_pc,517bool check_specification_or_abstract_origin) const {518519DWARFFormValue form_value;520if (GetAttributeValue(cu, DW_AT_ranges, form_value))521return GetRangesOrReportError(*cu, *this, form_value);522523DWARFRangeList ranges;524if (check_hi_lo_pc) {525dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;526dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;527if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS,528check_specification_or_abstract_origin)) {529if (lo_pc < hi_pc)530ranges.Append(DWARFRangeList::Entry(lo_pc, hi_pc - lo_pc));531}532}533return ranges;534}535536// GetName537//538// Get value of the DW_AT_name attribute and return it if one exists, else539// return NULL.540const char *DWARFDebugInfoEntry::GetName(const DWARFUnit *cu) const {541return GetAttributeValueAsString(cu, DW_AT_name, nullptr, true);542}543544// GetMangledName545//546// Get value of the DW_AT_MIPS_linkage_name attribute and return it if one547// exists, else return the value of the DW_AT_name attribute548const char *549DWARFDebugInfoEntry::GetMangledName(const DWARFUnit *cu,550bool substitute_name_allowed) const {551const char *name = nullptr;552553name = GetAttributeValueAsString(cu, DW_AT_MIPS_linkage_name, nullptr, true);554if (name)555return name;556557name = GetAttributeValueAsString(cu, DW_AT_linkage_name, nullptr, true);558if (name)559return name;560561if (!substitute_name_allowed)562return nullptr;563564name = GetAttributeValueAsString(cu, DW_AT_name, nullptr, true);565return name;566}567568// GetPubname569//570// Get value the name for a DIE as it should appear for a .debug_pubnames or571// .debug_pubtypes section.572const char *DWARFDebugInfoEntry::GetPubname(const DWARFUnit *cu) const {573const char *name = nullptr;574if (!cu)575return name;576577name = GetAttributeValueAsString(cu, DW_AT_MIPS_linkage_name, nullptr, true);578if (name)579return name;580581name = GetAttributeValueAsString(cu, DW_AT_linkage_name, nullptr, true);582if (name)583return name;584585name = GetAttributeValueAsString(cu, DW_AT_name, nullptr, true);586return name;587}588589/// This function is builds a table very similar to the standard .debug_aranges590/// table, except that the actual DIE offset for the function is placed in the591/// table instead of the compile unit offset.592void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable(593DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const {594if (m_tag) {595if (m_tag == DW_TAG_subprogram) {596DWARFRangeList ranges =597GetAttributeAddressRanges(cu, /*check_hi_lo_pc=*/true);598for (const auto &r : ranges) {599debug_aranges->AppendRange(GetOffset(), r.GetRangeBase(),600r.GetRangeEnd());601}602}603604const DWARFDebugInfoEntry *child = GetFirstChild();605while (child) {606child->BuildFunctionAddressRangeTable(cu, debug_aranges);607child = child->GetSibling();608}609}610}611612lldb::offset_t DWARFDebugInfoEntry::GetFirstAttributeOffset() const {613return GetOffset() + llvm::getULEB128Size(m_abbr_idx);614}615616const llvm::DWARFAbbreviationDeclaration *617DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const {618if (!cu)619return nullptr;620621const llvm::DWARFAbbreviationDeclarationSet *abbrev_set =622cu->GetAbbreviations();623if (!abbrev_set)624return nullptr;625626return abbrev_set->getAbbreviationDeclaration(m_abbr_idx);627}628629bool DWARFDebugInfoEntry::IsGlobalOrStaticScopeVariable() const {630if (Tag() != DW_TAG_variable)631return false;632const DWARFDebugInfoEntry *parent_die = GetParent();633while (parent_die != nullptr) {634switch (parent_die->Tag()) {635case DW_TAG_subprogram:636case DW_TAG_lexical_block:637case DW_TAG_inlined_subroutine:638return false;639640case DW_TAG_compile_unit:641case DW_TAG_partial_unit:642return true;643644default:645break;646}647parent_die = parent_die->GetParent();648}649return false;650}651652bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const {653return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx &&654m_sibling_idx == rhs.m_sibling_idx &&655m_abbr_idx == rhs.m_abbr_idx && m_has_children == rhs.m_has_children &&656m_tag == rhs.m_tag;657}658659bool DWARFDebugInfoEntry::operator!=(const DWARFDebugInfoEntry &rhs) const {660return !(*this == rhs);661}662663664