From 8b0c007ad990aa27d9868da49215fd1076ac77cc Mon Sep 17 00:00:00 2001 From: kpfleming Date: Mon, 21 Aug 2006 02:11:39 +0000 Subject: merge new_loader_completion branch, including (at least): - restructured build tree and makefiles to eliminate recursion problems - support for embedded modules - support for static builds - simpler cross-compilation support - simpler module/loader interface (no exported symbols) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@40722 f38db490-d61c-443f-a65b-d21fe96a405b --- dlfcn.c | 1314 --------------------------------------------------------------- 1 file changed, 1314 deletions(-) delete mode 100644 dlfcn.c (limited to 'dlfcn.c') diff --git a/dlfcn.c b/dlfcn.c deleted file mode 100644 index cc6fe40f9..000000000 --- a/dlfcn.c +++ /dev/null @@ -1,1314 +0,0 @@ -/* -Copyright (c) 2002 Jorge Acereda & - Peter O'Gorman - -Portions may be copyright others, see the AUTHORS file included with this -distribution. - -Maintained by Peter O'Gorman - -Bug Reports and other queries should go to - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* Just playing to see if it would compile with the freebsd headers, it does, - * but because of the different values for RTLD_LOCAL etc, it would break binary - * compat... oh well - */ -#ifndef __BSD_VISIBLE -#define __BSD_VISIBLE 1 -#endif - -#include "asterisk/dlfcn-compat.h" - -#ifndef dl_restrict -#define dl_restrict __restrict -#endif -/* This is not available on 10.1 */ -#ifndef LC_LOAD_WEAK_DYLIB -#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) -#endif - -/* With this stuff here, this thing may actually compile/run on 10.0 systems - * Not that I have a 10.0 system to test it on anylonger - */ -#ifndef LC_REQ_DYLD -#define LC_REQ_DYLD 0x80000000 -#endif -#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED -#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4 -#endif -#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR -#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1 -#endif -#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND -#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0 -#endif -#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR -#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4 -#endif -/* These symbols will be looked for in dyld */ -static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0; -static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0; -static NSSymbol(*dyld_NSLookupSymbolInImage) - (const struct mach_header *, const char *, unsigned long) = 0; - -/* Define this to make dlcompat reuse data block. This way in theory we save - * a little bit of overhead. However we then couldn't correctly catch excess - * calls to dlclose(). Hence we don't use this feature - */ -#undef REUSE_STATUS - -/* Size of the internal error message buffer (used by dlerror()) */ -#define ERR_STR_LEN 251 - -/* Maximum number of search paths supported by getSearchPath */ -#define MAX_SEARCH_PATHS 32 - - -#define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF') -#define MAGIC_DYLIB_MOD ((NSModule) 'DYMO') - -/* internal flags */ -#define DL_IN_LIST 0x01 - -/* our mutex */ -static pthread_mutex_t dlcompat_mutex; -/* Our thread specific storage - */ -static pthread_key_t dlerror_key; - -struct dlthread -{ - int lockcnt; - unsigned char errset; - char errstr[ERR_STR_LEN]; -}; - -/* This is our central data structure. Whenever a module is loaded via - * dlopen(), we create such a struct. - */ -struct dlstatus -{ - struct dlstatus *next; /* pointer to next element in the linked list */ - NSModule module; - const struct mach_header *lib; - int refs; /* reference count */ - int mode; /* mode in which this module was loaded */ - dev_t device; - ino_t inode; - int flags; /* Any internal flags we may need */ -}; - -/* Head node of the dlstatus list */ -static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 }; -static struct dlstatus *stqueue = &mainStatus; - - -/* Storage for the last error message (used by dlerror()) */ -/* static char err_str[ERR_STR_LEN]; */ -/* static int err_filled = 0; */ - -/* Prototypes to internal functions */ -static void debug(const char *fmt, ...); -static void error(const char *str, ...); -static const char *safegetenv(const char *s); -static const char *searchList(void); -static const char *getSearchPath(int i); -static const char *getFullPath(int i, const char *file); -static const struct stat *findFile(const char *file, const char **fullPath); -static int isValidStatus(struct dlstatus *status); -static inline int isFlagSet(int mode, int flag); -static struct dlstatus *lookupStatus(const struct stat *sbuf); -static void insertStatus(struct dlstatus *dls, const struct stat *sbuf); -static int promoteLocalToGlobal(struct dlstatus *dls); -static void *reference(struct dlstatus *dls, int mode); -static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError); -static struct dlstatus *allocStatus(void); -static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode); -static NSSymbol *search_linked_libs(const struct mach_header *mh, const char *symbol); -static const char *get_lib_name(const struct mach_header *mh); -static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod); -static void dlcompat_init_func(void); -static inline void dolock(void); -static inline void dounlock(void); -static void dlerrorfree(void *data); -static void resetdlerror(void); -static const struct mach_header *my_find_image(const char *name); -static const struct mach_header *image_for_address(const void *address); -static void dlcompat_cleanup(void); -static inline const char *dyld_error_str(void); - -#if FINK_BUILD -/* Two Global Functions */ -void *dlsym_prepend_underscore(void *handle, const char *symbol); -void *dlsym_auto_underscore(void *handle, const char *symbol); - -/* And their _intern counterparts */ -static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol); -static void *dlsym_auto_underscore_intern(void *handle, const char *symbol); -#endif - -/* Functions */ - -static void debug(const char *fmt, ...) -{ -#if DEBUG > 1 - va_list arg; - va_start(arg, fmt); - fprintf(stderr, "DLDEBUG: "); - vfprintf(stderr, fmt, arg); - fprintf(stderr, "\n"); - fflush(stderr); - va_end(arg); -#endif -} - -static void error(const char *str, ...) -{ - va_list arg; - struct dlthread *tss; - char * err_str; - va_start(arg, str); - tss = pthread_getspecific(dlerror_key); - err_str = tss->errstr; - strncpy(err_str, "dlcompat: ", ERR_STR_LEN); - vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg); - va_end(arg); - debug("ERROR: %s\n", err_str); - tss->errset = 1; -} - -static void warning(const char *str) -{ -#if DEBUG > 0 - fprintf(stderr, "WARNING: dlcompat: %s\n", str); -#endif -} - -static const char *safegetenv(const char *s) -{ - const char *ss = getenv(s); - return ss ? ss : ""; -} - -/* because this is only used for debugging and error reporting functions, we - * don't really care about how elegant it is... it could use the load - * commands to find the install name of the library, but... - */ -static const char *get_lib_name(const struct mach_header *mh) -{ - unsigned long count = _dyld_image_count(); - unsigned long i; - const char *val = NULL; - if (mh) - { - for (i = 0; i < count; i++) - { - if (mh == _dyld_get_image_header(i)) - { - val = _dyld_get_image_name(i); - break; - } - } - } - return val; -} - -/* Returns the mach_header for the module bu going through all the loaded images - * and finding the one with the same name as the module. There really ought to be - * an api for doing this, would be faster, but there isn't one right now - */ -static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod) -{ - const char *mod_name = NSNameOfModule(mod); - struct mach_header *mh = NULL; - unsigned long count = _dyld_image_count(); - unsigned long i; - debug("Module name: %s", mod_name); - for (i = 0; i < count; i++) - { - if (!strcmp(mod_name, _dyld_get_image_name(i))) - { - mh = _dyld_get_image_header(i); - break; - } - } - return mh; -} - - -/* Compute and return a list of all directories that we should search when - * trying to locate a module. We first look at the values of LD_LIBRARY_PATH - * and DYLD_LIBRARY_PATH, and then finally fall back to looking into - * /usr/lib and /lib. Since both of the environments variables can contain a - * list of colon separated paths, we simply concat them and the two other paths - * into one big string, which we then can easily parse. - * Splitting this string into the actual path list is done by getSearchPath() - */ -static const char *searchList() -{ - size_t buf_size; - static char *buf=NULL; - const char *ldlp = safegetenv("LD_LIBRARY_PATH"); - const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH"); - const char *stdpath = getenv("DYLD_FALLBACK_LIBRARY_PATH"); - if (!stdpath) - stdpath = "/usr/local/lib:/lib:/usr/lib"; - if (!buf) - { - buf_size = strlen(ldlp) + strlen(dyldlp) + strlen(stdpath) + 4; - buf = malloc(buf_size); - snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""), - stdpath, '\0'); - } - return buf; -} - -/* Returns the ith search path from the list as computed by searchList() */ -static const char *getSearchPath(int i) -{ - static const char *list = 0; - static char **path = (char **)0; - static int end = 0; - static int numsize = MAX_SEARCH_PATHS; - static char **tmp; - /* So we can call free() in the "destructor" we use i=-1 to return the alloc'd array */ - if (i == -1) - { - return (const char*)path; - } - if (!path) - { - path = (char **)calloc(MAX_SEARCH_PATHS, sizeof(char **)); - } - if (!list && !end) - list = searchList(); - if (i >= (numsize)) - { - debug("Increasing size for long PATH"); - tmp = (char **)calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **)); - if (tmp) - { - memcpy(tmp, path, sizeof(char **) * numsize); - free(path); - path = tmp; - numsize += MAX_SEARCH_PATHS; - } - else - { - return 0; - } - } - - while (!path[i] && !end) - { - path[i] = strsep((char **)&list, ":"); - - if (path[i][0] == 0) - path[i] = 0; - end = (list == 0); - } - return path[i]; -} - -static const char *getFullPath(int i, const char *file) -{ - static char buf[PATH_MAX]; - const char *path = getSearchPath(i); - if (path) - { - snprintf(buf, PATH_MAX, "%s/%s", path, file); - } - return path ? buf : 0; -} - -/* Given a file name, try to determine the full path for that file. Starts - * its search in the current directory, and then tries all paths in the - * search list in the order they are specified there. - */ -static const struct stat *findFile(const char *file, const char **fullPath) -{ - int i = 0; - static struct stat sbuf; - char *fileName; - debug("finding file %s", file); - *fullPath = file; - if (0 == stat(file, &sbuf)) - return &sbuf; - if (strchr(file, '/')) - return 0; /* If the path had a / we don't look in env var places */ - fileName = NULL; - if (!fileName) - fileName = (char *)file; - while ((*fullPath = getFullPath(i++, fileName))) - { - if (0 == stat(*fullPath, &sbuf)) - return &sbuf; - } - ; - return 0; -} - -/* Determine whether a given dlstatus is valid or not */ -static int isValidStatus(struct dlstatus *status) -{ - /* Walk the list to verify status is contained in it */ - struct dlstatus *dls = stqueue; - while (dls && status != dls) - dls = dls->next; - if (dls == 0) - error("invalid handle"); - else if ((dls->module == 0) || (dls->refs == 0)) - error("handle to closed library"); - else - return TRUE; - return FALSE; -} - -static inline int isFlagSet(int mode, int flag) -{ - return (mode & flag) == flag; -} - -static struct dlstatus *lookupStatus(const struct stat *sbuf) -{ - struct dlstatus *dls = stqueue; - debug("looking for status"); - while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0 - || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode)) - dls = dls->next; - return dls; -} - -static void insertStatus(struct dlstatus *dls, const struct stat *sbuf) -{ - debug("inserting status"); - dls->inode = sbuf->st_ino; - dls->device = sbuf->st_dev; - dls->refs = 0; - dls->mode = 0; - if ((dls->flags & DL_IN_LIST) == 0) - { - dls->next = stqueue; - stqueue = dls; - dls->flags |= DL_IN_LIST; - } -} - -static struct dlstatus *allocStatus() -{ - struct dlstatus *dls; -#ifdef REUSE_STATUS - dls = stqueue; - while (dls && dls->module) - dls = dls->next; - if (!dls) -#endif - dls = malloc(sizeof(*dls)); - dls->flags = 0; - return dls; -} - -static int promoteLocalToGlobal(struct dlstatus *dls) -{ - static int (*p) (NSModule module) = 0; - debug("promoting"); - if (!p) - _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p); - return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module)); -} - -static void *reference(struct dlstatus *dls, int mode) -{ - if (dls) - { - if (dls->module == MAGIC_DYLIB_MOD && !isFlagSet(mode, RTLD_GLOBAL)) - { - warning("trying to open a .dylib with RTLD_LOCAL"); - error("unable to open a .dylib with RTLD_LOCAL"); - return NULL; - } - if (isFlagSet(mode, RTLD_GLOBAL) && - !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls)) - { - error("unable to promote local module to global"); - return NULL; - } - dls->mode |= mode; - dls->refs++; - } - else - debug("reference called with NULL argument"); - - return dls; -} - -static const struct mach_header *my_find_image(const char *name) -{ - const struct mach_header *mh = 0; - const char *id = NULL; - int i = _dyld_image_count(); - int j; - mh = (struct mach_header *) - dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED | - NSADDIMAGE_OPTION_RETURN_ON_ERROR); - if (!mh) - { - for (j = 0; j < i; j++) - { - id = _dyld_get_image_name(j); - if (!strcmp(id, name)) - { - mh = _dyld_get_image_header(j); - break; - } - } - } - return mh; -} - -/* - * dyld adds libraries by first adding the directly dependant libraries in link order, and - * then adding the dependencies for those libraries, so we should do the same... but we don't - * bother adding the extra dependencies, if the symbols are neither in the loaded image nor - * any of it's direct dependencies, then it probably isn't there. - */ -NSSymbol *search_linked_libs(const struct mach_header * mh, const char *symbol) -{ - int n; - struct load_command *lc = 0; - struct mach_header *wh; - NSSymbol *nssym = 0; - if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) - { - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); - for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) - { - if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd)) - { - if ((wh = (struct mach_header *) - my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset + - (char *)lc)))) - { - if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol)) - { - nssym = dyld_NSLookupSymbolInImage(wh, - symbol, - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | - NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); - break; - } - } - } - } - if ((!nssym) && NSIsSymbolNameDefined(symbol)) - { - /* I've never seen this debug message...*/ - debug("Symbol \"%s\" is defined but was not found", symbol); - } - } - return nssym; -} - -/* Up to the caller to free() returned string */ -static inline const char *dyld_error_str() -{ - NSLinkEditErrors dylder; - int dylderno; - const char *dylderrstr; - const char *dyldfile; - const char* retStr = NULL; - NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr); - if (dylderrstr && strlen(dylderrstr)) - { - retStr = malloc(strlen(dylderrstr) +1); - strcpy((char*)retStr,dylderrstr); - } - return retStr; -} - -static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError) -{ - NSSymbol *nssym = 0; - void *caller = __builtin_return_address(1); /* Be *very* careful about inlining */ - const struct mach_header *caller_mh = 0; - const char* savedErrorStr = NULL; - resetdlerror(); -#ifndef RTLD_SELF -#define RTLD_SELF ((void *) -3) -#endif - if (NULL == dls) - dls = RTLD_SELF; - if ((RTLD_NEXT == dls) || (RTLD_SELF == dls)) - { - if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) - { - caller_mh = image_for_address(caller); - if (RTLD_SELF == dls) - { - /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE - * But it appears to work anyway, and looking at the code in dyld_libfuncs.c - * this is acceptable. - */ - if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol)) - { - nssym = dyld_NSLookupSymbolInImage(caller_mh, - symbol, - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | - NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); - } - } - if (!nssym) - { - if (RTLD_SELF == dls) - savedErrorStr = dyld_error_str(); - nssym = search_linked_libs(caller_mh, symbol); - } - } - else - { - if (canSetError) - error("RTLD_SELF and RTLD_NEXT are not supported"); - return NULL; - } - } - if (!nssym) - { - - if (RTLD_DEFAULT == dls) - { - dls = &mainStatus; - } - if (!isValidStatus(dls)) - return NULL; - - if (dls->module != MAGIC_DYLIB_MOD) - { - nssym = NSLookupSymbolInModule(dls->module, symbol); - if (!nssym && NSIsSymbolNameDefined(symbol)) - { - debug("Searching dependencies"); - savedErrorStr = dyld_error_str(); - nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol); - } - } - else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) - { - if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol)) - { - nssym = dyld_NSLookupSymbolInImage(dls->lib, - symbol, - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | - NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); - } - else if (NSIsSymbolNameDefined(symbol)) - { - debug("Searching dependencies"); - savedErrorStr = dyld_error_str(); - nssym = search_linked_libs(dls->lib, symbol); - } - } - else if (dls->module == MAGIC_DYLIB_MOD) - { - /* Global context, use NSLookupAndBindSymbol */ - if (NSIsSymbolNameDefined(symbol)) - { - /* There doesn't seem to be a return on error option for this call??? - this is potentially broken, if binding fails, it will improperly - exit the application. */ - nssym = NSLookupAndBindSymbol(symbol); - } - else - { - if (savedErrorStr) - free((char*)savedErrorStr); - savedErrorStr = malloc(256); - snprintf((char*)savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol); - } - } - } - /* Error reporting */ - if (!nssym) - { - if (!savedErrorStr || !strlen(savedErrorStr)) - { - if (savedErrorStr) - free((char*)savedErrorStr); - savedErrorStr = malloc(256); - snprintf((char*)savedErrorStr, 256,"Symbol \"%s\" not found",symbol); - } - if (canSetError) - { - error(savedErrorStr); - } - else - { - debug(savedErrorStr); - } - if (savedErrorStr) - free((char*)savedErrorStr); - return NULL; - } - return NSAddressOfSymbol(nssym); -} - -static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode) -{ - NSObjectFileImage ofi = 0; - NSObjectFileImageReturnCode ofirc; - struct dlstatus *dls; - NSLinkEditErrors ler; - int lerno; - const char *errstr; - const char *file; - void (*init) (void); - ofirc = NSCreateObjectFileImageFromFile(path, &ofi); - switch (ofirc) - { - case NSObjectFileImageSuccess: - break; - case NSObjectFileImageInappropriateFile: - if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) - { - if (!isFlagSet(mode, RTLD_GLOBAL)) - { - warning("trying to open a .dylib with RTLD_LOCAL"); - error("unable to open this file with RTLD_LOCAL"); - return NULL; - } - } - else - { - error("opening this file is unsupported on this system"); - return NULL; - } - break; - case NSObjectFileImageFailure: - error("object file setup failure"); - return NULL; - case NSObjectFileImageArch: - error("no object for this architecture"); - return NULL; - case NSObjectFileImageFormat: - error("bad object file format"); - return NULL; - case NSObjectFileImageAccess: - error("can't read object file"); - return NULL; - default: - error("unknown error from NSCreateObjectFileImageFromFile()"); - return NULL; - } - dls = lookupStatus(sbuf); - if (!dls) - { - dls = allocStatus(); - } - if (!dls) - { - error("unable to allocate memory"); - return NULL; - } - dls->lib = 0; - if (ofirc == NSObjectFileImageInappropriateFile) - { - if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR))) - { - debug("Dynamic lib loaded at %ld", dls->lib); - ofi = MAGIC_DYLIB_OFI; - dls->module = MAGIC_DYLIB_MOD; - ofirc = NSObjectFileImageSuccess; - /* Although it is possible with a bit of work to modify this so it works and - functions with RTLD_NOW, I don't deem it necessary at the moment */ - } - if (!(dls->module)) - { - NSLinkEditError(&ler, &lerno, &file, &errstr); - if (!errstr || (!strlen(errstr))) - error("Can't open this file type"); - else - error(errstr); - if ((dls->flags & DL_IN_LIST) == 0) - { - free(dls); - } - return NULL; - } - } - else - { - dls->module = NSLinkModule(ofi, path, - NSLINKMODULE_OPTION_RETURN_ON_ERROR | - NSLINKMODULE_OPTION_PRIVATE | - (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0)); - NSDestroyObjectFileImage(ofi); - if (dls->module) - { - dls->lib = get_mach_header_from_NSModule(dls->module); - } - } - if (!dls->module) - { - NSLinkEditError(&ler, &lerno, &file, &errstr); - if ((dls->flags & DL_IN_LIST) == 0) - { - free(dls); - } - error(errstr); - return NULL; - } - - insertStatus(dls, sbuf); - dls = reference(dls, mode); - if ((init = dlsymIntern(dls, "__init", 0))) - { - debug("calling _init()"); - init(); - } - return dls; -} - -static void dlcompat_init_func(void) -{ - static int inited = 0; - if (!inited) - { - inited = 1; - _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage); - _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage", - (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage); - _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage); - if (pthread_mutex_init(&dlcompat_mutex, NULL)) - exit(1); - if (pthread_key_create(&dlerror_key, &dlerrorfree)) - exit(1); - /* And be neat and tidy and clean up after ourselves */ - atexit(dlcompat_cleanup); - } -} - -#if 0 -#pragma CALL_ON_LOAD dlcompat_init_func -#endif - -static void dlcompat_cleanup(void) -{ - struct dlstatus *dls; - struct dlstatus *next; - char *data; - data = (char *)searchList(); - if ( data ) - free( data ); - data = (char *)getSearchPath(-1); - if ( data ) - free( data ); - pthread_mutex_destroy(&dlcompat_mutex); - pthread_key_delete(dlerror_key); - next = stqueue; - while (next && (next != &mainStatus)) - { - dls = next; - next = dls->next; - free(dls); - } -} - -static void resetdlerror() -{ - struct dlthread *tss; - tss = pthread_getspecific(dlerror_key); - tss->errset = 0; -} - -static void dlerrorfree(void *data) -{ - free(data); -} - -/* We kind of want a recursive lock here, but meet a little trouble - * because they are not available pre OS X 10.2, so we fake it - * using thread specific storage to keep a lock count - */ -static inline void dolock(void) -{ - int err = 0; - struct dlthread *tss; - tss = pthread_getspecific(dlerror_key); - if (!tss) - { - tss = malloc(sizeof(struct dlthread)); - tss->lockcnt = 0; - tss->errset = 0; - if (pthread_setspecific(dlerror_key, tss)) - { - fprintf(stderr,"dlcompat: pthread_setspecific failed\n"); - exit(1); - } - } - if (!tss->lockcnt) - err = pthread_mutex_lock(&dlcompat_mutex); - tss->lockcnt = tss->lockcnt +1; - if (err) - exit(err); -} - -static inline void dounlock(void) -{ - int err = 0; - struct dlthread *tss; - tss = pthread_getspecific(dlerror_key); - tss->lockcnt = tss->lockcnt -1; - if (!tss->lockcnt) - err = pthread_mutex_unlock(&dlcompat_mutex); - if (err) - exit(err); -} - -void *dlopen(const char *path, int mode) -{ - const struct stat *sbuf; - struct dlstatus *dls; - const char *fullPath; - dlcompat_init_func(); /* Just in case */ - dolock(); - resetdlerror(); - if (!path) - { - dls = &mainStatus; - goto dlopenok; - } - if (!(sbuf = findFile(path, &fullPath))) - { - error("file \"%s\" not found", path); - goto dlopenerror; - } - /* Now checks that it hasn't been closed already */ - if ((dls = lookupStatus(sbuf)) && (dls->refs > 0)) - { - /* debug("status found"); */ - dls = reference(dls, mode); - goto dlopenok; - } -#ifdef RTLD_NOLOAD - if (isFlagSet(mode, RTLD_NOLOAD)) - { - error("no existing handle and RTLD_NOLOAD specified"); - goto dlopenerror; - } -#endif - if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW)) - { - error("how can I load something both RTLD_LAZY and RTLD_NOW?"); - goto dlopenerror; - } - dls = loadModule(fullPath, sbuf, mode); - - dlopenok: - dounlock(); - return (void *)dls; - dlopenerror: - dounlock(); - return NULL; -} - -#if !FINK_BUILD -void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol) -{ - int sym_len = strlen(symbol); - void *value = NULL; - char *malloc_sym = NULL; - dolock(); - malloc_sym = malloc(sym_len + 2); - if (malloc_sym) - { - sprintf(malloc_sym, "_%s", symbol); - value = dlsymIntern(handle, malloc_sym, 1); - free(malloc_sym); - } - else - { - error("Unable to allocate memory"); - goto dlsymerror; - } - dounlock(); - return value; - dlsymerror: - dounlock(); - return NULL; -} -#endif - -#if FINK_BUILD - -void *dlsym_prepend_underscore(void *handle, const char *symbol) -{ - void *answer; - dolock(); - answer = dlsym_prepend_underscore_intern(handle, symbol); - dounlock(); - return answer; -} - -static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol) -{ -/* - * A quick and easy way for porting packages which call dlsym(handle,"sym") - * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then - * this function will be called, and will add the required underscore. - * - * Note that I haven't figured out yet which should be "standard", prepend - * the underscore always, or not at all. These global functions need to go away - * for opendarwin. - */ - int sym_len = strlen(symbol); - void *value = NULL; - char *malloc_sym = NULL; - malloc_sym = malloc(sym_len + 2); - if (malloc_sym) - { - sprintf(malloc_sym, "_%s", symbol); - value = dlsymIntern(handle, malloc_sym, 1); - free(malloc_sym); - } - else - { - error("Unable to allocate memory"); - } - return value; -} - -void *dlsym_auto_underscore(void *handle, const char *symbol) -{ - void *answer; - dolock(); - answer = dlsym_auto_underscore_intern(handle, symbol); - dounlock(); - return answer; - -} -static void *dlsym_auto_underscore_intern(void *handle, const char *symbol) -{ - struct dlstatus *dls = handle; - void *addr = 0; - addr = dlsymIntern(dls, symbol, 0); - if (!addr) - addr = dlsym_prepend_underscore_intern(handle, symbol); - return addr; -} - - -void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol) -{ - struct dlstatus *dls = handle; - void *addr = 0; - dolock(); - addr = dlsymIntern(dls, symbol, 1); - dounlock(); - return addr; -} -#endif - -int dlclose(void *handle) -{ - struct dlstatus *dls = handle; - dolock(); - resetdlerror(); - if (!isValidStatus(dls)) - { - goto dlcloseerror; - } - if (dls->module == MAGIC_DYLIB_MOD) - { - const char *name; - if (!dls->lib) - { - name = "global context"; - } - else - { - name = get_lib_name(dls->lib); - } - warning("trying to close a .dylib!"); - error("Not closing \"%s\" - dynamic libraries cannot be closed", name); - goto dlcloseerror; - } - if (!dls->module) - { - error("module already closed"); - goto dlcloseerror; - } - - if (dls->refs == 1) - { - unsigned long options = 0; - void (*fini) (void); - if ((fini = dlsymIntern(dls, "__fini", 0))) - { - debug("calling _fini()"); - fini(); - } -#ifdef __ppc__ - options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES; -#endif -#if 1 -/* Currently, if a module contains c++ static destructors and it is unloaded, we - * get a segfault in atexit(), due to compiler and dynamic loader differences of - * opinion, this works around that. - * I really need a way to figure out from code if this is still necessary. - */ - if ((const struct section *)NULL != - getsectbynamefromheader(get_mach_header_from_NSModule(dls->module), - "__DATA", "__mod_term_func")) - { - options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; - } -#endif -#ifdef RTLD_NODELETE - if (isFlagSet(dls->mode, RTLD_NODELETE)) - options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; -#endif - if (!NSUnLinkModule(dls->module, options)) - { - error("unable to unlink module"); - goto dlcloseerror; - } - dls->refs--; - dls->module = 0; - /* Note: the dlstatus struct dls is neither removed from the list - * nor is the memory it occupies freed. This shouldn't pose a - * problem in mostly all cases, though. - */ - } - dounlock(); - return 0; - dlcloseerror: - dounlock(); - return 1; -} - -const char *dlerror(void) -{ - struct dlthread *tss; - char * err_str; - tss = pthread_getspecific(dlerror_key); - err_str = tss->errstr; - tss = pthread_getspecific(dlerror_key); - if (tss->errset == 0) - return 0; - tss->errset = 0; - return (err_str ); -} - -/* Given an address, return the mach_header for the image containing it - * or zero if the given address is not contained in any loaded images. - */ -const struct mach_header *image_for_address(const void *address) -{ - unsigned long i; - unsigned long j; - unsigned long count = _dyld_image_count(); - struct mach_header *mh = 0; - struct load_command *lc = 0; - unsigned long addr = NULL; - for (i = 0; i < count; i++) - { - addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i); - mh = _dyld_get_image_header(i); - if (mh) - { - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); - for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) - { - if (LC_SEGMENT == lc->cmd && - addr >= ((struct segment_command *)lc)->vmaddr && - addr < - ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) - { - goto image_found; - } - } - } - mh = 0; - } - image_found: - return mh; -} - -int dladdr(const void * dl_restrict p, Dl_info * dl_restrict info) -{ -/* - FIXME: USe the routine image_for_address. -*/ - unsigned long i; - unsigned long j; - unsigned long count = _dyld_image_count(); - struct mach_header *mh = 0; - struct load_command *lc = 0; - unsigned long addr = NULL; - unsigned long table_off = (unsigned long)0; - int found = 0; - if (!info) - return 0; - dolock(); - resetdlerror(); - info->dli_fname = 0; - info->dli_fbase = 0; - info->dli_sname = 0; - info->dli_saddr = 0; -/* Some of this was swiped from code posted by Douglas Davidson - * to darwin-development AT lists DOT apple DOT com and slightly modified - */ - for (i = 0; i < count; i++) - { - addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i); - mh = _dyld_get_image_header(i); - if (mh) - { - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); - for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) - { - if (LC_SEGMENT == lc->cmd && - addr >= ((struct segment_command *)lc)->vmaddr && - addr < - ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) - { - info->dli_fname = _dyld_get_image_name(i); - info->dli_fbase = (void *)mh; - found = 1; - break; - } - } - if (found) - break; - } - } - if (!found) - { - dounlock(); - return 0; - } - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); - for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) - { - if (LC_SEGMENT == lc->cmd) - { - if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT")) - break; - } - } - table_off = - ((unsigned long)((struct segment_command *)lc)->vmaddr) - - ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i); - debug("table off %x", table_off); - - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); - for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) - { - if (LC_SYMTAB == lc->cmd) - { - - struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off); - unsigned long numsyms = ((struct symtab_command *)lc)->nsyms; - struct nlist *nearest = NULL; - unsigned long diff = 0xffffffff; - unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off); - debug("symtable %x", symtable); - for (i = 0; i < numsyms; i++) - { - /* Ignore the following kinds of Symbols */ - if ((!symtable->n_value) /* Undefined */ - || (symtable->n_type >= N_PEXT) /* Debug symbol */ - || (!(symtable->n_type & N_EXT)) /* Local Symbol */ - ) - { - symtable++; - continue; - } - if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr))) - { - diff = (unsigned long)symtable->n_value - addr; - nearest = symtable; - } - symtable++; - } - if (nearest) - { - info->dli_saddr = nearest->n_value + ((void *)p - addr); - info->dli_sname = (char *)(strtable + nearest->n_un.n_strx); - } - } - } - dounlock(); - return 1; -} - - -/* - * Implement the dlfunc() interface, which behaves exactly the same as - * dlsym() except that it returns a function pointer instead of a data - * pointer. This can be used by applications to avoid compiler warnings - * about undefined behavior, and is intended as prior art for future - * POSIX standardization. This function requires that all pointer types - * have the same representation, which is true on all platforms FreeBSD - * runs on, but is not guaranteed by the C standard. - */ -#if 0 -dlfunc_t dlfunc(void * dl_restrict handle, const char * dl_restrict symbol) -{ - union - { - void *d; - dlfunc_t f; - } rv; - int sym_len = strlen(symbol); - char *malloc_sym = NULL; - dolock(); - malloc_sym = malloc(sym_len + 2); - if (malloc_sym) - { - sprintf(malloc_sym, "_%s", symbol); - rv.d = dlsymIntern(handle, malloc_sym, 1); - free(malloc_sym); - } - else - { - error("Unable to allocate memory"); - goto dlfuncerror; - } - dounlock(); - return rv.f; - dlfuncerror: - dounlock(); - return NULL; -} -#endif -- cgit v1.2.3