diff options
Diffstat (limited to 'contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp')
-rw-r--r-- | contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 249 |
1 files changed, 138 insertions, 111 deletions
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index ee2c569..043bdb8 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -1,4 +1,4 @@ -//===-- DWARFUnit.cpp -----------------------------------------------------===// +//===- DWARFUnit.cpp ------------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,54 +7,51 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Casting.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Path.h" #include <algorithm> #include <cassert> +#include <cstddef> #include <cstdint> #include <cstdio> +#include <utility> #include <vector> -namespace llvm { - +using namespace llvm; using namespace dwarf; void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) { - parseImpl(C, Section, C.getDebugAbbrev(), C.getRangeSection(), - C.getStringSection(), StringRef(), C.getAddrSection(), - C.getLineSection().Data, C.isLittleEndian(), false); + parseImpl(C, Section, C.getDebugAbbrev(), &C.getRangeSection(), + C.getStringSection(), C.getStringOffsetSection(), + &C.getAddrSection(), C.getLineSection(), C.isLittleEndian(), false); } void DWARFUnitSectionBase::parseDWO(DWARFContext &C, const DWARFSection &DWOSection, DWARFUnitIndex *Index) { - parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), C.getRangeDWOSection(), + parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), &C.getRangeDWOSection(), C.getStringDWOSection(), C.getStringOffsetDWOSection(), - C.getAddrSection(), C.getLineDWOSection().Data, C.isLittleEndian(), + &C.getAddrSection(), C.getLineDWOSection(), C.isLittleEndian(), true); } DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, - const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, + const DWARFDebugAbbrev *DA, const DWARFSection *RS, + StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *IndexEntry) : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS), - LineSection(LS), StringSection(SS), StringOffsetSection([&]() { - if (IndexEntry) - if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) - return SOS.slice(C->Offset, C->Offset + C->Length); - return SOS; - }()), + LineSection(LS), StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE), isDWO(IsDWO), UnitSection(UnitSection), IndexEntry(IndexEntry) { clear(); @@ -64,30 +61,40 @@ DWARFUnit::~DWARFUnit() = default; bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const { - uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize; - if (AddrOffsetSection.size() < Offset + AddrSize) + uint32_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize(); + if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize()) return false; - DataExtractor DA(AddrOffsetSection, isLittleEndian, AddrSize); - Result = DA.getAddress(&Offset); + DWARFDataExtractor DA(*AddrOffsetSection, isLittleEndian, + getAddressByteSize()); + Result = DA.getRelocatedAddress(&Offset); return true; } bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index, - uint32_t &Result) const { - // FIXME: string offset section entries are 8-byte for DWARF64. - const uint32_t ItemSize = 4; - uint32_t Offset = Index * ItemSize; - if (StringOffsetSection.size() < Offset + ItemSize) + uint64_t &Result) const { + unsigned ItemSize = getDwarfOffsetByteSize(); + uint32_t Offset = StringOffsetSectionBase + Index * ItemSize; + if (StringOffsetSection.Data.size() < Offset + ItemSize) return false; - DataExtractor DA(StringOffsetSection, isLittleEndian, 0); - Result = DA.getU32(&Offset); + DWARFDataExtractor DA(StringOffsetSection, isLittleEndian, 0); + Result = DA.getRelocatedValue(ItemSize, &Offset); return true; } bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); - Version = debug_info.getU16(offset_ptr); - uint64_t AbbrOffset = debug_info.getU32(offset_ptr); + // FIXME: Support DWARF64. + FormParams.Format = DWARF32; + FormParams.Version = debug_info.getU16(offset_ptr); + uint64_t AbbrOffset; + if (FormParams.Version >= 5) { + UnitType = debug_info.getU8(offset_ptr); + FormParams.AddrSize = debug_info.getU8(offset_ptr); + AbbrOffset = debug_info.getU32(offset_ptr); + } else { + AbbrOffset = debug_info.getU32(offset_ptr); + FormParams.AddrSize = debug_info.getU8(offset_ptr); + } if (IndexEntry) { if (AbbrOffset) return false; @@ -99,15 +106,17 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { return false; AbbrOffset = AbbrEntry->Offset; } - AddrSize = debug_info.getU8(offset_ptr); bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); - bool VersionOK = DWARFContext::isSupportedVersion(Version); - bool AddrSizeOK = AddrSize == 4 || AddrSize == 8; + bool VersionOK = DWARFContext::isSupportedVersion(getVersion()); + bool AddrSizeOK = getAddressByteSize() == 4 || getAddressByteSize() == 8; if (!LengthOK || !VersionOK || !AddrSizeOK) return false; + // Keep track of the highest DWARF version we encounter across all units. + Context.setMaxVersionIfGreater(getVersion()); + Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); return Abbrevs != nullptr; } @@ -129,10 +138,11 @@ bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { } bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, - DWARFDebugRangeList &RangeList) const { + DWARFDebugRangeList &RangeList) const { // Require that compile unit is extracted. assert(!DieArray.empty()); - DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize); + DWARFDataExtractor RangesData(*RangeSection, isLittleEndian, + getAddressByteSize()); uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; return RangeList.extract(RangesData, &ActualRangeListOffset); } @@ -140,9 +150,8 @@ bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, void DWARFUnit::clear() { Offset = 0; Length = 0; - Version = 0; Abbrevs = nullptr; - AddrSize = 0; + FormParams = DWARFFormParams({0, 0, DWARF32}); BaseAddr = 0; RangeSectionBase = 0; AddrOffsetSectionBase = 0; @@ -151,11 +160,11 @@ void DWARFUnit::clear() { } const char *DWARFUnit::getCompilationDir() { - return getUnitDIE().getAttributeValueAsString(DW_AT_comp_dir, nullptr); + return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr); } Optional<uint64_t> DWARFUnit::getDWOId() { - return getUnitDIE().getAttributeValueAsUnsignedConstant(DW_AT_GNU_dwo_id); + return toUnsigned(getUnitDIE().find(DW_AT_GNU_dwo_id)); } void DWARFUnit::extractDIEsToVector( @@ -169,7 +178,7 @@ void DWARFUnit::extractDIEsToVector( uint32_t DIEOffset = Offset + getHeaderSize(); uint32_t NextCUOffset = getNextUnitOffset(); DWARFDebugInfoEntry DIE; - DataExtractor DebugInfoData = getDebugInfoExtractor(); + DWARFDataExtractor DebugInfoData = getDebugInfoExtractor(); uint32_t Depth = 0; bool IsCUDie = true; @@ -225,17 +234,22 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { // If CU DIE was just parsed, copy several attribute values from it. if (!HasCUDie) { DWARFDie UnitDie = getUnitDIE(); - auto BaseAddr = UnitDie.getAttributeValueAsAddress(DW_AT_low_pc); - if (!BaseAddr) - BaseAddr = UnitDie.getAttributeValueAsAddress(DW_AT_entry_pc); + auto BaseAddr = toAddress(UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc})); if (BaseAddr) setBaseAddress(*BaseAddr); - AddrOffsetSectionBase = - UnitDie.getAttributeValueAsSectionOffset(DW_AT_GNU_addr_base) - .getValueOr(0); - RangeSectionBase = - UnitDie.getAttributeValueAsSectionOffset(DW_AT_rnglists_base) - .getValueOr(0); + AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0); + RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); + + // In general, we derive the offset of the unit's contibution to the + // debug_str_offsets{.dwo} section from the unit DIE's + // DW_AT_str_offsets_base attribute. In dwp files we add to it the offset + // we get from the index table. + StringOffsetSectionBase = + toSectionOffset(UnitDie.find(DW_AT_str_offsets_base), 0); + if (IndexEntry) + if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) + StringOffsetSectionBase += C->Offset; + // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for // skeleton CU DIE, so that DWARF users not aware of it are not broken. } @@ -243,21 +257,6 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { return DieArray.size(); } -DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath) - : DWOU(nullptr) { - auto Obj = object::ObjectFile::createObjectFile(DWOPath); - if (!Obj) { - // TODO: Actually report errors helpfully. - consumeError(Obj.takeError()); - return; - } - DWOFile = std::move(Obj.get()); - DWOContext.reset( - cast<DWARFContext>(new DWARFContextInMemory(*DWOFile.getBinary()))); - if (DWOContext->getNumDWOCompileUnits() > 0) - DWOU = DWOContext->getDWOCompileUnitAtIndex(0); -} - bool DWARFUnit::parseDWO() { if (isDWO) return false; @@ -266,28 +265,31 @@ bool DWARFUnit::parseDWO() { DWARFDie UnitDie = getUnitDIE(); if (!UnitDie) return false; - const char *DWOFileName = - UnitDie.getAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); + auto DWOFileName = dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name)); if (!DWOFileName) return false; - const char *CompilationDir = - UnitDie.getAttributeValueAsString(DW_AT_comp_dir, nullptr); + auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir)); SmallString<16> AbsolutePath; - if (sys::path::is_relative(DWOFileName) && CompilationDir != nullptr) { - sys::path::append(AbsolutePath, CompilationDir); + if (sys::path::is_relative(*DWOFileName) && CompilationDir && + *CompilationDir) { + sys::path::append(AbsolutePath, *CompilationDir); } - sys::path::append(AbsolutePath, DWOFileName); - DWO = llvm::make_unique<DWOHolder>(AbsolutePath); - DWARFUnit *DWOCU = DWO->getUnit(); - // Verify that compile unit in .dwo file is valid. - if (!DWOCU || DWOCU->getDWOId() != getDWOId()) { - DWO.reset(); + sys::path::append(AbsolutePath, *DWOFileName); + auto DWOId = getDWOId(); + if (!DWOId) return false; - } + auto DWOContext = Context.getDWOContext(AbsolutePath); + if (!DWOContext) + return false; + + DWARFCompileUnit *DWOCU = DWOContext->getDWOCompileUnitForHash(*DWOId); + if (!DWOCU) + return false; + DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU); // Share .debug_addr and .debug_ranges section with compile unit in .dwo - DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); + DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); auto DWORangesBase = UnitDie.getRangesBaseAttribute(); - DWOCU->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); + DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); return true; } @@ -330,8 +332,8 @@ void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { // Collect address ranges from DIEs in .dwo if necessary. bool DWOCreated = parseDWO(); - if (DWO.get()) - DWO->getUnit()->collectAddressRanges(CURanges); + if (DWO) + DWO->collectAddressRanges(CURanges); if (DWOCreated) DWO.reset(); @@ -341,41 +343,67 @@ void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { clearDIEs(true); } -DWARFDie -DWARFUnit::getSubprogramForAddress(uint64_t Address) { - extractDIEsIfNeeded(false); - for (const DWARFDebugInfoEntry &D : DieArray) { - DWARFDie DIE(this, &D); - if (DIE.isSubprogramDIE() && - DIE.addressRangeContainsAddress(Address)) { - return DIE; +void DWARFUnit::updateAddressDieMap(DWARFDie Die) { + if (Die.isSubroutineDIE()) { + for (const auto &R : Die.getAddressRanges()) { + // Ignore 0-sized ranges. + if (R.LowPC == R.HighPC) + continue; + auto B = AddrDieMap.upper_bound(R.LowPC); + if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) { + // The range is a sub-range of existing ranges, we need to split the + // existing range. + if (R.HighPC < B->second.first) + AddrDieMap[R.HighPC] = B->second; + if (R.LowPC > B->first) + AddrDieMap[B->first].first = R.LowPC; + } + AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die); } } - return DWARFDie(); + // Parent DIEs are added to the AddrDieMap prior to the Children DIEs to + // simplify the logic to update AddrDieMap. The child's range will always + // be equal or smaller than the parent's range. With this assumption, when + // adding one range into the map, it will at most split a range into 3 + // sub-ranges. + for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling()) + updateAddressDieMap(Child); +} + +DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) { + extractDIEsIfNeeded(false); + if (AddrDieMap.empty()) + updateAddressDieMap(getUnitDIE()); + auto R = AddrDieMap.upper_bound(Address); + if (R == AddrDieMap.begin()) + return DWARFDie(); + // upper_bound's previous item contains Address. + --R; + if (Address >= R->second.first) + return DWARFDie(); + return R->second.second; } void DWARFUnit::getInlinedChainForAddress(uint64_t Address, SmallVectorImpl<DWARFDie> &InlinedChain) { - // First, find a subprogram that contains the given address (the root - // of inlined chain). - DWARFDie SubprogramDIE; + assert(InlinedChain.empty()); // Try to look for subprogram DIEs in the DWO file. parseDWO(); - if (DWO) - SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address); - else - SubprogramDIE = getSubprogramForAddress(Address); - - // Get inlined chain rooted at this subprogram DIE. - if (SubprogramDIE) - SubprogramDIE.getInlinedChainForAddress(Address, InlinedChain); - else - InlinedChain.clear(); + // First, find the subroutine that contains the given address (the leaf + // of inlined chain). + DWARFDie SubroutineDIE = + (DWO ? DWO.get() : this)->getSubroutineForAddress(Address); + + while (SubroutineDIE) { + if (SubroutineDIE.isSubroutineDIE()) + InlinedChain.push_back(SubroutineDIE); + SubroutineDIE = SubroutineDIE.getParent(); + } } -const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, - DWARFSectionKind Kind) { +const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context, + DWARFSectionKind Kind) { if (Kind == DW_SECT_INFO) return Context.getCUIndex(); assert(Kind == DW_SECT_TYPES); @@ -413,11 +441,10 @@ DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) { return DWARFDie(); // Find the next DIE whose depth is the same as the Die's depth. - for (size_t I=getDIEIndex(Die)+1, EndIdx = DieArray.size(); I<EndIdx; ++I) { + for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx; + ++I) { if (DieArray[I].getDepth() == Depth) return DWARFDie(this, &DieArray[I]); } return DWARFDie(); } - -} // end namespace llvm |