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.)
This commit is contained in:
Brandon Potter 2016-03-17 10:34:27 -07:00
parent de8077763e
commit 4a9dd1feb8
17 changed files with 188 additions and 66 deletions

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -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;

View file

@ -48,10 +48,13 @@ class AoutObject : public ObjectFile
public:
virtual ~AoutObject() {}
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max());
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::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);

View file

@ -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;

View file

@ -66,10 +66,12 @@ class DtbObject : public ObjectFile
*/
Addr findReleaseAddr();
bool loadGlobalSymbols(SymbolTable *symtab,
Addr addrMask = std::numeric_limits<Addr>::max());
bool loadLocalSymbols(SymbolTable *symtab,
Addr addrMask = std::numeric_limits<Addr>::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.

View file

@ -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;

View file

@ -51,10 +51,12 @@ class EcoffObject : public ObjectFile
public:
virtual ~EcoffObject() {}
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max());
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::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);

View file

@ -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

View file

@ -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<Addr>::max(),
Addr offset = 0) override;
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max()) override;
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max()) override;
virtual bool loadWeakSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::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; }

View file

@ -82,15 +82,19 @@ class ObjectFile
public:
virtual ~ObjectFile();
virtual bool loadSections(PortProxy& memProxy, Addr addrMask =
std::numeric_limits<Addr>::max(),
Addr offset = 0);
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max()) = 0;
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max()) = 0;
virtual bool loadWeakSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max())
static const Addr maxAddr = std::numeric_limits<Addr>::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; }

View file

@ -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;
}

View file

@ -41,10 +41,13 @@ class RawObject: public ObjectFile
public:
virtual ~RawObject() {}
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max());
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::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);

View file

@ -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();
}

View file

@ -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();

View file

@ -57,18 +57,20 @@
#ifdef __CYGWIN32__
#include <sys/fcntl.h> // for O_BINARY
#endif
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <cerrno>
#include <string>
#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).