Adds a fully-documented API for dynamically loading libraries and looking up symbols or addresses in them.
Signed-off-by: Zachary T Welch <z...@superlucidity.net> --- src/helper/Makefile.am | 2 + src/helper/module.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ src/helper/module.h | 73 ++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 0 deletions(-) create mode 100644 src/helper/module.c create mode 100644 src/helper/module.h diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index 22b3c33..13bcbd1 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -20,6 +20,7 @@ libhelper_la_SOURCES = \ configuration.c \ log.c \ command.c \ + module.c \ time_support.c \ replacements.c \ fileio.c \ @@ -42,6 +43,7 @@ noinst_HEADERS = \ log.h \ command.h \ membuf.h \ + module.h \ time_support.h \ replacements.h \ fileio.h \ diff --git a/src/helper/module.c b/src/helper/module.c new file mode 100644 index 0000000..145baa4 --- /dev/null +++ b/src/helper/module.c @@ -0,0 +1,96 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "module.h" +#include <dlfcn.h> +#include "log.h" + +struct module_instance { + /// Name of the module. + char *name; + /// The handle returned from dlopen + void *dlhandle; +}; + +void module_free(struct module_instance *module) +{ + if (NULL != module->name) + free(module->name); + if (NULL != module->dlhandle) + dlclose(module->dlhandle); + free(module); +} + +struct module_instance *module_load(const char *name) +{ + struct module_instance *module = calloc(1, sizeof(*module)); + if (NULL == module) + return NULL; + + module->dlhandle = dlopen(name, RTLD_NOW); + if (NULL == module->dlhandle) + goto module_load_error; + + if (NULL == name) + name = "<program>"; + + module->name = strdup(name); + if (NULL == module->name) + goto module_load_error; + + return module; + +module_load_error: + module_free(module); + return NULL; +} + +struct module_symbol *module_symbol_by_addr(void *addr) +{ + struct module_symbol *sym = calloc(1, sizeof(*sym)); + if (NULL == sym) + return NULL; + + Dl_info info; + int retval = dladdr(addr, &info); + if (0 == retval) + { + free(sym); + return NULL; + } + + sym->so_name = info.dli_fname; + sym->so_addr = info.dli_fbase; + sym->sym_name = info.dli_sname; + if (NULL != sym->sym_name) { + sym->sym_addr = info.dli_saddr; + sym->sym_offset = addr - sym->sym_addr; + } else { + sym->sym_addr = addr; + sym->sym_offset = 0; + } + + if (NULL == sym->so_name) + sym->so_name = "<unknown>"; + if (NULL == sym->sym_name) + sym->sym_name = "<unknown>"; + return sym; +} + +struct module_symbol *module_symbol_by_name(struct module_instance *module, + const char *name) +{ + void *addr = dlsym(module->dlhandle, name); + return module_symbol_by_addr(addr); +} + +void module_symbol_free(struct module_symbol *sym) +{ + assert(sym); + free(sym); +} + +const char *module_last_error(void) +{ + return dlerror(); +} diff --git a/src/helper/module.h b/src/helper/module.h new file mode 100644 index 0000000..d6d75d7 --- /dev/null +++ b/src/helper/module.h @@ -0,0 +1,73 @@ +#ifndef HELPER_MODULE_H +#define HELPER_MODULE_H + +#include "types.h" + +struct module_instance; + +struct module_symbol { + /// shared library name + const char *so_name; + /// shared library base address + void *so_addr; + /// current symbol name + const char *sym_name; + /// current symbol base address + void *sym_addr; + /// current location (on or after the current symbol, but before next) + ssize_t sym_offset; +}; + +/** + * Load the module with the given name. + * @param name The name of the module to load, or NULL to load the + * main application. + * @returns Returns the new module_instance for the named module, or + * NULL on failure. Use module_last_error() to discover the cause. + */ +struct module_instance *module_load(const char *name); + +/** + * Release the resources associated with a loaded module instance. + * No code may be called from this module after this call, so any + * provided entities must be unregistered and deallocated first. + * @param module The module that should be unloaded. + */ +void module_free(struct module_instance *module); + +/** + * Find a symbol by name in the specified module. + * @param module The module to search. + * @param name The name of the symbol to find. + * @returns On success, returns the symbol; otherwise, returns NULL. + * Use module_last_error() to discover the cause. + */ +struct module_symbol *module_symbol_by_name(struct module_instance *module, + const char *name); + +/** + * Lookup a module symbol from its corresponding address. Used to + * produce meaningful backtraces. + * @param addr The address of the symbol to resolve. + * @returns the symbol that was resolved, or NULL on failure. Use + * module_last_error() to discover the cause of the failure. + */ +struct module_symbol *module_symbol_by_addr(void *addr); + +/** + * Release the resources associated with a module symbol. + * @param sym The symbol that can be freed. + */ +void module_symbol_free(struct module_symbol *sym); + +/** + * If any of the other @c module_* routines fail, this returns a string + * containing the message of the failure. May be called more than once + * if multiple errors may be expected. + * @returns An error string, or NULL if no errors are known. If an + * error occured in another API but NULL is returned by this function, + * then an error code will be found in @c errno. + */ +const char *module_last_error(void); + +#endif // HELPER_MODULE_H -- 1.6.4.4 _______________________________________________ Openocd-development mailing list Openocd-development@lists.berlios.de https://lists.berlios.de/mailman/listinfo/openocd-development