| /* |
| * YASM module loader |
| * |
| * Copyright (C) 2002 Peter Johnson |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| #include <util.h> |
| /*@unused@*/ RCSID("$Id$"); |
| |
| #include <libyasm/compat-queue.h> |
| #include <libyasm.h> |
| |
| #ifdef HAVE_LIBGEN_H |
| #include <libgen.h> |
| #endif |
| |
| #include "ltdl.h" |
| |
| #include "yasm-module.h" |
| |
| |
| extern const lt_dlsymlist lt_preloaded_symbols[]; |
| |
| typedef struct module { |
| SLIST_ENTRY(module) link; |
| module_type type; /* module type */ |
| /*@only@*/ char *type_str; |
| char *keyword; /* module keyword */ |
| lt_dlhandle handle; /* dlopen handle */ |
| } module; |
| |
| static SLIST_HEAD(modulehead, module) modules = SLIST_HEAD_INITIALIZER(modules); |
| |
| static const char *module_type_str[] = { |
| "arch", |
| "dbgfmt", |
| "objfmt", |
| "listfmt", |
| "optimizer", |
| "parser", |
| "preproc" |
| }; |
| |
| static /*@dependent@*/ /*@null@*/ module * |
| load_module(module_type type, const char *keyword) |
| { |
| module *m; |
| char *name; |
| lt_dlhandle handle; |
| size_t typelen; |
| |
| /* See if the module has already been loaded. */ |
| SLIST_FOREACH(m, &modules, link) { |
| if (m->type == type && yasm__strcasecmp(m->keyword, keyword) == 0) |
| return m; |
| } |
| |
| /* Look for dynamic module. First build full module name from keyword. */ |
| typelen = strlen(module_type_str[type]); |
| name = yasm_xmalloc(typelen+strlen(keyword)+2); |
| strcpy(name, module_type_str[type]); |
| strcat(name, "_"); |
| strcat(name, keyword); |
| handle = lt_dlopenext(name); |
| |
| if (!handle) { |
| yasm_xfree(name); |
| return NULL; |
| } |
| |
| m = yasm_xmalloc(sizeof(module)); |
| m->type = type; |
| m->type_str = name; |
| name[typelen] = '\0'; |
| m->keyword = &name[typelen+1]; |
| m->handle = handle; |
| SLIST_INSERT_HEAD(&modules, m, link); |
| return m; |
| } |
| |
| void |
| unload_modules(void) |
| { |
| module *m; |
| |
| while (!SLIST_EMPTY(&modules)) { |
| m = SLIST_FIRST(&modules); |
| SLIST_REMOVE_HEAD(&modules, link); |
| yasm_xfree(m->type_str); |
| lt_dlclose(m->handle); |
| yasm_xfree(m); |
| } |
| } |
| |
| void * |
| get_module_data(module_type type, const char *keyword, const char *symbol) |
| { |
| char *name; |
| /*@dependent@*/ module *m; |
| void *data; |
| |
| /* Load module */ |
| m = load_module(type, keyword); |
| if (!m) |
| return NULL; |
| |
| name = yasm_xmalloc(strlen(keyword)+strlen(symbol)+11); |
| |
| strcpy(name, "yasm_"); |
| strcat(name, keyword); |
| strcat(name, "_LTX_"); |
| strcat(name, symbol); |
| |
| /* Find and return data pointer: NULL if it doesn't exist */ |
| data = lt_dlsym(m->handle, name); |
| |
| yasm_xfree(name); |
| return data; |
| } |
| |
| typedef struct list_module_info { |
| SLIST_ENTRY(list_module_info) link; |
| char keyword[20]; |
| char name[60]; |
| } list_module_info; |
| |
| typedef struct list_module_data { |
| module_type type; |
| list_module_info *matches; |
| size_t matches_num, matches_alloc; |
| } list_module_data; |
| |
| static int |
| list_module_load(const char *filename, lt_ptr data) |
| { |
| list_module_data *lmdata = data; |
| const char *base; |
| const char *module_keyword = NULL, *module_name = NULL; |
| char *name; |
| |
| yasm_arch_module *arch_module; |
| yasm_dbgfmt_module *dbgfmt_module; |
| yasm_objfmt_module *objfmt_module; |
| yasm_listfmt_module *listfmt_module; |
| yasm_optimizer_module *optimizer_module; |
| yasm_parser_module *parser_module; |
| yasm_preproc_module *preproc_module; |
| |
| lt_dlhandle handle; |
| |
| /* Strip off path components, if any */ |
| base = basename(filename); |
| if (!base) |
| return 0; |
| |
| /* All modules have '_' in them; early check */ |
| if (!strchr(base, '_')) |
| return 0; |
| |
| /* Check to see if module is of the type we're looking for. |
| * Even though this check is also implicitly performed below, there's a |
| * massive speedup in avoiding the dlopen() call. |
| */ |
| if (strncmp(base, module_type_str[lmdata->type], |
| strlen(module_type_str[lmdata->type])) != 0) |
| return 0; |
| |
| /* Load it */ |
| handle = lt_dlopenext(filename); |
| if (!handle) |
| return 0; |
| |
| /* Build base symbol name */ |
| name = yasm_xmalloc(strlen(base)+5+ |
| strlen(module_type_str[lmdata->type])+1); |
| strcpy(name, base); |
| strcat(name, "_LTX_"); |
| strcat(name, module_type_str[lmdata->type]); |
| |
| /* Prefix with yasm in the right place and get name/keyword */ |
| switch (lmdata->type) { |
| case MODULE_ARCH: |
| strncpy(name, "yasm", 4); |
| arch_module = lt_dlsym(handle, name); |
| if (arch_module) { |
| module_keyword = arch_module->keyword; |
| module_name = arch_module->name; |
| } |
| break; |
| case MODULE_DBGFMT: |
| strncpy(name+2, "yasm", 4); |
| dbgfmt_module = lt_dlsym(handle, name+2); |
| if (dbgfmt_module) { |
| module_keyword = dbgfmt_module->keyword; |
| module_name = dbgfmt_module->name; |
| } |
| break; |
| case MODULE_OBJFMT: |
| strncpy(name+2, "yasm", 4); |
| objfmt_module = lt_dlsym(handle, name+2); |
| if (objfmt_module) { |
| module_keyword = objfmt_module->keyword; |
| module_name = objfmt_module->name; |
| } |
| break; |
| case MODULE_LISTFMT: |
| strncpy(name+3, "yasm", 4); |
| listfmt_module = lt_dlsym(handle, name+3); |
| if (listfmt_module) { |
| module_keyword = listfmt_module->keyword; |
| module_name = listfmt_module->name; |
| } |
| break; |
| case MODULE_OPTIMIZER: |
| strncpy(name+5, "yasm", 4); |
| optimizer_module = lt_dlsym(handle, name+5); |
| if (optimizer_module) { |
| module_keyword = optimizer_module->keyword; |
| module_name = optimizer_module->name; |
| } |
| break; |
| case MODULE_PARSER: |
| strncpy(name+2, "yasm", 4); |
| parser_module = lt_dlsym(handle, name+2); |
| if (parser_module) { |
| module_keyword = parser_module->keyword; |
| module_name = parser_module->name; |
| } |
| break; |
| case MODULE_PREPROC: |
| strncpy(name+3, "yasm", 4); |
| preproc_module = lt_dlsym(handle, name+3); |
| if (preproc_module) { |
| module_keyword = preproc_module->keyword; |
| module_name = preproc_module->name; |
| } |
| break; |
| } |
| |
| if (module_keyword && module_name) { |
| list_module_info *lminfo; |
| /* Find empty location in array */ |
| if (lmdata->matches_num >= lmdata->matches_alloc) { |
| lmdata->matches_alloc *= 2; |
| lmdata->matches = |
| yasm_xrealloc(lmdata->matches, |
| sizeof(list_module_info)*lmdata->matches_alloc); |
| } |
| lminfo = &lmdata->matches[lmdata->matches_num++]; |
| /* Build lminfo structure */ |
| strncpy(lminfo->keyword, module_keyword, sizeof(lminfo->keyword) - 1); |
| lminfo->keyword[sizeof(lminfo->keyword) - 1] = '\0'; |
| strncpy(lminfo->name, module_name, sizeof(lminfo->name) - 1); |
| lminfo->name[sizeof(lminfo->name) - 1] = '\0'; |
| } |
| |
| /* Clean up */ |
| yasm_xfree(name); |
| lt_dlclose(handle); |
| return 0; |
| } |
| |
| static int |
| list_module_compare(const void *n1, const void *n2) |
| { |
| const list_module_info *i1 = n1, *i2 = n2; |
| return strcmp(i1->keyword, i2->keyword); |
| } |
| |
| void |
| list_modules(module_type type, |
| void (*printfunc) (const char *name, const char *keyword)) |
| { |
| size_t i; |
| const lt_dlsymlist *preloaded; |
| char name[100]; |
| char *dot; |
| list_module_data lmdata; |
| char *prev_keyword = NULL; |
| |
| lmdata.type = type; |
| lmdata.matches_num = 0; |
| lmdata.matches_alloc = 10; |
| lmdata.matches = |
| yasm_xmalloc(sizeof(list_module_info)*lmdata.matches_alloc); |
| |
| /* Search preloaded symbols */ |
| preloaded = lt_preloaded_symbols; |
| while (preloaded->name) { |
| /* Strip out any library extension */ |
| strncpy(name, preloaded->name, sizeof(name) - 1); |
| name[sizeof(name) - 1] = '\0'; |
| dot = strrchr(name, '.'); |
| if (dot) |
| *dot = '\0'; |
| |
| /* Search it */ |
| list_module_load(name, &lmdata); |
| preloaded++; |
| } |
| /* Search external module path */ |
| lt_dlforeachfile(NULL, list_module_load, &lmdata); |
| lt_dlforeachfile(".", list_module_load, &lmdata); |
| |
| /* Sort, print, and cleanup */ |
| yasm__mergesort(lmdata.matches, lmdata.matches_num, |
| sizeof(list_module_info), list_module_compare); |
| for (i=0; i<lmdata.matches_num; i++) { |
| /* Don't print duplicates */ |
| if (!prev_keyword || strcmp(prev_keyword, lmdata.matches[i].keyword)) |
| printfunc(lmdata.matches[i].name, lmdata.matches[i].keyword); |
| prev_keyword = lmdata.matches[i].keyword; |
| } |
| yasm_xfree(lmdata.matches); |
| } |