/* -*- 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 <string.h>
#ifdef XP_MAC
#include <CodeFragments.h>
#include <TextUtils.h>
#include <Types.h>
#include <Strings.h>
#endif
#ifdef XP_UNIX
#ifdef USE_DLFCN
#include <dlfcn.h>
#elif defined(USE_HPSHL)
#include <dl.h>
#elif defined(RHAPSODY)
#include <mach-o/dyld.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1