|
|
// 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. |