1292932Sdim//===-- DWARFDIE.cpp --------------------------------------------*- C++ -*-===// 2292932Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6292932Sdim// 7292932Sdim//===----------------------------------------------------------------------===// 8292932Sdim 9292932Sdim#include "DWARFDIE.h" 10292932Sdim 11309124Sdim#include "DWARFASTParser.h" 12292932Sdim#include "DWARFDebugInfo.h" 13292932Sdim#include "DWARFDebugInfoEntry.h" 14292932Sdim#include "DWARFDeclContext.h" 15341825Sdim#include "DWARFUnit.h" 16292932Sdim 17292932Sdimusing namespace lldb_private; 18292932Sdim 19353358Sdimnamespace { 20292932Sdim 21353358Sdim/// Iterate through all DIEs elaborating (i.e. reachable by a chain of 22353358Sdim/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For 23353358Sdim/// convenience, the starting die is included in the sequence as the first 24353358Sdim/// item. 25353358Sdimclass ElaboratingDIEIterator 26353358Sdim : public std::iterator<std::input_iterator_tag, DWARFDIE> { 27292932Sdim 28353358Sdim // The operating invariant is: top of m_worklist contains the "current" item 29353358Sdim // and the rest of the list are items yet to be visited. An empty worklist 30353358Sdim // means we've reached the end. 31353358Sdim // Infinite recursion is prevented by maintaining a list of seen DIEs. 32353358Sdim // Container sizes are optimized for the case of following DW_AT_specification 33353358Sdim // and DW_AT_abstract_origin just once. 34353358Sdim llvm::SmallVector<DWARFDIE, 2> m_worklist; 35353358Sdim llvm::SmallSet<lldb::user_id_t, 3> m_seen; 36353358Sdim 37353358Sdim void Next() { 38353358Sdim assert(!m_worklist.empty() && "Incrementing end iterator?"); 39353358Sdim 40353358Sdim // Pop the current item from the list. 41353358Sdim DWARFDIE die = m_worklist.back(); 42353358Sdim m_worklist.pop_back(); 43353358Sdim 44353358Sdim // And add back any items that elaborate it. 45353358Sdim for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) { 46353358Sdim if (DWARFDIE d = die.GetReferencedDIE(attr)) 47353358Sdim if (m_seen.insert(die.GetID()).second) 48353358Sdim m_worklist.push_back(d); 49353358Sdim } 50341825Sdim } 51353358Sdim 52353358Sdimpublic: 53353358Sdim /// An iterator starting at die d. 54353358Sdim explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {} 55353358Sdim 56353358Sdim /// End marker 57353358Sdim ElaboratingDIEIterator() {} 58353358Sdim 59353358Sdim const DWARFDIE &operator*() const { return m_worklist.back(); } 60353358Sdim ElaboratingDIEIterator &operator++() { 61353358Sdim Next(); 62353358Sdim return *this; 63353358Sdim } 64353358Sdim ElaboratingDIEIterator operator++(int) { 65353358Sdim ElaboratingDIEIterator I = *this; 66353358Sdim Next(); 67353358Sdim return I; 68353358Sdim } 69353358Sdim 70353358Sdim friend bool operator==(const ElaboratingDIEIterator &a, 71353358Sdim const ElaboratingDIEIterator &b) { 72353358Sdim if (a.m_worklist.empty() || b.m_worklist.empty()) 73353358Sdim return a.m_worklist.empty() == b.m_worklist.empty(); 74353358Sdim return a.m_worklist.back() == b.m_worklist.back(); 75353358Sdim } 76353358Sdim friend bool operator!=(const ElaboratingDIEIterator &a, 77353358Sdim const ElaboratingDIEIterator &b) { 78353358Sdim return !(a == b); 79353358Sdim } 80353358Sdim}; 81353358Sdim 82353358Sdimllvm::iterator_range<ElaboratingDIEIterator> 83353358Sdimelaborating_dies(const DWARFDIE &die) { 84353358Sdim return llvm::make_range(ElaboratingDIEIterator(die), 85353358Sdim ElaboratingDIEIterator()); 86292932Sdim} 87353358Sdim} // namespace 88292932Sdim 89292932SdimDWARFDIE 90314564SdimDWARFDIE::GetParent() const { 91314564Sdim if (IsValid()) 92314564Sdim return DWARFDIE(m_cu, m_die->GetParent()); 93314564Sdim else 94314564Sdim return DWARFDIE(); 95292932Sdim} 96292932Sdim 97292932SdimDWARFDIE 98314564SdimDWARFDIE::GetFirstChild() const { 99314564Sdim if (IsValid()) 100314564Sdim return DWARFDIE(m_cu, m_die->GetFirstChild()); 101314564Sdim else 102314564Sdim return DWARFDIE(); 103292932Sdim} 104292932Sdim 105292932SdimDWARFDIE 106314564SdimDWARFDIE::GetSibling() const { 107314564Sdim if (IsValid()) 108314564Sdim return DWARFDIE(m_cu, m_die->GetSibling()); 109314564Sdim else 110314564Sdim return DWARFDIE(); 111292932Sdim} 112292932Sdim 113292932SdimDWARFDIE 114314564SdimDWARFDIE::GetReferencedDIE(const dw_attr_t attr) const { 115353358Sdim if (IsValid()) 116353358Sdim return m_die->GetAttributeValueAsReference(GetCU(), attr); 117314564Sdim else 118353358Sdim return {}; 119292932Sdim} 120292932Sdim 121292932SdimDWARFDIE 122314564SdimDWARFDIE::GetDIE(dw_offset_t die_offset) const { 123314564Sdim if (IsValid()) 124314564Sdim return m_cu->GetDIE(die_offset); 125314564Sdim else 126314564Sdim return DWARFDIE(); 127292932Sdim} 128292932Sdim 129309124SdimDWARFDIE 130314564SdimDWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { 131314564Sdim if (IsValid()) { 132341825Sdim DWARFUnit *cu = GetCU(); 133314564Sdim const bool check_specification_or_abstract_origin = true; 134314564Sdim DWARFFormValue form_value; 135353358Sdim if (m_die->GetAttributeValue(cu, attr, form_value, nullptr, 136314564Sdim check_specification_or_abstract_origin)) 137353358Sdim return form_value.Reference(); 138314564Sdim } 139314564Sdim return DWARFDIE(); 140309124Sdim} 141309124Sdim 142292932SdimDWARFDIE 143314564SdimDWARFDIE::LookupDeepestBlock(lldb::addr_t file_addr) const { 144314564Sdim if (IsValid()) { 145314564Sdim SymbolFileDWARF *dwarf = GetDWARF(); 146341825Sdim DWARFUnit *cu = GetCU(); 147314564Sdim DWARFDebugInfoEntry *function_die = nullptr; 148314564Sdim DWARFDebugInfoEntry *block_die = nullptr; 149353358Sdim if (m_die->LookupAddress(file_addr, cu, &function_die, &block_die)) { 150314564Sdim if (block_die && block_die != function_die) { 151314564Sdim if (cu->ContainsDIEOffset(block_die->GetOffset())) 152314564Sdim return DWARFDIE(cu, block_die); 153314564Sdim else 154353358Sdim return DWARFDIE(dwarf->DebugInfo()->GetUnit(DIERef( 155353358Sdim cu->GetSymbolFileDWARF().GetDwoNum(), 156353358Sdim cu->GetDebugSection(), block_die->GetOffset())), 157314564Sdim block_die); 158314564Sdim } 159292932Sdim } 160314564Sdim } 161314564Sdim return DWARFDIE(); 162292932Sdim} 163292932Sdim 164314564Sdimconst char *DWARFDIE::GetMangledName() const { 165314564Sdim if (IsValid()) 166353358Sdim return m_die->GetMangledName(m_cu); 167314564Sdim else 168314564Sdim return nullptr; 169292932Sdim} 170292932Sdim 171314564Sdimconst char *DWARFDIE::GetPubname() const { 172314564Sdim if (IsValid()) 173353358Sdim return m_die->GetPubname(m_cu); 174314564Sdim else 175314564Sdim return nullptr; 176292932Sdim} 177292932Sdim 178314564Sdimconst char *DWARFDIE::GetQualifiedName(std::string &storage) const { 179314564Sdim if (IsValid()) 180353358Sdim return m_die->GetQualifiedName(m_cu, storage); 181314564Sdim else 182314564Sdim return nullptr; 183292932Sdim} 184292932Sdim 185353358Sdim// GetName 186353358Sdim// 187353358Sdim// Get value of the DW_AT_name attribute and place that value into the supplied 188353358Sdim// stream object. If the DIE is a NULL object "NULL" is placed into the stream, 189353358Sdim// and if no DW_AT_name attribute exists for the DIE then nothing is printed. 190353358Sdimvoid DWARFDIE::GetName(Stream &s) const { 191353358Sdim if (!IsValid()) 192353358Sdim return; 193353358Sdim if (GetDIE()->IsNULL()) { 194353358Sdim s.PutCString("NULL"); 195353358Sdim return; 196353358Sdim } 197353358Sdim const char *name = GetDIE()->GetAttributeValueAsString(GetCU(), DW_AT_name, nullptr, true); 198353358Sdim if (!name) 199353358Sdim return; 200353358Sdim s.PutCString(name); 201353358Sdim} 202353358Sdim 203353358Sdim// AppendTypeName 204353358Sdim// 205353358Sdim// Follows the type name definition down through all needed tags to end up with 206353358Sdim// a fully qualified type name and dump the results to the supplied stream. 207353358Sdim// This is used to show the name of types given a type identifier. 208353358Sdimvoid DWARFDIE::AppendTypeName(Stream &s) const { 209353358Sdim if (!IsValid()) 210353358Sdim return; 211353358Sdim if (GetDIE()->IsNULL()) { 212353358Sdim s.PutCString("NULL"); 213353358Sdim return; 214353358Sdim } 215353358Sdim if (const char *name = GetPubname()) { 216353358Sdim s.PutCString(name); 217353358Sdim return; 218353358Sdim } 219353358Sdim switch (Tag()) { 220353358Sdim case DW_TAG_array_type: 221353358Sdim break; // print out a "[]" after printing the full type of the element 222353358Sdim // below 223353358Sdim case DW_TAG_base_type: 224353358Sdim s.PutCString("base "); 225353358Sdim break; 226353358Sdim case DW_TAG_class_type: 227353358Sdim s.PutCString("class "); 228353358Sdim break; 229353358Sdim case DW_TAG_const_type: 230353358Sdim s.PutCString("const "); 231353358Sdim break; 232353358Sdim case DW_TAG_enumeration_type: 233353358Sdim s.PutCString("enum "); 234353358Sdim break; 235353358Sdim case DW_TAG_file_type: 236353358Sdim s.PutCString("file "); 237353358Sdim break; 238353358Sdim case DW_TAG_interface_type: 239353358Sdim s.PutCString("interface "); 240353358Sdim break; 241353358Sdim case DW_TAG_packed_type: 242353358Sdim s.PutCString("packed "); 243353358Sdim break; 244353358Sdim case DW_TAG_pointer_type: 245353358Sdim break; // print out a '*' after printing the full type below 246353358Sdim case DW_TAG_ptr_to_member_type: 247353358Sdim break; // print out a '*' after printing the full type below 248353358Sdim case DW_TAG_reference_type: 249353358Sdim break; // print out a '&' after printing the full type below 250353358Sdim case DW_TAG_restrict_type: 251353358Sdim s.PutCString("restrict "); 252353358Sdim break; 253353358Sdim case DW_TAG_set_type: 254353358Sdim s.PutCString("set "); 255353358Sdim break; 256353358Sdim case DW_TAG_shared_type: 257353358Sdim s.PutCString("shared "); 258353358Sdim break; 259353358Sdim case DW_TAG_string_type: 260353358Sdim s.PutCString("string "); 261353358Sdim break; 262353358Sdim case DW_TAG_structure_type: 263353358Sdim s.PutCString("struct "); 264353358Sdim break; 265353358Sdim case DW_TAG_subrange_type: 266353358Sdim s.PutCString("subrange "); 267353358Sdim break; 268353358Sdim case DW_TAG_subroutine_type: 269353358Sdim s.PutCString("function "); 270353358Sdim break; 271353358Sdim case DW_TAG_thrown_type: 272353358Sdim s.PutCString("thrown "); 273353358Sdim break; 274353358Sdim case DW_TAG_union_type: 275353358Sdim s.PutCString("union "); 276353358Sdim break; 277353358Sdim case DW_TAG_unspecified_type: 278353358Sdim s.PutCString("unspecified "); 279353358Sdim break; 280353358Sdim case DW_TAG_volatile_type: 281353358Sdim s.PutCString("volatile "); 282353358Sdim break; 283353358Sdim default: 284353358Sdim return; 285353358Sdim } 286353358Sdim 287353358Sdim // Follow the DW_AT_type if possible 288353358Sdim if (DWARFDIE next_die = GetAttributeValueAsReferenceDIE(DW_AT_type)) 289353358Sdim next_die.AppendTypeName(s); 290353358Sdim 291353358Sdim switch (Tag()) { 292353358Sdim case DW_TAG_array_type: 293353358Sdim s.PutCString("[]"); 294353358Sdim break; 295353358Sdim case DW_TAG_pointer_type: 296353358Sdim s.PutChar('*'); 297353358Sdim break; 298353358Sdim case DW_TAG_ptr_to_member_type: 299353358Sdim s.PutChar('*'); 300353358Sdim break; 301353358Sdim case DW_TAG_reference_type: 302353358Sdim s.PutChar('&'); 303353358Sdim break; 304353358Sdim default: 305353358Sdim break; 306353358Sdim } 307353358Sdim} 308353358Sdim 309314564Sdimlldb_private::Type *DWARFDIE::ResolveType() const { 310314564Sdim if (IsValid()) 311314564Sdim return GetDWARF()->ResolveType(*this, true); 312314564Sdim else 313314564Sdim return nullptr; 314292932Sdim} 315292932Sdim 316353358Sdimlldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const { 317353358Sdim if (SymbolFileDWARF *dwarf = GetDWARF()) 318353358Sdim return dwarf->ResolveTypeUID(die, true); 319353358Sdim return nullptr; 320292932Sdim} 321292932Sdim 322353358Sdimstd::vector<DWARFDIE> DWARFDIE::GetDeclContextDIEs() const { 323353358Sdim if (!IsValid()) 324353358Sdim return {}; 325353358Sdim 326353358Sdim std::vector<DWARFDIE> result; 327353358Sdim DWARFDIE parent = GetParentDeclContextDIE(); 328353358Sdim while (parent.IsValid() && parent.GetDIE() != GetDIE()) { 329353358Sdim result.push_back(std::move(parent)); 330353358Sdim parent = parent.GetParentDeclContextDIE(); 331314564Sdim } 332353358Sdim 333353358Sdim return result; 334292932Sdim} 335292932Sdim 336314564Sdimvoid DWARFDIE::GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const { 337314564Sdim if (IsValid()) { 338314564Sdim dwarf_decl_ctx.SetLanguage(GetLanguage()); 339353358Sdim m_die->GetDWARFDeclContext(GetCU(), dwarf_decl_ctx); 340314564Sdim } else { 341314564Sdim dwarf_decl_ctx.Clear(); 342314564Sdim } 343292932Sdim} 344292932Sdim 345360784Sdimvoid DWARFDIE::GetDeclContext( 346360784Sdim llvm::SmallVectorImpl<lldb_private::CompilerContext> &context) const { 347314564Sdim const dw_tag_t tag = Tag(); 348341825Sdim if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) 349314564Sdim return; 350314564Sdim DWARFDIE parent = GetParent(); 351314564Sdim if (parent) 352344779Sdim parent.GetDeclContext(context); 353314564Sdim switch (tag) { 354314564Sdim case DW_TAG_module: 355360784Sdim context.push_back({CompilerContextKind::Module, ConstString(GetName())}); 356314564Sdim break; 357314564Sdim case DW_TAG_namespace: 358360784Sdim context.push_back({CompilerContextKind::Namespace, ConstString(GetName())}); 359314564Sdim break; 360314564Sdim case DW_TAG_structure_type: 361360784Sdim context.push_back({CompilerContextKind::Struct, ConstString(GetName())}); 362314564Sdim break; 363314564Sdim case DW_TAG_union_type: 364360784Sdim context.push_back({CompilerContextKind::Union, ConstString(GetName())}); 365314564Sdim break; 366314564Sdim case DW_TAG_class_type: 367360784Sdim context.push_back({CompilerContextKind::Class, ConstString(GetName())}); 368314564Sdim break; 369314564Sdim case DW_TAG_enumeration_type: 370360784Sdim context.push_back({CompilerContextKind::Enum, ConstString(GetName())}); 371314564Sdim break; 372314564Sdim case DW_TAG_subprogram: 373360784Sdim context.push_back( 374360784Sdim {CompilerContextKind::Function, ConstString(GetPubname())}); 375314564Sdim break; 376314564Sdim case DW_TAG_variable: 377360784Sdim context.push_back( 378360784Sdim {CompilerContextKind::Variable, ConstString(GetPubname())}); 379314564Sdim break; 380314564Sdim case DW_TAG_typedef: 381360784Sdim context.push_back({CompilerContextKind::Typedef, ConstString(GetName())}); 382314564Sdim break; 383314564Sdim default: 384314564Sdim break; 385314564Sdim } 386292932Sdim} 387292932Sdim 388292932SdimDWARFDIE 389314564SdimDWARFDIE::GetParentDeclContextDIE() const { 390314564Sdim if (IsValid()) 391353358Sdim return m_die->GetParentDeclContextDIE(m_cu); 392314564Sdim else 393314564Sdim return DWARFDIE(); 394292932Sdim} 395292932Sdim 396341825Sdimbool DWARFDIE::IsStructUnionOrClass() const { 397341825Sdim const dw_tag_t tag = Tag(); 398341825Sdim return tag == DW_TAG_class_type || tag == DW_TAG_structure_type || 399341825Sdim tag == DW_TAG_union_type; 400292932Sdim} 401292932Sdim 402341825Sdimbool DWARFDIE::IsMethod() const { 403353358Sdim for (DWARFDIE d : elaborating_dies(*this)) 404341825Sdim if (d.GetParent().IsStructUnionOrClass()) 405341825Sdim return true; 406341825Sdim return false; 407292932Sdim} 408292932Sdim 409314564Sdimbool DWARFDIE::GetDIENamesAndRanges( 410314564Sdim const char *&name, const char *&mangled, DWARFRangeList &ranges, 411314564Sdim int &decl_file, int &decl_line, int &decl_column, int &call_file, 412314564Sdim int &call_line, int &call_column, 413314564Sdim lldb_private::DWARFExpression *frame_base) const { 414314564Sdim if (IsValid()) { 415314564Sdim return m_die->GetDIENamesAndRanges( 416353358Sdim GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column, 417353358Sdim call_file, call_line, call_column, frame_base); 418314564Sdim } else 419314564Sdim return false; 420292932Sdim} 421292932Sdim 422314564SdimCompilerDecl DWARFDIE::GetDecl() const { 423314564Sdim DWARFASTParser *dwarf_ast = GetDWARFParser(); 424314564Sdim if (dwarf_ast) 425314564Sdim return dwarf_ast->GetDeclForUIDFromDWARF(*this); 426314564Sdim else 427314564Sdim return CompilerDecl(); 428309124Sdim} 429309124Sdim 430314564SdimCompilerDeclContext DWARFDIE::GetDeclContext() const { 431314564Sdim DWARFASTParser *dwarf_ast = GetDWARFParser(); 432314564Sdim if (dwarf_ast) 433314564Sdim return dwarf_ast->GetDeclContextForUIDFromDWARF(*this); 434314564Sdim else 435314564Sdim return CompilerDeclContext(); 436309124Sdim} 437309124Sdim 438314564SdimCompilerDeclContext DWARFDIE::GetContainingDeclContext() const { 439314564Sdim DWARFASTParser *dwarf_ast = GetDWARFParser(); 440314564Sdim if (dwarf_ast) 441314564Sdim return dwarf_ast->GetDeclContextContainingUIDFromDWARF(*this); 442314564Sdim else 443314564Sdim return CompilerDeclContext(); 444309124Sdim} 445