/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "primpl.h" #include #ifdef XP_MAC #include #include #include #include #endif #ifdef XP_UNIX #ifdef USE_DLFCN #include #elif defined(USE_HPSHL) #include #elif defined(RHAPSODY) #include #endif /* Define this on systems which don't have it (AIX) */ #ifndef RTLD_LAZY #define RTLD_LAZY RTLD_NOW #endif #endif /* XP_UNIX */ /* * On these platforms, symbols have a leading '_'. */ #if defined(SUNOS4) || defined(RHAPSODY) || defined(WIN16) #define NEED_LEADING_UNDERSCORE #endif #ifdef XP_PC typedef PRStaticLinkTable *NODL_PROC(void); #endif /************************************************************************/ struct PRLibrary { char* name; /* Our own copy of the name string */ PRLibrary* next; int refCount; const PRStaticLinkTable* staticTable; #ifdef XP_PC HINSTANCE dlh; #endif #ifdef XP_MAC CFragConnectionID dlh; #endif #ifdef XP_UNIX #if defined(USE_HPSHL) shl_t dlh; #elif defined(RHAPSODY) NSModule dlh; #else void* dlh; #endif #endif }; static PRLibrary *pr_loadmap; static PRLibrary *pr_exe_loadmap; static PRMonitor *pr_linker_lock; static char* _pr_currentLibPath = NULL; /************************************************************************/ #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) { #ifndef XP_MAC PRLibrary *lm; #endif #if defined(XP_UNIX) void *h; #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(RHAPSODY) 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 */ #ifndef XP_MAC PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (init)", lm?lm->name:"NULL")); #endif PR_ExitMonitor(pr_linker_lock); } #if defined(WIN16) 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; } #endif /******************************************************************************/ PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path) { PRStatus rv = PR_SUCCESS; PR_EnterMonitor(pr_linker_lock); PR_FREEIF(_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() { char *ev; char *copy = NULL; /* a copy of _pr_currentLibPath */ 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 #ifdef XP_MAC { char *p; int len; ev = getenv("LD_LIBRARY_PATH"); /* if we couldn't find something make up a default */ if (!ev) ev = "/usr/local/netscape;/usr/local/netscape/java/bin"; /* do we put the classes in here too? */ len = strlen(ev) + 1; /* +1 for the null */ p = (char*) PR_MALLOC(len); if (p) { strcpy(p, ev); } ev = p; } #endif #ifdef XP_UNIX #if defined USE_DLFCN || defined RHAPSODY { char *home; char *local; char *p=NULL; char * mozilla_home=NULL; int len; ev = getenv("LD_LIBRARY_PATH"); if (!ev) { ev = "/usr/lib:/lib"; } home = getenv("HOME"); /* ** Augment the path automatically by adding in ~/.netscape and ** /usr/local/netscape */ len = strlen(ev) + 1; /* +1 for the null */ if (home && home[0]) { len += strlen(home) + 1; /* +1 for the colon */ } mozilla_home = getenv("MOZILLA_HOME"); if (mozilla_home && mozilla_home[0]) { len += strlen(mozilla_home) + 5 ; /* +5 for initial : and trailing "/lib" */ } local = ":/usr/local/netscape/lib/" PR_LINKER_ARCH; len += strlen(local); /* already got the : */ p = (char*) PR_MALLOC(len+50); if (p) { strcpy(p, ev); if (home) { strcat(p, ":"); strcat(p, home); } if (mozilla_home && mozilla_home[0]) { strcat(p, ":"); strcat(p, mozilla_home); strcat(p, "/lib"); } strcat(p, local); } /* if (p) */ ev = p; PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev)); printf("linker_path = %s\n", 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) { fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX); } else { fullname = PR_smprintf("%s\\%s", path, lib); } #endif /* XP_PC */ #ifdef XP_MAC fullname = PR_smprintf("%s%s", path, lib); #endif #ifdef XP_UNIX if (strstr(lib, PR_DLL_SUFFIX) == NULL) { fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX); } else { fullname = PR_smprintf("%s/%s", path, lib); } #endif /* XP_UNIX */ 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 XP_PC /* Windows DLL names are case insensitive... */ if (strcmpi(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; } /* ** Dynamically load a library. Only load libraries once, so scan the load ** map first. */ PR_IMPLEMENT(PRLibrary*) PR_LoadLibrary(const char *name) { PRLibrary *lm; PRLibrary* result; if (!_pr_initialized) _PR_ImplicitInitialization(); /* See if library is already loaded */ PR_EnterMonitor(pr_linker_lock); result = pr_UnlockedFindLibrary(name); if (result != NULL) goto unlock; lm = PR_NEWZAP(PRLibrary); if (lm == NULL) goto unlock; lm->staticTable = NULL; #ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */ { NODL_PROC *pfn; HMODULE h; UCHAR pszError[_MAX_PATH]; ULONG ulRc = NO_ERROR; int first_try = 1; retry: ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); if (ulRc != NO_ERROR) { 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; NODL_PROC *pfn; h = LoadLibrary(name); if (h < (HINSTANCE)HINSTANCE_ERROR) { PR_DELETE(lm); goto unlock; } lm->name = strdup(name); lm->dlh = h; lm->next = pr_loadmap; pr_loadmap = lm; /* ** Try to load a table of "static functions" provided by the DLL */ pfn = (NODL_PROC *)GetProcAddress(h, "NODL_TABLE"); if (pfn != NULL) { lm->staticTable = (*pfn)(); } } #endif /* WIN32 || WIN16 */ #if defined(XP_MAC) && GENERATINGCFM { OSErr err; Ptr main; CFragConnectionID connectionID; Str255 errName; Str255 pName; char cName[64]; const char* libName; /* * Algorithm: The "name" passed in could be either a shared * library name that we should look for in the normal library * search paths, or a full path name to a specific library on * disk. Since the full path will always contain a ":" * (shortest possible path is "Volume:File"), and since a * library name can not contain a ":", we can test for the * presence of a ":" to see which type of library we should load. * or its a full UNIX path which we for now assume is Java * enumerating all the paths (see below) */ if (strchr(name, PR_PATH_SEPARATOR) == NULL) { if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) { /* * The name did not contain a ":", so it must be a * library name. Convert the name to a Pascal string * and try to find the library. */ } else { /* name contained a "/" which means we need to suck off the last part */ /* of the path and pass that on the NSGetSharedLibrary */ /* this may not be what we really want to do .. because Java could */ /* be iterating through the whole LD path, and we'll find it if it's */ /* anywhere on that path -- it appears that's what UNIX and the PC do */ /* too...so we'll emulate but it could be wrong. */ name = strrchr(name, PR_DIRECTORY_SEPARATOR) + 1; } PStrFromCStr(name, pName); err = NSGetSharedLibrary(pName, &connectionID, &main); if (err != noErr) goto unlock; libName = name; } else { /* * The name did contain a ":", so it must be a full path name. * Now we have to do a lot of work to convert the path name to * an FSSpec (silly, since we were probably just called from the * MacFE plug-in code that already knew the FSSpec and converted * it to a full path just to pass to us). First we copy out the * volume name (the text leading up to the first ":"); then we * separate the file name (the text following the last ":") from * rest of the path. After converting the strings to Pascal * format we can call GetCatInfo to get the parent directory ID * of the file, and then (finally) make an FSSpec and call * GetDiskFragment. */ char* cMacPath = NULL; char* cFileName = NULL; char* position = NULL; CInfoPBRec pb; FSSpec fileSpec; PRUint32 index; /* Copy the name: we'll change it */ cMacPath = strdup(name); if (cMacPath == NULL) goto unlock; /* First, get the vRefNum */ position = strchr(cMacPath, PR_PATH_SEPARATOR); if ((position == cMacPath) || (position == NULL)) fileSpec.vRefNum = 0; /* Use application relative searching */ else { char cVolName[32]; memset(cVolName, 0, sizeof(cVolName)); strncpy(cVolName, cMacPath, position-cMacPath); fileSpec.vRefNum = GetVolumeRefNumFromName(cVolName); } /* Next, break the path and file name apart */ index = 0; while (cMacPath[index] != 0) index++; while (cMacPath[index] != PR_PATH_SEPARATOR && index > 0) index--; if (index == 0 || index == strlen(cMacPath)) { PR_DELETE(cMacPath); goto unlock; } cMacPath[index] = 0; cFileName = &(cMacPath[index + 1]); /* Convert the path and name into Pascal strings */ strcpy((char*) &pName, cMacPath); c2pstr((char*) &pName); strcpy((char*) &fileSpec.name, cFileName); c2pstr((char*) &fileSpec.name); strcpy(cName, cFileName); PR_DELETE(cMacPath); cMacPath = NULL; /* Now we can look up the path on the volume */ pb.dirInfo.ioNamePtr = pName; pb.dirInfo.ioVRefNum = fileSpec.vRefNum; pb.dirInfo.ioDrDirID = 0; pb.dirInfo.ioFDirIndex = 0; err = PBGetCatInfoSync(&pb); if (err != noErr) goto unlock; fileSpec.parID = pb.dirInfo.ioDrDirID; /* Finally, try to load the library */ err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, kLoadCFrag, &connectionID, &main, errName); libName = cName; if (err != noErr) goto unlock; } lm->name = strdup(libName); lm->dlh = connectionID; lm->next = pr_loadmap; pr_loadmap = lm; } #elif defined(XP_MAC) && !GENERATINGCFM { } #endif #ifdef XP_UNIX #ifdef HAVE_DLL { #if defined(USE_DLFCN) void *h = dlopen(name, RTLD_LAZY); #elif defined(USE_HPSHL) shl_t h = shl_load(name, BIND_DEFERRED | DYNAMIC_PATH, 0L); #elif defined(RHAPSODY) NSObjectFileImage ofi; NSModule h = NULL; if (NSCreateObjectFileImageFromFile(name, &ofi) == NSObjectFileImageSuccess) { h = NSLinkModule(ofi, name, TRUE); } #else #error Configuration error #endif if (!h) { 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; 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, _MD_ERRNO()); DLLErrorInternal(_MD_ERRNO()); /* sets error text */ } PR_ExitMonitor(pr_linker_lock); return result; } PR_IMPLEMENT(PRLibrary*) PR_FindLibrary(const char *name) { PRLibrary* result; PR_EnterMonitor(pr_linker_lock); result = pr_UnlockedFindLibrary(name); PR_ExitMonitor(pr_linker_lock); return result; } /* ** 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_UNIX #ifdef HAVE_DLL #ifdef USE_DLFCN result = dlclose(lib->dlh); #elif defined(USE_HPSHL) result = shl_unload(lib->dlh); #elif defined(RHAPSODY) result = NSUnLinkModule(lib->dlh, FALSE); #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 */ #if defined(XP_MAC) && GENERATINGCFM /* Close the connection */ CloseConnection(&(lib->dlh)); #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)); PR_DELETE(lib->name); PR_DELETE(lib); if (result == -1) { 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; 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) PR_SetError(PR_FIND_SYMBOL_ERROR, 0); return (void*)NULL; #endif } #ifdef XP_OS2 DosQueryProcAddr(lm->dlh, 0, name, (PFN *) &f); #endif /* XP_OS2 */ #if defined(WIN32) || defined(WIN16) f = GetProcAddress(lm->dlh, name); #endif /* WIN32 || WIN16 */ #ifdef XP_MAC { Ptr symAddr; CFragSymbolClass symClass; Str255 pName; PStrFromCStr(name, pName); f = (NSFindSymbol(lm->dlh, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; } #endif /* XP_MAC */ #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(RHAPSODY) f = NSAddressOfSymbol(NSLookupAndBindSymbol(name)); #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; } 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; /* ** 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; } /* ** 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; }