diff options
author | Alexander Kornienko <alexfh@google.com> | 2013-03-14 10:51:38 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2013-03-14 10:51:38 +0000 |
commit | 647735c781c5b37061ee03d6e9e6c7dda92218e2 (patch) | |
tree | 5a5e56606d41060263048b5a5586b3d2380898ba /lib/DebugInfo | |
parent | 6aed25d93d1cfcde5809a73ffa7dc1b0d6396f66 (diff) | |
parent | f635ef401786c84df32090251a8cf45981ecca33 (diff) |
Updating branches/google/stable to r176857
git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/google/stable@177040 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/DebugInfo')
-rw-r--r-- | lib/DebugInfo/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFAbbreviationDeclaration.cpp | 18 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFAbbreviationDeclaration.h | 10 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFCompileUnit.cpp | 15 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFCompileUnit.h | 27 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFContext.cpp | 313 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFContext.h | 86 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugFrame.cpp | 391 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugFrame.h | 46 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugInfoEntry.cpp | 30 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugLine.cpp | 92 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugLine.h | 8 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFFormValue.cpp | 91 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFFormValue.h | 4 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFRelocMap.h | 22 |
15 files changed, 1027 insertions, 127 deletions
diff --git a/lib/DebugInfo/CMakeLists.txt b/lib/DebugInfo/CMakeLists.txt index 1e9e509fd2..e97455abac 100644 --- a/lib/DebugInfo/CMakeLists.txt +++ b/lib/DebugInfo/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_library(LLVMDebugInfo DWARFDebugAbbrev.cpp DWARFDebugArangeSet.cpp DWARFDebugAranges.cpp + DWARFDebugFrame.cpp DWARFDebugInfoEntry.cpp DWARFDebugLine.cpp DWARFDebugRangeList.cpp diff --git a/lib/DebugInfo/DWARFAbbreviationDeclaration.cpp b/lib/DebugInfo/DWARFAbbreviationDeclaration.cpp index 0df692c3a3..2de62ab938 100644 --- a/lib/DebugInfo/DWARFAbbreviationDeclaration.cpp +++ b/lib/DebugInfo/DWARFAbbreviationDeclaration.cpp @@ -23,7 +23,7 @@ bool DWARFAbbreviationDeclaration::extract(DataExtractor data, uint32_t* offset_ptr, uint32_t code) { Code = code; - Attributes.clear(); + Attribute.clear(); if (Code) { Tag = data.getULEB128(offset_ptr); HasChildren = data.getU8(offset_ptr); @@ -33,7 +33,7 @@ DWARFAbbreviationDeclaration::extract(DataExtractor data, uint32_t* offset_ptr, uint16_t form = data.getULEB128(offset_ptr); if (attr && form) - Attributes.push_back(DWARFAttribute(attr, form)); + Attribute.push_back(DWARFAttribute(attr, form)); else break; } @@ -55,19 +55,19 @@ void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { else OS << format("DW_TAG_Unknown_%x", getTag()); OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n'; - for (unsigned i = 0, e = Attributes.size(); i != e; ++i) { + for (unsigned i = 0, e = Attribute.size(); i != e; ++i) { OS << '\t'; - const char *attrString = AttributeString(Attributes[i].getAttribute()); + const char *attrString = AttributeString(Attribute[i].getAttribute()); if (attrString) OS << attrString; else - OS << format("DW_AT_Unknown_%x", Attributes[i].getAttribute()); + OS << format("DW_AT_Unknown_%x", Attribute[i].getAttribute()); OS << '\t'; - const char *formString = FormEncodingString(Attributes[i].getForm()); + const char *formString = FormEncodingString(Attribute[i].getForm()); if (formString) OS << formString; else - OS << format("DW_FORM_Unknown_%x", Attributes[i].getForm()); + OS << format("DW_FORM_Unknown_%x", Attribute[i].getForm()); OS << '\n'; } OS << '\n'; @@ -75,8 +75,8 @@ void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { uint32_t DWARFAbbreviationDeclaration::findAttributeIndex(uint16_t attr) const { - for (uint32_t i = 0, e = Attributes.size(); i != e; ++i) { - if (Attributes[i].getAttribute() == attr) + for (uint32_t i = 0, e = Attribute.size(); i != e; ++i) { + if (Attribute[i].getAttribute() == attr) return i; } return -1U; diff --git a/lib/DebugInfo/DWARFAbbreviationDeclaration.h b/lib/DebugInfo/DWARFAbbreviationDeclaration.h index 2463a3cc04..9a3fcd8a78 100644 --- a/lib/DebugInfo/DWARFAbbreviationDeclaration.h +++ b/lib/DebugInfo/DWARFAbbreviationDeclaration.h @@ -22,7 +22,7 @@ class DWARFAbbreviationDeclaration { uint32_t Code; uint32_t Tag; bool HasChildren; - SmallVector<DWARFAttribute, 8> Attributes; + SmallVector<DWARFAttribute, 8> Attribute; public: enum { InvalidCode = 0 }; DWARFAbbreviationDeclaration() @@ -31,12 +31,12 @@ public: uint32_t getCode() const { return Code; } uint32_t getTag() const { return Tag; } bool hasChildren() const { return HasChildren; } - uint32_t getNumAttributes() const { return Attributes.size(); } + uint32_t getNumAttributes() const { return Attribute.size(); } uint16_t getAttrByIndex(uint32_t idx) const { - return Attributes.size() > idx ? Attributes[idx].getAttribute() : 0; + return Attribute.size() > idx ? Attribute[idx].getAttribute() : 0; } uint16_t getFormByIndex(uint32_t idx) const { - return Attributes.size() > idx ? Attributes[idx].getForm() : 0; + return Attribute.size() > idx ? Attribute[idx].getForm() : 0; } uint32_t findAttributeIndex(uint16_t attr) const; @@ -45,7 +45,7 @@ public: bool isValid() const { return Code != 0 && Tag != 0; } void dump(raw_ostream &OS) const; const SmallVectorImpl<DWARFAttribute> &getAttributes() const { - return Attributes; + return Attribute; } }; diff --git a/lib/DebugInfo/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARFCompileUnit.cpp index bdd65b77e4..e3e4ccd7d9 100644 --- a/lib/DebugInfo/DWARFCompileUnit.cpp +++ b/lib/DebugInfo/DWARFCompileUnit.cpp @@ -17,8 +17,7 @@ using namespace llvm; using namespace dwarf; DataExtractor DWARFCompileUnit::getDebugInfoExtractor() const { - return DataExtractor(Context.getInfoSection(), - Context.isLittleEndian(), getAddressByteSize()); + return DataExtractor(InfoSection, isLittleEndian, AddrSize); } bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { @@ -28,7 +27,6 @@ bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { if (debug_info.isValidOffset(*offset_ptr)) { uint64_t abbrOffset; - const DWARFDebugAbbrev *abbr = Context.getDebugAbbrev(); Length = debug_info.getU32(offset_ptr); Version = debug_info.getU16(offset_ptr); abbrOffset = debug_info.getU32(offset_ptr); @@ -36,11 +34,11 @@ bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { bool lengthOK = debug_info.isValidOffset(getNextCompileUnitOffset()-1); bool versionOK = DWARFContext::isSupportedVersion(Version); - bool abbrOffsetOK = Context.getAbbrevSection().size() > abbrOffset; + bool abbrOffsetOK = AbbrevSection.size() > abbrOffset; bool addrSizeOK = AddrSize == 4 || AddrSize == 8; - if (lengthOK && versionOK && addrSizeOK && abbrOffsetOK && abbr != NULL) { - Abbrevs = abbr->getAbbreviationDeclarationSet(abbrOffset); + if (lengthOK && versionOK && addrSizeOK && abbrOffsetOK && Abbrev != NULL) { + Abbrevs = Abbrev->getAbbreviationDeclarationSet(abbrOffset); return true; } @@ -79,8 +77,7 @@ bool DWARFCompileUnit::extractRangeList(uint32_t RangeListOffset, DWARFDebugRangeList &RangeList) const { // Require that compile unit is extracted. assert(DieArray.size() > 0); - DataExtractor RangesData(Context.getRangeSection(), - Context.isLittleEndian(), AddrSize); + DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize); return RangeList.extract(RangesData, &RangeListOffset); } @@ -211,7 +208,7 @@ size_t DWARFCompileUnit::extractDIEsIfNeeded(bool cu_die_only) { // should always terminate at or before the start of the next compilation // unit header). if (offset > next_cu_offset) - fprintf(stderr, "warning: DWARF compile unit extends beyond its" + fprintf(stderr, "warning: DWARF compile unit extends beyond its " "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), offset); setDIERelations(); diff --git a/lib/DebugInfo/DWARFCompileUnit.h b/lib/DebugInfo/DWARFCompileUnit.h index 03e28620d4..2a74605fcb 100644 --- a/lib/DebugInfo/DWARFCompileUnit.h +++ b/lib/DebugInfo/DWARFCompileUnit.h @@ -13,15 +13,25 @@ #include "DWARFDebugAbbrev.h" #include "DWARFDebugInfoEntry.h" #include "DWARFDebugRangeList.h" +#include "DWARFRelocMap.h" #include <vector> namespace llvm { -class DWARFContext; +class DWARFDebugAbbrev; +class StringRef; class raw_ostream; class DWARFCompileUnit { - DWARFContext &Context; + const DWARFDebugAbbrev *Abbrev; + StringRef InfoSection; + StringRef AbbrevSection; + StringRef RangeSection; + StringRef StringSection; + StringRef StringOffsetSection; + StringRef AddrOffsetSection; + const RelocAddrMap *RelocMap; + bool isLittleEndian; uint32_t Offset; uint32_t Length; @@ -32,11 +42,20 @@ class DWARFCompileUnit { // The compile unit debug information entry item. std::vector<DWARFDebugInfoEntryMinimal> DieArray; public: - DWARFCompileUnit(DWARFContext &context) : Context(context) { + + 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(); } - DWARFContext &getContext() const { return Context; } + StringRef getStringSection() const { return StringSection; } + StringRef getStringOffsetSection() const { return StringOffsetSection; } + StringRef getAddrOffsetSection() const { return AddrOffsetSection; } + const RelocAddrMap *getRelocMap() const { return RelocMap; } DataExtractor getDebugInfoExtractor() const; bool extract(DataExtractor debug_info, uint32_t* offset_ptr); diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp index 91ed2d22ab..9e19310a99 100644 --- a/lib/DebugInfo/DWARFContext.cpp +++ b/lib/DebugInfo/DWARFContext.cpp @@ -19,57 +19,124 @@ using namespace dwarf; typedef DWARFDebugLine::LineTable DWARFLineTable; -void DWARFContext::dump(raw_ostream &OS) { - OS << ".debug_abbrev contents:\n"; - getDebugAbbrev()->dump(OS); +void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { + if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { + OS << ".debug_abbrev contents:\n"; + getDebugAbbrev()->dump(OS); + } - OS << "\n.debug_info contents:\n"; - for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) - getCompileUnitAtIndex(i)->dump(OS); + if (DumpType == DIDT_All || DumpType == DIDT_Info) { + OS << "\n.debug_info contents:\n"; + for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) + getCompileUnitAtIndex(i)->dump(OS); + } + + if (DumpType == DIDT_All || DumpType == DIDT_Frames) { + OS << "\n.debug_frame contents:\n"; + getDebugFrame()->dump(OS); + } - OS << "\n.debug_aranges contents:\n"; - DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0); uint32_t offset = 0; - DWARFDebugArangeSet set; - while (set.extract(arangesData, &offset)) - set.dump(OS); + if (DumpType == DIDT_All || DumpType == DIDT_Aranges) { + OS << "\n.debug_aranges contents:\n"; + DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0); + DWARFDebugArangeSet set; + while (set.extract(arangesData, &offset)) + set.dump(OS); + } uint8_t savedAddressByteSize = 0; - OS << "\n.debug_line contents:\n"; - for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) { - DWARFCompileUnit *cu = getCompileUnitAtIndex(i); - savedAddressByteSize = cu->getAddressByteSize(); - unsigned stmtOffset = - cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list, - -1U); - if (stmtOffset != -1U) { - DataExtractor lineData(getLineSection(), isLittleEndian(), + if (DumpType == DIDT_All || DumpType == DIDT_Line) { + OS << "\n.debug_line contents:\n"; + for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) { + DWARFCompileUnit *cu = getCompileUnitAtIndex(i); + savedAddressByteSize = cu->getAddressByteSize(); + unsigned stmtOffset = + cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list, + -1U); + if (stmtOffset != -1U) { + DataExtractor lineData(getLineSection(), isLittleEndian(), + savedAddressByteSize); + DWARFDebugLine::DumpingState state(OS); + DWARFDebugLine::parseStatementTable(lineData, &lineRelocMap(), &stmtOffset, state); + } + } + } + + if (DumpType == DIDT_All || DumpType == DIDT_Str) { + OS << "\n.debug_str contents:\n"; + DataExtractor strData(getStringSection(), isLittleEndian(), 0); + offset = 0; + uint32_t strOffset = 0; + while (const char *s = strData.getCStr(&offset)) { + OS << format("0x%8.8x: \"%s\"\n", strOffset, s); + strOffset = offset; + } + } + + if (DumpType == DIDT_All || DumpType == DIDT_Ranges) { + OS << "\n.debug_ranges contents:\n"; + // In fact, different compile units may have different address byte + // sizes, but for simplicity we just use the address byte size of the last + // compile unit (there is no easy and fast way to associate address range + // list and the compile unit it describes). + DataExtractor rangesData(getRangeSection(), isLittleEndian(), savedAddressByteSize); - DWARFDebugLine::DumpingState state(OS); - DWARFDebugLine::parseStatementTable(lineData, &stmtOffset, state); + offset = 0; + DWARFDebugRangeList rangeList; + while (rangeList.extract(rangesData, &offset)) + rangeList.dump(OS); + } + + if (DumpType == DIDT_All || DumpType == DIDT_Pubnames) { + OS << "\n.debug_pubnames contents:\n"; + DataExtractor pubNames(getPubNamesSection(), isLittleEndian(), 0); + offset = 0; + OS << "Length: " << pubNames.getU32(&offset) << "\n"; + OS << "Version: " << pubNames.getU16(&offset) << "\n"; + OS << "Offset in .debug_info: " << pubNames.getU32(&offset) << "\n"; + OS << "Size: " << pubNames.getU32(&offset) << "\n"; + OS << "\n Offset Name\n"; + while (offset < getPubNamesSection().size()) { + uint32_t n = pubNames.getU32(&offset); + if (n == 0) + break; + OS << format("%8x ", n); + OS << pubNames.getCStr(&offset) << "\n"; } } - OS << "\n.debug_str contents:\n"; - DataExtractor strData(getStringSection(), isLittleEndian(), 0); - offset = 0; - uint32_t lastOffset = 0; - while (const char *s = strData.getCStr(&offset)) { - OS << format("0x%8.8x: \"%s\"\n", lastOffset, s); - lastOffset = offset; + if (DumpType == DIDT_All || DumpType == DIDT_AbbrevDwo) { + OS << "\n.debug_abbrev.dwo contents:\n"; + getDebugAbbrevDWO()->dump(OS); + } + + if (DumpType == DIDT_All || DumpType == DIDT_InfoDwo) { + OS << "\n.debug_info.dwo contents:\n"; + for (unsigned i = 0, e = getNumDWOCompileUnits(); i != e; ++i) + getDWOCompileUnitAtIndex(i)->dump(OS); } - OS << "\n.debug_ranges contents:\n"; - // In fact, different compile units may have different address byte - // sizes, but for simplicity we just use the address byte size of the last - // compile unit (there is no easy and fast way to associate address range - // list and the compile unit it describes). - DataExtractor rangesData(getRangeSection(), isLittleEndian(), - savedAddressByteSize); - offset = 0; - DWARFDebugRangeList rangeList; - while (rangeList.extract(rangesData, &offset)) - rangeList.dump(OS); + if (DumpType == DIDT_All || DumpType == DIDT_StrDwo) { + OS << "\n.debug_str.dwo contents:\n"; + DataExtractor strDWOData(getStringDWOSection(), isLittleEndian(), 0); + offset = 0; + uint32_t strDWOOffset = 0; + while (const char *s = strDWOData.getCStr(&offset)) { + OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s); + strDWOOffset = offset; + } + } + + if (DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) { + OS << "\n.debug_str_offsets.dwo contents:\n"; + DataExtractor strOffsetExt(getStringOffsetDWOSection(), isLittleEndian(), 0); + offset = 0; + while (offset < getStringOffsetDWOSection().size()) { + OS << format("0x%8.8x: ", offset); + OS << format("%8.8x\n", strOffsetExt.getU32(&offset)); + } + } } const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { @@ -83,6 +150,16 @@ const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { return Abbrev.get(); } +const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() { + if (AbbrevDWO) + return AbbrevDWO.get(); + + DataExtractor abbrData(getAbbrevDWOSection(), isLittleEndian(), 0); + AbbrevDWO.reset(new DWARFDebugAbbrev()); + AbbrevDWO->parse(abbrData); + return AbbrevDWO.get(); +} + const DWARFDebugAranges *DWARFContext::getDebugAranges() { if (Aranges) return Aranges.get(); @@ -98,10 +175,30 @@ const DWARFDebugAranges *DWARFContext::getDebugAranges() { return Aranges.get(); } +const DWARFDebugFrame *DWARFContext::getDebugFrame() { + if (DebugFrame) + return DebugFrame.get(); + + // There's a "bug" in the DWARFv3 standard with respect to the target address + // size within debug frame sections. While DWARF is supposed to be independent + // of its container, FDEs have fields with size being "target address size", + // which isn't specified in DWARF in general. It's only specified for CUs, but + // .eh_frame can appear without a .debug_info section. Follow the example of + // other tools (libdwarf) and extract this from the container (ObjectFile + // provides this information). This problem is fixed in DWARFv4 + // See this dwarf-discuss discussion for more details: + // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html + DataExtractor debugFrameData(getDebugFrameSection(), isLittleEndian(), + getAddressSize()); + DebugFrame.reset(new DWARFDebugFrame()); + DebugFrame->parse(debugFrameData); + return DebugFrame.get(); +} + const DWARFLineTable * DWARFContext::getLineTableForCompileUnit(DWARFCompileUnit *cu) { if (!Line) - Line.reset(new DWARFDebugLine()); + Line.reset(new DWARFDebugLine(&lineRelocMap())); unsigned stmtOffset = cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list, @@ -124,7 +221,12 @@ void DWARFContext::parseCompileUnits() { const DataExtractor &DIData = DataExtractor(getInfoSection(), isLittleEndian(), 0); while (DIData.isValidOffset(offset)) { - CUs.push_back(DWARFCompileUnit(*this)); + CUs.push_back(DWARFCompileUnit(getDebugAbbrev(), getInfoSection(), + getAbbrevSection(), getRangeSection(), + getStringSection(), StringRef(), + getAddrSection(), + &infoRelocMap(), + isLittleEndian())); if (!CUs.back().extract(DIData, &offset)) { CUs.pop_back(); break; @@ -134,6 +236,28 @@ void DWARFContext::parseCompileUnits() { } } +void DWARFContext::parseDWOCompileUnits() { + uint32_t offset = 0; + 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(); + break; + } + + offset = DWOCUs.back().getNextCompileUnitOffset(); + } +} + namespace { struct OffsetComparator { bool operator()(const DWARFCompileUnit &LHS, @@ -244,6 +368,64 @@ DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, Line, Column); } +DILineInfoTable DWARFContext::getLineInfoForAddressRange(uint64_t Address, + uint64_t Size, + DILineInfoSpecifier Specifier) { + DILineInfoTable Lines; + DWARFCompileUnit *CU = getCompileUnitForAddress(Address); + if (!CU) + return Lines; + + std::string FunctionName = "<invalid>"; + if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { + // 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 = + CU->getInlinedChainForAddress(Address); + if (InlinedChain.size() > 0) { + const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0]; + if (const char *Name = TopFunctionDIE.getSubroutineName(CU)) + FunctionName = Name; + } + } + + StringRef FuncNameRef = StringRef(FunctionName); + + // 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("<invalid>"), + FuncNameRef, 0, 0))); + return Lines; + } + + const DWARFLineTable *LineTable = getLineTableForCompileUnit(CU); + const bool NeedsAbsoluteFilePath = + Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); + + // Get the index of row we're looking for in the line table. + std::vector<uint32_t> RowVector; + if (!LineTable->lookupAddressRange(Address, Size, RowVector)) + return Lines; + + uint32_t NumRows = RowVector.size(); + for (uint32_t i = 0; i < NumRows; ++i) { + uint32_t RowIndex = RowVector[i]; + // Take file number and line/column from the row. + const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; + std::string FileName = "<invalid>"; + getFileNameForCompileUnit(CU, LineTable, Row.File, + NeedsAbsoluteFilePath, FileName); + Lines.push_back(std::make_pair(Row.Address, + DILineInfo(StringRef(FileName), + FuncNameRef, Row.Line, Row.Column))); + } + + return Lines; +} + DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { DWARFCompileUnit *CU = getCompileUnitForAddress(Address); @@ -301,7 +483,8 @@ DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, } DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : - IsLittleEndian(true /* FIXME */) { + IsLittleEndian(Obj->isLittleEndian()), + AddressSize(Obj->getBytesInAddress()) { error_code ec; for (object::section_iterator i = Obj->begin_sections(), e = Obj->end_sections(); @@ -311,8 +494,6 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : StringRef data; i->getContents(data); - if (name.startswith("__DWARF,")) - name = name.substr(8); // Skip "__DWARF," prefix. name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. if (name == "debug_info") InfoSection = data; @@ -322,16 +503,41 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : LineSection = data; else if (name == "debug_aranges") ARangeSection = data; + else if (name == "debug_frame") + DebugFrameSection = data; else if (name == "debug_str") StringSection = data; - else if (name == "debug_ranges") + else if (name == "debug_ranges") { + // FIXME: Use the other dwo range section when we emit it. + RangeDWOSection = data; RangeSection = data; + } + else if (name == "debug_pubnames") + PubNamesSection = data; + else if (name == "debug_info.dwo") + InfoDWOSection = data; + else if (name == "debug_abbrev.dwo") + AbbrevDWOSection = data; + else if (name == "debug_str.dwo") + StringDWOSection = data; + else if (name == "debug_str_offsets.dwo") + StringOffsetDWOSection = data; + else if (name == "debug_addr") + AddrSection = data; // Any more debug info sections go here. else continue; - // TODO: For now only handle relocations for the debug_info section. - if (name != "debug_info") + // TODO: Add support for relocations in other sections as needed. + // Record relocations for the debug_info and debug_line sections. + RelocAddrMap *Map; + if (name == "debug_info") + Map = &InfoRelocMap; + else if (name == "debug_info.dwo") + Map = &InfoDWORelocMap; + else if (name == "debug_line") + Map = &LineRelocMap; + else continue; if (i->begin_relocations() != i->end_relocations()) { @@ -344,10 +550,17 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : reloc_i->getAddress(Address); uint64_t Type; reloc_i->getType(Type); + uint64_t SymAddr = 0; + // ELF relocations may need the symbol address + if (Obj->isELF()) { + object::SymbolRef Sym; + reloc_i->getSymbol(Sym); + Sym.getAddress(SymAddr); + } object::RelocVisitor V(Obj->getFileFormatName()); // The section address is always 0 for debug sections. - object::RelocToApply R(V.visit(Type, *reloc_i)); + object::RelocToApply R(V.visit(Type, *reloc_i, 0, SymAddr)); if (V.error()) { SmallString<32> Name; error_code ec(reloc_i->getTypeName(Name)); @@ -374,7 +587,7 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : << " at " << format("%p", Address) << " with width " << format("%d", R.Width) << "\n"); - RelocMap[Address] = std::make_pair(R.Width, R.Value); + Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value))); } } } diff --git a/lib/DebugInfo/DWARFContext.h b/lib/DebugInfo/DWARFContext.h index 24613594de..37b272993f 100644 --- a/lib/DebugInfo/DWARFContext.h +++ b/lib/DebugInfo/DWARFContext.h @@ -12,6 +12,7 @@ #include "DWARFCompileUnit.h" #include "DWARFDebugAranges.h" +#include "DWARFDebugFrame.h" #include "DWARFDebugLine.h" #include "DWARFDebugRangeList.h" #include "llvm/ADT/OwningPtr.h" @@ -29,6 +30,10 @@ class DWARFContext : public DIContext { OwningPtr<DWARFDebugAbbrev> Abbrev; OwningPtr<DWARFDebugAranges> Aranges; OwningPtr<DWARFDebugLine> Line; + OwningPtr<DWARFDebugFrame> DebugFrame; + + SmallVector<DWARFCompileUnit, 1> DWOCUs; + OwningPtr<DWARFDebugAbbrev> AbbrevDWO; DWARFContext(DWARFContext &) LLVM_DELETED_FUNCTION; DWARFContext &operator=(DWARFContext &) LLVM_DELETED_FUNCTION; @@ -36,9 +41,13 @@ class DWARFContext : public DIContext { /// Read compile units from the debug_info section and store them in CUs. void parseCompileUnits(); + /// Read compile units from the debug_info.dwo section and store them in + /// DWOCUs. + void parseDWOCompileUnits(); + public: DWARFContext() {} - virtual void dump(raw_ostream &OS); + virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All); /// Get the number of compile units in this context. unsigned getNumCompileUnits() { @@ -46,6 +55,14 @@ public: parseCompileUnits(); return CUs.size(); } + + /// Get the number of compile units in the DWO context. + unsigned getNumDWOCompileUnits() { + if (DWOCUs.empty()) + parseDWOCompileUnits(); + return DWOCUs.size(); + } + /// Get the compile unit at the specified index for this compile unit. DWARFCompileUnit *getCompileUnitAtIndex(unsigned index) { if (CUs.empty()) @@ -53,29 +70,57 @@ public: 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]; + } + /// Get a pointer to the parsed DebugAbbrev object. const DWARFDebugAbbrev *getDebugAbbrev(); + /// Get a pointer to the parsed dwo abbreviations object. + const DWARFDebugAbbrev *getDebugAbbrevDWO(); + /// Get a pointer to the parsed DebugAranges object. const DWARFDebugAranges *getDebugAranges(); + /// Get a pointer to the parsed frame information object. + const DWARFDebugFrame *getDebugFrame(); + /// Get a pointer to a parsed line table corresponding to a compile unit. const DWARFDebugLine::LineTable * getLineTableForCompileUnit(DWARFCompileUnit *cu); virtual DILineInfo getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()); + virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address, + uint64_t Size, DILineInfoSpecifier Specifier = DILineInfoSpecifier()); virtual DIInliningInfo getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()); virtual bool isLittleEndian() const = 0; - virtual const RelocAddrMap &relocMap() const = 0; + virtual uint8_t getAddressSize() const = 0; + virtual const RelocAddrMap &infoRelocMap() const = 0; + virtual const RelocAddrMap &lineRelocMap() const = 0; virtual StringRef getInfoSection() = 0; virtual StringRef getAbbrevSection() = 0; virtual StringRef getARangeSection() = 0; + virtual StringRef getDebugFrameSection() = 0; virtual StringRef getLineSection() = 0; virtual StringRef getStringSection() = 0; virtual StringRef getRangeSection() = 0; + virtual StringRef getPubNamesSection() = 0; + + // Sections for DWARF5 split dwarf proposal. + virtual StringRef getInfoDWOSection() = 0; + virtual StringRef getAbbrevDWOSection() = 0; + virtual StringRef getStringDWOSection() = 0; + virtual StringRef getStringOffsetDWOSection() = 0; + virtual StringRef getRangeDWOSection() = 0; + virtual StringRef getAddrSection() = 0; + virtual const RelocAddrMap &infoDWORelocMap() const = 0; static bool isSupportedVersion(unsigned version) { return version == 2 || version == 3; @@ -95,23 +140,56 @@ private: class DWARFContextInMemory : public DWARFContext { virtual void anchor(); bool IsLittleEndian; - RelocAddrMap RelocMap; + uint8_t AddressSize; + RelocAddrMap InfoRelocMap; + RelocAddrMap LineRelocMap; StringRef InfoSection; StringRef AbbrevSection; StringRef ARangeSection; + StringRef DebugFrameSection; StringRef LineSection; StringRef StringSection; StringRef RangeSection; + StringRef PubNamesSection; + + // Sections for DWARF5 split dwarf proposal. + RelocAddrMap InfoDWORelocMap; + StringRef InfoDWOSection; + StringRef AbbrevDWOSection; + StringRef StringDWOSection; + StringRef StringOffsetDWOSection; + StringRef RangeDWOSection; + StringRef AddrSection; + public: DWARFContextInMemory(object::ObjectFile *); virtual bool isLittleEndian() const { return IsLittleEndian; } - virtual const RelocAddrMap &relocMap() const { return RelocMap; } + virtual uint8_t getAddressSize() const { return AddressSize; } + virtual const RelocAddrMap &infoRelocMap() const { return InfoRelocMap; } + virtual const RelocAddrMap &lineRelocMap() const { return LineRelocMap; } virtual StringRef getInfoSection() { return InfoSection; } virtual StringRef getAbbrevSection() { return AbbrevSection; } virtual StringRef getARangeSection() { return ARangeSection; } + virtual StringRef getDebugFrameSection() { return DebugFrameSection; } virtual StringRef getLineSection() { return LineSection; } virtual StringRef getStringSection() { return StringSection; } virtual StringRef getRangeSection() { return RangeSection; } + virtual StringRef getPubNamesSection() { return PubNamesSection; } + + // Sections for DWARF5 split dwarf proposal. + virtual StringRef getInfoDWOSection() { return InfoDWOSection; } + virtual StringRef getAbbrevDWOSection() { return AbbrevDWOSection; } + virtual StringRef getStringDWOSection() { return StringDWOSection; } + virtual StringRef getStringOffsetDWOSection() { + return StringOffsetDWOSection; + } + virtual StringRef getRangeDWOSection() { return RangeDWOSection; } + virtual StringRef getAddrSection() { + return AddrSection; + } + virtual const RelocAddrMap &infoDWORelocMap() const { + return InfoDWORelocMap; + } }; } diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp new file mode 100644 index 0000000000..3efe6a1ebd --- /dev/null +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -0,0 +1,391 @@ +//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugFrame.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <string> +#include <vector> + +using namespace llvm; +using namespace dwarf; + + +/// \brief Abstract frame entry defining the common interface concrete +/// entries implement. +class llvm::FrameEntry { +public: + enum FrameKind {FK_CIE, FK_FDE}; + FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length) + : Kind(K), Data(D), Offset(Offset), Length(Length) {} + + virtual ~FrameEntry() { + } + + FrameKind getKind() const { return Kind; } + virtual uint64_t getOffset() const { return Offset; } + + /// \brief Parse and store a sequence of CFI instructions from our data + /// stream, starting at *Offset and ending at EndOffset. If everything + /// goes well, *Offset should be equal to EndOffset when this method + /// returns. Otherwise, an error occurred. + virtual void parseInstructions(uint32_t *Offset, uint32_t EndOffset); + + /// \brief Dump the entry header to the given output stream. + virtual void dumpHeader(raw_ostream &OS) const = 0; + + /// \brief Dump the entry's instructions to the given output stream. + virtual void dumpInstructions(raw_ostream &OS) const; + +protected: + const FrameKind Kind; + + /// \brief The data stream holding the section from which the entry was + /// parsed. + DataExtractor Data; + + /// \brief Offset of this entry in the section. + uint64_t Offset; + + /// \brief Entry length as specified in DWARF. + uint64_t Length; + + /// An entry may contain CFI instructions. An instruction consists of an + /// opcode and an optional sequence of operands. + typedef std::vector<uint64_t> Operands; + struct Instruction { + Instruction(uint8_t Opcode) + : Opcode(Opcode) + {} + + uint8_t Opcode; + Operands Ops; + }; + + std::vector<Instruction> Instructions; + + /// Convenience methods to add a new instruction with the given opcode and + /// operands to the Instructions vector. + void addInstruction(uint8_t Opcode) { + Instructions.push_back(Instruction(Opcode)); + } + + void addInstruction(uint8_t Opcode, uint64_t Operand1) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + } + + void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + Instructions.back().Ops.push_back(Operand2); + } +}; + + +// See DWARF standard v3, section 7.23 +const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; +const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; + + +void FrameEntry::parseInstructions(uint32_t *Offset, uint32_t EndOffset) { + while (*Offset < EndOffset) { + uint8_t Opcode = Data.getU8(Offset); + // Some instructions have a primary opcode encoded in the top bits. + uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK; + + if (Primary) { + // If it's a primary opcode, the first operand is encoded in the bottom + // bits of the opcode itself. + uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; + switch (Primary) { + default: llvm_unreachable("Impossible primary CFI opcode"); + case DW_CFA_advance_loc: + case DW_CFA_restore: + addInstruction(Primary, Op1); + break; + case DW_CFA_offset: + addInstruction(Primary, Op1, Data.getULEB128(Offset)); + break; + } + } else { + // Extended opcode - its value is Opcode itself. + switch (Opcode) { + default: llvm_unreachable("Invalid extended CFI opcode"); + case DW_CFA_nop: + case DW_CFA_remember_state: + case DW_CFA_restore_state: + // No operands + addInstruction(Opcode); + break; + case DW_CFA_set_loc: + // Operands: Address + addInstruction(Opcode, Data.getAddress(Offset)); + break; + case DW_CFA_advance_loc1: + // Operands: 1-byte delta + addInstruction(Opcode, Data.getU8(Offset)); + break; + case DW_CFA_advance_loc2: + // Operands: 2-byte delta + addInstruction(Opcode, Data.getU16(Offset)); + break; + case DW_CFA_advance_loc4: + // Operands: 4-byte delta + addInstruction(Opcode, Data.getU32(Offset)); + break; + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + case DW_CFA_def_cfa_register: + case DW_CFA_def_cfa_offset: + // Operands: ULEB128 + addInstruction(Opcode, Data.getULEB128(Offset)); + break; + case DW_CFA_def_cfa_offset_sf: + // Operands: SLEB128 + addInstruction(Opcode, Data.getSLEB128(Offset)); + break; + case DW_CFA_offset_extended: + case DW_CFA_register: + case DW_CFA_def_cfa: + case DW_CFA_val_offset: + // Operands: ULEB128, ULEB128 + addInstruction(Opcode, Data.getULEB128(Offset), + Data.getULEB128(Offset)); + break; + case DW_CFA_offset_extended_sf: + case DW_CFA_def_cfa_sf: + case DW_CFA_val_offset_sf: + // Operands: ULEB128, SLEB128 + addInstruction(Opcode, Data.getULEB128(Offset), + Data.getSLEB128(Offset)); + break; + case DW_CFA_def_cfa_expression: + case DW_CFA_expression: + case DW_CFA_val_expression: + // TODO: implement this + report_fatal_error("Values with expressions not implemented yet!"); + } + } + } +} + + +void FrameEntry::dumpInstructions(raw_ostream &OS) const { + // TODO: at the moment only instruction names are dumped. Expand this to + // dump operands as well. + for (std::vector<Instruction>::const_iterator I = Instructions.begin(), + E = Instructions.end(); + I != E; ++I) { + uint8_t Opcode = I->Opcode; + if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) + Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK; + OS << " " << CallFrameString(Opcode) << ":\n"; + } +} + + +namespace { +/// \brief DWARF Common Information Entry (CIE) +class CIE : public FrameEntry { +public: + // CIEs (and FDEs) are simply container classes, so the only sensible way to + // create them is by providing the full parsed contents in the constructor. + CIE(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version, + SmallString<8> Augmentation, uint64_t CodeAlignmentFactor, + int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister) + : FrameEntry(FK_CIE, D, Offset, Length), Version(Version), + Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor), + ReturnAddressRegister(ReturnAddressRegister) {} + + ~CIE() { + } + + void dumpHeader(raw_ostream &OS) const { + OS << format("%08x %08x %08x CIE", + (uint32_t)Offset, (uint32_t)Length, DW_CIE_ID) + << "\n"; + OS << format(" Version: %d\n", Version); + OS << " Augmentation: \"" << Augmentation << "\"\n"; + OS << format(" Code alignment factor: %u\n", + (uint32_t)CodeAlignmentFactor); + OS << format(" Data alignment factor: %d\n", + (int32_t)DataAlignmentFactor); + OS << format(" Return address column: %d\n", + (int32_t)ReturnAddressRegister); + OS << "\n"; + } + + static bool classof(const FrameEntry *FE) { + return FE->getKind() == FK_CIE; + } + +private: + /// The following fields are defined in section 6.4.1 of the DWARF standard v3 + uint8_t Version; + SmallString<8> Augmentation; + uint64_t CodeAlignmentFactor; + int64_t DataAlignmentFactor; + uint64_t ReturnAddressRegister; +}; + + +/// \brief DWARF Frame Description Entry (FDE) +class FDE : public FrameEntry { +public: + // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with + // an offset to the CIE (provided by parsing the FDE header). The CIE itself + // is obtained lazily once it's actually required. + FDE(DataExtractor D, uint64_t Offset, uint64_t Length, + int64_t LinkedCIEOffset, uint64_t InitialLocation, uint64_t AddressRange) + : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset), + InitialLocation(InitialLocation), AddressRange(AddressRange), + LinkedCIE(NULL) {} + + ~FDE() { + } + + void dumpHeader(raw_ostream &OS) const { + OS << format("%08x %08x %08x FDE ", + (uint32_t)Offset, (uint32_t)Length, (int32_t)LinkedCIEOffset); + OS << format("cie=%08x pc=%08x...%08x\n", + (int32_t)LinkedCIEOffset, + (uint32_t)InitialLocation, + (uint32_t)InitialLocation + (uint32_t)AddressRange); + if (LinkedCIE) { + OS << format("%p\n", LinkedCIE); + } + } + + static bool classof(const FrameEntry *FE) { + return FE->getKind() == FK_FDE; + } +private: + + /// The following fields are defined in section 6.4.1 of the DWARF standard v3 + uint64_t LinkedCIEOffset; + uint64_t InitialLocation; + uint64_t AddressRange; + CIE *LinkedCIE; +}; +} // end anonymous namespace + + +DWARFDebugFrame::DWARFDebugFrame() { +} + + +DWARFDebugFrame::~DWARFDebugFrame() { + for (EntryVector::iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + delete *I; + } +} + + +static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data, + uint32_t Offset, int Length) { + errs() << "DUMP: "; + for (int i = 0; i < Length; ++i) { + uint8_t c = Data.getU8(&Offset); + errs().write_hex(c); errs() << " "; + } + errs() << "\n"; +} + + +void DWARFDebugFrame::parse(DataExtractor Data) { + uint32_t Offset = 0; + + while (Data.isValidOffset(Offset)) { + uint32_t StartOffset = Offset; + + bool IsDWARF64 = false; + uint64_t Length = Data.getU32(&Offset); + uint64_t Id; + + if (Length == UINT32_MAX) { + // DWARF-64 is distinguished by the first 32 bits of the initial length + // field being 0xffffffff. Then, the next 64 bits are the actual entry + // length. + IsDWARF64 = true; + Length = Data.getU64(&Offset); + } + + // At this point, Offset points to the next field after Length. + // Length is the structure size excluding itself. Compute an offset one + // past the end of the structure (needed to know how many instructions to + // read). + // TODO: For honest DWARF64 support, DataExtractor will have to treat + // offset_ptr as uint64_t* + uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length); + + // The Id field's size depends on the DWARF format + Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4); + bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID); + + FrameEntry *Entry = 0; + if (IsCIE) { + // Note: this is specifically DWARFv3 CIE header structure. It was + // changed in DWARFv4. We currently don't support reading DWARFv4 + // here because LLVM itself does not emit it (and LLDB doesn't + // support it either). + uint8_t Version = Data.getU8(&Offset); + const char *Augmentation = Data.getCStr(&Offset); + uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); + int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); + uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); + + Entry = new CIE(Data, StartOffset, Length, Version, + StringRef(Augmentation), CodeAlignmentFactor, + DataAlignmentFactor, ReturnAddressRegister); + } else { + // FDE + uint64_t CIEPointer = Id; + uint64_t InitialLocation = Data.getAddress(&Offset); + uint64_t AddressRange = Data.getAddress(&Offset); + + Entry = new FDE(Data, StartOffset, Length, CIEPointer, + InitialLocation, AddressRange); + } + + assert(Entry && "Expected Entry to be populated with CIE or FDE"); + Entry->parseInstructions(&Offset, EndStructureOffset); + + if (Offset == EndStructureOffset) { + // Entry instrucitons parsed successfully. + Entries.push_back(Entry); + } else { + std::string Str; + raw_string_ostream OS(Str); + OS << format("Parsing entry instructions at %lx failed", + Entry->getOffset()); + report_fatal_error(Str); + } + } +} + + +void DWARFDebugFrame::dump(raw_ostream &OS) const { + OS << "\n"; + for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + FrameEntry *Entry = *I; + Entry->dumpHeader(OS); + Entry->dumpInstructions(OS); + OS << "\n"; + } +} + diff --git a/lib/DebugInfo/DWARFDebugFrame.h b/lib/DebugInfo/DWARFDebugFrame.h new file mode 100644 index 0000000000..48b8d63a5a --- /dev/null +++ b/lib/DebugInfo/DWARFDebugFrame.h @@ -0,0 +1,46 @@ +//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- 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_DWARFDEBUGFRAME_H +#define LLVM_DEBUGINFO_DWARFDEBUGFRAME_H + +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> + + +namespace llvm { + +class FrameEntry; + + +/// \brief A parsed .debug_frame section +/// +class DWARFDebugFrame { +public: + DWARFDebugFrame(); + ~DWARFDebugFrame(); + + /// \brief Dump the section data into the given stream. + void dump(raw_ostream &OS) const; + + /// \brief Parse the section from raw data. + /// data is assumed to be pointing to the beginning of the section. + void parse(DataExtractor Data); + +private: + typedef std::vector<FrameEntry *> EntryVector; + EntryVector Entries; +}; + + +} // namespace llvm + +#endif + diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARFDebugInfoEntry.cpp index ab67464453..02b15d6904 100644 --- a/lib/DebugInfo/DWARFDebugInfoEntry.cpp +++ b/lib/DebugInfo/DWARFDebugInfoEntry.cpp @@ -12,6 +12,7 @@ #include "DWARFContext.h" #include "DWARFDebugAbbrev.h" #include "DWARFFormValue.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -39,7 +40,7 @@ void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, OS << format(" [%u] %c\n", abbrCode, AbbrevDecl->hasChildren() ? '*' : ' '); - // Dump all data in the .debug_info for the attributes + // Dump all data in the DIE for the attributes. const uint32_t numAttributes = AbbrevDecl->getNumAttributes(); for (uint32_t i = 0; i != numAttributes; ++i) { uint16_t attr = AbbrevDecl->getAttrByIndex(i); @@ -113,9 +114,14 @@ bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *cu, uint32_t i; uint16_t form; for (i=0; i<numAttributes; ++i) { + form = AbbrevDecl->getFormByIndex(i); - const uint8_t fixed_skip_size = fixed_form_sizes[form]; + // FIXME: Currently we're checking if this is less than the last + // entry in the fixed_form_sizes table, but this should be changed + // to use dynamic dispatch. + const uint8_t fixed_skip_size = (form < DW_FORM_ref_sig8) ? + fixed_form_sizes[form] : 0; if (fixed_skip_size) offset += fixed_skip_size; else { @@ -187,6 +193,8 @@ bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *cu, case DW_FORM_sdata: case DW_FORM_udata: case DW_FORM_ref_udata: + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_addr_index: debug_info_data.getULEB128(&offset); break; @@ -195,11 +203,9 @@ bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *cu, form = debug_info_data.getULEB128(&offset); break; + // FIXME: 64-bit for DWARF64 case DW_FORM_sec_offset: - if (cu->getAddressByteSize() == 4) - debug_info_data.getU32(offset_ptr); - else - debug_info_data.getU64(offset_ptr); + debug_info_data.getU32(offset_ptr); break; default: @@ -207,7 +213,6 @@ bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *cu, return false; } offset += form_size; - } while (form_is_indirect); } } @@ -327,6 +332,8 @@ DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *cu, case DW_FORM_sdata: case DW_FORM_udata: case DW_FORM_ref_udata: + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_addr_index: debug_info_data.getULEB128(&offset); break; @@ -335,11 +342,9 @@ DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *cu, form_is_indirect = true; break; + // FIXME: 64-bit for DWARF64. case DW_FORM_sec_offset: - if (cu->getAddressByteSize() == 4) - debug_info_data.getU32(offset_ptr); - else - debug_info_data.getU64(offset_ptr); + debug_info_data.getU32(offset_ptr); break; default: @@ -417,8 +422,7 @@ DWARFDebugInfoEntryMinimal::getAttributeValueAsString( const { DWARFFormValue form_value; if (getAttributeValue(cu, attr, form_value)) { - DataExtractor stringExtractor(cu->getContext().getStringSection(), - false, 0); + DataExtractor stringExtractor(cu->getStringSection(), false, 0); return form_value.getAsCString(&stringExtractor); } return fail_value; diff --git a/lib/DebugInfo/DWARFDebugLine.cpp b/lib/DebugInfo/DWARFDebugLine.cpp index 267364adfa..192381c6f7 100644 --- a/lib/DebugInfo/DWARFDebugLine.cpp +++ b/lib/DebugInfo/DWARFDebugLine.cpp @@ -155,7 +155,7 @@ DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data, if (pos.second) { // Parse and cache the line table for at this offset. State state; - if (!parseStatementTable(debug_line_data, &offset, state)) + if (!parseStatementTable(debug_line_data, RelocMap, &offset, state)) return 0; pos.first->second = state; } @@ -219,7 +219,8 @@ DWARFDebugLine::parsePrologue(DataExtractor debug_line_data, } bool -DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data, +DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data, + const RelocAddrMap *RMap, uint32_t *offset_ptr, State &state) { const uint32_t debug_line_offset = *offset_ptr; @@ -268,7 +269,15 @@ DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data, // relocatable address. All of the other statement program opcodes // that affect the address register add a delta to it. This instruction // stores a relocatable value into it instead. - state.Address = debug_line_data.getAddress(offset_ptr); + { + // If this address is in our relocation map, apply the relocation. + RelocAddrMap::const_iterator AI = RMap->find(*offset_ptr); + if (AI != RMap->end()) { + const std::pair<uint8_t, int64_t> &R = AI->second; + state.Address = debug_line_data.getAddress(offset_ptr) + R.second; + } else + state.Address = debug_line_data.getAddress(offset_ptr); + } break; case DW_LNE_define_file: @@ -516,6 +525,83 @@ DWARFDebugLine::LineTable::lookupAddress(uint64_t address) const { } bool +DWARFDebugLine::LineTable::lookupAddressRange(uint64_t address, + uint64_t size, + std::vector<uint32_t>& result) const { + if (Sequences.empty()) + return false; + uint64_t end_addr = address + size; + // First, find an instruction sequence containing the given address. + DWARFDebugLine::Sequence sequence; + sequence.LowPC = address; + SequenceIter first_seq = Sequences.begin(); + SequenceIter last_seq = Sequences.end(); + SequenceIter seq_pos = std::lower_bound(first_seq, last_seq, sequence, + DWARFDebugLine::Sequence::orderByLowPC); + if (seq_pos == last_seq || seq_pos->LowPC != address) { + if (seq_pos == first_seq) + return false; + seq_pos--; + } + if (!seq_pos->containsPC(address)) + return false; + + SequenceIter start_pos = seq_pos; + + // Add the rows from the first sequence to the vector, starting with the + // index we just calculated + + while (seq_pos != last_seq && seq_pos->LowPC < end_addr) { + DWARFDebugLine::Sequence cur_seq = *seq_pos; + uint32_t first_row_index; + uint32_t last_row_index; + if (seq_pos == start_pos) { + // For the first sequence, we need to find which row in the sequence is the + // first in our range. Rows are stored in a vector, so we may use + // arithmetical operations with iterators. + DWARFDebugLine::Row row; + row.Address = address; + RowIter first_row = Rows.begin() + cur_seq.FirstRowIndex; + RowIter last_row = Rows.begin() + cur_seq.LastRowIndex; + RowIter row_pos = std::upper_bound(first_row, last_row, row, + DWARFDebugLine::Row::orderByAddress); + // The 'row_pos' iterator references the first row that is greater than + // our start address. Unless that's the first row, we want to start at + // the row before that. + first_row_index = cur_seq.FirstRowIndex + (row_pos - first_row); + if (row_pos != first_row) + --first_row_index; + } else + first_row_index = cur_seq.FirstRowIndex; + + // For the last sequence in our range, we need to figure out the last row in + // range. For all other sequences we can go to the end of the sequence. + if (cur_seq.HighPC > end_addr) { + DWARFDebugLine::Row row; + row.Address = end_addr; + RowIter first_row = Rows.begin() + cur_seq.FirstRowIndex; + RowIter last_row = Rows.begin() + cur_seq.LastRowIndex; + RowIter row_pos = std::upper_bound(first_row, last_row, row, + DWARFDebugLine::Row::orderByAddress); + // The 'row_pos' iterator references the first row that is greater than + // our end address. The row before that is the last row we want. + last_row_index = cur_seq.FirstRowIndex + (row_pos - first_row) - 1; + } else + // Contrary to what you might expect, DWARFDebugLine::SequenceLastRowIndex + // isn't a valid index within the current sequence. It's that plus one. + last_row_index = cur_seq.LastRowIndex - 1; + + for (uint32_t i = first_row_index; i <= last_row_index; ++i) { + result.push_back(i); + } + + ++seq_pos; + } + + return true; +} + +bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, bool NeedsAbsoluteFilePath, std::string &Result) const { diff --git a/lib/DebugInfo/DWARFDebugLine.h b/lib/DebugInfo/DWARFDebugLine.h index 586dd7e878..2990756bd7 100644 --- a/lib/DebugInfo/DWARFDebugLine.h +++ b/lib/DebugInfo/DWARFDebugLine.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H #define LLVM_DEBUGINFO_DWARFDEBUGLINE_H +#include "DWARFRelocMap.h" #include "llvm/Support/DataExtractor.h" #include <map> #include <string> @@ -21,6 +22,7 @@ class raw_ostream; class DWARFDebugLine { public: + DWARFDebugLine(const RelocAddrMap* LineInfoRelocMap) : RelocMap(LineInfoRelocMap) {} struct FileNameEntry { FileNameEntry() : Name(0), DirIdx(0), ModTime(0), Length(0) {} @@ -176,6 +178,10 @@ public: // or -1 if there is no such row. uint32_t lookupAddress(uint64_t address) const; + bool lookupAddressRange(uint64_t address, + uint64_t size, + std::vector<uint32_t>& result) const; + // Extracts filename by its index in filename table in prologue. // Returns true on success. bool getFileNameByIndex(uint64_t FileIndex, @@ -227,6 +233,7 @@ public: Prologue *prologue); /// Parse a single line table (prologue and all rows). static bool parseStatementTable(DataExtractor debug_line_data, + const RelocAddrMap *RMap, uint32_t *offset_ptr, State &state); const LineTable *getLineTable(uint32_t offset) const; @@ -238,6 +245,7 @@ private: typedef LineTableMapTy::iterator LineTableIter; typedef LineTableMapTy::const_iterator LineTableConstIter; + const RelocAddrMap *RelocMap; LineTableMapTy LineTableMap; }; diff --git a/lib/DebugInfo/DWARFFormValue.cpp b/lib/DebugInfo/DWARFFormValue.cpp index 1d8ea01110..9f807aac5f 100644 --- a/lib/DebugInfo/DWARFFormValue.cpp +++ b/lib/DebugInfo/DWARFFormValue.cpp @@ -46,8 +46,6 @@ static const uint8_t form_sizes_addr4[] = { 0, // 0x18 DW_FORM_exprloc 0, // 0x19 DW_FORM_flag_present 8, // 0x20 DW_FORM_ref_sig8 - 4, // 0x1f01 DW_FORM_GNU_addr_index - 4, // 0x1f02 DW_FORM_GNU_str_index }; static const uint8_t form_sizes_addr8[] = { @@ -74,12 +72,10 @@ static const uint8_t form_sizes_addr8[] = { 8, // 0x14 DW_FORM_ref8 0, // 0x15 DW_FORM_ref_udata 0, // 0x16 DW_FORM_indirect - 8, // 0x17 DW_FORM_sec_offset + 4, // 0x17 DW_FORM_sec_offset 0, // 0x18 DW_FORM_exprloc 0, // 0x19 DW_FORM_flag_present 8, // 0x20 DW_FORM_ref_sig8 - 8, // 0x1f01 DW_FORM_GNU_addr_index - 8, // 0x1f01 DW_FORM_GNU_str_index }; const uint8_t * @@ -105,11 +101,11 @@ DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, case DW_FORM_addr: case DW_FORM_ref_addr: { RelocAddrMap::const_iterator AI - = cu->getContext().relocMap().find(*offset_ptr); - if (AI != cu->getContext().relocMap().end()) { + = cu->getRelocMap()->find(*offset_ptr); + if (AI != cu->getRelocMap()->end()) { const std::pair<uint8_t, int64_t> &R = AI->second; - Value.uval = R.second; - *offset_ptr += R.first; + Value.uval = data.getUnsigned(offset_ptr, cu->getAddressByteSize()) + + R.second; } else Value.uval = data.getUnsigned(offset_ptr, cu->getAddressByteSize()); break; @@ -153,11 +149,10 @@ DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, break; case DW_FORM_strp: { RelocAddrMap::const_iterator AI - = cu->getContext().relocMap().find(*offset_ptr); - if (AI != cu->getContext().relocMap().end()) { + = cu->getRelocMap()->find(*offset_ptr); + if (AI != cu->getRelocMap()->end()) { const std::pair<uint8_t, int64_t> &R = AI->second; - Value.uval = R.second; - *offset_ptr += R.first; + Value.uval = data.getU32(offset_ptr) + R.second; } else Value.uval = data.getU32(offset_ptr); break; @@ -178,10 +173,8 @@ DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, indirect = true; break; case DW_FORM_sec_offset: - if (cu->getAddressByteSize() == 4) - Value.uval = data.getU32(offset_ptr); - else - Value.uval = data.getU64(offset_ptr); + // FIXME: This is 64-bit for DWARF64. + Value.uval = data.getU32(offset_ptr); break; case DW_FORM_flag_present: Value.uval = 1; @@ -263,7 +256,7 @@ DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, // 0 byte values - implied from the form. case DW_FORM_flag_present: return true; - + // 1 byte values case DW_FORM_data1: case DW_FORM_flag: @@ -296,6 +289,8 @@ DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, case DW_FORM_sdata: case DW_FORM_udata: case DW_FORM_ref_udata: + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_addr_index: debug_info_data.getULEB128(offset_ptr); return true; @@ -304,14 +299,11 @@ DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, form = debug_info_data.getULEB128(offset_ptr); break; - // 4 for DWARF32, 8 for DWARF64. + // FIXME: 4 for DWARF32, 8 for DWARF64. case DW_FORM_sec_offset: - if (cu->getAddressByteSize() == 4) - *offset_ptr += 4; - else - *offset_ptr += 8; + *offset_ptr += 4; return true; - + default: return false; } @@ -321,12 +313,23 @@ DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, void DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const { - DataExtractor debug_str_data(cu->getContext().getStringSection(), true, 0); + DataExtractor debug_str_data(cu->getStringSection(), true, 0); + DataExtractor debug_str_offset_data(cu->getStringOffsetSection(), true, 0); uint64_t uvalue = getUnsigned(); bool cu_relative_offset = false; 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 + OS << "<no .debug_addr section>"; + break; + } case DW_FORM_flag_present: OS << "true"; break; case DW_FORM_flag: case DW_FORM_data1: OS << format("0x%02x", (uint8_t)uvalue); break; @@ -380,6 +383,17 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const { } break; } + 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); + if (dbg_str) { + OS << '"'; + OS.write_escaped(dbg_str); + OS << '"'; + } + break; + } case DW_FORM_ref_addr: OS << format("0x%016" PRIx64, uvalue); break; @@ -410,13 +424,11 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const { OS << "DW_FORM_indirect"; break; + // Should be formatted to 64-bit for DWARF64. case DW_FORM_sec_offset: - if (cu->getAddressByteSize() == 4) - OS << format("0x%08x", (uint32_t)uvalue); - else - OS << format("0x%016" PRIx64, uvalue); + OS << format("0x%08x", (uint32_t)uvalue); break; - + default: OS << format("DW_FORM(0x%4.4x)", Form); break; @@ -437,6 +449,25 @@ DWARFFormValue::getAsCString(const DataExtractor *debug_str_data_ptr) const { 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); +} + +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); +} + uint64_t DWARFFormValue::getReference(const DWARFCompileUnit *cu) const { uint64_t die_offset = Value.uval; switch (Form) { diff --git a/lib/DebugInfo/DWARFFormValue.h b/lib/DebugInfo/DWARFFormValue.h index c5b590db95..b863001e4a 100644 --- a/lib/DebugInfo/DWARFFormValue.h +++ b/lib/DebugInfo/DWARFFormValue.h @@ -64,6 +64,10 @@ public: 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; bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFCompileUnit *cu) const; static bool skipValue(uint16_t form, DataExtractor debug_info_data, diff --git a/lib/DebugInfo/DWARFRelocMap.h b/lib/DebugInfo/DWARFRelocMap.h new file mode 100644 index 0000000000..6929e367b8 --- /dev/null +++ b/lib/DebugInfo/DWARFRelocMap.h @@ -0,0 +1,22 @@ +//===-- DWARFRelocMap.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_DWARFRELOCMAP_H +#define LLVM_DEBUGINFO_DWARFRELOCMAP_H + +#include "llvm/ADT/DenseMap.h" + +namespace llvm { + +typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t> > RelocAddrMap; + +} // namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFRELOCMAP_H + |