Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

dlfcn.c

Go to the documentation of this file.
00001 /* 00002 Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> & 00003 Peter O'Gorman <ogorman@users.sourceforge.net> 00004 00005 Portions may be copyright others, see the AUTHORS file included with this 00006 distribution. 00007 00008 Maintained by Peter O'Gorman <ogorman@users.sourceforge.net> 00009 00010 Bug Reports and other queries should go to <ogorman@users.sourceforge.net> 00011 00012 Permission is hereby granted, free of charge, to any person obtaining 00013 a copy of this software and associated documentation files (the 00014 "Software"), to deal in the Software without restriction, including 00015 without limitation the rights to use, copy, modify, merge, publish, 00016 distribute, sublicense, and/or sell copies of the Software, and to 00017 permit persons to whom the Software is furnished to do so, subject to 00018 the following conditions: 00019 00020 The above copyright notice and this permission notice shall be 00021 included in all copies or substantial portions of the Software. 00022 00023 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00024 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00025 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00026 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 00027 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00028 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00029 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00030 */ 00031 00032 #include <pthread.h> 00033 #include <stdio.h> 00034 #include <stdlib.h> 00035 #include <string.h> 00036 #include <sys/types.h> 00037 #include <sys/stat.h> 00038 #include <stdarg.h> 00039 #include <limits.h> 00040 #include <mach-o/dyld.h> 00041 #include <mach-o/nlist.h> 00042 #include <mach-o/getsect.h> 00043 /* Just playing to see if it would compile with the freebsd headers, it does, 00044 * but because of the different values for RTLD_LOCAL etc, it would break binary 00045 * compat... oh well 00046 */ 00047 #ifndef __BSD_VISIBLE 00048 #define __BSD_VISIBLE 1 00049 #endif 00050 #include <asterisk/dlfcn-compat.h> 00051 00052 #ifndef dl_restrict 00053 #define dl_restrict __restrict 00054 #endif 00055 /* This is not available on 10.1 */ 00056 #ifndef LC_LOAD_WEAK_DYLIB 00057 #define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) 00058 #endif 00059 00060 /* With this stuff here, this thing may actually compile/run on 10.0 systems 00061 * Not that I have a 10.0 system to test it on anylonger 00062 */ 00063 #ifndef LC_REQ_DYLD 00064 #define LC_REQ_DYLD 0x80000000 00065 #endif 00066 #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 00067 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4 00068 #endif 00069 #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR 00070 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1 00071 #endif 00072 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 00073 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0 00074 #endif 00075 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 00076 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4 00077 #endif 00078 /* These symbols will be looked for in dyld */ 00079 static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0; 00080 static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0; 00081 static NSSymbol(*dyld_NSLookupSymbolInImage) 00082 (const struct mach_header *, const char *, unsigned long) = 0; 00083 00084 /* Define this to make dlcompat reuse data block. This way in theory we save 00085 * a little bit of overhead. However we then couldn't correctly catch excess 00086 * calls to dlclose(). Hence we don't use this feature 00087 */ 00088 #undef REUSE_STATUS 00089 00090 /* Size of the internal error message buffer (used by dlerror()) */ 00091 #define ERR_STR_LEN 251 00092 00093 /* Maximum number of search paths supported by getSearchPath */ 00094 #define MAX_SEARCH_PATHS 32 00095 00096 00097 #define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF') 00098 #define MAGIC_DYLIB_MOD ((NSModule) 'DYMO') 00099 00100 /* internal flags */ 00101 #define DL_IN_LIST 0x01 00102 00103 /* our mutex */ 00104 static pthread_mutex_t dlcompat_mutex; 00105 /* Our thread specific storage 00106 */ 00107 static pthread_key_t dlerror_key; 00108 00109 struct dlthread 00110 { 00111 int lockcnt; 00112 unsigned char errset; 00113 char errstr[ERR_STR_LEN]; 00114 }; 00115 00116 /* This is our central data structure. Whenever a module is loaded via 00117 * dlopen(), we create such a struct. 00118 */ 00119 struct dlstatus 00120 { 00121 struct dlstatus *next; /* pointer to next element in the linked list */ 00122 NSModule module; 00123 const struct mach_header *lib; 00124 int refs; /* reference count */ 00125 int mode; /* mode in which this module was loaded */ 00126 dev_t device; 00127 ino_t inode; 00128 int flags; /* Any internal flags we may need */ 00129 }; 00130 00131 /* Head node of the dlstatus list */ 00132 static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 }; 00133 static struct dlstatus *stqueue = &mainStatus; 00134 00135 00136 /* Storage for the last error message (used by dlerror()) */ 00137 /* static char err_str[ERR_STR_LEN]; */ 00138 /* static int err_filled = 0; */ 00139 00140 /* Prototypes to internal functions */ 00141 static void debug(const char *fmt, ...); 00142 static void error(const char *str, ...); 00143 static const char *safegetenv(const char *s); 00144 static const char *searchList(void); 00145 static const char *getSearchPath(int i); 00146 static const char *getFullPath(int i, const char *file); 00147 static const struct stat *findFile(const char *file, const char **fullPath); 00148 static int isValidStatus(struct dlstatus *status); 00149 static inline int isFlagSet(int mode, int flag); 00150 static struct dlstatus *lookupStatus(const struct stat *sbuf); 00151 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf); 00152 static int promoteLocalToGlobal(struct dlstatus *dls); 00153 static void *reference(struct dlstatus *dls, int mode); 00154 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError); 00155 static struct dlstatus *allocStatus(void); 00156 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode); 00157 static NSSymbol *search_linked_libs(const struct mach_header *mh, const char *symbol); 00158 static const char *get_lib_name(const struct mach_header *mh); 00159 static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod); 00160 static void dlcompat_init_func(void); 00161 static inline void dolock(void); 00162 static inline void dounlock(void); 00163 static void dlerrorfree(void *data); 00164 static void resetdlerror(void); 00165 static const struct mach_header *my_find_image(const char *name); 00166 static const struct mach_header *image_for_address(const void *address); 00167 static void dlcompat_cleanup(void); 00168 static inline const char *dyld_error_str(void); 00169 00170 #if FINK_BUILD 00171 /* Two Global Functions */ 00172 void *dlsym_prepend_underscore(void *handle, const char *symbol); 00173 void *dlsym_auto_underscore(void *handle, const char *symbol); 00174 00175 /* And their _intern counterparts */ 00176 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol); 00177 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol); 00178 #endif 00179 00180 /* Functions */ 00181 00182 static void debug(const char *fmt, ...) 00183 { 00184 #if DEBUG > 1 00185 va_list arg; 00186 va_start(arg, fmt); 00187 fprintf(stderr, "DLDEBUG: "); 00188 vfprintf(stderr, fmt, arg); 00189 fprintf(stderr, "\n"); 00190 fflush(stderr); 00191 va_end(arg); 00192 #endif 00193 } 00194 00195 static void error(const char *str, ...) 00196 { 00197 va_list arg; 00198 struct dlthread *tss; 00199 char * err_str; 00200 va_start(arg, str); 00201 tss = pthread_getspecific(dlerror_key); 00202 err_str = tss->errstr; 00203 strncpy(err_str, "dlcompat: ", ERR_STR_LEN); 00204 vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg); 00205 va_end(arg); 00206 debug("ERROR: %s\n", err_str); 00207 tss->errset = 1; 00208 } 00209 00210 static void warning(const char *str) 00211 { 00212 #if DEBUG > 0 00213 fprintf(stderr, "WARNING: dlcompat: %s\n", str); 00214 #endif 00215 } 00216 00217 static const char *safegetenv(const char *s) 00218 { 00219 const char *ss = getenv(s); 00220 return ss ? ss : ""; 00221 } 00222 00223 /* because this is only used for debugging and error reporting functions, we 00224 * don't really care about how elegant it is... it could use the load 00225 * commands to find the install name of the library, but... 00226 */ 00227 static const char *get_lib_name(const struct mach_header *mh) 00228 { 00229 unsigned long count = _dyld_image_count(); 00230 unsigned long i; 00231 const char *val = NULL; 00232 if (mh) 00233 { 00234 for (i = 0; i < count; i++) 00235 { 00236 if (mh == _dyld_get_image_header(i)) 00237 { 00238 val = _dyld_get_image_name(i); 00239 break; 00240 } 00241 } 00242 } 00243 return val; 00244 } 00245 00246 /* Returns the mach_header for the module bu going through all the loaded images 00247 * and finding the one with the same name as the module. There really ought to be 00248 * an api for doing this, would be faster, but there isn't one right now 00249 */ 00250 static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod) 00251 { 00252 const char *mod_name = NSNameOfModule(mod); 00253 struct mach_header *mh = NULL; 00254 unsigned long count = _dyld_image_count(); 00255 unsigned long i; 00256 debug("Module name: %s", mod_name); 00257 for (i = 0; i < count; i++) 00258 { 00259 if (!strcmp(mod_name, _dyld_get_image_name(i))) 00260 { 00261 mh = _dyld_get_image_header(i); 00262 break; 00263 } 00264 } 00265 return mh; 00266 } 00267 00268 00269 /* Compute and return a list of all directories that we should search when 00270 * trying to locate a module. We first look at the values of LD_LIBRARY_PATH 00271 * and DYLD_LIBRARY_PATH, and then finally fall back to looking into 00272 * /usr/lib and /lib. Since both of the environments variables can contain a 00273 * list of colon seperated paths, we simply concat them and the two other paths 00274 * into one big string, which we then can easily parse. 00275 * Splitting this string into the actual path list is done by getSearchPath() 00276 */ 00277 static const char *searchList() 00278 { 00279 size_t buf_size; 00280 static char *buf=NULL; 00281 const char *ldlp = safegetenv("LD_LIBRARY_PATH"); 00282 const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH"); 00283 const char *stdpath = getenv("DYLD_FALLBACK_LIBRARY_PATH"); 00284 if (!stdpath) 00285 stdpath = "/usr/local/lib:/lib:/usr/lib"; 00286 if (!buf) 00287 { 00288 buf_size = strlen(ldlp) + strlen(dyldlp) + strlen(stdpath) + 4; 00289 buf = malloc(buf_size); 00290 snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""), 00291 stdpath, '\0'); 00292 } 00293 return buf; 00294 } 00295 00296 /* Returns the ith search path from the list as computed by searchList() */ 00297 static const char *getSearchPath(int i) 00298 { 00299 static const char *list = 0; 00300 static char **path = (char **)0; 00301 static int end = 0; 00302 static int numsize = MAX_SEARCH_PATHS; 00303 static char **tmp; 00304 /* So we can call free() in the "destructor" we use i=-1 to return the alloc'd array */ 00305 if (i == -1) 00306 { 00307 return (const char*)path; 00308 } 00309 if (!path) 00310 { 00311 path = (char **)calloc(MAX_SEARCH_PATHS, sizeof(char **)); 00312 } 00313 if (!list && !end) 00314 list = searchList(); 00315 if (i >= (numsize)) 00316 { 00317 debug("Increasing size for long PATH"); 00318 tmp = (char **)calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **)); 00319 if (tmp) 00320 { 00321 memcpy(tmp, path, sizeof(char **) * numsize); 00322 free(path); 00323 path = tmp; 00324 numsize += MAX_SEARCH_PATHS; 00325 } 00326 else 00327 { 00328 return 0; 00329 } 00330 } 00331 00332 while (!path[i] && !end) 00333 { 00334 path[i] = strsep((char **)&list, ":"); 00335 00336 if (path[i][0] == 0) 00337 path[i] = 0; 00338 end = (list == 0); 00339 } 00340 return path[i]; 00341 } 00342 00343 static const char *getFullPath(int i, const char *file) 00344 { 00345 static char buf[PATH_MAX]; 00346 const char *path = getSearchPath(i); 00347 if (path) 00348 { 00349 snprintf(buf, PATH_MAX, "%s/%s", path, file); 00350 } 00351 return path ? buf : 0; 00352 } 00353 00354 /* Given a file name, try to determine the full path for that file. Starts 00355 * its search in the current directory, and then tries all paths in the 00356 * search list in the order they are specified there. 00357 */ 00358 static const struct stat *findFile(const char *file, const char **fullPath) 00359 { 00360 int i = 0; 00361 static struct stat sbuf; 00362 char *fileName; 00363 debug("finding file %s", file); 00364 *fullPath = file; 00365 if (0 == stat(file, &sbuf)) 00366 return &sbuf; 00367 if (strchr(file, '/')) 00368 return 0; /* If the path had a / we don't look in env var places */ 00369 fileName = NULL; 00370 if (!fileName) 00371 fileName = (char *)file; 00372 while ((*fullPath = getFullPath(i++, fileName))) 00373 { 00374 if (0 == stat(*fullPath, &sbuf)) 00375 return &sbuf; 00376 } 00377 ; 00378 return 0; 00379 } 00380 00381 /* Determine whether a given dlstatus is valid or not */ 00382 static int isValidStatus(struct dlstatus *status) 00383 { 00384 /* Walk the list to verify status is contained in it */ 00385 struct dlstatus *dls = stqueue; 00386 while (dls && status != dls) 00387 dls = dls->next; 00388 if (dls == 0) 00389 error("invalid handle"); 00390 else if ((dls->module == 0) || (dls->refs == 0)) 00391 error("handle to closed library"); 00392 else 00393 return TRUE; 00394 return FALSE; 00395 } 00396 00397 static inline int isFlagSet(int mode, int flag) 00398 { 00399 return (mode & flag) == flag; 00400 } 00401 00402 static struct dlstatus *lookupStatus(const struct stat *sbuf) 00403 { 00404 struct dlstatus *dls = stqueue; 00405 debug("looking for status"); 00406 while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0 00407 || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode)) 00408 dls = dls->next; 00409 return dls; 00410 } 00411 00412 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf) 00413 { 00414 debug("inserting status"); 00415 dls->inode = sbuf->st_ino; 00416 dls->device = sbuf->st_dev; 00417 dls->refs = 0; 00418 dls->mode = 0; 00419 if ((dls->flags & DL_IN_LIST) == 0) 00420 { 00421 dls->next = stqueue; 00422 stqueue = dls; 00423 dls->flags |= DL_IN_LIST; 00424 } 00425 } 00426 00427 static struct dlstatus *allocStatus() 00428 { 00429 struct dlstatus *dls; 00430 #ifdef REUSE_STATUS 00431 dls = stqueue; 00432 while (dls && dls->module) 00433 dls = dls->next; 00434 if (!dls) 00435 #endif 00436 dls = malloc(sizeof(*dls)); 00437 dls->flags = 0; 00438 return dls; 00439 } 00440 00441 static int promoteLocalToGlobal(struct dlstatus *dls) 00442 { 00443 static int (*p) (NSModule module) = 0; 00444 debug("promoting"); 00445 if (!p) 00446 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p); 00447 return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module)); 00448 } 00449 00450 static void *reference(struct dlstatus *dls, int mode) 00451 { 00452 if (dls) 00453 { 00454 if (dls->module == MAGIC_DYLIB_MOD && !isFlagSet(mode, RTLD_GLOBAL)) 00455 { 00456 warning("trying to open a .dylib with RTLD_LOCAL"); 00457 error("unable to open a .dylib with RTLD_LOCAL"); 00458 return NULL; 00459 } 00460 if (isFlagSet(mode, RTLD_GLOBAL) && 00461 !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls)) 00462 { 00463 error("unable to promote local module to global"); 00464 return NULL; 00465 } 00466 dls->mode |= mode; 00467 dls->refs++; 00468 } 00469 else 00470 debug("reference called with NULL argument"); 00471 00472 return dls; 00473 } 00474 00475 static const struct mach_header *my_find_image(const char *name) 00476 { 00477 const struct mach_header *mh = 0; 00478 const char *id = NULL; 00479 int i = _dyld_image_count(); 00480 int j; 00481 mh = (struct mach_header *) 00482 dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED | 00483 NSADDIMAGE_OPTION_RETURN_ON_ERROR); 00484 if (!mh) 00485 { 00486 for (j = 0; j < i; j++) 00487 { 00488 id = _dyld_get_image_name(j); 00489 if (!strcmp(id, name)) 00490 { 00491 mh = _dyld_get_image_header(j); 00492 break; 00493 } 00494 } 00495 } 00496 return mh; 00497 } 00498 00499 /* 00500 * dyld adds libraries by first adding the directly dependant libraries in link order, and 00501 * then adding the dependencies for those libraries, so we should do the same... but we don't 00502 * bother adding the extra dependencies, if the symbols are neither in the loaded image nor 00503 * any of it's direct dependencies, then it probably isn't there. 00504 */ 00505 NSSymbol *search_linked_libs(const struct mach_header * mh, const char *symbol) 00506 { 00507 int n; 00508 struct load_command *lc = 0; 00509 struct mach_header *wh; 00510 NSSymbol *nssym = 0; 00511 if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) 00512 { 00513 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); 00514 for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) 00515 { 00516 if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd)) 00517 { 00518 if ((wh = (struct mach_header *) 00519 my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset + 00520 (char *)lc)))) 00521 { 00522 if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol)) 00523 { 00524 nssym = dyld_NSLookupSymbolInImage(wh, 00525 symbol, 00526 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | 00527 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); 00528 break; 00529 } 00530 } 00531 } 00532 } 00533 if ((!nssym) && NSIsSymbolNameDefined(symbol)) 00534 { 00535 /* I've never seen this debug message...*/ 00536 debug("Symbol \"%s\" is defined but was not found", symbol); 00537 } 00538 } 00539 return nssym; 00540 } 00541 00542 /* Up to the caller to free() returned string */ 00543 static inline const char *dyld_error_str() 00544 { 00545 NSLinkEditErrors dylder; 00546 int dylderno; 00547 const char *dylderrstr; 00548 const char *dyldfile; 00549 const char* retStr = NULL; 00550 NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr); 00551 if (dylderrstr && strlen(dylderrstr)) 00552 { 00553 retStr = malloc(strlen(dylderrstr) +1); 00554 strcpy((char*)retStr,dylderrstr); 00555 } 00556 return retStr; 00557 } 00558 00559 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError) 00560 { 00561 NSSymbol *nssym = 0; 00562 void *caller = __builtin_return_address(1); /* Be *very* careful about inlining */ 00563 const struct mach_header *caller_mh = 0; 00564 const char* savedErrorStr = NULL; 00565 resetdlerror(); 00566 #ifndef RTLD_SELF 00567 #define RTLD_SELF ((void *) -3) 00568 #endif 00569 if (NULL == dls) 00570 dls = RTLD_SELF; 00571 if ((RTLD_NEXT == dls) || (RTLD_SELF == dls)) 00572 { 00573 if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) 00574 { 00575 caller_mh = image_for_address(caller); 00576 if (RTLD_SELF == dls) 00577 { 00578 /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE 00579 * But it appears to work anyway, and looking at the code in dyld_libfuncs.c 00580 * this is acceptable. 00581 */ 00582 if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol)) 00583 { 00584 nssym = dyld_NSLookupSymbolInImage(caller_mh, 00585 symbol, 00586 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | 00587 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); 00588 } 00589 } 00590 if (!nssym) 00591 { 00592 if (RTLD_SELF == dls) 00593 savedErrorStr = dyld_error_str(); 00594 nssym = search_linked_libs(caller_mh, symbol); 00595 } 00596 } 00597 else 00598 { 00599 if (canSetError) 00600 error("RTLD_SELF and RTLD_NEXT are not supported"); 00601 return NULL; 00602 } 00603 } 00604 if (!nssym) 00605 { 00606 00607 if (RTLD_DEFAULT == dls) 00608 { 00609 dls = &mainStatus; 00610 } 00611 if (!isValidStatus(dls)) 00612 return NULL; 00613 00614 if (dls->module != MAGIC_DYLIB_MOD) 00615 { 00616 nssym = NSLookupSymbolInModule(dls->module, symbol); 00617 if (!nssym && NSIsSymbolNameDefined(symbol)) 00618 { 00619 debug("Searching dependencies"); 00620 savedErrorStr = dyld_error_str(); 00621 nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol); 00622 } 00623 } 00624 else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) 00625 { 00626 if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol)) 00627 { 00628 nssym = dyld_NSLookupSymbolInImage(dls->lib, 00629 symbol, 00630 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | 00631 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); 00632 } 00633 else if (NSIsSymbolNameDefined(symbol)) 00634 { 00635 debug("Searching dependencies"); 00636 savedErrorStr = dyld_error_str(); 00637 nssym = search_linked_libs(dls->lib, symbol); 00638 } 00639 } 00640 else if (dls->module == MAGIC_DYLIB_MOD) 00641 { 00642 /* Global context, use NSLookupAndBindSymbol */ 00643 if (NSIsSymbolNameDefined(symbol)) 00644 { 00645 /* There doesn't seem to be a return on error option for this call??? 00646 this is potentially broken, if binding fails, it will improperly 00647 exit the application. */ 00648 nssym = NSLookupAndBindSymbol(symbol); 00649 } 00650 else 00651 { 00652 if (savedErrorStr) 00653 free((char*)savedErrorStr); 00654 savedErrorStr = malloc(256); 00655 snprintf((char*)savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol); 00656 } 00657 } 00658 } 00659 /* Error reporting */ 00660 if (!nssym) 00661 { 00662 if (!savedErrorStr || !strlen(savedErrorStr)) 00663 { 00664 if (savedErrorStr) 00665 free((char*)savedErrorStr); 00666 savedErrorStr = malloc(256); 00667 snprintf((char*)savedErrorStr, 256,"Symbol \"%s\" not found",symbol); 00668 } 00669 if (canSetError) 00670 { 00671 error(savedErrorStr); 00672 } 00673 else 00674 { 00675 debug(savedErrorStr); 00676 } 00677 if (savedErrorStr) 00678 free((char*)savedErrorStr); 00679 return NULL; 00680 } 00681 return NSAddressOfSymbol(nssym); 00682 } 00683 00684 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode) 00685 { 00686 NSObjectFileImage ofi = 0; 00687 NSObjectFileImageReturnCode ofirc; 00688 struct dlstatus *dls; 00689 NSLinkEditErrors ler; 00690 int lerno; 00691 const char *errstr; 00692 const char *file; 00693 void (*init) (void); 00694 ofirc = NSCreateObjectFileImageFromFile(path, &ofi); 00695 switch (ofirc) 00696 { 00697 case NSObjectFileImageSuccess: 00698 break; 00699 case NSObjectFileImageInappropriateFile: 00700 if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) 00701 { 00702 if (!isFlagSet(mode, RTLD_GLOBAL)) 00703 { 00704 warning("trying to open a .dylib with RTLD_LOCAL"); 00705 error("unable to open this file with RTLD_LOCAL"); 00706 return NULL; 00707 } 00708 } 00709 else 00710 { 00711 error("opening this file is unsupported on this system"); 00712 return NULL; 00713 } 00714 break; 00715 case NSObjectFileImageFailure: 00716 error("object file setup failure"); 00717 return NULL; 00718 case NSObjectFileImageArch: 00719 error("no object for this architecture"); 00720 return NULL; 00721 case NSObjectFileImageFormat: 00722 error("bad object file format"); 00723 return NULL; 00724 case NSObjectFileImageAccess: 00725 error("can't read object file"); 00726 return NULL; 00727 default: 00728 error("unknown error from NSCreateObjectFileImageFromFile()"); 00729 return NULL; 00730 } 00731 dls = lookupStatus(sbuf); 00732 if (!dls) 00733 { 00734 dls = allocStatus(); 00735 } 00736 if (!dls) 00737 { 00738 error("unable to allocate memory"); 00739 return NULL; 00740 } 00741 dls->lib = 0; 00742 if (ofirc == NSObjectFileImageInappropriateFile) 00743 { 00744 if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR))) 00745 { 00746 debug("Dynamic lib loaded at %ld", dls->lib); 00747 ofi = MAGIC_DYLIB_OFI; 00748 dls->module = MAGIC_DYLIB_MOD; 00749 ofirc = NSObjectFileImageSuccess; 00750 /* Although it is possible with a bit of work to modify this so it works and 00751 functions with RTLD_NOW, I don't deem it necessary at the moment */ 00752 } 00753 if (!(dls->module)) 00754 { 00755 NSLinkEditError(&ler, &lerno, &file, &errstr); 00756 if (!errstr || (!strlen(errstr))) 00757 error("Can't open this file type"); 00758 else 00759 error(errstr); 00760 if ((dls->flags & DL_IN_LIST) == 0) 00761 { 00762 free(dls); 00763 } 00764 return NULL; 00765 } 00766 } 00767 else 00768 { 00769 dls->module = NSLinkModule(ofi, path, 00770 NSLINKMODULE_OPTION_RETURN_ON_ERROR | 00771 NSLINKMODULE_OPTION_PRIVATE | 00772 (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0)); 00773 NSDestroyObjectFileImage(ofi); 00774 if (dls->module) 00775 { 00776 dls->lib = get_mach_header_from_NSModule(dls->module); 00777 } 00778 } 00779 if (!dls->module) 00780 { 00781 NSLinkEditError(&ler, &lerno, &file, &errstr); 00782 if ((dls->flags & DL_IN_LIST) == 0) 00783 { 00784 free(dls); 00785 } 00786 error(errstr); 00787 return NULL; 00788 } 00789 00790 insertStatus(dls, sbuf); 00791 dls = reference(dls, mode); 00792 if ((init = dlsymIntern(dls, "__init", 0))) 00793 { 00794 debug("calling _init()"); 00795 init(); 00796 } 00797 return dls; 00798 } 00799 00800 static void dlcompat_init_func(void) 00801 { 00802 static int inited = 0; 00803 if (!inited) 00804 { 00805 inited = 1; 00806 _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage); 00807 _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage", 00808 (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage); 00809 _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage); 00810 if (pthread_mutex_init(&dlcompat_mutex, NULL)) 00811 exit(1); 00812 if (pthread_key_create(&dlerror_key, &dlerrorfree)) 00813 exit(1); 00814 /* And be neat and tidy and clean up after ourselves */ 00815 atexit(dlcompat_cleanup); 00816 } 00817 } 00818 00819 #if 0 00820 #pragma CALL_ON_LOAD dlcompat_init_func 00821 #endif 00822 00823 static void dlcompat_cleanup(void) 00824 { 00825 struct dlstatus *dls; 00826 struct dlstatus *next; 00827 char *data; 00828 data = (char *)searchList(); 00829 if ( data ) 00830 free( data ); 00831 data = (char *)getSearchPath(-1); 00832 if ( data ) 00833 free( data ); 00834 pthread_mutex_destroy(&dlcompat_mutex); 00835 pthread_key_delete(dlerror_key); 00836 next = stqueue; 00837 while (next && (next != &mainStatus)) 00838 { 00839 dls = next; 00840 next = dls->next; 00841 free(dls); 00842 } 00843 } 00844 00845 static void resetdlerror() 00846 { 00847 struct dlthread *tss; 00848 tss = pthread_getspecific(dlerror_key); 00849 tss->errset = 0; 00850 } 00851 00852 static void dlerrorfree(void *data) 00853 { 00854 free(data); 00855 } 00856 00857 /* We kind of want a recursive lock here, but meet a little trouble 00858 * because they are not available pre OS X 10.2, so we fake it 00859 * using thread specific storage to keep a lock count 00860 */ 00861 static inline void dolock(void) 00862 { 00863 int err = 0; 00864 struct dlthread *tss; 00865 tss = pthread_getspecific(dlerror_key); 00866 if (!tss) 00867 { 00868 tss = malloc(sizeof(struct dlthread)); 00869 tss->lockcnt = 0; 00870 tss->errset = 0; 00871 if (pthread_setspecific(dlerror_key, tss)) 00872 { 00873 fprintf(stderr,"dlcompat: pthread_setspecific failed\n"); 00874 exit(1); 00875 } 00876 } 00877 if (!tss->lockcnt) 00878 err = pthread_mutex_lock(&dlcompat_mutex); 00879 tss->lockcnt = tss->lockcnt +1; 00880 if (err) 00881 exit(err); 00882 } 00883 00884 static inline void dounlock(void) 00885 { 00886 int err = 0; 00887 struct dlthread *tss; 00888 tss = pthread_getspecific(dlerror_key); 00889 tss->lockcnt = tss->lockcnt -1; 00890 if (!tss->lockcnt) 00891 err = pthread_mutex_unlock(&dlcompat_mutex); 00892 if (err) 00893 exit(err); 00894 } 00895 00896 void *dlopen(const char *path, int mode) 00897 { 00898 const struct stat *sbuf; 00899 struct dlstatus *dls; 00900 const char *fullPath; 00901 dlcompat_init_func(); /* Just in case */ 00902 dolock(); 00903 resetdlerror(); 00904 if (!path) 00905 { 00906 dls = &mainStatus; 00907 goto dlopenok; 00908 } 00909 if (!(sbuf = findFile(path, &fullPath))) 00910 { 00911 error("file \"%s\" not found", path); 00912 goto dlopenerror; 00913 } 00914 /* Now checks that it hasn't been closed already */ 00915 if ((dls = lookupStatus(sbuf)) && (dls->refs > 0)) 00916 { 00917 /* debug("status found"); */ 00918 dls = reference(dls, mode); 00919 goto dlopenok; 00920 } 00921 #ifdef RTLD_NOLOAD 00922 if (isFlagSet(mode, RTLD_NOLOAD)) 00923 { 00924 error("no existing handle and RTLD_NOLOAD specified"); 00925 goto dlopenerror; 00926 } 00927 #endif 00928 if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW)) 00929 { 00930 error("how can I load something both RTLD_LAZY and RTLD_NOW?"); 00931 goto dlopenerror; 00932 } 00933 dls = loadModule(fullPath, sbuf, mode); 00934 00935 dlopenok: 00936 dounlock(); 00937 return (void *)dls; 00938 dlopenerror: 00939 dounlock(); 00940 return NULL; 00941 } 00942 00943 #if !FINK_BUILD 00944 void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol) 00945 { 00946 int sym_len = strlen(symbol); 00947 void *value = NULL; 00948 char *malloc_sym = NULL; 00949 dolock(); 00950 malloc_sym = malloc(sym_len + 2); 00951 if (malloc_sym) 00952 { 00953 sprintf(malloc_sym, "_%s", symbol); 00954 value = dlsymIntern(handle, malloc_sym, 1); 00955 free(malloc_sym); 00956 } 00957 else 00958 { 00959 error("Unable to allocate memory"); 00960 goto dlsymerror; 00961 } 00962 dounlock(); 00963 return value; 00964 dlsymerror: 00965 dounlock(); 00966 return NULL; 00967 } 00968 #endif 00969 00970 #if FINK_BUILD 00971 00972 void *dlsym_prepend_underscore(void *handle, const char *symbol) 00973 { 00974 void *answer; 00975 dolock(); 00976 answer = dlsym_prepend_underscore_intern(handle, symbol); 00977 dounlock(); 00978 return answer; 00979 } 00980 00981 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol) 00982 { 00983 /* 00984 * A quick and easy way for porting packages which call dlsym(handle,"sym") 00985 * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then 00986 * this function will be called, and will add the required underscore. 00987 * 00988 * Note that I haven't figured out yet which should be "standard", prepend 00989 * the underscore always, or not at all. These global functions need to go away 00990 * for opendarwin. 00991 */ 00992 int sym_len = strlen(symbol); 00993 void *value = NULL; 00994 char *malloc_sym = NULL; 00995 malloc_sym = malloc(sym_len + 2); 00996 if (malloc_sym) 00997 { 00998 sprintf(malloc_sym, "_%s", symbol); 00999 value = dlsymIntern(handle, malloc_sym, 1); 01000 free(malloc_sym); 01001 } 01002 else 01003 { 01004 error("Unable to allocate memory"); 01005 } 01006 return value; 01007 } 01008 01009 void *dlsym_auto_underscore(void *handle, const char *symbol) 01010 { 01011 void *answer; 01012 dolock(); 01013 answer = dlsym_auto_underscore_intern(handle, symbol); 01014 dounlock(); 01015 return answer; 01016 01017 } 01018 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol) 01019 { 01020 struct dlstatus *dls = handle; 01021 void *addr = 0; 01022 addr = dlsymIntern(dls, symbol, 0); 01023 if (!addr) 01024 addr = dlsym_prepend_underscore_intern(handle, symbol); 01025 return addr; 01026 } 01027 01028 01029 void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol) 01030 { 01031 struct dlstatus *dls = handle; 01032 void *addr = 0; 01033 dolock(); 01034 addr = dlsymIntern(dls, symbol, 1); 01035 dounlock(); 01036 return addr; 01037 } 01038 #endif 01039 01040 int dlclose(void *handle) 01041 { 01042 struct dlstatus *dls = handle; 01043 dolock(); 01044 resetdlerror(); 01045 if (!isValidStatus(dls)) 01046 { 01047 goto dlcloseerror; 01048 } 01049 if (dls->module == MAGIC_DYLIB_MOD) 01050 { 01051 const char *name; 01052 if (!dls->lib) 01053 { 01054 name = "global context"; 01055 } 01056 else 01057 { 01058 name = get_lib_name(dls->lib); 01059 } 01060 warning("trying to close a .dylib!"); 01061 error("Not closing \"%s\" - dynamic libraries cannot be closed", name); 01062 goto dlcloseerror; 01063 } 01064 if (!dls->module) 01065 { 01066 error("module already closed"); 01067 goto dlcloseerror; 01068 } 01069 01070 if (dls->refs == 1) 01071 { 01072 unsigned long options = 0; 01073 void (*fini) (void); 01074 if ((fini = dlsymIntern(dls, "__fini", 0))) 01075 { 01076 debug("calling _fini()"); 01077 fini(); 01078 } 01079 #ifdef __ppc__ 01080 options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES; 01081 #endif 01082 #if 1 01083 /* Currently, if a module contains c++ static destructors and it is unloaded, we 01084 * get a segfault in atexit(), due to compiler and dynamic loader differences of 01085 * opinion, this works around that. 01086 * I really need a way to figure out from code if this is still necessary. 01087 */ 01088 if ((const struct section *)NULL != 01089 getsectbynamefromheader(get_mach_header_from_NSModule(dls->module), 01090 "__DATA", "__mod_term_func")) 01091 { 01092 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; 01093 } 01094 #endif 01095 #ifdef RTLD_NODELETE 01096 if (isFlagSet(dls->mode, RTLD_NODELETE)) 01097 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; 01098 #endif 01099 if (!NSUnLinkModule(dls->module, options)) 01100 { 01101 error("unable to unlink module"); 01102 goto dlcloseerror; 01103 } 01104 dls->refs--; 01105 dls->module = 0; 01106 /* Note: the dlstatus struct dls is neither removed from the list 01107 * nor is the memory it occupies freed. This shouldn't pose a 01108 * problem in mostly all cases, though. 01109 */ 01110 } 01111 dounlock(); 01112 return 0; 01113 dlcloseerror: 01114 dounlock(); 01115 return 1; 01116 } 01117 01118 const char *dlerror(void) 01119 { 01120 struct dlthread *tss; 01121 char * err_str; 01122 tss = pthread_getspecific(dlerror_key); 01123 err_str = tss->errstr; 01124 tss = pthread_getspecific(dlerror_key); 01125 if (tss->errset == 0) 01126 return 0; 01127 tss->errset = 0; 01128 return (err_str ); 01129 } 01130 01131 /* Given an address, return the mach_header for the image containing it 01132 * or zero if the given address is not contained in any loaded images. 01133 */ 01134 const struct mach_header *image_for_address(const void *address) 01135 { 01136 unsigned long i; 01137 unsigned long j; 01138 unsigned long count = _dyld_image_count(); 01139 struct mach_header *mh = 0; 01140 struct load_command *lc = 0; 01141 unsigned long addr = NULL; 01142 for (i = 0; i < count; i++) 01143 { 01144 addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i); 01145 mh = _dyld_get_image_header(i); 01146 if (mh) 01147 { 01148 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); 01149 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) 01150 { 01151 if (LC_SEGMENT == lc->cmd && 01152 addr >= ((struct segment_command *)lc)->vmaddr && 01153 addr < 01154 ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) 01155 { 01156 goto image_found; 01157 } 01158 } 01159 } 01160 mh = 0; 01161 } 01162 image_found: 01163 return mh; 01164 } 01165 01166 int dladdr(const void * dl_restrict p, Dl_info * dl_restrict info) 01167 { 01168 /* 01169 FIXME: USe the routine image_for_address. 01170 */ 01171 unsigned long i; 01172 unsigned long j; 01173 unsigned long count = _dyld_image_count(); 01174 struct mach_header *mh = 0; 01175 struct load_command *lc = 0; 01176 unsigned long addr = NULL; 01177 unsigned long table_off = (unsigned long)0; 01178 int found = 0; 01179 if (!info) 01180 return 0; 01181 dolock(); 01182 resetdlerror(); 01183 info->dli_fname = 0; 01184 info->dli_fbase = 0; 01185 info->dli_sname = 0; 01186 info->dli_saddr = 0; 01187 /* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com> 01188 * to darwin-development AT lists DOT apple DOT com and slightly modified 01189 */ 01190 for (i = 0; i < count; i++) 01191 { 01192 addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i); 01193 mh = _dyld_get_image_header(i); 01194 if (mh) 01195 { 01196 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); 01197 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) 01198 { 01199 if (LC_SEGMENT == lc->cmd && 01200 addr >= ((struct segment_command *)lc)->vmaddr && 01201 addr < 01202 ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) 01203 { 01204 info->dli_fname = _dyld_get_image_name(i); 01205 info->dli_fbase = (void *)mh; 01206 found = 1; 01207 break; 01208 } 01209 } 01210 if (found) 01211 break; 01212 } 01213 } 01214 if (!found) 01215 { 01216 dounlock(); 01217 return 0; 01218 } 01219 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); 01220 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) 01221 { 01222 if (LC_SEGMENT == lc->cmd) 01223 { 01224 if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT")) 01225 break; 01226 } 01227 } 01228 table_off = 01229 ((unsigned long)((struct segment_command *)lc)->vmaddr) - 01230 ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i); 01231 debug("table off %x", table_off); 01232 01233 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); 01234 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) 01235 { 01236 if (LC_SYMTAB == lc->cmd) 01237 { 01238 01239 struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off); 01240 unsigned long numsyms = ((struct symtab_command *)lc)->nsyms; 01241 struct nlist *nearest = NULL; 01242 unsigned long diff = 0xffffffff; 01243 unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off); 01244 debug("symtable %x", symtable); 01245 for (i = 0; i < numsyms; i++) 01246 { 01247 /* Ignore the following kinds of Symbols */ 01248 if ((!symtable->n_value) /* Undefined */ 01249 || (symtable->n_type >= N_PEXT) /* Debug symbol */ 01250 || (!(symtable->n_type & N_EXT)) /* Local Symbol */ 01251 ) 01252 { 01253 symtable++; 01254 continue; 01255 } 01256 if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr))) 01257 { 01258 diff = (unsigned long)symtable->n_value - addr; 01259 nearest = symtable; 01260 } 01261 symtable++; 01262 } 01263 if (nearest) 01264 { 01265 info->dli_saddr = nearest->n_value + ((void *)p - addr); 01266 info->dli_sname = (char *)(strtable + nearest->n_un.n_strx); 01267 } 01268 } 01269 } 01270 dounlock(); 01271 return 1; 01272 } 01273 01274 01275 /* 01276 * Implement the dlfunc() interface, which behaves exactly the same as 01277 * dlsym() except that it returns a function pointer instead of a data 01278 * pointer. This can be used by applications to avoid compiler warnings 01279 * about undefined behavior, and is intended as prior art for future 01280 * POSIX standardization. This function requires that all pointer types 01281 * have the same representation, which is true on all platforms FreeBSD 01282 * runs on, but is not guaranteed by the C standard. 01283 */ 01284 #if 0 01285 dlfunc_t dlfunc(void * dl_restrict handle, const char * dl_restrict symbol) 01286 { 01287 union 01288 { 01289 void *d; 01290 dlfunc_t f; 01291 } rv; 01292 int sym_len = strlen(symbol); 01293 char *malloc_sym = NULL; 01294 dolock(); 01295 malloc_sym = malloc(sym_len + 2); 01296 if (malloc_sym) 01297 { 01298 sprintf(malloc_sym, "_%s", symbol); 01299 rv.d = dlsymIntern(handle, malloc_sym, 1); 01300 free(malloc_sym); 01301 } 01302 else 01303 { 01304 error("Unable to allocate memory"); 01305 goto dlfuncerror; 01306 } 01307 dounlock(); 01308 return rv.f; 01309 dlfuncerror: 01310 dounlock(); 01311 return NULL; 01312 } 01313 #endif

Generated on Sat Jun 12 16:40:57 2004 for Asterisk by doxygen 1.3.7