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 #include <asterisk/dlfcn-compat.h>
00051
00052 #ifndef dl_restrict
00053 #define dl_restrict __restrict
00054 #endif
00055
00056 #ifndef LC_LOAD_WEAK_DYLIB
00057 #define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
00058 #endif
00059
00060
00061
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
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
00085
00086
00087
00088 #undef REUSE_STATUS
00089
00090
00091 #define ERR_STR_LEN 251
00092
00093
00094 #define MAX_SEARCH_PATHS 32
00095
00096
00097 #define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
00098 #define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
00099
00100
00101 #define DL_IN_LIST 0x01
00102
00103
00104 static pthread_mutex_t dlcompat_mutex;
00105
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
00117
00118
00119 struct dlstatus
00120 {
00121 struct dlstatus *next;
00122 NSModule module;
00123 const struct mach_header *lib;
00124 int refs;
00125 int mode;
00126 dev_t device;
00127 ino_t inode;
00128 int flags;
00129 };
00130
00131
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
00137
00138
00139
00140
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
00172 void *dlsym_prepend_underscore(void *handle, const char *symbol);
00173 void *dlsym_auto_underscore(void *handle, const char *symbol);
00174
00175
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
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
00224
00225
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
00247
00248
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
00270
00271
00272
00273
00274
00275
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
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
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
00355
00356
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;
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
00382 static int isValidStatus(struct dlstatus *status)
00383 {
00384
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 && ( 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
00501
00502
00503
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
00536 debug("Symbol \"%s\" is defined but was not found", symbol);
00537 }
00538 }
00539 return nssym;
00540 }
00541
00542
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);
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
00579
00580
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
00643 if (NSIsSymbolNameDefined(symbol))
00644 {
00645
00646
00647
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
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
00751
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
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
00858
00859
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();
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
00915 if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
00916 {
00917
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
00985
00986
00987
00988
00989
00990
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
01084
01085
01086
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
01107
01108
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
01132
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
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
01188
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
01248 if ((!symtable->n_value)
01249 || (symtable->n_type >= N_PEXT)
01250 || (!(symtable->n_type & N_EXT))
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
01277
01278
01279
01280
01281
01282
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