diff --git a/include/llvm/ExecutionEngine/ObjectImage.h b/include/llvm/ExecutionEngine/ObjectImage.h index d09e4deb1ae..9fddca7e33c 100644 --- a/include/llvm/ExecutionEngine/ObjectImage.h +++ b/include/llvm/ExecutionEngine/ObjectImage.h @@ -50,6 +50,8 @@ public: virtual StringRef getData() const = 0; + virtual object::ObjectFile* getObjectFile() const = 0; + // Subclasses can override these methods to provide JIT debugging support virtual void registerWithDebugger() = 0; virtual void deregisterWithDebugger() = 0; diff --git a/lib/DebugInfo/DWARFCompileUnit.h b/lib/DebugInfo/DWARFCompileUnit.h index de70b2e2a90..2a74605fcb2 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 namespace llvm { @@ -20,7 +21,6 @@ namespace llvm { class DWARFDebugAbbrev; class StringRef; class raw_ostream; -typedef DenseMap > RelocAddrMap; class DWARFCompileUnit { const DWARFDebugAbbrev *Abbrev; diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp index 39953499ce6..66d299bad28 100644 --- a/lib/DebugInfo/DWARFContext.cpp +++ b/lib/DebugInfo/DWARFContext.cpp @@ -53,7 +53,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { DataExtractor lineData(getLineSection(), isLittleEndian(), savedAddressByteSize); DWARFDebugLine::DumpingState state(OS); - DWARFDebugLine::parseStatementTable(lineData, &stmtOffset, state); + DWARFDebugLine::parseStatementTable(lineData, &lineRelocMap(), &stmtOffset, state); } } } @@ -155,7 +155,7 @@ const DWARFDebugAranges *DWARFContext::getDebugAranges() { 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, @@ -422,12 +422,15 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : 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; @@ -441,10 +444,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 8a4a3afec35..d6314b87c33 100644 --- a/lib/DebugInfo/DWARFContext.h +++ b/lib/DebugInfo/DWARFContext.h @@ -95,6 +95,7 @@ public: virtual bool isLittleEndian() 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; @@ -130,6 +131,7 @@ class DWARFContextInMemory : public DWARFContext { virtual void anchor(); bool IsLittleEndian; RelocAddrMap InfoRelocMap; + RelocAddrMap LineRelocMap; StringRef InfoSection; StringRef AbbrevSection; StringRef ARangeSection; @@ -150,6 +152,7 @@ public: DWARFContextInMemory(object::ObjectFile *); virtual bool isLittleEndian() const { return IsLittleEndian; } 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; } diff --git a/lib/DebugInfo/DWARFDebugLine.cpp b/lib/DebugInfo/DWARFDebugLine.cpp index 267364adfac..16ef896ca7e 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 &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: diff --git a/lib/DebugInfo/DWARFDebugLine.h b/lib/DebugInfo/DWARFDebugLine.h index 586dd7e8784..dbaf91d321f 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 #include @@ -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) {} @@ -227,6 +229,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 +241,7 @@ private: typedef LineTableMapTy::iterator LineTableIter; typedef LineTableMapTy::const_iterator LineTableConstIter; + const RelocAddrMap *RelocMap; LineTableMapTy LineTableMap; }; diff --git a/lib/DebugInfo/DWARFRelocMap.h b/lib/DebugInfo/DWARFRelocMap.h new file mode 100644 index 00000000000..f53d05cac58 --- /dev/null +++ b/lib/DebugInfo/DWARFRelocMap.h @@ -0,0 +1,21 @@ +//===-- 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 > RelocAddrMap; + +} // namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFRELOCMAP_H \ No newline at end of file diff --git a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h index 28b4f0f84a0..89350cc5b62 100644 --- a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h +++ b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h @@ -58,6 +58,8 @@ public: virtual StringRef getData() const { return ObjFile->getData(); } + virtual object::ObjectFile* getObjectFile() const { return ObjFile; } + // Subclasses can override these methods to update the image with loaded // addresses for sections and common symbols virtual void updateSectionAddress(const object::SectionRef &Sec, diff --git a/test/DebugInfo/Inputs/test-inline.o b/test/DebugInfo/Inputs/test-inline.o new file mode 100644 index 00000000000..a650c91725d Binary files /dev/null and b/test/DebugInfo/Inputs/test-inline.o differ diff --git a/test/DebugInfo/debuglineinfo.test b/test/DebugInfo/debuglineinfo.test new file mode 100644 index 00000000000..78de390a8b1 --- /dev/null +++ b/test/DebugInfo/debuglineinfo.test @@ -0,0 +1,15 @@ +RUN: llvm-rtdyld -printline %p/Inputs/test-inline.o \ +RUN: | FileCheck %s -check-prefix TEST_INLINE + +; This test verifies that relocations are correctly applied to the +; .debug_line section. If relocations are not applied the first two +; functions will be reported as both starting at address zero in the +; line number table. +TEST_INLINE: Function: _Z15test_parametersPfPA2_dR11char_structPPitm, Size = 170 +TEST_INLINE-NEXT: Line info:test-inline.cpp, line:33 +TEST_INLINE-NEXT: Function: _Z3foov, Size = 3 +TEST_INLINE-NEXT: Line info:test-inline.cpp, line:28 +TEST_INLINE-NEXT: Function: main, Size = 146 +TEST_INLINE-NEXT: Line info:test-inline.cpp, line:39 + + diff --git a/tools/llvm-rtdyld/CMakeLists.txt b/tools/llvm-rtdyld/CMakeLists.txt index 17e2c3e2d5b..8d161d366da 100644 --- a/tools/llvm-rtdyld/CMakeLists.txt +++ b/tools/llvm-rtdyld/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC object RuntimeDyld JIT) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC object RuntimeDyld JIT debuginfo) add_llvm_tool(llvm-rtdyld llvm-rtdyld.cpp diff --git a/tools/llvm-rtdyld/Makefile b/tools/llvm-rtdyld/Makefile index 30fbee0979b..fabdd683a99 100644 --- a/tools/llvm-rtdyld/Makefile +++ b/tools/llvm-rtdyld/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-rtdyld -LINK_COMPONENTS := all-targets support MC object RuntimeDyld JIT +LINK_COMPONENTS := all-targets support MC object RuntimeDyld JIT debuginfo # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index ec63c9b56ca..8b71a4f3641 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringMap.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/ExecutionEngine/ObjectBuffer.h" #include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" @@ -31,7 +32,8 @@ InputFileList(cl::Positional, cl::ZeroOrMore, cl::desc("")); enum ActionType { - AC_Execute + AC_Execute, + AC_PrintLineInfo }; static cl::opt @@ -39,6 +41,8 @@ Action(cl::desc("Action to perform:"), cl::init(AC_Execute), cl::values(clEnumValN(AC_Execute, "execute", "Load, link, and execute the inputs."), + clEnumValN(AC_PrintLineInfo, "printline", + "Load, link, and print line information for each function."), clEnumValEnd)); static cl::opt @@ -114,6 +118,60 @@ static int Error(const Twine &Msg) { /* *** */ +static int printLineInfoForInput() { + // If we don't have any input files, read from stdin. + if (!InputFileList.size()) + InputFileList.push_back("-"); + for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + // Instantiate a dynamic linker. + TrivialMemoryManager *MemMgr = new TrivialMemoryManager; + RuntimeDyld Dyld(MemMgr); + + // Load the input memory buffer. + OwningPtr InputBuffer; + OwningPtr LoadedObject; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], + InputBuffer)) + return Error("unable to read input: '" + ec.message() + "'"); + + // Load the object file + LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.take()))); + if (!LoadedObject) { + return Error(Dyld.getErrorString()); + } + + // Resolve all the relocations we can. + Dyld.resolveRelocations(); + + OwningPtr Context(DIContext::getDWARFContext(LoadedObject->getObjectFile())); + + // Use symbol info to iterate functions in the object. + error_code ec; + for (object::symbol_iterator I = LoadedObject->begin_symbols(), + E = LoadedObject->end_symbols(); + I != E && !ec; + I.increment(ec)) { + object::SymbolRef::Type SymType; + if (I->getType(SymType)) continue; + if (SymType == object::SymbolRef::ST_Function) { + StringRef Name; + uint64_t Addr; + uint64_t Size; + if (I->getName(Name)) continue; + if (I->getAddress(Addr)) continue; + if (I->getSize(Size)) continue; + + outs() << "Function: " << Name << ", Size = " << Size << "\n"; + + DILineInfo Result = Context->getLineInfoForAddress(Addr); + outs() << " Line info:" << Result.getFileName() << ", line:" << Result.getLine() << "\n"; + } + } + } + + return 0; +} + static int executeInput() { // Instantiate a dynamic linker. TrivialMemoryManager *MemMgr = new TrivialMemoryManager; @@ -180,5 +238,7 @@ int main(int argc, char **argv) { switch (Action) { case AC_Execute: return executeInput(); + case AC_PrintLineInfo: + return printLineInfoForInput(); } }