summaryrefslogtreecommitdiff
path: root/third_party/llvm-project/DWARFDie.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2019-12-19 09:04:08 -0800
committerGitHub <noreply@github.com>2019-12-19 09:04:08 -0800
commit4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6 (patch)
tree91bffc2d47b1fe4bba01e7ada77006ef340bd138 /third_party/llvm-project/DWARFDie.cpp
parent0048f5b004ddf50e750aa335d0be314a73852058 (diff)
downloadbinaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.gz
binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.bz2
binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.zip
DWARF parsing and writing support using LLVM (#2520)
This imports LLVM code for DWARF handling. That code has the Apache 2 license like us. It's also the same code used to emit DWARF in the common toolchain, so it seems like a safe choice. This adds two passes: --dwarfdump which runs the same code LLVM runs for llvm-dwarfdump. This shows we can parse it ok, and will be useful for debugging. And --dwarfupdate writes out the DWARF sections (unchanged from what we read, so it just roundtrips - for updating we need #2515). This puts LLVM in thirdparty which is added here. All the LLVM code is behind USE_LLVM_DWARF, which is on by default, but off in JS for now, as it increases code size by 20%. This current approach imports the LLVM files directly. This is not how they are intended to be used, so it required a bunch of local changes - more than I expected actually, for the platform-specific stuff. For now this seems to work, so it may be good enough, but in the long term we may want to switch to linking against libllvm. A downside to doing that is that binaryen users would need to have an LLVM build, and even in the waterfall builds we'd have a problem - while we ship LLVM there anyhow, we constantly update it, which means that binaryen would need to be on latest llvm all the time too (which otherwise, given DWARF is quite stable, we might not need to constantly update). An even larger issue is that as I did this work I learned about how DWARF works in LLVM, and while the reading code is easy to reuse, the writing code is trickier. The main code path is heavily integrated with the MC layer, which we don't have - we might want to create a "fake MC layer" for that, but it sounds hard. Instead, there is the YAML path which is used mostly for testing, and which can convert DWARF to and from YAML and from binary. Using the non-YAML parts there, we can convert binary DWARF to the YAML layer's nice Info data, then convert that to binary. This works, however, this is not the path LLVM uses normally, and it supports only some basic DWARF sections - I had to add ranges support, in fact. So if we need more complex things, we may end up needing to use the MC layer approach, or consider some other DWARF library. However, hopefully that should not affect the core binaryen code which just calls a library for DWARF stuff. Helps #2400
Diffstat (limited to 'third_party/llvm-project/DWARFDie.cpp')
-rw-r--r--third_party/llvm-project/DWARFDie.cpp747
1 files changed, 747 insertions, 0 deletions
diff --git a/third_party/llvm-project/DWARFDie.cpp b/third_party/llvm-project/DWARFDie.cpp
new file mode 100644
index 000000000..ebc8cc565
--- /dev/null
+++ b/third_party/llvm-project/DWARFDie.cpp
@@ -0,0 +1,747 @@
+//===- 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;
+ }
+
+ if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
+ uint64_t Offset = *FormValue.getAsSectionOffset();
+ uint64_t BaseAddr = 0;
+ if (Optional<object::SectionedAddress> BA = U->getBaseAddress())
+ BaseAddr = BA->Address;
+ auto LLDumpOpts = DumpOpts;
+ LLDumpOpts.Verbose = false;
+
+ if (!U->isDWOUnit() && !U->getLocSection()->Data.empty()) {
+ DWARFDebugLoc DebugLoc;
+ DWARFDataExtractor Data(Obj, *U->getLocSection(), Ctx.isLittleEndian(),
+ Obj.getAddressSize());
+
+ FormValue.dump(OS, DumpOpts);
+ OS << ": ";
+
+ if (Expected<DWARFDebugLoc::LocationList> LL =
+ DebugLoc.parseOneLocationList(Data, &Offset)) {
+ LL->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(LL.takeError()));
+ }
+ return;
+ }
+
+ bool UseLocLists = !U->isDWOUnit();
+ auto Data =
+ UseLocLists
+ ? DWARFDataExtractor(Obj, Obj.getLoclistsSection(),
+ Ctx.isLittleEndian(), Obj.getAddressSize())
+ : DWARFDataExtractor(U->getLocSectionData(), Ctx.isLittleEndian(),
+ Obj.getAddressSize());
+
+ if (!Data.getData().empty()) {
+ // 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.
+ DWARFDebugLoclists::dumpLocationList(
+ Data, &Offset, UseLocLists ? U->getVersion() : 4, OS, BaseAddr, MRI,
+ U, LLDumpOpts, Indent);
+ }
+ return;
+ }
+
+ FormValue.dump(OS, DumpOpts);
+}
+
+/// 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;
+ }
+}