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-exception 6 // 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 25 using namespace lldb_private; 26 using namespace lldb_private::dwarf; 27 using namespace lldb_private::plugin::dwarf; 28 29 namespace { 30 31 /// Iterate through all DIEs elaborating (i.e. reachable by a chain of 32 /// DW_AT_specification, DW_AT_abstract_origin and/or DW_AT_signature 33 /// attributes) a given DIE. For convenience, the starting die is included in 34 /// the sequence as the first item. 35 class ElaboratingDIEIterator 36 : 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" item 41 // and the rest of the list are items yet to be visited. An empty worklist 42 // 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_specification 45 // and DW_AT_abstract_origin just once. 46 llvm::SmallVector<DWARFDIE, 2> m_worklist; 47 llvm::SmallSet<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 65 public: 66 /// An iterator starting at die d. 67 explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {} 68 69 /// End marker 70 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 86 llvm::iterator_range<ElaboratingDIEIterator> 87 elaborating_dies(const DWARFDIE &die) { 88 return llvm::make_range(ElaboratingDIEIterator(die), 89 ElaboratingDIEIterator()); 90 } 91 } // namespace 92 93 DWARFDIE 94 DWARFDIE::GetParent() const { 95 if (IsValid()) 96 return DWARFDIE(m_cu, m_die->GetParent()); 97 else 98 return DWARFDIE(); 99 } 100 101 DWARFDIE 102 DWARFDIE::GetFirstChild() const { 103 if (IsValid()) 104 return DWARFDIE(m_cu, m_die->GetFirstChild()); 105 else 106 return DWARFDIE(); 107 } 108 109 DWARFDIE 110 DWARFDIE::GetSibling() const { 111 if (IsValid()) 112 return DWARFDIE(m_cu, m_die->GetSibling()); 113 else 114 return DWARFDIE(); 115 } 116 117 DWARFDIE 118 DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const { 119 if (IsValid()) 120 return m_die->GetAttributeValueAsReference(GetCU(), attr); 121 else 122 return {}; 123 } 124 125 DWARFDIE 126 DWARFDIE::GetDIE(dw_offset_t die_offset) const { 127 if (IsValid()) 128 return m_cu->GetDIE(die_offset); 129 else 130 return DWARFDIE(); 131 } 132 133 DWARFDIE 134 DWARFDIE::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 146 DWARFDIE 147 DWARFDIE::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 Function 191 case DW_TAG_lexical_block: // Block { } in code 192 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 212 const char *DWARFDIE::GetMangledName(bool substitute_name_allowed) const { 213 if (IsValid()) 214 return m_die->GetMangledName(m_cu, substitute_name_allowed); 215 else 216 return nullptr; 217 } 218 219 const char *DWARFDIE::GetPubname() const { 220 if (IsValid()) 221 return m_die->GetPubname(m_cu); 222 else 223 return nullptr; 224 } 225 226 // GetName 227 // 228 // Get value of the DW_AT_name attribute and place that value into the supplied 229 // 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. 231 void 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 // AppendTypeName 245 // 246 // Follows the type name definition down through all needed tags to end up with 247 // 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. 249 void 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 element 263 // below 264 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 below 287 case DW_TAG_ptr_to_member_type: 288 break; // print out a '*' after printing the full type below 289 case DW_TAG_reference_type: 290 break; // print out a '&' after printing the full type below 291 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 possible 347 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 368 lldb_private::Type *DWARFDIE::ResolveType() const { 369 if (IsValid()) 370 return GetDWARF()->ResolveType(*this, true); 371 else 372 return nullptr; 373 } 374 375 lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const { 376 if (SymbolFileDWARF *dwarf = GetDWARF()) 377 return dwarf->ResolveTypeUID(die, true); 378 return nullptr; 379 } 380 381 static 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_type 406 ? CompilerContextKind::Union 407 : 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 423 static 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 455 std::vector<CompilerContext> 456 DWARFDIE::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 464 static 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 decl 483 // context and return. Prior to these being in here, if a type existed in a 484 // namespace "a" like "a::my_struct", but we also have a function in that 485 // same namespace "a" which contained a type named "my_struct", both would 486 // return "a::my_struct" as the declaration context since the 487 // 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 502 std::vector<CompilerContext> 503 DWARFDIE::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 511 static 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 526 DWARFDeclContext DWARFDIE::GetDWARFDeclContext() const { 527 return GetDWARFDeclContextImpl(*this); 528 } 529 530 static 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 be 535 // 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 566 DWARFDIE 567 DWARFDIE::GetParentDeclContextDIE() const { 568 return GetParentDeclContextDIEImpl(*this); 569 } 570 571 bool 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 577 bool DWARFDIE::IsMethod() const { 578 for (DWARFDIE d : elaborating_dies(*this)) 579 if (d.GetParent().IsStructUnionOrClass()) 580 return true; 581 return false; 582 } 583 584 bool 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 } else 596 return false; 597 } 598 599 // The following methods use LLVM naming convension in order to be are used by 600 // LLVM libraries. 601 llvm::iterator_range<DWARFDIE::child_iterator> DWARFDIE::children() const { 602 return llvm::make_range(child_iterator(*this), child_iterator()); 603 } 604 605 DWARFDIE::child_iterator DWARFDIE::begin() const { 606 return child_iterator(*this); 607 } 608 609 DWARFDIE::child_iterator DWARFDIE::end() const { return child_iterator(); } 610 611 std::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 618 std::optional<uint64_t> DWARFDIE::getLanguage() const { 619 if (IsValid()) 620 return m_cu->GetDWARFLanguageType(); 621 return std::nullopt; 622 } 623 624 DWARFDIE DWARFDIE::resolveReferencedType(dw_attr_t attr) const { 625 return GetReferencedDIE(attr); 626 } 627 628 DWARFDIE DWARFDIE::resolveReferencedType(DWARFFormValue v) const { 629 if (IsValid()) 630 return v.Reference(); 631 return {}; 632 } 633 634 DWARFDIE DWARFDIE::resolveTypeUnitReference() const { 635 if (DWARFDIE reference = GetReferencedDIE(DW_AT_signature)) 636 return reference; 637 return *this; 638 } 639