/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Steve Streeter (Hewlett-Packard Company) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "primpl.h" #include #ifdef XP_BEOS #include #endif #ifdef XP_MACOSX #include #include #include #include #include #include #include #include #include #endif #ifdef XP_UNIX #ifdef USE_DLFCN #include /* Define these on systems that don't have them. */ #ifndef RTLD_NOW #define RTLD_NOW 0 #endif #ifndef RTLD_LAZY #define RTLD_LAZY RTLD_NOW #endif #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif #ifndef RTLD_LOCAL #define RTLD_LOCAL 0 #endif #ifdef AIX #include #endif #ifdef OSF1 #include #include #endif #elif defined(USE_HPSHL) #include #elif defined(USE_MACH_DYLD) #include #endif #endif /* XP_UNIX */ #define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY #ifdef VMS /* These are all require for the PR_GetLibraryFilePathname implementation */ #include #include #include #include #include #include #include #include #include #pragma __nostandard #pragma __member_alignment __save #pragma __nomember_alignment #ifdef __INITIAL_POINTER_SIZE #pragma __required_pointer_size __save #pragma __required_pointer_size __short #endif typedef struct _imcb { struct _imcb *imcb$l_flink; struct _imcb *imcb$l_blink; unsigned short int imcb$w_size; unsigned char imcb$b_type; char imcb$b_resv_1; unsigned char imcb$b_access_mode; unsigned char imcb$b_act_code; unsigned short int imcb$w_chan; unsigned int imcb$l_flags; char imcb$t_image_name [40]; unsigned int imcb$l_symvec_size; unsigned __int64 imcb$q_ident; void *imcb$l_starting_address; void *imcb$l_end_address; } IMCB; #pragma __member_alignment __restore #ifdef __INITIAL_POINTER_SIZE #pragma __required_pointer_size __restore #endif #pragma __standard typedef struct { short buflen; short itmcode; void *buffer; void *retlen; } ITMLST; typedef struct { short cond; short count; int rest; } IOSB; typedef unsigned long int ulong_t; struct _imcb *IAC$GL_IMAGE_LIST = NULL; #define MAX_DEVNAM 64 #define MAX_FILNAM 255 #endif /* VMS */ /* * On these platforms, symbols have a leading '_'. */ #if defined(SUNOS4) || defined(DARWIN) || defined(NEXTSTEP) \ || defined(WIN16) || defined(XP_OS2) \ || ((defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__)) #define NEED_LEADING_UNDERSCORE #endif #define PR_LD_PATHW 0x8000 /* for PR_LibSpec_PathnameU */ /************************************************************************/ struct PRLibrary { char* name; /* Our own copy of the name string */ PRLibrary* next; int refCount; const PRStaticLinkTable* staticTable; #ifdef XP_PC #ifdef XP_OS2 HMODULE dlh; #else HINSTANCE dlh; #endif #endif #ifdef XP_MACOSX CFragConnectionID connection; CFBundleRef bundle; Ptr main; CFMutableDictionaryRef wrappers; const struct mach_header* image; #endif #ifdef XP_UNIX #if defined(USE_HPSHL) shl_t dlh; #elif defined(USE_MACH_DYLD) NSModule dlh; #else void* dlh; #endif #endif #ifdef XP_BEOS void* dlh; void* stub_dlh; #endif }; static PRLibrary *pr_loadmap; static PRLibrary *pr_exe_loadmap; static PRMonitor *pr_linker_lock; static char* _pr_currentLibPath = NULL; static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags); #ifdef WIN95 typedef HMODULE (WINAPI *LoadLibraryWFn)(LPCWSTR); static HMODULE WINAPI EmulateLoadLibraryW(LPCWSTR); static LoadLibraryWFn loadLibraryW = LoadLibraryW; #endif #ifdef WIN32 static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len); #endif /************************************************************************/ #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR) static char* errStrBuf = NULL; #define ERR_STR_BUF_LENGTH 20 static char* errno_string(PRIntn oserr) { if (errStrBuf == NULL) errStrBuf = PR_MALLOC(ERR_STR_BUF_LENGTH); PR_snprintf(errStrBuf, ERR_STR_BUF_LENGTH, "error %d", oserr); return errStrBuf; } #endif static void DLLErrorInternal(PRIntn oserr) /* ** This whole function, and most of the code in this file, are run ** with a big hairy lock wrapped around it. Not the best of situations, ** but will eventually come up with the right answer. */ { const char *error = NULL; #ifdef USE_DLFCN error = dlerror(); /* $$$ That'll be wrong some of the time - AOF */ #elif defined(HAVE_STRERROR) error = strerror(oserr); /* this should be okay */ #else error = errno_string(oserr); #endif if (NULL != error) PR_SetErrorText(strlen(error), error); } /* DLLErrorInternal */ void _PR_InitLinker(void) { PRLibrary *lm = NULL; #if defined(XP_UNIX) void *h; #endif #ifdef WIN95 if (!_pr_useUnicode) { loadLibraryW = EmulateLoadLibraryW; } #endif if (!pr_linker_lock) { pr_linker_lock = PR_NewNamedMonitor("linker-lock"); } PR_EnterMonitor(pr_linker_lock); #if defined(XP_PC) lm = PR_NEWZAP(PRLibrary); lm->name = strdup("Executable"); /* ** In WIN32, GetProcAddress(...) expects a module handle in order to ** get exported symbols from the executable... ** ** However, in WIN16 this is accomplished by passing NULL to ** GetProcAddress(...) */ #if defined(_WIN32) lm->dlh = GetModuleHandle(NULL); #else lm->dlh = (HINSTANCE)NULL; #endif /* ! _WIN32 */ lm->refCount = 1; lm->staticTable = NULL; pr_exe_loadmap = lm; pr_loadmap = lm; #elif defined(XP_UNIX) #ifdef HAVE_DLL #ifdef USE_DLFCN h = dlopen(0, RTLD_LAZY); if (!h) { char *error; DLLErrorInternal(_MD_ERRNO()); error = (char*)PR_MALLOC(PR_GetErrorTextLength()); (void) PR_GetErrorText(error); fprintf(stderr, "failed to initialize shared libraries [%s]\n", error); PR_DELETE(error); abort();/* XXX */ } #elif defined(USE_HPSHL) h = NULL; /* don't abort with this NULL */ #elif defined(USE_MACH_DYLD) h = NULL; /* XXXX toshok */ #else #error no dll strategy #endif /* USE_DLFCN */ lm = PR_NEWZAP(PRLibrary); if (lm) { lm->name = strdup("a.out"); lm->refCount = 1; lm->dlh = h; lm->staticTable = NULL; } pr_exe_loadmap = lm; pr_loadmap = lm; #endif /* HAVE_DLL */ #endif /* XP_UNIX */ if (lm) { PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (init)", lm->name)); } PR_ExitMonitor(pr_linker_lock); } #if defined(WIN16) /* * _PR_ShutdownLinker unloads all dlls loaded by the application via * calls to PR_LoadLibrary */ void _PR_ShutdownLinker(void) { PR_EnterMonitor(pr_linker_lock); while (pr_loadmap) { if (pr_loadmap->refCount > 1) { #ifdef DEBUG fprintf(stderr, "# Forcing library to unload: %s (%d outstanding references)\n", pr_loadmap->name, pr_loadmap->refCount); #endif pr_loadmap->refCount = 1; } PR_UnloadLibrary(pr_loadmap); } PR_ExitMonitor(pr_linker_lock); PR_DestroyMonitor(pr_linker_lock); pr_linker_lock = NULL; } #else /* * _PR_ShutdownLinker was originally only used on WIN16 (see above), * but I think it should also be used on other platforms. However, * I disagree with the original implementation's unloading the dlls * for the application. Any dlls that still remain on the pr_loadmap * list when NSPR shuts down are application programming errors. The * only exception is pr_exe_loadmap, which was added to the list by * NSPR and hence should be cleaned up by NSPR. */ void _PR_ShutdownLinker(void) { /* FIXME: pr_exe_loadmap should be destroyed. */ PR_DestroyMonitor(pr_linker_lock); pr_linker_lock = NULL; if (_pr_currentLibPath) { free(_pr_currentLibPath); _pr_currentLibPath = NULL; } #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR) PR_DELETE(errStrBuf); #endif } #endif /******************************************************************************/ PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path) { PRStatus rv = PR_SUCCESS; if (!_pr_initialized) _PR_ImplicitInitialization(); PR_EnterMonitor(pr_linker_lock); if (_pr_currentLibPath) { free(_pr_currentLibPath); } if (path) { _pr_currentLibPath = strdup(path); if (!_pr_currentLibPath) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); rv = PR_FAILURE; } } else { _pr_currentLibPath = 0; } PR_ExitMonitor(pr_linker_lock); return rv; } /* ** Return the library path for finding shared libraries. */ PR_IMPLEMENT(char *) PR_GetLibraryPath(void) { char *ev; char *copy = NULL; /* a copy of _pr_currentLibPath */ if (!_pr_initialized) _PR_ImplicitInitialization(); PR_EnterMonitor(pr_linker_lock); if (_pr_currentLibPath != NULL) { goto exit; } /* initialize pr_currentLibPath */ #ifdef XP_PC ev = getenv("LD_LIBRARY_PATH"); if (!ev) { ev = ".;\\lib"; } ev = strdup(ev); #endif #if defined(XP_UNIX) || defined(XP_BEOS) #if defined(USE_DLFCN) || defined(USE_MACH_DYLD) || defined(XP_BEOS) { char *p=NULL; int len; #ifdef XP_BEOS ev = getenv("LIBRARY_PATH"); if (!ev) { ev = "%A/lib:/boot/home/config/lib:/boot/beos/system/lib"; } #else ev = getenv("LD_LIBRARY_PATH"); if (!ev) { ev = "/usr/lib:/lib"; } #endif len = strlen(ev) + 1; /* +1 for the null */ p = (char*) malloc(len); if (p) { strcpy(p, ev); } /* if (p) */ ev = p; PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev)); } #else /* AFAIK there isn't a library path with the HP SHL interface --Rob */ ev = strdup(""); #endif #endif /* * If ev is NULL, we have run out of memory */ _pr_currentLibPath = ev; exit: if (_pr_currentLibPath) { copy = strdup(_pr_currentLibPath); } PR_ExitMonitor(pr_linker_lock); if (!copy) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); } return copy; } /* ** Build library name from path, lib and extensions */ PR_IMPLEMENT(char*) PR_GetLibraryName(const char *path, const char *lib) { char *fullname; #ifdef XP_PC if (strstr(lib, PR_DLL_SUFFIX) == NULL) { if (path) { fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX); } else { fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX); } } else { if (path) { fullname = PR_smprintf("%s\\%s", path, lib); } else { fullname = PR_smprintf("%s", lib); } } #endif /* XP_PC */ #if defined(XP_UNIX) || defined(XP_BEOS) if (strstr(lib, PR_DLL_SUFFIX) == NULL) { if (path) { fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX); } else { fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX); } } else { if (path) { fullname = PR_smprintf("%s/%s", path, lib); } else { fullname = PR_smprintf("%s", lib); } } #endif /* XP_UNIX || XP_BEOS */ return fullname; } /* ** Free the memory allocated, for the caller, by PR_GetLibraryName */ PR_IMPLEMENT(void) PR_FreeLibraryName(char *mem) { PR_smprintf_free(mem); } static PRLibrary* pr_UnlockedFindLibrary(const char *name) { PRLibrary* lm = pr_loadmap; const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR); np = np ? np + 1 : name; while (lm) { const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR); cp = cp ? cp + 1 : lm->name; #ifdef WIN32 /* Windows DLL names are case insensitive... */ if (strcmpi(np, cp) == 0) #elif defined(XP_OS2) if (stricmp(np, cp) == 0) #else if (strcmp(np, cp) == 0) #endif { /* found */ lm->refCount++; PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("%s incr => %d (find lib)", lm->name, lm->refCount)); return lm; } lm = lm->next; } return NULL; } PR_IMPLEMENT(PRLibrary*) PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags) { if (flags == 0) { flags = _PR_DEFAULT_LD_FLAGS; } switch (libSpec.type) { case PR_LibSpec_Pathname: return pr_LoadLibraryByPathname(libSpec.value.pathname, flags); #ifdef WIN32 case PR_LibSpec_PathnameU: /* * cast to |char *| and set PR_LD_PATHW flag so that * it can be cast back to PRUnichar* in the callee. */ return pr_LoadLibraryByPathname((const char*) libSpec.value.pathname_u, flags | PR_LD_PATHW); #endif default: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } } PR_IMPLEMENT(PRLibrary*) PR_LoadLibrary(const char *name) { PRLibSpec libSpec; libSpec.type = PR_LibSpec_Pathname; libSpec.value.pathname = name; return PR_LoadLibraryWithFlags(libSpec, 0); } #if defined(USE_MACH_DYLD) static NSModule pr_LoadMachDyldModule(const char *name) { NSObjectFileImage ofi; NSModule h = NULL; if (NSCreateObjectFileImageFromFile(name, &ofi) == NSObjectFileImageSuccess) { h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR); /* * TODO: If NSLinkModule fails, use NSLinkEditError to retrieve * error information. */ if (NSDestroyObjectFileImage(ofi) == FALSE) { if (h) { (void)NSUnLinkModule(h, NSUNLINKMODULE_OPTION_NONE); h = NULL; } } } return h; } #endif #ifdef XP_MACOSX static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp) { static uint32 glue[6] = { 0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420 }; uint32* newGlue = NULL; if (tvp != NULL) { CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII); if (nameRef) { CFMutableDataRef glueData = (CFMutableDataRef) CFDictionaryGetValue(dict, nameRef); if (glueData == NULL) { glueData = CFDataCreateMutable(NULL, sizeof(glue)); if (glueData != NULL) { newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); memcpy(newGlue, glue, sizeof(glue)); newGlue[0] |= ((UInt32)tvp >> 16); newGlue[1] |= ((UInt32)tvp & 0xFFFF); MakeDataExecutable(newGlue, sizeof(glue)); CFDictionaryAddValue(dict, nameRef, glueData); CFRelease(glueData); PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: created wrapper for CFM function %s().", name)); } } else { PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: found wrapper for CFM function %s().", name)); newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); } CFRelease(nameRef); } } return newGlue; } /* ** macLibraryLoadProc is a function definition for a Mac shared library ** loading method. The "name" param is the same full or partial pathname ** that was passed to pr_LoadLibraryByPathName. The function must fill ** in the fields of "lm" which apply to its library type. Returns ** PR_SUCCESS if successful. */ typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm); static PRStatus pr_LoadViaCFM(const char *name, PRLibrary *lm) { OSErr err; Str255 errName; FSRef ref; FSSpec fileSpec; Boolean tempUnusedBool; /* * Make an FSSpec from the path name and call GetDiskFragment. */ /* Use direct conversion of POSIX path to FSRef to FSSpec. */ err = FSPathMakeRef((const UInt8*)name, &ref, NULL); if (err != noErr) return PR_FAILURE; err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, &fileSpec, NULL); if (err != noErr) return PR_FAILURE; /* Resolve an alias if this was one */ err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool, &tempUnusedBool); if (err != noErr) return PR_FAILURE; /* Finally, try to load the library */ err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, kLoadCFrag, &lm->connection, &lm->main, errName); if (err == noErr && lm->connection) { /* * if we're a mach-o binary, need to wrap all CFM function * pointers. need a hash-table of already seen function * pointers, etc. */ lm->wrappers = CFDictionaryCreateMutable(NULL, 16, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (lm->wrappers) { lm->main = TV2FP(lm->wrappers, "main", lm->main); } else err = memFullErr; } return (err == noErr) ? PR_SUCCESS : PR_FAILURE; } /* ** Creates a CFBundleRef if the pathname refers to a Mac OS X bundle ** directory. The caller is responsible for calling CFRelease() to ** deallocate. */ static PRStatus pr_LoadCFBundle(const char *name, PRLibrary *lm) { CFURLRef bundleURL; CFBundleRef bundle = NULL; char pathBuf[PATH_MAX]; const char *resolvedPath; CFStringRef pathRef; /* Takes care of relative paths and symlinks */ resolvedPath = realpath(name, pathBuf); if (!resolvedPath) return PR_FAILURE; pathRef = CFStringCreateWithCString(NULL, pathBuf, kCFStringEncodingUTF8); if (pathRef) { bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef, kCFURLPOSIXPathStyle, true); if (bundleURL) { bundle = CFBundleCreate(NULL, bundleURL); CFRelease(bundleURL); } CFRelease(pathRef); } lm->bundle = bundle; return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE; } static PRStatus pr_LoadViaDyld(const char *name, PRLibrary *lm) { lm->dlh = pr_LoadMachDyldModule(name); if (lm->dlh == NULL) { lm->image = NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_WITH_SEARCHING); /* * TODO: If NSAddImage fails, use NSLinkEditError to retrieve * error information. */ } return (lm->dlh != NULL || lm->image != NULL) ? PR_SUCCESS : PR_FAILURE; } #endif /* XP_MACOSX */ #ifdef WIN95 static HMODULE WINAPI EmulateLoadLibraryW(LPCWSTR lpLibFileName) { HMODULE h; char nameA[MAX_PATH]; if (!WideCharToMultiByte(CP_ACP, 0, lpLibFileName, -1, nameA, sizeof nameA, NULL, NULL)) { return NULL; } /* Perhaps it's better to add a check for characters * not representable in CP_ACP. */ h = LoadLibraryA(nameA); return h; } #endif /* WIN95 */ /* ** Dynamically load a library. Only load libraries once, so scan the load ** map first. */ static PRLibrary* pr_LoadLibraryByPathname(const char *name, PRIntn flags) { PRLibrary *lm; PRLibrary* result = NULL; PRInt32 oserr; #ifdef WIN32 char utf8name_stack[MAX_PATH]; char *utf8name_malloc = NULL; char *utf8name = utf8name_stack; PRUnichar wname_stack[MAX_PATH]; PRUnichar *wname_malloc = NULL; PRUnichar *wname = wname_stack; int len; #endif if (!_pr_initialized) _PR_ImplicitInitialization(); /* See if library is already loaded */ PR_EnterMonitor(pr_linker_lock); #ifdef WIN32 if (flags & PR_LD_PATHW) { /* cast back what's cast to |char *| for the argument passing. */ wname = (LPWSTR) name; } else { int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); if (wlen > MAX_PATH) wname = wname_malloc = PR_Malloc(wlen * sizeof(PRUnichar)); if (wname == NULL || !MultiByteToWideChar(CP_ACP, 0, name, -1, wname, wlen)) { oserr = _MD_ERRNO(); goto unlock; } } len = pr_ConvertUTF16toUTF8(wname, NULL, 0); if (len > MAX_PATH) utf8name = utf8name_malloc = PR_Malloc(len); if (utf8name == NULL || !pr_ConvertUTF16toUTF8(wname, utf8name, len)) { oserr = _MD_ERRNO(); goto unlock; } /* the list of loaded library names are always kept in UTF-8 * on Win32 platforms */ result = pr_UnlockedFindLibrary(utf8name); #else result = pr_UnlockedFindLibrary(name); #endif if (result != NULL) goto unlock; lm = PR_NEWZAP(PRLibrary); if (lm == NULL) { oserr = _MD_ERRNO(); goto unlock; } lm->staticTable = NULL; #ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */ { HMODULE h; UCHAR pszError[_MAX_PATH]; ULONG ulRc = NO_ERROR; ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); if (ulRc != NO_ERROR) { oserr = ulRc; PR_DELETE(lm); goto unlock; } lm->name = strdup(name); lm->dlh = h; lm->next = pr_loadmap; pr_loadmap = lm; } #endif /* XP_OS2 */ #if defined(WIN32) || defined(WIN16) { HINSTANCE h; #ifdef WIN32 #ifdef WIN95 if (flags & PR_LD_PATHW) h = loadLibraryW(wname); else h = LoadLibraryA(name); #else if (flags & PR_LD_PATHW) h = LoadLibraryW(wname); else h = LoadLibraryA(name); #endif /* WIN95 */ #else h = LoadLibrary(name); #endif if (h < (HINSTANCE)HINSTANCE_ERROR) { oserr = _MD_ERRNO(); PR_DELETE(lm); goto unlock; } #ifdef WIN32 lm->name = strdup(utf8name); #else lm->name = strdup(name); #endif lm->dlh = h; lm->next = pr_loadmap; pr_loadmap = lm; } #endif /* WIN32 || WIN16 */ #ifdef XP_MACOSX { int i; PRStatus status; static const macLibraryLoadProc loadProcs[] = { pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM }; for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) { if ((status = loadProcs[i](name, lm)) == PR_SUCCESS) break; } if (status != PR_SUCCESS) { oserr = cfragNoLibraryErr; PR_DELETE(lm); goto unlock; } lm->name = strdup(name); lm->next = pr_loadmap; pr_loadmap = lm; } #endif #if defined(XP_UNIX) && !defined(XP_MACOSX) #ifdef HAVE_DLL { #if defined(USE_DLFCN) #ifdef NTO /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */ int dl_flags = RTLD_GROUP; #elif defined(AIX) /* AIX needs RTLD_MEMBER to load an archive member. (bug 228899) */ int dl_flags = RTLD_MEMBER; #else int dl_flags = 0; #endif void *h; if (flags & PR_LD_LAZY) { dl_flags |= RTLD_LAZY; } if (flags & PR_LD_NOW) { dl_flags |= RTLD_NOW; } if (flags & PR_LD_GLOBAL) { dl_flags |= RTLD_GLOBAL; } if (flags & PR_LD_LOCAL) { dl_flags |= RTLD_LOCAL; } h = dlopen(name, dl_flags); #elif defined(USE_HPSHL) int shl_flags = 0; shl_t h; /* * Use the DYNAMIC_PATH flag only if 'name' is a plain file * name (containing no directory) to match the behavior of * dlopen(). */ if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) { shl_flags |= DYNAMIC_PATH; } if (flags & PR_LD_LAZY) { shl_flags |= BIND_DEFERRED; } if (flags & PR_LD_NOW) { shl_flags |= BIND_IMMEDIATE; } /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */ h = shl_load(name, shl_flags, 0L); #elif defined(USE_MACH_DYLD) NSModule h = pr_LoadMachDyldModule(name); #else #error Configuration error #endif if (!h) { oserr = _MD_ERRNO(); PR_DELETE(lm); goto unlock; } lm->name = strdup(name); lm->dlh = h; lm->next = pr_loadmap; pr_loadmap = lm; } #endif /* HAVE_DLL */ #endif /* XP_UNIX */ lm->refCount = 1; #ifdef XP_BEOS { image_info info; int32 cookie = 0; image_id imageid = B_ERROR; image_id stubid = B_ERROR; PRLibrary *p; for (p = pr_loadmap; p != NULL; p = p->next) { /* hopefully, our caller will always use the same string to refer to the same library */ if (strcmp(name, p->name) == 0) { /* we've already loaded this library */ imageid = info.id; lm->refCount++; break; } } if(imageid == B_ERROR) { /* it appears the library isn't yet loaded - load it now */ char stubName [B_PATH_NAME_LENGTH + 1]; /* the following is a work-around to a "bug" in the beos - the beos system loader allows only 32M (system-wide) to be used by code loaded as "add-ons" (code loaded through the 'load_add_on()' system call, which includes mozilla components), but allows 256M to be used by shared libraries. unfortunately, mozilla is too large to fit into the "add-on" space, so we must trick the loader into loading some of the components as shared libraries. this is accomplished by creating a "stub" add-on (an empty shared object), and linking it with the component (the actual .so file generated by the build process, without any modifications). when this stub is loaded by load_add_on(), the loader will automatically load the component into the shared library space. */ strcpy(stubName, name); strcat(stubName, ".stub"); /* first, attempt to load the stub (thereby loading the component as a shared library */ if ((stubid = load_add_on(stubName)) > B_ERROR) { /* the stub was loaded successfully. */ imageid = B_FILE_NOT_FOUND; cookie = 0; while (get_next_image_info(0, &cookie, &info) == B_OK) { const char *endOfSystemName = strrchr(info.name, '/'); const char *endOfPassedName = strrchr(name, '/'); if( 0 == endOfSystemName ) endOfSystemName = info.name; else endOfSystemName++; if( 0 == endOfPassedName ) endOfPassedName = name; else endOfPassedName++; if (strcmp(endOfSystemName, endOfPassedName) == 0) { /* this is the actual component - remember it */ imageid = info.id; break; } } } else { /* we failed to load the "stub" - try to load the component directly as an add-on */ stubid = B_ERROR; imageid = load_add_on(name); } } if (imageid <= B_ERROR) { oserr = imageid; PR_DELETE( lm ); goto unlock; } lm->name = strdup(name); lm->dlh = (void*)imageid; lm->stub_dlh = (void*)stubid; lm->next = pr_loadmap; pr_loadmap = lm; } #endif result = lm; /* success */ PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name)); unlock: if (result == NULL) { PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr); DLLErrorInternal(oserr); /* sets error text */ } #ifdef WIN32 if (utf8name_malloc) PR_Free(utf8name_malloc); if (wname_malloc) PR_Free(wname_malloc); #endif PR_ExitMonitor(pr_linker_lock); return result; } #ifdef WIN32 #ifdef WIN95 /* * CP_UTF8 is not supported by WideCharToMultiByte on Windows 95 so that * we have to emulate it */ static PRStatus pr_ConvertSingleCharToUTF8(PRUint32 usv, PRUint16 offset, int bufLen, int *utf8Len, char * *buf) { char* p = *buf; PR_ASSERT(!bufLen || *buf); if (!bufLen) { *utf8Len += offset; return PR_SUCCESS; } if (*utf8Len + offset >= bufLen) return PR_FAILURE; *utf8Len += offset; if (offset == 1) { *p++ = (char) usv; } else if (offset == 2) { *p++ = (char)0xc0 | (usv >> 6); *p++ = (char)0x80 | (usv & 0x003f); } else if (offset == 3) { *p++ = (char)0xe0 | (usv >> 12); *p++ = (char)0x80 | ((usv >> 6) & 0x003f); *p++ = (char)0x80 | (usv & 0x003f); } else { /* offset = 4 */ *p++ = (char)0xf0 | (usv >> 18); *p++ = (char)0x80 | ((usv >> 12) & 0x003f); *p++ = (char)0x80 | ((usv >> 6) & 0x003f); *p++ = (char)0x80 | (usv & 0x003f); } *buf = p; return PR_SUCCESS; } static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len) { LPCWSTR pw = wname; LPSTR p = name; int utf8Len = 0; PRBool highSurrogate = PR_FALSE; utf8Len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len, NULL, NULL); /* * Windows 95 and NT 3.51 don't support CP_UTF8. * WideCharToMultiByte(CP_UTF8, ...) fails with the error code * ERROR_INVALID_PARAMETER on Windows 95 and NT 3.51. */ if (utf8Len || GetLastError() != ERROR_INVALID_PARAMETER) return utf8Len; if (!wname || len < 0 || (len > 0 && !name)) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } while (*pw) { PRStatus status = PR_SUCCESS; if (highSurrogate) { if (*pw >= (PRUnichar) 0xDC00 && *pw < (PRUnichar) 0xE000) { /* found a matching low surrogate */ /* convert a surrogate pair to UCS4 */ PRUint32 usv = ((*(pw-1) - (PRUnichar)0xD800) << 10) + (*pw - (PRUnichar)0xDC00) + (PRUint32)0x10000; if (pr_ConvertSingleCharToUTF8(usv, 4, len, &utf8Len, &p) == PR_FAILURE) return 0; highSurrogate = PR_FALSE; ++pw; continue; } else { /* * silently ignore a lone high surrogate * as is done by WideCharToMultiByte by default */ highSurrogate = PR_FALSE; } } if (*pw <= 0x7f) status = pr_ConvertSingleCharToUTF8(*pw, 1, len, &utf8Len, &p); else if (*pw <= 0x07ff) status = pr_ConvertSingleCharToUTF8(*pw, 2, len, &utf8Len, &p); else if (*pw < (PRUnichar) 0xD800 || *pw >= (PRUnichar) 0xE000) status = pr_ConvertSingleCharToUTF8(*pw, 3, len, &utf8Len, &p); else if (*pw < (PRUnichar) 0xDC00) highSurrogate = PR_TRUE; /* else */ /* silently ignore a lone low surrogate as is done by * WideCharToMultiByte by default */ if (status == PR_FAILURE) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return 0; } ++pw; } /* if we're concerned with a lone high surrogate, * we have to take care of it here, but we just drop it */ if (len > 0) *p = '\0'; return utf8Len + 1; } #else static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len) { return WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len, NULL, NULL); } #endif /* WIN95 */ #endif /* WIN32 */ /* ** Unload a shared library which was loaded via PR_LoadLibrary */ PR_IMPLEMENT(PRStatus) PR_UnloadLibrary(PRLibrary *lib) { int result = 0; PRStatus status = PR_SUCCESS; if ((lib == 0) || (lib->refCount <= 0)) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return PR_FAILURE; } PR_EnterMonitor(pr_linker_lock); if (--lib->refCount > 0) { PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("%s decr => %d", lib->name, lib->refCount)); goto done; } #ifdef XP_BEOS if(((image_id)lib->stub_dlh) == B_ERROR) unload_add_on( (image_id) lib->dlh ); else unload_add_on( (image_id) lib->stub_dlh); #endif #ifdef XP_UNIX #ifdef HAVE_DLL #ifdef USE_DLFCN result = dlclose(lib->dlh); #elif defined(USE_HPSHL) result = shl_unload(lib->dlh); #elif defined(USE_MACH_DYLD) if (lib->dlh) result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1; #else #error Configuration error #endif #endif /* HAVE_DLL */ #endif /* XP_UNIX */ #ifdef XP_PC if (lib->dlh) { FreeLibrary((HINSTANCE)(lib->dlh)); lib->dlh = (HINSTANCE)NULL; } #endif /* XP_PC */ #ifdef XP_MACOSX /* Close the connection */ if (lib->connection) CloseConnection(&(lib->connection)); if (lib->bundle) CFRelease(lib->bundle); if (lib->wrappers) CFRelease(lib->wrappers); /* No way to unload an image (lib->image) */ #endif /* unlink from library search list */ if (pr_loadmap == lib) pr_loadmap = pr_loadmap->next; else if (pr_loadmap != NULL) { PRLibrary* prev = pr_loadmap; PRLibrary* next = pr_loadmap->next; while (next != NULL) { if (next == lib) { prev->next = next->next; goto freeLib; } prev = next; next = next->next; } /* * fail (the library is not on the _pr_loadmap list), * but don't wipe out an error from dlclose/shl_unload. */ PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent"); if (result == 0) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); status = PR_FAILURE; } } /* * We free the PRLibrary structure whether dlclose/shl_unload * succeeds or not. */ freeLib: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name)); free(lib->name); lib->name = NULL; PR_DELETE(lib); if (result != 0) { PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO()); DLLErrorInternal(_MD_ERRNO()); status = PR_FAILURE; } done: PR_ExitMonitor(pr_linker_lock); return status; } static void* pr_FindSymbolInLib(PRLibrary *lm, const char *name) { void *f = NULL; #ifdef XP_OS2 int rc; #endif if (lm->staticTable != NULL) { const PRStaticLinkTable* tp; for (tp = lm->staticTable; tp->name; tp++) { if (strcmp(name, tp->name) == 0) { return (void*) tp->fp; } } /* ** If the symbol was not found in the static table then check if ** the symbol was exported in the DLL... Win16 only!! */ #if !defined(WIN16) && !defined(XP_BEOS) PR_SetError(PR_FIND_SYMBOL_ERROR, 0); return (void*)NULL; #endif } #ifdef XP_OS2 rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); #if defined(NEED_LEADING_UNDERSCORE) /* * Older plugins (not built using GCC) will have symbols that are not * underscore prefixed. We check for that here. */ if (rc != NO_ERROR) { name++; DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); } #endif #endif /* XP_OS2 */ #if defined(WIN32) || defined(WIN16) f = GetProcAddress(lm->dlh, name); #endif /* WIN32 || WIN16 */ #ifdef XP_MACOSX /* add this offset to skip the leading underscore in name */ #define SYM_OFFSET 1 if (lm->bundle) { CFStringRef nameRef = CFStringCreateWithCString(NULL, name + SYM_OFFSET, kCFStringEncodingASCII); if (nameRef) { f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef); CFRelease(nameRef); } } if (lm->connection) { Ptr symAddr; CFragSymbolClass symClass; Str255 pName; PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET)); c2pstrcpy(pName, name + SYM_OFFSET); f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; /* callers expect mach-o function pointers, so must wrap tvectors with glue. */ if (f && symClass == kTVectorCFragSymbol) { f = TV2FP(lm->wrappers, name + SYM_OFFSET, f); } if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main; } if (lm->image) { NSSymbol symbol; symbol = NSLookupSymbolInImage(lm->image, name, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); if (symbol != NULL) f = NSAddressOfSymbol(symbol); else f = NULL; } #undef SYM_OFFSET #endif /* XP_MACOSX */ #ifdef XP_BEOS if( B_NO_ERROR != get_image_symbol( (image_id)lm->dlh, name, B_SYMBOL_TYPE_TEXT, &f ) ) { f = NULL; } #endif #ifdef XP_UNIX #ifdef HAVE_DLL #ifdef USE_DLFCN f = dlsym(lm->dlh, name); #elif defined(USE_HPSHL) if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) { f = NULL; } #elif defined(USE_MACH_DYLD) if (lm->dlh) { NSSymbol symbol; symbol = NSLookupSymbolInModule(lm->dlh, name); if (symbol != NULL) f = NSAddressOfSymbol(symbol); else f = NULL; } #endif #endif /* HAVE_DLL */ #endif /* XP_UNIX */ if (f == NULL) { PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO()); DLLErrorInternal(_MD_ERRNO()); } return f; } /* ** Called by class loader to resolve missing native's */ PR_IMPLEMENT(void*) PR_FindSymbol(PRLibrary *lib, const char *raw_name) { void *f = NULL; #if defined(NEED_LEADING_UNDERSCORE) char *name; #else const char *name; #endif /* ** Mangle the raw symbol name in any way that is platform specific. */ #if defined(NEED_LEADING_UNDERSCORE) /* Need a leading _ */ name = PR_smprintf("_%s", raw_name); #elif defined(AIX) /* ** AIX with the normal linker put's a "." in front of the symbol ** name. When use "svcc" and "svld" then the "." disappears. Go ** figure. */ name = raw_name; #else name = raw_name; #endif PR_EnterMonitor(pr_linker_lock); PR_ASSERT(lib != NULL); f = pr_FindSymbolInLib(lib, name); #if defined(NEED_LEADING_UNDERSCORE) PR_smprintf_free(name); #endif PR_ExitMonitor(pr_linker_lock); return f; } /* ** Return the address of the function 'raw_name' in the library 'lib' */ PR_IMPLEMENT(PRFuncPtr) PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name) { return ((PRFuncPtr) PR_FindSymbol(lib, raw_name)); } PR_IMPLEMENT(void*) PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) { void *f = NULL; #if defined(NEED_LEADING_UNDERSCORE) char *name; #else const char *name; #endif PRLibrary* lm; if (!_pr_initialized) _PR_ImplicitInitialization(); /* ** Mangle the raw symbol name in any way that is platform specific. */ #if defined(NEED_LEADING_UNDERSCORE) /* Need a leading _ */ name = PR_smprintf("_%s", raw_name); #elif defined(AIX) /* ** AIX with the normal linker put's a "." in front of the symbol ** name. When use "svcc" and "svld" then the "." disappears. Go ** figure. */ name = raw_name; #else name = raw_name; #endif PR_EnterMonitor(pr_linker_lock); /* search all libraries */ for (lm = pr_loadmap; lm != NULL; lm = lm->next) { f = pr_FindSymbolInLib(lm, name); if (f != NULL) { *lib = lm; lm->refCount++; PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("%s incr => %d (for %s)", lm->name, lm->refCount, name)); break; } } #if defined(NEED_LEADING_UNDERSCORE) PR_smprintf_free(name); #endif PR_ExitMonitor(pr_linker_lock); return f; } PR_IMPLEMENT(PRFuncPtr) PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) { return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib)); } /* ** Add a static library to the list of loaded libraries. If LoadLibrary ** is called with the name then we will pretend it was already loaded */ PR_IMPLEMENT(PRLibrary*) PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt) { PRLibrary *lm=NULL; PRLibrary* result = NULL; if (!_pr_initialized) _PR_ImplicitInitialization(); /* See if library is already loaded */ PR_EnterMonitor(pr_linker_lock); /* If the lbrary is already loaded, then add the static table information... */ result = pr_UnlockedFindLibrary(name); if (result != NULL) { PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) ); result->staticTable = slt; goto unlock; } /* Add library to list...Mark it static */ lm = PR_NEWZAP(PRLibrary); if (lm == NULL) goto unlock; lm->name = strdup(name); lm->refCount = 1; lm->dlh = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0; lm->staticTable = slt; lm->next = pr_loadmap; pr_loadmap = lm; result = lm; /* success */ PR_ASSERT(lm->refCount == 1); unlock: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name)); PR_ExitMonitor(pr_linker_lock); return result; } PR_IMPLEMENT(char *) PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr) { #if defined(SOLARIS) || defined(LINUX) || defined(FREEBSD) Dl_info dli; char *result; if (dladdr((void *)addr, &dli) == 0) { PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); DLLErrorInternal(_MD_ERRNO()); return NULL; } result = PR_Malloc(strlen(dli.dli_fname)+1); if (result != NULL) { strcpy(result, dli.dli_fname); } return result; #elif defined(USE_MACH_DYLD) char *result; char *image_name; int i, count = _dyld_image_count(); for (i = 0; i < count; i++) { image_name = _dyld_get_image_name(i); if (strstr(image_name, name) != NULL) { result = PR_Malloc(strlen(image_name)+1); if (result != NULL) { strcpy(result, image_name); } return result; } } PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); return NULL; #elif defined(AIX) char *result; #define LD_INFO_INCREMENT 64 struct ld_info *info; unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info); struct ld_info *infop; int loadflags = L_GETINFO | L_IGNOREUNLOAD; for (;;) { info = PR_Malloc(info_length); if (info == NULL) { return NULL; } /* If buffer is too small, loadquery fails with ENOMEM. */ if (loadquery(loadflags, info, info_length) != -1) { break; } /* * Calling loadquery when compiled for 64-bit with the * L_IGNOREUNLOAD flag can cause an invalid argument error * on AIX 5.1. Detect this error the first time that * loadquery is called, and try calling it again without * this flag set. */ if (errno == EINVAL && (loadflags & L_IGNOREUNLOAD)) { loadflags &= ~L_IGNOREUNLOAD; if (loadquery(loadflags, info, info_length) != -1) { break; } } PR_Free(info); if (errno != ENOMEM) { /* should not happen */ _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); return NULL; } /* retry with a larger buffer */ info_length += LD_INFO_INCREMENT * sizeof(struct ld_info); } for (infop = info; ; infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) { unsigned long start = (unsigned long)infop->ldinfo_dataorg; unsigned long end = start + infop->ldinfo_datasize; if (start <= (unsigned long)addr && end > (unsigned long)addr) { result = PR_Malloc(strlen(infop->ldinfo_filename)+1); if (result != NULL) { strcpy(result, infop->ldinfo_filename); } break; } if (!infop->ldinfo_next) { PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); result = NULL; break; } } PR_Free(info); return result; #elif defined(OSF1) /* Contributed by Steve Streeter of HP */ ldr_process_t process, ldr_my_process(); ldr_module_t mod_id; ldr_module_info_t info; ldr_region_t regno; ldr_region_info_t reginfo; size_t retsize; int rv; char *result; /* Get process for which dynamic modules will be listed */ process = ldr_my_process(); /* Attach to process */ rv = ldr_xattach(process); if (rv) { /* should not happen */ _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); return NULL; } /* Print information for list of modules */ mod_id = LDR_NULL_MODULE; for (;;) { /* Get information for the next module in the module list. */ ldr_next_module(process, &mod_id); if (ldr_inq_module(process, mod_id, &info, sizeof(info), &retsize) != 0) { /* No more modules */ break; } if (retsize < sizeof(info)) { continue; } /* * Get information for each region in the module and check if any * contain the address of this function. */ for (regno = 0; ; regno++) { if (ldr_inq_region(process, mod_id, regno, ®info, sizeof(reginfo), &retsize) != 0) { /* No more regions */ break; } if (((unsigned long)reginfo.lri_mapaddr <= (unsigned long)addr) && (((unsigned long)reginfo.lri_mapaddr + reginfo.lri_size) > (unsigned long)addr)) { /* Found it. */ result = PR_Malloc(strlen(info.lmi_name)+1); if (result != NULL) { strcpy(result, info.lmi_name); } return result; } } } PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); return NULL; #elif defined(VMS) /* Contributed by Colin Blake of HP */ struct _imcb *icb; ulong_t status; char device_name[MAX_DEVNAM]; int device_name_len; $DESCRIPTOR (device_name_desc, device_name); struct fibdef fib; struct dsc$descriptor_s fib_desc = { sizeof(struct fibdef), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (char *)&fib } ; IOSB iosb; ITMLST devlst[2] = { {MAX_DEVNAM, DVI$_ALLDEVNAM, device_name, &device_name_len}, {0,0,0,0}}; short file_name_len; char file_name[MAX_FILNAM+1]; char *result = NULL; struct dsc$descriptor_s file_name_desc = { MAX_FILNAM, DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) &file_name[0] } ; /* ** The address for the process image list could change in future versions ** of the operating system. 7FFD0688 is valid for V7.2 and V7.3 releases, ** so we use that for the default, but allow an environment variable ** (logical name) to override. */ if (IAC$GL_IMAGE_LIST == NULL) { char *p = getenv("MOZILLA_IAC_GL_IMAGE_LIST"); if (p) IAC$GL_IMAGE_LIST = (struct _imcb *) strtol(p,NULL,0); else IAC$GL_IMAGE_LIST = (struct _imcb *) 0x7FFD0688; } for (icb = IAC$GL_IMAGE_LIST->imcb$l_flink; icb != IAC$GL_IMAGE_LIST; icb = icb->imcb$l_flink) { if (((void *)addr >= icb->imcb$l_starting_address) && ((void *)addr <= icb->imcb$l_end_address)) { /* ** This is the correct image. ** Get the device name. */ status = sys$getdviw(0,icb->imcb$w_chan,0,&devlst,0,0,0,0); if ($VMS_STATUS_SUCCESS(status)) device_name_desc.dsc$w_length = device_name_len; /* ** Get the FID. */ memset(&fib,0,sizeof(struct fibdef)); status = sys$qiow(0,icb->imcb$w_chan,IO$_ACCESS,&iosb, 0,0,&fib_desc,0,0,0,0,0); /* ** If we got the FID, now look up its name (if for some reason ** we didn't get the device name, this call will fail). */ if (($VMS_STATUS_SUCCESS(status)) && ($VMS_STATUS_SUCCESS(iosb.cond))) { status = lib$fid_to_name ( &device_name_desc, &fib.fib$w_fid, &file_name_desc, &file_name_len, 0, 0); /* ** If we succeeded then remove the version number and ** return a copy of the UNIX format version of the file name. */ if ($VMS_STATUS_SUCCESS(status)) { char *p, *result; file_name[file_name_len] = 0; p = strrchr(file_name,';'); if (p) *p = 0; p = decc$translate_vms(&file_name[0]); result = PR_Malloc(strlen(p)+1); if (result != NULL) { strcpy(result, p); } return result; } } } } /* Didn't find it */ PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); return NULL; #elif defined(HPUX) && defined(USE_HPSHL) int index; struct shl_descriptor desc; char *result; for (index = 0; shl_get_r(index, &desc) == 0; index++) { if (strstr(desc.filename, name) != NULL) { result = PR_Malloc(strlen(desc.filename)+1); if (result != NULL) { strcpy(result, desc.filename); } return result; } } /* * Since the index value of a library is decremented if * a library preceding it in the shared library search * list was unloaded, it is possible that we missed some * libraries as we went up the list. So we should go * down the list to be sure that we not miss anything. */ for (index--; index >= 0; index--) { if ((shl_get_r(index, &desc) == 0) && (strstr(desc.filename, name) != NULL)) { result = PR_Malloc(strlen(desc.filename)+1); if (result != NULL) { strcpy(result, desc.filename); } return result; } } PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); return NULL; #elif defined(HPUX) && defined(USE_DLFCN) struct load_module_desc desc; char *result; const char *module_name; if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) { PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); DLLErrorInternal(_MD_ERRNO()); return NULL; } module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0); if (module_name == NULL) { /* should not happen */ _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); DLLErrorInternal(_MD_ERRNO()); return NULL; } result = PR_Malloc(strlen(module_name)+1); if (result != NULL) { strcpy(result, module_name); } return result; #elif defined(WIN32) HMODULE handle; char module_name[MAX_PATH]; char *result; handle = GetModuleHandle(name); if (handle == NULL) { PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); DLLErrorInternal(_MD_ERRNO()); return NULL; } if (GetModuleFileName(handle, module_name, sizeof module_name) == 0) { /* should not happen */ _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); return NULL; } result = PR_Malloc(strlen(module_name)+1); if (result != NULL) { strcpy(result, module_name); } return result; #elif defined(XP_OS2) HMODULE module = NULL; char module_name[_MAX_PATH]; char *result; APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr); if ((NO_ERROR != ulrc) || (NULL == module) ) { PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); DLLErrorInternal(_MD_ERRNO()); return NULL; } ulrc = DosQueryModuleName(module, sizeof module_name, module_name); if (NO_ERROR != ulrc) { /* should not happen */ _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); return NULL; } result = PR_Malloc(strlen(module_name)+1); if (result != NULL) { strcpy(result, module_name); } return result; #else PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); return NULL; #endif }