📄 dlfcn.c
字号:
exit(err);}static inline void dounlock(void){ int err = 0; struct dlthread *tss; tss = pthread_getspecific(dlerror_key); tss->lockcnt = tss->lockcnt -1; if (!tss->lockcnt) err = pthread_mutex_unlock(&dlcompat_mutex); if (err) exit(err);}void *DL_PREFIX(dlopen)(const char *path, int mode){ const struct stat *sbuf; struct dlstatus *dls; const char *fullPath; dolock(); resetdlerror(); if (!path) { dls = &mainStatus; goto dlopenok; } if (!(sbuf = findFile(path, &fullPath))) { error("file \"%s\" not found", path); goto dlopenerror; } /* Now checks that it hasn't been closed already */ if ((dls = lookupStatus(sbuf)) && (dls->refs > 0)) { /* debug("status found"); */ dls = reference(dls, mode); goto dlopenok; }#ifdef RTLD_NOLOAD if (isFlagSet(mode, RTLD_NOLOAD)) { error("no existing handle and RTLD_NOLOAD specified"); goto dlopenerror; }#endif if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW)) { error("how can I load something both RTLD_LAZY and RTLD_NOW?"); goto dlopenerror; } dls = loadModule(fullPath, sbuf, mode); dlopenok: dounlock(); return (void *)dls; dlopenerror: dounlock(); return NULL;}#if !FINK_BUILDvoid *DL_PREFIX(dlsym)(void * dl_restrict handle, const char * dl_restrict symbol){ int sym_len = strlen(symbol); void *value = NULL; char *malloc_sym = NULL; dolock(); malloc_sym = malloc(sym_len + 2); if (malloc_sym) { sprintf(malloc_sym, "_%s", symbol); value = dlsymIntern(handle, malloc_sym, 1); free(malloc_sym); } else { error("Unable to allocate memory"); goto dlsymerror; } dounlock(); return value; dlsymerror: dounlock(); return NULL;}#endif#if FINK_BUILDstatic void *dlsym_prepend_underscore(void *handle, const char *symbol){ void *answer; dolock(); answer = dlsym_prepend_underscore_intern(handle, symbol); dounlock(); return answer;}static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol){/* * A quick and easy way for porting packages which call dlsym(handle,"sym") * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then * this function will be called, and will add the required underscore. * * Note that I haven't figured out yet which should be "standard", prepend * the underscore always, or not at all. These global functions need to go away * for opendarwin. */ int sym_len = strlen(symbol); void *value = NULL; char *malloc_sym = NULL; malloc_sym = malloc(sym_len + 2); if (malloc_sym) { sprintf(malloc_sym, "_%s", symbol); value = dlsymIntern(handle, malloc_sym, 1); free(malloc_sym); } else { error("Unable to allocate memory"); } return value;}static void *dlsym_auto_underscore(void *handle, const char *symbol){ void *answer; dolock(); answer = dlsym_auto_underscore_intern(handle, symbol); dounlock(); return answer;}static void *dlsym_auto_underscore_intern(void *handle, const char *symbol){ struct dlstatus *dls = handle; void *addr = 0; addr = dlsymIntern(dls, symbol, 0); if (!addr) addr = dlsym_prepend_underscore_intern(handle, symbol); return addr;}void *DL_PREFIX(dlsym)(void * dl_restrict handle, const char * dl_restrict symbol){ struct dlstatus *dls = handle; void *addr = 0; dolock(); addr = dlsymIntern(dls, symbol, 1); dounlock(); return addr;}#endifint DL_PREFIX(dlclose)(void *handle){ struct dlstatus *dls = handle; dolock(); resetdlerror(); if (!isValidStatus(dls)) { goto dlcloseerror; } if (dls->module == MAGIC_DYLIB_MOD) { const char *name; if (!dls->lib) { name = "global context"; } else { name = get_lib_name(dls->lib); } warning("trying to close a .dylib!"); error("Not closing \"%s\" - dynamic libraries cannot be closed", name); goto dlcloseerror; } if (!dls->module) { error("module already closed"); goto dlcloseerror; } if (dls->refs == 1) { unsigned long options = 0; void (*fini) (void); if ((fini = dlsymIntern(dls, "__fini", 0))) { debug("calling _fini()"); fini(); } options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;#if 0/* Currently, if a module contains c++ static destructors and it is unloaded, we * get a segfault in atexit(), due to compiler and dynamic loader differences of * opinion, this works around that. * I really need a way to figure out from code if this is still necessary. */ if ((const struct section *)NULL != getsectbynamefromheader(get_mach_header_from_NSModule(dls->module), "__DATA", "__mod_term_func")) { options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; }#endif#ifdef RTLD_NODELETE if (isFlagSet(dls->mode, RTLD_NODELETE)) options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;#endif if (!NSUnLinkModule(dls->module, options)) { error("unable to unlink module"); goto dlcloseerror; } dls->refs--; dls->module = 0; /* Note: the dlstatus struct dls is neither removed from the list * nor is the memory it occupies freed. This shouldn't pose a * problem in mostly all cases, though. */ } dounlock(); return 0; dlcloseerror: dounlock(); return 1;}const char *DL_PREFIX(dlerror)(void){ struct dlthread *tss; const char * err_str = NULL; dlcompat_init_check(); tss = pthread_getspecific(dlerror_key); if (tss != NULL && tss->errset != 0) { tss->errset = 0; err_str = tss->errstr; } return (err_str);}/* Given an address, return the mach_header for the image containing it * or zero if the given address is not contained in any loaded images. */const struct mach_header *image_for_address(const void *address){ unsigned long i; unsigned long j; unsigned long count = _dyld_image_count(); struct mach_header *mh = 0; struct load_command *lc = 0; unsigned long addr = NULL; for (i = 0; i < count; i++) { addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i); mh = _dyld_get_image_header(i); if (mh) { lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) { if (LC_SEGMENT == lc->cmd && addr >= ((struct segment_command *)lc)->vmaddr && addr < ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) { goto image_found; } } } mh = 0; } image_found: return mh;}int DL_PREFIX(dladdr)(const void * dl_restrict p, DL_PREFIX(Dl_info) * dl_restrict info){/* FIXME: USe the routine image_for_address.*/ unsigned long i; unsigned long j; unsigned long count = _dyld_image_count(); struct mach_header *mh = 0; struct load_command *lc = 0; unsigned long addr = NULL; unsigned long table_off = (unsigned long)0; int found = 0; if (!info) return 0; dolock(); resetdlerror(); info->dli_fname = 0; info->dli_fbase = 0; info->dli_sname = 0; info->dli_saddr = 0;/* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com> * to darwin-development AT lists DOT apple DOT com and slightly modified */ for (i = 0; i < count; i++) { addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i); mh = _dyld_get_image_header(i); if (mh) { lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) { if (LC_SEGMENT == lc->cmd && addr >= ((struct segment_command *)lc)->vmaddr && addr < ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) { info->dli_fname = _dyld_get_image_name(i); info->dli_fbase = (void *)mh; found = 1; break; } } if (found) break; } } if (!found) { dounlock(); return 0; } lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) { if (LC_SEGMENT == lc->cmd) { if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT")) break; } } table_off = ((unsigned long)((struct segment_command *)lc)->vmaddr) - ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i); debug("table off %x", table_off); lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) { if (LC_SYMTAB == lc->cmd) { struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off); unsigned long numsyms = ((struct symtab_command *)lc)->nsyms; struct nlist *nearest = NULL; unsigned long diff = 0xffffffff; unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off); debug("symtable %x", symtable); for (i = 0; i < numsyms; i++) { /* Ignore the following kinds of Symbols */ if ((!symtable->n_value) /* Undefined */ || (symtable->n_type >= N_PEXT) /* Debug symbol */ || (!(symtable->n_type & N_EXT)) /* Local Symbol */ ) { symtable++; continue; } if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr))) { diff = (unsigned long)symtable->n_value - addr; nearest = symtable; } symtable++; } if (nearest) { info->dli_saddr = nearest->n_value + ((void *)p - addr); info->dli_sname = (char *)(strtable + nearest->n_un.n_strx); } } } dounlock(); return 1;}/* * Implement the dlfunc() interface, which behaves exactly the same as * dlsym() except that it returns a function pointer instead of a data * pointer. This can be used by applications to avoid compiler warnings * about undefined behavior, and is intended as prior art for future * POSIX standardization. This function requires that all pointer types * have the same representation, which is true on all platforms FreeBSD * runs on, but is not guaranteed by the C standard. */#if 0 dlfunc_t dlfunc(void * dl_restrict handle, const char * dl_restrict symbol){ union { void *d; dlfunc_t f; } rv; int sym_len = strlen(symbol); char *malloc_sym = NULL; dolock(); malloc_sym = malloc(sym_len + 2); if (malloc_sym) { sprintf(malloc_sym, "_%s", symbol); rv.d = dlsymIntern(handle, malloc_sym, 1); free(malloc_sym); } else { error("Unable to allocate memory"); goto dlfuncerror; } dounlock(); return rv.f; dlfuncerror: dounlock(); return NULL;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -