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

Reply via email to