diff options
Diffstat (limited to 'lib/DebugInfo')
-rw-r--r-- | lib/DebugInfo/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFCompileUnit.h | 8 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFContext.cpp | 268 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFContext.h | 26 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugFrame.cpp | 391 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugFrame.h | 46 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugInfoEntry.cpp | 12 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugLine.cpp | 92 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFDebugLine.h | 8 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFFormValue.cpp | 42 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFFormValue.h | 2 | ||||
-rw-r--r-- | lib/DebugInfo/DWARFRelocMap.h | 22 |
12 files changed, 828 insertions, 90 deletions
diff --git a/lib/DebugInfo/CMakeLists.txt b/lib/DebugInfo/CMakeLists.txt index 1e9e509..e97455a 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/DWARFCompileUnit.h b/lib/DebugInfo/DWARFCompileUnit.h index c58664f..2a74605 100644 --- a/lib/DebugInfo/DWARFCompileUnit.h +++ b/lib/DebugInfo/DWARFCompileUnit.h @@ -13,6 +13,7 @@ #include "DWARFDebugAbbrev.h" #include "DWARFDebugInfoEntry.h" #include "DWARFDebugRangeList.h" +#include "DWARFRelocMap.h" #include <vector> namespace llvm { @@ -20,7 +21,6 @@ namespace llvm { class DWARFDebugAbbrev; class StringRef; class raw_ostream; -typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t> > RelocAddrMap; class DWARFCompileUnit { const DWARFDebugAbbrev *Abbrev; @@ -29,6 +29,7 @@ class DWARFCompileUnit { StringRef RangeSection; StringRef StringSection; StringRef StringOffsetSection; + StringRef AddrOffsetSection; const RelocAddrMap *RelocMap; bool isLittleEndian; @@ -43,16 +44,17 @@ class DWARFCompileUnit { public: DWARFCompileUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, - StringRef RS, StringRef SS, StringRef SOS, + 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), - RelocMap(M), isLittleEndian(LE) { + AddrOffsetSection(AOS), RelocMap(M), isLittleEndian(LE) { clear(); } StringRef getStringSection() const { return StringSection; } StringRef getStringOffsetSection() const { return StringOffsetSection; } + StringRef getAddrOffsetSection() const { return AddrOffsetSection; } const RelocAddrMap *getRelocMap() const { return RelocMap; } DataExtractor getDebugInfoExtractor() const; diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp index d6d9fcf..9e19310 100644 --- a/lib/DebugInfo/DWARFContext.cpp +++ b/lib/DebugInfo/DWARFContext.cpp @@ -19,72 +19,123 @@ 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 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_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); - - OS << "\n.debug_abbrev.dwo contents:\n"; - getDebugAbbrevDWO()->dump(OS); - - OS << "\n.debug_info.dwo contents:\n"; - for (unsigned i = 0, e = getNumDWOCompileUnits(); i != e; ++i) - getDWOCompileUnitAtIndex(i)->dump(OS); - - 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_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)); + } } } @@ -124,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, @@ -152,7 +223,8 @@ void DWARFContext::parseCompileUnits() { while (DIData.isValidOffset(offset)) { CUs.push_back(DWARFCompileUnit(getDebugAbbrev(), getInfoSection(), getAbbrevSection(), getRangeSection(), - getStringSection(), "", + getStringSection(), StringRef(), + getAddrSection(), &infoRelocMap(), isLittleEndian())); if (!CUs.back().extract(DIData, &offset)) { @@ -174,6 +246,7 @@ void DWARFContext::parseDWOCompileUnits() { getRangeDWOSection(), getStringDWOSection(), getStringOffsetDWOSection(), + getAddrSection(), &infoDWORelocMap(), isLittleEndian())); if (!DWOCUs.back().extract(DIData, &offset)) { @@ -295,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); @@ -352,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(); @@ -371,6 +503,8 @@ 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") { @@ -378,6 +512,8 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : 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") @@ -386,16 +522,21 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : 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. + // 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; @@ -409,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)); diff --git a/lib/DebugInfo/DWARFContext.h b/lib/DebugInfo/DWARFContext.h index 687ff93..37b2729 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,7 @@ class DWARFContext : public DIContext { OwningPtr<DWARFDebugAbbrev> Abbrev; OwningPtr<DWARFDebugAranges> Aranges; OwningPtr<DWARFDebugLine> Line; + OwningPtr<DWARFDebugFrame> DebugFrame; SmallVector<DWARFCompileUnit, 1> DWOCUs; OwningPtr<DWARFDebugAbbrev> AbbrevDWO; @@ -45,7 +47,7 @@ class DWARFContext : public DIContext { 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() { @@ -84,23 +86,32 @@ public: /// 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 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; @@ -108,6 +119,7 @@ public: 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) { @@ -128,13 +140,17 @@ private: class DWARFContextInMemory : public DWARFContext { virtual void anchor(); bool IsLittleEndian; + 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; @@ -143,17 +159,22 @@ class DWARFContextInMemory : public DWARFContext { StringRef StringDWOSection; StringRef StringOffsetDWOSection; StringRef RangeDWOSection; + StringRef AddrSection; public: DWARFContextInMemory(object::ObjectFile *); virtual bool isLittleEndian() const { return IsLittleEndian; } + 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; } @@ -163,6 +184,9 @@ public: 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 0000000..3efe6a1 --- /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 0000000..48b8d63 --- /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 bb11850..02b15d6 100644 --- a/lib/DebugInfo/DWARFDebugInfoEntry.cpp +++ b/lib/DebugInfo/DWARFDebugInfoEntry.cpp @@ -203,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: @@ -344,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: diff --git a/lib/DebugInfo/DWARFDebugLine.cpp b/lib/DebugInfo/DWARFDebugLine.cpp index 267364a..192381c 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 586dd7e..2990756 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 14c6804..9f807aa 100644 --- a/lib/DebugInfo/DWARFFormValue.cpp +++ b/lib/DebugInfo/DWARFFormValue.cpp @@ -72,7 +72,7 @@ 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 @@ -173,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; @@ -301,12 +299,9 @@ 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: @@ -325,6 +320,16 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const { 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; @@ -419,11 +424,9 @@ 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: @@ -452,10 +455,19 @@ DWARFFormValue::getIndirectCString(const DataExtractor *DS, if (!DS || !DSO) return NULL; uint32_t offset = Value.uval * 4; - uint32_t soffset = DSO->getULEB128(&offset); + 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 7768c18..b863001 100644 --- a/lib/DebugInfo/DWARFFormValue.h +++ b/lib/DebugInfo/DWARFFormValue.h @@ -66,6 +66,8 @@ public: 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 0000000..6929e36 --- /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 + |