From 4a9dd1feb846e015303196ad5274a829a7c18525 Mon Sep 17 00:00:00 2001 From: Brandon Potter Date: Thu, 17 Mar 2016 10:34:27 -0700 Subject: [PATCH] base: add symbol support for dynamic libraries Libraries are loaded into the process address space using the mmap system call. Conveniently, this happens to be a good time to update the process symbol table with the library's incoming symbols so we handle the table update from within the system call. This works just like an application's normal symbols. The only difference between a dynamic library and a main executable is when the symbol table update occurs. The symbol table update for an executable happens at program load time and is finished before the process ever begins executing. Since dynamic linking happens at runtime, the symbol loading happens after the library is first loaded into the process address space. The library binary is examined at this time for a symbol section and that section is parsed for symbol types with specific bindings (global, local, weak). Subsequently, these symbols are added to the table and are available for use by gem5 for things like trace generation. Checkpointing should work just as it did previously. The address space (and therefore the library) will be recorded and the symbol table will be entirely recorded. (It's not possible to do anything clever like checkpoint a program and then load the program back with different libraries with LD_LIBRARY_PATH, because the library becomes part of the address space after being loaded.) --- src/arch/arm/freebsd/system.cc | 4 +-- src/arch/arm/linux/system.cc | 4 +-- src/arch/sparc/system.cc | 2 +- src/base/loader/aout_object.cc | 13 +++++++-- src/base/loader/aout_object.hh | 11 +++++--- src/base/loader/dtb_object.cc | 12 ++++++-- src/base/loader/dtb_object.hh | 10 ++++--- src/base/loader/ecoff_object.cc | 14 ++++++++-- src/base/loader/ecoff_object.hh | 10 ++++--- src/base/loader/elf_object.cc | 49 +++++++++++++++++++++++++-------- src/base/loader/elf_object.hh | 31 ++++++++++++++------- src/base/loader/object_file.hh | 24 +++++++++------- src/base/loader/raw_object.cc | 17 +++++++++--- src/base/loader/raw_object.hh | 11 +++++--- src/sim/process.cc | 11 ++++++-- src/sim/process.hh | 2 ++ src/sim/syscall_emul.hh | 29 ++++++++++++++++++- 17 files changed, 188 insertions(+), 66 deletions(-) diff --git a/src/arch/arm/freebsd/system.cc b/src/arch/arm/freebsd/system.cc index d6f3e4e9a..da427e832 100644 --- a/src/arch/arm/freebsd/system.cc +++ b/src/arch/arm/freebsd/system.cc @@ -86,8 +86,8 @@ FreebsdArmSystem::initState() // to do this permanently, for but early bootup work // it is helpful. if (params()->early_kernel_symbols) { - kernel->loadGlobalSymbols(kernelSymtab, loadAddrMask); - kernel->loadGlobalSymbols(debugSymbolTable, loadAddrMask); + kernel->loadGlobalSymbols(kernelSymtab, 0, 0, loadAddrMask); + kernel->loadGlobalSymbols(debugSymbolTable, 0, 0, loadAddrMask); } // Setup boot data structure diff --git a/src/arch/arm/linux/system.cc b/src/arch/arm/linux/system.cc index c22ce160f..a78bab5bf 100644 --- a/src/arch/arm/linux/system.cc +++ b/src/arch/arm/linux/system.cc @@ -110,8 +110,8 @@ LinuxArmSystem::initState() // to do this permanently, for but early bootup work // it is helpful. if (params()->early_kernel_symbols) { - kernel->loadGlobalSymbols(kernelSymtab, loadAddrMask); - kernel->loadGlobalSymbols(debugSymbolTable, loadAddrMask); + kernel->loadGlobalSymbols(kernelSymtab, 0, 0, loadAddrMask); + kernel->loadGlobalSymbols(debugSymbolTable, 0, 0, loadAddrMask); } // Setup boot data structure diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc index b6fa645ce..5c7f06db3 100644 --- a/src/arch/sparc/system.cc +++ b/src/arch/sparc/system.cc @@ -115,7 +115,7 @@ SparcSystem::SparcSystem(Params *p) // Strip off the rom address so when the hypervisor is copied into memory we // have symbols still - if (!hypervisor->loadLocalSymbols(debugSymbolTable, 0xFFFFFF)) + if (!hypervisor->loadLocalSymbols(debugSymbolTable, 0, 0, 0xFFFFFF)) panic("could not load hypervisor symbols\n"); if (!nvram->loadGlobalSymbols(debugSymbolTable)) diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc index 07acc8fbd..468b1b1f0 100644 --- a/src/base/loader/aout_object.cc +++ b/src/base/loader/aout_object.cc @@ -80,14 +80,23 @@ AoutObject::AoutObject(const string &_filename, bool -AoutObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) +AoutObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) +{ + return false; +} + +bool +AoutObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { // a.out symbols not supported yet return false; } bool -AoutObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) +AoutObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { // a.out symbols not supported yet return false; diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh index 110dcfd36..65ed7ca0f 100644 --- a/src/base/loader/aout_object.hh +++ b/src/base/loader/aout_object.hh @@ -48,10 +48,13 @@ class AoutObject : public ObjectFile public: virtual ~AoutObject() {} - virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()); - virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()); + virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr); + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, + Addr addr_mask = maxAddr); + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr); static ObjectFile *tryFile(const std::string &fname, size_t len, uint8_t *data); diff --git a/src/base/loader/dtb_object.cc b/src/base/loader/dtb_object.cc index ead667f11..e9bbceec4 100644 --- a/src/base/loader/dtb_object.cc +++ b/src/base/loader/dtb_object.cc @@ -171,16 +171,24 @@ DtbObject::findReleaseAddr() return rel_addr; } +bool +DtbObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) +{ + return false; +} bool -DtbObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) +DtbObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { // nothing to do here return false; } bool -DtbObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) +DtbObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { // nothing to do here return false; diff --git a/src/base/loader/dtb_object.hh b/src/base/loader/dtb_object.hh index 451b52a4c..c49b144ac 100644 --- a/src/base/loader/dtb_object.hh +++ b/src/base/loader/dtb_object.hh @@ -66,10 +66,12 @@ class DtbObject : public ObjectFile */ Addr findReleaseAddr(); - bool loadGlobalSymbols(SymbolTable *symtab, - Addr addrMask = std::numeric_limits::max()); - bool loadLocalSymbols(SymbolTable *symtab, - Addr addrMask = std::numeric_limits::max()); + bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addrMask = maxAddr); + bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addrMask = maxAddr); + bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addrMask = maxAddr); /** Static function that tries to load file as a * flattened device tree blob. diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc index c3c1c1108..1869efa13 100644 --- a/src/base/loader/ecoff_object.cc +++ b/src/base/loader/ecoff_object.cc @@ -89,9 +89,18 @@ EcoffObject::EcoffObject(const string &_filename, size_t _len, uint8_t *_data, bss.baseAddr, bss.size); } +bool +EcoffObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) +{ + bool retval = loadGlobalSymbols(symtab, base, offset, addr_mask); + retval = retval && loadLocalSymbols(symtab, base, offset, addr_mask); + return retval; +} bool -EcoffObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) +EcoffObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { if (!symtab) return false; @@ -120,7 +129,8 @@ EcoffObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) } bool -EcoffObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) +EcoffObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { if (!symtab) return false; diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh index 0a5a43f72..b1ae91107 100644 --- a/src/base/loader/ecoff_object.hh +++ b/src/base/loader/ecoff_object.hh @@ -51,10 +51,12 @@ class EcoffObject : public ObjectFile public: virtual ~EcoffObject() {} - virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()); - virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()); + virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr); + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr); + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr); static ObjectFile *tryFile(const std::string &fname, size_t len, uint8_t *data); diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index fb5ec4c14..73c1c5dcd 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -396,7 +396,8 @@ ElfObject::ElfObject(const std::string &_filename, size_t _len, bool -ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask) +ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask, + Addr base, Addr offset) { if (!symtab) return false; @@ -432,9 +433,11 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask) if (GELF_ST_BIND(sym.st_info) == binding) { char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name); if (sym_name && sym_name[0] != '$') { - DPRINTF(Loader, "Symbol: %-40s value %#x\n", - sym_name, sym.st_value); - symtab->insert(sym.st_value & mask, sym_name); + Addr value = sym.st_value - base + offset; + if (symtab->insert(value & mask, sym_name)) { + DPRINTF(Loader, "Symbol: %-40s value %#x\n", + sym_name, value); + } } } } @@ -449,23 +452,45 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask) } bool -ElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addr_mask) +ElfObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { - return loadSomeSymbols(symtab, STB_GLOBAL, addr_mask); + return (loadGlobalSymbols(symtab, base, offset, addr_mask) && + loadLocalSymbols(symtab, base, offset, addr_mask) && + loadWeakSymbols(symtab, base, offset, addr_mask)); } bool -ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addr_mask) +ElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { - bool found_local = loadSomeSymbols(symtab, STB_LOCAL, addr_mask); - bool found_weak = loadSomeSymbols(symtab, STB_WEAK, addr_mask); - return found_local || found_weak; + if (interpreter) { + interpreter->loadSomeSymbols(symtab, STB_GLOBAL, addr_mask, + base, offset); + } + return loadSomeSymbols(symtab, STB_GLOBAL, addr_mask, base, offset); } bool -ElfObject::loadWeakSymbols(SymbolTable *symtab, Addr addr_mask) +ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { - return loadSomeSymbols(symtab, STB_WEAK, addr_mask); + if (interpreter) { + interpreter->loadSomeSymbols(symtab, STB_LOCAL, addr_mask, + base, offset); + } + return loadSomeSymbols(symtab, STB_LOCAL, addr_mask, base, offset); +} + +bool +ElfObject::loadWeakSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) +{ + if (interpreter) { + interpreter->loadSomeSymbols(symtab, STB_WEAK, addr_mask, + base, offset); + } + return loadSomeSymbols(symtab, STB_WEAK, addr_mask, base, offset); } bool diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh index cec20a47a..aa28cd62a 100644 --- a/src/base/loader/elf_object.hh +++ b/src/base/loader/elf_object.hh @@ -81,7 +81,8 @@ class ElfObject : public ObjectFile Addr ldMax; /// Helper functions for loadGlobalSymbols() and loadLocalSymbols(). - bool loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask); + bool loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask, + Addr base, Addr offset); ElfObject(const std::string &_filename, size_t _len, uint8_t *_data, Arch _arch, OpSys _opSys); @@ -94,15 +95,25 @@ class ElfObject : public ObjectFile public: virtual ~ElfObject() {} - bool loadSections(PortProxy& memProxy, - Addr addrMask = std::numeric_limits::max(), - Addr offset = 0) override; - virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()) override; - virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()) override; - virtual bool loadWeakSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()) override; + bool loadSections(PortProxy& mem_proxy, Addr addr_mask = maxAddr, + Addr offset = 0) override; + + virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr) + override; + + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr) + override; + + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr) + override; + + virtual bool loadWeakSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr) + override; + virtual ObjectFile *getInterpreter() const override { return interpreter; } diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index fb30118e0..b2628a0d0 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -82,15 +82,19 @@ class ObjectFile public: virtual ~ObjectFile(); - virtual bool loadSections(PortProxy& memProxy, Addr addrMask = - std::numeric_limits::max(), - Addr offset = 0); - virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()) = 0; - virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()) = 0; - virtual bool loadWeakSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()) + static const Addr maxAddr = std::numeric_limits::max(); + + virtual bool loadSections(PortProxy& mem_proxy, + Addr mask = maxAddr, Addr offset = 0); + + virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr mask = maxAddr) = 0; + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr mask = maxAddr) = 0; + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr mask = maxAddr) = 0; + virtual bool loadWeakSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr mask = maxAddr) { return false; } virtual ObjectFile *getInterpreter() const { return nullptr; } @@ -121,7 +125,7 @@ class ObjectFile Section data; Section bss; - bool loadSection(Section *sec, PortProxy& memProxy, Addr addrMask, + bool loadSection(Section *sec, PortProxy& mem_proxy, Addr mask, Addr offset = 0); void setGlobalPointer(Addr global_ptr) { globalPtr = global_ptr; } diff --git a/src/base/loader/raw_object.cc b/src/base/loader/raw_object.cc index 73d8372ef..35a952741 100644 --- a/src/base/loader/raw_object.cc +++ b/src/base/loader/raw_object.cc @@ -62,21 +62,30 @@ RawObject::RawObject(const std::string &_filename, size_t _len, } bool -RawObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) +RawObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) +{ + return true; +} + +bool +RawObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { /* int fnameStart = filename.rfind('/',filename.size()) + 1; int extStart = filename.rfind('.',filename.size()); - symtab->insert(text.baseAddr & addrMask, filename.substr(fnameStart, + symtab->insert(text.baseAddr & addr_mask, filename.substr(fnameStart, extStart-fnameStart) + "_start");*/ return true; } bool -RawObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) +RawObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, + Addr addr_mask) { /* int fnameStart = filename.rfind('/',filename.size()) + 1; int extStart = filename.rfind('.',filename.size()); - symtab->insert(text.baseAddr & addrMask, filename.substr(fnameStart, + symtab->insert(text.baseAddr & addr_mask, filename.substr(fnameStart, extStart-fnameStart) + "_start");*/ return true; } diff --git a/src/base/loader/raw_object.hh b/src/base/loader/raw_object.hh index 3865425d0..6931a1321 100644 --- a/src/base/loader/raw_object.hh +++ b/src/base/loader/raw_object.hh @@ -41,10 +41,13 @@ class RawObject: public ObjectFile public: virtual ~RawObject() {} - virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()); - virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = - std::numeric_limits::max()); + virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr); + virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, + Addr addr_mask = maxAddr); + virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0, + Addr offset = 0, Addr addr_mask = maxAddr); static ObjectFile *tryFile(const std::string &fname, size_t len, uint8_t *data); diff --git a/src/sim/process.cc b/src/sim/process.cc index 7fa160995..d0dd3d92b 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -543,10 +543,17 @@ LiveProcess::updateBias() } +ObjectFile * +LiveProcess::getInterpreter() +{ + return objFile->getInterpreter(); +} + + Addr LiveProcess::getBias() { - ObjectFile *interp = objFile->getInterpreter(); + ObjectFile *interp = getInterpreter(); return interp ? interp->bias() : objFile->bias(); } @@ -555,7 +562,7 @@ LiveProcess::getBias() Addr LiveProcess::getStartPC() { - ObjectFile *interp = objFile->getInterpreter(); + ObjectFile *interp = getInterpreter(); return interp ? interp->entryPoint() : objFile->entryPoint(); } diff --git a/src/sim/process.hh b/src/sim/process.hh index aa4c7a008..54e6b2df2 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -341,6 +341,8 @@ class LiveProcess : public Process // bias are not available when the object file is created. void updateBias(); + ObjectFile *getInterpreter(); + Addr getBias(); Addr getStartPC(); diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index 71c0dd090..e9ed130f0 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -57,18 +57,20 @@ #ifdef __CYGWIN32__ #include // for O_BINARY + #endif +#include #include #include #include #include -#include #include #include #include "base/chunk_generator.hh" #include "base/intmath.hh" // for RoundUp +#include "base/loader/object_file.hh" #include "base/misc.hh" #include "base/trace.hh" #include "base/types.hh" @@ -1354,6 +1356,31 @@ mmapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, // Cleanup the mmap region before exiting this function. munmap(pmap, length); + // Maintain the symbol table for dynamic executables. + // The loader will call mmap to map the images into its address + // space and we intercept that here. We can verify that we are + // executing inside the loader by checking the program counter value. + // XXX: with multiprogrammed workloads or multi-node configurations, + // this will not work since there is a single global symbol table. + ObjectFile *interpreter = p->getInterpreter(); + if (interpreter) { + Addr text_start = interpreter->textBase(); + Addr text_end = text_start + interpreter->textSize(); + + Addr pc = tc->pcState().pc(); + + if (pc >= text_start && pc < text_end) { + FDEntry *fde = p->getFDEntry(tgt_fd); + + ObjectFile *lib = createObjectFile(fde->filename); + + if (lib) { + lib->loadAllSymbols(debugSymbolTable, + lib->textBase(), start); + } + } + } + // Note that we do not zero out the remainder of the mapping. This // is done by a real system, but it probably will not affect // execution (hopefully). -- 2.30.2