| 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(Ptr: die.GetDIE()).second) |
| 61 | m_worklist.push_back(Elt: 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(x: ElaboratingDIEIterator(die), |
| 89 | y: 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(cu: 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, formValue&: form_value, end_attr_offset_ptr: 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(cu: m_cu, /*check_hi_lo_pc=*/true)) { |
| 181 | bool addr_in_range = |
| 182 | llvm::any_of(Range&: *ranges, P: [&](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(cu: 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(cu: 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(cstr: "NULL" ); |
| 236 | return; |
| 237 | } |
| 238 | const char *name = GetDIE()->GetAttributeValueAsString(cu: GetCU(), attr: DW_AT_name, fail_value: nullptr, check_elaborating_dies: true); |
| 239 | if (!name) |
| 240 | return; |
| 241 | s.PutCString(cstr: 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(cstr: "NULL" ); |
| 254 | return; |
| 255 | } |
| 256 | if (const char *name = GetPubname()) { |
| 257 | s.PutCString(cstr: 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(cstr: "base " ); |
| 266 | break; |
| 267 | case DW_TAG_class_type: |
| 268 | s.PutCString(cstr: "class " ); |
| 269 | break; |
| 270 | case DW_TAG_const_type: |
| 271 | s.PutCString(cstr: "const " ); |
| 272 | break; |
| 273 | case DW_TAG_enumeration_type: |
| 274 | s.PutCString(cstr: "enum " ); |
| 275 | break; |
| 276 | case DW_TAG_file_type: |
| 277 | s.PutCString(cstr: "file " ); |
| 278 | break; |
| 279 | case DW_TAG_interface_type: |
| 280 | s.PutCString(cstr: "interface " ); |
| 281 | break; |
| 282 | case DW_TAG_packed_type: |
| 283 | s.PutCString(cstr: "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(cstr: "restrict " ); |
| 293 | break; |
| 294 | case DW_TAG_set_type: |
| 295 | s.PutCString(cstr: "set " ); |
| 296 | break; |
| 297 | case DW_TAG_shared_type: |
| 298 | s.PutCString(cstr: "shared " ); |
| 299 | break; |
| 300 | case DW_TAG_string_type: |
| 301 | s.PutCString(cstr: "string " ); |
| 302 | break; |
| 303 | case DW_TAG_structure_type: |
| 304 | s.PutCString(cstr: "struct " ); |
| 305 | break; |
| 306 | case DW_TAG_subrange_type: |
| 307 | s.PutCString(cstr: "subrange " ); |
| 308 | break; |
| 309 | case DW_TAG_subroutine_type: |
| 310 | s.PutCString(cstr: "function " ); |
| 311 | break; |
| 312 | case DW_TAG_thrown_type: |
| 313 | s.PutCString(cstr: "thrown " ); |
| 314 | break; |
| 315 | case DW_TAG_union_type: |
| 316 | s.PutCString(cstr: "union " ); |
| 317 | break; |
| 318 | case DW_TAG_unspecified_type: |
| 319 | s.PutCString(cstr: "unspecified " ); |
| 320 | break; |
| 321 | case DW_TAG_volatile_type: |
| 322 | s.PutCString(cstr: "volatile " ); |
| 323 | break; |
| 324 | case DW_TAG_LLVM_ptrauth_type: { |
| 325 | unsigned key = GetAttributeValueAsUnsigned(attr: DW_AT_LLVM_ptrauth_key, fail_value: 0); |
| 326 | bool isAddressDiscriminated = GetAttributeValueAsUnsigned( |
| 327 | attr: DW_AT_LLVM_ptrauth_address_discriminated, fail_value: 0); |
| 328 | unsigned = |
| 329 | GetAttributeValueAsUnsigned(attr: DW_AT_LLVM_ptrauth_extra_discriminator, fail_value: 0); |
| 330 | bool isaPointer = |
| 331 | GetAttributeValueAsUnsigned(attr: DW_AT_LLVM_ptrauth_isa_pointer, fail_value: 0); |
| 332 | bool authenticatesNullValues = GetAttributeValueAsUnsigned( |
| 333 | attr: DW_AT_LLVM_ptrauth_authenticates_null_values, fail_value: 0); |
| 334 | unsigned authenticationMode = |
| 335 | GetAttributeValueAsUnsigned(attr: DW_AT_LLVM_ptrauth_authentication_mode, fail_value: 3); |
| 336 | |
| 337 | s.Printf(format: "__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(attr: DW_AT_type)) |
| 348 | next_die.AppendTypeName(s); |
| 349 | |
| 350 | switch (Tag()) { |
| 351 | case DW_TAG_array_type: |
| 352 | s.PutCString(cstr: "[]" ); |
| 353 | break; |
| 354 | case DW_TAG_pointer_type: |
| 355 | s.PutChar(ch: '*'); |
| 356 | break; |
| 357 | case DW_TAG_ptr_to_member_type: |
| 358 | s.PutChar(ch: '*'); |
| 359 | break; |
| 360 | case DW_TAG_reference_type: |
| 361 | s.PutChar(ch: '&'); |
| 362 | break; |
| 363 | default: |
| 364 | break; |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | lldb_private::Type *DWARFDIE::ResolveType() const { |
| 369 | if (IsValid()) |
| 370 | return GetDWARF()->ResolveType(die: *this, assert_not_being_parsed: 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, assert_not_being_parsed: 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(C: '<')) |
| 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 | D: 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(V: die.GetID()).second) { |
| 428 | // Handle outline member function DIEs by following the specification. |
| 429 | if (DWARFDIE spec = die.GetReferencedDIE(attr: 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(x: 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(die: *this, derive_template_names, seen, context); |
| 460 | std::reverse(first: context.begin(), last: 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(V: 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(x: 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(die: *this, derive_template_names, seen, context); |
| 507 | std::reverse(first: context.begin(), last: 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, name: 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(die: *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(attr: 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(attr: 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(die: *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(die: *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 | cu: GetCU(), name, mangled, rangeList&: 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(x: child_iterator(*this), y: 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(cu: m_cu, attr, formValue&: form_value, end_attr_offset_ptr: nullptr, check_elaborating_dies: 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).resolveTypeUnitReference(); |
| 626 | } |
| 627 | |
| 628 | DWARFDIE DWARFDIE::resolveReferencedType(DWARFFormValue v) const { |
| 629 | if (IsValid()) |
| 630 | return v.Reference().resolveTypeUnitReference(); |
| 631 | return {}; |
| 632 | } |
| 633 | |
| 634 | DWARFDIE DWARFDIE::resolveTypeUnitReference() const { |
| 635 | if (DWARFDIE reference = GetReferencedDIE(attr: DW_AT_signature)) |
| 636 | return reference; |
| 637 | return *this; |
| 638 | } |
| 639 | |