When requesting to dump both the parent chain and children, we used to print the DIE more than once because we propagated the dump options to the parent without clearing the respective flags. This commit fixes this oversight and adds a test. rdar://39415292 Differential revision: https://reviews.llvm.org/D47263 llvm-svn: 333350
600 lines
19 KiB
C++
600 lines
19 KiB
C++
//===- DWARFDie.cpp -------------------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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/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) {
|
|
ArrayRef<SectionName> SectionNames;
|
|
if (DumpOpts.Verbose)
|
|
SectionNames = Obj.getSectionNames();
|
|
|
|
for (const DWARFAddressRange &R : Ranges) {
|
|
|
|
OS << '\n';
|
|
OS.indent(Indent);
|
|
R.dump(OS, AddressSize);
|
|
|
|
if (SectionNames.empty() || R.SectionIndex == -1ULL)
|
|
continue;
|
|
|
|
StringRef Name = SectionNames[R.SectionIndex].Name;
|
|
OS << " \"" << Name << '\"';
|
|
|
|
// Print section index if name is not unique.
|
|
if (!SectionNames[R.SectionIndex].IsNameUnique)
|
|
OS << format(" [%" PRIu64 "]", 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);
|
|
return;
|
|
}
|
|
|
|
FormValue.dump(OS, DumpOpts);
|
|
if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
|
|
const DWARFSection &LocSection = Obj.getLocSection();
|
|
const DWARFSection &LocDWOSection = Obj.getLocDWOSection();
|
|
uint32_t Offset = *FormValue.getAsSectionOffset();
|
|
if (!LocSection.Data.empty()) {
|
|
DWARFDebugLoc DebugLoc;
|
|
DWARFDataExtractor Data(Obj, LocSection, Ctx.isLittleEndian(),
|
|
Obj.getAddressSize());
|
|
auto LL = DebugLoc.parseOneLocationList(Data, &Offset);
|
|
if (LL) {
|
|
uint64_t BaseAddr = 0;
|
|
if (Optional<BaseAddress> BA = U->getBaseAddress())
|
|
BaseAddr = BA->Address;
|
|
LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, BaseAddr,
|
|
Indent);
|
|
} else
|
|
OS << "error extracting location list.";
|
|
} else if (!LocDWOSection.Data.empty()) {
|
|
DataExtractor Data(LocDWOSection.Data, Ctx.isLittleEndian(), 0);
|
|
auto LL = DWARFDebugLocDWO::parseOneLocationList(Data, &Offset);
|
|
if (LL)
|
|
LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent);
|
|
else
|
|
OS << "error extracting location list.";
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 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) << " ";
|
|
}
|
|
|
|
/// Recursively dump the DIE type name when applicable.
|
|
static void dumpTypeName(raw_ostream &OS, const DWARFDie &Die) {
|
|
DWARFDie D = Die.getAttributeValueAsReferencedDie(DW_AT_type);
|
|
|
|
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:
|
|
break;
|
|
default:
|
|
dumpTypeTagName(OS, T);
|
|
}
|
|
|
|
// Follow the DW_AT_type if possible.
|
|
dumpTypeName(OS, D);
|
|
|
|
switch (T) {
|
|
case DW_TAG_array_type:
|
|
OS << "[]";
|
|
break;
|
|
case DW_TAG_pointer_type:
|
|
OS << '*';
|
|
break;
|
|
case DW_TAG_ptr_to_member_type:
|
|
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,
|
|
uint32_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(Form);
|
|
|
|
if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr,
|
|
U->getFormParams(), U))
|
|
return;
|
|
|
|
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 (Attr == DW_AT_location || Attr == DW_AT_frame_base ||
|
|
Attr == DW_AT_data_member_location ||
|
|
Attr == DW_AT_GNU_call_site_value)
|
|
dumpLocation(OS, formValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts);
|
|
else
|
|
formValue.dump(OS, DumpOpts);
|
|
|
|
// 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(Attr).getName(
|
|
DINameKind::LinkageName))
|
|
OS << " \"" << Name << '\"';
|
|
} else if (Attr == DW_AT_type) {
|
|
OS << " \"";
|
|
dumpTypeName(OS, Die);
|
|
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.
|
|
Optional<DWARFFormValue> Value = Die.find(DW_AT_ranges);
|
|
if (Value && Value->getForm() == DW_FORM_rnglistx)
|
|
if (auto RangeListOffset =
|
|
U->getRnglistOffset(*Value->getAsSectionOffset())) {
|
|
DWARFFormValue FV(dwarf::DW_FORM_sec_offset);
|
|
FV.setUValue(*RangeListOffset);
|
|
FV.dump(OS, DumpOpts);
|
|
}
|
|
dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(),
|
|
sizeof(BaseIndent) + Indent + 4, DumpOpts);
|
|
}
|
|
|
|
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;
|
|
|
|
while (!Worklist.empty()) {
|
|
DWARFDie Die = Worklist.back();
|
|
Worklist.pop_back();
|
|
|
|
if (!Die.isValid())
|
|
continue;
|
|
|
|
if (Seen.count(Die))
|
|
continue;
|
|
|
|
Seen.insert(Die);
|
|
|
|
if (auto Value = Die.find(Attrs))
|
|
return Value;
|
|
|
|
if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
|
|
Worklist.push_back(D);
|
|
|
|
if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification))
|
|
Worklist.push_back(D);
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
DWARFDie
|
|
DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
|
|
if (auto SpecRef = toReference(find(Attr))) {
|
|
if (auto SpecUnit = U->getUnitSection().getUnitForOffset(*SpecRef))
|
|
return SpecUnit->getDIEForOffset(*SpecRef);
|
|
}
|
|
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 = toAddress(F);
|
|
if (!LowPcAddr)
|
|
return false;
|
|
if (auto HighPcAddr = getHighPC(*LowPcAddr)) {
|
|
LowPC = *LowPcAddr;
|
|
HighPC = *HighPcAddr;
|
|
SectionIndex = F->getSectionIndex();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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 {{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()) {
|
|
const auto &DIERanges = getAddressRanges();
|
|
Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end());
|
|
}
|
|
|
|
for (auto Child : children())
|
|
Child.collectChildrenAddressRanges(Ranges);
|
|
}
|
|
|
|
bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
|
|
for (const auto &R : getAddressRanges()) {
|
|
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) {
|
|
if (!Die)
|
|
return Indent;
|
|
Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts);
|
|
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 uint32_t Offset = getOffset();
|
|
uint32_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.8x: ", 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.RecurseDepth > 0 && child) {
|
|
DumpOpts.RecurseDepth--;
|
|
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::getFirstChild() const {
|
|
if (isValid())
|
|
return U->getFirstChild(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), AttrValue(0), 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;
|
|
AttrValue.Value.setForm(AbbrDecl.getFormByIndex(Index));
|
|
uint32_t ParseOffset = AttrValue.Offset;
|
|
auto U = Die.getDwarfUnit();
|
|
assert(U && "Die must have valid DWARF unit");
|
|
bool b = AttrValue.Value.extractValue(U->getDebugInfoExtractor(),
|
|
&ParseOffset, U->getFormParams(), U);
|
|
(void)b;
|
|
assert(b && "extractValue cannot fail on fully parsed DWARF");
|
|
AttrValue.ByteSize = ParseOffset - AttrValue.Offset;
|
|
} else {
|
|
assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only");
|
|
AttrValue.clear();
|
|
}
|
|
}
|
|
|
|
DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() {
|
|
if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr())
|
|
updateForIndex(*AbbrDecl, Index + 1);
|
|
return *this;
|
|
}
|