00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
00044
00045
00046
00047 #ifndef __BSD_VISIBLE
00048 #define __BSD_VISIBLE 1
00049 #endif
00050
00051 #include "asterisk/dlfcn-compat.h"
00052
00053 #ifndef dl_restrict
00054 #define dl_restrict __restrict
00055 #endif
00056
00057 #ifndef LC_LOAD_WEAK_DYLIB
00058 #define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
00059 #endif
00060
00061
00062
00063
00064 #ifndef LC_REQ_DYLD
00065 #define LC_REQ_DYLD 0x80000000
00066 #endif
00067 #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
00068 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
00069 #endif
00070 #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
00071 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
00072 #endif
00073 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
00074 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
00075 #endif
00076 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
00077 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
00078 #endif
00079
00080 static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
00081 static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
00082 static NSSymbol(*dyld_NSLookupSymbolInImage)
00083 (const struct mach_header *, const char *, unsigned long) = 0;
00084
00085
00086
00087
00088
00089 #undef REUSE_STATUS
00090
00091
00092 #define ERR_STR_LEN 251
00093
00094
00095 #define MAX_SEARCH_PATHS 32
00096
00097
00098 #define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
00099 #define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
00100
00101
00102 #define DL_IN_LIST 0x01
00103
00104
00105 static pthread_mutex_t dlcompat_mutex;
00106
00107
00108 static pthread_key_t dlerror_key;
00109
00110 struct dlthread
00111 {
00112 int lockcnt;
00113 unsigned char errset;
00114 char errstr[ERR_STR_LEN];
00115 };
00116
00117
00118
00119
00120 struct dlstatus
00121 {
00122 struct dlstatus *next;
00123 NSModule module;
00124 const struct mach_header *lib;
00125 int refs;
00126 int mode;
00127 dev_t device;
00128 ino_t inode;
00129 int flags;
00130 };
00131
00132
00133 static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
00134 static struct dlstatus *stqueue = &mainStatus;
00135
00136
00137
00138
00139
00140
00141
00142 static void debug(const char *fmt, ...);
00143 static void error(const char *str, ...);
00144 static const char *safegetenv(const char *s);
00145 static const char *searchList(void);
00146 static const char *getSearchPath(int i);
00147 static const char *getFullPath(int i, const char *file);
00148 static const struct stat *findFile(const char *file, const char **fullPath);
00149 static int isValidStatus(struct dlstatus *status);
00150 static inline int isFlagSet(int mode, int flag);
00151 static struct dlstatus *lookupStatus(const struct stat *sbuf);
00152 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
00153 static int promoteLocalToGlobal(struct dlstatus *dls);
00154 static void *reference(struct dlstatus *dls, int mode);
00155 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
00156 static struct dlstatus *allocStatus(void);
00157 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
00158 static NSSymbol *search_linked_libs(const struct mach_header *mh, const char *symbol);
00159 static const char *get_lib_name(const struct mach_header *mh);
00160 static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod);
00161 static void dlcompat_init_func(void);
00162 static inline void dolock(void);
00163 static inline void dounlock(void);
00164 static void dlerrorfree(void *data);
00165 static void resetdlerror(void);
00166 static const struct mach_header *my_find_image(const char *name);
00167 static const struct mach_header *image_for_address(const void *address);
00168 static void dlcompat_cleanup(void);
00169 static inline const char *dyld_error_str(void);
00170
00171 #if FINK_BUILD
00172
00173 void *dlsym_prepend_underscore(void *handle, const char *symbol);
00174 void *dlsym_auto_underscore(void *handle, const char *symbol);
00175
00176
00177 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
00178 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
00179 #endif
00180
00181
00182
00183 static void debug(const char *fmt, ...)
00184 {
00185 #if DEBUG > 1
00186 va_list arg;
00187 va_start(arg, fmt);
00188 fprintf(stderr, "DLDEBUG: ");
00189 vfprintf(stderr, fmt, arg);
00190 fprintf(stderr, "\n");
00191 fflush(stderr);
00192 va_end(arg);
00193 #endif
00194 }
00195
00196 static void error(const char *str, ...)
00197 {
00198 va_list arg;
00199 struct dlthread *tss;
00200 char * err_str;
00201 va_start(arg, str);
00202 tss = pthread_getspecific(dlerror_key);
00203 err_str = tss->errstr;
00204 strncpy(err_str, "dlcompat: ", ERR_STR_LEN);
00205 vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
00206 va_end(arg);
00207 debug("ERROR: %s\n", err_str);
00208 tss->errset = 1;
00209 }
00210
00211 static void warning(const char *str)
00212 {
00213 #if DEBUG > 0
00214 fprintf(stderr, "WARNING: dlcompat: %s\n", str);
00215 #endif
00216 }
00217
00218 static const char *safegetenv(const char *s)
00219 {
00220 const char *ss = getenv(s);
00221 return ss ? ss : "";
00222 }
00223
00224
00225
00226
00227
00228 static const char *get_lib_name(const struct mach_header *mh)
00229 {
00230 unsigned long count = _dyld_image_count();
00231 unsigned long i;
00232 const char *val = NULL;
00233 if (mh)
00234 {
00235 for (i = 0; i < count; i++)
00236 {
00237 if (mh == _dyld_get_image_header(i))
00238 {
00239 val = _dyld_get_image_name(i);
00240 break;
00241 }
00242 }
00243 }
00244 return val;
00245 }
00246
00247
00248
00249
00250
00251 static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod)
00252 {
00253 const char *mod_name = NSNameOfModule(mod);
00254 struct mach_header *mh = NULL;
00255 unsigned long count = _dyld_image_count();
00256 unsigned long i;
00257 debug("Module name: %s", mod_name);
00258 for (i = 0; i < count; i++)
00259 {
00260 if (!strcmp(mod_name, _dyld_get_image_name(i)))
00261 {
00262 mh = _dyld_get_image_header(i);
00263 break;
00264 }
00265 }
00266 return mh;
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 static const char *searchList()
00279 {
00280 size_t buf_size;
00281 static char *buf=NULL;
00282 const char *ldlp = safegetenv("LD_LIBRARY_PATH");
00283 const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
00284 const char *stdpath = getenv("DYLD_FALLBACK_LIBRARY_PATH");
00285 if (!stdpath)
00286 stdpath = "/usr/local/lib:/lib:/usr/lib";
00287 if (!buf)
00288 {
00289 buf_size = strlen(ldlp) + strlen(dyldlp) + strlen(stdpath) + 4;
00290 buf = malloc(buf_size);
00291 snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
00292 stdpath, '\0');
00293 }
00294 return buf;
00295 }
00296
00297
00298 static const char *getSearchPath(int i)
00299 {
00300 static const char *list = 0;
00301 static char **path = (char **)0;
00302 static int end = 0;
00303 static int numsize = MAX_SEARCH_PATHS;
00304 static char **tmp;
00305
00306 if (i == -1)
00307 {
00308 return (const char*)path;
00309 }
00310 if (!path)
00311 {
00312 path = (char **)calloc(MAX_SEARCH_PATHS, sizeof(char **));
00313 }
00314 if (!list && !end)
00315 list = searchList();
00316 if (i >= (numsize))
00317 {
00318 debug("Increasing size for long PATH");
00319 tmp = (char **)calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
00320 if (tmp)
00321 {
00322 memcpy(tmp, path, sizeof(char **) * numsize);
00323 free(path);
00324 path = tmp;
00325 numsize += MAX_SEARCH_PATHS;
00326 }
00327 else
00328 {
00329 return 0;
00330 }
00331 }
00332
00333 while (!path[i] && !end)
00334 {
00335 path[i] = strsep((char **)&list, ":");
00336
00337 if (path[i][0] == 0)
00338 path[i] = 0;
00339 end = (list == 0);
00340 }
00341 return path[i];
00342 }
00343
00344 static const char *getFullPath(int i, const char *file)
00345 {
00346 static char buf[PATH_MAX];
00347 const char *path = getSearchPath(i);
00348 if (path)
00349 {
00350 snprintf(buf, PATH_MAX, "%s/%s", path, file);
00351 }
00352 return path ? buf : 0;
00353 }
00354
00355
00356
00357
00358
00359 static const struct stat *findFile(const char *file, const char **fullPath)
00360 {
00361 int i = 0;
00362 static struct stat sbuf;
00363 char *fileName;
00364 debug("finding file %s", file);
00365 *fullPath = file;
00366 if (0 == stat(file, &sbuf))
00367 return &sbuf;
00368 if (strchr(file, '/'))
00369 return 0;
00370 fileName = NULL;
00371 if (!fileName)
00372 fileName = (char *)file;
00373 while ((*fullPath = getFullPath(i++, fileName)))
00374 {
00375 if (0 == stat(*fullPath, &sbuf))
00376 return &sbuf;
00377 }
00378 ;
00379 return 0;
00380 }
00381
00382
00383 static int isValidStatus(struct dlstatus *status)
00384 {
00385
00386 struct dlstatus *dls = stqueue;
00387 while (dls && status != dls)
00388 dls = dls->next;
00389 if (dls == 0)
00390 error("invalid handle");
00391 else if ((dls->module == 0) || (dls->refs == 0))
00392 error("handle to closed library");
00393 else
00394 return TRUE;
00395 return FALSE;
00396 }
00397
00398 static inline int isFlagSet(int mode, int flag)
00399 {
00400 return (mode & flag) == flag;
00401 }
00402
00403 static struct dlstatus *lookupStatus(const struct stat *sbuf)
00404 {
00405 struct dlstatus *dls = stqueue;
00406 debug("looking for status");
00407 while (dls && ( 0
00408 || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
00409 dls = dls->next;
00410 return dls;
00411 }
00412
00413 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
00414 {
00415 debug("inserting status");
00416 dls->inode = sbuf->st_ino;
00417 dls->device = sbuf->st_dev;
00418 dls->refs = 0;
00419 dls->mode = 0;
00420 if ((dls->flags & DL_IN_LIST) == 0)
00421 {
00422 dls->next = stqueue;
00423 stqueue = dls;
00424 dls->flags |= DL_IN_LIST;
00425 }
00426 }
00427
00428 static struct dlstatus *allocStatus()
00429 {
00430 struct dlstatus *dls;
00431 #ifdef REUSE_STATUS
00432 dls = stqueue;
00433 while (dls && dls->module)
00434 dls = dls->next;
00435 if (!dls)
00436 #endif
00437 dls = malloc(sizeof(*dls));
00438 dls->flags = 0;
00439 return dls;
00440 }
00441
00442 static int promoteLocalToGlobal(struct dlstatus *dls)
00443 {
00444 static int (*p) (NSModule module) = 0;
00445 debug("promoting");
00446 if (!p)
00447 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p);
00448 return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
00449 }
00450
00451 static void *reference(struct dlstatus *dls, int mode)
00452 {
00453 if (dls)
00454 {
00455 if (dls->module == MAGIC_DYLIB_MOD && !isFlagSet(mode, RTLD_GLOBAL))
00456 {
00457 warning("trying to open a .dylib with RTLD_LOCAL");
00458 error("unable to open a .dylib with RTLD_LOCAL");
00459 return NULL;
00460 }
00461 if (isFlagSet(mode, RTLD_GLOBAL) &&
00462 !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
00463 {
00464 error("unable to promote local module to global");
00465 return NULL;
00466 }
00467 dls->mode |= mode;
00468 dls->refs++;
00469 }
00470 else
00471 debug("reference called with NULL argument");
00472
00473 return dls;
00474 }
00475
00476 static const struct mach_header *my_find_image(const char *name)
00477 {
00478 const struct mach_header *mh = 0;
00479 const char *id = NULL;
00480 int i = _dyld_image_count();
00481 int j;
00482 mh = (struct mach_header *)
00483 dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
00484 NSADDIMAGE_OPTION_RETURN_ON_ERROR);
00485 if (!mh)
00486 {
00487 for (j = 0; j < i; j++)
00488 {
00489 id = _dyld_get_image_name(j);
00490 if (!strcmp(id, name))
00491 {
00492 mh = _dyld_get_image_header(j);
00493 break;
00494 }
00495 }
00496 }
00497 return mh;
00498 }
00499
00500
00501
00502
00503
00504
00505
00506 NSSymbol *search_linked_libs(const struct mach_header * mh, const char *symbol)
00507 {
00508 int n;
00509 struct load_command *lc = 0;
00510 struct mach_header *wh;
00511 NSSymbol *nssym = 0;
00512 if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
00513 {
00514 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
00515 for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
00516 {
00517 if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
00518 {
00519 if ((wh = (struct mach_header *)
00520 my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
00521 (char *)lc))))
00522 {
00523 if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
00524 {
00525 nssym = dyld_NSLookupSymbolInImage(wh,
00526 symbol,
00527 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
00528 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
00529 break;
00530 }
00531 }
00532 }
00533 }
00534 if ((!nssym) && NSIsSymbolNameDefined(symbol))
00535 {
00536
00537 debug("Symbol \"%s\" is defined but was not found", symbol);
00538 }
00539 }
00540 return nssym;
00541 }
00542
00543
00544 static inline const char *dyld_error_str()
00545 {
00546 NSLinkEditErrors dylder;
00547 int dylderno;
00548 const char *dylderrstr;
00549 const char *dyldfile;
00550 const char* retStr = NULL;
00551 NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
00552 if (dylderrstr && strlen(dylderrstr))
00553 {
00554 retStr = malloc(strlen(dylderrstr) +1);
00555 strcpy((char*)retStr,dylderrstr);
00556 }
00557 return retStr;
00558 }
00559
00560 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
00561 {
00562 NSSymbol *nssym = 0;
00563 void *caller = __builtin_return_address(1);
00564 const struct mach_header *caller_mh = 0;
00565 const char* savedErrorStr = NULL;
00566 resetdlerror();
00567 #ifndef RTLD_SELF
00568 #define RTLD_SELF ((void *) -3)
00569 #endif
00570 if (NULL == dls)
00571 dls = RTLD_SELF;
00572 if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
00573 {
00574 if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
00575 {
00576 caller_mh = image_for_address(caller);
00577 if (RTLD_SELF == dls)
00578 {
00579
00580
00581
00582
00583 if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
00584 {
00585 nssym = dyld_NSLookupSymbolInImage(caller_mh,
00586 symbol,
00587 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
00588 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
00589 }
00590 }
00591 if (!nssym)
00592 {
00593 if (RTLD_SELF == dls)
00594 savedErrorStr = dyld_error_str();
00595 nssym = search_linked_libs(caller_mh, symbol);
00596 }
00597 }
00598 else
00599 {
00600 if (canSetError)
00601 error("RTLD_SELF and RTLD_NEXT are not supported");
00602 return NULL;
00603 }
00604 }
00605 if (!nssym)
00606 {
00607
00608 if (RTLD_DEFAULT == dls)
00609 {
00610 dls = &mainStatus;
00611 }
00612 if (!isValidStatus(dls))
00613 return NULL;
00614
00615 if (dls->module != MAGIC_DYLIB_MOD)
00616 {
00617 nssym = NSLookupSymbolInModule(dls->module, symbol);
00618 if (!nssym && NSIsSymbolNameDefined(symbol))
00619 {
00620 debug("Searching dependencies");
00621 savedErrorStr = dyld_error_str();
00622 nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
00623 }
00624 }
00625 else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
00626 {
00627 if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
00628 {
00629 nssym = dyld_NSLookupSymbolInImage(dls->lib,
00630 symbol,
00631 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
00632 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
00633 }
00634 else if (NSIsSymbolNameDefined(symbol))
00635 {
00636 debug("Searching dependencies");
00637 savedErrorStr = dyld_error_str();
00638 nssym = search_linked_libs(dls->lib, symbol);
00639 }
00640 }
00641 else if (dls->module == MAGIC_DYLIB_MOD)
00642 {
00643
00644 if (NSIsSymbolNameDefined(symbol))
00645 {
00646
00647
00648
00649 nssym = NSLookupAndBindSymbol(symbol);
00650 }
00651 else
00652 {
00653 if (savedErrorStr)
00654 free((char*)savedErrorStr);
00655 savedErrorStr = malloc(256);
00656 snprintf((char*)savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);
00657 }
00658 }
00659 }
00660
00661 if (!nssym)
00662 {
00663 if (!savedErrorStr || !strlen(savedErrorStr))
00664 {
00665 if (savedErrorStr)
00666 free((char*)savedErrorStr);
00667 savedErrorStr = malloc(256);
00668 snprintf((char*)savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
00669 }
00670 if (canSetError)
00671 {
00672 error(savedErrorStr);
00673 }
00674 else
00675 {
00676 debug(savedErrorStr);
00677 }
00678 if (savedErrorStr)
00679 free((char*)savedErrorStr);
00680 return NULL;
00681 }
00682 return NSAddressOfSymbol(nssym);
00683 }
00684
00685 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
00686 {
00687 NSObjectFileImage ofi = 0;
00688 NSObjectFileImageReturnCode ofirc;
00689 struct dlstatus *dls;
00690 NSLinkEditErrors ler;
00691 int lerno;
00692 const char *errstr;
00693 const char *file;
00694 void (*init) (void);
00695 ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
00696 switch (ofirc)
00697 {
00698 case NSObjectFileImageSuccess:
00699 break;
00700 case NSObjectFileImageInappropriateFile:
00701 if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
00702 {
00703 if (!isFlagSet(mode, RTLD_GLOBAL))
00704 {
00705 warning("trying to open a .dylib with RTLD_LOCAL");
00706 error("unable to open this file with RTLD_LOCAL");
00707 return NULL;
00708 }
00709 }
00710 else
00711 {
00712 error("opening this file is unsupported on this system");
00713 return NULL;
00714 }
00715 break;
00716 case NSObjectFileImageFailure:
00717 error("object file setup failure");
00718 return NULL;
00719 case NSObjectFileImageArch:
00720 error("no object for this architecture");
00721 return NULL;
00722 case NSObjectFileImageFormat:
00723 error("bad object file format");
00724 return NULL;
00725 case NSObjectFileImageAccess:
00726 error("can't read object file");
00727 return NULL;
00728 default:
00729 error("unknown error from NSCreateObjectFileImageFromFile()");
00730 return NULL;
00731 }
00732 dls = lookupStatus(sbuf);
00733 if (!dls)
00734 {
00735 dls = allocStatus();
00736 }
00737 if (!dls)
00738 {
00739 error("unable to allocate memory");
00740 return NULL;
00741 }
00742 dls->lib = 0;
00743 if (ofirc == NSObjectFileImageInappropriateFile)
00744 {
00745 if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
00746 {
00747 debug("Dynamic lib loaded at %ld", dls->lib);
00748 ofi = MAGIC_DYLIB_OFI;
00749 dls->module = MAGIC_DYLIB_MOD;
00750 ofirc = NSObjectFileImageSuccess;
00751
00752
00753 }
00754 if (!(dls->module))
00755 {
00756 NSLinkEditError(&ler, &lerno, &file, &errstr);
00757 if (!errstr || (!strlen(errstr)))
00758 error("Can't open this file type");
00759 else
00760 error(errstr);
00761 if ((dls->flags & DL_IN_LIST) == 0)
00762 {
00763 free(dls);
00764 }
00765 return NULL;
00766 }
00767 }
00768 else
00769 {
00770 dls->module = NSLinkModule(ofi, path,
00771 NSLINKMODULE_OPTION_RETURN_ON_ERROR |
00772 NSLINKMODULE_OPTION_PRIVATE |
00773 (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
00774 NSDestroyObjectFileImage(ofi);
00775 if (dls->module)
00776 {
00777 dls->lib = get_mach_header_from_NSModule(dls->module);
00778 }
00779 }
00780 if (!dls->module)
00781 {
00782 NSLinkEditError(&ler, &lerno, &file, &errstr);
00783 if ((dls->flags & DL_IN_LIST) == 0)
00784 {
00785 free(dls);
00786 }
00787 error(errstr);
00788 return NULL;
00789 }
00790
00791 insertStatus(dls, sbuf);
00792 dls = reference(dls, mode);
00793 if ((init = dlsymIntern(dls, "__init", 0)))
00794 {
00795 debug("calling _init()");
00796 init();
00797 }
00798 return dls;
00799 }
00800
00801 static void dlcompat_init_func(void)
00802 {
00803 static int inited = 0;
00804 if (!inited)
00805 {
00806 inited = 1;
00807 _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage);
00808 _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
00809 (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage);
00810 _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage);
00811 if (pthread_mutex_init(&dlcompat_mutex, NULL))
00812 exit(1);
00813 if (pthread_key_create(&dlerror_key, &dlerrorfree))
00814 exit(1);
00815
00816 atexit(dlcompat_cleanup);
00817 }
00818 }
00819
00820 #if 0
00821 #pragma CALL_ON_LOAD dlcompat_init_func
00822 #endif
00823
00824 static void dlcompat_cleanup(void)
00825 {
00826 struct dlstatus *dls;
00827 struct dlstatus *next;
00828 char *data;
00829 data = (char *)searchList();
00830 if ( data )
00831 free( data );
00832 data = (char *)getSearchPath(-1);
00833 if ( data )
00834 free( data );
00835 pthread_mutex_destroy(&dlcompat_mutex);
00836 pthread_key_delete(dlerror_key);
00837 next = stqueue;
00838 while (next && (next != &mainStatus))
00839 {
00840 dls = next;
00841 next = dls->next;
00842 free(dls);
00843 }
00844 }
00845
00846 static void resetdlerror()
00847 {
00848 struct dlthread *tss;
00849 tss = pthread_getspecific(dlerror_key);
00850 tss->errset = 0;
00851 }
00852
00853 static void dlerrorfree(void *data)
00854 {
00855 free(data);
00856 }
00857
00858
00859
00860
00861
00862 static inline void dolock(void)
00863 {
00864 int err = 0;
00865 struct dlthread *tss;
00866 tss = pthread_getspecific(dlerror_key);
00867 if (!tss)
00868 {
00869 tss = malloc(sizeof(struct dlthread));
00870 tss->lockcnt = 0;
00871 tss->errset = 0;
00872 if (pthread_setspecific(dlerror_key, tss))
00873 {
00874 fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
00875 exit(1);
00876 }
00877 }
00878 if (!tss->lockcnt)
00879 err = pthread_mutex_lock(&dlcompat_mutex);
00880 tss->lockcnt = tss->lockcnt +1;
00881 if (err)
00882 exit(err);
00883 }
00884
00885 static inline void dounlock(void)
00886 {
00887 int err = 0;
00888 struct dlthread *tss;
00889 tss = pthread_getspecific(dlerror_key);
00890 tss->lockcnt = tss->lockcnt -1;
00891 if (!tss->lockcnt)
00892 err = pthread_mutex_unlock(&dlcompat_mutex);
00893 if (err)
00894 exit(err);
00895 }
00896
00897 void *dlopen(const char *path, int mode)
00898 {
00899 const struct stat *sbuf;
00900 struct dlstatus *dls;
00901 const char *fullPath;
00902 dlcompat_init_func();
00903 dolock();
00904 resetdlerror();
00905 if (!path)
00906 {
00907 dls = &mainStatus;
00908 goto dlopenok;
00909 }
00910 if (!(sbuf = findFile(path, &fullPath)))
00911 {
00912 error("file \"%s\" not found", path);
00913 goto dlopenerror;
00914 }
00915
00916 if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
00917 {
00918
00919 dls = reference(dls, mode);
00920 goto dlopenok;
00921 }
00922 #ifdef RTLD_NOLOAD
00923 if (isFlagSet(mode, RTLD_NOLOAD))
00924 {
00925 error("no existing handle and RTLD_NOLOAD specified");
00926 goto dlopenerror;
00927 }
00928 #endif
00929 if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
00930 {
00931 error("how can I load something both RTLD_LAZY and RTLD_NOW?");
00932 goto dlopenerror;
00933 }
00934 dls = loadModule(fullPath, sbuf, mode);
00935
00936 dlopenok:
00937 dounlock();
00938 return (void *)dls;
00939 dlopenerror:
00940 dounlock();
00941 return NULL;
00942 }
00943
00944 #if !FINK_BUILD
00945 void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
00946 {
00947 int sym_len = strlen(symbol);
00948 void *value = NULL;
00949 char *malloc_sym = NULL;
00950 dolock();
00951 malloc_sym = malloc(sym_len + 2);
00952 if (malloc_sym)
00953 {
00954 sprintf(malloc_sym, "_%s", symbol);
00955 value = dlsymIntern(handle, malloc_sym, 1);
00956 free(malloc_sym);
00957 }
00958 else
00959 {
00960 error("Unable to allocate memory");
00961 goto dlsymerror;
00962 }
00963 dounlock();
00964 return value;
00965 dlsymerror:
00966 dounlock();
00967 return NULL;
00968 }
00969 #endif
00970
00971 #if FINK_BUILD
00972
00973 void *dlsym_prepend_underscore(void *handle, const char *symbol)
00974 {
00975 void *answer;
00976 dolock();
00977 answer = dlsym_prepend_underscore_intern(handle, symbol);
00978 dounlock();
00979 return answer;
00980 }
00981
00982 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
00983 {
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993 int sym_len = strlen(symbol);
00994 void *value = NULL;
00995 char *malloc_sym = NULL;
00996 malloc_sym = malloc(sym_len + 2);
00997 if (malloc_sym)
00998 {
00999 sprintf(malloc_sym, "_%s", symbol);
01000 value = dlsymIntern(handle, malloc_sym, 1);
01001 free(malloc_sym);
01002 }
01003 else
01004 {
01005 error("Unable to allocate memory");
01006 }
01007 return value;
01008 }
01009
01010 void *dlsym_auto_underscore(void *handle, const char *symbol)
01011 {
01012 void *answer;
01013 dolock();
01014 answer = dlsym_auto_underscore_intern(handle, symbol);
01015 dounlock();
01016 return answer;
01017
01018 }
01019 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
01020 {
01021 struct dlstatus *dls = handle;
01022 void *addr = 0;
01023 addr = dlsymIntern(dls, symbol, 0);
01024 if (!addr)
01025 addr = dlsym_prepend_underscore_intern(handle, symbol);
01026 return addr;
01027 }
01028
01029
01030 void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
01031 {
01032 struct dlstatus *dls = handle;
01033 void *addr = 0;
01034 dolock();
01035 addr = dlsymIntern(dls, symbol, 1);
01036 dounlock();
01037 return addr;
01038 }
01039 #endif
01040
01041 int dlclose(void *handle)
01042 {
01043 struct dlstatus *dls = handle;
01044 dolock();
01045 resetdlerror();
01046 if (!isValidStatus(dls))
01047 {
01048 goto dlcloseerror;
01049 }
01050 if (dls->module == MAGIC_DYLIB_MOD)
01051 {
01052 const char *name;
01053 if (!dls->lib)
01054 {
01055 name = "global context";
01056 }
01057 else
01058 {
01059 name = get_lib_name(dls->lib);
01060 }
01061 warning("trying to close a .dylib!");
01062 error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
01063 goto dlcloseerror;
01064 }
01065 if (!dls->module)
01066 {
01067 error("module already closed");
01068 goto dlcloseerror;
01069 }
01070
01071 if (dls->refs == 1)
01072 {
01073 unsigned long options = 0;
01074 void (*fini) (void);
01075 if ((fini = dlsymIntern(dls, "__fini", 0)))
01076 {
01077 debug("calling _fini()");
01078 fini();
01079 }
01080 #ifdef __ppc__
01081 options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
01082 #endif
01083 #if 1
01084
01085
01086
01087
01088
01089 if ((const struct section *)NULL !=
01090 getsectbynamefromheader(get_mach_header_from_NSModule(dls->module),
01091 "__DATA", "__mod_term_func"))
01092 {
01093 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
01094 }
01095 #endif
01096 #ifdef RTLD_NODELETE
01097 if (isFlagSet(dls->mode, RTLD_NODELETE))
01098 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
01099 #endif
01100 if (!NSUnLinkModule(dls->module, options))
01101 {
01102 error("unable to unlink module");
01103 goto dlcloseerror;
01104 }
01105 dls->refs--;
01106 dls->module = 0;
01107
01108
01109
01110
01111 }
01112 dounlock();
01113 return 0;
01114 dlcloseerror:
01115 dounlock();
01116 return 1;
01117 }
01118
01119 const char *dlerror(void)
01120 {
01121 struct dlthread *tss;
01122 char * err_str;
01123 tss = pthread_getspecific(dlerror_key);
01124 err_str = tss->errstr;
01125 tss = pthread_getspecific(dlerror_key);
01126 if (tss->errset == 0)
01127 return 0;
01128 tss->errset = 0;
01129 return (err_str );
01130 }
01131
01132
01133
01134
01135 const struct mach_header *image_for_address(const void *address)
01136 {
01137 unsigned long i;
01138 unsigned long j;
01139 unsigned long count = _dyld_image_count();
01140 struct mach_header *mh = 0;
01141 struct load_command *lc = 0;
01142 unsigned long addr = NULL;
01143 for (i = 0; i < count; i++)
01144 {
01145 addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
01146 mh = _dyld_get_image_header(i);
01147 if (mh)
01148 {
01149 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
01150 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
01151 {
01152 if (LC_SEGMENT == lc->cmd &&
01153 addr >= ((struct segment_command *)lc)->vmaddr &&
01154 addr <
01155 ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
01156 {
01157 goto image_found;
01158 }
01159 }
01160 }
01161 mh = 0;
01162 }
01163 image_found:
01164 return mh;
01165 }
01166
01167 int dladdr(const void * dl_restrict p, Dl_info * dl_restrict info)
01168 {
01169
01170
01171
01172 unsigned long i;
01173 unsigned long j;
01174 unsigned long count = _dyld_image_count();
01175 struct mach_header *mh = 0;
01176 struct load_command *lc = 0;
01177 unsigned long addr = NULL;
01178 unsigned long table_off = (unsigned long)0;
01179 int found = 0;
01180 if (!info)
01181 return 0;
01182 dolock();
01183 resetdlerror();
01184 info->dli_fname = 0;
01185 info->dli_fbase = 0;
01186 info->dli_sname = 0;
01187 info->dli_saddr = 0;
01188
01189
01190
01191 for (i = 0; i < count; i++)
01192 {
01193 addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
01194 mh = _dyld_get_image_header(i);
01195 if (mh)
01196 {
01197 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
01198 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
01199 {
01200 if (LC_SEGMENT == lc->cmd &&
01201 addr >= ((struct segment_command *)lc)->vmaddr &&
01202 addr <
01203 ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
01204 {
01205 info->dli_fname = _dyld_get_image_name(i);
01206 info->dli_fbase = (void *)mh;
01207 found = 1;
01208 break;
01209 }
01210 }
01211 if (found)
01212 break;
01213 }
01214 }
01215 if (!found)
01216 {
01217 dounlock();
01218 return 0;
01219 }
01220 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
01221 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
01222 {
01223 if (LC_SEGMENT == lc->cmd)
01224 {
01225 if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
01226 break;
01227 }
01228 }
01229 table_off =
01230 ((unsigned long)((struct segment_command *)lc)->vmaddr) -
01231 ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i);
01232 debug("table off %x", table_off);
01233
01234 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
01235 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
01236 {
01237 if (LC_SYMTAB == lc->cmd)
01238 {
01239
01240 struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off);
01241 unsigned long numsyms = ((struct symtab_command *)lc)->nsyms;
01242 struct nlist *nearest = NULL;
01243 unsigned long diff = 0xffffffff;
01244 unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off);
01245 debug("symtable %x", symtable);
01246 for (i = 0; i < numsyms; i++)
01247 {
01248
01249 if ((!symtable->n_value)
01250 || (symtable->n_type >= N_PEXT)
01251 || (!(symtable->n_type & N_EXT))
01252 )
01253 {
01254 symtable++;
01255 continue;
01256 }
01257 if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
01258 {
01259 diff = (unsigned long)symtable->n_value - addr;
01260 nearest = symtable;
01261 }
01262 symtable++;
01263 }
01264 if (nearest)
01265 {
01266 info->dli_saddr = nearest->n_value + ((void *)p - addr);
01267 info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
01268 }
01269 }
01270 }
01271 dounlock();
01272 return 1;
01273 }
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285 #if 0
01286 dlfunc_t dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
01287 {
01288 union
01289 {
01290 void *d;
01291 dlfunc_t f;
01292 } rv;
01293 int sym_len = strlen(symbol);
01294 char *malloc_sym = NULL;
01295 dolock();
01296 malloc_sym = malloc(sym_len + 2);
01297 if (malloc_sym)
01298 {
01299 sprintf(malloc_sym, "_%s", symbol);
01300 rv.d = dlsymIntern(handle, malloc_sym, 1);
01301 free(malloc_sym);
01302 }
01303 else
01304 {
01305 error("Unable to allocate memory");
01306 goto dlfuncerror;
01307 }
01308 dounlock();
01309 return rv.f;
01310 dlfuncerror:
01311 dounlock();
01312 return NULL;
01313 }
01314 #endif