mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-18 11:24:01 +00:00
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
This commit is contained in:
@ -50,6 +50,8 @@ public:
|
|||||||
|
|
||||||
virtual StringRef getData() const = 0;
|
virtual StringRef getData() const = 0;
|
||||||
|
|
||||||
|
virtual object::ObjectFile* getObjectFile() const = 0;
|
||||||
|
|
||||||
// Subclasses can override these methods to provide JIT debugging support
|
// Subclasses can override these methods to provide JIT debugging support
|
||||||
virtual void registerWithDebugger() = 0;
|
virtual void registerWithDebugger() = 0;
|
||||||
virtual void deregisterWithDebugger() = 0;
|
virtual void deregisterWithDebugger() = 0;
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "DWARFDebugAbbrev.h"
|
#include "DWARFDebugAbbrev.h"
|
||||||
#include "DWARFDebugInfoEntry.h"
|
#include "DWARFDebugInfoEntry.h"
|
||||||
#include "DWARFDebugRangeList.h"
|
#include "DWARFDebugRangeList.h"
|
||||||
|
#include "DWARFRelocMap.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -20,7 +21,6 @@ namespace llvm {
|
|||||||
class DWARFDebugAbbrev;
|
class DWARFDebugAbbrev;
|
||||||
class StringRef;
|
class StringRef;
|
||||||
class raw_ostream;
|
class raw_ostream;
|
||||||
typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t> > RelocAddrMap;
|
|
||||||
|
|
||||||
class DWARFCompileUnit {
|
class DWARFCompileUnit {
|
||||||
const DWARFDebugAbbrev *Abbrev;
|
const DWARFDebugAbbrev *Abbrev;
|
||||||
|
@ -53,7 +53,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
|
|||||||
DataExtractor lineData(getLineSection(), isLittleEndian(),
|
DataExtractor lineData(getLineSection(), isLittleEndian(),
|
||||||
savedAddressByteSize);
|
savedAddressByteSize);
|
||||||
DWARFDebugLine::DumpingState state(OS);
|
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 *
|
const DWARFLineTable *
|
||||||
DWARFContext::getLineTableForCompileUnit(DWARFCompileUnit *cu) {
|
DWARFContext::getLineTableForCompileUnit(DWARFCompileUnit *cu) {
|
||||||
if (!Line)
|
if (!Line)
|
||||||
Line.reset(new DWARFDebugLine());
|
Line.reset(new DWARFDebugLine(&lineRelocMap()));
|
||||||
|
|
||||||
unsigned stmtOffset =
|
unsigned stmtOffset =
|
||||||
cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list,
|
cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list,
|
||||||
@ -422,12 +422,15 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
|
|||||||
else
|
else
|
||||||
continue;
|
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;
|
RelocAddrMap *Map;
|
||||||
if (name == "debug_info")
|
if (name == "debug_info")
|
||||||
Map = &InfoRelocMap;
|
Map = &InfoRelocMap;
|
||||||
else if (name == "debug_info.dwo")
|
else if (name == "debug_info.dwo")
|
||||||
Map = &InfoDWORelocMap;
|
Map = &InfoDWORelocMap;
|
||||||
|
else if (name == "debug_line")
|
||||||
|
Map = &LineRelocMap;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -441,10 +444,17 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
|
|||||||
reloc_i->getAddress(Address);
|
reloc_i->getAddress(Address);
|
||||||
uint64_t Type;
|
uint64_t Type;
|
||||||
reloc_i->getType(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());
|
object::RelocVisitor V(Obj->getFileFormatName());
|
||||||
// The section address is always 0 for debug sections.
|
// 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()) {
|
if (V.error()) {
|
||||||
SmallString<32> Name;
|
SmallString<32> Name;
|
||||||
error_code ec(reloc_i->getTypeName(Name));
|
error_code ec(reloc_i->getTypeName(Name));
|
||||||
|
@ -95,6 +95,7 @@ public:
|
|||||||
|
|
||||||
virtual bool isLittleEndian() const = 0;
|
virtual bool isLittleEndian() const = 0;
|
||||||
virtual const RelocAddrMap &infoRelocMap() const = 0;
|
virtual const RelocAddrMap &infoRelocMap() const = 0;
|
||||||
|
virtual const RelocAddrMap &lineRelocMap() const = 0;
|
||||||
virtual StringRef getInfoSection() = 0;
|
virtual StringRef getInfoSection() = 0;
|
||||||
virtual StringRef getAbbrevSection() = 0;
|
virtual StringRef getAbbrevSection() = 0;
|
||||||
virtual StringRef getARangeSection() = 0;
|
virtual StringRef getARangeSection() = 0;
|
||||||
@ -130,6 +131,7 @@ class DWARFContextInMemory : public DWARFContext {
|
|||||||
virtual void anchor();
|
virtual void anchor();
|
||||||
bool IsLittleEndian;
|
bool IsLittleEndian;
|
||||||
RelocAddrMap InfoRelocMap;
|
RelocAddrMap InfoRelocMap;
|
||||||
|
RelocAddrMap LineRelocMap;
|
||||||
StringRef InfoSection;
|
StringRef InfoSection;
|
||||||
StringRef AbbrevSection;
|
StringRef AbbrevSection;
|
||||||
StringRef ARangeSection;
|
StringRef ARangeSection;
|
||||||
@ -150,6 +152,7 @@ public:
|
|||||||
DWARFContextInMemory(object::ObjectFile *);
|
DWARFContextInMemory(object::ObjectFile *);
|
||||||
virtual bool isLittleEndian() const { return IsLittleEndian; }
|
virtual bool isLittleEndian() const { return IsLittleEndian; }
|
||||||
virtual const RelocAddrMap &infoRelocMap() const { return InfoRelocMap; }
|
virtual const RelocAddrMap &infoRelocMap() const { return InfoRelocMap; }
|
||||||
|
virtual const RelocAddrMap &lineRelocMap() const { return LineRelocMap; }
|
||||||
virtual StringRef getInfoSection() { return InfoSection; }
|
virtual StringRef getInfoSection() { return InfoSection; }
|
||||||
virtual StringRef getAbbrevSection() { return AbbrevSection; }
|
virtual StringRef getAbbrevSection() { return AbbrevSection; }
|
||||||
virtual StringRef getARangeSection() { return ARangeSection; }
|
virtual StringRef getARangeSection() { return ARangeSection; }
|
||||||
|
@ -155,7 +155,7 @@ DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data,
|
|||||||
if (pos.second) {
|
if (pos.second) {
|
||||||
// Parse and cache the line table for at this offset.
|
// Parse and cache the line table for at this offset.
|
||||||
State state;
|
State state;
|
||||||
if (!parseStatementTable(debug_line_data, &offset, state))
|
if (!parseStatementTable(debug_line_data, RelocMap, &offset, state))
|
||||||
return 0;
|
return 0;
|
||||||
pos.first->second = state;
|
pos.first->second = state;
|
||||||
}
|
}
|
||||||
@ -220,6 +220,7 @@ DWARFDebugLine::parsePrologue(DataExtractor debug_line_data,
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
|
DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
|
||||||
|
const RelocAddrMap *RMap,
|
||||||
uint32_t *offset_ptr, State &state) {
|
uint32_t *offset_ptr, State &state) {
|
||||||
const uint32_t debug_line_offset = *offset_ptr;
|
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
|
// relocatable address. All of the other statement program opcodes
|
||||||
// that affect the address register add a delta to it. This instruction
|
// that affect the address register add a delta to it. This instruction
|
||||||
// stores a relocatable value into it instead.
|
// stores a relocatable value into it instead.
|
||||||
|
{
|
||||||
|
// 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);
|
state.Address = debug_line_data.getAddress(offset_ptr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_LNE_define_file:
|
case DW_LNE_define_file:
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H
|
#ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H
|
||||||
#define LLVM_DEBUGINFO_DWARFDEBUGLINE_H
|
#define LLVM_DEBUGINFO_DWARFDEBUGLINE_H
|
||||||
|
|
||||||
|
#include "DWARFRelocMap.h"
|
||||||
#include "llvm/Support/DataExtractor.h"
|
#include "llvm/Support/DataExtractor.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -21,6 +22,7 @@ class raw_ostream;
|
|||||||
|
|
||||||
class DWARFDebugLine {
|
class DWARFDebugLine {
|
||||||
public:
|
public:
|
||||||
|
DWARFDebugLine(const RelocAddrMap* LineInfoRelocMap) : RelocMap(LineInfoRelocMap) {}
|
||||||
struct FileNameEntry {
|
struct FileNameEntry {
|
||||||
FileNameEntry() : Name(0), DirIdx(0), ModTime(0), Length(0) {}
|
FileNameEntry() : Name(0), DirIdx(0), ModTime(0), Length(0) {}
|
||||||
|
|
||||||
@ -227,6 +229,7 @@ public:
|
|||||||
Prologue *prologue);
|
Prologue *prologue);
|
||||||
/// Parse a single line table (prologue and all rows).
|
/// Parse a single line table (prologue and all rows).
|
||||||
static bool parseStatementTable(DataExtractor debug_line_data,
|
static bool parseStatementTable(DataExtractor debug_line_data,
|
||||||
|
const RelocAddrMap *RMap,
|
||||||
uint32_t *offset_ptr, State &state);
|
uint32_t *offset_ptr, State &state);
|
||||||
|
|
||||||
const LineTable *getLineTable(uint32_t offset) const;
|
const LineTable *getLineTable(uint32_t offset) const;
|
||||||
@ -238,6 +241,7 @@ private:
|
|||||||
typedef LineTableMapTy::iterator LineTableIter;
|
typedef LineTableMapTy::iterator LineTableIter;
|
||||||
typedef LineTableMapTy::const_iterator LineTableConstIter;
|
typedef LineTableMapTy::const_iterator LineTableConstIter;
|
||||||
|
|
||||||
|
const RelocAddrMap *RelocMap;
|
||||||
LineTableMapTy LineTableMap;
|
LineTableMapTy LineTableMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
21
lib/DebugInfo/DWARFRelocMap.h
Normal file
21
lib/DebugInfo/DWARFRelocMap.h
Normal file
@ -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<uint64_t, std::pair<uint8_t, int64_t> > RelocAddrMap;
|
||||||
|
|
||||||
|
} // namespace llvm
|
||||||
|
|
||||||
|
#endif // LLVM_DEBUGINFO_DWARFRELOCMAP_H
|
@ -58,6 +58,8 @@ public:
|
|||||||
|
|
||||||
virtual StringRef getData() const { return ObjFile->getData(); }
|
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
|
// Subclasses can override these methods to update the image with loaded
|
||||||
// addresses for sections and common symbols
|
// addresses for sections and common symbols
|
||||||
virtual void updateSectionAddress(const object::SectionRef &Sec,
|
virtual void updateSectionAddress(const object::SectionRef &Sec,
|
||||||
|
BIN
test/DebugInfo/Inputs/test-inline.o
Normal file
BIN
test/DebugInfo/Inputs/test-inline.o
Normal file
Binary file not shown.
15
test/DebugInfo/debuglineinfo.test
Normal file
15
test/DebugInfo/debuglineinfo.test
Normal file
@ -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
|
||||||
|
|
||||||
|
|
@ -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
|
add_llvm_tool(llvm-rtdyld
|
||||||
llvm-rtdyld.cpp
|
llvm-rtdyld.cpp
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
LEVEL := ../..
|
LEVEL := ../..
|
||||||
TOOLNAME := llvm-rtdyld
|
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.
|
# This tool has no plugins, optimize startup time.
|
||||||
TOOL_NO_EXPORTS := 1
|
TOOL_NO_EXPORTS := 1
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
|
#include "llvm/DebugInfo/DIContext.h"
|
||||||
#include "llvm/ExecutionEngine/ObjectBuffer.h"
|
#include "llvm/ExecutionEngine/ObjectBuffer.h"
|
||||||
#include "llvm/ExecutionEngine/ObjectImage.h"
|
#include "llvm/ExecutionEngine/ObjectImage.h"
|
||||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||||
@ -31,7 +32,8 @@ InputFileList(cl::Positional, cl::ZeroOrMore,
|
|||||||
cl::desc("<input file>"));
|
cl::desc("<input file>"));
|
||||||
|
|
||||||
enum ActionType {
|
enum ActionType {
|
||||||
AC_Execute
|
AC_Execute,
|
||||||
|
AC_PrintLineInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
static cl::opt<ActionType>
|
static cl::opt<ActionType>
|
||||||
@ -39,6 +41,8 @@ Action(cl::desc("Action to perform:"),
|
|||||||
cl::init(AC_Execute),
|
cl::init(AC_Execute),
|
||||||
cl::values(clEnumValN(AC_Execute, "execute",
|
cl::values(clEnumValN(AC_Execute, "execute",
|
||||||
"Load, link, and execute the inputs."),
|
"Load, link, and execute the inputs."),
|
||||||
|
clEnumValN(AC_PrintLineInfo, "printline",
|
||||||
|
"Load, link, and print line information for each function."),
|
||||||
clEnumValEnd));
|
clEnumValEnd));
|
||||||
|
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string>
|
||||||
@ -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<MemoryBuffer> InputBuffer;
|
||||||
|
OwningPtr<ObjectImage> 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<DIContext> 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() {
|
static int executeInput() {
|
||||||
// Instantiate a dynamic linker.
|
// Instantiate a dynamic linker.
|
||||||
TrivialMemoryManager *MemMgr = new TrivialMemoryManager;
|
TrivialMemoryManager *MemMgr = new TrivialMemoryManager;
|
||||||
@ -180,5 +238,7 @@ int main(int argc, char **argv) {
|
|||||||
switch (Action) {
|
switch (Action) {
|
||||||
case AC_Execute:
|
case AC_Execute:
|
||||||
return executeInput();
|
return executeInput();
|
||||||
|
case AC_PrintLineInfo:
|
||||||
|
return printLineInfoForInput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user