diff options
author | Greg Clayton <gclayton@apple.com> | 2016-12-13 18:25:19 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2016-12-13 18:25:19 +0000 |
commit | c8c1032c0c52d7f851ccfa29ec850b24047ebcb9 (patch) | |
tree | 83f7c48017baaef8f964eea18527f5f736aa7034 /llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | |
parent | c21b3c949d370c36333ea7b401d780c500cef11a (diff) | |
download | bcm5719-llvm-c8c1032c0c52d7f851ccfa29ec850b24047ebcb9.tar.gz bcm5719-llvm-c8c1032c0c52d7f851ccfa29ec850b24047ebcb9.zip |
Make a DWARFDIE class that can help avoid using the wrong DWARFUnit when extracting attributes
Many places pass around a DWARFDebugInfoEntryMinimal and a DWARFUnit. It is easy to get things wrong by using the wrong DWARFUnit with a DWARFDebugInfoEntryMinimal. This patch creates a DWARFDie class that contains the DWARFUnit and DWARFDebugInfoEntryMinimal objects so that they can't get out of sync. All attribute extraction has been moved out of DWARFDebugInfoEntryMinimal and into DWARFDie. DWARFDebugInfoEntryMinimal was also renamed to DWARFDebugInfoEntry.
DWARFDie objects are temporary objects that are used by clients and contain 2 pointers that you always need to have anyway. Keeping them grouped will avoid errors and simplify many of the attribute extracting APIs by not having to pass in a DWARFUnit.
Differential Revision: https://reviews.llvm.org/D27634
llvm-svn: 289565
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFDie.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp new file mode 100644 index 00000000000..a41fe6fce1d --- /dev/null +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -0,0 +1,391 @@ +//===-- 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 "SyntaxHighlighting.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace dwarf; +using namespace syntax; + +namespace { + 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(raw_ostream &OS, const DWARFAddressRangesVector& Ranges, + unsigned AddressSize, unsigned Indent) { + if (Ranges.empty()) + return; + + for (const auto &Range: Ranges) { + OS << '\n'; + OS.indent(Indent); + OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")", + AddressSize*2, Range.first, + AddressSize*2, Range.second); + } +} + +static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, + uint32_t *OffsetPtr, dwarf::Attribute Attr, + dwarf::Form Form, unsigned Indent) { + if (!Die.isValid()) + return; + const char BaseIndent[] = " "; + OS << BaseIndent; + OS.indent(Indent+2); + auto attrString = AttributeString(Attr); + if (!attrString.empty()) + WithColor(OS, syntax::Attribute) << attrString; + else + WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", Attr); + + auto formString = FormEncodingString(Form); + if (!formString.empty()) + OS << " [" << formString << ']'; + else + OS << format(" [DW_FORM_Unknown_%x]", Form); + + DWARFUnit *U = Die.getDwarfUnit(); + DWARFFormValue formValue(Form); + + if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, U)) + return; + + OS << "\t("; + + StringRef Name; + std::string File; + auto Color = syntax::Enumerator; + if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { + Color = syntax::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 + formValue.dump(OS); + + // 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_APPLE_property_attribute) { + if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant()) + dumpApplePropertyAttribute(OS, *OptVal); + } else if (Attr == DW_AT_ranges) { + dumpRanges(OS, Die.getAddressRanges(), U->getAddressByteSize(), + sizeof(BaseIndent)+Indent+4); + } + + OS << ")\n"; +} + +} // end anonymous namespace + +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; +} + +bool DWARFDie::getAttributeValue(dwarf::Attribute Attr, + DWARFFormValue &FormValue) const { + if (!U) + return false; + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) + return AbbrevDecl->getAttributeValue(getOffset(), Attr, *U, FormValue); + return false; +} + +const char *DWARFDie::getAttributeValueAsString(dwarf::Attribute Attr, + const char *FailValue) const { + DWARFFormValue FormValue; + if (!getAttributeValue(Attr, FormValue)) + return FailValue; + Optional<const char *> Result = FormValue.getAsCString(); + return Result.hasValue() ? Result.getValue() : FailValue; +} + +uint64_t DWARFDie::getAttributeValueAsAddress(dwarf::Attribute Attr, + uint64_t FailValue) const { + DWARFFormValue FormValue; + if (!getAttributeValue(Attr, FormValue)) + return FailValue; + Optional<uint64_t> Result = FormValue.getAsAddress(); + return Result.hasValue() ? Result.getValue() : FailValue; +} + +int64_t DWARFDie::getAttributeValueAsSignedConstant(dwarf::Attribute Attr, + int64_t FailValue) const { + DWARFFormValue FormValue; + if (!getAttributeValue(Attr, FormValue)) + return FailValue; + Optional<int64_t> Result = FormValue.getAsSignedConstant(); + return Result.hasValue() ? Result.getValue() : FailValue; +} + +uint64_t +DWARFDie::getAttributeValueAsUnsignedConstant(dwarf::Attribute Attr, + uint64_t FailValue) const { + DWARFFormValue FormValue; + if (!getAttributeValue(Attr, FormValue)) + return FailValue; + Optional<uint64_t> Result = FormValue.getAsUnsignedConstant(); + return Result.hasValue() ? Result.getValue() : FailValue; +} + +uint64_t DWARFDie::getAttributeValueAsReference(dwarf::Attribute Attr, + uint64_t FailValue) const { + DWARFFormValue FormValue; + if (!getAttributeValue(Attr, FormValue)) + return FailValue; + Optional<uint64_t> Result = FormValue.getAsReference(); + return Result.hasValue() ? Result.getValue() : FailValue; +} + +uint64_t DWARFDie::getAttributeValueAsSectionOffset(dwarf::Attribute Attr, + uint64_t FailValue) const { + DWARFFormValue FormValue; + if (!getAttributeValue(Attr, FormValue)) + return FailValue; + Optional<uint64_t> Result = FormValue.getAsSectionOffset(); + return Result.hasValue() ? Result.getValue() : FailValue; +} + +DWARFDie +DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { + uint32_t SpecRef = getAttributeValueAsReference(Attr, -1U); + if (SpecRef != -1U) { + auto SpecUnit = U->getUnitSection().getUnitForOffset(SpecRef); + if (SpecUnit) + return SpecUnit->getDIEForOffset(SpecRef); + } + return DWARFDie(); +} + +uint64_t +DWARFDie::getRangesBaseAttribute(uint64_t FailValue) const { + auto Result = getAttributeValueAsSectionOffset(DW_AT_rnglists_base, -1ULL); + if (Result != -1ULL) + return Result; + return getAttributeValueAsSectionOffset(DW_AT_GNU_ranges_base, FailValue); +} + +bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC) const { + LowPC = getAttributeValueAsAddress(DW_AT_low_pc, -1ULL); + if (LowPC == -1ULL) + return false; + HighPC = getAttributeValueAsAddress(DW_AT_high_pc, -1ULL); + if (HighPC == -1ULL) { + // Since DWARF4, DW_AT_high_pc may also be of class constant, in which case + // it represents function size. + HighPC = getAttributeValueAsUnsignedConstant(DW_AT_high_pc, -1ULL); + if (HighPC != -1ULL) + HighPC += LowPC; + } + return (HighPC != -1ULL); +} + +DWARFAddressRangesVector +DWARFDie::getAddressRanges() const { + if (isNULL()) + return DWARFAddressRangesVector(); + // Single range specified by low/high PC. + uint64_t LowPC, HighPC; + if (getLowAndHighPC(LowPC, HighPC)) { + return DWARFAddressRangesVector(1, std::make_pair(LowPC, HighPC)); + } + // Multiple ranges from .debug_ranges section. + uint32_t RangesOffset = getAttributeValueAsSectionOffset(DW_AT_ranges, -1U); + if (RangesOffset != -1U) { + DWARFDebugRangeList RangeList; + if (U->extractRangeList(RangesOffset, RangeList)) + return RangeList.getAbsoluteRanges(U->getBaseAddress()); + } + 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()); + } + + DWARFDie Child = getFirstChild(); + while (Child) { + Child.collectChildrenAddressRanges(Ranges); + Child = Child.getSibling(); + } +} + +bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { + for (const auto& R : getAddressRanges()) { + if (R.first <= Address && Address < R.second) + 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; + const char *name = nullptr; + // Try to get mangled name only if it was asked for. + if (Kind == DINameKind::LinkageName) { + if ((name = getAttributeValueAsString(DW_AT_MIPS_linkage_name, nullptr))) + return name; + if ((name = getAttributeValueAsString(DW_AT_linkage_name, nullptr))) + return name; + } + if ((name = getAttributeValueAsString(DW_AT_name, nullptr))) + return name; + // Try to get name from specification DIE. + DWARFDie SpecDie = getAttributeValueAsReferencedDie(DW_AT_specification); + if (SpecDie && (name = SpecDie.getName(Kind))) + return name; + // Try to get name from abstract origin DIE. + DWARFDie AbsDie = getAttributeValueAsReferencedDie(DW_AT_abstract_origin); + if (AbsDie && (name = AbsDie.getName(Kind))) + return name; + return nullptr; +} + +void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, + uint32_t &CallColumn) const { + CallFile = getAttributeValueAsUnsignedConstant(DW_AT_call_file, 0); + CallLine = getAttributeValueAsUnsignedConstant(DW_AT_call_line, 0); + CallColumn = getAttributeValueAsUnsignedConstant(DW_AT_call_column, 0); +} + +void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, + unsigned Indent) const { + if (!isValid()) + return; + DataExtractor debug_info_data = U->getDebugInfoExtractor(); + const uint32_t Offset = getOffset(); + uint32_t offset = Offset; + + if (debug_info_data.isValidOffset(offset)) { + uint32_t abbrCode = debug_info_data.getULEB128(&offset); + WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset); + + if (abbrCode) { + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) { + auto tagString = TagString(getTag()); + if (!tagString.empty()) + WithColor(OS, syntax::Tag).get().indent(Indent) << tagString; + else + WithColor(OS, syntax::Tag).get().indent(Indent) + << format("DW_TAG_Unknown_%x", getTag()); + + OS << format(" [%u] %c\n", abbrCode, + AbbrevDecl->hasChildren() ? '*' : ' '); + + // Dump all data in the DIE for the attributes. + for (const auto &AttrSpec : AbbrevDecl->attributes()) { + dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form, + Indent); + } + + DWARFDie child = getFirstChild(); + if (RecurseDepth > 0 && child) { + while (child) { + child.dump(OS, RecurseDepth-1, Indent+2); + child = child.getSibling(); + } + } + } else { + OS << "Abbreviation code not found in 'debug_abbrev' class for code: " + << abbrCode << '\n'; + } + } else { + OS.indent(Indent) << "NULL\n"; + } + } +} + + +void DWARFDie::getInlinedChainForAddress( + const uint64_t Address, SmallVectorImpl<DWARFDie> &InlinedChain) const { + if (isNULL()) + return; + DWARFDie DIE(*this); + while (DIE) { + // Append current DIE to inlined chain only if it has correct tag + // (e.g. it is not a lexical block). + if (DIE.isSubroutineDIE()) + InlinedChain.push_back(DIE); + + // Try to get child which also contains provided address. + DWARFDie Child = DIE.getFirstChild(); + while (Child) { + if (Child.addressRangeContainsAddress(Address)) { + // Assume there is only one such child. + break; + } + Child = Child.getSibling(); + } + DIE = Child; + } + // Reverse the obtained chain to make the root of inlined chain last. + std::reverse(InlinedChain.begin(), InlinedChain.end()); +} + |