const DIContextKind Kind;
};
+/// An inferface for inquiring the load address of a loaded object file
+/// to be used by the DIContext implementations when applying relocations
+/// on the fly.
+class LoadedObjectInfo {
+public:
+ LoadedObjectInfo() {}
+ virtual ~LoadedObjectInfo() {}
+
+ /// Obtain the Load Address of a section by Name.
+ ///
+ /// Calculate the address of the section identified by the passed in Name.
+ /// The section need not be present in the local address space. The addresses
+ /// need to be consistent with the addresses used to query the DIContext and
+ /// the output of this function should be deterministic, i.e. repeated calls with
+ /// the same Name should give the same address.
+ virtual uint64_t getSectionLoadAddress(StringRef Name) const = 0;
+
+ /// If conveniently available, return the content of the given Section.
+ ///
+ /// When the section is available in the local address space, in relocated (loaded)
+ /// form, e.g. because it was relocated by a JIT for execution, this function
+ /// should provide the contents of said section in `Data`. If the loaded section
+ /// is not available, or the cost of retrieving it would be prohibitive, this
+ /// function should return false. In that case, relocations will be read from the
+ /// local (unrelocated) object file and applied on the fly. Note that this method
+ /// is used purely for optimzation purposes in the common case of JITting in the
+ /// local address space, so returning false should always be correct.
+ virtual bool getLoadedSectionContents(StringRef Name, StringRef &Data) const {
+ return false;
+ }
+
+ /// Obtain a copy of this LoadedObjectInfo.
+ ///
+ /// The caller is responsible for deallocation once the copy is no longer required.
+ virtual LoadedObjectInfo *clone() const = 0;
+};
+
}
#endif
SmallVector<SmallString<32>, 4> UncompressedSections;
public:
- DWARFContextInMemory(const object::ObjectFile &Obj);
+ DWARFContextInMemory(const object::ObjectFile &Obj,
+ const LoadedObjectInfo *L = nullptr);
bool isLittleEndian() const override { return IsLittleEndian; }
uint8_t getAddressSize() const override { return AddressSize; }
const DWARFSection &getInfoSection() override { return InfoSection; }
#include "JITSymbolFlags.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Memory.h"
+#include "llvm/DebugInfo/DIContext.h"
#include <memory>
namespace llvm {
};
/// \brief Information about the loaded object.
- class LoadedObjectInfo {
+ class LoadedObjectInfo : public llvm::LoadedObjectInfo {
friend class RuntimeDyldImpl;
public:
LoadedObjectInfo(RuntimeDyldImpl &RTDyld, unsigned BeginIdx,
return getStorageClass() == COFF::IMAGE_SYM_CLASS_FILE;
}
+ bool isSection() const {
+ return getStorageClass() == COFF::IMAGE_SYM_CLASS_SECTION;
+ }
+
bool isSectionDefinition() const {
// C++/CLI creates external ABS symbols for non-const appdomain globals.
// These are also followed by an auxiliary section definition.
std::error_code getRelocationOffset(DataRefImpl Rel,
uint64_t &Res) const override;
symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
+ section_iterator getRelocationSection(DataRefImpl Rel) const override;
std::error_code getRelocationType(DataRefImpl Rel,
uint64_t &Res) const override;
std::error_code
std::error_code getSymbolOther(DataRefImpl Symb, uint8_t &Res) const override;
std::error_code getSymbolType(DataRefImpl Symb,
SymbolRef::Type &Res) const override;
+ section_iterator getSymbolSection(const Elf_Sym *Symb) const;
std::error_code getSymbolSection(DataRefImpl Symb,
section_iterator &Res) const override;
std::error_code getRelocationOffset(DataRefImpl Rel,
uint64_t &Res) const override;
symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
+ section_iterator getRelocationSection(DataRefImpl Rel) const override;
std::error_code getRelocationType(DataRefImpl Rel,
uint64_t &Res) const override;
std::error_code
}
template <class ELFT>
-std::error_code
-ELFObjectFile<ELFT>::getSymbolSection(DataRefImpl Symb,
- section_iterator &Res) const {
- const Elf_Sym *ESym = getSymbol(Symb);
+section_iterator
+ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym) const {
const Elf_Shdr *ESec = EF.getSection(ESym);
if (!ESec)
- Res = section_end();
+ return section_end();
else {
DataRefImpl Sec;
Sec.p = reinterpret_cast<intptr_t>(ESec);
- Res = section_iterator(SectionRef(Sec, this));
+ return section_iterator(SectionRef(Sec, this));
}
+}
+
+template <class ELFT>
+std::error_code
+ELFObjectFile<ELFT>::getSymbolSection(DataRefImpl Symb,
+ section_iterator &Res) const {
+ Res = getSymbolSection(getSymbol(Symb));
return object_error::success;
}
return symbol_iterator(SymbolRef(SymbolData, this));
}
+// ELF relocations can target sections, by targetting a symbol of type
+// STT_SECTION
+template <class ELFT>
+section_iterator
+ELFObjectFile<ELFT>::getRelocationSection(DataRefImpl Rel) const {
+ symbol_iterator Sym = getRelocationSymbol(Rel);
+ if (Sym == symbol_end())
+ return section_end();
+ const Elf_Sym *ESym = getSymbol(Sym->getRawDataRefImpl());
+ if (ESym->getType() != ELF::STT_SECTION)
+ return section_end();
+ return getSymbolSection(ESym);
+}
+
template <class ELFT>
std::error_code
ELFObjectFile<ELFT>::getRelocationAddress(DataRefImpl Rel,
std::error_code getRelocationOffset(DataRefImpl Rel,
uint64_t &Res) const override;
symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
+ section_iterator getRelocationSection(DataRefImpl Rel) const override;
std::error_code getRelocationType(DataRefImpl Rel,
uint64_t &Res) const override;
std::error_code
unsigned getAnyRelocationPCRel(const MachO::any_relocation_info &RE) const;
unsigned getAnyRelocationLength(const MachO::any_relocation_info &RE) const;
unsigned getAnyRelocationType(const MachO::any_relocation_info &RE) const;
- SectionRef getRelocationSection(const MachO::any_relocation_info &RE) const;
+ SectionRef getAnyRelocationSection(const MachO::any_relocation_info &RE) const;
// Walk load commands.
LoadCommandInfo getFirstLoadCommandInfo() const;
class SymbolRef;
class symbol_iterator;
+class SectionRef;
+typedef content_iterator<SectionRef> section_iterator;
/// RelocationRef - This is a value type class that represents a single
/// relocation in the list of relocations in the object file.
std::error_code getAddress(uint64_t &Result) const;
std::error_code getOffset(uint64_t &Result) const;
symbol_iterator getSymbol() const;
+ section_iterator getSection() const;
std::error_code getType(uint64_t &Result) const;
/// @brief Indicates whether this relocation should hidden when listing
/// SectionRef - This is a value type class that represents a single section in
/// the list of sections in the object file.
-class SectionRef;
-typedef content_iterator<SectionRef> section_iterator;
class SectionRef {
friend class SymbolRef;
DataRefImpl SectionPimpl;
virtual std::error_code getRelocationOffset(DataRefImpl Rel,
uint64_t &Res) const = 0;
virtual symbol_iterator getRelocationSymbol(DataRefImpl Rel) const = 0;
+ virtual section_iterator getRelocationSection(DataRefImpl Rel) const = 0;
virtual std::error_code getRelocationType(DataRefImpl Rel,
uint64_t &Res) const = 0;
virtual std::error_code
return OwningObject->getRelocationSymbol(RelocationPimpl);
}
+inline section_iterator RelocationRef::getSection() const {
+ return OwningObject->getRelocationSection(RelocationPimpl);
+}
+
inline std::error_code RelocationRef::getType(uint64_t &Result) const {
return OwningObject->getRelocationType(RelocationPimpl, Result);
}
return true;
}
-DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj)
+DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
+ const LoadedObjectInfo *L)
: IsLittleEndian(Obj.isLittleEndian()),
AddressSize(Obj.getBytesInAddress()) {
for (const SectionRef &Section : Obj.sections()) {
if (IsVirtual)
continue;
StringRef data;
- Section.getContents(data);
+
+ // Try to obtain an already relocated version of this section.
+ // Else use the unrelocated section from the object file. We'll have to
+ // apply relocations ourselves later.
+ if (!L || !L->getLoadedSectionContents(name,data))
+ Section.getContents(data);
name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes.
continue;
StringRef RelSecName;
+ StringRef RelSecData;
RelocatedSection->getName(RelSecName);
+
+ // If the section we're relocating was relocated already by the JIT,
+ // then we used the relocated version above, so we do not need to process
+ // relocations for it now.
+ if (L && L->getLoadedSectionContents(RelSecName,RelSecData))
+ continue;
+
RelSecName = RelSecName.substr(
RelSecName.find_first_not_of("._")); // Skip . and _ prefixes.
uint64_t Type;
Reloc.getType(Type);
uint64_t SymAddr = 0;
+ uint64_t SectionLoadAddress = 0;
object::symbol_iterator Sym = Reloc.getSymbol();
- if (Sym != Obj.symbol_end())
+ object::section_iterator RSec = Reloc.getSection();
+
+ // First calculate the address of the symbol or section as it appears
+ // in the objct file
+ if (Sym != Obj.symbol_end()) {
Sym->getAddress(SymAddr);
+ // Also remember what section this symbol is in for later
+ Sym->getSection(RSec);
+ } else if (RSec != Obj.section_end())
+ SymAddr = RSec->getAddress();
+
+ // If we are given load addresses for the sections, we need to adjust:
+ // SymAddr = (Address of Symbol Or Section in File) -
+ // (Address of Section in File) +
+ // (Load Address of Section)
+ if (L != nullptr && RSec != Obj.section_end()) {
+ // RSec is now either the section being targetted or the section
+ // containing the symbol being targetted. In either case,
+ // we need to perform the same computation.
+ StringRef SecName;
+ RSec->getName(SecName);
+ SectionLoadAddress = L->getSectionLoadAddress(SecName);
+ if (SectionLoadAddress != 0)
+ SymAddr += SectionLoadAddress - RSec->getAddress();
+ }
object::RelocVisitor V(Obj);
object::RelocToApply R(V.visit(Type, Reloc, SymAddr));
getObjectForDebug(const ObjectFile &Obj) const override {
return OwningBinary<ObjectFile>();
}
+
+ RuntimeDyld::LoadedObjectInfo *clone() const { return new LoadedCOFFObjectInfo(*this); }
};
}
OwningBinary<ObjectFile>
getObjectForDebug(const ObjectFile &Obj) const override;
+
+ RuntimeDyld::LoadedObjectInfo *clone() const { return new LoadedELFObjectInfo(*this); }
};
template <typename ELFT>
SectionList Sections;
typedef unsigned SID; // Type for SectionIDs
-#define RTDYLD_INVALID_SECTION_ID ((SID)(-1))
+#define RTDYLD_INVALID_SECTION_ID ((RuntimeDyldImpl::SID)(-1))
// Keep a map of sections from object file to the SectionID which
// references it.
getObjectForDebug(const ObjectFile &Obj) const override {
return OwningBinary<ObjectFile>();
}
+
+ RuntimeDyld::LoadedObjectInfo *clone() const { return new LoadedMachOObjectInfo(*this); }
};
}
Value.Offset = RE.Addend;
}
} else {
- SectionRef Sec = Obj.getRelocationSection(RelInfo);
+ SectionRef Sec = Obj.getAnyRelocationSection(RelInfo);
bool IsCode = Sec.isText();
Value.SectionID = findOrEmitSection(Obj, Sec, IsCode, ObjSectionToID);
uint64_t Addr = Sec.getAddress();
return symbol_iterator(SymbolRef(Ref, this));
}
+section_iterator COFFObjectFile::getRelocationSection(DataRefImpl Rel) const {
+ symbol_iterator Sym = getRelocationSymbol(Rel);
+ if (Sym == symbol_end())
+ return section_end();
+ COFFSymbolRef Symb = getCOFFSymbol(*Sym);
+ if (!Symb.isSection())
+ return section_end();
+ section_iterator Res(section_end());
+ if (getSymbolSection(Sym->getRawDataRefImpl(),Res))
+ return section_end();
+ return Res;
+}
+
std::error_code COFFObjectFile::getRelocationType(DataRefImpl Rel,
uint64_t &Res) const {
const coff_relocation* R = toRel(Rel);
return symbol_iterator(SymbolRef(Sym, this));
}
+section_iterator
+MachOObjectFile::getRelocationSection(DataRefImpl Rel) const {
+ return section_iterator(getAnyRelocationSection(getRelocation(Rel)));
+}
+
std::error_code MachOObjectFile::getRelocationType(DataRefImpl Rel,
uint64_t &Res) const {
MachO::any_relocation_info RE = getRelocation(Rel);
}
SectionRef
-MachOObjectFile::getRelocationSection(
+MachOObjectFile::getAnyRelocationSection(
const MachO::any_relocation_info &RE) const {
if (isRelocationScattered(RE) || getPlainRelocationExternal(RE))
return *section_end();
RUN: llvm-rtdyld -printline %p/Inputs/test-inline.o \
RUN: | FileCheck %s -check-prefix TEST_INLINE
+RUN: llvm-rtdyld -printdebugline %p/Inputs/test-inline.o \
+RUN: | FileCheck %s -check-prefix TEST_INLINE
RUN: llvm-rtdyld -printline %p/Inputs/test-parameters.o \
RUN: | FileCheck %s -check-prefix TEST_PARAMETERS
+RUN: llvm-rtdyld -printdebugline %p/Inputs/test-parameters.o \
+RUN: | FileCheck %s -check-prefix TEST_PARAMETERS
; This test verifies that relocations are correctly applied to the
; .debug_line section and exercises DIContext::getLineInfoForAddressRange().
}
auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
- SectionRef RelocSection = Obj->getRelocationSection(RE);
+ SectionRef RelocSection = Obj->getAnyRelocationSection(RE);
uint64_t SectionAddr = RelocSection.getAddress();
enum ActionType {
AC_Execute,
AC_PrintLineInfo,
+ AC_PrintDebugLineInfo,
AC_Verify
};
"Load, link, and execute the inputs."),
clEnumValN(AC_PrintLineInfo, "printline",
"Load, link, and print line information for each function."),
+ clEnumValN(AC_PrintDebugLineInfo, "printdebugline",
+ "Load, link, and print line information for each function using the debug object"),
clEnumValN(AC_Verify, "verify",
"Load, link and verify the resulting memory image."),
clEnumValEnd));
/* *** */
-static int printLineInfoForInput() {
+static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {
+ assert(LoadObjects || !UseDebugObj);
+
// Load any dylibs requested on the command line.
loadDylibs();
ObjectFile &Obj = **MaybeObj;
- // Load the object file
- std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo =
- Dyld.loadObject(Obj);
+ OwningBinary<ObjectFile> DebugObj;
+ std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr;
+ ObjectFile *SymbolObj = &Obj;
+ if (LoadObjects) {
+ // Load the object file
+ LoadedObjInfo =
+ Dyld.loadObject(Obj);
- if (Dyld.hasError())
- return Error(Dyld.getErrorString());
+ if (Dyld.hasError())
+ return Error(Dyld.getErrorString());
- // Resolve all the relocations we can.
- Dyld.resolveRelocations();
+ // Resolve all the relocations we can.
+ Dyld.resolveRelocations();
- OwningBinary<ObjectFile> DebugObj = LoadedObjInfo->getObjectForDebug(Obj);
+ if (UseDebugObj) {
+ DebugObj = LoadedObjInfo->getObjectForDebug(Obj);
+ SymbolObj = DebugObj.getBinary();
+ }
+ }
std::unique_ptr<DIContext> Context(
- new DWARFContextInMemory(*DebugObj.getBinary()));
+ new DWARFContextInMemory(*SymbolObj,LoadedObjInfo.get()));
// Use symbol info to iterate functions in the object.
- for (object::symbol_iterator I = DebugObj.getBinary()->symbol_begin(),
- E = DebugObj.getBinary()->symbol_end();
+ for (object::symbol_iterator I = SymbolObj->symbol_begin(),
+ E = SymbolObj->symbol_end();
I != E; ++I) {
object::SymbolRef::Type SymType;
if (I->getType(SymType)) continue;
if (I->getAddress(Addr)) continue;
if (I->getSize(Size)) continue;
- outs() << "Function: " << Name << ", Size = " << Size << "\n";
+ // If we're not using the debug object, compute the address of the
+ // symbol in memory (rather than that in the unrelocated object file)
+ // and use that to query the DWARFContext.
+ if (!UseDebugObj && LoadObjects) {
+ object::section_iterator Sec(SymbolObj->section_end());
+ I->getSection(Sec);
+ StringRef SecName;
+ Sec->getName(SecName);
+ uint64_t SectionLoadAddress =
+ LoadedObjInfo->getSectionLoadAddress(SecName);
+ if (SectionLoadAddress != 0)
+ Addr += SectionLoadAddress - Sec->getAddress();
+ }
+
+ outs() << "Function: " << Name << ", Size = " << Size << ", Addr = " << Addr << "\n";
DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
DILineInfoTable::iterator Begin = Lines.begin();
switch (Action) {
case AC_Execute:
return executeInput();
+ case AC_PrintDebugLineInfo:
+ return printLineInfoForInput(true,true);
case AC_PrintLineInfo:
- return printLineInfoForInput();
+ return printLineInfoForInput(true,false);
case AC_Verify:
return linkAndVerify();
}