1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315 |
- /*
- Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> &
- Peter O'Gorman <ogorman@users.sourceforge.net>
-
- Portions may be copyright others, see the AUTHORS file included with this
- distribution.
- Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
- Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
- 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 <pthread.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdarg.h>
- #include <limits.h>
- #include <mach-o/dyld.h>
- #include <mach-o/nlist.h>
- #include <mach-o/getsect.h>
- /* 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 <ddavidso AT apple DOT com>
- * 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
|