From ee7c0d2f931590ccdc53a14b1839e11bb29fc96e Mon Sep 17 00:00:00 2001 From: Andrew Kaylor Date: Fri, 25 Jan 2013 22:50:58 +0000 Subject: [PATCH] Add support for applying in-memory relocations to the .debug_line section and, in the case of ELF files, using symbol addresses when available for relocations to the .debug_info section. Also extending the llvm-rtdyld tool to add the ability to dump line number information for testing purposes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@173517 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ExecutionEngine/ObjectImage.h | 2 + lib/DebugInfo/DWARFCompileUnit.h | 2 +- lib/DebugInfo/DWARFContext.cpp | 18 +++-- lib/DebugInfo/DWARFContext.h | 3 + lib/DebugInfo/DWARFDebugLine.cpp | 15 ++++- lib/DebugInfo/DWARFDebugLine.h | 4 ++ lib/DebugInfo/DWARFRelocMap.h | 21 ++++++ .../RuntimeDyld/ObjectImageCommon.h | 2 + test/DebugInfo/Inputs/test-inline.o | Bin 0 -> 6040 bytes test/DebugInfo/debuglineinfo.test | 15 +++++ tools/llvm-rtdyld/CMakeLists.txt | 2 +- tools/llvm-rtdyld/Makefile | 2 +- tools/llvm-rtdyld/llvm-rtdyld.cpp | 62 +++++++++++++++++- 13 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 lib/DebugInfo/DWARFRelocMap.h create mode 100644 test/DebugInfo/Inputs/test-inline.o create mode 100644 test/DebugInfo/debuglineinfo.test 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 0000000000000000000000000000000000000000..a650c91725d9db5504757fd91472e301e59bf2b1 GIT binary patch literal 6040 zcmbtYeQX)oxg!X=9YGDaTt4s_Db(9?f6XqZfY;(6Jy$=H$aB#-0N^%zoiZ46XDxC zfNkH>mKPFXKo%0w+><}ZT`OxJSYTN1@@or;vsew3y@X}w062-jZV_c|9LgHcMa$Z; zd?F4lg!$1zB5UTZTuz+KU2!4mm9sGH_P9WM+JNT%Wb(%8t9=me^!JWKdwVCjUFL;C zDdDoFzuF2s9=v)R2cvBJLS;pI&f#W+p? z4#dlN>`k8Wq$eG}mzNjyB*Uu)CY4tc>=_g_D5Kpg@~Z9$VbC7*7Hjqg=nrA$5ITnb z4Gp(F5b#(yra>o!D;XMvp3j*=FlA7=Hxdh~kwGOI8immX5=@Pp>hFhTRk7ROe+s%i zin17k#P_hp*d)jy4LY!4VhUQE=>H&K;Q=sTjG>U}n*yL$2Q7*xM^Yp6BM9{c!7nue zyC%hr=SNT~)dXZuASit=H^#yDeDn5cla@s)o@2ABc_5L^m#Eytax)T@=cr576wfPs4XJY!Fd zD}8~ZvB2k)*o%GPeE1%?vR^tEHo{*G1R;>$bX4h^3@88=t7d&IzF{?;id~OS>(lXZ z$5}ryIcZ)nFIDYkcCF%0n6>6aQZHE>u5DKxy;66rs$R5fC#L37$;_nVtgTk78?^}@ zY$^^ewo`GkwMx_0FMP&l&kc0Y$EW8~X`^JMX67uTlul>n%+mB+xnvZkj6!-gH8qH%JTcxDmMbeG4N^4KFxxfoSO z4;~0V4I2_4Vecc|3&V&Sg5xmKHd+PuQp0M?Fn9H}U9nSwnP&Q0({43{d(A9X>SddvdkH6&27TTjx9j+>m} z|<(Q}kPE&$?U z{DPwyUZM6A*fZQFe>uPKqj2ok)rZ)?SJ?;Fqn_z zTwexVxA}`7_M8mz#reZCn>>Fn1185rm*?N*_$Thr|2+ANIx#nr$ba`f`$yEA2V2qS zj?{eL|Iy}C$hKd&L;r7+zf>l>PWhL8xv?weU%=mlPPg@2qV>y>A+8@jKZQTaNUy;q z-{XkK$?#t&_(&fA&p{{Gj^@wtLpozwQo`|*zk}ucHv#XK|5x-<*uY>ulJomi9bL5R zVSl~d0g|A0tr+X*Hj{{V-^}Wsw~m)U^*#Xiq*mLr->Fjhlc^I!N%g)7_bAle&%zF! z>V0H&U?`}2zqYuI%1=Lg%)!3f8yVxsZyC>5W$+2ph1B+`t5d1+o!E(?q;|Oz@%b?1 zTQ7b_1MK5)9r4Yx*hA}p5Bk700#e zR+9tbW2IXCKaacOOvul-ohNF>j#GZzr~ciQk?<(V5BYGsj|II!9gO3DWWje4CuHL6 zi-0&M^+DhFmsNX5Ax^h0nzvV6;FA>h{agzlqQDPQAK4M=3;TJpzfZzV!gUF+5dNTq z*9d=D!dD6ZgoKv~$M-9es7J)Xa|4pVKT7sbc`)CJhp3P2Y3d96OJx77gnxtZuMm!+ z|M~cJ34ej)ZxI*q-=H|#68aby@m+^<;)7w7tq5H9lKA2mqlCHyYJ#r_iU zf9RRBPwx}|F)5Ci=S>M8q4-~vaQwRn>3Ink^YdK^7xld?;nzssmhc~w{5o-D;vUDm zKb3ItJp2XWV%~(E_$Nl-zazUSjYHsnBYYZ@0HH`GT>d0)J=|YUoN%=D+oycE-#+KV J(O&F_{{Z55NBIB% literal 0 HcmV?d00001 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(); } }