nsprpub/pr/src/linking/prlink.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "primpl.h"
     8 #include <string.h>
    10 #ifdef XP_BEOS
    11 #include <image.h>
    12 #endif
    14 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
    15 #include <Carbon/Carbon.h>
    16 #include <CoreFoundation/CoreFoundation.h>
    17 #endif
    19 #ifdef XP_UNIX
    20 #ifdef USE_DLFCN
    21 #include <dlfcn.h>
    22 /* Define these on systems that don't have them. */
    23 #ifndef RTLD_NOW
    24 #define RTLD_NOW 0
    25 #endif
    26 #ifndef RTLD_LAZY
    27 #define RTLD_LAZY RTLD_NOW
    28 #endif
    29 #ifndef RTLD_GLOBAL
    30 #define RTLD_GLOBAL 0
    31 #endif
    32 #ifndef RTLD_LOCAL
    33 #define RTLD_LOCAL 0
    34 #endif
    35 #ifdef AIX
    36 #include <sys/ldr.h>
    37 #ifndef L_IGNOREUNLOAD /* AIX 4.3.3 does not have L_IGNOREUNLOAD. */
    38 #define L_IGNOREUNLOAD 0x10000000
    39 #endif
    40 #endif
    41 #ifdef OSF1
    42 #include <loader.h>
    43 #include <rld_interface.h>
    44 #endif
    45 #elif defined(USE_HPSHL)
    46 #include <dl.h>
    47 #elif defined(USE_MACH_DYLD)
    48 #include <mach-o/dyld.h>
    49 #endif
    50 #endif /* XP_UNIX */
    52 #define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY
    54 /*
    55  * On these platforms, symbols have a leading '_'.
    56  */
    57 #if (defined(DARWIN) && defined(USE_MACH_DYLD)) \
    58     || defined(XP_OS2) \
    59     || ((defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__))
    60 #define NEED_LEADING_UNDERSCORE
    61 #endif
    63 #define PR_LD_PATHW 0x8000  /* for PR_LibSpec_PathnameU */
    65 /************************************************************************/
    67 struct PRLibrary {
    68     char*                       name;  /* Our own copy of the name string */
    69     PRLibrary*                  next;
    70     int                         refCount;
    71     const PRStaticLinkTable*    staticTable;
    73 #ifdef XP_PC
    74 #ifdef XP_OS2
    75     HMODULE                     dlh;
    76 #else
    77     HINSTANCE                   dlh;
    78 #endif
    79 #endif
    81 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
    82     CFragConnectionID           connection;
    83     CFBundleRef                 bundle;
    84     Ptr                         main;
    85     CFMutableDictionaryRef      wrappers;
    86     const struct mach_header*   image;
    87 #endif
    89 #ifdef XP_UNIX
    90 #if defined(USE_HPSHL)
    91     shl_t                       dlh;
    92 #elif defined(USE_MACH_DYLD)
    93     NSModule                    dlh;
    94 #else
    95     void*                       dlh;
    96 #endif 
    97 #endif 
    99 #ifdef XP_BEOS
   100     void*                       dlh;
   101     void*                       stub_dlh;
   102 #endif
   103 };
   105 static PRLibrary *pr_loadmap;
   106 static PRLibrary *pr_exe_loadmap;
   107 static PRMonitor *pr_linker_lock;
   108 static char* _pr_currentLibPath = NULL;
   110 static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags);
   112 /************************************************************************/
   114 #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR)
   115 #define ERR_STR_BUF_LENGTH    20
   116 #endif
   118 static void DLLErrorInternal(PRIntn oserr)
   119 /*
   120 ** This whole function, and most of the code in this file, are run
   121 ** with a big hairy lock wrapped around it. Not the best of situations,
   122 ** but will eventually come up with the right answer.
   123 */
   124 {
   125     const char *error = NULL;
   126 #ifdef USE_DLFCN
   127     error = dlerror();  /* $$$ That'll be wrong some of the time - AOF */
   128 #elif defined(HAVE_STRERROR)
   129     error = strerror(oserr);  /* this should be okay */
   130 #else
   131     char errStrBuf[ERR_STR_BUF_LENGTH];
   132     PR_snprintf(errStrBuf, sizeof(errStrBuf), "error %d", oserr);
   133     error = errStrBuf;
   134 #endif
   135     if (NULL != error)
   136         PR_SetErrorText(strlen(error), error);
   137 }  /* DLLErrorInternal */
   139 void _PR_InitLinker(void)
   140 {
   141     PRLibrary *lm = NULL;
   142 #if defined(XP_UNIX)
   143     void *h;
   144 #endif
   146     if (!pr_linker_lock) {
   147         pr_linker_lock = PR_NewNamedMonitor("linker-lock");
   148     }
   149     PR_EnterMonitor(pr_linker_lock);
   151 #if defined(XP_PC)
   152     lm = PR_NEWZAP(PRLibrary);
   153     lm->name = strdup("Executable");
   154 #if defined(XP_OS2)
   155     lm->dlh = NULLHANDLE;
   156 #else
   157     /* A module handle for the executable. */
   158     lm->dlh = GetModuleHandle(NULL);
   159 #endif /* ! XP_OS2 */
   161     lm->refCount    = 1;
   162     lm->staticTable = NULL;
   163     pr_exe_loadmap  = lm;
   164     pr_loadmap      = lm;
   166 #elif defined(XP_UNIX)
   167 #ifdef HAVE_DLL
   168 #if defined(USE_DLFCN) && !defined(NO_DLOPEN_NULL)
   169     h = dlopen(0, RTLD_LAZY);
   170     if (!h) {
   171         char *error;
   173         DLLErrorInternal(_MD_ERRNO());
   174         error = (char*)PR_MALLOC(PR_GetErrorTextLength());
   175         (void) PR_GetErrorText(error);
   176         fprintf(stderr, "failed to initialize shared libraries [%s]\n",
   177             error);
   178         PR_DELETE(error);
   179         abort();/* XXX */
   180     }
   181 #elif defined(USE_HPSHL)
   182     h = NULL;
   183     /* don't abort with this NULL */
   184 #elif defined(USE_MACH_DYLD) || defined(NO_DLOPEN_NULL)
   185     h = NULL; /* XXXX  toshok */ /* XXXX  vlad */
   186 #else
   187 #error no dll strategy
   188 #endif /* USE_DLFCN */
   190     lm = PR_NEWZAP(PRLibrary);
   191     if (lm) {
   192         lm->name = strdup("a.out");
   193         lm->refCount = 1;
   194         lm->dlh = h;
   195         lm->staticTable = NULL;
   196     }
   197     pr_exe_loadmap = lm;
   198     pr_loadmap = lm;
   199 #endif /* HAVE_DLL */
   200 #endif /* XP_UNIX */
   202     if (lm) {
   203         PR_LOG(_pr_linker_lm, PR_LOG_MIN,
   204             ("Loaded library %s (init)", lm->name));
   205     }
   207     PR_ExitMonitor(pr_linker_lock);
   208 }
   210 /*
   211  * _PR_ShutdownLinker does not unload the dlls loaded by the application
   212  * via calls to PR_LoadLibrary.  Any dlls that still remain on the
   213  * pr_loadmap list when NSPR shuts down are application programming errors.
   214  * The only exception is pr_exe_loadmap, which was added to the list by
   215  * NSPR and hence should be cleaned up by NSPR.
   216  */
   217 void _PR_ShutdownLinker(void)
   218 {
   219     /* FIXME: pr_exe_loadmap should be destroyed. */
   221     PR_DestroyMonitor(pr_linker_lock);
   222     pr_linker_lock = NULL;
   224     if (_pr_currentLibPath) {
   225         free(_pr_currentLibPath);
   226         _pr_currentLibPath = NULL;
   227     }
   228 }
   230 /******************************************************************************/
   232 PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path)
   233 {
   234     PRStatus rv = PR_SUCCESS;
   236     if (!_pr_initialized) _PR_ImplicitInitialization();
   237     PR_EnterMonitor(pr_linker_lock);
   238     if (_pr_currentLibPath) {
   239         free(_pr_currentLibPath);
   240     }
   241     if (path) {
   242         _pr_currentLibPath = strdup(path);
   243         if (!_pr_currentLibPath) {
   244             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   245         rv = PR_FAILURE;
   246         }
   247     } else {
   248         _pr_currentLibPath = 0;
   249     }
   250     PR_ExitMonitor(pr_linker_lock);
   251     return rv;
   252 }
   254 /*
   255 ** Return the library path for finding shared libraries.
   256 */
   257 PR_IMPLEMENT(char *) 
   258 PR_GetLibraryPath(void)
   259 {
   260     char *ev;
   261     char *copy = NULL;  /* a copy of _pr_currentLibPath */
   263     if (!_pr_initialized) _PR_ImplicitInitialization();
   264     PR_EnterMonitor(pr_linker_lock);
   265     if (_pr_currentLibPath != NULL) {
   266         goto exit;
   267     }
   269     /* initialize pr_currentLibPath */
   271 #ifdef XP_PC
   272     ev = getenv("LD_LIBRARY_PATH");
   273     if (!ev) {
   274     ev = ".;\\lib";
   275     }
   276     ev = strdup(ev);
   277 #endif
   279 #if defined(XP_UNIX) || defined(XP_BEOS)
   280 #if defined(USE_DLFCN) || defined(USE_MACH_DYLD) || defined(XP_BEOS)
   281     {
   282     char *p=NULL;
   283     int len;
   285 #ifdef XP_BEOS
   286     ev = getenv("LIBRARY_PATH");
   287     if (!ev) {
   288         ev = "%A/lib:/boot/home/config/lib:/boot/beos/system/lib";
   289     }
   290 #else
   291     ev = getenv("LD_LIBRARY_PATH");
   292     if (!ev) {
   293         ev = "/usr/lib:/lib";
   294     }
   295 #endif
   296     len = strlen(ev) + 1;        /* +1 for the null */
   298     p = (char*) malloc(len);
   299     if (p) {
   300         strcpy(p, ev);
   301     }   /* if (p)  */
   302     ev = p;
   303     PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev));
   305     }
   306 #else
   307     /* AFAIK there isn't a library path with the HP SHL interface --Rob */
   308     ev = strdup("");
   309 #endif
   310 #endif
   312     /*
   313      * If ev is NULL, we have run out of memory
   314      */
   315     _pr_currentLibPath = ev;
   317   exit:
   318     if (_pr_currentLibPath) {
   319         copy = strdup(_pr_currentLibPath);
   320     }
   321     PR_ExitMonitor(pr_linker_lock);
   322     if (!copy) {
   323         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   324     }
   325     return copy;
   326 }
   328 /*
   329 ** Build library name from path, lib and extensions
   330 */
   331 PR_IMPLEMENT(char*) 
   332 PR_GetLibraryName(const char *path, const char *lib)
   333 {
   334     char *fullname;
   336 #ifdef XP_PC
   337     if (strstr(lib, PR_DLL_SUFFIX) == NULL)
   338     {
   339         if (path) {
   340             fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX);
   341         } else {
   342             fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX);
   343         }
   344     } else {
   345         if (path) {
   346             fullname = PR_smprintf("%s\\%s", path, lib);
   347         } else {
   348             fullname = PR_smprintf("%s", lib);
   349         }
   350     }
   351 #endif /* XP_PC */
   352 #if defined(XP_UNIX) || defined(XP_BEOS)
   353     if (strstr(lib, PR_DLL_SUFFIX) == NULL)
   354     {
   355         if (path) {
   356             fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX);
   357         } else {
   358             fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX);
   359         }
   360     } else {
   361         if (path) {
   362             fullname = PR_smprintf("%s/%s", path, lib);
   363         } else {
   364             fullname = PR_smprintf("%s", lib);
   365         }
   366     }
   367 #endif /* XP_UNIX || XP_BEOS */
   368     return fullname;
   369 }
   371 /*
   372 ** Free the memory allocated, for the caller, by PR_GetLibraryName
   373 */
   374 PR_IMPLEMENT(void) 
   375 PR_FreeLibraryName(char *mem)
   376 {
   377     PR_smprintf_free(mem);
   378 }
   380 static PRLibrary* 
   381 pr_UnlockedFindLibrary(const char *name)
   382 {
   383     PRLibrary* lm = pr_loadmap;
   384     const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR);
   385     np = np ? np + 1 : name;
   386     while (lm) {
   387     const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR);
   388     cp = cp ? cp + 1 : lm->name;
   389 #ifdef WIN32
   390         /* Windows DLL names are case insensitive... */
   391     if (strcmpi(np, cp) == 0) 
   392 #elif defined(XP_OS2)
   393     if (stricmp(np, cp) == 0)
   394 #else
   395     if (strcmp(np, cp)  == 0) 
   396 #endif
   397     {
   398         /* found */
   399         lm->refCount++;
   400         PR_LOG(_pr_linker_lm, PR_LOG_MIN,
   401            ("%s incr => %d (find lib)",
   402             lm->name, lm->refCount));
   403         return lm;
   404     }
   405     lm = lm->next;
   406     }
   407     return NULL;
   408 }
   410 PR_IMPLEMENT(PRLibrary*)
   411 PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags)
   412 {
   413     if (flags == 0) {
   414         flags = _PR_DEFAULT_LD_FLAGS;
   415     }
   416     switch (libSpec.type) {
   417         case PR_LibSpec_Pathname:
   418             return pr_LoadLibraryByPathname(libSpec.value.pathname, flags);
   419 #ifdef WIN32
   420         case PR_LibSpec_PathnameU:
   421             /*
   422              * cast to |char *| and set PR_LD_PATHW flag so that
   423              * it can be cast back to PRUnichar* in the callee.
   424              */
   425             return pr_LoadLibraryByPathname((const char*) 
   426                                             libSpec.value.pathname_u, 
   427                                             flags | PR_LD_PATHW);
   428 #endif
   429         default:
   430             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   431             return NULL;
   432     }
   433 }
   435 PR_IMPLEMENT(PRLibrary*) 
   436 PR_LoadLibrary(const char *name)
   437 {
   438     PRLibSpec libSpec;
   440     libSpec.type = PR_LibSpec_Pathname;
   441     libSpec.value.pathname = name;
   442     return PR_LoadLibraryWithFlags(libSpec, 0);
   443 }
   445 #if defined(USE_MACH_DYLD)
   446 static NSModule
   447 pr_LoadMachDyldModule(const char *name)
   448 {
   449     NSObjectFileImage ofi;
   450     NSModule h = NULL;
   451     if (NSCreateObjectFileImageFromFile(name, &ofi)
   452             == NSObjectFileImageSuccess) {
   453         h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE
   454                          | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
   455         if (h == NULL) {
   456             NSLinkEditErrors linkEditError;
   457             int errorNum;
   458             const char *fileName;
   459             const char *errorString;
   460             NSLinkEditError(&linkEditError, &errorNum, &fileName, &errorString);
   461             PR_LOG(_pr_linker_lm, PR_LOG_MIN, 
   462                    ("LoadMachDyldModule error %d:%d for file %s:\n%s",
   463                     linkEditError, errorNum, fileName, errorString));
   464         }
   465         if (NSDestroyObjectFileImage(ofi) == FALSE) {
   466             if (h) {
   467                 (void)NSUnLinkModule(h, NSUNLINKMODULE_OPTION_NONE);
   468                 h = NULL;
   469             }
   470         }
   471     }
   472     return h;
   473 }
   474 #endif
   476 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
   478 /*
   479 ** macLibraryLoadProc is a function definition for a Mac shared library
   480 ** loading method. The "name" param is the same full or partial pathname
   481 ** that was passed to pr_LoadLibraryByPathName. The function must fill
   482 ** in the fields of "lm" which apply to its library type. Returns
   483 ** PR_SUCCESS if successful.
   484 */
   486 typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm);
   488 #ifdef __ppc__
   490 /*
   491 ** CFM and its TVectors only exist on PowerPC.  Other OS X architectures
   492 ** only use Mach-O as a native binary format.
   493 */
   495 static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp)
   496 {
   497     static uint32 glue[6] = { 0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420 };
   498     uint32* newGlue = NULL;
   500     if (tvp != NULL) {
   501         CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII);
   502         if (nameRef) {
   503             CFMutableDataRef glueData = (CFMutableDataRef) CFDictionaryGetValue(dict, nameRef);
   504             if (glueData == NULL) {
   505                 glueData = CFDataCreateMutable(NULL, sizeof(glue));
   506                 if (glueData != NULL) {
   507                     newGlue = (uint32*) CFDataGetMutableBytePtr(glueData);
   508                     memcpy(newGlue, glue, sizeof(glue));
   509                     newGlue[0] |= ((UInt32)tvp >> 16);
   510                     newGlue[1] |= ((UInt32)tvp & 0xFFFF);
   511                     MakeDataExecutable(newGlue, sizeof(glue));
   512                     CFDictionaryAddValue(dict, nameRef, glueData);
   513                     CFRelease(glueData);
   515                     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: created wrapper for CFM function %s().", name));
   516                 }
   517             } else {
   518                 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: found wrapper for CFM function %s().", name));
   520                 newGlue = (uint32*) CFDataGetMutableBytePtr(glueData);
   521             }
   522             CFRelease(nameRef);
   523         }
   524     }
   526     return newGlue;
   527 }
   529 static PRStatus
   530 pr_LoadViaCFM(const char *name, PRLibrary *lm)
   531 {
   532     OSErr err;
   533     Str255 errName;
   534     FSRef ref;
   535     FSSpec fileSpec;
   536     Boolean tempUnusedBool;
   538     /*
   539      * Make an FSSpec from the path name and call GetDiskFragment.
   540      */
   542     /* Use direct conversion of POSIX path to FSRef to FSSpec. */
   543     err = FSPathMakeRef((const UInt8*)name, &ref, NULL);
   544     if (err != noErr)
   545         return PR_FAILURE;
   546     err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL,
   547                            &fileSpec, NULL);
   548     if (err != noErr)
   549         return PR_FAILURE;
   551     /* Resolve an alias if this was one */
   552     err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool,
   553                            &tempUnusedBool);
   554     if (err != noErr)
   555         return PR_FAILURE;
   557     /* Finally, try to load the library */
   558     err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name,
   559                           kLoadCFrag, &lm->connection, &lm->main, errName);
   561     if (err == noErr && lm->connection) {
   562         /*
   563          * if we're a mach-o binary, need to wrap all CFM function
   564          * pointers. need a hash-table of already seen function
   565          * pointers, etc.
   566          */
   567         lm->wrappers = CFDictionaryCreateMutable(NULL, 16,
   568                        &kCFTypeDictionaryKeyCallBacks,
   569                        &kCFTypeDictionaryValueCallBacks);
   570         if (lm->wrappers) {
   571             lm->main = TV2FP(lm->wrappers, "main", lm->main);
   572         } else
   573             err = memFullErr;
   574     }
   575     return (err == noErr) ? PR_SUCCESS : PR_FAILURE;
   576 }
   577 #endif /* __ppc__ */
   579 /*
   580 ** Creates a CFBundleRef if the pathname refers to a Mac OS X bundle
   581 ** directory. The caller is responsible for calling CFRelease() to
   582 ** deallocate.
   583 */
   585 static PRStatus
   586 pr_LoadCFBundle(const char *name, PRLibrary *lm)
   587 {
   588     CFURLRef bundleURL;
   589     CFBundleRef bundle = NULL;
   590     char pathBuf[PATH_MAX];
   591     const char *resolvedPath;
   592     CFStringRef pathRef;
   594     /* Takes care of relative paths and symlinks */
   595     resolvedPath = realpath(name, pathBuf);
   596     if (!resolvedPath)
   597         return PR_FAILURE;
   599     pathRef = CFStringCreateWithCString(NULL, pathBuf, kCFStringEncodingUTF8);
   600     if (pathRef) {
   601         bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef,
   602                                                   kCFURLPOSIXPathStyle, true);
   603         if (bundleURL) {
   604             bundle = CFBundleCreate(NULL, bundleURL);
   605             CFRelease(bundleURL);
   606         }
   607         CFRelease(pathRef);
   608     }
   610     lm->bundle = bundle;
   611     return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE;
   612 }
   614 static PRStatus
   615 pr_LoadViaDyld(const char *name, PRLibrary *lm)
   616 {
   617     lm->dlh = pr_LoadMachDyldModule(name);
   618     if (lm->dlh == NULL) {
   619         lm->image = NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR
   620                                | NSADDIMAGE_OPTION_WITH_SEARCHING);
   621         if (lm->image == NULL) {
   622             NSLinkEditErrors linkEditError;
   623             int errorNum;
   624             const char *fileName;
   625             const char *errorString;
   626             NSLinkEditError(&linkEditError, &errorNum, &fileName, &errorString);
   627             PR_LOG(_pr_linker_lm, PR_LOG_MIN, 
   628                    ("LoadMachDyldModule error %d:%d for file %s:\n%s",
   629                     linkEditError, errorNum, fileName, errorString));
   630         }
   631     }
   632     return (lm->dlh != NULL || lm->image != NULL) ? PR_SUCCESS : PR_FAILURE;
   633 }
   635 #endif /* XP_MACOSX && USE_MACH_DYLD */
   637 /*
   638 ** Dynamically load a library. Only load libraries once, so scan the load
   639 ** map first.
   640 */
   641 static PRLibrary*
   642 pr_LoadLibraryByPathname(const char *name, PRIntn flags)
   643 {
   644     PRLibrary *lm;
   645     PRLibrary* result = NULL;
   646     PRInt32 oserr;
   647 #ifdef WIN32
   648     char utf8name_stack[MAX_PATH];
   649     char *utf8name_malloc = NULL;
   650     char *utf8name = utf8name_stack;
   651     PRUnichar wname_stack[MAX_PATH];
   652     PRUnichar *wname_malloc = NULL;
   653     PRUnichar *wname = wname_stack;
   654     int len;
   655 #endif
   657     if (!_pr_initialized) _PR_ImplicitInitialization();
   659     /* See if library is already loaded */
   660     PR_EnterMonitor(pr_linker_lock);
   662 #ifdef WIN32
   663     if (flags & PR_LD_PATHW) {
   664         /* cast back what's cast to |char *| for the argument passing. */
   665         wname = (LPWSTR) name;
   666     } else {
   667         int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
   668         if (wlen > MAX_PATH)
   669             wname = wname_malloc = PR_Malloc(wlen * sizeof(PRUnichar));
   670         if (wname == NULL ||
   671             !MultiByteToWideChar(CP_ACP, 0,  name, -1, wname, wlen)) {
   672             oserr = _MD_ERRNO();
   673             goto unlock;
   674         }
   675     }
   676     len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
   677     if (len > MAX_PATH)
   678         utf8name = utf8name_malloc = PR_Malloc(len);
   679     if (utf8name == NULL ||
   680         !WideCharToMultiByte(CP_UTF8, 0, wname, -1,
   681                              utf8name, len, NULL, NULL)) {
   682         oserr = _MD_ERRNO();
   683         goto unlock;
   684     }
   685     /* the list of loaded library names are always kept in UTF-8 
   686      * on Win32 platforms */
   687     result = pr_UnlockedFindLibrary(utf8name);
   688 #else
   689     result = pr_UnlockedFindLibrary(name);
   690 #endif
   692     if (result != NULL) goto unlock;
   694     lm = PR_NEWZAP(PRLibrary);
   695     if (lm == NULL) {
   696         oserr = _MD_ERRNO();
   697         goto unlock;
   698     }
   699     lm->staticTable = NULL;
   701 #ifdef XP_OS2  /* Why isn't all this stuff in MD code?! */
   702     {
   703         HMODULE h;
   704         UCHAR pszError[_MAX_PATH];
   705         ULONG ulRc = NO_ERROR;
   707           ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h);
   708           if (ulRc != NO_ERROR) {
   709               oserr = ulRc;
   710               PR_DELETE(lm);
   711               goto unlock;
   712           }
   713           lm->name = strdup(name);
   714           lm->dlh  = h;
   715           lm->next = pr_loadmap;
   716           pr_loadmap = lm;
   717     }
   718 #endif /* XP_OS2 */
   720 #ifdef WIN32
   721     {
   722     HINSTANCE h;
   724     h = LoadLibraryExW(wname, NULL,
   725                        (flags & PR_LD_ALT_SEARCH_PATH) ?
   726                        LOAD_WITH_ALTERED_SEARCH_PATH : 0);
   727     if (h == NULL) {
   728         oserr = _MD_ERRNO();
   729         PR_DELETE(lm);
   730         goto unlock;
   731     }
   732     lm->name = strdup(utf8name);
   733     lm->dlh = h;
   734     lm->next = pr_loadmap;
   735     pr_loadmap = lm;
   736     }
   737 #endif /* WIN32 */
   739 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
   740     {
   741     int     i;
   742     PRStatus status;
   744     static const macLibraryLoadProc loadProcs[] = {
   745 #ifdef __ppc__
   746         pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM
   747 #else  /* __ppc__ */
   748         pr_LoadViaDyld, pr_LoadCFBundle
   749 #endif /* __ppc__ */
   750     };
   752     for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) {
   753         if ((status = loadProcs[i](name, lm)) == PR_SUCCESS)
   754             break;
   755     }
   756     if (status != PR_SUCCESS) {
   757         oserr = cfragNoLibraryErr;
   758         PR_DELETE(lm);
   759         goto unlock;        
   760     }
   761     lm->name = strdup(name);
   762     lm->next = pr_loadmap;
   763     pr_loadmap = lm;
   764     }
   765 #endif
   767 #if defined(XP_UNIX) && !(defined(XP_MACOSX) && defined(USE_MACH_DYLD))
   768 #ifdef HAVE_DLL
   769     {
   770 #if defined(USE_DLFCN)
   771 #ifdef NTO
   772     /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */
   773     int dl_flags = RTLD_GROUP;
   774 #elif defined(AIX)
   775     /* AIX needs RTLD_MEMBER to load an archive member.  (bug 228899) */
   776     int dl_flags = RTLD_MEMBER;
   777 #else
   778     int dl_flags = 0;
   779 #endif
   780     void *h = NULL;
   782     if (flags & PR_LD_LAZY) {
   783         dl_flags |= RTLD_LAZY;
   784     }
   785     if (flags & PR_LD_NOW) {
   786         dl_flags |= RTLD_NOW;
   787     }
   788     if (flags & PR_LD_GLOBAL) {
   789         dl_flags |= RTLD_GLOBAL;
   790     }
   791     if (flags & PR_LD_LOCAL) {
   792         dl_flags |= RTLD_LOCAL;
   793     }
   794 #if defined(DARWIN)
   795     /* ensure the file exists if it contains a slash character i.e. path */
   796     /* DARWIN's dlopen ignores the provided path and checks for the */
   797     /* plain filename in DYLD_LIBRARY_PATH */
   798     if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL ||
   799         PR_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) {
   800             h = dlopen(name, dl_flags);
   801         }
   802 #else
   803     h = dlopen(name, dl_flags);
   804 #endif
   805 #elif defined(USE_HPSHL)
   806     int shl_flags = 0;
   807     shl_t h;
   809     /*
   810      * Use the DYNAMIC_PATH flag only if 'name' is a plain file
   811      * name (containing no directory) to match the behavior of
   812      * dlopen().
   813      */
   814     if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) {
   815         shl_flags |= DYNAMIC_PATH;
   816     }
   817     if (flags & PR_LD_LAZY) {
   818         shl_flags |= BIND_DEFERRED;
   819     }
   820     if (flags & PR_LD_NOW) {
   821         shl_flags |= BIND_IMMEDIATE;
   822     }
   823     /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */
   824     h = shl_load(name, shl_flags, 0L);
   825 #elif defined(USE_MACH_DYLD)
   826     NSModule h = pr_LoadMachDyldModule(name);
   827 #else
   828 #error Configuration error
   829 #endif
   830     if (!h) {
   831         oserr = _MD_ERRNO();
   832         PR_DELETE(lm);
   833         goto unlock;
   834     }
   835     lm->name = strdup(name);
   836     lm->dlh = h;
   837     lm->next = pr_loadmap;
   838     pr_loadmap = lm;
   839     }
   840 #endif /* HAVE_DLL */
   841 #endif /* XP_UNIX && !(XP_MACOSX && USE_MACH_DYLD) */
   843     lm->refCount = 1;
   845 #ifdef XP_BEOS
   846     {
   847         image_info info;
   848         int32 cookie = 0;
   849         image_id imageid = B_ERROR;
   850         image_id stubid = B_ERROR;
   851         PRLibrary *p;
   853         for (p = pr_loadmap; p != NULL; p = p->next) {
   854             /* hopefully, our caller will always use the same string
   855                to refer to the same library */
   856             if (strcmp(name, p->name) == 0) {
   857                 /* we've already loaded this library */
   858                 imageid = info.id;
   859                 lm->refCount++;
   860                 break;
   861             }
   862         }
   864         if(imageid == B_ERROR) {
   865             /* it appears the library isn't yet loaded - load it now */
   866             char stubName [B_PATH_NAME_LENGTH + 1];
   868             /* the following is a work-around to a "bug" in the beos -
   869                the beos system loader allows only 32M (system-wide)
   870                to be used by code loaded as "add-ons" (code loaded
   871                through the 'load_add_on()' system call, which includes
   872                mozilla components), but allows 256M to be used by
   873                shared libraries.
   875                unfortunately, mozilla is too large to fit into the
   876                "add-on" space, so we must trick the loader into
   877                loading some of the components as shared libraries.  this
   878                is accomplished by creating a "stub" add-on (an empty
   879                shared object), and linking it with the component
   880                (the actual .so file generated by the build process,
   881                without any modifications).  when this stub is loaded
   882                by load_add_on(), the loader will automatically load the
   883                component into the shared library space.
   884             */
   886             strcpy(stubName, name);
   887             strcat(stubName, ".stub");
   889             /* first, attempt to load the stub (thereby loading the
   890                component as a shared library */
   891             if ((stubid = load_add_on(stubName)) > B_ERROR) {
   892                 /* the stub was loaded successfully. */
   893                 imageid = B_FILE_NOT_FOUND;
   895                 cookie = 0;
   896                 while (get_next_image_info(0, &cookie, &info) == B_OK) {
   897                     const char *endOfSystemName = strrchr(info.name, '/');
   898                     const char *endOfPassedName = strrchr(name, '/');
   899                     if( 0 == endOfSystemName ) 
   900                         endOfSystemName = info.name;
   901                     else
   902                         endOfSystemName++;
   903                     if( 0 == endOfPassedName )
   904                         endOfPassedName = name;
   905                     else
   906                         endOfPassedName++;
   907                     if (strcmp(endOfSystemName, endOfPassedName) == 0) {
   908                         /* this is the actual component - remember it */
   909                         imageid = info.id;
   910                         break;
   911                     }
   912                 }
   914             } else {
   915                 /* we failed to load the "stub" - try to load the
   916                    component directly as an add-on */
   917                 stubid = B_ERROR;
   918                 imageid = load_add_on(name);
   919             }
   920         }
   922         if (imageid <= B_ERROR) {
   923             oserr = imageid;
   924             PR_DELETE( lm );
   925             goto unlock;
   926         }
   927         lm->name = strdup(name);
   928         lm->dlh = (void*)imageid;
   929         lm->stub_dlh = (void*)stubid;
   930         lm->next = pr_loadmap;
   931         pr_loadmap = lm;
   932     }
   933 #endif
   935     result = lm;    /* success */
   936     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name));
   938   unlock:
   939     if (result == NULL) {
   940         PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr);
   941         DLLErrorInternal(oserr);  /* sets error text */
   942     }
   943 #ifdef WIN32
   944     if (utf8name_malloc) 
   945         PR_Free(utf8name_malloc);
   946     if (wname_malloc)
   947         PR_Free(wname_malloc);
   948 #endif
   949     PR_ExitMonitor(pr_linker_lock);
   950     return result;
   951 }
   953 /*
   954 ** Unload a shared library which was loaded via PR_LoadLibrary
   955 */
   956 PR_IMPLEMENT(PRStatus) 
   957 PR_UnloadLibrary(PRLibrary *lib)
   958 {
   959     int result = 0;
   960     PRStatus status = PR_SUCCESS;
   962     if (lib == 0) {
   963         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   964         return PR_FAILURE;
   965     }
   967     PR_EnterMonitor(pr_linker_lock);
   969     if (lib->refCount <= 0) {
   970         PR_ExitMonitor(pr_linker_lock);
   971         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   972         return PR_FAILURE;
   973     }
   975     if (--lib->refCount > 0) {
   976     PR_LOG(_pr_linker_lm, PR_LOG_MIN,
   977            ("%s decr => %d",
   978         lib->name, lib->refCount));
   979     goto done;
   980     }
   982 #ifdef XP_BEOS
   983     if(((image_id)lib->stub_dlh) == B_ERROR)
   984         unload_add_on( (image_id) lib->dlh );
   985     else
   986         unload_add_on( (image_id) lib->stub_dlh);
   987 #endif
   989 #ifdef XP_UNIX
   990 #ifdef HAVE_DLL
   991 #ifdef USE_DLFCN
   992     result = dlclose(lib->dlh);
   993 #elif defined(USE_HPSHL)
   994     result = shl_unload(lib->dlh);
   995 #elif defined(USE_MACH_DYLD)
   996     if (lib->dlh)
   997         result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1;
   998 #else
   999 #error Configuration error
  1000 #endif
  1001 #endif /* HAVE_DLL */
  1002 #endif /* XP_UNIX */
  1003 #ifdef XP_PC
  1004     if (lib->dlh) {
  1005         FreeLibrary((HINSTANCE)(lib->dlh));
  1006         lib->dlh = (HINSTANCE)NULL;
  1008 #endif  /* XP_PC */
  1010 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
  1011     /* Close the connection */
  1012     if (lib->connection)
  1013         CloseConnection(&(lib->connection));
  1014     if (lib->bundle)
  1015         CFRelease(lib->bundle);
  1016     if (lib->wrappers)
  1017         CFRelease(lib->wrappers);
  1018     /* No way to unload an image (lib->image) */
  1019 #endif
  1021     /* unlink from library search list */
  1022     if (pr_loadmap == lib)
  1023         pr_loadmap = pr_loadmap->next;
  1024     else if (pr_loadmap != NULL) {
  1025         PRLibrary* prev = pr_loadmap;
  1026         PRLibrary* next = pr_loadmap->next;
  1027         while (next != NULL) {
  1028             if (next == lib) {
  1029                 prev->next = next->next;
  1030                 goto freeLib;
  1032             prev = next;
  1033             next = next->next;
  1035         /*
  1036          * fail (the library is not on the _pr_loadmap list),
  1037          * but don't wipe out an error from dlclose/shl_unload.
  1038          */
  1039         PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent");
  1040         if (result == 0) {
  1041             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1042             status = PR_FAILURE;
  1045     /*
  1046      * We free the PRLibrary structure whether dlclose/shl_unload
  1047      * succeeds or not.
  1048      */
  1050   freeLib:
  1051     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name));
  1052     free(lib->name);
  1053     lib->name = NULL;
  1054     PR_DELETE(lib);
  1055     if (result != 0) {
  1056         PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO());
  1057         DLLErrorInternal(_MD_ERRNO());
  1058         status = PR_FAILURE;
  1061 done:
  1062     PR_ExitMonitor(pr_linker_lock);
  1063     return status;
  1066 static void* 
  1067 pr_FindSymbolInLib(PRLibrary *lm, const char *name)
  1069     void *f = NULL;
  1070 #ifdef XP_OS2
  1071     int rc;
  1072 #endif
  1074     if (lm->staticTable != NULL) {
  1075         const PRStaticLinkTable* tp;
  1076         for (tp = lm->staticTable; tp->name; tp++) {
  1077             if (strcmp(name, tp->name) == 0) {
  1078                 return (void*) tp->fp;
  1081         /* 
  1082         ** If the symbol was not found in the static table then check if
  1083         ** the symbol was exported in the DLL... Win16 only!!
  1084         */
  1085 #if !defined(WIN16) && !defined(XP_BEOS)
  1086         PR_SetError(PR_FIND_SYMBOL_ERROR, 0);
  1087         return (void*)NULL;
  1088 #endif
  1091 #ifdef XP_OS2
  1092     rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
  1093 #if defined(NEED_LEADING_UNDERSCORE)
  1094     /*
  1095      * Older plugins (not built using GCC) will have symbols that are not
  1096      * underscore prefixed.  We check for that here.
  1097      */
  1098     if (rc != NO_ERROR) {
  1099         name++;
  1100         DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
  1102 #endif
  1103 #endif  /* XP_OS2 */
  1105 #ifdef WIN32
  1106     f = GetProcAddress(lm->dlh, name);
  1107 #endif  /* WIN32 */
  1109 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
  1110 /* add this offset to skip the leading underscore in name */
  1111 #define SYM_OFFSET 1
  1112     if (lm->bundle) {
  1113         CFStringRef nameRef = CFStringCreateWithCString(NULL, name + SYM_OFFSET, kCFStringEncodingASCII);
  1114         if (nameRef) {
  1115             f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef);
  1116             CFRelease(nameRef);
  1119     if (lm->connection) {
  1120         Ptr                 symAddr;
  1121         CFragSymbolClass    symClass;
  1122         Str255              pName;
  1124         PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET));
  1126         c2pstrcpy(pName, name + SYM_OFFSET);
  1128         f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL;
  1130 #ifdef __ppc__
  1131         /* callers expect mach-o function pointers, so must wrap tvectors with glue. */
  1132         if (f && symClass == kTVectorCFragSymbol) {
  1133             f = TV2FP(lm->wrappers, name + SYM_OFFSET, f);
  1135 #endif /* __ppc__ */
  1137         if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main;
  1139     if (lm->image) {
  1140         NSSymbol symbol;
  1141         symbol = NSLookupSymbolInImage(lm->image, name,
  1142                  NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
  1143                  | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
  1144         if (symbol != NULL)
  1145             f = NSAddressOfSymbol(symbol);
  1146         else
  1147             f = NULL;
  1149 #undef SYM_OFFSET
  1150 #endif /* XP_MACOSX && USE_MACH_DYLD */
  1152 #ifdef XP_BEOS
  1153     if( B_NO_ERROR != get_image_symbol( (image_id)lm->dlh, name, B_SYMBOL_TYPE_TEXT, &f ) ) {
  1154         f = NULL;
  1156 #endif
  1158 #ifdef XP_UNIX
  1159 #ifdef HAVE_DLL
  1160 #ifdef USE_DLFCN
  1161     f = dlsym(lm->dlh, name);
  1162 #elif defined(USE_HPSHL)
  1163     if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) {
  1164         f = NULL;
  1166 #elif defined(USE_MACH_DYLD)
  1167     if (lm->dlh) {
  1168         NSSymbol symbol;
  1169         symbol = NSLookupSymbolInModule(lm->dlh, name);
  1170         if (symbol != NULL)
  1171             f = NSAddressOfSymbol(symbol);
  1172         else
  1173             f = NULL;
  1175 #endif
  1176 #endif /* HAVE_DLL */
  1177 #endif /* XP_UNIX */
  1178     if (f == NULL) {
  1179         PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO());
  1180         DLLErrorInternal(_MD_ERRNO());
  1182     return f;
  1185 /*
  1186 ** Called by class loader to resolve missing native's
  1187 */
  1188 PR_IMPLEMENT(void*) 
  1189 PR_FindSymbol(PRLibrary *lib, const char *raw_name)
  1191     void *f = NULL;
  1192 #if defined(NEED_LEADING_UNDERSCORE)
  1193     char *name;
  1194 #else
  1195     const char *name;
  1196 #endif
  1197     /*
  1198     ** Mangle the raw symbol name in any way that is platform specific.
  1199     */
  1200 #if defined(NEED_LEADING_UNDERSCORE)
  1201     /* Need a leading _ */
  1202     name = PR_smprintf("_%s", raw_name);
  1203 #elif defined(AIX)
  1204     /*
  1205     ** AIX with the normal linker put's a "." in front of the symbol
  1206     ** name.  When use "svcc" and "svld" then the "." disappears. Go
  1207     ** figure.
  1208     */
  1209     name = raw_name;
  1210 #else
  1211     name = raw_name;
  1212 #endif
  1214     PR_EnterMonitor(pr_linker_lock);
  1215     PR_ASSERT(lib != NULL);
  1216     f = pr_FindSymbolInLib(lib, name);
  1218 #if defined(NEED_LEADING_UNDERSCORE)
  1219     PR_smprintf_free(name);
  1220 #endif
  1222     PR_ExitMonitor(pr_linker_lock);
  1223     return f;
  1226 /*
  1227 ** Return the address of the function 'raw_name' in the library 'lib'
  1228 */
  1229 PR_IMPLEMENT(PRFuncPtr) 
  1230 PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name)
  1232     return ((PRFuncPtr) PR_FindSymbol(lib, raw_name));
  1235 PR_IMPLEMENT(void*) 
  1236 PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
  1238     void *f = NULL;
  1239 #if defined(NEED_LEADING_UNDERSCORE)
  1240     char *name;
  1241 #else
  1242     const char *name;
  1243 #endif
  1244     PRLibrary* lm;
  1246     if (!_pr_initialized) _PR_ImplicitInitialization();
  1247     /*
  1248     ** Mangle the raw symbol name in any way that is platform specific.
  1249     */
  1250 #if defined(NEED_LEADING_UNDERSCORE)
  1251     /* Need a leading _ */
  1252     name = PR_smprintf("_%s", raw_name);
  1253 #elif defined(AIX)
  1254     /*
  1255     ** AIX with the normal linker put's a "." in front of the symbol
  1256     ** name.  When use "svcc" and "svld" then the "." disappears. Go
  1257     ** figure.
  1258     */
  1259     name = raw_name;
  1260 #else
  1261     name = raw_name;
  1262 #endif
  1264     PR_EnterMonitor(pr_linker_lock);
  1266     /* search all libraries */
  1267     for (lm = pr_loadmap; lm != NULL; lm = lm->next) {
  1268         f = pr_FindSymbolInLib(lm, name);
  1269         if (f != NULL) {
  1270             *lib = lm;
  1271             lm->refCount++;
  1272             PR_LOG(_pr_linker_lm, PR_LOG_MIN,
  1273                        ("%s incr => %d (for %s)",
  1274                     lm->name, lm->refCount, name));
  1275             break;
  1278 #if defined(NEED_LEADING_UNDERSCORE)
  1279     PR_smprintf_free(name);
  1280 #endif
  1282     PR_ExitMonitor(pr_linker_lock);
  1283     return f;
  1286 PR_IMPLEMENT(PRFuncPtr) 
  1287 PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
  1289     return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib));
  1292 /*
  1293 ** Add a static library to the list of loaded libraries. If LoadLibrary
  1294 ** is called with the name then we will pretend it was already loaded
  1295 */
  1296 PR_IMPLEMENT(PRLibrary*) 
  1297 PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt)
  1299     PRLibrary *lm=NULL;
  1300     PRLibrary* result = NULL;
  1302     if (!_pr_initialized) _PR_ImplicitInitialization();
  1304     /* See if library is already loaded */
  1305     PR_EnterMonitor(pr_linker_lock);
  1307     /* If the lbrary is already loaded, then add the static table information... */
  1308     result = pr_UnlockedFindLibrary(name);
  1309     if (result != NULL) {
  1310         PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) );
  1311         result->staticTable = slt;
  1312         goto unlock;
  1315     /* Add library to list...Mark it static */
  1316     lm = PR_NEWZAP(PRLibrary);
  1317     if (lm == NULL) goto unlock;
  1319     lm->name = strdup(name);
  1320     lm->refCount    = 1;
  1321     lm->dlh         = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0;
  1322     lm->staticTable = slt;
  1323     lm->next        = pr_loadmap;
  1324     pr_loadmap      = lm;
  1326     result = lm;    /* success */
  1327     PR_ASSERT(lm->refCount == 1);
  1328     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name));
  1329   unlock:
  1330     PR_ExitMonitor(pr_linker_lock);
  1331     return result;
  1334 PR_IMPLEMENT(char *)
  1335 PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr)
  1337 #if defined(USE_DLFCN) && defined(HAVE_DLADDR)
  1338     Dl_info dli;
  1339     char *result;
  1341     if (dladdr((void *)addr, &dli) == 0) {
  1342         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
  1343         DLLErrorInternal(_MD_ERRNO());
  1344         return NULL;
  1346     result = PR_Malloc(strlen(dli.dli_fname)+1);
  1347     if (result != NULL) {
  1348         strcpy(result, dli.dli_fname);
  1350     return result;
  1351 #elif defined(USE_MACH_DYLD)
  1352     char *result;
  1353     const char *image_name;
  1354     int i, count = _dyld_image_count();
  1356     for (i = 0; i < count; i++) {
  1357         image_name = _dyld_get_image_name(i);
  1358         if (strstr(image_name, name) != NULL) {
  1359             result = PR_Malloc(strlen(image_name)+1);
  1360             if (result != NULL) {
  1361                 strcpy(result, image_name);
  1363             return result;
  1366     PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
  1367     return NULL;
  1368 #elif defined(AIX)
  1369     char *result;
  1370 #define LD_INFO_INCREMENT 64
  1371     struct ld_info *info;
  1372     unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info);
  1373     struct ld_info *infop;
  1374     int loadflags = L_GETINFO | L_IGNOREUNLOAD;
  1376     for (;;) {
  1377         info = PR_Malloc(info_length);
  1378         if (info == NULL) {
  1379             return NULL;
  1381         /* If buffer is too small, loadquery fails with ENOMEM. */
  1382         if (loadquery(loadflags, info, info_length) != -1) {
  1383             break;
  1385         /*
  1386          * Calling loadquery when compiled for 64-bit with the
  1387          * L_IGNOREUNLOAD flag can cause an invalid argument error
  1388          * on AIX 5.1. Detect this error the first time that
  1389          * loadquery is called, and try calling it again without
  1390          * this flag set.
  1391          */
  1392         if (errno == EINVAL && (loadflags & L_IGNOREUNLOAD)) {
  1393             loadflags &= ~L_IGNOREUNLOAD;
  1394             if (loadquery(loadflags, info, info_length) != -1) {
  1395                 break;
  1398         PR_Free(info);
  1399         if (errno != ENOMEM) {
  1400             /* should not happen */
  1401             _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
  1402             return NULL;
  1404         /* retry with a larger buffer */
  1405         info_length += LD_INFO_INCREMENT * sizeof(struct ld_info);
  1408     for (infop = info;
  1410          infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) {
  1411         unsigned long start = (unsigned long)infop->ldinfo_dataorg;
  1412         unsigned long end = start + infop->ldinfo_datasize;
  1413         if (start <= (unsigned long)addr && end > (unsigned long)addr) {
  1414             result = PR_Malloc(strlen(infop->ldinfo_filename)+1);
  1415             if (result != NULL) {
  1416                 strcpy(result, infop->ldinfo_filename);
  1418             break;
  1420         if (!infop->ldinfo_next) {
  1421             PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
  1422             result = NULL;
  1423             break;
  1426     PR_Free(info);
  1427     return result;
  1428 #elif defined(OSF1)
  1429     /* Contributed by Steve Streeter of HP */
  1430     ldr_process_t process, ldr_my_process();
  1431     ldr_module_t mod_id;
  1432     ldr_module_info_t info;
  1433     ldr_region_t regno;
  1434     ldr_region_info_t reginfo;
  1435     size_t retsize;
  1436     int rv;
  1437     char *result;
  1439     /* Get process for which dynamic modules will be listed */
  1441     process = ldr_my_process();
  1443     /* Attach to process */
  1445     rv = ldr_xattach(process);
  1446     if (rv) {
  1447         /* should not happen */
  1448         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
  1449         return NULL;
  1452     /* Print information for list of modules */
  1454     mod_id = LDR_NULL_MODULE;
  1456     for (;;) {
  1458         /* Get information for the next module in the module list. */
  1460         ldr_next_module(process, &mod_id);
  1461         if (ldr_inq_module(process, mod_id, &info, sizeof(info),
  1462                            &retsize) != 0) {
  1463             /* No more modules */
  1464             break;
  1466         if (retsize < sizeof(info)) {
  1467             continue;
  1470         /*
  1471          * Get information for each region in the module and check if any
  1472          * contain the address of this function.
  1473          */
  1475         for (regno = 0; ; regno++) {
  1476             if (ldr_inq_region(process, mod_id, regno, &reginfo,
  1477                                sizeof(reginfo), &retsize) != 0) {
  1478                 /* No more regions */
  1479                 break;
  1481             if (((unsigned long)reginfo.lri_mapaddr <=
  1482                 (unsigned long)addr) &&
  1483                 (((unsigned long)reginfo.lri_mapaddr + reginfo.lri_size) >
  1484                 (unsigned long)addr)) {
  1485                 /* Found it. */
  1486                 result = PR_Malloc(strlen(info.lmi_name)+1);
  1487                 if (result != NULL) {
  1488                     strcpy(result, info.lmi_name);
  1490                 return result;
  1494     PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
  1495     return NULL;
  1496 #elif defined(HPUX) && defined(USE_HPSHL)
  1497     int index;
  1498     struct shl_descriptor desc;
  1499     char *result;
  1501     for (index = 0; shl_get_r(index, &desc) == 0; index++) {
  1502         if (strstr(desc.filename, name) != NULL) {
  1503             result = PR_Malloc(strlen(desc.filename)+1);
  1504             if (result != NULL) {
  1505                 strcpy(result, desc.filename);
  1507             return result;
  1510     /*
  1511      * Since the index value of a library is decremented if
  1512      * a library preceding it in the shared library search
  1513      * list was unloaded, it is possible that we missed some
  1514      * libraries as we went up the list.  So we should go
  1515      * down the list to be sure that we not miss anything.
  1516      */
  1517     for (index--; index >= 0; index--) {
  1518         if ((shl_get_r(index, &desc) == 0)
  1519                 && (strstr(desc.filename, name) != NULL)) {
  1520             result = PR_Malloc(strlen(desc.filename)+1);
  1521             if (result != NULL) {
  1522                 strcpy(result, desc.filename);
  1524             return result;
  1527     PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
  1528     return NULL;
  1529 #elif defined(HPUX) && defined(USE_DLFCN)
  1530     struct load_module_desc desc;
  1531     char *result;
  1532     const char *module_name;
  1534     if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) {
  1535         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
  1536         DLLErrorInternal(_MD_ERRNO());
  1537         return NULL;
  1539     module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0);
  1540     if (module_name == NULL) {
  1541         /* should not happen */
  1542         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
  1543         DLLErrorInternal(_MD_ERRNO());
  1544         return NULL;
  1546     result = PR_Malloc(strlen(module_name)+1);
  1547     if (result != NULL) {
  1548         strcpy(result, module_name);
  1550     return result;
  1551 #elif defined(WIN32)
  1552     PRUnichar wname[MAX_PATH];
  1553     HMODULE handle = NULL;
  1554     PRUnichar module_name[MAX_PATH];
  1555     int len;
  1556     char *result;
  1558     if (MultiByteToWideChar(CP_ACP, 0, name, -1, wname, MAX_PATH)) {
  1559         handle = GetModuleHandleW(wname);
  1561     if (handle == NULL) {
  1562         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
  1563         DLLErrorInternal(_MD_ERRNO());
  1564         return NULL;
  1566     if (GetModuleFileNameW(handle, module_name, MAX_PATH) == 0) {
  1567         /* should not happen */
  1568         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
  1569         return NULL;
  1571     len = WideCharToMultiByte(CP_ACP, 0, module_name, -1,
  1572                               NULL, 0, NULL, NULL);
  1573     if (len == 0) {
  1574         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
  1575         return NULL;
  1577     result = PR_Malloc(len * sizeof(PRUnichar));
  1578     if (result != NULL) {
  1579         WideCharToMultiByte(CP_ACP, 0, module_name, -1,
  1580                             result, len, NULL, NULL);
  1582     return result;
  1583 #elif defined(XP_OS2)
  1584     HMODULE module = NULL;
  1585     char module_name[_MAX_PATH];
  1586     char *result;
  1587     APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr);
  1588     if ((NO_ERROR != ulrc) || (NULL == module) ) {
  1589         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
  1590         DLLErrorInternal(_MD_ERRNO());
  1591         return NULL;
  1593     ulrc = DosQueryModuleName(module, sizeof module_name, module_name);
  1594     if (NO_ERROR != ulrc) {
  1595         /* should not happen */
  1596         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
  1597         return NULL;
  1599     result = PR_Malloc(strlen(module_name)+1);
  1600     if (result != NULL) {
  1601         strcpy(result, module_name);
  1603     return result;
  1604 #else
  1605     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1606     return NULL;
  1607 #endif

mercurial