diff options
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFDie.cpp')
| -rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 740 | 
1 files changed, 740 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp new file mode 100644 index 0000000000000..cec194e8b6b3e --- /dev/null +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -0,0 +1,740 @@ +//===- DWARFDie.cpp -------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <string> +#include <utility> + +using namespace llvm; +using namespace dwarf; +using namespace object; + +static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { +  OS << " ("; +  do { +    uint64_t Shift = countTrailingZeros(Val); +    assert(Shift < 64 && "undefined behavior"); +    uint64_t Bit = 1ULL << Shift; +    auto PropName = ApplePropertyString(Bit); +    if (!PropName.empty()) +      OS << PropName; +    else +      OS << format("DW_APPLE_PROPERTY_0x%" PRIx64, Bit); +    if (!(Val ^= Bit)) +      break; +    OS << ", "; +  } while (true); +  OS << ")"; +} + +static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS, +                       const DWARFAddressRangesVector &Ranges, +                       unsigned AddressSize, unsigned Indent, +                       const DIDumpOptions &DumpOpts) { +  if (!DumpOpts.ShowAddresses) +    return; + +  ArrayRef<SectionName> SectionNames; +  if (DumpOpts.Verbose) +    SectionNames = Obj.getSectionNames(); + +  for (const DWARFAddressRange &R : Ranges) { +    OS << '\n'; +    OS.indent(Indent); +    R.dump(OS, AddressSize); + +    DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, R.SectionIndex); +  } +} + +static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue, +                         DWARFUnit *U, unsigned Indent, +                         DIDumpOptions DumpOpts) { +  DWARFContext &Ctx = U->getContext(); +  const DWARFObject &Obj = Ctx.getDWARFObj(); +  const MCRegisterInfo *MRI = Ctx.getRegisterInfo(); +  if (FormValue.isFormClass(DWARFFormValue::FC_Block) || +      FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) { +    ArrayRef<uint8_t> Expr = *FormValue.getAsBlock(); +    DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), +                       Ctx.isLittleEndian(), 0); +    DWARFExpression(Data, U->getVersion(), U->getAddressByteSize()) +        .print(OS, MRI, U); +    return; +  } + +  FormValue.dump(OS, DumpOpts); +  const auto &DumpLL = [&](auto ExpectedLL) { +    if (ExpectedLL) { +      uint64_t BaseAddr = 0; +      if (Optional<object::SectionedAddress> BA = U->getBaseAddress()) +        BaseAddr = BA->Address; +      auto LLDumpOpts = DumpOpts; +      LLDumpOpts.Verbose = false; +      ExpectedLL->dump(OS, BaseAddr, Ctx.isLittleEndian(), Obj.getAddressSize(), +                       MRI, U, LLDumpOpts, Indent); +    } else { +      OS << '\n'; +      OS.indent(Indent); +      OS << formatv("error extracting location list: {0}", +                    fmt_consume(ExpectedLL.takeError())); +    } +  }; +  if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { +    uint64_t Offset = *FormValue.getAsSectionOffset(); +    if (!U->isDWOUnit() && !U->getLocSection()->Data.empty()) { +      DWARFDebugLoc DebugLoc; +      DWARFDataExtractor Data(Obj, *U->getLocSection(), Ctx.isLittleEndian(), +                              Obj.getAddressSize()); +      DumpLL(DebugLoc.parseOneLocationList(Data, &Offset)); +      return; +    } + +    bool UseLocLists = !U->isDWOUnit(); +    StringRef LoclistsSectionData = +        UseLocLists ? Obj.getLoclistsSection().Data : U->getLocSectionData(); + +    if (!LoclistsSectionData.empty()) { +      DataExtractor Data(LoclistsSectionData, Ctx.isLittleEndian(), +                         Obj.getAddressSize()); + +      // Old-style location list were used in DWARF v4 (.debug_loc.dwo section). +      // Modern locations list (.debug_loclists) are used starting from v5. +      // Ideally we should take the version from the .debug_loclists section +      // header, but using CU's version for simplicity. +      DumpLL(DWARFDebugLoclists::parseOneLocationList( +          Data, &Offset, UseLocLists ? U->getVersion() : 4)); +    } +  } +} + +/// Dump the name encoded in the type tag. +static void dumpTypeTagName(raw_ostream &OS, dwarf::Tag T) { +  StringRef TagStr = TagString(T); +  if (!TagStr.startswith("DW_TAG_") || !TagStr.endswith("_type")) +    return; +  OS << TagStr.substr(7, TagStr.size() - 12) << " "; +} + +static void dumpArrayType(raw_ostream &OS, const DWARFDie &D) { +  Optional<uint64_t> Bound; +  for (const DWARFDie &C : D.children()) +    if (C.getTag() == DW_TAG_subrange_type) { +      Optional<uint64_t> LB; +      Optional<uint64_t> Count; +      Optional<uint64_t> UB; +      Optional<unsigned> DefaultLB; +      if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound)) +        LB = L->getAsUnsignedConstant(); +      if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count)) +        Count = CountV->getAsUnsignedConstant(); +      if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound)) +        UB = UpperV->getAsUnsignedConstant(); +      if (Optional<DWARFFormValue> LV = +              D.getDwarfUnit()->getUnitDIE().find(DW_AT_language)) +        if (Optional<uint64_t> LC = LV->getAsUnsignedConstant()) +          if ((DefaultLB = +                   LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC)))) +            if (LB && *LB == *DefaultLB) +              LB = None; +      if (!LB && !Count && !UB) +        OS << "[]"; +      else if (!LB && (Count || UB) && DefaultLB) +        OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']'; +      else { +        OS << "[["; +        if (LB) +          OS << *LB; +        else +          OS << '?'; +        OS << ", "; +        if (Count) +          if (LB) +            OS << *LB + *Count; +          else +            OS << "? + " << *Count; +        else if (UB) +          OS << *UB + 1; +        else +          OS << '?'; +        OS << ")]"; +      } +    } +} + +/// Recursively dump the DIE type name when applicable. +static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) { +  if (!D.isValid()) +    return; + +  if (const char *Name = D.getName(DINameKind::LinkageName)) { +    OS << Name; +    return; +  } + +  // FIXME: We should have pretty printers per language. Currently we print +  // everything as if it was C++ and fall back to the TAG type name. +  const dwarf::Tag T = D.getTag(); +  switch (T) { +  case DW_TAG_array_type: +  case DW_TAG_pointer_type: +  case DW_TAG_ptr_to_member_type: +  case DW_TAG_reference_type: +  case DW_TAG_rvalue_reference_type: +  case DW_TAG_subroutine_type: +    break; +  default: +    dumpTypeTagName(OS, T); +  } + +  // Follow the DW_AT_type if possible. +  DWARFDie TypeDie = D.getAttributeValueAsReferencedDie(DW_AT_type); +  dumpTypeName(OS, TypeDie); + +  switch (T) { +  case DW_TAG_subroutine_type: { +    if (!TypeDie) +      OS << "void"; +    OS << '('; +    bool First = true; +    for (const DWARFDie &C : D.children()) { +      if (C.getTag() == DW_TAG_formal_parameter) { +        if (!First) +          OS << ", "; +        First = false; +        dumpTypeName(OS, C.getAttributeValueAsReferencedDie(DW_AT_type)); +      } +    } +    OS << ')'; +    break; +  } +  case DW_TAG_array_type: { +    dumpArrayType(OS, D); +    break; +  } +  case DW_TAG_pointer_type: +    OS << '*'; +    break; +  case DW_TAG_ptr_to_member_type: +    if (DWARFDie Cont = +            D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) { +      dumpTypeName(OS << ' ', Cont); +      OS << "::"; +    } +    OS << '*'; +    break; +  case DW_TAG_reference_type: +    OS << '&'; +    break; +  case DW_TAG_rvalue_reference_type: +    OS << "&&"; +    break; +  default: +    break; +  } +} + +static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, +                          uint64_t *OffsetPtr, dwarf::Attribute Attr, +                          dwarf::Form Form, unsigned Indent, +                          DIDumpOptions DumpOpts) { +  if (!Die.isValid()) +    return; +  const char BaseIndent[] = "            "; +  OS << BaseIndent; +  OS.indent(Indent + 2); +  WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr); + +  if (DumpOpts.Verbose || DumpOpts.ShowForm) +    OS << formatv(" [{0}]", Form); + +  DWARFUnit *U = Die.getDwarfUnit(); +  DWARFFormValue FormValue = DWARFFormValue::createFromUnit(Form, U, OffsetPtr); + +  OS << "\t("; + +  StringRef Name; +  std::string File; +  auto Color = HighlightColor::Enumerator; +  if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { +    Color = HighlightColor::String; +    if (const auto *LT = U->getContext().getLineTableForUnit(U)) +      if (LT->getFileNameByIndex( +              FormValue.getAsUnsignedConstant().getValue(), +              U->getCompilationDir(), +              DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) { +        File = '"' + File + '"'; +        Name = File; +      } +  } else if (Optional<uint64_t> Val = FormValue.getAsUnsignedConstant()) +    Name = AttributeValueString(Attr, *Val); + +  if (!Name.empty()) +    WithColor(OS, Color) << Name; +  else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line) +    OS << *FormValue.getAsUnsignedConstant(); +  else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose && +           FormValue.getAsUnsignedConstant()) { +    if (DumpOpts.ShowAddresses) { +      // Print the actual address rather than the offset. +      uint64_t LowPC, HighPC, Index; +      if (Die.getLowAndHighPC(LowPC, HighPC, Index)) +        OS << format("0x%016" PRIx64, HighPC); +      else +        FormValue.dump(OS, DumpOpts); +    } +  } else if (DWARFAttribute::mayHaveLocationDescription(Attr)) +    dumpLocation(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts); +  else +    FormValue.dump(OS, DumpOpts); + +  std::string Space = DumpOpts.ShowAddresses ? " " : ""; + +  // We have dumped the attribute raw value. For some attributes +  // having both the raw value and the pretty-printed value is +  // interesting. These attributes are handled below. +  if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) { +    if (const char *Name = +            Die.getAttributeValueAsReferencedDie(FormValue).getName( +                DINameKind::LinkageName)) +      OS << Space << "\"" << Name << '\"'; +  } else if (Attr == DW_AT_type) { +    OS << Space << "\""; +    dumpTypeName(OS, Die.getAttributeValueAsReferencedDie(FormValue)); +    OS << '"'; +  } else if (Attr == DW_AT_APPLE_property_attribute) { +    if (Optional<uint64_t> OptVal = FormValue.getAsUnsignedConstant()) +      dumpApplePropertyAttribute(OS, *OptVal); +  } else if (Attr == DW_AT_ranges) { +    const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj(); +    // For DW_FORM_rnglistx we need to dump the offset separately, since +    // we have only dumped the index so far. +    if (FormValue.getForm() == DW_FORM_rnglistx) +      if (auto RangeListOffset = +              U->getRnglistOffset(*FormValue.getAsSectionOffset())) { +        DWARFFormValue FV = DWARFFormValue::createFromUValue( +            dwarf::DW_FORM_sec_offset, *RangeListOffset); +        FV.dump(OS, DumpOpts); +      } +    if (auto RangesOrError = Die.getAddressRanges()) +      dumpRanges(Obj, OS, RangesOrError.get(), U->getAddressByteSize(), +                 sizeof(BaseIndent) + Indent + 4, DumpOpts); +    else +      WithColor::error() << "decoding address ranges: " +                         << toString(RangesOrError.takeError()) << '\n'; +  } + +  OS << ")\n"; +} + +bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; } + +bool DWARFDie::isSubroutineDIE() const { +  auto Tag = getTag(); +  return Tag == DW_TAG_subprogram || Tag == DW_TAG_inlined_subroutine; +} + +Optional<DWARFFormValue> DWARFDie::find(dwarf::Attribute Attr) const { +  if (!isValid()) +    return None; +  auto AbbrevDecl = getAbbreviationDeclarationPtr(); +  if (AbbrevDecl) +    return AbbrevDecl->getAttributeValue(getOffset(), Attr, *U); +  return None; +} + +Optional<DWARFFormValue> +DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const { +  if (!isValid()) +    return None; +  auto AbbrevDecl = getAbbreviationDeclarationPtr(); +  if (AbbrevDecl) { +    for (auto Attr : Attrs) { +      if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U)) +        return Value; +    } +  } +  return None; +} + +Optional<DWARFFormValue> +DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const { +  std::vector<DWARFDie> Worklist; +  Worklist.push_back(*this); + +  // Keep track if DIEs already seen to prevent infinite recursion. +  // Empirically we rarely see a depth of more than 3 when dealing with valid +  // DWARF. This corresponds to following the DW_AT_abstract_origin and +  // DW_AT_specification just once. +  SmallSet<DWARFDie, 3> Seen; +  Seen.insert(*this); + +  while (!Worklist.empty()) { +    DWARFDie Die = Worklist.back(); +    Worklist.pop_back(); + +    if (!Die.isValid()) +      continue; + +    if (auto Value = Die.find(Attrs)) +      return Value; + +    if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) +      if (Seen.insert(D).second) +        Worklist.push_back(D); + +    if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification)) +      if (Seen.insert(D).second) +        Worklist.push_back(D); +  } + +  return None; +} + +DWARFDie +DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { +  if (Optional<DWARFFormValue> F = find(Attr)) +    return getAttributeValueAsReferencedDie(*F); +  return DWARFDie(); +} + +DWARFDie +DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const { +  if (auto SpecRef = V.getAsRelativeReference()) { +    if (SpecRef->Unit) +      return SpecRef->Unit->getDIEForOffset(SpecRef->Unit->getOffset() + SpecRef->Offset); +    if (auto SpecUnit = U->getUnitVector().getUnitForOffset(SpecRef->Offset)) +      return SpecUnit->getDIEForOffset(SpecRef->Offset); +  } +  return DWARFDie(); +} + +Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const { +  return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); +} + +Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { +  if (auto FormValue = find(DW_AT_high_pc)) { +    if (auto Address = FormValue->getAsAddress()) { +      // High PC is an address. +      return Address; +    } +    if (auto Offset = FormValue->getAsUnsignedConstant()) { +      // High PC is an offset from LowPC. +      return LowPC + *Offset; +    } +  } +  return None; +} + +bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC, +                               uint64_t &SectionIndex) const { +  auto F = find(DW_AT_low_pc); +  auto LowPcAddr = toSectionedAddress(F); +  if (!LowPcAddr) +    return false; +  if (auto HighPcAddr = getHighPC(LowPcAddr->Address)) { +    LowPC = LowPcAddr->Address; +    HighPC = *HighPcAddr; +    SectionIndex = LowPcAddr->SectionIndex; +    return true; +  } +  return false; +} + +Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const { +  if (isNULL()) +    return DWARFAddressRangesVector(); +  // Single range specified by low/high PC. +  uint64_t LowPC, HighPC, Index; +  if (getLowAndHighPC(LowPC, HighPC, Index)) +    return DWARFAddressRangesVector{{LowPC, HighPC, Index}}; + +  Optional<DWARFFormValue> Value = find(DW_AT_ranges); +  if (Value) { +    if (Value->getForm() == DW_FORM_rnglistx) +      return U->findRnglistFromIndex(*Value->getAsSectionOffset()); +    return U->findRnglistFromOffset(*Value->getAsSectionOffset()); +  } +  return DWARFAddressRangesVector(); +} + +void DWARFDie::collectChildrenAddressRanges( +    DWARFAddressRangesVector &Ranges) const { +  if (isNULL()) +    return; +  if (isSubprogramDIE()) { +    if (auto DIERangesOrError = getAddressRanges()) +      Ranges.insert(Ranges.end(), DIERangesOrError.get().begin(), +                    DIERangesOrError.get().end()); +    else +      llvm::consumeError(DIERangesOrError.takeError()); +  } + +  for (auto Child : children()) +    Child.collectChildrenAddressRanges(Ranges); +} + +bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { +  auto RangesOrError = getAddressRanges(); +  if (!RangesOrError) { +    llvm::consumeError(RangesOrError.takeError()); +    return false; +  } + +  for (const auto &R : RangesOrError.get()) +    if (R.LowPC <= Address && Address < R.HighPC) +      return true; +  return false; +} + +const char *DWARFDie::getSubroutineName(DINameKind Kind) const { +  if (!isSubroutineDIE()) +    return nullptr; +  return getName(Kind); +} + +const char *DWARFDie::getName(DINameKind Kind) const { +  if (!isValid() || Kind == DINameKind::None) +    return nullptr; +  // Try to get mangled name only if it was asked for. +  if (Kind == DINameKind::LinkageName) { +    if (auto Name = dwarf::toString( +            findRecursively({DW_AT_MIPS_linkage_name, DW_AT_linkage_name}), +            nullptr)) +      return Name; +  } +  if (auto Name = dwarf::toString(findRecursively(DW_AT_name), nullptr)) +    return Name; +  return nullptr; +} + +uint64_t DWARFDie::getDeclLine() const { +  return toUnsigned(findRecursively(DW_AT_decl_line), 0); +} + +void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, +                              uint32_t &CallColumn, +                              uint32_t &CallDiscriminator) const { +  CallFile = toUnsigned(find(DW_AT_call_file), 0); +  CallLine = toUnsigned(find(DW_AT_call_line), 0); +  CallColumn = toUnsigned(find(DW_AT_call_column), 0); +  CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0); +} + +/// Helper to dump a DIE with all of its parents, but no siblings. +static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, +                                DIDumpOptions DumpOpts, unsigned Depth = 0) { +  if (!Die) +    return Indent; +  if (DumpOpts.ParentRecurseDepth > 0 && Depth >= DumpOpts.ParentRecurseDepth) +    return Indent; +  Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts, Depth + 1); +  Die.dump(OS, Indent, DumpOpts); +  return Indent + 2; +} + +void DWARFDie::dump(raw_ostream &OS, unsigned Indent, +                    DIDumpOptions DumpOpts) const { +  if (!isValid()) +    return; +  DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor(); +  const uint64_t Offset = getOffset(); +  uint64_t offset = Offset; +  if (DumpOpts.ShowParents) { +    DIDumpOptions ParentDumpOpts = DumpOpts; +    ParentDumpOpts.ShowParents = false; +    ParentDumpOpts.ShowChildren = false; +    Indent = dumpParentChain(getParent(), OS, Indent, ParentDumpOpts); +  } + +  if (debug_info_data.isValidOffset(offset)) { +    uint32_t abbrCode = debug_info_data.getULEB128(&offset); +    if (DumpOpts.ShowAddresses) +      WithColor(OS, HighlightColor::Address).get() +          << format("\n0x%8.8" PRIx64 ": ", Offset); + +    if (abbrCode) { +      auto AbbrevDecl = getAbbreviationDeclarationPtr(); +      if (AbbrevDecl) { +        WithColor(OS, HighlightColor::Tag).get().indent(Indent) +            << formatv("{0}", getTag()); +        if (DumpOpts.Verbose) +          OS << format(" [%u] %c", abbrCode, +                       AbbrevDecl->hasChildren() ? '*' : ' '); +        OS << '\n'; + +        // Dump all data in the DIE for the attributes. +        for (const auto &AttrSpec : AbbrevDecl->attributes()) { +          if (AttrSpec.Form == DW_FORM_implicit_const) { +            // We are dumping .debug_info section , +            // implicit_const attribute values are not really stored here, +            // but in .debug_abbrev section. So we just skip such attrs. +            continue; +          } +          dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form, +                        Indent, DumpOpts); +        } + +        DWARFDie child = getFirstChild(); +        if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0 && child) { +          DumpOpts.ChildRecurseDepth--; +          DIDumpOptions ChildDumpOpts = DumpOpts; +          ChildDumpOpts.ShowParents = false; +          while (child) { +            child.dump(OS, Indent + 2, ChildDumpOpts); +            child = child.getSibling(); +          } +        } +      } else { +        OS << "Abbreviation code not found in 'debug_abbrev' class for code: " +           << abbrCode << '\n'; +      } +    } else { +      OS.indent(Indent) << "NULL\n"; +    } +  } +} + +LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(llvm::errs(), 0); } + +DWARFDie DWARFDie::getParent() const { +  if (isValid()) +    return U->getParent(Die); +  return DWARFDie(); +} + +DWARFDie DWARFDie::getSibling() const { +  if (isValid()) +    return U->getSibling(Die); +  return DWARFDie(); +} + +DWARFDie DWARFDie::getPreviousSibling() const { +  if (isValid()) +    return U->getPreviousSibling(Die); +  return DWARFDie(); +} + +DWARFDie DWARFDie::getFirstChild() const { +  if (isValid()) +    return U->getFirstChild(Die); +  return DWARFDie(); +} + +DWARFDie DWARFDie::getLastChild() const { +  if (isValid()) +    return U->getLastChild(Die); +  return DWARFDie(); +} + +iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const { +  return make_range(attribute_iterator(*this, false), +                    attribute_iterator(*this, true)); +} + +DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) +    : Die(D), Index(0) { +  auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); +  assert(AbbrDecl && "Must have abbreviation declaration"); +  if (End) { +    // This is the end iterator so we set the index to the attribute count. +    Index = AbbrDecl->getNumAttributes(); +  } else { +    // This is the begin iterator so we extract the value for this->Index. +    AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); +    updateForIndex(*AbbrDecl, 0); +  } +} + +void DWARFDie::attribute_iterator::updateForIndex( +    const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) { +  Index = I; +  // AbbrDecl must be valid before calling this function. +  auto NumAttrs = AbbrDecl.getNumAttributes(); +  if (Index < NumAttrs) { +    AttrValue.Attr = AbbrDecl.getAttrByIndex(Index); +    // Add the previous byte size of any previous attribute value. +    AttrValue.Offset += AttrValue.ByteSize; +    uint64_t ParseOffset = AttrValue.Offset; +    auto U = Die.getDwarfUnit(); +    assert(U && "Die must have valid DWARF unit"); +    AttrValue.Value = DWARFFormValue::createFromUnit( +        AbbrDecl.getFormByIndex(Index), U, &ParseOffset); +    AttrValue.ByteSize = ParseOffset - AttrValue.Offset; +  } else { +    assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only"); +    AttrValue = {}; +  } +} + +DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() { +  if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr()) +    updateForIndex(*AbbrDecl, Index + 1); +  return *this; +} + +bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) { +  switch (Attr) { +  // From the DWARF v5 specification. +  case DW_AT_location: +  case DW_AT_byte_size: +  case DW_AT_bit_size: +  case DW_AT_string_length: +  case DW_AT_lower_bound: +  case DW_AT_return_addr: +  case DW_AT_bit_stride: +  case DW_AT_upper_bound: +  case DW_AT_count: +  case DW_AT_data_member_location: +  case DW_AT_frame_base: +  case DW_AT_segment: +  case DW_AT_static_link: +  case DW_AT_use_location: +  case DW_AT_vtable_elem_location: +  case DW_AT_allocated: +  case DW_AT_associated: +  case DW_AT_byte_stride: +  case DW_AT_rank: +  case DW_AT_call_value: +  case DW_AT_call_origin: +  case DW_AT_call_target: +  case DW_AT_call_target_clobbered: +  case DW_AT_call_data_location: +  case DW_AT_call_data_value: +  // Extensions. +  case DW_AT_GNU_call_site_value: +  case DW_AT_GNU_call_site_target: +    return true; +  default: +    return false; +  } +}  | 
