andre@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: #include "primpl.h" andre@0: andre@0: #include andre@0: andre@0: #ifdef XP_BEOS andre@0: #include andre@0: #endif andre@0: andre@0: #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) andre@0: #include andre@0: #include andre@0: #endif andre@0: andre@0: #ifdef XP_UNIX andre@0: #ifdef USE_DLFCN andre@0: #include andre@0: /* Define these on systems that don't have them. */ andre@0: #ifndef RTLD_NOW andre@0: #define RTLD_NOW 0 andre@0: #endif andre@0: #ifndef RTLD_LAZY andre@0: #define RTLD_LAZY RTLD_NOW andre@0: #endif andre@0: #ifndef RTLD_GLOBAL andre@0: #define RTLD_GLOBAL 0 andre@0: #endif andre@0: #ifndef RTLD_LOCAL andre@0: #define RTLD_LOCAL 0 andre@0: #endif andre@0: #ifdef AIX andre@0: #include andre@0: #ifndef L_IGNOREUNLOAD /* AIX 4.3.3 does not have L_IGNOREUNLOAD. */ andre@0: #define L_IGNOREUNLOAD 0x10000000 andre@0: #endif andre@0: #endif andre@0: #ifdef OSF1 andre@0: #include andre@0: #include andre@0: #endif andre@0: #elif defined(USE_HPSHL) andre@0: #include andre@0: #elif defined(USE_MACH_DYLD) andre@0: #include andre@0: #endif andre@0: #endif /* XP_UNIX */ andre@0: andre@0: #define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY andre@0: andre@0: /* andre@0: * On these platforms, symbols have a leading '_'. andre@0: */ andre@0: #if (defined(DARWIN) && defined(USE_MACH_DYLD)) \ andre@0: || defined(XP_OS2) \ andre@0: || ((defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__)) andre@0: #define NEED_LEADING_UNDERSCORE andre@0: #endif andre@0: andre@0: #define PR_LD_PATHW 0x8000 /* for PR_LibSpec_PathnameU */ andre@0: andre@0: /************************************************************************/ andre@0: andre@0: struct PRLibrary { andre@0: char* name; /* Our own copy of the name string */ andre@0: PRLibrary* next; andre@0: int refCount; andre@0: const PRStaticLinkTable* staticTable; andre@0: andre@0: #ifdef XP_PC andre@0: #ifdef XP_OS2 andre@0: HMODULE dlh; andre@0: #else andre@0: HINSTANCE dlh; andre@0: #endif andre@0: #endif andre@0: andre@0: #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) andre@0: CFragConnectionID connection; andre@0: CFBundleRef bundle; andre@0: Ptr main; andre@0: CFMutableDictionaryRef wrappers; andre@0: const struct mach_header* image; andre@0: #endif andre@0: andre@0: #ifdef XP_UNIX andre@0: #if defined(USE_HPSHL) andre@0: shl_t dlh; andre@0: #elif defined(USE_MACH_DYLD) andre@0: NSModule dlh; andre@0: #else andre@0: void* dlh; andre@0: #endif andre@0: #endif andre@0: andre@0: #ifdef XP_BEOS andre@0: void* dlh; andre@0: void* stub_dlh; andre@0: #endif andre@0: }; andre@0: andre@0: static PRLibrary *pr_loadmap; andre@0: static PRLibrary *pr_exe_loadmap; andre@0: static PRMonitor *pr_linker_lock; andre@0: static char* _pr_currentLibPath = NULL; andre@0: andre@0: static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags); andre@0: andre@0: /************************************************************************/ andre@0: andre@0: #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR) andre@0: #define ERR_STR_BUF_LENGTH 20 andre@0: #endif andre@0: andre@0: static void DLLErrorInternal(PRIntn oserr) andre@0: /* andre@0: ** This whole function, and most of the code in this file, are run andre@0: ** with a big hairy lock wrapped around it. Not the best of situations, andre@0: ** but will eventually come up with the right answer. andre@0: */ andre@0: { andre@0: const char *error = NULL; andre@0: #ifdef USE_DLFCN andre@0: error = dlerror(); /* $$$ That'll be wrong some of the time - AOF */ andre@0: #elif defined(HAVE_STRERROR) andre@0: error = strerror(oserr); /* this should be okay */ andre@0: #else andre@0: char errStrBuf[ERR_STR_BUF_LENGTH]; andre@0: PR_snprintf(errStrBuf, sizeof(errStrBuf), "error %d", oserr); andre@0: error = errStrBuf; andre@0: #endif andre@0: if (NULL != error) andre@0: PR_SetErrorText(strlen(error), error); andre@0: } /* DLLErrorInternal */ andre@0: andre@0: void _PR_InitLinker(void) andre@0: { andre@0: PRLibrary *lm = NULL; andre@0: #if defined(XP_UNIX) andre@0: void *h; andre@0: #endif andre@0: andre@0: if (!pr_linker_lock) { andre@0: pr_linker_lock = PR_NewNamedMonitor("linker-lock"); andre@0: } andre@0: PR_EnterMonitor(pr_linker_lock); andre@0: andre@0: #if defined(XP_PC) andre@0: lm = PR_NEWZAP(PRLibrary); andre@0: lm->name = strdup("Executable"); andre@0: #if defined(XP_OS2) andre@0: lm->dlh = NULLHANDLE; andre@0: #else andre@0: /* A module handle for the executable. */ andre@0: lm->dlh = GetModuleHandle(NULL); andre@0: #endif /* ! XP_OS2 */ andre@0: andre@0: lm->refCount = 1; andre@0: lm->staticTable = NULL; andre@0: pr_exe_loadmap = lm; andre@0: pr_loadmap = lm; andre@0: andre@0: #elif defined(XP_UNIX) andre@0: #ifdef HAVE_DLL andre@0: #if defined(USE_DLFCN) && !defined(NO_DLOPEN_NULL) andre@0: h = dlopen(0, RTLD_LAZY); andre@0: if (!h) { andre@0: char *error; andre@0: andre@0: DLLErrorInternal(_MD_ERRNO()); andre@0: error = (char*)PR_MALLOC(PR_GetErrorTextLength()); andre@0: (void) PR_GetErrorText(error); andre@0: fprintf(stderr, "failed to initialize shared libraries [%s]\n", andre@0: error); andre@0: PR_DELETE(error); andre@0: abort();/* XXX */ andre@0: } andre@0: #elif defined(USE_HPSHL) andre@0: h = NULL; andre@0: /* don't abort with this NULL */ andre@0: #elif defined(USE_MACH_DYLD) || defined(NO_DLOPEN_NULL) andre@0: h = NULL; /* XXXX toshok */ /* XXXX vlad */ andre@0: #else andre@0: #error no dll strategy andre@0: #endif /* USE_DLFCN */ andre@0: andre@0: lm = PR_NEWZAP(PRLibrary); andre@0: if (lm) { andre@0: lm->name = strdup("a.out"); andre@0: lm->refCount = 1; andre@0: lm->dlh = h; andre@0: lm->staticTable = NULL; andre@0: } andre@0: pr_exe_loadmap = lm; andre@0: pr_loadmap = lm; andre@0: #endif /* HAVE_DLL */ andre@0: #endif /* XP_UNIX */ andre@0: andre@0: if (lm) { andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, andre@0: ("Loaded library %s (init)", lm->name)); andre@0: } andre@0: andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: } andre@0: andre@0: /* andre@0: * _PR_ShutdownLinker does not unload the dlls loaded by the application andre@0: * via calls to PR_LoadLibrary. Any dlls that still remain on the andre@0: * pr_loadmap list when NSPR shuts down are application programming errors. andre@0: * The only exception is pr_exe_loadmap, which was added to the list by andre@0: * NSPR and hence should be cleaned up by NSPR. andre@0: */ andre@0: void _PR_ShutdownLinker(void) andre@0: { andre@0: /* FIXME: pr_exe_loadmap should be destroyed. */ andre@0: andre@0: PR_DestroyMonitor(pr_linker_lock); andre@0: pr_linker_lock = NULL; andre@0: andre@0: if (_pr_currentLibPath) { andre@0: free(_pr_currentLibPath); andre@0: _pr_currentLibPath = NULL; andre@0: } andre@0: } andre@0: andre@0: /******************************************************************************/ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path) andre@0: { andre@0: PRStatus rv = PR_SUCCESS; andre@0: andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: PR_EnterMonitor(pr_linker_lock); andre@0: if (_pr_currentLibPath) { andre@0: free(_pr_currentLibPath); andre@0: } andre@0: if (path) { andre@0: _pr_currentLibPath = strdup(path); andre@0: if (!_pr_currentLibPath) { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: rv = PR_FAILURE; andre@0: } andre@0: } else { andre@0: _pr_currentLibPath = 0; andre@0: } andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: ** Return the library path for finding shared libraries. andre@0: */ andre@0: PR_IMPLEMENT(char *) andre@0: PR_GetLibraryPath(void) andre@0: { andre@0: char *ev; andre@0: char *copy = NULL; /* a copy of _pr_currentLibPath */ andre@0: andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: PR_EnterMonitor(pr_linker_lock); andre@0: if (_pr_currentLibPath != NULL) { andre@0: goto exit; andre@0: } andre@0: andre@0: /* initialize pr_currentLibPath */ andre@0: andre@0: #ifdef XP_PC andre@0: ev = getenv("LD_LIBRARY_PATH"); andre@0: if (!ev) { andre@0: ev = ".;\\lib"; andre@0: } andre@0: ev = strdup(ev); andre@0: #endif andre@0: andre@0: #if defined(XP_UNIX) || defined(XP_BEOS) andre@0: #if defined(USE_DLFCN) || defined(USE_MACH_DYLD) || defined(XP_BEOS) andre@0: { andre@0: char *p=NULL; andre@0: int len; andre@0: andre@0: #ifdef XP_BEOS andre@0: ev = getenv("LIBRARY_PATH"); andre@0: if (!ev) { andre@0: ev = "%A/lib:/boot/home/config/lib:/boot/beos/system/lib"; andre@0: } andre@0: #else andre@0: ev = getenv("LD_LIBRARY_PATH"); andre@0: if (!ev) { andre@0: ev = "/usr/lib:/lib"; andre@0: } andre@0: #endif andre@0: len = strlen(ev) + 1; /* +1 for the null */ andre@0: andre@0: p = (char*) malloc(len); andre@0: if (p) { andre@0: strcpy(p, ev); andre@0: } /* if (p) */ andre@0: ev = p; andre@0: PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev)); andre@0: andre@0: } andre@0: #else andre@0: /* AFAIK there isn't a library path with the HP SHL interface --Rob */ andre@0: ev = strdup(""); andre@0: #endif andre@0: #endif andre@0: andre@0: /* andre@0: * If ev is NULL, we have run out of memory andre@0: */ andre@0: _pr_currentLibPath = ev; andre@0: andre@0: exit: andre@0: if (_pr_currentLibPath) { andre@0: copy = strdup(_pr_currentLibPath); andre@0: } andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: if (!copy) { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: } andre@0: return copy; andre@0: } andre@0: andre@0: /* andre@0: ** Build library name from path, lib and extensions andre@0: */ andre@0: PR_IMPLEMENT(char*) andre@0: PR_GetLibraryName(const char *path, const char *lib) andre@0: { andre@0: char *fullname; andre@0: andre@0: #ifdef XP_PC andre@0: if (strstr(lib, PR_DLL_SUFFIX) == NULL) andre@0: { andre@0: if (path) { andre@0: fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX); andre@0: } else { andre@0: fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX); andre@0: } andre@0: } else { andre@0: if (path) { andre@0: fullname = PR_smprintf("%s\\%s", path, lib); andre@0: } else { andre@0: fullname = PR_smprintf("%s", lib); andre@0: } andre@0: } andre@0: #endif /* XP_PC */ andre@0: #if defined(XP_UNIX) || defined(XP_BEOS) andre@0: if (strstr(lib, PR_DLL_SUFFIX) == NULL) andre@0: { andre@0: if (path) { andre@0: fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX); andre@0: } else { andre@0: fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX); andre@0: } andre@0: } else { andre@0: if (path) { andre@0: fullname = PR_smprintf("%s/%s", path, lib); andre@0: } else { andre@0: fullname = PR_smprintf("%s", lib); andre@0: } andre@0: } andre@0: #endif /* XP_UNIX || XP_BEOS */ andre@0: return fullname; andre@0: } andre@0: andre@0: /* andre@0: ** Free the memory allocated, for the caller, by PR_GetLibraryName andre@0: */ andre@0: PR_IMPLEMENT(void) andre@0: PR_FreeLibraryName(char *mem) andre@0: { andre@0: PR_smprintf_free(mem); andre@0: } andre@0: andre@0: static PRLibrary* andre@0: pr_UnlockedFindLibrary(const char *name) andre@0: { andre@0: PRLibrary* lm = pr_loadmap; andre@0: const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR); andre@0: np = np ? np + 1 : name; andre@0: while (lm) { andre@0: const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR); andre@0: cp = cp ? cp + 1 : lm->name; andre@0: #ifdef WIN32 andre@0: /* Windows DLL names are case insensitive... */ andre@0: if (strcmpi(np, cp) == 0) andre@0: #elif defined(XP_OS2) andre@0: if (stricmp(np, cp) == 0) andre@0: #else andre@0: if (strcmp(np, cp) == 0) andre@0: #endif andre@0: { andre@0: /* found */ andre@0: lm->refCount++; andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, andre@0: ("%s incr => %d (find lib)", andre@0: lm->name, lm->refCount)); andre@0: return lm; andre@0: } andre@0: lm = lm->next; andre@0: } andre@0: return NULL; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRLibrary*) andre@0: PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags) andre@0: { andre@0: if (flags == 0) { andre@0: flags = _PR_DEFAULT_LD_FLAGS; andre@0: } andre@0: switch (libSpec.type) { andre@0: case PR_LibSpec_Pathname: andre@0: return pr_LoadLibraryByPathname(libSpec.value.pathname, flags); andre@0: #ifdef WIN32 andre@0: case PR_LibSpec_PathnameU: andre@0: /* andre@0: * cast to |char *| and set PR_LD_PATHW flag so that andre@0: * it can be cast back to PRUnichar* in the callee. andre@0: */ andre@0: return pr_LoadLibraryByPathname((const char*) andre@0: libSpec.value.pathname_u, andre@0: flags | PR_LD_PATHW); andre@0: #endif andre@0: default: andre@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); andre@0: return NULL; andre@0: } andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRLibrary*) andre@0: PR_LoadLibrary(const char *name) andre@0: { andre@0: PRLibSpec libSpec; andre@0: andre@0: libSpec.type = PR_LibSpec_Pathname; andre@0: libSpec.value.pathname = name; andre@0: return PR_LoadLibraryWithFlags(libSpec, 0); andre@0: } andre@0: andre@0: #if defined(USE_MACH_DYLD) andre@0: static NSModule andre@0: pr_LoadMachDyldModule(const char *name) andre@0: { andre@0: NSObjectFileImage ofi; andre@0: NSModule h = NULL; andre@0: if (NSCreateObjectFileImageFromFile(name, &ofi) andre@0: == NSObjectFileImageSuccess) { andre@0: h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE andre@0: | NSLINKMODULE_OPTION_RETURN_ON_ERROR); andre@0: if (h == NULL) { andre@0: NSLinkEditErrors linkEditError; andre@0: int errorNum; andre@0: const char *fileName; andre@0: const char *errorString; andre@0: NSLinkEditError(&linkEditError, &errorNum, &fileName, &errorString); andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, andre@0: ("LoadMachDyldModule error %d:%d for file %s:\n%s", andre@0: linkEditError, errorNum, fileName, errorString)); andre@0: } andre@0: if (NSDestroyObjectFileImage(ofi) == FALSE) { andre@0: if (h) { andre@0: (void)NSUnLinkModule(h, NSUNLINKMODULE_OPTION_NONE); andre@0: h = NULL; andre@0: } andre@0: } andre@0: } andre@0: return h; andre@0: } andre@0: #endif andre@0: andre@0: #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) andre@0: andre@0: /* andre@0: ** macLibraryLoadProc is a function definition for a Mac shared library andre@0: ** loading method. The "name" param is the same full or partial pathname andre@0: ** that was passed to pr_LoadLibraryByPathName. The function must fill andre@0: ** in the fields of "lm" which apply to its library type. Returns andre@0: ** PR_SUCCESS if successful. andre@0: */ andre@0: andre@0: typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm); andre@0: andre@0: #ifdef __ppc__ andre@0: andre@0: /* andre@0: ** CFM and its TVectors only exist on PowerPC. Other OS X architectures andre@0: ** only use Mach-O as a native binary format. andre@0: */ andre@0: andre@0: static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp) andre@0: { andre@0: static uint32 glue[6] = { 0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420 }; andre@0: uint32* newGlue = NULL; andre@0: andre@0: if (tvp != NULL) { andre@0: CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII); andre@0: if (nameRef) { andre@0: CFMutableDataRef glueData = (CFMutableDataRef) CFDictionaryGetValue(dict, nameRef); andre@0: if (glueData == NULL) { andre@0: glueData = CFDataCreateMutable(NULL, sizeof(glue)); andre@0: if (glueData != NULL) { andre@0: newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); andre@0: memcpy(newGlue, glue, sizeof(glue)); andre@0: newGlue[0] |= ((UInt32)tvp >> 16); andre@0: newGlue[1] |= ((UInt32)tvp & 0xFFFF); andre@0: MakeDataExecutable(newGlue, sizeof(glue)); andre@0: CFDictionaryAddValue(dict, nameRef, glueData); andre@0: CFRelease(glueData); andre@0: andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: created wrapper for CFM function %s().", name)); andre@0: } andre@0: } else { andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: found wrapper for CFM function %s().", name)); andre@0: andre@0: newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); andre@0: } andre@0: CFRelease(nameRef); andre@0: } andre@0: } andre@0: andre@0: return newGlue; andre@0: } andre@0: andre@0: static PRStatus andre@0: pr_LoadViaCFM(const char *name, PRLibrary *lm) andre@0: { andre@0: OSErr err; andre@0: Str255 errName; andre@0: FSRef ref; andre@0: FSSpec fileSpec; andre@0: Boolean tempUnusedBool; andre@0: andre@0: /* andre@0: * Make an FSSpec from the path name and call GetDiskFragment. andre@0: */ andre@0: andre@0: /* Use direct conversion of POSIX path to FSRef to FSSpec. */ andre@0: err = FSPathMakeRef((const UInt8*)name, &ref, NULL); andre@0: if (err != noErr) andre@0: return PR_FAILURE; andre@0: err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, andre@0: &fileSpec, NULL); andre@0: if (err != noErr) andre@0: return PR_FAILURE; andre@0: andre@0: /* Resolve an alias if this was one */ andre@0: err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool, andre@0: &tempUnusedBool); andre@0: if (err != noErr) andre@0: return PR_FAILURE; andre@0: andre@0: /* Finally, try to load the library */ andre@0: err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, andre@0: kLoadCFrag, &lm->connection, &lm->main, errName); andre@0: andre@0: if (err == noErr && lm->connection) { andre@0: /* andre@0: * if we're a mach-o binary, need to wrap all CFM function andre@0: * pointers. need a hash-table of already seen function andre@0: * pointers, etc. andre@0: */ andre@0: lm->wrappers = CFDictionaryCreateMutable(NULL, 16, andre@0: &kCFTypeDictionaryKeyCallBacks, andre@0: &kCFTypeDictionaryValueCallBacks); andre@0: if (lm->wrappers) { andre@0: lm->main = TV2FP(lm->wrappers, "main", lm->main); andre@0: } else andre@0: err = memFullErr; andre@0: } andre@0: return (err == noErr) ? PR_SUCCESS : PR_FAILURE; andre@0: } andre@0: #endif /* __ppc__ */ andre@0: andre@0: /* andre@0: ** Creates a CFBundleRef if the pathname refers to a Mac OS X bundle andre@0: ** directory. The caller is responsible for calling CFRelease() to andre@0: ** deallocate. andre@0: */ andre@0: andre@0: static PRStatus andre@0: pr_LoadCFBundle(const char *name, PRLibrary *lm) andre@0: { andre@0: CFURLRef bundleURL; andre@0: CFBundleRef bundle = NULL; andre@0: char pathBuf[PATH_MAX]; andre@0: const char *resolvedPath; andre@0: CFStringRef pathRef; andre@0: andre@0: /* Takes care of relative paths and symlinks */ andre@0: resolvedPath = realpath(name, pathBuf); andre@0: if (!resolvedPath) andre@0: return PR_FAILURE; andre@0: andre@0: pathRef = CFStringCreateWithCString(NULL, pathBuf, kCFStringEncodingUTF8); andre@0: if (pathRef) { andre@0: bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef, andre@0: kCFURLPOSIXPathStyle, true); andre@0: if (bundleURL) { andre@0: bundle = CFBundleCreate(NULL, bundleURL); andre@0: CFRelease(bundleURL); andre@0: } andre@0: CFRelease(pathRef); andre@0: } andre@0: andre@0: lm->bundle = bundle; andre@0: return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE; andre@0: } andre@0: andre@0: static PRStatus andre@0: pr_LoadViaDyld(const char *name, PRLibrary *lm) andre@0: { andre@0: lm->dlh = pr_LoadMachDyldModule(name); andre@0: if (lm->dlh == NULL) { andre@0: lm->image = NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR andre@0: | NSADDIMAGE_OPTION_WITH_SEARCHING); andre@0: if (lm->image == NULL) { andre@0: NSLinkEditErrors linkEditError; andre@0: int errorNum; andre@0: const char *fileName; andre@0: const char *errorString; andre@0: NSLinkEditError(&linkEditError, &errorNum, &fileName, &errorString); andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, andre@0: ("LoadMachDyldModule error %d:%d for file %s:\n%s", andre@0: linkEditError, errorNum, fileName, errorString)); andre@0: } andre@0: } andre@0: return (lm->dlh != NULL || lm->image != NULL) ? PR_SUCCESS : PR_FAILURE; andre@0: } andre@0: andre@0: #endif /* XP_MACOSX && USE_MACH_DYLD */ andre@0: andre@0: /* andre@0: ** Dynamically load a library. Only load libraries once, so scan the load andre@0: ** map first. andre@0: */ andre@0: static PRLibrary* andre@0: pr_LoadLibraryByPathname(const char *name, PRIntn flags) andre@0: { andre@0: PRLibrary *lm; andre@0: PRLibrary* result = NULL; andre@0: PRInt32 oserr; andre@0: #ifdef WIN32 andre@0: char utf8name_stack[MAX_PATH]; andre@0: char *utf8name_malloc = NULL; andre@0: char *utf8name = utf8name_stack; andre@0: PRUnichar wname_stack[MAX_PATH]; andre@0: PRUnichar *wname_malloc = NULL; andre@0: PRUnichar *wname = wname_stack; andre@0: int len; andre@0: #endif andre@0: andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: andre@0: /* See if library is already loaded */ andre@0: PR_EnterMonitor(pr_linker_lock); andre@0: andre@0: #ifdef WIN32 andre@0: if (flags & PR_LD_PATHW) { andre@0: /* cast back what's cast to |char *| for the argument passing. */ andre@0: wname = (LPWSTR) name; andre@0: } else { andre@0: int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); andre@0: if (wlen > MAX_PATH) andre@0: wname = wname_malloc = PR_Malloc(wlen * sizeof(PRUnichar)); andre@0: if (wname == NULL || andre@0: !MultiByteToWideChar(CP_ACP, 0, name, -1, wname, wlen)) { andre@0: oserr = _MD_ERRNO(); andre@0: goto unlock; andre@0: } andre@0: } andre@0: len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL); andre@0: if (len > MAX_PATH) andre@0: utf8name = utf8name_malloc = PR_Malloc(len); andre@0: if (utf8name == NULL || andre@0: !WideCharToMultiByte(CP_UTF8, 0, wname, -1, andre@0: utf8name, len, NULL, NULL)) { andre@0: oserr = _MD_ERRNO(); andre@0: goto unlock; andre@0: } andre@0: /* the list of loaded library names are always kept in UTF-8 andre@0: * on Win32 platforms */ andre@0: result = pr_UnlockedFindLibrary(utf8name); andre@0: #else andre@0: result = pr_UnlockedFindLibrary(name); andre@0: #endif andre@0: andre@0: if (result != NULL) goto unlock; andre@0: andre@0: lm = PR_NEWZAP(PRLibrary); andre@0: if (lm == NULL) { andre@0: oserr = _MD_ERRNO(); andre@0: goto unlock; andre@0: } andre@0: lm->staticTable = NULL; andre@0: andre@0: #ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */ andre@0: { andre@0: HMODULE h; andre@0: UCHAR pszError[_MAX_PATH]; andre@0: ULONG ulRc = NO_ERROR; andre@0: andre@0: ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); andre@0: if (ulRc != NO_ERROR) { andre@0: oserr = ulRc; andre@0: PR_DELETE(lm); andre@0: goto unlock; andre@0: } andre@0: lm->name = strdup(name); andre@0: lm->dlh = h; andre@0: lm->next = pr_loadmap; andre@0: pr_loadmap = lm; andre@0: } andre@0: #endif /* XP_OS2 */ andre@0: andre@0: #ifdef WIN32 andre@0: { andre@0: HINSTANCE h; andre@0: andre@0: h = LoadLibraryExW(wname, NULL, andre@0: (flags & PR_LD_ALT_SEARCH_PATH) ? andre@0: LOAD_WITH_ALTERED_SEARCH_PATH : 0); andre@0: if (h == NULL) { andre@0: oserr = _MD_ERRNO(); andre@0: PR_DELETE(lm); andre@0: goto unlock; andre@0: } andre@0: lm->name = strdup(utf8name); andre@0: lm->dlh = h; andre@0: lm->next = pr_loadmap; andre@0: pr_loadmap = lm; andre@0: } andre@0: #endif /* WIN32 */ andre@0: andre@0: #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) andre@0: { andre@0: int i; andre@0: PRStatus status; andre@0: andre@0: static const macLibraryLoadProc loadProcs[] = { andre@0: #ifdef __ppc__ andre@0: pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM andre@0: #else /* __ppc__ */ andre@0: pr_LoadViaDyld, pr_LoadCFBundle andre@0: #endif /* __ppc__ */ andre@0: }; andre@0: andre@0: for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) { andre@0: if ((status = loadProcs[i](name, lm)) == PR_SUCCESS) andre@0: break; andre@0: } andre@0: if (status != PR_SUCCESS) { andre@0: oserr = cfragNoLibraryErr; andre@0: PR_DELETE(lm); andre@0: goto unlock; andre@0: } andre@0: lm->name = strdup(name); andre@0: lm->next = pr_loadmap; andre@0: pr_loadmap = lm; andre@0: } andre@0: #endif andre@0: andre@0: #if defined(XP_UNIX) && !(defined(XP_MACOSX) && defined(USE_MACH_DYLD)) andre@0: #ifdef HAVE_DLL andre@0: { andre@0: #if defined(USE_DLFCN) andre@0: #ifdef NTO andre@0: /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */ andre@0: int dl_flags = RTLD_GROUP; andre@0: #elif defined(AIX) andre@0: /* AIX needs RTLD_MEMBER to load an archive member. (bug 228899) */ andre@0: int dl_flags = RTLD_MEMBER; andre@0: #else andre@0: int dl_flags = 0; andre@0: #endif andre@0: void *h = NULL; andre@0: andre@0: if (flags & PR_LD_LAZY) { andre@0: dl_flags |= RTLD_LAZY; andre@0: } andre@0: if (flags & PR_LD_NOW) { andre@0: dl_flags |= RTLD_NOW; andre@0: } andre@0: if (flags & PR_LD_GLOBAL) { andre@0: dl_flags |= RTLD_GLOBAL; andre@0: } andre@0: if (flags & PR_LD_LOCAL) { andre@0: dl_flags |= RTLD_LOCAL; andre@0: } andre@0: #if defined(DARWIN) andre@0: /* ensure the file exists if it contains a slash character i.e. path */ andre@0: /* DARWIN's dlopen ignores the provided path and checks for the */ andre@0: /* plain filename in DYLD_LIBRARY_PATH */ andre@0: if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL || andre@0: PR_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) { andre@0: h = dlopen(name, dl_flags); andre@0: } andre@0: #else andre@0: h = dlopen(name, dl_flags); andre@0: #endif andre@0: #elif defined(USE_HPSHL) andre@0: int shl_flags = 0; andre@0: shl_t h; andre@0: andre@0: /* andre@0: * Use the DYNAMIC_PATH flag only if 'name' is a plain file andre@0: * name (containing no directory) to match the behavior of andre@0: * dlopen(). andre@0: */ andre@0: if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) { andre@0: shl_flags |= DYNAMIC_PATH; andre@0: } andre@0: if (flags & PR_LD_LAZY) { andre@0: shl_flags |= BIND_DEFERRED; andre@0: } andre@0: if (flags & PR_LD_NOW) { andre@0: shl_flags |= BIND_IMMEDIATE; andre@0: } andre@0: /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */ andre@0: h = shl_load(name, shl_flags, 0L); andre@0: #elif defined(USE_MACH_DYLD) andre@0: NSModule h = pr_LoadMachDyldModule(name); andre@0: #else andre@0: #error Configuration error andre@0: #endif andre@0: if (!h) { andre@0: oserr = _MD_ERRNO(); andre@0: PR_DELETE(lm); andre@0: goto unlock; andre@0: } andre@0: lm->name = strdup(name); andre@0: lm->dlh = h; andre@0: lm->next = pr_loadmap; andre@0: pr_loadmap = lm; andre@0: } andre@0: #endif /* HAVE_DLL */ andre@0: #endif /* XP_UNIX && !(XP_MACOSX && USE_MACH_DYLD) */ andre@0: andre@0: lm->refCount = 1; andre@0: andre@0: #ifdef XP_BEOS andre@0: { andre@0: image_info info; andre@0: int32 cookie = 0; andre@0: image_id imageid = B_ERROR; andre@0: image_id stubid = B_ERROR; andre@0: PRLibrary *p; andre@0: andre@0: for (p = pr_loadmap; p != NULL; p = p->next) { andre@0: /* hopefully, our caller will always use the same string andre@0: to refer to the same library */ andre@0: if (strcmp(name, p->name) == 0) { andre@0: /* we've already loaded this library */ andre@0: imageid = info.id; andre@0: lm->refCount++; andre@0: break; andre@0: } andre@0: } andre@0: andre@0: if(imageid == B_ERROR) { andre@0: /* it appears the library isn't yet loaded - load it now */ andre@0: char stubName [B_PATH_NAME_LENGTH + 1]; andre@0: andre@0: /* the following is a work-around to a "bug" in the beos - andre@0: the beos system loader allows only 32M (system-wide) andre@0: to be used by code loaded as "add-ons" (code loaded andre@0: through the 'load_add_on()' system call, which includes andre@0: mozilla components), but allows 256M to be used by andre@0: shared libraries. andre@0: andre@0: unfortunately, mozilla is too large to fit into the andre@0: "add-on" space, so we must trick the loader into andre@0: loading some of the components as shared libraries. this andre@0: is accomplished by creating a "stub" add-on (an empty andre@0: shared object), and linking it with the component andre@0: (the actual .so file generated by the build process, andre@0: without any modifications). when this stub is loaded andre@0: by load_add_on(), the loader will automatically load the andre@0: component into the shared library space. andre@0: */ andre@0: andre@0: strcpy(stubName, name); andre@0: strcat(stubName, ".stub"); andre@0: andre@0: /* first, attempt to load the stub (thereby loading the andre@0: component as a shared library */ andre@0: if ((stubid = load_add_on(stubName)) > B_ERROR) { andre@0: /* the stub was loaded successfully. */ andre@0: imageid = B_FILE_NOT_FOUND; andre@0: andre@0: cookie = 0; andre@0: while (get_next_image_info(0, &cookie, &info) == B_OK) { andre@0: const char *endOfSystemName = strrchr(info.name, '/'); andre@0: const char *endOfPassedName = strrchr(name, '/'); andre@0: if( 0 == endOfSystemName ) andre@0: endOfSystemName = info.name; andre@0: else andre@0: endOfSystemName++; andre@0: if( 0 == endOfPassedName ) andre@0: endOfPassedName = name; andre@0: else andre@0: endOfPassedName++; andre@0: if (strcmp(endOfSystemName, endOfPassedName) == 0) { andre@0: /* this is the actual component - remember it */ andre@0: imageid = info.id; andre@0: break; andre@0: } andre@0: } andre@0: andre@0: } else { andre@0: /* we failed to load the "stub" - try to load the andre@0: component directly as an add-on */ andre@0: stubid = B_ERROR; andre@0: imageid = load_add_on(name); andre@0: } andre@0: } andre@0: andre@0: if (imageid <= B_ERROR) { andre@0: oserr = imageid; andre@0: PR_DELETE( lm ); andre@0: goto unlock; andre@0: } andre@0: lm->name = strdup(name); andre@0: lm->dlh = (void*)imageid; andre@0: lm->stub_dlh = (void*)stubid; andre@0: lm->next = pr_loadmap; andre@0: pr_loadmap = lm; andre@0: } andre@0: #endif andre@0: andre@0: result = lm; /* success */ andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name)); andre@0: andre@0: unlock: andre@0: if (result == NULL) { andre@0: PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr); andre@0: DLLErrorInternal(oserr); /* sets error text */ andre@0: } andre@0: #ifdef WIN32 andre@0: if (utf8name_malloc) andre@0: PR_Free(utf8name_malloc); andre@0: if (wname_malloc) andre@0: PR_Free(wname_malloc); andre@0: #endif andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: return result; andre@0: } andre@0: andre@0: /* andre@0: ** Unload a shared library which was loaded via PR_LoadLibrary andre@0: */ andre@0: PR_IMPLEMENT(PRStatus) andre@0: PR_UnloadLibrary(PRLibrary *lib) andre@0: { andre@0: int result = 0; andre@0: PRStatus status = PR_SUCCESS; andre@0: andre@0: if (lib == 0) { andre@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PR_EnterMonitor(pr_linker_lock); andre@0: andre@0: if (lib->refCount <= 0) { andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: if (--lib->refCount > 0) { andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, andre@0: ("%s decr => %d", andre@0: lib->name, lib->refCount)); andre@0: goto done; andre@0: } andre@0: andre@0: #ifdef XP_BEOS andre@0: if(((image_id)lib->stub_dlh) == B_ERROR) andre@0: unload_add_on( (image_id) lib->dlh ); andre@0: else andre@0: unload_add_on( (image_id) lib->stub_dlh); andre@0: #endif andre@0: andre@0: #ifdef XP_UNIX andre@0: #ifdef HAVE_DLL andre@0: #ifdef USE_DLFCN andre@0: result = dlclose(lib->dlh); andre@0: #elif defined(USE_HPSHL) andre@0: result = shl_unload(lib->dlh); andre@0: #elif defined(USE_MACH_DYLD) andre@0: if (lib->dlh) andre@0: result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1; andre@0: #else andre@0: #error Configuration error andre@0: #endif andre@0: #endif /* HAVE_DLL */ andre@0: #endif /* XP_UNIX */ andre@0: #ifdef XP_PC andre@0: if (lib->dlh) { andre@0: FreeLibrary((HINSTANCE)(lib->dlh)); andre@0: lib->dlh = (HINSTANCE)NULL; andre@0: } andre@0: #endif /* XP_PC */ andre@0: andre@0: #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) andre@0: /* Close the connection */ andre@0: if (lib->connection) andre@0: CloseConnection(&(lib->connection)); andre@0: if (lib->bundle) andre@0: CFRelease(lib->bundle); andre@0: if (lib->wrappers) andre@0: CFRelease(lib->wrappers); andre@0: /* No way to unload an image (lib->image) */ andre@0: #endif andre@0: andre@0: /* unlink from library search list */ andre@0: if (pr_loadmap == lib) andre@0: pr_loadmap = pr_loadmap->next; andre@0: else if (pr_loadmap != NULL) { andre@0: PRLibrary* prev = pr_loadmap; andre@0: PRLibrary* next = pr_loadmap->next; andre@0: while (next != NULL) { andre@0: if (next == lib) { andre@0: prev->next = next->next; andre@0: goto freeLib; andre@0: } andre@0: prev = next; andre@0: next = next->next; andre@0: } andre@0: /* andre@0: * fail (the library is not on the _pr_loadmap list), andre@0: * but don't wipe out an error from dlclose/shl_unload. andre@0: */ andre@0: PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent"); andre@0: if (result == 0) { andre@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); andre@0: status = PR_FAILURE; andre@0: } andre@0: } andre@0: /* andre@0: * We free the PRLibrary structure whether dlclose/shl_unload andre@0: * succeeds or not. andre@0: */ andre@0: andre@0: freeLib: andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name)); andre@0: free(lib->name); andre@0: lib->name = NULL; andre@0: PR_DELETE(lib); andre@0: if (result != 0) { andre@0: PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO()); andre@0: DLLErrorInternal(_MD_ERRNO()); andre@0: status = PR_FAILURE; andre@0: } andre@0: andre@0: done: andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: return status; andre@0: } andre@0: andre@0: static void* andre@0: pr_FindSymbolInLib(PRLibrary *lm, const char *name) andre@0: { andre@0: void *f = NULL; andre@0: #ifdef XP_OS2 andre@0: int rc; andre@0: #endif andre@0: andre@0: if (lm->staticTable != NULL) { andre@0: const PRStaticLinkTable* tp; andre@0: for (tp = lm->staticTable; tp->name; tp++) { andre@0: if (strcmp(name, tp->name) == 0) { andre@0: return (void*) tp->fp; andre@0: } andre@0: } andre@0: /* andre@0: ** If the symbol was not found in the static table then check if andre@0: ** the symbol was exported in the DLL... Win16 only!! andre@0: */ andre@0: #if !defined(WIN16) && !defined(XP_BEOS) andre@0: PR_SetError(PR_FIND_SYMBOL_ERROR, 0); andre@0: return (void*)NULL; andre@0: #endif andre@0: } andre@0: andre@0: #ifdef XP_OS2 andre@0: rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); andre@0: #if defined(NEED_LEADING_UNDERSCORE) andre@0: /* andre@0: * Older plugins (not built using GCC) will have symbols that are not andre@0: * underscore prefixed. We check for that here. andre@0: */ andre@0: if (rc != NO_ERROR) { andre@0: name++; andre@0: DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); andre@0: } andre@0: #endif andre@0: #endif /* XP_OS2 */ andre@0: andre@0: #ifdef WIN32 andre@0: f = GetProcAddress(lm->dlh, name); andre@0: #endif /* WIN32 */ andre@0: andre@0: #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) andre@0: /* add this offset to skip the leading underscore in name */ andre@0: #define SYM_OFFSET 1 andre@0: if (lm->bundle) { andre@0: CFStringRef nameRef = CFStringCreateWithCString(NULL, name + SYM_OFFSET, kCFStringEncodingASCII); andre@0: if (nameRef) { andre@0: f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef); andre@0: CFRelease(nameRef); andre@0: } andre@0: } andre@0: if (lm->connection) { andre@0: Ptr symAddr; andre@0: CFragSymbolClass symClass; andre@0: Str255 pName; andre@0: andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET)); andre@0: andre@0: c2pstrcpy(pName, name + SYM_OFFSET); andre@0: andre@0: f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; andre@0: andre@0: #ifdef __ppc__ andre@0: /* callers expect mach-o function pointers, so must wrap tvectors with glue. */ andre@0: if (f && symClass == kTVectorCFragSymbol) { andre@0: f = TV2FP(lm->wrappers, name + SYM_OFFSET, f); andre@0: } andre@0: #endif /* __ppc__ */ andre@0: andre@0: if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main; andre@0: } andre@0: if (lm->image) { andre@0: NSSymbol symbol; andre@0: symbol = NSLookupSymbolInImage(lm->image, name, andre@0: NSLOOKUPSYMBOLINIMAGE_OPTION_BIND andre@0: | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); andre@0: if (symbol != NULL) andre@0: f = NSAddressOfSymbol(symbol); andre@0: else andre@0: f = NULL; andre@0: } andre@0: #undef SYM_OFFSET andre@0: #endif /* XP_MACOSX && USE_MACH_DYLD */ andre@0: andre@0: #ifdef XP_BEOS andre@0: if( B_NO_ERROR != get_image_symbol( (image_id)lm->dlh, name, B_SYMBOL_TYPE_TEXT, &f ) ) { andre@0: f = NULL; andre@0: } andre@0: #endif andre@0: andre@0: #ifdef XP_UNIX andre@0: #ifdef HAVE_DLL andre@0: #ifdef USE_DLFCN andre@0: f = dlsym(lm->dlh, name); andre@0: #elif defined(USE_HPSHL) andre@0: if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) { andre@0: f = NULL; andre@0: } andre@0: #elif defined(USE_MACH_DYLD) andre@0: if (lm->dlh) { andre@0: NSSymbol symbol; andre@0: symbol = NSLookupSymbolInModule(lm->dlh, name); andre@0: if (symbol != NULL) andre@0: f = NSAddressOfSymbol(symbol); andre@0: else andre@0: f = NULL; andre@0: } andre@0: #endif andre@0: #endif /* HAVE_DLL */ andre@0: #endif /* XP_UNIX */ andre@0: if (f == NULL) { andre@0: PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO()); andre@0: DLLErrorInternal(_MD_ERRNO()); andre@0: } andre@0: return f; andre@0: } andre@0: andre@0: /* andre@0: ** Called by class loader to resolve missing native's andre@0: */ andre@0: PR_IMPLEMENT(void*) andre@0: PR_FindSymbol(PRLibrary *lib, const char *raw_name) andre@0: { andre@0: void *f = NULL; andre@0: #if defined(NEED_LEADING_UNDERSCORE) andre@0: char *name; andre@0: #else andre@0: const char *name; andre@0: #endif andre@0: /* andre@0: ** Mangle the raw symbol name in any way that is platform specific. andre@0: */ andre@0: #if defined(NEED_LEADING_UNDERSCORE) andre@0: /* Need a leading _ */ andre@0: name = PR_smprintf("_%s", raw_name); andre@0: #elif defined(AIX) andre@0: /* andre@0: ** AIX with the normal linker put's a "." in front of the symbol andre@0: ** name. When use "svcc" and "svld" then the "." disappears. Go andre@0: ** figure. andre@0: */ andre@0: name = raw_name; andre@0: #else andre@0: name = raw_name; andre@0: #endif andre@0: andre@0: PR_EnterMonitor(pr_linker_lock); andre@0: PR_ASSERT(lib != NULL); andre@0: f = pr_FindSymbolInLib(lib, name); andre@0: andre@0: #if defined(NEED_LEADING_UNDERSCORE) andre@0: PR_smprintf_free(name); andre@0: #endif andre@0: andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: return f; andre@0: } andre@0: andre@0: /* andre@0: ** Return the address of the function 'raw_name' in the library 'lib' andre@0: */ andre@0: PR_IMPLEMENT(PRFuncPtr) andre@0: PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name) andre@0: { andre@0: return ((PRFuncPtr) PR_FindSymbol(lib, raw_name)); andre@0: } andre@0: andre@0: PR_IMPLEMENT(void*) andre@0: PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) andre@0: { andre@0: void *f = NULL; andre@0: #if defined(NEED_LEADING_UNDERSCORE) andre@0: char *name; andre@0: #else andre@0: const char *name; andre@0: #endif andre@0: PRLibrary* lm; andre@0: andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: /* andre@0: ** Mangle the raw symbol name in any way that is platform specific. andre@0: */ andre@0: #if defined(NEED_LEADING_UNDERSCORE) andre@0: /* Need a leading _ */ andre@0: name = PR_smprintf("_%s", raw_name); andre@0: #elif defined(AIX) andre@0: /* andre@0: ** AIX with the normal linker put's a "." in front of the symbol andre@0: ** name. When use "svcc" and "svld" then the "." disappears. Go andre@0: ** figure. andre@0: */ andre@0: name = raw_name; andre@0: #else andre@0: name = raw_name; andre@0: #endif andre@0: andre@0: PR_EnterMonitor(pr_linker_lock); andre@0: andre@0: /* search all libraries */ andre@0: for (lm = pr_loadmap; lm != NULL; lm = lm->next) { andre@0: f = pr_FindSymbolInLib(lm, name); andre@0: if (f != NULL) { andre@0: *lib = lm; andre@0: lm->refCount++; andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, andre@0: ("%s incr => %d (for %s)", andre@0: lm->name, lm->refCount, name)); andre@0: break; andre@0: } andre@0: } andre@0: #if defined(NEED_LEADING_UNDERSCORE) andre@0: PR_smprintf_free(name); andre@0: #endif andre@0: andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: return f; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRFuncPtr) andre@0: PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) andre@0: { andre@0: return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib)); andre@0: } andre@0: andre@0: /* andre@0: ** Add a static library to the list of loaded libraries. If LoadLibrary andre@0: ** is called with the name then we will pretend it was already loaded andre@0: */ andre@0: PR_IMPLEMENT(PRLibrary*) andre@0: PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt) andre@0: { andre@0: PRLibrary *lm=NULL; andre@0: PRLibrary* result = NULL; andre@0: andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: andre@0: /* See if library is already loaded */ andre@0: PR_EnterMonitor(pr_linker_lock); andre@0: andre@0: /* If the lbrary is already loaded, then add the static table information... */ andre@0: result = pr_UnlockedFindLibrary(name); andre@0: if (result != NULL) { andre@0: PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) ); andre@0: result->staticTable = slt; andre@0: goto unlock; andre@0: } andre@0: andre@0: /* Add library to list...Mark it static */ andre@0: lm = PR_NEWZAP(PRLibrary); andre@0: if (lm == NULL) goto unlock; andre@0: andre@0: lm->name = strdup(name); andre@0: lm->refCount = 1; andre@0: lm->dlh = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0; andre@0: lm->staticTable = slt; andre@0: lm->next = pr_loadmap; andre@0: pr_loadmap = lm; andre@0: andre@0: result = lm; /* success */ andre@0: PR_ASSERT(lm->refCount == 1); andre@0: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name)); andre@0: unlock: andre@0: PR_ExitMonitor(pr_linker_lock); andre@0: return result; andre@0: } andre@0: andre@0: PR_IMPLEMENT(char *) andre@0: PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr) andre@0: { andre@0: #if defined(USE_DLFCN) && defined(HAVE_DLADDR) andre@0: Dl_info dli; andre@0: char *result; andre@0: andre@0: if (dladdr((void *)addr, &dli) == 0) { andre@0: PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); andre@0: DLLErrorInternal(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: result = PR_Malloc(strlen(dli.dli_fname)+1); andre@0: if (result != NULL) { andre@0: strcpy(result, dli.dli_fname); andre@0: } andre@0: return result; andre@0: #elif defined(USE_MACH_DYLD) andre@0: char *result; andre@0: const char *image_name; andre@0: int i, count = _dyld_image_count(); andre@0: andre@0: for (i = 0; i < count; i++) { andre@0: image_name = _dyld_get_image_name(i); andre@0: if (strstr(image_name, name) != NULL) { andre@0: result = PR_Malloc(strlen(image_name)+1); andre@0: if (result != NULL) { andre@0: strcpy(result, image_name); andre@0: } andre@0: return result; andre@0: } andre@0: } andre@0: PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); andre@0: return NULL; andre@0: #elif defined(AIX) andre@0: char *result; andre@0: #define LD_INFO_INCREMENT 64 andre@0: struct ld_info *info; andre@0: unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info); andre@0: struct ld_info *infop; andre@0: int loadflags = L_GETINFO | L_IGNOREUNLOAD; andre@0: andre@0: for (;;) { andre@0: info = PR_Malloc(info_length); andre@0: if (info == NULL) { andre@0: return NULL; andre@0: } andre@0: /* If buffer is too small, loadquery fails with ENOMEM. */ andre@0: if (loadquery(loadflags, info, info_length) != -1) { andre@0: break; andre@0: } andre@0: /* andre@0: * Calling loadquery when compiled for 64-bit with the andre@0: * L_IGNOREUNLOAD flag can cause an invalid argument error andre@0: * on AIX 5.1. Detect this error the first time that andre@0: * loadquery is called, and try calling it again without andre@0: * this flag set. andre@0: */ andre@0: if (errno == EINVAL && (loadflags & L_IGNOREUNLOAD)) { andre@0: loadflags &= ~L_IGNOREUNLOAD; andre@0: if (loadquery(loadflags, info, info_length) != -1) { andre@0: break; andre@0: } andre@0: } andre@0: PR_Free(info); andre@0: if (errno != ENOMEM) { andre@0: /* should not happen */ andre@0: _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: /* retry with a larger buffer */ andre@0: info_length += LD_INFO_INCREMENT * sizeof(struct ld_info); andre@0: } andre@0: andre@0: for (infop = info; andre@0: ; andre@0: infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) { andre@0: unsigned long start = (unsigned long)infop->ldinfo_dataorg; andre@0: unsigned long end = start + infop->ldinfo_datasize; andre@0: if (start <= (unsigned long)addr && end > (unsigned long)addr) { andre@0: result = PR_Malloc(strlen(infop->ldinfo_filename)+1); andre@0: if (result != NULL) { andre@0: strcpy(result, infop->ldinfo_filename); andre@0: } andre@0: break; andre@0: } andre@0: if (!infop->ldinfo_next) { andre@0: PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); andre@0: result = NULL; andre@0: break; andre@0: } andre@0: } andre@0: PR_Free(info); andre@0: return result; andre@0: #elif defined(OSF1) andre@0: /* Contributed by Steve Streeter of HP */ andre@0: ldr_process_t process, ldr_my_process(); andre@0: ldr_module_t mod_id; andre@0: ldr_module_info_t info; andre@0: ldr_region_t regno; andre@0: ldr_region_info_t reginfo; andre@0: size_t retsize; andre@0: int rv; andre@0: char *result; andre@0: andre@0: /* Get process for which dynamic modules will be listed */ andre@0: andre@0: process = ldr_my_process(); andre@0: andre@0: /* Attach to process */ andre@0: andre@0: rv = ldr_xattach(process); andre@0: if (rv) { andre@0: /* should not happen */ andre@0: _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: andre@0: /* Print information for list of modules */ andre@0: andre@0: mod_id = LDR_NULL_MODULE; andre@0: andre@0: for (;;) { andre@0: andre@0: /* Get information for the next module in the module list. */ andre@0: andre@0: ldr_next_module(process, &mod_id); andre@0: if (ldr_inq_module(process, mod_id, &info, sizeof(info), andre@0: &retsize) != 0) { andre@0: /* No more modules */ andre@0: break; andre@0: } andre@0: if (retsize < sizeof(info)) { andre@0: continue; andre@0: } andre@0: andre@0: /* andre@0: * Get information for each region in the module and check if any andre@0: * contain the address of this function. andre@0: */ andre@0: andre@0: for (regno = 0; ; regno++) { andre@0: if (ldr_inq_region(process, mod_id, regno, ®info, andre@0: sizeof(reginfo), &retsize) != 0) { andre@0: /* No more regions */ andre@0: break; andre@0: } andre@0: if (((unsigned long)reginfo.lri_mapaddr <= andre@0: (unsigned long)addr) && andre@0: (((unsigned long)reginfo.lri_mapaddr + reginfo.lri_size) > andre@0: (unsigned long)addr)) { andre@0: /* Found it. */ andre@0: result = PR_Malloc(strlen(info.lmi_name)+1); andre@0: if (result != NULL) { andre@0: strcpy(result, info.lmi_name); andre@0: } andre@0: return result; andre@0: } andre@0: } andre@0: } andre@0: PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); andre@0: return NULL; andre@0: #elif defined(HPUX) && defined(USE_HPSHL) andre@0: int index; andre@0: struct shl_descriptor desc; andre@0: char *result; andre@0: andre@0: for (index = 0; shl_get_r(index, &desc) == 0; index++) { andre@0: if (strstr(desc.filename, name) != NULL) { andre@0: result = PR_Malloc(strlen(desc.filename)+1); andre@0: if (result != NULL) { andre@0: strcpy(result, desc.filename); andre@0: } andre@0: return result; andre@0: } andre@0: } andre@0: /* andre@0: * Since the index value of a library is decremented if andre@0: * a library preceding it in the shared library search andre@0: * list was unloaded, it is possible that we missed some andre@0: * libraries as we went up the list. So we should go andre@0: * down the list to be sure that we not miss anything. andre@0: */ andre@0: for (index--; index >= 0; index--) { andre@0: if ((shl_get_r(index, &desc) == 0) andre@0: && (strstr(desc.filename, name) != NULL)) { andre@0: result = PR_Malloc(strlen(desc.filename)+1); andre@0: if (result != NULL) { andre@0: strcpy(result, desc.filename); andre@0: } andre@0: return result; andre@0: } andre@0: } andre@0: PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); andre@0: return NULL; andre@0: #elif defined(HPUX) && defined(USE_DLFCN) andre@0: struct load_module_desc desc; andre@0: char *result; andre@0: const char *module_name; andre@0: andre@0: if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) { andre@0: PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); andre@0: DLLErrorInternal(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0); andre@0: if (module_name == NULL) { andre@0: /* should not happen */ andre@0: _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); andre@0: DLLErrorInternal(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: result = PR_Malloc(strlen(module_name)+1); andre@0: if (result != NULL) { andre@0: strcpy(result, module_name); andre@0: } andre@0: return result; andre@0: #elif defined(WIN32) andre@0: PRUnichar wname[MAX_PATH]; andre@0: HMODULE handle = NULL; andre@0: PRUnichar module_name[MAX_PATH]; andre@0: int len; andre@0: char *result; andre@0: andre@0: if (MultiByteToWideChar(CP_ACP, 0, name, -1, wname, MAX_PATH)) { andre@0: handle = GetModuleHandleW(wname); andre@0: } andre@0: if (handle == NULL) { andre@0: PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); andre@0: DLLErrorInternal(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: if (GetModuleFileNameW(handle, module_name, MAX_PATH) == 0) { andre@0: /* should not happen */ andre@0: _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: len = WideCharToMultiByte(CP_ACP, 0, module_name, -1, andre@0: NULL, 0, NULL, NULL); andre@0: if (len == 0) { andre@0: _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: result = PR_Malloc(len * sizeof(PRUnichar)); andre@0: if (result != NULL) { andre@0: WideCharToMultiByte(CP_ACP, 0, module_name, -1, andre@0: result, len, NULL, NULL); andre@0: } andre@0: return result; andre@0: #elif defined(XP_OS2) andre@0: HMODULE module = NULL; andre@0: char module_name[_MAX_PATH]; andre@0: char *result; andre@0: APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr); andre@0: if ((NO_ERROR != ulrc) || (NULL == module) ) { andre@0: PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); andre@0: DLLErrorInternal(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: ulrc = DosQueryModuleName(module, sizeof module_name, module_name); andre@0: if (NO_ERROR != ulrc) { andre@0: /* should not happen */ andre@0: _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); andre@0: return NULL; andre@0: } andre@0: result = PR_Malloc(strlen(module_name)+1); andre@0: if (result != NULL) { andre@0: strcpy(result, module_name); andre@0: } andre@0: return result; andre@0: #else andre@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); andre@0: return NULL; andre@0: #endif andre@0: }