Index: include/llvm/DebugInfo/DIContext.h =================================================================== --- include/llvm/DebugInfo/DIContext.h +++ include/llvm/DebugInfo/DIContext.h @@ -21,6 +21,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/RelocVisitor.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/DataTypes.h" namespace llvm { @@ -122,6 +123,12 @@ class DIContext { public: + enum DIContextKind { + DICK_DWARF + }; + DIContextKind getKind() const { return Kind; } + + DIContext(DIContextKind K) : Kind(K) {} virtual ~DIContext(); /// getDWARFContext - get a context for binary DWARF data. @@ -135,6 +142,8 @@ uint64_t Size, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; virtual DIInliningInfo getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; +private: + const DIContextKind Kind; }; } Index: include/llvm/DebugInfo/DWARFFormValue.h =================================================================== --- include/llvm/DebugInfo/DWARFFormValue.h +++ include/llvm/DebugInfo/DWARFFormValue.h @@ -20,7 +20,7 @@ class DWARFFormValue { public: struct ValueType { - ValueType() : data(NULL) { + ValueType() : data(NULL), IsDWOIndex(false) { uval = 0; } @@ -30,6 +30,7 @@ const char* cstr; }; const uint8_t* data; + bool IsDWOIndex; }; enum { @@ -63,11 +64,8 @@ bool resolveCompileUnitReferences(const DWARFCompileUnit* cu); uint64_t getUnsigned() const { return Value.uval; } int64_t getSigned() const { return Value.sval; } - const char *getAsCString(const DataExtractor *debug_str_data_ptr) const; - const char *getIndirectCString(const DataExtractor *, - const DataExtractor *) const; - uint64_t getIndirectAddress(const DataExtractor *, - const DWARFCompileUnit *) const; + const char *getAsCString(const DWARFCompileUnit *CU) const; + uint64_t getAsAddress(const DWARFCompileUnit *CU) const; bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFCompileUnit *cu) const; static bool skipValue(uint16_t form, DataExtractor debug_info_data, Index: lib/DebugInfo/DWARFCompileUnit.h =================================================================== --- lib/DebugInfo/DWARFCompileUnit.h +++ lib/DebugInfo/DWARFCompileUnit.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H #define LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H +#include "llvm/ADT/OwningPtr.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugInfoEntry.h" #include "DWARFDebugRangeList.h" @@ -18,18 +19,27 @@ 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; @@ -41,6 +51,17 @@ 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; + public: DWARFCompileUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, @@ -54,9 +75,27 @@ StringRef getStringSection() const { return StringSection; } StringRef getStringOffsetSection() const { return StringOffsetSection; } - StringRef getAddrOffsetSection() const { return AddrOffsetSection; } + 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; } - DataExtractor getDebugInfoExtractor() const; bool extract(DataExtractor debug_info, uint32_t* offset_ptr); uint32_t extract(uint32_t offset, DataExtractor debug_info_data, @@ -102,6 +141,7 @@ } 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 @@ -109,11 +149,13 @@ void setDIERelations(); void buildAddressRangeTable(DWARFDebugAranges *debug_aranges, - bool clear_dies_if_already_not_parsed); + 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. - DWARFDebugInfoEntryMinimal::InlinedChain getInlinedChainForAddress( + /// 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: @@ -122,6 +164,15 @@ 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); }; } Index: lib/DebugInfo/DWARFCompileUnit.cpp =================================================================== --- lib/DebugInfo/DWARFCompileUnit.cpp +++ lib/DebugInfo/DWARFCompileUnit.cpp @@ -12,12 +12,31 @@ #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; -DataExtractor DWARFCompileUnit::getDebugInfoExtractor() const { - return DataExtractor(InfoSection, isLittleEndian, AddrSize); +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) { @@ -78,7 +97,8 @@ // Require that compile unit is extracted. assert(DieArray.size() > 0); DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize); - return RangeList.extract(RangesData, &RangeListOffset); + uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; + return RangeList.extract(RangesData, &ActualRangeListOffset); } void DWARFCompileUnit::clear() { @@ -88,7 +108,10 @@ Abbrevs = 0; AddrSize = 0; BaseAddr = 0; + RangeSectionBase = 0; + AddrOffsetSectionBase = 0; clearDIEs(false); + DWO.reset(); } void DWARFCompileUnit::dump(raw_ostream &OS) { @@ -112,6 +135,15 @@ return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0); } +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; @@ -207,21 +239,72 @@ DieArray.size() > 1) return 0; // Already parsed. - extractDIEsToVector(DieArray.empty(), !CUDieOnly, DieArray); + bool HasCUDie = DieArray.size() > 0; + extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray); + + if (DieArray.empty()) + return 0; - // Set the base address of current compile unit. - if (!DieArray.empty()) { + // 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, @@ -241,7 +324,8 @@ void DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges, - bool clear_dies_if_already_not_parsed){ + 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 @@ -250,7 +334,17 @@ // down. const bool clear_dies = extractDIEsIfNeeded(false) > 1 && clear_dies_if_already_not_parsed; - DieArray[0].buildAddressRangeTable(this, debug_aranges); + 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. @@ -258,21 +352,38 @@ clearDIEs(true); } -DWARFDebugInfoEntryMinimal::InlinedChain -DWARFCompileUnit::getInlinedChainForAddress(uint64_t Address) { - // First, find a subprogram that contains the given address (the root - // of inlined chain). +const DWARFDebugInfoEntryMinimal * +DWARFCompileUnit::getSubprogramForAddress(uint64_t Address) { extractDIEsIfNeeded(false); - const DWARFDebugInfoEntryMinimal *SubprogramDIE = 0; - for (size_t i = 0, n = DieArray.size(); i != n; i++) { + for (size_t i = 0, n = DieArray.size(); i != n; i++) if (DieArray[i].isSubprogramDIE() && DieArray[i].addressRangeContainsAddress(this, Address)) { - SubprogramDIE = &DieArray[i]; - break; + 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 DWARFDebugInfoEntryMinimal::InlinedChain(); - return SubprogramDIE->getInlinedChainForAddress(this, Address); + return DWARFDebugInfoEntryInlinedChain(); + return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address); } Index: lib/DebugInfo/DWARFContext.h =================================================================== --- lib/DebugInfo/DWARFContext.h +++ lib/DebugInfo/DWARFContext.h @@ -27,14 +27,14 @@ /// information parsing. The actual data is supplied through pure virtual /// methods that a concrete implementation provides. class DWARFContext : public DIContext { - SmallVector CUs; + SmallVector CUs; OwningPtr Abbrev; OwningPtr Loc; OwningPtr Aranges; OwningPtr Line; OwningPtr DebugFrame; - SmallVector DWOCUs; + SmallVector DWOCUs; OwningPtr AbbrevDWO; DWARFContext(DWARFContext &) LLVM_DELETED_FUNCTION; @@ -48,7 +48,13 @@ void parseDWOCompileUnits(); public: - DWARFContext() {} + DWARFContext() : DIContext(DICK_DWARF) {} + virtual ~DWARFContext(); + + static bool classof(const DIContext *DICtx) { + return DICtx->getKind() == DICK_DWARF; + } + virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All); /// Get the number of compile units in this context. @@ -69,14 +75,14 @@ DWARFCompileUnit *getCompileUnitAtIndex(unsigned index) { if (CUs.empty()) parseCompileUnits(); - return &CUs[index]; + return CUs[index]; } /// Get the compile unit at the specified index for the DWO compile units. DWARFCompileUnit *getDWOCompileUnitAtIndex(unsigned index) { if (DWOCUs.empty()) parseDWOCompileUnits(); - return &DWOCUs[index]; + return DWOCUs[index]; } /// Get a pointer to the parsed DebugAbbrev object. Index: lib/DebugInfo/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARFContext.cpp +++ lib/DebugInfo/DWARFContext.cpp @@ -23,6 +23,11 @@ typedef DWARFDebugLine::LineTable DWARFLineTable; +DWARFContext::~DWARFContext() { + DeleteContainerPointers(CUs); + DeleteContainerPointers(DWOCUs); +} + void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { OS << ".debug_abbrev contents:\n"; @@ -249,18 +254,15 @@ const DataExtractor &DIData = DataExtractor(getInfoSection(), isLittleEndian(), 0); while (DIData.isValidOffset(offset)) { - CUs.push_back(DWARFCompileUnit(getDebugAbbrev(), getInfoSection(), - getAbbrevSection(), getRangeSection(), - getStringSection(), StringRef(), - getAddrSection(), - &infoRelocMap(), - isLittleEndian())); - if (!CUs.back().extract(DIData, &offset)) { - CUs.pop_back(); + OwningPtr CU(new DWARFCompileUnit( + getDebugAbbrev(), getInfoSection(), getAbbrevSection(), + getRangeSection(), getStringSection(), StringRef(), getAddrSection(), + &infoRelocMap(), isLittleEndian())); + if (!CU->extract(DIData, &offset)) { break; } - - offset = CUs.back().getNextCompileUnitOffset(); + CUs.push_back(CU.take()); + offset = CUs.back()->getNextCompileUnitOffset(); } } @@ -269,34 +271,30 @@ const DataExtractor &DIData = DataExtractor(getInfoDWOSection(), isLittleEndian(), 0); while (DIData.isValidOffset(offset)) { - DWOCUs.push_back(DWARFCompileUnit(getDebugAbbrevDWO(), getInfoDWOSection(), - getAbbrevDWOSection(), - getRangeDWOSection(), - getStringDWOSection(), - getStringOffsetDWOSection(), - getAddrSection(), - &infoDWORelocMap(), - isLittleEndian())); - if (!DWOCUs.back().extract(DIData, &offset)) { - DWOCUs.pop_back(); + OwningPtr DWOCU(new DWARFCompileUnit( + getDebugAbbrevDWO(), getInfoDWOSection(), getAbbrevDWOSection(), + getRangeDWOSection(), getStringDWOSection(), + getStringOffsetDWOSection(), getAddrSection(), &infoDWORelocMap(), + isLittleEndian())); + if (!DWOCU->extract(DIData, &offset)) { break; } - - offset = DWOCUs.back().getNextCompileUnitOffset(); + DWOCUs.push_back(DWOCU.take()); + offset = DWOCUs.back()->getNextCompileUnitOffset(); } } namespace { struct OffsetComparator { - bool operator()(const DWARFCompileUnit &LHS, - const DWARFCompileUnit &RHS) const { - return LHS.getOffset() < RHS.getOffset(); + bool operator()(const DWARFCompileUnit *LHS, + const DWARFCompileUnit *RHS) const { + return LHS->getOffset() < RHS->getOffset(); } - bool operator()(const DWARFCompileUnit &LHS, uint32_t RHS) const { - return LHS.getOffset() < RHS; + bool operator()(const DWARFCompileUnit *LHS, uint32_t RHS) const { + return LHS->getOffset() < RHS; } - bool operator()(uint32_t LHS, const DWARFCompileUnit &RHS) const { - return LHS < RHS.getOffset(); + bool operator()(uint32_t LHS, const DWARFCompileUnit *RHS) const { + return LHS < RHS->getOffset(); } }; } @@ -305,10 +303,11 @@ if (CUs.empty()) parseCompileUnits(); - DWARFCompileUnit *CU = std::lower_bound(CUs.begin(), CUs.end(), Offset, - OffsetComparator()); - if (CU != CUs.end()) - return &*CU; + DWARFCompileUnit **CU = + std::lower_bound(CUs.begin(), CUs.end(), Offset, OffsetComparator()); + if (CU != CUs.end()) { + return *CU; + } return 0; } @@ -376,11 +375,11 @@ // The address may correspond to instruction in some inlined function, // so we have to build the chain of inlined functions and take the // name of the topmost function in it. - const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain = + const DWARFDebugInfoEntryInlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); - if (InlinedChain.size() > 0) { - const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0]; - if (const char *Name = TopFunctionDIE.getSubroutineName(CU)) + if (InlinedChain.DIEs.size() > 0) { + const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain.DIEs[0]; + if (const char *Name = TopFunctionDIE.getSubroutineName(InlinedChain.CU)) FunctionName = Name; } } @@ -409,11 +408,11 @@ // The address may correspond to instruction in some inlined function, // so we have to build the chain of inlined functions and take the // name of the topmost function in it. - const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain = + const DWARFDebugInfoEntryInlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); - if (InlinedChain.size() > 0) { - const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0]; - if (const char *Name = TopFunctionDIE.getSubroutineName(CU)) + if (InlinedChain.DIEs.size() > 0) { + const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain.DIEs[0]; + if (const char *Name = TopFunctionDIE.getSubroutineName(InlinedChain.CU)) FunctionName = Name; } } @@ -423,8 +422,8 @@ // If the Specifier says we don't need FileLineInfo, just // return the top-most function at the starting address. if (!Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { - Lines.push_back(std::make_pair(Address, - DILineInfo(StringRef(""), + Lines.push_back(std::make_pair(Address, + DILineInfo(StringRef(""), FuncNameRef, 0, 0))); return Lines; } @@ -446,7 +445,7 @@ std::string FileName = ""; getFileNameForCompileUnit(CU, LineTable, Row.File, NeedsAbsoluteFilePath, FileName); - Lines.push_back(std::make_pair(Row.Address, + Lines.push_back(std::make_pair(Row.Address, DILineInfo(StringRef(FileName), FuncNameRef, Row.Line, Row.Column))); } @@ -460,23 +459,23 @@ if (!CU) return DIInliningInfo(); - const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain = + const DWARFDebugInfoEntryInlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); - if (InlinedChain.size() == 0) + if (InlinedChain.DIEs.size() == 0) return DIInliningInfo(); DIInliningInfo InliningInfo; uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; const DWARFLineTable *LineTable = 0; - for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) { - const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain[i]; + for (uint32_t i = 0, n = InlinedChain.DIEs.size(); i != n; i++) { + const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain.DIEs[i]; std::string FileName = ""; std::string FunctionName = ""; uint32_t Line = 0; uint32_t Column = 0; // Get function name if necessary. if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { - if (const char *Name = FunctionDIE.getSubroutineName(CU)) + if (const char *Name = FunctionDIE.getSubroutineName(InlinedChain.CU)) FunctionName = Name; } if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { @@ -500,7 +499,8 @@ } // Get call file/line/column of a current DIE. if (i + 1 < n) { - FunctionDIE.getCallerFrame(CU, CallFile, CallLine, CallColumn); + FunctionDIE.getCallerFrame(InlinedChain.CU, CallFile, CallLine, + CallColumn); } } DILineInfo Frame(StringRef(FileName), StringRef(FunctionName), Index: lib/DebugInfo/DWARFDebugAranges.cpp =================================================================== --- lib/DebugInfo/DWARFDebugAranges.cpp +++ lib/DebugInfo/DWARFDebugAranges.cpp @@ -95,7 +95,7 @@ if (DWARFCompileUnit *cu = ctx->getCompileUnitAtIndex(cu_idx)) { uint32_t CUOffset = cu->getOffset(); if (ParsedCUOffsets.insert(CUOffset).second) - cu->buildAddressRangeTable(this, true); + cu->buildAddressRangeTable(this, true, CUOffset); } } } Index: lib/DebugInfo/DWARFDebugInfoEntry.h =================================================================== --- lib/DebugInfo/DWARFDebugInfoEntry.h +++ lib/DebugInfo/DWARFDebugInfoEntry.h @@ -20,7 +20,7 @@ class DWARFCompileUnit; class DWARFContext; class DWARFFormValue; -class DWARFInlinedSubroutineChain; +struct DWARFDebugInfoEntryInlinedChain; /// DWARFDebugInfoEntryMinimal - A DIE with only the minimum required data. class DWARFDebugInfoEntryMinimal { @@ -128,6 +128,10 @@ const uint16_t attr, const char *fail_value) const; + uint64_t getAttributeValueAsAddress(const DWARFCompileUnit *CU, + const uint16_t Attr, + uint64_t FailValue) const; + uint64_t getAttributeValueAsUnsigned(const DWARFCompileUnit *cu, const uint16_t attr, uint64_t fail_value) const; @@ -146,7 +150,8 @@ uint64_t &LowPC, uint64_t &HighPC) const; void buildAddressRangeTable(const DWARFCompileUnit *CU, - DWARFDebugAranges *DebugAranges) const; + DWARFDebugAranges *DebugAranges, + uint32_t CUOffsetInAranges) const; bool addressRangeContainsAddress(const DWARFCompileUnit *CU, const uint64_t Address) const; @@ -162,18 +167,23 @@ void getCallerFrame(const DWARFCompileUnit *CU, uint32_t &CallFile, uint32_t &CallLine, uint32_t &CallColumn) const; - /// InlinedChain - represents a chain of inlined_subroutine - /// DIEs, (possibly ending with subprogram DIE), all of which are contained - /// in some concrete inlined instance tree. Address range for each DIE - /// (except the last DIE) in this chain is contained in address - /// range for next DIE in the chain. - typedef SmallVector InlinedChain; - /// 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. - InlinedChain getInlinedChainForAddress(const DWARFCompileUnit *CU, - const uint64_t Address) const; + DWARFDebugInfoEntryInlinedChain + getInlinedChainForAddress(const DWARFCompileUnit *CU, + const uint64_t Address) const; +}; + +/// DWARFDebugInfoEntryInlinedChain - represents a chain of inlined_subroutine +/// DIEs, (possibly ending with subprogram DIE), all of which are contained +/// in some concrete inlined instance tree. Address range for each DIE +/// (except the last DIE) in this chain is contained in address +/// range for next DIE in the chain. +struct DWARFDebugInfoEntryInlinedChain { + DWARFDebugInfoEntryInlinedChain() : CU(0) {} + SmallVector DIEs; + const DWARFCompileUnit *CU; }; } Index: lib/DebugInfo/DWARFDebugInfoEntry.cpp =================================================================== --- lib/DebugInfo/DWARFDebugInfoEntry.cpp +++ lib/DebugInfo/DWARFDebugInfoEntry.cpp @@ -222,29 +222,30 @@ return 0; } -const char* -DWARFDebugInfoEntryMinimal::getAttributeValueAsString( - const DWARFCompileUnit* cu, - const uint16_t attr, - const char* fail_value) - const { - DWARFFormValue form_value; - if (getAttributeValue(cu, attr, form_value)) { - DataExtractor stringExtractor(cu->getStringSection(), false, 0); - return form_value.getAsCString(&stringExtractor); +const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString( + const DWARFCompileUnit *CU, const uint16_t Attr, + const char *FailValue) const { + DWARFFormValue FormValue; + if (getAttributeValue(CU, Attr, FormValue)) + return FormValue.getAsCString(CU); + return FailValue; +} + +uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress( + const DWARFCompileUnit *CU, const uint16_t Attr, uint64_t FailValue) const { + DWARFFormValue FormValue; + if (getAttributeValue(CU, Attr, FormValue)) + return FormValue.getAsAddress(CU); + return FailValue; +} + +uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned( + const DWARFCompileUnit *CU, const uint16_t Attr, uint64_t FailValue) const { + DWARFFormValue FormValue; + if (getAttributeValue(CU, Attr, FormValue)) { + return FormValue.getUnsigned(); } - return fail_value; -} - -uint64_t -DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned( - const DWARFCompileUnit* cu, - const uint16_t attr, - uint64_t fail_value) const { - DWARFFormValue form_value; - if (getAttributeValue(cu, attr, form_value)) - return form_value.getUnsigned(); - return fail_value; + return FailValue; } int64_t @@ -274,29 +275,29 @@ uint64_t &LowPC, uint64_t &HighPC) const { HighPC = -1ULL; - LowPC = getAttributeValueAsUnsigned(CU, DW_AT_low_pc, -1ULL); + LowPC = getAttributeValueAsAddress(CU, DW_AT_low_pc, -1ULL); if (LowPC != -1ULL) - HighPC = getAttributeValueAsUnsigned(CU, DW_AT_high_pc, -1ULL); + HighPC = getAttributeValueAsAddress(CU, DW_AT_high_pc, -1ULL); return (HighPC != -1ULL); } void DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *CU, - DWARFDebugAranges *DebugAranges) + DWARFDebugAranges *DebugAranges, + uint32_t CUOffsetInAranges) const { if (AbbrevDecl) { if (isSubprogramDIE()) { uint64_t LowPC, HighPC; - if (getLowAndHighPC(CU, LowPC, HighPC)) { - DebugAranges->appendRange(CU->getOffset(), LowPC, HighPC); - } + if (getLowAndHighPC(CU, LowPC, HighPC)) + DebugAranges->appendRange(CUOffsetInAranges, LowPC, HighPC); // FIXME: try to append ranges from .debug_ranges section. } - const DWARFDebugInfoEntryMinimal *child = getFirstChild(); - while (child) { - child->buildAddressRangeTable(CU, DebugAranges); - child = child->getSibling(); + const DWARFDebugInfoEntryMinimal *Child = getFirstChild(); + while (Child) { + Child->buildAddressRangeTable(CU, DebugAranges, CUOffsetInAranges); + Child = Child->getSibling(); } } } @@ -366,19 +367,18 @@ CallColumn = getAttributeValueAsUnsigned(CU, DW_AT_call_column, 0); } -DWARFDebugInfoEntryMinimal::InlinedChain +DWARFDebugInfoEntryInlinedChain DWARFDebugInfoEntryMinimal::getInlinedChainForAddress( - const DWARFCompileUnit *CU, - const uint64_t Address) - const { - DWARFDebugInfoEntryMinimal::InlinedChain InlinedChain; + const DWARFCompileUnit *CU, const uint64_t Address) const { + DWARFDebugInfoEntryInlinedChain InlinedChain; if (isNULL()) return InlinedChain; + InlinedChain.CU = CU; for (const DWARFDebugInfoEntryMinimal *DIE = this; 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); + InlinedChain.DIEs.push_back(*DIE); } // Try to get child which also contains provided address. const DWARFDebugInfoEntryMinimal *Child = DIE->getFirstChild(); @@ -392,6 +392,6 @@ DIE = Child; } // Reverse the obtained chain to make the root of inlined chain last. - std::reverse(InlinedChain.begin(), InlinedChain.end()); + std::reverse(InlinedChain.DIEs.begin(), InlinedChain.DIEs.end()); return InlinedChain; } Index: lib/DebugInfo/DWARFFormValue.cpp =================================================================== --- lib/DebugInfo/DWARFFormValue.cpp +++ lib/DebugInfo/DWARFFormValue.cpp @@ -183,10 +183,9 @@ Value.uval = data.getU64(offset_ptr); break; case DW_FORM_GNU_addr_index: - Value.uval = data.getULEB128(offset_ptr); - break; case DW_FORM_GNU_str_index: Value.uval = data.getULEB128(offset_ptr); + Value.IsDWOIndex = true; break; default: return false; @@ -322,12 +321,11 @@ switch (Form) { case DW_FORM_addr: OS << format("0x%016" PRIx64, uvalue); break; case DW_FORM_GNU_addr_index: { - StringRef AddrOffsetSec = cu->getAddrOffsetSection(); OS << format(" indexed (%8.8x) address = ", (uint32_t)uvalue); - if (AddrOffsetSec.size() != 0) { - DataExtractor DA(AddrOffsetSec, true, cu->getAddressByteSize()); - OS << format("0x%016" PRIx64, getIndirectAddress(&DA, cu)); - } else + uint64_t Address; + if (cu->getAddrOffsetSectionItem(uvalue, Address)) + OS << format("0x%016" PRIx64, Address); + else OS << ""; break; } @@ -376,7 +374,7 @@ case DW_FORM_udata: OS << getUnsigned(); break; case DW_FORM_strp: { OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue); - const char* dbg_str = getAsCString(&debug_str_data); + const char* dbg_str = getAsCString(cu); if (dbg_str) { OS << '"'; OS.write_escaped(dbg_str); @@ -386,8 +384,7 @@ } case DW_FORM_GNU_str_index: { OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue); - const char *dbg_str = getIndirectCString(&debug_str_data, - &debug_str_offset_data); + const char *dbg_str = getAsCString(cu); if (dbg_str) { OS << '"'; OS.write_escaped(dbg_str); @@ -440,33 +437,33 @@ } const char* -DWARFFormValue::getAsCString(const DataExtractor *debug_str_data_ptr) const { - if (isInlinedCStr()) { +DWARFFormValue::getAsCString(const DWARFCompileUnit *CU) const { + if (isInlinedCStr()) return Value.cstr; - } else if (debug_str_data_ptr) { - uint32_t offset = Value.uval; - return debug_str_data_ptr->getCStr(&offset); + if (!CU) + return NULL; + uint32_t Offset = Value.uval; + if (Value.IsDWOIndex) { + uint32_t StrOffset; + if (!CU->getStringOffsetSectionItem(Offset, StrOffset)) + return NULL; + Offset = StrOffset; } - return NULL; -} - -const char* -DWARFFormValue::getIndirectCString(const DataExtractor *DS, - const DataExtractor *DSO) const { - if (!DS || !DSO) return NULL; - - uint32_t offset = Value.uval * 4; - uint32_t soffset = DSO->getU32(&offset); - return DS->getCStr(&soffset); + return CU->getStringExtractor().getCStr(&Offset); } uint64_t -DWARFFormValue::getIndirectAddress(const DataExtractor *DA, - const DWARFCompileUnit *cu) const { - if (!DA) return 0; - - uint32_t offset = Value.uval * cu->getAddressByteSize(); - return DA->getAddress(&offset); +DWARFFormValue::getAsAddress(const DWARFCompileUnit *CU) const { + if (!CU) + return 0; + if (Value.IsDWOIndex) { + uint32_t Index = Value.uval; + uint64_t Address; + if (!CU->getAddrOffsetSectionItem(Index, Address)) + return 0; + return Address; + } + return Value.uval; } uint64_t DWARFFormValue::getReference(const DWARFCompileUnit *cu) const {