brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.6 KiB · 1bfa17f Raw
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