// Elf - interning of Elf DSOs
// Copyright (C) 1998,1999 Colin McCormack,
// see LICENSE (MD5 f5220f8f599e5e926f37cf32efe3ab68) for terms
// $Id
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <elf.h>
#include <qvmm.h>
#include <Q.hh>
// Have to take .so files,
// dig out the symbols needed,
// find their length,
// allocate that space in the store,
// spit out a new companion .s file defining those symbols,
// compile it up,
// and dlopen() the resultant .so before the target .so.
class Elf; // forward reference
//struct Elf32_Sym; // external reference to libelf's Symbols
/** Interned Symbols from @ref Elf objects
* @author Colin McCormack colin@field.medicine.adelaide.edu.au
*
* Each symbol interned from an @ref Elf object has a corresponding Csym
* which is mapped into the store and contains storage for the symbol.
*
* In the case of a DATA or VTBL type Csym, the storage contains
* the content of the symbol from the original Elf. In the case of a
* FUNCTION type, the storage contains an absolute JMP into the Elf
* object's function.
*/
class Csym
: public Q<Csym>, // Q of symbols in a given Elf
Memory
{
public:
/** symbol type
* FUNCTION a function symbol
* DATA a data symbol
* VTBL a vtable
* UNKNOWN not found
*/
enum Type {
FUNCTION,
DATA,
VTBL,
UNKNOWN
}; // symbol type (F,V or O)
/** Elf this Csym is in
*/
const Elf *in;
private:
friend class Elf; // only Elf can create Csyms
/** symbol type (F,V or O)
*/
Type _type;
/** allocated length of this Csym
*/
unsigned _len;
/** true if this Csym's been loaded
* that is, its Elf has been loaded,
* and the Csym was found and has been relocated.
*/
bool loaded;
/** mangled name of Csym
*/
char name[256];
/** content of Csym (longword aligned)
* ***** HAS TO BE LAST DATA MEMBER IN CLASS! *****
*/
char content[0];
static const int JMP = 0xE9; // absolute JMP opcode
/** construct a Csym - can only be called by Elf
* @param elf the @ref Elf with which this is associated
* @param mangled the symbol's mangled name
* @param the Type of the symbol
* @param len the length of allocation for the symbol
*/
Csym(Elf *elf, const char *mangled, enum Type type, int len);
/** can never destroy a Csym, some Builtin may reference it.
*/
~Csym();
/** reset this Csym to an unloaded state
*/
void reset();
/** copy-relocate contents from original to this Csym symbol
* @param so dlopen()-returned value for the source Elf
*/
void reloc(void *so);
public:
/** Csym's mangled name
* @returns mangled name of Csym
*/
const char *symname() const {
return name;
}
/** address of the Csym's coldstored content
* @returns address of the symbol's content
* @exception undefined
*/
void *address() const {
if (_type != UNKNOWN)
return (void *)content;
else
throw "Csym is undefined";
}
/** virtual type implemented by this vtbl
* @returns type implemented by this vtbl
* @exception not-loaded not-VTBL
*/
void *vtype() const {
if (_type == VTBL && loaded) {
//cerr << "vtype " << (void*)content << '\n';
return (void *)content;
} else
throw "Csym is not a loaded VTBL";
}
/** call the function represented by this symbol
* @param arg a single void* argument to the function
* @returns whatever's returned by the call
* @exception not-loaded not-FUNCTION
*/
void *call(void *arg) const {
if (_type == FUNCTION && loaded) {
void *(*fn)(void *) = (void *(*)(void*))address();
return (*fn)(arg);
} else
throw "Csym is not a loaded FUNCTION";
}
/** allocation length
* @returns symbol's allocation length
* @exception undefined
*/
unsigned len() const {
if (_type != UNKNOWN)
return _len;
else
throw "Csym is undefined";
}
/** Csym type
* @returns type of the Csym
*/
enum Type type() const {
return _type;
}
/** predicate: is Csym loaded?
* @returns true iff Csym has been loaded
*/
bool isLoaded() const;
};
extern "C" {
struct link_map;
}
class ElfExe;
/** Elf class - permits the dynamic interning of Elf DSOs
* @author Colin McCormack colin@field.medicine.adelaide.edu.au
*
* Elf instances have Csyms Q'd off them, one for each interned symbol.
*
* Symbols may be requested to be interned, by using addSym to associate
* the Csym with the Elf, or may be added automatically (if they represent
* vtables, for example.)
*/
class Elf
: public Q<Elf>, // Q of all the Elf objects
public Memory
{
public:
/** persistent header of Elf Q */
static Qh<Elf> all;
/** modifies the Elf symbol snarfing process
*
* COLDSTORE snarf ColdStore constructors
* in addition to DEFAULT_P
*
* STL snarf all global functional symbols
* in addition to DEFAULT_P
*
* DEFAULT_P snarf only requested symbols
* and vtables
*/
enum Policy {
COLDSTORE,
STL,
DEFAULT_P
};
/** Q of all the symbols defined
*/
mutable Qh<Csym> symbols;
protected:
/** .so name implementing the Elf
*/
char elf[257];
/** size set aside trampolining functions
*/
static const int functSize = 20;
/** Elf target for BFD
*/
static const char *const elf_target = "elf32-i386";
/** Elf architecture for BFD
*/
static const char *const elf_arch = "i386";
/** run through all Elfs and reset them to a clean state
* persistent references to .so handles must be NULLed
*/
void reset();
private:
/** create a Csym given an Elf32 symbol
* Called from snarf
*/
Csym *snarfSym(char *symname, Elf32_Sym *sym);
/** can never destroy a Elf, some Builtin may reference it.
*/
~Elf();
static ElfExe *exe;
friend class ElfExe;// dummy to stop errors about private destructor
/** snarf the interesting symbols from the .so file
* the output of this phase is a Q of Csym objects
* @param personality @ref Elf::Policy determining which symbols to intern
*/
void snarf(Policy personality = DEFAULT_P);
/** create shadow symbol definitions for Elf's Csyms
*/
int shadow();
/** load the shadowed Elf .so file
*/
void load();
/** resolve Csyms in shadowed Elf .so files
*/
void resolve();
public:
/** dlopen handle for main Elf
*/
link_map *_so;
/** create an Elf
* @param name filename of elf DSO
*/
Elf(const char *name);
/** intern an Elf and all its Csyms
* @param policy @ref Elf::Policy for interning
*/
void intern(Policy policy);
/** iterate over all Elf,
* calling a function on each instance
* @param fn function to call on each @ref Elf instance
*/
static void forallElf(void (fn)(Elf*));
/** iterate over all Csym in this Elf,
* calling a function on each instance
* @param fn function to call on each (@ref Elf, @ref Csym) pair
*/
void forallSym(void (fn)(Elf*,Csym*));
/** Q of all Csyms interned by this Elf
* @returns the @ref Q of all Csyms for this
*/
const Csym *symQ() const {
return symbols;
}
/** called once on startup to reset Elfs
* @param _exe an @ref ElfExe instance to enable new symbol definition
*/
static void initialize(ElfExe *_exe);
/** close this Elf
*/
void close();
/** find an Elf by name
* @param elf file name of elf
* @returns the @ref Elf with this name, or NULL
*/
static Elf *findElf(const char *elf);
/** find a Csym by name
* @param symname symbol name
* @returns the @ref Csym with this name, or NULL
*/
Csym *findSym(const char *symname) const;
/** add an undefined Csym if it doesn't already exist
* used to request the interning of symbols
* @param sym symbol name
* @returns a @ref Csym with this name
*/
bool addSym(const char *sym);
/** predicate: has this Elf been loaded?
* @returns true iff this Elf has been loaded
*/
bool isLoaded() const {
return _so != NULL;
}
/** create a Csym interned by this Elf
* @param mangled symbol name
* @param type symbol type
* @param size size of symbol's allocation
* @returns a @ref Csym with this name
*/
Csym *csym(const char *mangled, Csym::Type type, int size);
/** Elf's .so name
* @returns elf's DSO file name
*/
const char *name() const {
return elf;
}
/** find a simple C symbol in Elf
* @param name C symbol name
* @returns symbol's value
*/
void *getSym(const char *name) const;
};
/** load an Elf
*/
void *loadElf(char *name,
Elf::Policy type = Elf::DEFAULT_P);
/** elf autoloading and interning
* @author Colin McCormack colin@field.medicine.adelaide.edu.au
*
* The InitElf instance, when created:
* @li looks for a NULL terminated variable named: AutoLoad autoload_elfs[]
* @li interns each named library with the given policy
* @li calls the named function with a pointer to its @ref Elf
*/
struct AutoLoad {
/** file name of the elf DSO to autoload
*/
char *name;
/** what kind of interning @ref Elf::Policy to apply?
*/
Elf::Policy type;
/** mangled name of a function to call after the library's been
* loaded, interned and initialised.
*
* Underlying function should be of type void fn(Elf *)
*/
char *initFn;
};
/** class to initialize Elf
* @author Colin McCormack colin@field.medicine.adelaide.edu.au
*
* InitElf is instantiated once and only once, by elf.so.
*
* InitElf arranges for the
* initialization of the elf.so module and the autoloading of modules
* @see AutoLoad
*/
class InitElf
{
private:
ElfExe *exe;
link_map *main_so;
link_map *elf;
// loadElf()
void *load(const char *name, int flags = RTLD_LAZY);
void *getSym(void *so, char *name, bool chuck = true);
/** copy symbol contents from .so into the store.
*/
char *copy_reloc(void *from, char *what, size_t len);
public:
/** initialize the Elf interning library
* @param elflib the name of the elf.so lib
* @returns THE InitElf instance
*/
InitElf(const char *elflib="../libs/elf.so");
/** shut down the Elf interning library
*/
~InitElf();
};
// Local Variables:
// mode:C++
// End:
| Generated by: colin@sharedtech.dhis.org on Sat Nov 6 11:59:21 199. |