diff --git a/include/llvm/DebugInfo/DWARFFormValue.h b/include/llvm/DebugInfo/DWARFFormValue.h index 561815586a2..f92d5a98cef 100644 --- a/include/llvm/DebugInfo/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARFFormValue.h @@ -14,7 +14,7 @@ namespace llvm { -class DWARFCompileUnit; +class DWARFUnit; class raw_ostream; class DWARFFormValue { @@ -49,23 +49,23 @@ public: DWARFFormValue(uint16_t form = 0) : Form(form) {} uint16_t getForm() const { return Form; } const ValueType& value() const { return Value; } - void dump(raw_ostream &OS, const DWARFCompileUnit* cu) const; + void dump(raw_ostream &OS, const DWARFUnit *U) const; bool extractValue(DataExtractor data, uint32_t *offset_ptr, - const DWARFCompileUnit *cu); + const DWARFUnit *u); bool isInlinedCStr() const { return Value.data != NULL && Value.data == (const uint8_t*)Value.cstr; } const uint8_t *BlockData() const; - uint64_t getReference(const DWARFCompileUnit* cu) const; + uint64_t getReference(const DWARFUnit *U) const; uint64_t getUnsigned() const { return Value.uval; } int64_t getSigned() const { return Value.sval; } - const char *getAsCString(const DWARFCompileUnit *CU) const; - uint64_t getAsAddress(const DWARFCompileUnit *CU) const; + const char *getAsCString(const DWARFUnit *U) const; + uint64_t getAsAddress(const DWARFUnit *U) const; bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr, - const DWARFCompileUnit *cu) const; + const DWARFUnit *u) const; static bool skipValue(uint16_t form, DataExtractor debug_info_data, - uint32_t *offset_ptr, const DWARFCompileUnit *cu); + uint32_t *offset_ptr, const DWARFUnit *u); static bool isBlockForm(uint16_t form); static bool isDataForm(uint16_t form); static const uint8_t *getFixedFormSizes(uint8_t AddrSize, uint16_t Version); diff --git a/lib/DebugInfo/CMakeLists.txt b/lib/DebugInfo/CMakeLists.txt index 4a6221d454a..e25d1499136 100644 --- a/lib/DebugInfo/CMakeLists.txt +++ b/lib/DebugInfo/CMakeLists.txt @@ -12,4 +12,5 @@ add_llvm_library(LLVMDebugInfo DWARFDebugLoc.cpp DWARFDebugRangeList.cpp DWARFFormValue.cpp + DWARFUnit.cpp ) diff --git a/lib/DebugInfo/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARFCompileUnit.cpp index 4b6aa272f7d..33869d8c998 100644 --- a/lib/DebugInfo/DWARFCompileUnit.cpp +++ b/lib/DebugInfo/DWARFCompileUnit.cpp @@ -8,119 +8,18 @@ //===----------------------------------------------------------------------===// #include "DWARFCompileUnit.h" -#include "DWARFContext.h" -#include "llvm/DebugInfo/DWARFFormValue.h" -#include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" -#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" + using namespace llvm; -using namespace dwarf; - -bool DWARFCompileUnit::getAddrOffsetSectionItem(uint32_t Index, - uint64_t &Result) const { - uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize; - if (AddrOffsetSection.size() < Offset + AddrSize) - return false; - DataExtractor DA(AddrOffsetSection, isLittleEndian, AddrSize); - Result = DA.getAddress(&Offset); - return true; -} - -bool DWARFCompileUnit::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) - return false; - DataExtractor DA(StringOffsetSection, isLittleEndian, 0); - Result = DA.getU32(&Offset); - return true; -} - -bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { - clear(); - - Offset = *offset_ptr; - - if (debug_info.isValidOffset(*offset_ptr)) { - uint64_t abbrOffset; - Length = debug_info.getU32(offset_ptr); - Version = debug_info.getU16(offset_ptr); - abbrOffset = debug_info.getU32(offset_ptr); - AddrSize = debug_info.getU8(offset_ptr); - - bool lengthOK = debug_info.isValidOffset(getNextCompileUnitOffset()-1); - bool versionOK = DWARFContext::isSupportedVersion(Version); - bool abbrOffsetOK = AbbrevSection.size() > abbrOffset; - bool addrSizeOK = AddrSize == 4 || AddrSize == 8; - - if (lengthOK && versionOK && addrSizeOK && abbrOffsetOK && Abbrev != NULL) { - Abbrevs = Abbrev->getAbbreviationDeclarationSet(abbrOffset); - return true; - } - - // reset the offset to where we tried to parse from if anything went wrong - *offset_ptr = Offset; - } - - return false; -} - -uint32_t -DWARFCompileUnit::extract(uint32_t offset, DataExtractor debug_info_data, - const DWARFAbbreviationDeclarationSet *abbrevs) { - clear(); - - Offset = offset; - - if (debug_info_data.isValidOffset(offset)) { - Length = debug_info_data.getU32(&offset); - Version = debug_info_data.getU16(&offset); - bool abbrevsOK = debug_info_data.getU32(&offset) == abbrevs->getOffset(); - Abbrevs = abbrevs; - AddrSize = debug_info_data.getU8(&offset); - - bool versionOK = DWARFContext::isSupportedVersion(Version); - bool addrSizeOK = AddrSize == 4 || AddrSize == 8; - - if (versionOK && addrSizeOK && abbrevsOK && - debug_info_data.isValidOffset(offset)) - return offset; - } - return 0; -} - -bool DWARFCompileUnit::extractRangeList(uint32_t RangeListOffset, - DWARFDebugRangeList &RangeList) const { - // Require that compile unit is extracted. - assert(DieArray.size() > 0); - DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize); - uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; - return RangeList.extract(RangesData, &ActualRangeListOffset); -} - -void DWARFCompileUnit::clear() { - Offset = 0; - Length = 0; - Version = 0; - Abbrevs = 0; - AddrSize = 0; - BaseAddr = 0; - RangeSectionBase = 0; - AddrOffsetSectionBase = 0; - clearDIEs(false); - DWO.reset(); -} void DWARFCompileUnit::dump(raw_ostream &OS) { - OS << format("0x%08x", Offset) << ": Compile Unit:" - << " length = " << format("0x%08x", Length) - << " version = " << format("0x%04x", Version) - << " abbr_offset = " << format("0x%04x", Abbrevs->getOffset()) - << " addr_size = " << format("0x%02x", AddrSize) - << " (next CU at " << format("0x%08x", getNextCompileUnitOffset()) + OS << format("0x%08x", getOffset()) << ": Compile Unit:" + << " length = " << format("0x%08x", getLength()) + << " version = " << format("0x%04x", getVersion()) + << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) + << " addr_size = " << format("0x%02x", getAddressByteSize()) + << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; const DWARFDebugInfoEntryMinimal *CU = getCompileUnitDIE(false); @@ -128,262 +27,6 @@ void DWARFCompileUnit::dump(raw_ostream &OS) { CU->dump(OS, this, -1U); } -const char *DWARFCompileUnit::getCompilationDir() { - extractDIEsIfNeeded(true); - if (DieArray.empty()) - return 0; - return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0); +// VTable anchor. +DWARFCompileUnit::~DWARFCompileUnit() { } - -uint64_t DWARFCompileUnit::getDWOId() { - extractDIEsIfNeeded(true); - const uint64_t FailValue = -1ULL; - if (DieArray.empty()) - return FailValue; - return DieArray[0] - .getAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, FailValue); -} - -void DWARFCompileUnit::setDIERelations() { - if (DieArray.empty()) - return; - DWARFDebugInfoEntryMinimal *die_array_begin = &DieArray.front(); - DWARFDebugInfoEntryMinimal *die_array_end = &DieArray.back(); - DWARFDebugInfoEntryMinimal *curr_die; - // We purposely are skipping the last element in the array in the loop below - // so that we can always have a valid next item - for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) { - // Since our loop doesn't include the last element, we can always - // safely access the next die in the array. - DWARFDebugInfoEntryMinimal *next_die = curr_die + 1; - - const DWARFAbbreviationDeclaration *curr_die_abbrev = - curr_die->getAbbreviationDeclarationPtr(); - - if (curr_die_abbrev) { - // Normal DIE - if (curr_die_abbrev->hasChildren()) - next_die->setParent(curr_die); - else - curr_die->setSibling(next_die); - } else { - // NULL DIE that terminates a sibling chain - DWARFDebugInfoEntryMinimal *parent = curr_die->getParent(); - if (parent) - parent->setSibling(next_die); - } - } - - // Since we skipped the last element, we need to fix it up! - if (die_array_begin < die_array_end) - curr_die->setParent(die_array_begin); -} - -void DWARFCompileUnit::extractDIEsToVector( - bool AppendCUDie, bool AppendNonCUDies, - std::vector &Dies) const { - if (!AppendCUDie && !AppendNonCUDies) - return; - - // Set the offset to that of the first DIE and calculate the start of the - // next compilation unit header. - uint32_t Offset = getFirstDIEOffset(); - uint32_t NextCUOffset = getNextCompileUnitOffset(); - DWARFDebugInfoEntryMinimal DIE; - uint32_t Depth = 0; - const uint8_t *FixedFormSizes = - DWARFFormValue::getFixedFormSizes(getAddressByteSize(), getVersion()); - bool IsCUDie = true; - - while (Offset < NextCUOffset && - DIE.extractFast(this, FixedFormSizes, &Offset)) { - if (IsCUDie) { - if (AppendCUDie) - Dies.push_back(DIE); - if (!AppendNonCUDies) - break; - // The average bytes per DIE entry has been seen to be - // around 14-20 so let's pre-reserve the needed memory for - // our DIE entries accordingly. - Dies.reserve(Dies.size() + getDebugInfoSize() / 14); - IsCUDie = false; - } else { - Dies.push_back(DIE); - } - - const DWARFAbbreviationDeclaration *AbbrDecl = - DIE.getAbbreviationDeclarationPtr(); - if (AbbrDecl) { - // Normal DIE - if (AbbrDecl->hasChildren()) - ++Depth; - } else { - // NULL DIE. - if (Depth > 0) - --Depth; - if (Depth == 0) - break; // We are done with this compile unit! - } - } - - // Give a little bit of info if we encounter corrupt DWARF (our offset - // should always terminate at or before the start of the next compilation - // unit header). - if (Offset > NextCUOffset) - fprintf(stderr, "warning: DWARF compile unit extends beyond its " - "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), Offset); -} - -size_t DWARFCompileUnit::extractDIEsIfNeeded(bool CUDieOnly) { - if ((CUDieOnly && DieArray.size() > 0) || - DieArray.size() > 1) - return 0; // Already parsed. - - bool HasCUDie = DieArray.size() > 0; - extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray); - - if (DieArray.empty()) - return 0; - - // If CU DIE was just parsed, copy several attribute values from it. - if (!HasCUDie) { - uint64_t BaseAddr = - DieArray[0].getAttributeValueAsUnsigned(this, DW_AT_low_pc, -1U); - if (BaseAddr == -1U) - BaseAddr = DieArray[0].getAttributeValueAsUnsigned(this, DW_AT_entry_pc, 0); - setBaseAddress(BaseAddr); - AddrOffsetSectionBase = - DieArray[0].getAttributeValueAsReference(this, DW_AT_GNU_addr_base, 0); - RangeSectionBase = - DieArray[0].getAttributeValueAsReference(this, DW_AT_GNU_ranges_base, 0); - } - - setDIERelations(); - return DieArray.size(); -} - -DWARFCompileUnit::DWOHolder::DWOHolder(object::ObjectFile *DWOFile) - : DWOFile(DWOFile), - DWOContext(cast(DIContext::getDWARFContext(DWOFile))), - DWOCU(0) { - if (DWOContext->getNumDWOCompileUnits() > 0) - DWOCU = DWOContext->getDWOCompileUnitAtIndex(0); -} - -bool DWARFCompileUnit::parseDWO() { - if (DWO.get() != 0) - return false; - extractDIEsIfNeeded(true); - if (DieArray.empty()) - return false; - const char *DWOFileName = - DieArray[0].getAttributeValueAsString(this, DW_AT_GNU_dwo_name, 0); - if (DWOFileName == 0) - return false; - const char *CompilationDir = - DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0); - SmallString<16> AbsolutePath; - if (sys::path::is_relative(DWOFileName) && CompilationDir != 0) { - sys::path::append(AbsolutePath, CompilationDir); - } - sys::path::append(AbsolutePath, DWOFileName); - object::ObjectFile *DWOFile = - object::ObjectFile::createObjectFile(AbsolutePath); - if (!DWOFile) - return false; - // Reset DWOHolder. - DWO.reset(new DWOHolder(DWOFile)); - DWARFCompileUnit *DWOCU = DWO->getCU(); - // Verify that compile unit in .dwo file is valid. - if (DWOCU == 0 || DWOCU->getDWOId() != getDWOId()) { - DWO.reset(); - return false; - } - // Share .debug_addr and .debug_ranges section with compile unit in .dwo - DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); - DWOCU->setRangesSection(RangeSection, RangeSectionBase); - return true; -} - -void DWARFCompileUnit::clearDIEs(bool KeepCUDie) { - if (DieArray.size() > (unsigned)KeepCUDie) { - // std::vectors never get any smaller when resized to a smaller size, - // or when clear() or erase() are called, the size will report that it - // is smaller, but the memory allocated remains intact (call capacity() - // to see this). So we need to create a temporary vector and swap the - // contents which will cause just the internal pointers to be swapped - // so that when temporary vector goes out of scope, it will destroy the - // contents. - std::vector TmpArray; - DieArray.swap(TmpArray); - // Save at least the compile unit DIE - if (KeepCUDie) - DieArray.push_back(TmpArray.front()); - } -} - -void -DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges, - bool clear_dies_if_already_not_parsed, - uint32_t CUOffsetInAranges) { - // This function is usually called if there in no .debug_aranges section - // in order to produce a compile unit level set of address ranges that - // is accurate. If the DIEs weren't parsed, then we don't want all dies for - // all compile units to stay loaded when they weren't needed. So we can end - // up parsing the DWARF and then throwing them all away to keep memory usage - // down. - const bool clear_dies = extractDIEsIfNeeded(false) > 1 && - clear_dies_if_already_not_parsed; - DieArray[0].buildAddressRangeTable(this, debug_aranges, CUOffsetInAranges); - bool DWOCreated = parseDWO(); - if (DWO.get()) { - // If there is a .dwo file for this compile unit, then skeleton CU DIE - // doesn't have children, and we should instead build address range table - // from DIEs in the .debug_info.dwo section of .dwo file. - DWO->getCU()->buildAddressRangeTable( - debug_aranges, clear_dies_if_already_not_parsed, CUOffsetInAranges); - } - if (DWOCreated && clear_dies_if_already_not_parsed) - DWO.reset(); - - // Keep memory down by clearing DIEs if this generate function - // caused them to be parsed. - if (clear_dies) - clearDIEs(true); -} - -const DWARFDebugInfoEntryMinimal * -DWARFCompileUnit::getSubprogramForAddress(uint64_t Address) { - extractDIEsIfNeeded(false); - for (size_t i = 0, n = DieArray.size(); i != n; i++) - if (DieArray[i].isSubprogramDIE() && - DieArray[i].addressRangeContainsAddress(this, Address)) { - return &DieArray[i]; - } - return 0; -} - -DWARFDebugInfoEntryInlinedChain -DWARFCompileUnit::getInlinedChainForAddress(uint64_t Address) { - // First, find a subprogram that contains the given address (the root - // of inlined chain). - const DWARFCompileUnit *ChainCU = 0; - const DWARFDebugInfoEntryMinimal *SubprogramDIE = - getSubprogramForAddress(Address); - if (SubprogramDIE) { - ChainCU = this; - } else { - // Try to look for subprogram DIEs in the DWO file. - parseDWO(); - if (DWO.get()) { - SubprogramDIE = DWO->getCU()->getSubprogramForAddress(Address); - if (SubprogramDIE) - ChainCU = DWO->getCU(); - } - } - - // Get inlined chain rooted at this subprogram DIE. - if (!SubprogramDIE) - return DWARFDebugInfoEntryInlinedChain(); - return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address); - } diff --git a/lib/DebugInfo/DWARFCompileUnit.h b/lib/DebugInfo/DWARFCompileUnit.h index 09167d128f5..1c9573b0b4b 100644 --- a/lib/DebugInfo/DWARFCompileUnit.h +++ b/lib/DebugInfo/DWARFCompileUnit.h @@ -10,168 +10,19 @@ #ifndef LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H #define LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H -#include "llvm/ADT/OwningPtr.h" -#include "DWARFDebugAbbrev.h" -#include "DWARFDebugInfoEntry.h" -#include "DWARFDebugRangeList.h" -#include "DWARFRelocMap.h" -#include +#include "DWARFUnit.h" namespace llvm { -namespace object { -class ObjectFile; -} - -class DWARFDebugAbbrev; -class StringRef; -class raw_ostream; - -class DWARFCompileUnit { - DWARFCompileUnit(DWARFCompileUnit const &) LLVM_DELETED_FUNCTION; - DWARFCompileUnit &operator=(DWARFCompileUnit const &) LLVM_DELETED_FUNCTION; - - const DWARFDebugAbbrev *Abbrev; - StringRef InfoSection; - StringRef AbbrevSection; - StringRef RangeSection; - uint32_t RangeSectionBase; - StringRef StringSection; - StringRef StringOffsetSection; - StringRef AddrOffsetSection; - uint32_t AddrOffsetSectionBase; - const RelocAddrMap *RelocMap; - bool isLittleEndian; - - uint32_t Offset; - uint32_t Length; - uint16_t Version; - const DWARFAbbreviationDeclarationSet *Abbrevs; - uint8_t AddrSize; - uint64_t BaseAddr; - // The compile unit debug information entry items. - std::vector DieArray; - - class DWOHolder { - OwningPtr DWOFile; - OwningPtr DWOContext; - DWARFCompileUnit *DWOCU; - public: - DWOHolder(object::ObjectFile *DWOFile); - DWARFCompileUnit *getCU() const { return DWOCU; } - }; - OwningPtr DWO; - +class DWARFCompileUnit : public DWARFUnit { public: - DWARFCompileUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, - const RelocAddrMap *M, bool LE) : - Abbrev(DA), InfoSection(IS), AbbrevSection(AS), - RangeSection(RS), StringSection(SS), StringOffsetSection(SOS), - AddrOffsetSection(AOS), RelocMap(M), isLittleEndian(LE) { - clear(); - } - - StringRef getStringSection() const { return StringSection; } - StringRef getStringOffsetSection() const { return StringOffsetSection; } - void setAddrOffsetSection(StringRef AOS, uint32_t Base) { - AddrOffsetSection = AOS; - AddrOffsetSectionBase = Base; - } - void setRangesSection(StringRef RS, uint32_t Base) { - RangeSection = RS; - RangeSectionBase = Base; - } - - bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const; - // FIXME: Result should be uint64_t in DWARF64. - bool getStringOffsetSectionItem(uint32_t Index, uint32_t &Result) const; - - DataExtractor getDebugInfoExtractor() const { - return DataExtractor(InfoSection, isLittleEndian, AddrSize); - } - DataExtractor getStringExtractor() const { - return DataExtractor(StringSection, false, 0); - } - - const RelocAddrMap *getRelocMap() const { return RelocMap; } - - bool extract(DataExtractor debug_info, uint32_t* offset_ptr); - uint32_t extract(uint32_t offset, DataExtractor debug_info_data, - const DWARFAbbreviationDeclarationSet *abbrevs); - - /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it - /// hasn't already been done. Returns the number of DIEs parsed at this call. - size_t extractDIEsIfNeeded(bool CUDieOnly); - /// extractRangeList - extracts the range list referenced by this compile - /// unit from .debug_ranges section. Returns true on success. - /// Requires that compile unit is already extracted. - bool extractRangeList(uint32_t RangeListOffset, - DWARFDebugRangeList &RangeList) const; - void clear(); + const RelocAddrMap *M, bool LE) + : DWARFUnit(DA, IS, AS, RS, SS, SOS, AOS, M, LE) {} void dump(raw_ostream &OS); - uint32_t getOffset() const { return Offset; } - /// Size in bytes of the compile unit header. - uint32_t getSize() const { return 11; } - bool containsDIEOffset(uint32_t die_offset) const { - return die_offset >= getFirstDIEOffset() && - die_offset < getNextCompileUnitOffset(); - } - uint32_t getFirstDIEOffset() const { return Offset + getSize(); } - uint32_t getNextCompileUnitOffset() const { return Offset + Length + 4; } - /// Size in bytes of the .debug_info data associated with this compile unit. - size_t getDebugInfoSize() const { return Length + 4 - getSize(); } - uint32_t getLength() const { return Length; } - uint16_t getVersion() const { return Version; } - const DWARFAbbreviationDeclarationSet *getAbbreviations() const { - return Abbrevs; - } - uint8_t getAddressByteSize() const { return AddrSize; } - uint64_t getBaseAddress() const { return BaseAddr; } - - void setBaseAddress(uint64_t base_addr) { - BaseAddr = base_addr; - } - - const DWARFDebugInfoEntryMinimal * - getCompileUnitDIE(bool extract_cu_die_only = true) { - extractDIEsIfNeeded(extract_cu_die_only); - return DieArray.empty() ? NULL : &DieArray[0]; - } - - const char *getCompilationDir(); - uint64_t getDWOId(); - - /// setDIERelations - We read in all of the DIE entries into our flat list - /// of DIE entries and now we need to go back through all of them and set the - /// parent, sibling and child pointers for quick DIE navigation. - void setDIERelations(); - - void buildAddressRangeTable(DWARFDebugAranges *debug_aranges, - bool clear_dies_if_already_not_parsed, - uint32_t CUOffsetInAranges); - - /// getInlinedChainForAddress - fetches inlined chain for a given address. - /// Returns empty chain if there is no subprogram containing address. The - /// chain is valid as long as parsed compile unit DIEs are not cleared. - DWARFDebugInfoEntryInlinedChain getInlinedChainForAddress(uint64_t Address); - -private: - /// extractDIEsToVector - Appends all parsed DIEs to a vector. - void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs, - std::vector &DIEs) const; - /// clearDIEs - Clear parsed DIEs to keep memory usage low. - void clearDIEs(bool KeepCUDie); - - /// parseDWO - Parses .dwo file for current compile unit. Returns true if - /// it was actually constructed. - bool parseDWO(); - - /// getSubprogramForAddress - Returns subprogram DIE with address range - /// encompassing the provided address. The pointer is alive as long as parsed - /// compile unit DIEs are not cleared. - const DWARFDebugInfoEntryMinimal *getSubprogramForAddress(uint64_t Address); + // VTable anchor. + ~DWARFCompileUnit() LLVM_OVERRIDE; }; } diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp index 075d8cddc0d..ee152bd9b36 100644 --- a/lib/DebugInfo/DWARFContext.cpp +++ b/lib/DebugInfo/DWARFContext.cpp @@ -283,7 +283,7 @@ void DWARFContext::parseCompileUnits() { break; } CUs.push_back(CU.take()); - offset = CUs.back()->getNextCompileUnitOffset(); + offset = CUs.back()->getNextUnitOffset(); } } @@ -301,7 +301,7 @@ void DWARFContext::parseDWOCompileUnits() { break; } DWOCUs.push_back(DWOCU.take()); - offset = DWOCUs.back()->getNextCompileUnitOffset(); + offset = DWOCUs.back()->getNextUnitOffset(); } } @@ -400,7 +400,7 @@ DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, CU->getInlinedChainForAddress(Address); if (InlinedChain.DIEs.size() > 0) { const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain.DIEs[0]; - if (const char *Name = TopFunctionDIE.getSubroutineName(InlinedChain.CU)) + if (const char *Name = TopFunctionDIE.getSubroutineName(InlinedChain.U)) FunctionName = Name; } } @@ -433,7 +433,7 @@ DILineInfoTable DWARFContext::getLineInfoForAddressRange(uint64_t Address, CU->getInlinedChainForAddress(Address); if (InlinedChain.DIEs.size() > 0) { const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain.DIEs[0]; - if (const char *Name = TopFunctionDIE.getSubroutineName(InlinedChain.CU)) + if (const char *Name = TopFunctionDIE.getSubroutineName(InlinedChain.U)) FunctionName = Name; } } @@ -492,7 +492,7 @@ DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, uint32_t Column = 0; // Get function name if necessary. if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { - if (const char *Name = FunctionDIE.getSubroutineName(InlinedChain.CU)) + if (const char *Name = FunctionDIE.getSubroutineName(InlinedChain.U)) FunctionName = Name; } if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { @@ -516,7 +516,7 @@ DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, } // Get call file/line/column of a current DIE. if (i + 1 < n) { - FunctionDIE.getCallerFrame(InlinedChain.CU, CallFile, CallLine, + FunctionDIE.getCallerFrame(InlinedChain.U, CallFile, CallLine, CallColumn); } } diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARFDebugInfoEntry.cpp index 775e68fa23f..fd801a22c21 100644 --- a/lib/DebugInfo/DWARFDebugInfoEntry.cpp +++ b/lib/DebugInfo/DWARFDebugInfoEntry.cpp @@ -19,11 +19,10 @@ using namespace llvm; using namespace dwarf; -void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, - const DWARFCompileUnit *cu, +void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, const DWARFUnit *u, unsigned recurseDepth, unsigned indent) const { - DataExtractor debug_info_data = cu->getDebugInfoExtractor(); + DataExtractor debug_info_data = u->getDebugInfoExtractor(); uint32_t offset = Offset; if (debug_info_data.isValidOffset(offset)) { @@ -45,13 +44,13 @@ void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, for (uint32_t i = 0; i != numAttributes; ++i) { uint16_t attr = AbbrevDecl->getAttrByIndex(i); uint16_t form = AbbrevDecl->getFormByIndex(i); - dumpAttribute(OS, cu, &offset, attr, form, indent); + dumpAttribute(OS, u, &offset, attr, form, indent); } const DWARFDebugInfoEntryMinimal *child = getFirstChild(); if (recurseDepth > 0 && child) { while (child) { - child->dump(OS, cu, recurseDepth-1, indent+2); + child->dump(OS, u, recurseDepth-1, indent+2); child = child->getSibling(); } } @@ -66,10 +65,9 @@ void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, } void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS, - const DWARFCompileUnit *cu, - uint32_t* offset_ptr, - uint16_t attr, - uint16_t form, + const DWARFUnit *u, + uint32_t *offset_ptr, + uint16_t attr, uint16_t form, unsigned indent) const { OS << " "; OS.indent(indent+2); @@ -86,26 +84,26 @@ void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS, DWARFFormValue formValue(form); - if (!formValue.extractValue(cu->getDebugInfoExtractor(), offset_ptr, cu)) + if (!formValue.extractValue(u->getDebugInfoExtractor(), offset_ptr, u)) return; OS << "\t("; - formValue.dump(OS, cu); + formValue.dump(OS, u); OS << ")\n"; } -bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *CU, +bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFUnit *U, const uint8_t *FixedFormSizes, uint32_t *OffsetPtr) { Offset = *OffsetPtr; - DataExtractor DebugInfoData = CU->getDebugInfoExtractor(); + DataExtractor DebugInfoData = U->getDebugInfoExtractor(); uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr); if (0 == AbbrCode) { // NULL debug tag entry. AbbrevDecl = NULL; return true; } - AbbrevDecl = CU->getAbbreviations()->getAbbreviationDeclaration(AbbrCode); + AbbrevDecl = U->getAbbreviations()->getAbbreviationDeclaration(AbbrCode); assert(AbbrevDecl); assert(FixedFormSizes); // For best performance this should be specified! @@ -121,7 +119,7 @@ bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *CU, if (FixedFormSize) *OffsetPtr += FixedFormSize; else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, - CU)) { + U)) { // Restore the original offset. *OffsetPtr = Offset; return false; @@ -130,13 +128,12 @@ bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *CU, return true; } -bool -DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *CU, - uint32_t *OffsetPtr) { - DataExtractor DebugInfoData = CU->getDebugInfoExtractor(); - const uint32_t CUEndOffset = CU->getNextCompileUnitOffset(); +bool DWARFDebugInfoEntryMinimal::extract(const DWARFUnit *U, + uint32_t *OffsetPtr) { + DataExtractor DebugInfoData = U->getDebugInfoExtractor(); + const uint32_t UEndOffset = U->getNextUnitOffset(); Offset = *OffsetPtr; - if ((Offset >= CUEndOffset) || !DebugInfoData.isValidOffset(Offset)) + if ((Offset >= UEndOffset) || !DebugInfoData.isValidOffset(Offset)) return false; uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr); if (0 == AbbrCode) { @@ -144,7 +141,7 @@ DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *CU, AbbrevDecl = NULL; return true; } - AbbrevDecl = CU->getAbbreviations()->getAbbreviationDeclaration(AbbrCode); + AbbrevDecl = U->getAbbreviations()->getAbbreviationDeclaration(AbbrCode); if (0 == AbbrevDecl) { // Restore the original offset. *OffsetPtr = Offset; @@ -152,7 +149,7 @@ DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *CU, } bool IsCompileUnitTag = (AbbrevDecl->getTag() == DW_TAG_compile_unit); if (IsCompileUnitTag) - const_cast(CU)->setBaseAddress(0); + const_cast(U)->setBaseAddress(0); // Skip all data in the .debug_info for the attributes for (uint32_t i = 0, n = AbbrevDecl->getNumAttributes(); i < n; ++i) { @@ -162,13 +159,11 @@ DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *CU, if (IsCompileUnitTag && ((Attr == DW_AT_entry_pc) || (Attr == DW_AT_low_pc))) { DWARFFormValue FormValue(Form); - if (FormValue.extractValue(DebugInfoData, OffsetPtr, CU)) { + if (FormValue.extractValue(DebugInfoData, OffsetPtr, U)) { if (Attr == DW_AT_low_pc || Attr == DW_AT_entry_pc) - const_cast(CU) - ->setBaseAddress(FormValue.getUnsigned()); + const_cast(U)->setBaseAddress(FormValue.getUnsigned()); } - } else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, - CU)) { + } else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U)) { // Restore the original offset. *OffsetPtr = Offset; return false; @@ -187,19 +182,16 @@ bool DWARFDebugInfoEntryMinimal::isSubroutineDIE() const { Tag == DW_TAG_inlined_subroutine; } -uint32_t -DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFCompileUnit *cu, - const uint16_t attr, - DWARFFormValue &form_value, - uint32_t *end_attr_offset_ptr) - const { +uint32_t DWARFDebugInfoEntryMinimal::getAttributeValue( + const DWARFUnit *u, const uint16_t attr, DWARFFormValue &form_value, + uint32_t *end_attr_offset_ptr) const { if (AbbrevDecl) { uint32_t attr_idx = AbbrevDecl->findAttributeIndex(attr); if (attr_idx != -1U) { uint32_t offset = getOffset(); - DataExtractor debug_info_data = cu->getDebugInfoExtractor(); + DataExtractor debug_info_data = u->getDebugInfoExtractor(); // Skip the abbreviation code so we are at the data for the attributes debug_info_data.getULEB128(&offset); @@ -207,11 +199,11 @@ DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFCompileUnit *cu, uint32_t idx = 0; while (idx < attr_idx) DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(idx++), - debug_info_data, &offset, cu); + debug_info_data, &offset, u); const uint32_t attr_offset = offset; form_value = DWARFFormValue(AbbrevDecl->getFormByIndex(idx)); - if (form_value.extractValue(debug_info_data, &offset, cu)) { + if (form_value.extractValue(debug_info_data, &offset, u)) { if (end_attr_offset_ptr) *end_attr_offset_ptr = offset; return attr_offset; @@ -223,155 +215,140 @@ DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFCompileUnit *cu, } const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString( - const DWARFCompileUnit *CU, const uint16_t Attr, - const char *FailValue) const { + const DWARFUnit *U, const uint16_t Attr, const char *FailValue) const { DWARFFormValue FormValue; - if (getAttributeValue(CU, Attr, FormValue)) - return FormValue.getAsCString(CU); + if (getAttributeValue(U, Attr, FormValue)) + return FormValue.getAsCString(U); return FailValue; } uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress( - const DWARFCompileUnit *CU, const uint16_t Attr, uint64_t FailValue) const { + const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { DWARFFormValue FormValue; - if (getAttributeValue(CU, Attr, FormValue)) - return FormValue.getAsAddress(CU); + if (getAttributeValue(U, Attr, FormValue)) + return FormValue.getAsAddress(U); return FailValue; } uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned( - const DWARFCompileUnit *CU, const uint16_t Attr, uint64_t FailValue) const { + const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { DWARFFormValue FormValue; - if (getAttributeValue(CU, Attr, FormValue)) { + if (getAttributeValue(U, Attr, FormValue)) return FormValue.getUnsigned(); - } return FailValue; } -int64_t -DWARFDebugInfoEntryMinimal::getAttributeValueAsSigned( - const DWARFCompileUnit* cu, - const uint16_t attr, - int64_t fail_value) const { +int64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsSigned( + const DWARFUnit *u, const uint16_t attr, int64_t fail_value) const { DWARFFormValue form_value; - if (getAttributeValue(cu, attr, form_value)) + if (getAttributeValue(u, attr, form_value)) return form_value.getSigned(); return fail_value; } -uint64_t -DWARFDebugInfoEntryMinimal::getAttributeValueAsReference( - const DWARFCompileUnit* cu, - const uint16_t attr, - uint64_t fail_value) - const { +uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsReference( + const DWARFUnit *u, const uint16_t attr, uint64_t fail_value) const { DWARFFormValue form_value; - if (getAttributeValue(cu, attr, form_value)) - return form_value.getReference(cu); + if (getAttributeValue(u, attr, form_value)) + return form_value.getReference(u); return fail_value; } -bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFCompileUnit *CU, +bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFUnit *U, uint64_t &LowPC, uint64_t &HighPC) const { HighPC = -1ULL; - LowPC = getAttributeValueAsAddress(CU, DW_AT_low_pc, -1ULL); + LowPC = getAttributeValueAsAddress(U, DW_AT_low_pc, -1ULL); if (LowPC != -1ULL) - HighPC = getAttributeValueAsAddress(CU, DW_AT_high_pc, -1ULL); + HighPC = getAttributeValueAsAddress(U, DW_AT_high_pc, -1ULL); return (HighPC != -1ULL); } -void -DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *CU, - DWARFDebugAranges *DebugAranges, - uint32_t CUOffsetInAranges) - const { +void DWARFDebugInfoEntryMinimal::buildAddressRangeTable( + const DWARFUnit *U, DWARFDebugAranges *DebugAranges, + uint32_t UOffsetInAranges) const { if (AbbrevDecl) { if (isSubprogramDIE()) { uint64_t LowPC, HighPC; - if (getLowAndHighPC(CU, LowPC, HighPC)) - DebugAranges->appendRange(CUOffsetInAranges, LowPC, HighPC); + if (getLowAndHighPC(U, LowPC, HighPC)) + DebugAranges->appendRange(UOffsetInAranges, LowPC, HighPC); // FIXME: try to append ranges from .debug_ranges section. } const DWARFDebugInfoEntryMinimal *Child = getFirstChild(); while (Child) { - Child->buildAddressRangeTable(CU, DebugAranges, CUOffsetInAranges); + Child->buildAddressRangeTable(U, DebugAranges, UOffsetInAranges); Child = Child->getSibling(); } } } -bool -DWARFDebugInfoEntryMinimal::addressRangeContainsAddress( - const DWARFCompileUnit *CU, - const uint64_t Address) - const { +bool DWARFDebugInfoEntryMinimal::addressRangeContainsAddress( + const DWARFUnit *U, const uint64_t Address) const { if (isNULL()) return false; uint64_t LowPC, HighPC; - if (getLowAndHighPC(CU, LowPC, HighPC)) + if (getLowAndHighPC(U, LowPC, HighPC)) return (LowPC <= Address && Address <= HighPC); // Try to get address ranges from .debug_ranges section. - uint32_t RangesOffset = getAttributeValueAsReference(CU, DW_AT_ranges, -1U); + uint32_t RangesOffset = getAttributeValueAsReference(U, DW_AT_ranges, -1U); if (RangesOffset != -1U) { DWARFDebugRangeList RangeList; - if (CU->extractRangeList(RangesOffset, RangeList)) - return RangeList.containsAddress(CU->getBaseAddress(), Address); + if (U->extractRangeList(RangesOffset, RangeList)) + return RangeList.containsAddress(U->getBaseAddress(), Address); } return false; } -const char* -DWARFDebugInfoEntryMinimal::getSubroutineName(const DWARFCompileUnit *CU) - const { +const char * +DWARFDebugInfoEntryMinimal::getSubroutineName(const DWARFUnit *U) const { if (!isSubroutineDIE()) return 0; // Try to get mangled name if possible. if (const char *name = - getAttributeValueAsString(CU, DW_AT_MIPS_linkage_name, 0)) + getAttributeValueAsString(U, DW_AT_MIPS_linkage_name, 0)) return name; - if (const char *name = getAttributeValueAsString(CU, DW_AT_linkage_name, 0)) + if (const char *name = getAttributeValueAsString(U, DW_AT_linkage_name, 0)) return name; - if (const char *name = getAttributeValueAsString(CU, DW_AT_name, 0)) + if (const char *name = getAttributeValueAsString(U, DW_AT_name, 0)) return name; // Try to get name from specification DIE. uint32_t spec_ref = - getAttributeValueAsReference(CU, DW_AT_specification, -1U); + getAttributeValueAsReference(U, DW_AT_specification, -1U); if (spec_ref != -1U) { DWARFDebugInfoEntryMinimal spec_die; - if (spec_die.extract(CU, &spec_ref)) { - if (const char *name = spec_die.getSubroutineName(CU)) + if (spec_die.extract(U, &spec_ref)) { + if (const char *name = spec_die.getSubroutineName(U)) return name; } } // Try to get name from abstract origin DIE. uint32_t abs_origin_ref = - getAttributeValueAsReference(CU, DW_AT_abstract_origin, -1U); + getAttributeValueAsReference(U, DW_AT_abstract_origin, -1U); if (abs_origin_ref != -1U) { DWARFDebugInfoEntryMinimal abs_origin_die; - if (abs_origin_die.extract(CU, &abs_origin_ref)) { - if (const char *name = abs_origin_die.getSubroutineName(CU)) + if (abs_origin_die.extract(U, &abs_origin_ref)) { + if (const char *name = abs_origin_die.getSubroutineName(U)) return name; } } return 0; } -void DWARFDebugInfoEntryMinimal::getCallerFrame(const DWARFCompileUnit *CU, +void DWARFDebugInfoEntryMinimal::getCallerFrame(const DWARFUnit *U, uint32_t &CallFile, uint32_t &CallLine, uint32_t &CallColumn) const { - CallFile = getAttributeValueAsUnsigned(CU, DW_AT_call_file, 0); - CallLine = getAttributeValueAsUnsigned(CU, DW_AT_call_line, 0); - CallColumn = getAttributeValueAsUnsigned(CU, DW_AT_call_column, 0); + CallFile = getAttributeValueAsUnsigned(U, DW_AT_call_file, 0); + CallLine = getAttributeValueAsUnsigned(U, DW_AT_call_line, 0); + CallColumn = getAttributeValueAsUnsigned(U, DW_AT_call_column, 0); } DWARFDebugInfoEntryInlinedChain DWARFDebugInfoEntryMinimal::getInlinedChainForAddress( - const DWARFCompileUnit *CU, const uint64_t Address) const { + const DWARFUnit *U, const uint64_t Address) const { DWARFDebugInfoEntryInlinedChain InlinedChain; - InlinedChain.CU = CU; + InlinedChain.U = U; if (isNULL()) return InlinedChain; for (const DWARFDebugInfoEntryMinimal *DIE = this; DIE; ) { @@ -383,7 +360,7 @@ DWARFDebugInfoEntryMinimal::getInlinedChainForAddress( // Try to get child which also contains provided address. const DWARFDebugInfoEntryMinimal *Child = DIE->getFirstChild(); while (Child) { - if (Child->addressRangeContainsAddress(CU, Address)) { + if (Child->addressRangeContainsAddress(U, Address)) { // Assume there is only one such child. break; } diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.h b/lib/DebugInfo/DWARFDebugInfoEntry.h index 2feea36b919..b5a9753487f 100644 --- a/lib/DebugInfo/DWARFDebugInfoEntry.h +++ b/lib/DebugInfo/DWARFDebugInfoEntry.h @@ -18,6 +18,7 @@ namespace llvm { class DWARFDebugAranges; class DWARFCompileUnit; +class DWARFUnit; class DWARFContext; class DWARFFormValue; struct DWARFDebugInfoEntryInlinedChain; @@ -39,23 +40,22 @@ public: DWARFDebugInfoEntryMinimal() : Offset(0), ParentIdx(0), SiblingIdx(0), AbbrevDecl(0) {} - void dump(raw_ostream &OS, const DWARFCompileUnit *cu, - unsigned recurseDepth, unsigned indent = 0) const; - void dumpAttribute(raw_ostream &OS, const DWARFCompileUnit *cu, - uint32_t *offset_ptr, uint16_t attr, uint16_t form, - unsigned indent = 0) const; + void dump(raw_ostream &OS, const DWARFUnit *u, unsigned recurseDepth, + unsigned indent = 0) const; + void dumpAttribute(raw_ostream &OS, const DWARFUnit *u, uint32_t *offset_ptr, + uint16_t attr, uint16_t form, unsigned indent = 0) const; /// Extracts a debug info entry, which is a child of a given compile unit, /// starting at a given offset. If DIE can't be extracted, returns false and /// doesn't change OffsetPtr. - bool extractFast(const DWARFCompileUnit *CU, const uint8_t *FixedFormSizes, + bool extractFast(const DWARFUnit *U, const uint8_t *FixedFormSizes, uint32_t *OffsetPtr); /// Extract a debug info entry for a given compile unit from the /// .debug_info and .debug_abbrev data starting at the given offset. /// If compile unit can't be parsed, returns false and doesn't change /// OffsetPtr. - bool extract(const DWARFCompileUnit *CU, uint32_t *OffsetPtr); + bool extract(const DWARFUnit *U, uint32_t *OffsetPtr); uint32_t getTag() const { return AbbrevDecl ? AbbrevDecl->getTag() : 0; } bool isNULL() const { return AbbrevDecl == 0; } @@ -120,59 +120,53 @@ public: return AbbrevDecl; } - uint32_t getAttributeValue(const DWARFCompileUnit *cu, - const uint16_t attr, DWARFFormValue &formValue, + uint32_t getAttributeValue(const DWARFUnit *u, const uint16_t attr, + DWARFFormValue &formValue, uint32_t *end_attr_offset_ptr = 0) const; - const char* getAttributeValueAsString(const DWARFCompileUnit* cu, - const uint16_t attr, + const char *getAttributeValueAsString(const DWARFUnit *u, const uint16_t attr, const char *fail_value) const; - uint64_t getAttributeValueAsAddress(const DWARFCompileUnit *CU, - const uint16_t Attr, + uint64_t getAttributeValueAsAddress(const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const; - uint64_t getAttributeValueAsUnsigned(const DWARFCompileUnit *cu, - const uint16_t attr, + uint64_t getAttributeValueAsUnsigned(const DWARFUnit *u, const uint16_t attr, uint64_t fail_value) const; - uint64_t getAttributeValueAsReference(const DWARFCompileUnit *cu, - const uint16_t attr, + uint64_t getAttributeValueAsReference(const DWARFUnit *u, const uint16_t attr, uint64_t fail_value) const; - int64_t getAttributeValueAsSigned(const DWARFCompileUnit* cu, - const uint16_t attr, + int64_t getAttributeValueAsSigned(const DWARFUnit *u, const uint16_t attr, int64_t fail_value) const; /// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU. /// Returns true if both attributes are present. - bool getLowAndHighPC(const DWARFCompileUnit *CU, - uint64_t &LowPC, uint64_t &HighPC) const; + bool getLowAndHighPC(const DWARFUnit *U, uint64_t &LowPC, + uint64_t &HighPC) const; - void buildAddressRangeTable(const DWARFCompileUnit *CU, + void buildAddressRangeTable(const DWARFUnit *U, DWARFDebugAranges *DebugAranges, uint32_t CUOffsetInAranges) const; - bool addressRangeContainsAddress(const DWARFCompileUnit *CU, + bool addressRangeContainsAddress(const DWARFUnit *U, const uint64_t Address) const; /// If a DIE represents a subprogram (or inlined subroutine), /// returns its mangled name (or short name, if mangled is missing). /// This name may be fetched from specification or abstract origin /// for this subprogram. Returns null if no name is found. - const char* getSubroutineName(const DWARFCompileUnit *CU) const; + const char *getSubroutineName(const DWARFUnit *U) const; /// Retrieves values of DW_AT_call_file, DW_AT_call_line and /// DW_AT_call_column from DIE (or zeroes if they are missing). - void getCallerFrame(const DWARFCompileUnit *CU, uint32_t &CallFile, + void getCallerFrame(const DWARFUnit *U, uint32_t &CallFile, uint32_t &CallLine, uint32_t &CallColumn) const; /// Get inlined chain for a given address, rooted at the current DIE. /// Returns empty chain if address is not contained in address range /// of current DIE. DWARFDebugInfoEntryInlinedChain - getInlinedChainForAddress(const DWARFCompileUnit *CU, - const uint64_t Address) const; + getInlinedChainForAddress(const DWARFUnit *U, const uint64_t Address) const; }; /// DWARFDebugInfoEntryInlinedChain - represents a chain of inlined_subroutine @@ -181,9 +175,9 @@ public: /// (except the last DIE) in this chain is contained in address /// range for next DIE in the chain. struct DWARFDebugInfoEntryInlinedChain { - DWARFDebugInfoEntryInlinedChain() : CU(0) {} + DWARFDebugInfoEntryInlinedChain() : U(0) {} SmallVector DIEs; - const DWARFCompileUnit *CU; + const DWARFUnit *U; }; } diff --git a/lib/DebugInfo/DWARFFormValue.cpp b/lib/DebugInfo/DWARFFormValue.cpp index 4ae92fc8981..8ea30c612d9 100644 --- a/lib/DebugInfo/DWARFFormValue.cpp +++ b/lib/DebugInfo/DWARFFormValue.cpp @@ -74,9 +74,8 @@ DWARFFormValue::getFixedFormSizes(uint8_t AddrSize, uint16_t Version) { return 0; } -bool -DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, - const DWARFCompileUnit *cu) { +bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, + const DWARFUnit *cu) { bool indirect = false; bool is_block = false; Value.data = NULL; @@ -206,13 +205,13 @@ DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, bool DWARFFormValue::skipValue(DataExtractor debug_info_data, uint32_t* offset_ptr, - const DWARFCompileUnit *cu) const { + const DWARFUnit *cu) const { return DWARFFormValue::skipValue(Form, debug_info_data, offset_ptr, cu); } bool DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, - uint32_t *offset_ptr, const DWARFCompileUnit *cu) { + uint32_t *offset_ptr, const DWARFUnit *cu) { bool indirect = false; do { switch (form) { @@ -312,7 +311,7 @@ DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, } void -DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const { +DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { DataExtractor debug_str_data(cu->getStringSection(), true, 0); DataExtractor debug_str_offset_data(cu->getStringOffsetSection(), true, 0); uint64_t uvalue = getUnsigned(); @@ -436,8 +435,7 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const { OS << format(" => {0x%8.8" PRIx64 "}", uvalue + (cu ? cu->getOffset() : 0)); } -const char* -DWARFFormValue::getAsCString(const DWARFCompileUnit *CU) const { +const char *DWARFFormValue::getAsCString(const DWARFUnit *CU) const { if (isInlinedCStr()) return Value.cstr; if (!CU) @@ -452,8 +450,7 @@ DWARFFormValue::getAsCString(const DWARFCompileUnit *CU) const { return CU->getStringExtractor().getCStr(&Offset); } -uint64_t -DWARFFormValue::getAsAddress(const DWARFCompileUnit *CU) const { +uint64_t DWARFFormValue::getAsAddress(const DWARFUnit *CU) const { if (!CU) return 0; if (Value.IsDWOIndex) { @@ -466,7 +463,7 @@ DWARFFormValue::getAsAddress(const DWARFCompileUnit *CU) const { return Value.uval; } -uint64_t DWARFFormValue::getReference(const DWARFCompileUnit *cu) const { +uint64_t DWARFFormValue::getReference(const DWARFUnit *cu) const { uint64_t die_offset = Value.uval; switch (Form) { case DW_FORM_ref1: diff --git a/lib/DebugInfo/DWARFUnit.cpp b/lib/DebugInfo/DWARFUnit.cpp new file mode 100644 index 00000000000..c5ffb33cb89 --- /dev/null +++ b/lib/DebugInfo/DWARFUnit.cpp @@ -0,0 +1,391 @@ +//===-- DWARFUnit.cpp -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFUnit.h" +#include "DWARFContext.h" +#include "llvm/DebugInfo/DWARFFormValue.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Path.h" + +using namespace llvm; +using namespace dwarf; + +DWARFUnit::DWARFUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, + StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, + const RelocAddrMap *M, bool LE) + : Abbrev(DA), InfoSection(IS), AbbrevSection(AS), RangeSection(RS), + StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS), + RelocMap(M), isLittleEndian(LE) { + clear(); +} + +DWARFUnit::~DWARFUnit() { +} + +bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index, + uint64_t &Result) const { + uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize; + if (AddrOffsetSection.size() < Offset + AddrSize) + return false; + DataExtractor DA(AddrOffsetSection, isLittleEndian, AddrSize); + Result = DA.getAddress(&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) + return false; + DataExtractor DA(StringOffsetSection, isLittleEndian, 0); + Result = DA.getU32(&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); + AddrSize = debug_info.getU8(offset_ptr); + + bool lengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); + bool versionOK = DWARFContext::isSupportedVersion(Version); + bool abbrOffsetOK = AbbrevSection.size() > abbrOffset; + bool addrSizeOK = AddrSize == 4 || AddrSize == 8; + + if (!lengthOK || !versionOK || !addrSizeOK || !abbrOffsetOK) + return false; + + Abbrevs = Abbrev->getAbbreviationDeclarationSet(abbrOffset); + return true; +} + +bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { + clear(); + + Offset = *offset_ptr; + + if (debug_info.isValidOffset(*offset_ptr)) { + if (extractImpl(debug_info, offset_ptr)) + return true; + + // reset the offset to where we tried to parse from if anything went wrong + *offset_ptr = Offset; + } + + return false; +} + +uint32_t +DWARFUnit::extract(uint32_t offset, DataExtractor debug_info_data, + const DWARFAbbreviationDeclarationSet *abbrevs) { + clear(); + + Offset = offset; + + if (debug_info_data.isValidOffset(offset)) { + Length = debug_info_data.getU32(&offset); + Version = debug_info_data.getU16(&offset); + bool abbrevsOK = debug_info_data.getU32(&offset) == abbrevs->getOffset(); + Abbrevs = abbrevs; + AddrSize = debug_info_data.getU8(&offset); + + bool versionOK = DWARFContext::isSupportedVersion(Version); + bool addrSizeOK = AddrSize == 4 || AddrSize == 8; + + if (versionOK && addrSizeOK && abbrevsOK && + debug_info_data.isValidOffset(offset)) + return offset; + } + return 0; +} + +bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, + DWARFDebugRangeList &RangeList) const { + // Require that compile unit is extracted. + assert(DieArray.size() > 0); + DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize); + uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; + return RangeList.extract(RangesData, &ActualRangeListOffset); +} + +void DWARFUnit::clear() { + Offset = 0; + Length = 0; + Version = 0; + Abbrevs = 0; + AddrSize = 0; + BaseAddr = 0; + RangeSectionBase = 0; + AddrOffsetSectionBase = 0; + clearDIEs(false); + DWO.reset(); +} + +const char *DWARFUnit::getCompilationDir() { + extractDIEsIfNeeded(true); + if (DieArray.empty()) + return 0; + return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0); +} + +uint64_t DWARFUnit::getDWOId() { + extractDIEsIfNeeded(true); + const uint64_t FailValue = -1ULL; + if (DieArray.empty()) + return FailValue; + return DieArray[0] + .getAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, FailValue); +} + +void DWARFUnit::setDIERelations() { + if (DieArray.empty()) + return; + DWARFDebugInfoEntryMinimal *die_array_begin = &DieArray.front(); + DWARFDebugInfoEntryMinimal *die_array_end = &DieArray.back(); + DWARFDebugInfoEntryMinimal *curr_die; + // We purposely are skipping the last element in the array in the loop below + // so that we can always have a valid next item + for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) { + // Since our loop doesn't include the last element, we can always + // safely access the next die in the array. + DWARFDebugInfoEntryMinimal *next_die = curr_die + 1; + + const DWARFAbbreviationDeclaration *curr_die_abbrev = + curr_die->getAbbreviationDeclarationPtr(); + + if (curr_die_abbrev) { + // Normal DIE + if (curr_die_abbrev->hasChildren()) + next_die->setParent(curr_die); + else + curr_die->setSibling(next_die); + } else { + // NULL DIE that terminates a sibling chain + DWARFDebugInfoEntryMinimal *parent = curr_die->getParent(); + if (parent) + parent->setSibling(next_die); + } + } + + // Since we skipped the last element, we need to fix it up! + if (die_array_begin < die_array_end) + curr_die->setParent(die_array_begin); +} + +void DWARFUnit::extractDIEsToVector( + bool AppendCUDie, bool AppendNonCUDies, + std::vector &Dies) const { + if (!AppendCUDie && !AppendNonCUDies) + return; + + // Set the offset to that of the first DIE and calculate the start of the + // next compilation unit header. + uint32_t Offset = getFirstDIEOffset(); + uint32_t NextCUOffset = getNextUnitOffset(); + DWARFDebugInfoEntryMinimal DIE; + uint32_t Depth = 0; + const uint8_t *FixedFormSizes = + DWARFFormValue::getFixedFormSizes(getAddressByteSize(), getVersion()); + bool IsCUDie = true; + + while (Offset < NextCUOffset && + DIE.extractFast(this, FixedFormSizes, &Offset)) { + if (IsCUDie) { + if (AppendCUDie) + Dies.push_back(DIE); + if (!AppendNonCUDies) + break; + // The average bytes per DIE entry has been seen to be + // around 14-20 so let's pre-reserve the needed memory for + // our DIE entries accordingly. + Dies.reserve(Dies.size() + getDebugInfoSize() / 14); + IsCUDie = false; + } else { + Dies.push_back(DIE); + } + + const DWARFAbbreviationDeclaration *AbbrDecl = + DIE.getAbbreviationDeclarationPtr(); + if (AbbrDecl) { + // Normal DIE + if (AbbrDecl->hasChildren()) + ++Depth; + } else { + // NULL DIE. + if (Depth > 0) + --Depth; + if (Depth == 0) + break; // We are done with this compile unit! + } + } + + // Give a little bit of info if we encounter corrupt DWARF (our offset + // should always terminate at or before the start of the next compilation + // unit header). + if (Offset > NextCUOffset) + fprintf(stderr, "warning: DWARF compile unit extends beyond its " + "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), Offset); +} + +size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { + if ((CUDieOnly && DieArray.size() > 0) || + DieArray.size() > 1) + return 0; // Already parsed. + + bool HasCUDie = DieArray.size() > 0; + extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray); + + if (DieArray.empty()) + return 0; + + // If CU DIE was just parsed, copy several attribute values from it. + if (!HasCUDie) { + uint64_t BaseAddr = + DieArray[0].getAttributeValueAsUnsigned(this, DW_AT_low_pc, -1U); + if (BaseAddr == -1U) + BaseAddr = DieArray[0].getAttributeValueAsUnsigned(this, DW_AT_entry_pc, 0); + setBaseAddress(BaseAddr); + AddrOffsetSectionBase = + DieArray[0].getAttributeValueAsReference(this, DW_AT_GNU_addr_base, 0); + RangeSectionBase = + DieArray[0].getAttributeValueAsReference(this, DW_AT_GNU_ranges_base, 0); + } + + setDIERelations(); + return DieArray.size(); +} + +DWARFUnit::DWOHolder::DWOHolder(object::ObjectFile *DWOFile) + : DWOFile(DWOFile), + DWOContext(cast(DIContext::getDWARFContext(DWOFile))), + DWOU(0) { + if (DWOContext->getNumDWOCompileUnits() > 0) + DWOU = DWOContext->getDWOCompileUnitAtIndex(0); +} + +bool DWARFUnit::parseDWO() { + if (DWO.get() != 0) + return false; + extractDIEsIfNeeded(true); + if (DieArray.empty()) + return false; + const char *DWOFileName = + DieArray[0].getAttributeValueAsString(this, DW_AT_GNU_dwo_name, 0); + if (DWOFileName == 0) + return false; + const char *CompilationDir = + DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0); + SmallString<16> AbsolutePath; + if (sys::path::is_relative(DWOFileName) && CompilationDir != 0) { + sys::path::append(AbsolutePath, CompilationDir); + } + sys::path::append(AbsolutePath, DWOFileName); + object::ObjectFile *DWOFile = + object::ObjectFile::createObjectFile(AbsolutePath); + if (!DWOFile) + return false; + // Reset DWOHolder. + DWO.reset(new DWOHolder(DWOFile)); + DWARFUnit *DWOCU = DWO->getUnit(); + // Verify that compile unit in .dwo file is valid. + if (DWOCU == 0 || DWOCU->getDWOId() != getDWOId()) { + DWO.reset(); + return false; + } + // Share .debug_addr and .debug_ranges section with compile unit in .dwo + DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); + DWOCU->setRangesSection(RangeSection, RangeSectionBase); + return true; +} + +void DWARFUnit::clearDIEs(bool KeepCUDie) { + if (DieArray.size() > (unsigned)KeepCUDie) { + // std::vectors never get any smaller when resized to a smaller size, + // or when clear() or erase() are called, the size will report that it + // is smaller, but the memory allocated remains intact (call capacity() + // to see this). So we need to create a temporary vector and swap the + // contents which will cause just the internal pointers to be swapped + // so that when temporary vector goes out of scope, it will destroy the + // contents. + std::vector TmpArray; + DieArray.swap(TmpArray); + // Save at least the compile unit DIE + if (KeepCUDie) + DieArray.push_back(TmpArray.front()); + } +} + +void +DWARFUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges, + bool clear_dies_if_already_not_parsed, + uint32_t CUOffsetInAranges) { + // This function is usually called if there in no .debug_aranges section + // in order to produce a compile unit level set of address ranges that + // is accurate. If the DIEs weren't parsed, then we don't want all dies for + // all compile units to stay loaded when they weren't needed. So we can end + // up parsing the DWARF and then throwing them all away to keep memory usage + // down. + const bool clear_dies = extractDIEsIfNeeded(false) > 1 && + clear_dies_if_already_not_parsed; + DieArray[0].buildAddressRangeTable(this, debug_aranges, CUOffsetInAranges); + bool DWOCreated = parseDWO(); + if (DWO.get()) { + // If there is a .dwo file for this compile unit, then skeleton CU DIE + // doesn't have children, and we should instead build address range table + // from DIEs in the .debug_info.dwo section of .dwo file. + DWO->getUnit()->buildAddressRangeTable( + debug_aranges, clear_dies_if_already_not_parsed, CUOffsetInAranges); + } + if (DWOCreated && clear_dies_if_already_not_parsed) + DWO.reset(); + + // Keep memory down by clearing DIEs if this generate function + // caused them to be parsed. + if (clear_dies) + clearDIEs(true); +} + +const DWARFDebugInfoEntryMinimal * +DWARFUnit::getSubprogramForAddress(uint64_t Address) { + extractDIEsIfNeeded(false); + for (size_t i = 0, n = DieArray.size(); i != n; i++) + if (DieArray[i].isSubprogramDIE() && + DieArray[i].addressRangeContainsAddress(this, Address)) { + return &DieArray[i]; + } + return 0; +} + +DWARFDebugInfoEntryInlinedChain +DWARFUnit::getInlinedChainForAddress(uint64_t Address) { + // First, find a subprogram that contains the given address (the root + // of inlined chain). + const DWARFUnit *ChainCU = 0; + const DWARFDebugInfoEntryMinimal *SubprogramDIE = + getSubprogramForAddress(Address); + if (SubprogramDIE) { + ChainCU = this; + } else { + // Try to look for subprogram DIEs in the DWO file. + parseDWO(); + if (DWO.get()) { + SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address); + if (SubprogramDIE) + ChainCU = DWO->getUnit(); + } + } + + // Get inlined chain rooted at this subprogram DIE. + if (!SubprogramDIE) + return DWARFDebugInfoEntryInlinedChain(); + return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address); +} diff --git a/lib/DebugInfo/DWARFUnit.h b/lib/DebugInfo/DWARFUnit.h new file mode 100644 index 00000000000..4d93de9e100 --- /dev/null +++ b/lib/DebugInfo/DWARFUnit.h @@ -0,0 +1,175 @@ +//===-- DWARFUnit.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFUNIT_H +#define LLVM_DEBUGINFO_DWARFUNIT_H + +#include "llvm/ADT/OwningPtr.h" +#include "DWARFDebugAbbrev.h" +#include "DWARFDebugInfoEntry.h" +#include "DWARFDebugRangeList.h" +#include "DWARFRelocMap.h" +#include + +namespace llvm { + +namespace object { +class ObjectFile; +} + +class DWARFDebugAbbrev; +class StringRef; +class raw_ostream; + +class DWARFUnit { + const DWARFDebugAbbrev *Abbrev; + StringRef InfoSection; + StringRef AbbrevSection; + StringRef RangeSection; + uint32_t RangeSectionBase; + StringRef StringSection; + StringRef StringOffsetSection; + StringRef AddrOffsetSection; + uint32_t AddrOffsetSectionBase; + const RelocAddrMap *RelocMap; + bool isLittleEndian; + + uint32_t Offset; + uint32_t Length; + uint16_t Version; + const DWARFAbbreviationDeclarationSet *Abbrevs; + uint8_t AddrSize; + uint64_t BaseAddr; + // The compile unit debug information entry items. + std::vector DieArray; + + class DWOHolder { + OwningPtr DWOFile; + OwningPtr DWOContext; + DWARFUnit *DWOU; + public: + DWOHolder(object::ObjectFile *DWOFile); + DWARFUnit *getUnit() const { return DWOU; } + }; + OwningPtr DWO; + +protected: + virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr); + +public: + + DWARFUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, + StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, + const RelocAddrMap *M, bool LE); + + virtual ~DWARFUnit(); + + StringRef getStringSection() const { return StringSection; } + StringRef getStringOffsetSection() const { return StringOffsetSection; } + void setAddrOffsetSection(StringRef AOS, uint32_t Base) { + AddrOffsetSection = AOS; + AddrOffsetSectionBase = Base; + } + void setRangesSection(StringRef RS, uint32_t Base) { + RangeSection = RS; + RangeSectionBase = Base; + } + + bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const; + // FIXME: Result should be uint64_t in DWARF64. + bool getStringOffsetSectionItem(uint32_t Index, uint32_t &Result) const; + + DataExtractor getDebugInfoExtractor() const { + return DataExtractor(InfoSection, isLittleEndian, AddrSize); + } + DataExtractor getStringExtractor() const { + return DataExtractor(StringSection, false, 0); + } + + const RelocAddrMap *getRelocMap() const { return RelocMap; } + + bool extract(DataExtractor debug_info, uint32_t* offset_ptr); + uint32_t extract(uint32_t offset, DataExtractor debug_info_data, + const DWARFAbbreviationDeclarationSet *abbrevs); + + /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it + /// hasn't already been done. Returns the number of DIEs parsed at this call. + size_t extractDIEsIfNeeded(bool CUDieOnly); + /// extractRangeList - extracts the range list referenced by this compile + /// unit from .debug_ranges section. Returns true on success. + /// Requires that compile unit is already extracted. + bool extractRangeList(uint32_t RangeListOffset, + DWARFDebugRangeList &RangeList) const; + void clear(); + uint32_t getOffset() const { return Offset; } + /// Size in bytes of the compile unit header. + virtual uint32_t getSize() const { return 11; } + bool containsDIEOffset(uint32_t die_offset) const { + return die_offset >= getFirstDIEOffset() && + die_offset < getNextUnitOffset(); + } + uint32_t getFirstDIEOffset() const { return Offset + getSize(); } + uint32_t getNextUnitOffset() const { return Offset + Length + 4; } + /// Size in bytes of the .debug_info data associated with this compile unit. + size_t getDebugInfoSize() const { return Length + 4 - getSize(); } + uint32_t getLength() const { return Length; } + uint16_t getVersion() const { return Version; } + const DWARFAbbreviationDeclarationSet *getAbbreviations() const { + return Abbrevs; + } + uint8_t getAddressByteSize() const { return AddrSize; } + uint64_t getBaseAddress() const { return BaseAddr; } + + void setBaseAddress(uint64_t base_addr) { + BaseAddr = base_addr; + } + + const DWARFDebugInfoEntryMinimal * + getCompileUnitDIE(bool extract_cu_die_only = true) { + extractDIEsIfNeeded(extract_cu_die_only); + return DieArray.empty() ? NULL : &DieArray[0]; + } + + const char *getCompilationDir(); + uint64_t getDWOId(); + + /// setDIERelations - We read in all of the DIE entries into our flat list + /// of DIE entries and now we need to go back through all of them and set the + /// parent, sibling and child pointers for quick DIE navigation. + void setDIERelations(); + + void buildAddressRangeTable(DWARFDebugAranges *debug_aranges, + bool clear_dies_if_already_not_parsed, + uint32_t CUOffsetInAranges); + + /// getInlinedChainForAddress - fetches inlined chain for a given address. + /// Returns empty chain if there is no subprogram containing address. The + /// chain is valid as long as parsed compile unit DIEs are not cleared. + DWARFDebugInfoEntryInlinedChain getInlinedChainForAddress(uint64_t Address); + +private: + /// extractDIEsToVector - Appends all parsed DIEs to a vector. + void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs, + std::vector &DIEs) const; + /// clearDIEs - Clear parsed DIEs to keep memory usage low. + void clearDIEs(bool KeepCUDie); + + /// parseDWO - Parses .dwo file for current compile unit. Returns true if + /// it was actually constructed. + bool parseDWO(); + + /// getSubprogramForAddress - Returns subprogram DIE with address range + /// encompassing the provided address. The pointer is alive as long as parsed + /// compile unit DIEs are not cleared. + const DWARFDebugInfoEntryMinimal *getSubprogramForAddress(uint64_t Address); +}; + +} + +#endif