639 lines · cpp
1//===-- DWARFDIE.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 "DWARFDIE.h"10 11#include "DWARFASTParser.h"12#include "DWARFDebugInfo.h"13#include "DWARFDebugInfoEntry.h"14#include "DWARFDeclContext.h"15#include "DWARFUnit.h"16#include "LogChannelDWARF.h"17#include "lldb/Symbol/Type.h"18 19#include "llvm/ADT/iterator.h"20#include "llvm/BinaryFormat/Dwarf.h"21#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"22#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"23#include "llvm/Support/raw_ostream.h"24 25using namespace lldb_private;26using namespace lldb_private::plugin::dwarf;27using namespace llvm::dwarf;28 29namespace {30 31/// Iterate through all DIEs elaborating (i.e. reachable by a chain of32/// DW_AT_specification, DW_AT_abstract_origin and/or DW_AT_signature33/// attributes) a given DIE. For convenience, the starting die is included in34/// the sequence as the first item.35class ElaboratingDIEIterator36 : public llvm::iterator_facade_base<37 ElaboratingDIEIterator, std::input_iterator_tag, DWARFDIE,38 std::ptrdiff_t, DWARFDIE *, DWARFDIE *> {39 40 // The operating invariant is: top of m_worklist contains the "current" item41 // and the rest of the list are items yet to be visited. An empty worklist42 // means we've reached the end.43 // Infinite recursion is prevented by maintaining a list of seen DIEs.44 // Container sizes are optimized for the case of following DW_AT_specification45 // and DW_AT_abstract_origin just once.46 llvm::SmallVector<DWARFDIE, 2> m_worklist;47 llvm::SmallPtrSet<DWARFDebugInfoEntry *, 3> m_seen;48 49 void Next() {50 assert(!m_worklist.empty() && "Incrementing end iterator?");51 52 // Pop the current item from the list.53 DWARFDIE die = m_worklist.back();54 m_worklist.pop_back();55 56 // And add back any items that elaborate it.57 for (dw_attr_t attr :58 {DW_AT_specification, DW_AT_abstract_origin, DW_AT_signature}) {59 if (DWARFDIE d = die.GetReferencedDIE(attr))60 if (m_seen.insert(die.GetDIE()).second)61 m_worklist.push_back(d);62 }63 }64 65public:66 /// An iterator starting at die d.67 explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {}68 69 /// End marker70 ElaboratingDIEIterator() = default;71 72 const DWARFDIE &operator*() const { return m_worklist.back(); }73 ElaboratingDIEIterator &operator++() {74 Next();75 return *this;76 }77 78 friend bool operator==(const ElaboratingDIEIterator &a,79 const ElaboratingDIEIterator &b) {80 if (a.m_worklist.empty() || b.m_worklist.empty())81 return a.m_worklist.empty() == b.m_worklist.empty();82 return a.m_worklist.back() == b.m_worklist.back();83 }84};85 86llvm::iterator_range<ElaboratingDIEIterator>87elaborating_dies(const DWARFDIE &die) {88 return llvm::make_range(ElaboratingDIEIterator(die),89 ElaboratingDIEIterator());90}91} // namespace92 93DWARFDIE94DWARFDIE::GetParent() const {95 if (IsValid())96 return DWARFDIE(m_cu, m_die->GetParent());97 else98 return DWARFDIE();99}100 101DWARFDIE102DWARFDIE::GetFirstChild() const {103 if (IsValid())104 return DWARFDIE(m_cu, m_die->GetFirstChild());105 else106 return DWARFDIE();107}108 109DWARFDIE110DWARFDIE::GetSibling() const {111 if (IsValid())112 return DWARFDIE(m_cu, m_die->GetSibling());113 else114 return DWARFDIE();115}116 117DWARFDIE118DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const {119 if (IsValid())120 return m_die->GetAttributeValueAsReference(GetCU(), attr);121 else122 return {};123}124 125DWARFDIE126DWARFDIE::GetDIE(dw_offset_t die_offset) const {127 if (IsValid())128 return m_cu->GetDIE(die_offset);129 else130 return DWARFDIE();131}132 133DWARFDIE134DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const {135 if (IsValid()) {136 DWARFUnit *cu = GetCU();137 const bool check_elaborating_dies = true;138 DWARFFormValue form_value;139 if (m_die->GetAttributeValue(cu, attr, form_value, nullptr,140 check_elaborating_dies))141 return form_value.Reference();142 }143 return DWARFDIE();144}145 146DWARFDIE147DWARFDIE::LookupDeepestBlock(lldb::addr_t address) const {148 if (!IsValid())149 return DWARFDIE();150 151 DWARFDIE result;152 bool check_children = false;153 bool match_addr_range = false;154 switch (Tag()) {155 case DW_TAG_class_type:156 case DW_TAG_namespace:157 case DW_TAG_structure_type:158 case DW_TAG_common_block:159 check_children = true;160 break;161 case DW_TAG_compile_unit:162 case DW_TAG_module:163 case DW_TAG_catch_block:164 case DW_TAG_subprogram:165 case DW_TAG_try_block:166 case DW_TAG_partial_unit:167 match_addr_range = true;168 break;169 case DW_TAG_lexical_block:170 case DW_TAG_inlined_subroutine:171 check_children = true;172 match_addr_range = true;173 break;174 default:175 break;176 }177 178 if (match_addr_range) {179 if (llvm::Expected<llvm::DWARFAddressRangesVector> ranges =180 m_die->GetAttributeAddressRanges(m_cu, /*check_hi_lo_pc=*/true)) {181 bool addr_in_range =182 llvm::any_of(*ranges, [&](const llvm::DWARFAddressRange &r) {183 return r.LowPC <= address && address < r.HighPC;184 });185 if (addr_in_range) {186 switch (Tag()) {187 default:188 break;189 190 case DW_TAG_inlined_subroutine: // Inlined Function191 case DW_TAG_lexical_block: // Block { } in code192 result = *this;193 break;194 }195 }196 check_children = addr_in_range;197 } else {198 LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), ranges.takeError(),199 "DIE({1:x}): {0}", GetID());200 }201 }202 203 if (check_children) {204 for (DWARFDIE child : children()) {205 if (DWARFDIE child_result = child.LookupDeepestBlock(address))206 return child_result;207 }208 }209 return result;210}211 212const char *DWARFDIE::GetMangledName(bool substitute_name_allowed) const {213 if (IsValid())214 return m_die->GetMangledName(m_cu, substitute_name_allowed);215 else216 return nullptr;217}218 219const char *DWARFDIE::GetPubname() const {220 if (IsValid())221 return m_die->GetPubname(m_cu);222 else223 return nullptr;224}225 226// GetName227//228// Get value of the DW_AT_name attribute and place that value into the supplied229// stream object. If the DIE is a NULL object "NULL" is placed into the stream,230// and if no DW_AT_name attribute exists for the DIE then nothing is printed.231void DWARFDIE::GetName(Stream &s) const {232 if (!IsValid())233 return;234 if (GetDIE()->IsNULL()) {235 s.PutCString("NULL");236 return;237 }238 const char *name = GetDIE()->GetAttributeValueAsString(GetCU(), DW_AT_name, nullptr, true);239 if (!name)240 return;241 s.PutCString(name);242}243 244// AppendTypeName245//246// Follows the type name definition down through all needed tags to end up with247// a fully qualified type name and dump the results to the supplied stream.248// This is used to show the name of types given a type identifier.249void DWARFDIE::AppendTypeName(Stream &s) const {250 if (!IsValid())251 return;252 if (GetDIE()->IsNULL()) {253 s.PutCString("NULL");254 return;255 }256 if (const char *name = GetPubname()) {257 s.PutCString(name);258 return;259 }260 switch (Tag()) {261 case DW_TAG_array_type:262 break; // print out a "[]" after printing the full type of the element263 // below264 case DW_TAG_base_type:265 s.PutCString("base ");266 break;267 case DW_TAG_class_type:268 s.PutCString("class ");269 break;270 case DW_TAG_const_type:271 s.PutCString("const ");272 break;273 case DW_TAG_enumeration_type:274 s.PutCString("enum ");275 break;276 case DW_TAG_file_type:277 s.PutCString("file ");278 break;279 case DW_TAG_interface_type:280 s.PutCString("interface ");281 break;282 case DW_TAG_packed_type:283 s.PutCString("packed ");284 break;285 case DW_TAG_pointer_type:286 break; // print out a '*' after printing the full type below287 case DW_TAG_ptr_to_member_type:288 break; // print out a '*' after printing the full type below289 case DW_TAG_reference_type:290 break; // print out a '&' after printing the full type below291 case DW_TAG_restrict_type:292 s.PutCString("restrict ");293 break;294 case DW_TAG_set_type:295 s.PutCString("set ");296 break;297 case DW_TAG_shared_type:298 s.PutCString("shared ");299 break;300 case DW_TAG_string_type:301 s.PutCString("string ");302 break;303 case DW_TAG_structure_type:304 s.PutCString("struct ");305 break;306 case DW_TAG_subrange_type:307 s.PutCString("subrange ");308 break;309 case DW_TAG_subroutine_type:310 s.PutCString("function ");311 break;312 case DW_TAG_thrown_type:313 s.PutCString("thrown ");314 break;315 case DW_TAG_union_type:316 s.PutCString("union ");317 break;318 case DW_TAG_unspecified_type:319 s.PutCString("unspecified ");320 break;321 case DW_TAG_volatile_type:322 s.PutCString("volatile ");323 break;324 case DW_TAG_LLVM_ptrauth_type: {325 unsigned key = GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_key, 0);326 bool isAddressDiscriminated = GetAttributeValueAsUnsigned(327 DW_AT_LLVM_ptrauth_address_discriminated, 0);328 unsigned extraDiscriminator =329 GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_extra_discriminator, 0);330 bool isaPointer =331 GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_isa_pointer, 0);332 bool authenticatesNullValues = GetAttributeValueAsUnsigned(333 DW_AT_LLVM_ptrauth_authenticates_null_values, 0);334 unsigned authenticationMode =335 GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_authentication_mode, 3);336 337 s.Printf("__ptrauth(%d, %d, 0x0%x, %d, %d, %d)", key,338 isAddressDiscriminated, extraDiscriminator, isaPointer,339 authenticatesNullValues, authenticationMode);340 break;341 }342 default:343 return;344 }345 346 // Follow the DW_AT_type if possible347 if (DWARFDIE next_die = GetAttributeValueAsReferenceDIE(DW_AT_type))348 next_die.AppendTypeName(s);349 350 switch (Tag()) {351 case DW_TAG_array_type:352 s.PutCString("[]");353 break;354 case DW_TAG_pointer_type:355 s.PutChar('*');356 break;357 case DW_TAG_ptr_to_member_type:358 s.PutChar('*');359 break;360 case DW_TAG_reference_type:361 s.PutChar('&');362 break;363 default:364 break;365 }366}367 368lldb_private::Type *DWARFDIE::ResolveType() const {369 if (IsValid())370 return GetDWARF()->ResolveType(*this, true);371 else372 return nullptr;373}374 375lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const {376 if (SymbolFileDWARF *dwarf = GetDWARF())377 return dwarf->ResolveTypeUID(die, true);378 return nullptr;379}380 381static CompilerContext GetContextEntry(DWARFDIE die,382 bool derive_template_names) {383 auto ctx = [die](CompilerContextKind kind) {384 return CompilerContext(kind, ConstString(die.GetName()));385 };386 387 switch (die.Tag()) {388 case DW_TAG_module:389 return ctx(CompilerContextKind::Module);390 case DW_TAG_namespace:391 return ctx(CompilerContextKind::Namespace);392 case DW_TAG_enumeration_type:393 return ctx(CompilerContextKind::Enum);394 case DW_TAG_subprogram:395 return ctx(CompilerContextKind::Function);396 case DW_TAG_variable:397 return ctx(CompilerContextKind::Variable);398 case DW_TAG_typedef:399 return ctx(CompilerContextKind::Typedef);400 case DW_TAG_base_type:401 return ctx(CompilerContextKind::Builtin);402 case DW_TAG_class_type:403 case DW_TAG_structure_type:404 case DW_TAG_union_type: {405 CompilerContextKind kind = die.Tag() == DW_TAG_union_type406 ? CompilerContextKind::Union407 : CompilerContextKind::ClassOrStruct;408 llvm::StringRef name = die.GetName();409 if (!derive_template_names || name.contains('<'))410 return CompilerContext(kind, ConstString(name));411 412 std::string name_storage = name.str();413 llvm::raw_string_ostream os(name_storage);414 llvm::DWARFTypePrinter<DWARFDIE>(os).appendAndTerminateTemplateParameters(415 die);416 return CompilerContext(kind, ConstString(os.str()));417 }418 default:419 llvm_unreachable("Check tag type in the caller!");420 }421}422 423static void GetDeclContextImpl(DWARFDIE die, bool derive_template_names,424 llvm::SmallSet<lldb::user_id_t, 4> &seen,425 std::vector<CompilerContext> &context) {426 // Stop if we hit a cycle.427 while (die && seen.insert(die.GetID()).second) {428 // Handle outline member function DIEs by following the specification.429 if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_specification)) {430 die = spec;431 continue;432 }433 434 // Add this DIE's contribution at the end of the chain.435 switch (die.Tag()) {436 case DW_TAG_module:437 case DW_TAG_namespace:438 case DW_TAG_class_type:439 case DW_TAG_structure_type:440 case DW_TAG_union_type:441 case DW_TAG_enumeration_type:442 case DW_TAG_subprogram:443 case DW_TAG_variable:444 case DW_TAG_typedef:445 context.push_back(GetContextEntry(die, derive_template_names));446 break;447 default:448 break;449 }450 // Now process the parent.451 die = die.GetParent();452 }453}454 455std::vector<CompilerContext>456DWARFDIE::GetDeclContext(bool derive_template_names) const {457 llvm::SmallSet<lldb::user_id_t, 4> seen;458 std::vector<CompilerContext> context;459 GetDeclContextImpl(*this, derive_template_names, seen, context);460 std::reverse(context.begin(), context.end());461 return context;462}463 464static void GetTypeLookupContextImpl(DWARFDIE die, bool derive_template_names,465 llvm::SmallSet<lldb::user_id_t, 4> &seen,466 std::vector<CompilerContext> &context) {467 // Stop if we hit a cycle.468 while (die && seen.insert(die.GetID()).second) {469 // Add this DIE's contribution at the end of the chain.470 switch (die.Tag()) {471 case DW_TAG_namespace:472 case DW_TAG_class_type:473 case DW_TAG_structure_type:474 case DW_TAG_union_type:475 case DW_TAG_enumeration_type:476 case DW_TAG_variable:477 case DW_TAG_typedef:478 case DW_TAG_base_type:479 context.push_back(GetContextEntry(die, derive_template_names));480 break;481 482 // If any of the tags below appear in the parent chain, stop the decl483 // context and return. Prior to these being in here, if a type existed in a484 // namespace "a" like "a::my_struct", but we also have a function in that485 // same namespace "a" which contained a type named "my_struct", both would486 // return "a::my_struct" as the declaration context since the487 // DW_TAG_subprogram would be skipped and its parent would be found.488 case DW_TAG_compile_unit:489 case DW_TAG_type_unit:490 case DW_TAG_subprogram:491 case DW_TAG_lexical_block:492 case DW_TAG_inlined_subroutine:493 return;494 default:495 break;496 }497 // Now process the parent.498 die = die.GetParent();499 }500}501 502std::vector<CompilerContext>503DWARFDIE::GetTypeLookupContext(bool derive_template_names) const {504 llvm::SmallSet<lldb::user_id_t, 4> seen;505 std::vector<CompilerContext> context;506 GetTypeLookupContextImpl(*this, derive_template_names, seen, context);507 std::reverse(context.begin(), context.end());508 return context;509}510 511static DWARFDeclContext GetDWARFDeclContextImpl(DWARFDIE die) {512 DWARFDeclContext dwarf_decl_ctx;513 while (die) {514 const dw_tag_t tag = die.Tag();515 if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)516 break;517 dwarf_decl_ctx.AppendDeclContext(tag, die.GetName());518 DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE();519 if (parent_decl_ctx_die == die)520 break;521 die = parent_decl_ctx_die;522 }523 return dwarf_decl_ctx;524}525 526DWARFDeclContext DWARFDIE::GetDWARFDeclContext() const {527 return GetDWARFDeclContextImpl(*this);528}529 530static DWARFDIE GetParentDeclContextDIEImpl(DWARFDIE die) {531 DWARFDIE orig_die = die;532 while (die) {533 // If this is the original DIE that we are searching for a declaration for,534 // then don't look in the cache as we don't want our own decl context to be535 // our decl context...536 if (die != orig_die) {537 switch (die.Tag()) {538 case DW_TAG_compile_unit:539 case DW_TAG_partial_unit:540 case DW_TAG_namespace:541 case DW_TAG_structure_type:542 case DW_TAG_union_type:543 case DW_TAG_class_type:544 return die;545 546 default:547 break;548 }549 }550 551 if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification)) {552 if (DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE())553 return decl_ctx_die;554 }555 556 if (DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin)) {557 if (DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE())558 return decl_ctx_die;559 }560 561 die = die.GetParent();562 }563 return DWARFDIE();564}565 566DWARFDIE567DWARFDIE::GetParentDeclContextDIE() const {568 return GetParentDeclContextDIEImpl(*this);569}570 571bool DWARFDIE::IsStructUnionOrClass() const {572 const dw_tag_t tag = Tag();573 return tag == DW_TAG_class_type || tag == DW_TAG_structure_type ||574 tag == DW_TAG_union_type;575}576 577bool DWARFDIE::IsMethod() const {578 for (DWARFDIE d : elaborating_dies(*this))579 if (d.GetParent().IsStructUnionOrClass())580 return true;581 return false;582}583 584bool DWARFDIE::GetDIENamesAndRanges(585 const char *&name, const char *&mangled,586 llvm::DWARFAddressRangesVector &ranges, std::optional<int> &decl_file,587 std::optional<int> &decl_line, std::optional<int> &decl_column,588 std::optional<int> &call_file, std::optional<int> &call_line,589 std::optional<int> &call_column,590 lldb_private::DWARFExpressionList *frame_base) const {591 if (IsValid()) {592 return m_die->GetDIENamesAndRanges(593 GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column,594 call_file, call_line, call_column, frame_base);595 } else596 return false;597}598 599// The following methods use LLVM naming convension in order to be are used by600// LLVM libraries.601llvm::iterator_range<DWARFDIE::child_iterator> DWARFDIE::children() const {602 return llvm::make_range(child_iterator(*this), child_iterator());603}604 605DWARFDIE::child_iterator DWARFDIE::begin() const {606 return child_iterator(*this);607}608 609DWARFDIE::child_iterator DWARFDIE::end() const { return child_iterator(); }610 611std::optional<DWARFFormValue> DWARFDIE::find(const dw_attr_t attr) const {612 DWARFFormValue form_value;613 if (m_die->GetAttributeValue(m_cu, attr, form_value, nullptr, false))614 return form_value;615 return std::nullopt;616}617 618std::optional<uint64_t> DWARFDIE::getLanguage() const {619 if (IsValid())620 return m_cu->GetDWARFLanguageType();621 return std::nullopt;622}623 624DWARFDIE DWARFDIE::resolveReferencedType(dw_attr_t attr) const {625 return GetReferencedDIE(attr).resolveTypeUnitReference();626}627 628DWARFDIE DWARFDIE::resolveReferencedType(DWARFFormValue v) const {629 if (IsValid())630 return v.Reference().resolveTypeUnitReference();631 return {};632}633 634DWARFDIE DWARFDIE::resolveTypeUnitReference() const {635 if (DWARFDIE reference = GetReferencedDIE(DW_AT_signature))636 return reference;637 return *this;638}639