Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
39645 views
//===-- DWARFDIE.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 "DWARFDIE.h"910#include "DWARFASTParser.h"11#include "DWARFDebugInfo.h"12#include "DWARFDebugInfoEntry.h"13#include "DWARFDeclContext.h"14#include "DWARFUnit.h"15#include "lldb/Symbol/Type.h"1617#include "llvm/ADT/iterator.h"18#include "llvm/BinaryFormat/Dwarf.h"1920using namespace lldb_private;21using namespace lldb_private::dwarf;22using namespace lldb_private::plugin::dwarf;2324namespace {2526/// Iterate through all DIEs elaborating (i.e. reachable by a chain of27/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For28/// convenience, the starting die is included in the sequence as the first29/// item.30class ElaboratingDIEIterator31: public llvm::iterator_facade_base<32ElaboratingDIEIterator, std::input_iterator_tag, DWARFDIE,33std::ptrdiff_t, DWARFDIE *, DWARFDIE *> {3435// The operating invariant is: top of m_worklist contains the "current" item36// and the rest of the list are items yet to be visited. An empty worklist37// means we've reached the end.38// Infinite recursion is prevented by maintaining a list of seen DIEs.39// Container sizes are optimized for the case of following DW_AT_specification40// and DW_AT_abstract_origin just once.41llvm::SmallVector<DWARFDIE, 2> m_worklist;42llvm::SmallSet<DWARFDebugInfoEntry *, 3> m_seen;4344void Next() {45assert(!m_worklist.empty() && "Incrementing end iterator?");4647// Pop the current item from the list.48DWARFDIE die = m_worklist.back();49m_worklist.pop_back();5051// And add back any items that elaborate it.52for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) {53if (DWARFDIE d = die.GetReferencedDIE(attr))54if (m_seen.insert(die.GetDIE()).second)55m_worklist.push_back(d);56}57}5859public:60/// An iterator starting at die d.61explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {}6263/// End marker64ElaboratingDIEIterator() = default;6566const DWARFDIE &operator*() const { return m_worklist.back(); }67ElaboratingDIEIterator &operator++() {68Next();69return *this;70}7172friend bool operator==(const ElaboratingDIEIterator &a,73const ElaboratingDIEIterator &b) {74if (a.m_worklist.empty() || b.m_worklist.empty())75return a.m_worklist.empty() == b.m_worklist.empty();76return a.m_worklist.back() == b.m_worklist.back();77}78};7980llvm::iterator_range<ElaboratingDIEIterator>81elaborating_dies(const DWARFDIE &die) {82return llvm::make_range(ElaboratingDIEIterator(die),83ElaboratingDIEIterator());84}85} // namespace8687DWARFDIE88DWARFDIE::GetParent() const {89if (IsValid())90return DWARFDIE(m_cu, m_die->GetParent());91else92return DWARFDIE();93}9495DWARFDIE96DWARFDIE::GetFirstChild() const {97if (IsValid())98return DWARFDIE(m_cu, m_die->GetFirstChild());99else100return DWARFDIE();101}102103DWARFDIE104DWARFDIE::GetSibling() const {105if (IsValid())106return DWARFDIE(m_cu, m_die->GetSibling());107else108return DWARFDIE();109}110111DWARFDIE112DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const {113if (IsValid())114return m_die->GetAttributeValueAsReference(GetCU(), attr);115else116return {};117}118119DWARFDIE120DWARFDIE::GetDIE(dw_offset_t die_offset) const {121if (IsValid())122return m_cu->GetDIE(die_offset);123else124return DWARFDIE();125}126127DWARFDIE128DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const {129if (IsValid()) {130DWARFUnit *cu = GetCU();131const bool check_specification_or_abstract_origin = true;132DWARFFormValue form_value;133if (m_die->GetAttributeValue(cu, attr, form_value, nullptr,134check_specification_or_abstract_origin))135return form_value.Reference();136}137return DWARFDIE();138}139140DWARFDIE141DWARFDIE::LookupDeepestBlock(lldb::addr_t address) const {142if (!IsValid())143return DWARFDIE();144145DWARFDIE result;146bool check_children = false;147bool match_addr_range = false;148switch (Tag()) {149case DW_TAG_class_type:150case DW_TAG_namespace:151case DW_TAG_structure_type:152case DW_TAG_common_block:153check_children = true;154break;155case DW_TAG_compile_unit:156case DW_TAG_module:157case DW_TAG_catch_block:158case DW_TAG_subprogram:159case DW_TAG_try_block:160case DW_TAG_partial_unit:161match_addr_range = true;162break;163case DW_TAG_lexical_block:164case DW_TAG_inlined_subroutine:165check_children = true;166match_addr_range = true;167break;168default:169break;170}171172if (match_addr_range) {173DWARFRangeList ranges =174m_die->GetAttributeAddressRanges(m_cu, /*check_hi_lo_pc=*/true);175if (ranges.FindEntryThatContains(address)) {176check_children = true;177switch (Tag()) {178default:179break;180181case DW_TAG_inlined_subroutine: // Inlined Function182case DW_TAG_lexical_block: // Block { } in code183result = *this;184break;185}186} else {187check_children = false;188}189}190191if (check_children) {192for (DWARFDIE child : children()) {193if (DWARFDIE child_result = child.LookupDeepestBlock(address))194return child_result;195}196}197return result;198}199200const char *DWARFDIE::GetMangledName() const {201if (IsValid())202return m_die->GetMangledName(m_cu);203else204return nullptr;205}206207const char *DWARFDIE::GetPubname() const {208if (IsValid())209return m_die->GetPubname(m_cu);210else211return nullptr;212}213214// GetName215//216// Get value of the DW_AT_name attribute and place that value into the supplied217// stream object. If the DIE is a NULL object "NULL" is placed into the stream,218// and if no DW_AT_name attribute exists for the DIE then nothing is printed.219void DWARFDIE::GetName(Stream &s) const {220if (!IsValid())221return;222if (GetDIE()->IsNULL()) {223s.PutCString("NULL");224return;225}226const char *name = GetDIE()->GetAttributeValueAsString(GetCU(), DW_AT_name, nullptr, true);227if (!name)228return;229s.PutCString(name);230}231232// AppendTypeName233//234// Follows the type name definition down through all needed tags to end up with235// a fully qualified type name and dump the results to the supplied stream.236// This is used to show the name of types given a type identifier.237void DWARFDIE::AppendTypeName(Stream &s) const {238if (!IsValid())239return;240if (GetDIE()->IsNULL()) {241s.PutCString("NULL");242return;243}244if (const char *name = GetPubname()) {245s.PutCString(name);246return;247}248switch (Tag()) {249case DW_TAG_array_type:250break; // print out a "[]" after printing the full type of the element251// below252case DW_TAG_base_type:253s.PutCString("base ");254break;255case DW_TAG_class_type:256s.PutCString("class ");257break;258case DW_TAG_const_type:259s.PutCString("const ");260break;261case DW_TAG_enumeration_type:262s.PutCString("enum ");263break;264case DW_TAG_file_type:265s.PutCString("file ");266break;267case DW_TAG_interface_type:268s.PutCString("interface ");269break;270case DW_TAG_packed_type:271s.PutCString("packed ");272break;273case DW_TAG_pointer_type:274break; // print out a '*' after printing the full type below275case DW_TAG_ptr_to_member_type:276break; // print out a '*' after printing the full type below277case DW_TAG_reference_type:278break; // print out a '&' after printing the full type below279case DW_TAG_restrict_type:280s.PutCString("restrict ");281break;282case DW_TAG_set_type:283s.PutCString("set ");284break;285case DW_TAG_shared_type:286s.PutCString("shared ");287break;288case DW_TAG_string_type:289s.PutCString("string ");290break;291case DW_TAG_structure_type:292s.PutCString("struct ");293break;294case DW_TAG_subrange_type:295s.PutCString("subrange ");296break;297case DW_TAG_subroutine_type:298s.PutCString("function ");299break;300case DW_TAG_thrown_type:301s.PutCString("thrown ");302break;303case DW_TAG_union_type:304s.PutCString("union ");305break;306case DW_TAG_unspecified_type:307s.PutCString("unspecified ");308break;309case DW_TAG_volatile_type:310s.PutCString("volatile ");311break;312case DW_TAG_LLVM_ptrauth_type: {313unsigned key = GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_key, 0);314bool isAddressDiscriminated = GetAttributeValueAsUnsigned(315DW_AT_LLVM_ptrauth_address_discriminated, 0);316unsigned extraDiscriminator =317GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_extra_discriminator, 0);318bool isaPointer =319GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_isa_pointer, 0);320bool authenticatesNullValues = GetAttributeValueAsUnsigned(321DW_AT_LLVM_ptrauth_authenticates_null_values, 0);322unsigned authenticationMode =323GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_authentication_mode, 3);324325s.Printf("__ptrauth(%d, %d, 0x0%x, %d, %d, %d)", key,326isAddressDiscriminated, extraDiscriminator, isaPointer,327authenticatesNullValues, authenticationMode);328break;329}330default:331return;332}333334// Follow the DW_AT_type if possible335if (DWARFDIE next_die = GetAttributeValueAsReferenceDIE(DW_AT_type))336next_die.AppendTypeName(s);337338switch (Tag()) {339case DW_TAG_array_type:340s.PutCString("[]");341break;342case DW_TAG_pointer_type:343s.PutChar('*');344break;345case DW_TAG_ptr_to_member_type:346s.PutChar('*');347break;348case DW_TAG_reference_type:349s.PutChar('&');350break;351default:352break;353}354}355356lldb_private::Type *DWARFDIE::ResolveType() const {357if (IsValid())358return GetDWARF()->ResolveType(*this, true);359else360return nullptr;361}362363lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const {364if (SymbolFileDWARF *dwarf = GetDWARF())365return dwarf->ResolveTypeUID(die, true);366return nullptr;367}368369static void GetDeclContextImpl(DWARFDIE die,370llvm::SmallSet<lldb::user_id_t, 4> &seen,371std::vector<CompilerContext> &context) {372// Stop if we hit a cycle.373while (die && seen.insert(die.GetID()).second) {374// Handle outline member function DIEs by following the specification.375if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_specification)) {376die = spec;377continue;378}379// To find the name of a type in a type unit, we must follow the signature.380if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) {381die = spec;382continue;383}384385// Add this DIE's contribution at the end of the chain.386auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {387context.push_back({kind, ConstString(name)});388};389switch (die.Tag()) {390case DW_TAG_module:391push_ctx(CompilerContextKind::Module, die.GetName());392break;393case DW_TAG_namespace:394push_ctx(CompilerContextKind::Namespace, die.GetName());395break;396case DW_TAG_class_type:397case DW_TAG_structure_type:398push_ctx(CompilerContextKind::ClassOrStruct, die.GetName());399break;400case DW_TAG_union_type:401push_ctx(CompilerContextKind::Union, die.GetName());402break;403case DW_TAG_enumeration_type:404push_ctx(CompilerContextKind::Enum, die.GetName());405break;406case DW_TAG_subprogram:407push_ctx(CompilerContextKind::Function, die.GetName());408break;409case DW_TAG_variable:410push_ctx(CompilerContextKind::Variable, die.GetPubname());411break;412case DW_TAG_typedef:413push_ctx(CompilerContextKind::Typedef, die.GetName());414break;415default:416break;417}418// Now process the parent.419die = die.GetParent();420}421}422423std::vector<CompilerContext> DWARFDIE::GetDeclContext() const {424llvm::SmallSet<lldb::user_id_t, 4> seen;425std::vector<CompilerContext> context;426GetDeclContextImpl(*this, seen, context);427std::reverse(context.begin(), context.end());428return context;429}430431static void GetTypeLookupContextImpl(DWARFDIE die,432llvm::SmallSet<lldb::user_id_t, 4> &seen,433std::vector<CompilerContext> &context) {434// Stop if we hit a cycle.435while (die && seen.insert(die.GetID()).second) {436// To find the name of a type in a type unit, we must follow the signature.437if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) {438die = spec;439continue;440}441442// If there is no name, then there is no need to look anything up for this443// DIE.444const char *name = die.GetName();445if (!name || !name[0])446return;447448// Add this DIE's contribution at the end of the chain.449auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {450context.push_back({kind, ConstString(name)});451};452switch (die.Tag()) {453case DW_TAG_namespace:454push_ctx(CompilerContextKind::Namespace, die.GetName());455break;456case DW_TAG_class_type:457case DW_TAG_structure_type:458push_ctx(CompilerContextKind::ClassOrStruct, die.GetName());459break;460case DW_TAG_union_type:461push_ctx(CompilerContextKind::Union, die.GetName());462break;463case DW_TAG_enumeration_type:464push_ctx(CompilerContextKind::Enum, die.GetName());465break;466case DW_TAG_variable:467push_ctx(CompilerContextKind::Variable, die.GetPubname());468break;469case DW_TAG_typedef:470push_ctx(CompilerContextKind::Typedef, die.GetName());471break;472case DW_TAG_base_type:473push_ctx(CompilerContextKind::Builtin, name);474break;475// If any of the tags below appear in the parent chain, stop the decl476// context and return. Prior to these being in here, if a type existed in a477// namespace "a" like "a::my_struct", but we also have a function in that478// same namespace "a" which contained a type named "my_struct", both would479// return "a::my_struct" as the declaration context since the480// DW_TAG_subprogram would be skipped and its parent would be found.481case DW_TAG_compile_unit:482case DW_TAG_type_unit:483case DW_TAG_subprogram:484case DW_TAG_lexical_block:485case DW_TAG_inlined_subroutine:486return;487default:488break;489}490// Now process the parent.491die = die.GetParent();492}493}494495std::vector<CompilerContext> DWARFDIE::GetTypeLookupContext() const {496llvm::SmallSet<lldb::user_id_t, 4> seen;497std::vector<CompilerContext> context;498GetTypeLookupContextImpl(*this, seen, context);499std::reverse(context.begin(), context.end());500return context;501}502503static DWARFDeclContext GetDWARFDeclContextImpl(DWARFDIE die) {504DWARFDeclContext dwarf_decl_ctx;505while (die) {506const dw_tag_t tag = die.Tag();507if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)508break;509dwarf_decl_ctx.AppendDeclContext(tag, die.GetName());510DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE();511if (parent_decl_ctx_die == die)512break;513die = parent_decl_ctx_die;514}515return dwarf_decl_ctx;516}517518DWARFDeclContext DWARFDIE::GetDWARFDeclContext() const {519return GetDWARFDeclContextImpl(*this);520}521522static DWARFDIE GetParentDeclContextDIEImpl(DWARFDIE die) {523DWARFDIE orig_die = die;524while (die) {525// If this is the original DIE that we are searching for a declaration for,526// then don't look in the cache as we don't want our own decl context to be527// our decl context...528if (die != orig_die) {529switch (die.Tag()) {530case DW_TAG_compile_unit:531case DW_TAG_partial_unit:532case DW_TAG_namespace:533case DW_TAG_structure_type:534case DW_TAG_union_type:535case DW_TAG_class_type:536return die;537538default:539break;540}541}542543if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification)) {544if (DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE())545return decl_ctx_die;546}547548if (DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin)) {549if (DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE())550return decl_ctx_die;551}552553die = die.GetParent();554}555return DWARFDIE();556}557558DWARFDIE559DWARFDIE::GetParentDeclContextDIE() const {560return GetParentDeclContextDIEImpl(*this);561}562563bool DWARFDIE::IsStructUnionOrClass() const {564const dw_tag_t tag = Tag();565return tag == DW_TAG_class_type || tag == DW_TAG_structure_type ||566tag == DW_TAG_union_type;567}568569bool DWARFDIE::IsMethod() const {570for (DWARFDIE d : elaborating_dies(*this))571if (d.GetParent().IsStructUnionOrClass())572return true;573return false;574}575576bool DWARFDIE::GetDIENamesAndRanges(577const char *&name, const char *&mangled, DWARFRangeList &ranges,578std::optional<int> &decl_file, std::optional<int> &decl_line,579std::optional<int> &decl_column, std::optional<int> &call_file,580std::optional<int> &call_line, std::optional<int> &call_column,581lldb_private::DWARFExpressionList *frame_base) const {582if (IsValid()) {583return m_die->GetDIENamesAndRanges(584GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column,585call_file, call_line, call_column, frame_base);586} else587return false;588}589590llvm::iterator_range<DWARFDIE::child_iterator> DWARFDIE::children() const {591return llvm::make_range(child_iterator(*this), child_iterator());592}593594595