Back to index

lightning-sunbird  0.9+nobinonly
prlink.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Steve Streeter (Hewlett-Packard Company)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "primpl.h"
00040 
00041 #include <string.h>
00042 
00043 #ifdef XP_BEOS
00044 #include <image.h>
00045 #endif
00046 
00047 #ifdef XP_MACOSX
00048 #include <CodeFragments.h>
00049 #include <TextUtils.h>
00050 #include <Types.h>
00051 #include <Aliases.h>
00052 #include <CFURL.h>
00053 #include <CFBundle.h>
00054 #include <CFString.h>
00055 #include <CFDictionary.h>
00056 #include <CFData.h>
00057 #endif
00058 
00059 #ifdef XP_UNIX
00060 #ifdef USE_DLFCN
00061 #include <dlfcn.h>
00062 /* Define these on systems that don't have them. */
00063 #ifndef RTLD_NOW
00064 #define RTLD_NOW 0
00065 #endif
00066 #ifndef RTLD_LAZY
00067 #define RTLD_LAZY RTLD_NOW
00068 #endif
00069 #ifndef RTLD_GLOBAL
00070 #define RTLD_GLOBAL 0
00071 #endif
00072 #ifndef RTLD_LOCAL
00073 #define RTLD_LOCAL 0
00074 #endif
00075 #ifdef AIX
00076 #include <sys/ldr.h>
00077 #endif
00078 #ifdef OSF1
00079 #include <loader.h>
00080 #include <rld_interface.h>
00081 #endif
00082 #elif defined(USE_HPSHL)
00083 #include <dl.h>
00084 #elif defined(USE_MACH_DYLD)
00085 #include <mach-o/dyld.h>
00086 #endif
00087 #endif /* XP_UNIX */
00088 
00089 #define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY
00090 
00091 #ifdef VMS
00092 /* These are all require for the PR_GetLibraryFilePathname implementation */
00093 #include <descrip.h>
00094 #include <dvidef.h>
00095 #include <fibdef.h>
00096 #include <iodef.h>
00097 #include <lib$routines.h>
00098 #include <ssdef.h>
00099 #include <starlet.h>
00100 #include <stsdef.h>
00101 #include <unixlib.h>
00102 
00103 #pragma __nostandard 
00104 #pragma __member_alignment __save
00105 #pragma __nomember_alignment
00106 #ifdef __INITIAL_POINTER_SIZE
00107 #pragma __required_pointer_size __save 
00108 #pragma __required_pointer_size __short
00109 #endif
00110  
00111 typedef struct _imcb {
00112     struct _imcb *imcb$l_flink;         
00113     struct _imcb *imcb$l_blink;         
00114     unsigned short int imcb$w_size;     
00115     unsigned char imcb$b_type;          
00116     char imcb$b_resv_1;                 
00117     unsigned char imcb$b_access_mode;   
00118     unsigned char imcb$b_act_code;      
00119     unsigned short int imcb$w_chan;     
00120     unsigned int imcb$l_flags;            
00121     char imcb$t_image_name [40];        
00122     unsigned int imcb$l_symvec_size; 
00123     unsigned __int64 imcb$q_ident;
00124     void *imcb$l_starting_address;
00125     void *imcb$l_end_address;
00126 } IMCB;
00127  
00128 #pragma __member_alignment __restore
00129 #ifdef __INITIAL_POINTER_SIZE 
00130 #pragma __required_pointer_size __restore
00131 #endif
00132 #pragma __standard
00133  
00134 typedef struct {
00135     short   buflen;
00136     short   itmcode;
00137     void    *buffer;
00138     void    *retlen;
00139 } ITMLST;
00140 
00141 typedef struct {
00142     short cond;
00143     short count;
00144     int   rest;
00145 } IOSB;
00146 
00147 typedef unsigned long int ulong_t;
00148 
00149 struct _imcb *IAC$GL_IMAGE_LIST = NULL;
00150 
00151 #define MAX_DEVNAM 64
00152 #define MAX_FILNAM 255
00153 #endif  /* VMS */
00154 
00155 /*
00156  * On these platforms, symbols have a leading '_'.
00157  */
00158 #if defined(SUNOS4) || defined(DARWIN) || defined(NEXTSTEP) \
00159     || defined(WIN16) || defined(XP_OS2) \
00160     || ((defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__))
00161 #define NEED_LEADING_UNDERSCORE
00162 #endif
00163 
00164 #define PR_LD_PATHW 0x8000  /* for PR_LibSpec_PathnameU */
00165 
00166 /************************************************************************/
00167 
00168 struct PRLibrary {
00169     char*                       name;  /* Our own copy of the name string */
00170     PRLibrary*                  next;
00171     int                         refCount;
00172     const PRStaticLinkTable*    staticTable;
00173 
00174 #ifdef XP_PC
00175 #ifdef XP_OS2
00176     HMODULE                     dlh;
00177 #else
00178     HINSTANCE                   dlh;
00179 #endif
00180 #endif
00181 
00182 #ifdef XP_MACOSX
00183     CFragConnectionID           connection;
00184     CFBundleRef                 bundle;
00185     Ptr                         main;
00186     CFMutableDictionaryRef      wrappers;
00187     const struct mach_header*   image;
00188 #endif
00189 
00190 #ifdef XP_UNIX
00191 #if defined(USE_HPSHL)
00192     shl_t                       dlh;
00193 #elif defined(USE_MACH_DYLD)
00194     NSModule                    dlh;
00195 #else
00196     void*                       dlh;
00197 #endif 
00198 #endif 
00199 
00200 #ifdef XP_BEOS
00201     void*                       dlh;
00202     void*                       stub_dlh;
00203 #endif
00204 };
00205 
00206 static PRLibrary *pr_loadmap;
00207 static PRLibrary *pr_exe_loadmap;
00208 static PRMonitor *pr_linker_lock;
00209 static char* _pr_currentLibPath = NULL;
00210 
00211 static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags);
00212 
00213 #ifdef WIN95
00214 typedef HMODULE (WINAPI *LoadLibraryWFn)(LPCWSTR);
00215 static HMODULE WINAPI EmulateLoadLibraryW(LPCWSTR);
00216 static LoadLibraryWFn loadLibraryW = LoadLibraryW;
00217 #endif
00218 
00219 #ifdef WIN32
00220 static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len);
00221 #endif
00222 
00223 /************************************************************************/
00224 
00225 #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR)
00226 static char* errStrBuf = NULL;
00227 #define ERR_STR_BUF_LENGTH    20
00228 static char* errno_string(PRIntn oserr)
00229 {
00230     if (errStrBuf == NULL)
00231         errStrBuf = PR_MALLOC(ERR_STR_BUF_LENGTH);
00232     PR_snprintf(errStrBuf, ERR_STR_BUF_LENGTH, "error %d", oserr);
00233     return errStrBuf;
00234 }
00235 #endif
00236 
00237 static void DLLErrorInternal(PRIntn oserr)
00238 /*
00239 ** This whole function, and most of the code in this file, are run
00240 ** with a big hairy lock wrapped around it. Not the best of situations,
00241 ** but will eventually come up with the right answer.
00242 */
00243 {
00244     const char *error = NULL;
00245 #ifdef USE_DLFCN
00246     error = dlerror();  /* $$$ That'll be wrong some of the time - AOF */
00247 #elif defined(HAVE_STRERROR)
00248     error = strerror(oserr);  /* this should be okay */
00249 #else
00250     error = errno_string(oserr);
00251 #endif
00252     if (NULL != error)
00253         PR_SetErrorText(strlen(error), error);
00254 }  /* DLLErrorInternal */
00255 
00256 void _PR_InitLinker(void)
00257 {
00258     PRLibrary *lm = NULL;
00259 #if defined(XP_UNIX)
00260     void *h;
00261 #endif
00262 
00263 #ifdef WIN95
00264     if (!_pr_useUnicode) {
00265         loadLibraryW = EmulateLoadLibraryW;
00266     }
00267 #endif
00268 
00269     if (!pr_linker_lock) {
00270         pr_linker_lock = PR_NewNamedMonitor("linker-lock");
00271     }
00272     PR_EnterMonitor(pr_linker_lock);
00273 
00274 #if defined(XP_PC)
00275     lm = PR_NEWZAP(PRLibrary);
00276     lm->name = strdup("Executable");
00277         /* 
00278         ** In WIN32, GetProcAddress(...) expects a module handle in order to
00279         ** get exported symbols from the executable...
00280         **
00281         ** However, in WIN16 this is accomplished by passing NULL to 
00282         ** GetProcAddress(...)
00283         */
00284 #if defined(_WIN32)
00285         lm->dlh = GetModuleHandle(NULL);
00286 #else
00287         lm->dlh = (HINSTANCE)NULL;
00288 #endif /* ! _WIN32 */
00289 
00290     lm->refCount    = 1;
00291     lm->staticTable = NULL;
00292     pr_exe_loadmap  = lm;
00293     pr_loadmap      = lm;
00294 
00295 #elif defined(XP_UNIX)
00296 #ifdef HAVE_DLL
00297 #ifdef USE_DLFCN
00298     h = dlopen(0, RTLD_LAZY);
00299     if (!h) {
00300         char *error;
00301         
00302         DLLErrorInternal(_MD_ERRNO());
00303         error = (char*)PR_MALLOC(PR_GetErrorTextLength());
00304         (void) PR_GetErrorText(error);
00305         fprintf(stderr, "failed to initialize shared libraries [%s]\n",
00306             error);
00307         PR_DELETE(error);
00308         abort();/* XXX */
00309     }
00310 #elif defined(USE_HPSHL)
00311     h = NULL;
00312     /* don't abort with this NULL */
00313 #elif defined(USE_MACH_DYLD)
00314     h = NULL; /* XXXX  toshok */
00315 #else
00316 #error no dll strategy
00317 #endif /* USE_DLFCN */
00318 
00319     lm = PR_NEWZAP(PRLibrary);
00320     if (lm) {
00321         lm->name = strdup("a.out");
00322         lm->refCount = 1;
00323         lm->dlh = h;
00324         lm->staticTable = NULL;
00325     }
00326     pr_exe_loadmap = lm;
00327     pr_loadmap = lm;
00328 #endif /* HAVE_DLL */
00329 #endif /* XP_UNIX */
00330 
00331     if (lm) {
00332         PR_LOG(_pr_linker_lm, PR_LOG_MIN,
00333             ("Loaded library %s (init)", lm->name));
00334     }
00335 
00336     PR_ExitMonitor(pr_linker_lock);
00337 }
00338 
00339 #if defined(WIN16)
00340 /*
00341  * _PR_ShutdownLinker unloads all dlls loaded by the application via
00342  * calls to PR_LoadLibrary
00343  */
00344 void _PR_ShutdownLinker(void)
00345 {
00346     PR_EnterMonitor(pr_linker_lock);
00347 
00348     while (pr_loadmap) {
00349     if (pr_loadmap->refCount > 1) {
00350 #ifdef DEBUG
00351         fprintf(stderr, "# Forcing library to unload: %s (%d outstanding references)\n",
00352             pr_loadmap->name, pr_loadmap->refCount);
00353 #endif
00354         pr_loadmap->refCount = 1;
00355     }
00356     PR_UnloadLibrary(pr_loadmap);
00357     }
00358     
00359     PR_ExitMonitor(pr_linker_lock);
00360 
00361     PR_DestroyMonitor(pr_linker_lock);
00362     pr_linker_lock = NULL;
00363 }
00364 #else
00365 /*
00366  * _PR_ShutdownLinker was originally only used on WIN16 (see above),
00367  * but I think it should also be used on other platforms.  However,
00368  * I disagree with the original implementation's unloading the dlls
00369  * for the application.  Any dlls that still remain on the pr_loadmap
00370  * list when NSPR shuts down are application programming errors.  The
00371  * only exception is pr_exe_loadmap, which was added to the list by
00372  * NSPR and hence should be cleaned up by NSPR.
00373  */
00374 void _PR_ShutdownLinker(void)
00375 {
00376     /* FIXME: pr_exe_loadmap should be destroyed. */
00377     
00378     PR_DestroyMonitor(pr_linker_lock);
00379     pr_linker_lock = NULL;
00380 
00381     if (_pr_currentLibPath) {
00382         free(_pr_currentLibPath);
00383         _pr_currentLibPath = NULL;
00384     }
00385 
00386 #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR)
00387     PR_DELETE(errStrBuf);
00388 #endif
00389 }
00390 #endif
00391 
00392 /******************************************************************************/
00393 
00394 PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path)
00395 {
00396     PRStatus rv = PR_SUCCESS;
00397 
00398     if (!_pr_initialized) _PR_ImplicitInitialization();
00399     PR_EnterMonitor(pr_linker_lock);
00400     if (_pr_currentLibPath) {
00401         free(_pr_currentLibPath);
00402     }
00403     if (path) {
00404         _pr_currentLibPath = strdup(path);
00405         if (!_pr_currentLibPath) {
00406             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00407         rv = PR_FAILURE;
00408         }
00409     } else {
00410         _pr_currentLibPath = 0;
00411     }
00412     PR_ExitMonitor(pr_linker_lock);
00413     return rv;
00414 }
00415 
00416 /*
00417 ** Return the library path for finding shared libraries.
00418 */
00419 PR_IMPLEMENT(char *) 
00420 PR_GetLibraryPath(void)
00421 {
00422     char *ev;
00423     char *copy = NULL;  /* a copy of _pr_currentLibPath */
00424 
00425     if (!_pr_initialized) _PR_ImplicitInitialization();
00426     PR_EnterMonitor(pr_linker_lock);
00427     if (_pr_currentLibPath != NULL) {
00428         goto exit;
00429     }
00430 
00431     /* initialize pr_currentLibPath */
00432 
00433 #ifdef XP_PC
00434     ev = getenv("LD_LIBRARY_PATH");
00435     if (!ev) {
00436     ev = ".;\\lib";
00437     }
00438     ev = strdup(ev);
00439 #endif
00440 
00441 #if defined(XP_UNIX) || defined(XP_BEOS)
00442 #if defined(USE_DLFCN) || defined(USE_MACH_DYLD) || defined(XP_BEOS)
00443     {
00444     char *p=NULL;
00445     int len;
00446 
00447 #ifdef XP_BEOS
00448     ev = getenv("LIBRARY_PATH");
00449     if (!ev) {
00450         ev = "%A/lib:/boot/home/config/lib:/boot/beos/system/lib";
00451     }
00452 #else
00453     ev = getenv("LD_LIBRARY_PATH");
00454     if (!ev) {
00455         ev = "/usr/lib:/lib";
00456     }
00457 #endif
00458     len = strlen(ev) + 1;        /* +1 for the null */
00459 
00460     p = (char*) malloc(len);
00461     if (p) {
00462         strcpy(p, ev);
00463     }   /* if (p)  */
00464     ev = p;
00465     PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev));
00466 
00467     }
00468 #else
00469     /* AFAIK there isn't a library path with the HP SHL interface --Rob */
00470     ev = strdup("");
00471 #endif
00472 #endif
00473 
00474     /*
00475      * If ev is NULL, we have run out of memory
00476      */
00477     _pr_currentLibPath = ev;
00478 
00479   exit:
00480     if (_pr_currentLibPath) {
00481         copy = strdup(_pr_currentLibPath);
00482     }
00483     PR_ExitMonitor(pr_linker_lock);
00484     if (!copy) {
00485         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00486     }
00487     return copy;
00488 }
00489 
00490 /*
00491 ** Build library name from path, lib and extensions
00492 */
00493 PR_IMPLEMENT(char*) 
00494 PR_GetLibraryName(const char *path, const char *lib)
00495 {
00496     char *fullname;
00497 
00498 #ifdef XP_PC
00499     if (strstr(lib, PR_DLL_SUFFIX) == NULL)
00500     {
00501         if (path) {
00502             fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX);
00503         } else {
00504             fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX);
00505         }
00506     } else {
00507         if (path) {
00508             fullname = PR_smprintf("%s\\%s", path, lib);
00509         } else {
00510             fullname = PR_smprintf("%s", lib);
00511         }
00512     }
00513 #endif /* XP_PC */
00514 #if defined(XP_UNIX) || defined(XP_BEOS)
00515     if (strstr(lib, PR_DLL_SUFFIX) == NULL)
00516     {
00517         if (path) {
00518             fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX);
00519         } else {
00520             fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX);
00521         }
00522     } else {
00523         if (path) {
00524             fullname = PR_smprintf("%s/%s", path, lib);
00525         } else {
00526             fullname = PR_smprintf("%s", lib);
00527         }
00528     }
00529 #endif /* XP_UNIX || XP_BEOS */
00530     return fullname;
00531 }
00532 
00533 /*
00534 ** Free the memory allocated, for the caller, by PR_GetLibraryName
00535 */
00536 PR_IMPLEMENT(void) 
00537 PR_FreeLibraryName(char *mem)
00538 {
00539     PR_smprintf_free(mem);
00540 }
00541 
00542 static PRLibrary* 
00543 pr_UnlockedFindLibrary(const char *name)
00544 {
00545     PRLibrary* lm = pr_loadmap;
00546     const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR);
00547     np = np ? np + 1 : name;
00548     while (lm) {
00549     const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR);
00550     cp = cp ? cp + 1 : lm->name;
00551 #ifdef WIN32
00552         /* Windows DLL names are case insensitive... */
00553     if (strcmpi(np, cp) == 0) 
00554 #elif defined(XP_OS2)
00555     if (stricmp(np, cp) == 0)
00556 #else
00557     if (strcmp(np, cp)  == 0) 
00558 #endif
00559     {
00560         /* found */
00561         lm->refCount++;
00562         PR_LOG(_pr_linker_lm, PR_LOG_MIN,
00563            ("%s incr => %d (find lib)",
00564             lm->name, lm->refCount));
00565         return lm;
00566     }
00567     lm = lm->next;
00568     }
00569     return NULL;
00570 }
00571 
00572 PR_IMPLEMENT(PRLibrary*)
00573 PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags)
00574 {
00575     if (flags == 0) {
00576         flags = _PR_DEFAULT_LD_FLAGS;
00577     }
00578     switch (libSpec.type) {
00579         case PR_LibSpec_Pathname:
00580             return pr_LoadLibraryByPathname(libSpec.value.pathname, flags);
00581 #ifdef WIN32
00582         case PR_LibSpec_PathnameU:
00583             /*
00584              * cast to |char *| and set PR_LD_PATHW flag so that
00585              * it can be cast back to PRUnichar* in the callee.
00586              */
00587             return pr_LoadLibraryByPathname((const char*) 
00588                                             libSpec.value.pathname_u, 
00589                                             flags | PR_LD_PATHW);
00590 #endif
00591         default:
00592             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00593             return NULL;
00594     }
00595 }
00596             
00597 PR_IMPLEMENT(PRLibrary*) 
00598 PR_LoadLibrary(const char *name)
00599 {
00600     PRLibSpec libSpec;
00601 
00602     libSpec.type = PR_LibSpec_Pathname;
00603     libSpec.value.pathname = name;
00604     return PR_LoadLibraryWithFlags(libSpec, 0);
00605 }
00606 
00607 #if defined(USE_MACH_DYLD)
00608 static NSModule
00609 pr_LoadMachDyldModule(const char *name)
00610 {
00611     NSObjectFileImage ofi;
00612     NSModule h = NULL;
00613     if (NSCreateObjectFileImageFromFile(name, &ofi)
00614             == NSObjectFileImageSuccess) {
00615         h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE
00616                          | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
00617         /*
00618          * TODO: If NSLinkModule fails, use NSLinkEditError to retrieve
00619          * error information.
00620          */
00621         if (NSDestroyObjectFileImage(ofi) == FALSE) {
00622             if (h) {
00623                 (void)NSUnLinkModule(h, NSUNLINKMODULE_OPTION_NONE);
00624                 h = NULL;
00625             }
00626         }
00627     }
00628     return h;
00629 }
00630 #endif
00631 
00632 #ifdef XP_MACOSX
00633 
00634 static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp)
00635 {
00636     static uint32 glue[6] = { 0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420 };
00637     uint32* newGlue = NULL;
00638 
00639     if (tvp != NULL) {
00640         CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII);
00641         if (nameRef) {
00642             CFMutableDataRef glueData = (CFMutableDataRef) CFDictionaryGetValue(dict, nameRef);
00643             if (glueData == NULL) {
00644                 glueData = CFDataCreateMutable(NULL, sizeof(glue));
00645                 if (glueData != NULL) {
00646                     newGlue = (uint32*) CFDataGetMutableBytePtr(glueData);
00647                     memcpy(newGlue, glue, sizeof(glue));
00648                     newGlue[0] |= ((UInt32)tvp >> 16);
00649                     newGlue[1] |= ((UInt32)tvp & 0xFFFF);
00650                     MakeDataExecutable(newGlue, sizeof(glue));
00651                     CFDictionaryAddValue(dict, nameRef, glueData);
00652                     CFRelease(glueData);
00653 
00654                     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: created wrapper for CFM function %s().", name));
00655                 }
00656             } else {
00657                 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: found wrapper for CFM function %s().", name));
00658 
00659                 newGlue = (uint32*) CFDataGetMutableBytePtr(glueData);
00660             }
00661             CFRelease(nameRef);
00662         }
00663     }
00664     
00665     return newGlue;
00666 }
00667 
00668 /*
00669 ** macLibraryLoadProc is a function definition for a Mac shared library
00670 ** loading method. The "name" param is the same full or partial pathname
00671 ** that was passed to pr_LoadLibraryByPathName. The function must fill
00672 ** in the fields of "lm" which apply to its library type. Returns
00673 ** PR_SUCCESS if successful.
00674 */
00675 
00676 typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm);
00677 
00678 static PRStatus
00679 pr_LoadViaCFM(const char *name, PRLibrary *lm)
00680 {
00681     OSErr err;
00682     Str255 errName;
00683     FSRef ref;
00684     FSSpec fileSpec;
00685     Boolean tempUnusedBool;
00686 
00687     /*
00688      * Make an FSSpec from the path name and call GetDiskFragment.
00689      */
00690 
00691     /* Use direct conversion of POSIX path to FSRef to FSSpec. */
00692     err = FSPathMakeRef((const UInt8*)name, &ref, NULL);
00693     if (err != noErr)
00694         return PR_FAILURE;
00695     err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL,
00696                            &fileSpec, NULL);
00697     if (err != noErr)
00698         return PR_FAILURE;
00699 
00700     /* Resolve an alias if this was one */
00701     err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool,
00702                            &tempUnusedBool);
00703     if (err != noErr)
00704         return PR_FAILURE;
00705 
00706     /* Finally, try to load the library */
00707     err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name,
00708                           kLoadCFrag, &lm->connection, &lm->main, errName);
00709 
00710     if (err == noErr && lm->connection) {
00711         /*
00712          * if we're a mach-o binary, need to wrap all CFM function
00713          * pointers. need a hash-table of already seen function
00714          * pointers, etc.
00715          */
00716         lm->wrappers = CFDictionaryCreateMutable(NULL, 16,
00717                        &kCFTypeDictionaryKeyCallBacks,
00718                        &kCFTypeDictionaryValueCallBacks);
00719         if (lm->wrappers) {
00720             lm->main = TV2FP(lm->wrappers, "main", lm->main);
00721         } else
00722             err = memFullErr;
00723     }
00724     return (err == noErr) ? PR_SUCCESS : PR_FAILURE;
00725 }
00726 
00727 /*
00728 ** Creates a CFBundleRef if the pathname refers to a Mac OS X bundle
00729 ** directory. The caller is responsible for calling CFRelease() to
00730 ** deallocate.
00731 */
00732 
00733 static PRStatus
00734 pr_LoadCFBundle(const char *name, PRLibrary *lm)
00735 {
00736     CFURLRef bundleURL;
00737     CFBundleRef bundle = NULL;
00738     char pathBuf[PATH_MAX];
00739     const char *resolvedPath;
00740     CFStringRef pathRef;
00741 
00742     /* Takes care of relative paths and symlinks */
00743     resolvedPath = realpath(name, pathBuf);
00744     if (!resolvedPath)
00745         return PR_FAILURE;
00746         
00747     pathRef = CFStringCreateWithCString(NULL, pathBuf, kCFStringEncodingUTF8);
00748     if (pathRef) {
00749         bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef,
00750                                                   kCFURLPOSIXPathStyle, true);
00751         if (bundleURL) {
00752             bundle = CFBundleCreate(NULL, bundleURL);
00753             CFRelease(bundleURL);
00754         }
00755         CFRelease(pathRef);
00756     }
00757 
00758     lm->bundle = bundle;
00759     return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE;
00760 }
00761 
00762 static PRStatus
00763 pr_LoadViaDyld(const char *name, PRLibrary *lm)
00764 {
00765     lm->dlh = pr_LoadMachDyldModule(name);
00766     if (lm->dlh == NULL) {
00767         lm->image = NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR
00768                                | NSADDIMAGE_OPTION_WITH_SEARCHING);
00769         /*
00770          * TODO: If NSAddImage fails, use NSLinkEditError to retrieve
00771          * error information.
00772          */
00773     }
00774     return (lm->dlh != NULL || lm->image != NULL) ? PR_SUCCESS : PR_FAILURE;
00775 }
00776 
00777 #endif /* XP_MACOSX */
00778 
00779 #ifdef WIN95
00780 static HMODULE WINAPI
00781 EmulateLoadLibraryW(LPCWSTR lpLibFileName)
00782 {
00783     HMODULE h;
00784     char nameA[MAX_PATH];
00785 
00786     if (!WideCharToMultiByte(CP_ACP, 0, lpLibFileName, -1,
00787                              nameA, sizeof nameA, NULL, NULL)) {
00788         return NULL;
00789     }
00790     /* Perhaps it's better to add a check for characters 
00791      * not representable in CP_ACP.
00792      */
00793     h = LoadLibraryA(nameA);
00794     return h;
00795 }
00796 #endif /* WIN95 */
00797 
00798 /*
00799 ** Dynamically load a library. Only load libraries once, so scan the load
00800 ** map first.
00801 */
00802 static PRLibrary*
00803 pr_LoadLibraryByPathname(const char *name, PRIntn flags)
00804 {
00805     PRLibrary *lm;
00806     PRLibrary* result = NULL;
00807     PRInt32 oserr;
00808 #ifdef WIN32
00809     char utf8name_stack[MAX_PATH];
00810     char *utf8name_malloc = NULL;
00811     char *utf8name = utf8name_stack;
00812     PRUnichar wname_stack[MAX_PATH];
00813     PRUnichar *wname_malloc = NULL;
00814     PRUnichar *wname = wname_stack;
00815     int len;
00816 #endif
00817 
00818     if (!_pr_initialized) _PR_ImplicitInitialization();
00819 
00820     /* See if library is already loaded */
00821     PR_EnterMonitor(pr_linker_lock);
00822 
00823 #ifdef WIN32
00824     if (flags & PR_LD_PATHW) {
00825         /* cast back what's cast to |char *| for the argument passing. */
00826         wname = (LPWSTR) name;
00827     } else {
00828         int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
00829         if (wlen > MAX_PATH)
00830             wname = wname_malloc = PR_Malloc(wlen * sizeof(PRUnichar));
00831         if (wname == NULL ||
00832             !MultiByteToWideChar(CP_ACP, 0,  name, -1, wname, wlen)) {
00833             oserr = _MD_ERRNO();
00834             goto unlock;
00835         }
00836     }
00837     len = pr_ConvertUTF16toUTF8(wname, NULL, 0);
00838     if (len > MAX_PATH)
00839         utf8name = utf8name_malloc = PR_Malloc(len);
00840     if (utf8name == NULL ||
00841         !pr_ConvertUTF16toUTF8(wname, utf8name, len)) {
00842         oserr = _MD_ERRNO();
00843         goto unlock;
00844     }
00845     /* the list of loaded library names are always kept in UTF-8 
00846      * on Win32 platforms */
00847     result = pr_UnlockedFindLibrary(utf8name);
00848 #else
00849     result = pr_UnlockedFindLibrary(name);
00850 #endif
00851 
00852     if (result != NULL) goto unlock;
00853 
00854     lm = PR_NEWZAP(PRLibrary);
00855     if (lm == NULL) {
00856         oserr = _MD_ERRNO();
00857         goto unlock;
00858     }
00859     lm->staticTable = NULL;
00860 
00861 #ifdef XP_OS2  /* Why isn't all this stuff in MD code?! */
00862     {
00863         HMODULE h;
00864         UCHAR pszError[_MAX_PATH];
00865         ULONG ulRc = NO_ERROR;
00866 
00867           ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h);
00868           if (ulRc != NO_ERROR) {
00869               oserr = ulRc;
00870               PR_DELETE(lm);
00871               goto unlock;
00872           }
00873           lm->name = strdup(name);
00874           lm->dlh  = h;
00875           lm->next = pr_loadmap;
00876           pr_loadmap = lm;
00877     }
00878 #endif /* XP_OS2 */
00879 
00880 #if defined(WIN32) || defined(WIN16)
00881     {
00882     HINSTANCE h;
00883 
00884 #ifdef WIN32
00885 #ifdef WIN95
00886     if (flags & PR_LD_PATHW)
00887         h = loadLibraryW(wname);
00888     else
00889         h = LoadLibraryA(name);
00890 #else
00891     if (flags & PR_LD_PATHW)
00892         h = LoadLibraryW(wname);
00893     else
00894         h = LoadLibraryA(name);
00895 #endif /* WIN95 */
00896 #else 
00897     h = LoadLibrary(name);
00898 #endif
00899     if (h < (HINSTANCE)HINSTANCE_ERROR) {
00900         oserr = _MD_ERRNO();
00901         PR_DELETE(lm);
00902         goto unlock;
00903     }
00904 #ifdef WIN32
00905     lm->name = strdup(utf8name);
00906 #else
00907     lm->name = strdup(name);
00908 #endif
00909     lm->dlh = h;
00910     lm->next = pr_loadmap;
00911     pr_loadmap = lm;
00912     }
00913 #endif /* WIN32 || WIN16 */
00914 
00915 #ifdef XP_MACOSX
00916     {
00917     int     i;
00918     PRStatus status;
00919 
00920     static const macLibraryLoadProc loadProcs[] = {
00921         pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM
00922     };
00923 
00924     for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) {
00925         if ((status = loadProcs[i](name, lm)) == PR_SUCCESS)
00926             break;
00927     }
00928     if (status != PR_SUCCESS) {
00929         oserr = cfragNoLibraryErr;
00930         PR_DELETE(lm);
00931         goto unlock;        
00932     }
00933     lm->name = strdup(name);
00934     lm->next = pr_loadmap;
00935     pr_loadmap = lm;
00936     }
00937 #endif
00938 
00939 #if defined(XP_UNIX) && !defined(XP_MACOSX)
00940 #ifdef HAVE_DLL
00941     {
00942 #if defined(USE_DLFCN)
00943 #ifdef NTO
00944     /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */
00945     int dl_flags = RTLD_GROUP;
00946 #elif defined(AIX)
00947     /* AIX needs RTLD_MEMBER to load an archive member.  (bug 228899) */
00948     int dl_flags = RTLD_MEMBER;
00949 #else
00950     int dl_flags = 0;
00951 #endif
00952     void *h;
00953 
00954     if (flags & PR_LD_LAZY) {
00955         dl_flags |= RTLD_LAZY;
00956     }
00957     if (flags & PR_LD_NOW) {
00958         dl_flags |= RTLD_NOW;
00959     }
00960     if (flags & PR_LD_GLOBAL) {
00961         dl_flags |= RTLD_GLOBAL;
00962     }
00963     if (flags & PR_LD_LOCAL) {
00964         dl_flags |= RTLD_LOCAL;
00965     }
00966     h = dlopen(name, dl_flags);
00967 #elif defined(USE_HPSHL)
00968     int shl_flags = 0;
00969     shl_t h;
00970 
00971     /*
00972      * Use the DYNAMIC_PATH flag only if 'name' is a plain file
00973      * name (containing no directory) to match the behavior of
00974      * dlopen().
00975      */
00976     if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) {
00977         shl_flags |= DYNAMIC_PATH;
00978     }
00979     if (flags & PR_LD_LAZY) {
00980         shl_flags |= BIND_DEFERRED;
00981     }
00982     if (flags & PR_LD_NOW) {
00983         shl_flags |= BIND_IMMEDIATE;
00984     }
00985     /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */
00986     h = shl_load(name, shl_flags, 0L);
00987 #elif defined(USE_MACH_DYLD)
00988     NSModule h = pr_LoadMachDyldModule(name);
00989 #else
00990 #error Configuration error
00991 #endif
00992     if (!h) {
00993         oserr = _MD_ERRNO();
00994         PR_DELETE(lm);
00995         goto unlock;
00996     }
00997     lm->name = strdup(name);
00998     lm->dlh = h;
00999     lm->next = pr_loadmap;
01000     pr_loadmap = lm;
01001     }
01002 #endif /* HAVE_DLL */
01003 #endif /* XP_UNIX */
01004 
01005     lm->refCount = 1;
01006 
01007 #ifdef XP_BEOS
01008     {
01009         image_info info;
01010         int32 cookie = 0;
01011         image_id imageid = B_ERROR;
01012         image_id stubid = B_ERROR;
01013         PRLibrary *p;
01014 
01015         for (p = pr_loadmap; p != NULL; p = p->next) {
01016             /* hopefully, our caller will always use the same string
01017                to refer to the same library */
01018             if (strcmp(name, p->name) == 0) {
01019                 /* we've already loaded this library */
01020                 imageid = info.id;
01021                 lm->refCount++;
01022                 break;
01023             }
01024         }
01025 
01026         if(imageid == B_ERROR) {
01027             /* it appears the library isn't yet loaded - load it now */
01028             char stubName [B_PATH_NAME_LENGTH + 1];
01029 
01030             /* the following is a work-around to a "bug" in the beos -
01031                the beos system loader allows only 32M (system-wide)
01032                to be used by code loaded as "add-ons" (code loaded
01033                through the 'load_add_on()' system call, which includes
01034                mozilla components), but allows 256M to be used by
01035                shared libraries.
01036                
01037                unfortunately, mozilla is too large to fit into the
01038                "add-on" space, so we must trick the loader into
01039                loading some of the components as shared libraries.  this
01040                is accomplished by creating a "stub" add-on (an empty
01041                shared object), and linking it with the component
01042                (the actual .so file generated by the build process,
01043                without any modifications).  when this stub is loaded
01044                by load_add_on(), the loader will automatically load the
01045                component into the shared library space.
01046             */
01047 
01048             strcpy(stubName, name);
01049             strcat(stubName, ".stub");
01050 
01051             /* first, attempt to load the stub (thereby loading the
01052                component as a shared library */
01053             if ((stubid = load_add_on(stubName)) > B_ERROR) {
01054                 /* the stub was loaded successfully. */
01055                 imageid = B_FILE_NOT_FOUND;
01056 
01057                 cookie = 0;
01058                 while (get_next_image_info(0, &cookie, &info) == B_OK) {
01059                     const char *endOfSystemName = strrchr(info.name, '/');
01060                     const char *endOfPassedName = strrchr(name, '/');
01061                     if( 0 == endOfSystemName ) 
01062                         endOfSystemName = info.name;
01063                     else
01064                         endOfSystemName++;
01065                     if( 0 == endOfPassedName )
01066                         endOfPassedName = name;
01067                     else
01068                         endOfPassedName++;
01069                     if (strcmp(endOfSystemName, endOfPassedName) == 0) {
01070                         /* this is the actual component - remember it */
01071                         imageid = info.id;
01072                         break;
01073                     }
01074                 }
01075 
01076             } else {
01077                 /* we failed to load the "stub" - try to load the
01078                    component directly as an add-on */
01079                 stubid = B_ERROR;
01080                 imageid = load_add_on(name);
01081             }
01082         }
01083 
01084         if (imageid <= B_ERROR) {
01085             oserr = imageid;
01086             PR_DELETE( lm );
01087             goto unlock;
01088         }
01089         lm->name = strdup(name);
01090         lm->dlh = (void*)imageid;
01091         lm->stub_dlh = (void*)stubid;
01092         lm->next = pr_loadmap;
01093         pr_loadmap = lm;
01094     }
01095 #endif
01096 
01097     result = lm;    /* success */
01098     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name));
01099 
01100   unlock:
01101     if (result == NULL) {
01102         PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr);
01103         DLLErrorInternal(oserr);  /* sets error text */
01104     }
01105 #ifdef WIN32
01106     if (utf8name_malloc) 
01107         PR_Free(utf8name_malloc);
01108     if (wname_malloc)
01109         PR_Free(wname_malloc);
01110 #endif
01111     PR_ExitMonitor(pr_linker_lock);
01112     return result;
01113 }
01114 
01115 #ifdef WIN32
01116 #ifdef WIN95
01117 /*
01118  * CP_UTF8 is not supported by WideCharToMultiByte on Windows 95 so that 
01119  * we have to emulate it
01120  */
01121 static PRStatus 
01122 pr_ConvertSingleCharToUTF8(PRUint32 usv, PRUint16 offset, int bufLen,
01123                            int *utf8Len, char * *buf)
01124 {
01125     char* p = *buf;
01126     PR_ASSERT(!bufLen || *buf);
01127     if (!bufLen) {
01128         *utf8Len += offset;
01129         return PR_SUCCESS;
01130     }
01131 
01132     if (*utf8Len + offset >= bufLen)
01133         return PR_FAILURE;
01134 
01135     *utf8Len += offset;
01136     if (offset == 1) {
01137         *p++ = (char) usv;
01138     } else if (offset == 2) {
01139         *p++ = (char)0xc0 | (usv >> 6);
01140         *p++ = (char)0x80 | (usv & 0x003f);
01141     } else if (offset == 3) {
01142         *p++ = (char)0xe0 | (usv >> 12);
01143         *p++ = (char)0x80 | ((usv >> 6) & 0x003f);
01144         *p++ = (char)0x80 | (usv & 0x003f);
01145     } else { /* offset = 4 */
01146         *p++ = (char)0xf0 | (usv >> 18);
01147         *p++ = (char)0x80 | ((usv >> 12) & 0x003f);
01148         *p++ = (char)0x80 | ((usv >> 6) & 0x003f);
01149         *p++ = (char)0x80 | (usv & 0x003f);
01150     }
01151 
01152     *buf = p;
01153     return PR_SUCCESS;
01154 }
01155 
01156 static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len)
01157 {
01158     LPCWSTR pw = wname;
01159     LPSTR p = name;
01160     int utf8Len = 0;
01161     PRBool highSurrogate = PR_FALSE;
01162 
01163     utf8Len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len, 
01164                                   NULL, NULL);
01165     /*
01166      * Windows 95 and NT 3.51 don't support CP_UTF8.
01167      * WideCharToMultiByte(CP_UTF8, ...) fails with the error code
01168      * ERROR_INVALID_PARAMETER on Windows 95 and NT 3.51.
01169      */
01170     if (utf8Len || GetLastError() != ERROR_INVALID_PARAMETER)
01171         return utf8Len;
01172 
01173     if (!wname || len < 0 || (len > 0 && !name)) {
01174         SetLastError(ERROR_INVALID_PARAMETER);
01175         return 0;
01176     }
01177 
01178     while (*pw) {
01179         PRStatus status = PR_SUCCESS;
01180         if (highSurrogate) {
01181             if (*pw >= (PRUnichar) 0xDC00 && *pw < (PRUnichar) 0xE000) {
01182                 /* found a matching low surrogate */
01183                 /* convert a surrogate pair to UCS4 */
01184                 PRUint32 usv = ((*(pw-1) - (PRUnichar)0xD800) << 10) + 
01185                                (*pw - (PRUnichar)0xDC00) + (PRUint32)0x10000;
01186                 if (pr_ConvertSingleCharToUTF8(usv, 4, len, &utf8Len, &p) ==
01187                     PR_FAILURE)
01188                     return 0;
01189                 highSurrogate = PR_FALSE;
01190                 ++pw;
01191                 continue;
01192             } else {
01193                 /*
01194                  * silently ignore a lone high surrogate
01195                  * as is done by WideCharToMultiByte by default
01196                  */
01197                 highSurrogate = PR_FALSE;
01198             }
01199         }
01200         if (*pw <= 0x7f) 
01201             status = pr_ConvertSingleCharToUTF8(*pw, 1, len, &utf8Len, &p);
01202         else if (*pw <= 0x07ff)
01203             status = pr_ConvertSingleCharToUTF8(*pw, 2, len, &utf8Len, &p);
01204         else if (*pw < (PRUnichar) 0xD800 || *pw >= (PRUnichar) 0xE000)
01205             status = pr_ConvertSingleCharToUTF8(*pw, 3, len, &utf8Len, &p);
01206         else if (*pw < (PRUnichar) 0xDC00)
01207             highSurrogate = PR_TRUE;
01208         /* else */
01209         /* silently ignore a lone low surrogate as is done by 
01210          * WideCharToMultiByte by default */
01211 
01212         if (status == PR_FAILURE) {
01213             SetLastError(ERROR_INSUFFICIENT_BUFFER);
01214             return 0;
01215         }
01216         ++pw;
01217     }
01218 
01219     /* if we're concerned with a lone high surrogate,
01220      * we have to take care of it here, but we just drop it 
01221      */
01222     if (len > 0)
01223         *p = '\0';
01224     return utf8Len + 1;
01225 }
01226 #else
01227 static int pr_ConvertUTF16toUTF8(LPCWSTR wname, LPSTR name, int len)
01228 {
01229     return WideCharToMultiByte(CP_UTF8, 0, wname, -1, name, len, NULL, NULL);
01230 }
01231 #endif /* WIN95 */
01232 #endif /* WIN32 */
01233 
01234 /*
01235 ** Unload a shared library which was loaded via PR_LoadLibrary
01236 */
01237 PR_IMPLEMENT(PRStatus) 
01238 PR_UnloadLibrary(PRLibrary *lib)
01239 {
01240     int result = 0;
01241     PRStatus status = PR_SUCCESS;
01242 
01243     if ((lib == 0) || (lib->refCount <= 0)) {
01244         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01245         return PR_FAILURE;
01246     }
01247 
01248     PR_EnterMonitor(pr_linker_lock);
01249     if (--lib->refCount > 0) {
01250     PR_LOG(_pr_linker_lm, PR_LOG_MIN,
01251            ("%s decr => %d",
01252         lib->name, lib->refCount));
01253     goto done;
01254     }
01255 
01256 #ifdef XP_BEOS
01257     if(((image_id)lib->stub_dlh) == B_ERROR)
01258         unload_add_on( (image_id) lib->dlh );
01259     else
01260         unload_add_on( (image_id) lib->stub_dlh);
01261 #endif
01262 
01263 #ifdef XP_UNIX
01264 #ifdef HAVE_DLL
01265 #ifdef USE_DLFCN
01266     result = dlclose(lib->dlh);
01267 #elif defined(USE_HPSHL)
01268     result = shl_unload(lib->dlh);
01269 #elif defined(USE_MACH_DYLD)
01270     if (lib->dlh)
01271         result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1;
01272 #else
01273 #error Configuration error
01274 #endif
01275 #endif /* HAVE_DLL */
01276 #endif /* XP_UNIX */
01277 #ifdef XP_PC
01278     if (lib->dlh) {
01279         FreeLibrary((HINSTANCE)(lib->dlh));
01280         lib->dlh = (HINSTANCE)NULL;
01281     }
01282 #endif  /* XP_PC */
01283 
01284 #ifdef XP_MACOSX
01285     /* Close the connection */
01286     if (lib->connection)
01287         CloseConnection(&(lib->connection));
01288     if (lib->bundle)
01289         CFRelease(lib->bundle);
01290     if (lib->wrappers)
01291         CFRelease(lib->wrappers);
01292     /* No way to unload an image (lib->image) */
01293 #endif
01294 
01295     /* unlink from library search list */
01296     if (pr_loadmap == lib)
01297         pr_loadmap = pr_loadmap->next;
01298     else if (pr_loadmap != NULL) {
01299         PRLibrary* prev = pr_loadmap;
01300         PRLibrary* next = pr_loadmap->next;
01301         while (next != NULL) {
01302             if (next == lib) {
01303                 prev->next = next->next;
01304                 goto freeLib;
01305             }
01306             prev = next;
01307             next = next->next;
01308         }
01309         /*
01310          * fail (the library is not on the _pr_loadmap list),
01311          * but don't wipe out an error from dlclose/shl_unload.
01312          */
01313         PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent");
01314         if (result == 0) {
01315             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01316             status = PR_FAILURE;
01317         }
01318     }
01319     /*
01320      * We free the PRLibrary structure whether dlclose/shl_unload
01321      * succeeds or not.
01322      */
01323 
01324   freeLib:
01325     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name));
01326     free(lib->name);
01327     lib->name = NULL;
01328     PR_DELETE(lib);
01329     if (result != 0) {
01330         PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO());
01331         DLLErrorInternal(_MD_ERRNO());
01332         status = PR_FAILURE;
01333     }
01334 
01335 done:
01336     PR_ExitMonitor(pr_linker_lock);
01337     return status;
01338 }
01339 
01340 static void* 
01341 pr_FindSymbolInLib(PRLibrary *lm, const char *name)
01342 {
01343     void *f = NULL;
01344 #ifdef XP_OS2
01345     int rc;
01346 #endif
01347 
01348     if (lm->staticTable != NULL) {
01349         const PRStaticLinkTable* tp;
01350         for (tp = lm->staticTable; tp->name; tp++) {
01351             if (strcmp(name, tp->name) == 0) {
01352                 return (void*) tp->fp;
01353             }
01354         }
01355         /* 
01356         ** If the symbol was not found in the static table then check if
01357         ** the symbol was exported in the DLL... Win16 only!!
01358         */
01359 #if !defined(WIN16) && !defined(XP_BEOS)
01360         PR_SetError(PR_FIND_SYMBOL_ERROR, 0);
01361         return (void*)NULL;
01362 #endif
01363     }
01364     
01365 #ifdef XP_OS2
01366     rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
01367 #if defined(NEED_LEADING_UNDERSCORE)
01368     /*
01369      * Older plugins (not built using GCC) will have symbols that are not
01370      * underscore prefixed.  We check for that here.
01371      */
01372     if (rc != NO_ERROR) {
01373         name++;
01374         DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
01375     }
01376 #endif
01377 #endif  /* XP_OS2 */
01378 
01379 #if defined(WIN32) || defined(WIN16)
01380     f = GetProcAddress(lm->dlh, name);
01381 #endif  /* WIN32 || WIN16 */
01382 
01383 #ifdef XP_MACOSX
01384 /* add this offset to skip the leading underscore in name */
01385 #define SYM_OFFSET 1
01386     if (lm->bundle) {
01387         CFStringRef nameRef = CFStringCreateWithCString(NULL, name + SYM_OFFSET, kCFStringEncodingASCII);
01388         if (nameRef) {
01389             f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef);
01390             CFRelease(nameRef);
01391         }
01392     }
01393     if (lm->connection) {
01394         Ptr                 symAddr;
01395         CFragSymbolClass    symClass;
01396         Str255              pName;
01397         
01398         PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET));
01399         
01400         c2pstrcpy(pName, name + SYM_OFFSET);
01401         
01402         f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL;
01403         
01404         /* callers expect mach-o function pointers, so must wrap tvectors with glue. */
01405         if (f && symClass == kTVectorCFragSymbol) {
01406             f = TV2FP(lm->wrappers, name + SYM_OFFSET, f);
01407         }
01408         
01409         if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main;
01410     }
01411     if (lm->image) {
01412         NSSymbol symbol;
01413         symbol = NSLookupSymbolInImage(lm->image, name,
01414                  NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
01415                  | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
01416         if (symbol != NULL)
01417             f = NSAddressOfSymbol(symbol);
01418         else
01419             f = NULL;
01420     }
01421 #undef SYM_OFFSET
01422 #endif /* XP_MACOSX */
01423 
01424 #ifdef XP_BEOS
01425     if( B_NO_ERROR != get_image_symbol( (image_id)lm->dlh, name, B_SYMBOL_TYPE_TEXT, &f ) ) {
01426         f = NULL;
01427     }
01428 #endif
01429 
01430 #ifdef XP_UNIX
01431 #ifdef HAVE_DLL
01432 #ifdef USE_DLFCN
01433     f = dlsym(lm->dlh, name);
01434 #elif defined(USE_HPSHL)
01435     if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) {
01436         f = NULL;
01437     }
01438 #elif defined(USE_MACH_DYLD)
01439     if (lm->dlh) {
01440         NSSymbol symbol;
01441         symbol = NSLookupSymbolInModule(lm->dlh, name);
01442         if (symbol != NULL)
01443             f = NSAddressOfSymbol(symbol);
01444         else
01445             f = NULL;
01446     }
01447 #endif
01448 #endif /* HAVE_DLL */
01449 #endif /* XP_UNIX */
01450     if (f == NULL) {
01451         PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO());
01452         DLLErrorInternal(_MD_ERRNO());
01453     }
01454     return f;
01455 }
01456 
01457 /*
01458 ** Called by class loader to resolve missing native's
01459 */
01460 PR_IMPLEMENT(void*) 
01461 PR_FindSymbol(PRLibrary *lib, const char *raw_name)
01462 {
01463     void *f = NULL;
01464 #if defined(NEED_LEADING_UNDERSCORE)
01465     char *name;
01466 #else
01467     const char *name;
01468 #endif
01469     /*
01470     ** Mangle the raw symbol name in any way that is platform specific.
01471     */
01472 #if defined(NEED_LEADING_UNDERSCORE)
01473     /* Need a leading _ */
01474     name = PR_smprintf("_%s", raw_name);
01475 #elif defined(AIX)
01476     /*
01477     ** AIX with the normal linker put's a "." in front of the symbol
01478     ** name.  When use "svcc" and "svld" then the "." disappears. Go
01479     ** figure.
01480     */
01481     name = raw_name;
01482 #else
01483     name = raw_name;
01484 #endif
01485 
01486     PR_EnterMonitor(pr_linker_lock);
01487     PR_ASSERT(lib != NULL);
01488     f = pr_FindSymbolInLib(lib, name);
01489 
01490 #if defined(NEED_LEADING_UNDERSCORE)
01491     PR_smprintf_free(name);
01492 #endif
01493 
01494     PR_ExitMonitor(pr_linker_lock);
01495     return f;
01496 }
01497 
01498 /*
01499 ** Return the address of the function 'raw_name' in the library 'lib'
01500 */
01501 PR_IMPLEMENT(PRFuncPtr) 
01502 PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name)
01503 {
01504     return ((PRFuncPtr) PR_FindSymbol(lib, raw_name));
01505 }
01506 
01507 PR_IMPLEMENT(void*) 
01508 PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
01509 {
01510     void *f = NULL;
01511 #if defined(NEED_LEADING_UNDERSCORE)
01512     char *name;
01513 #else
01514     const char *name;
01515 #endif
01516     PRLibrary* lm;
01517 
01518     if (!_pr_initialized) _PR_ImplicitInitialization();
01519     /*
01520     ** Mangle the raw symbol name in any way that is platform specific.
01521     */
01522 #if defined(NEED_LEADING_UNDERSCORE)
01523     /* Need a leading _ */
01524     name = PR_smprintf("_%s", raw_name);
01525 #elif defined(AIX)
01526     /*
01527     ** AIX with the normal linker put's a "." in front of the symbol
01528     ** name.  When use "svcc" and "svld" then the "." disappears. Go
01529     ** figure.
01530     */
01531     name = raw_name;
01532 #else
01533     name = raw_name;
01534 #endif
01535 
01536     PR_EnterMonitor(pr_linker_lock);
01537 
01538     /* search all libraries */
01539     for (lm = pr_loadmap; lm != NULL; lm = lm->next) {
01540         f = pr_FindSymbolInLib(lm, name);
01541         if (f != NULL) {
01542             *lib = lm;
01543             lm->refCount++;
01544             PR_LOG(_pr_linker_lm, PR_LOG_MIN,
01545                        ("%s incr => %d (for %s)",
01546                     lm->name, lm->refCount, name));
01547             break;
01548         }
01549     }
01550 #if defined(NEED_LEADING_UNDERSCORE)
01551     PR_smprintf_free(name);
01552 #endif
01553 
01554     PR_ExitMonitor(pr_linker_lock);
01555     return f;
01556 }
01557 
01558 PR_IMPLEMENT(PRFuncPtr) 
01559 PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
01560 {
01561     return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib));
01562 }
01563 
01564 /*
01565 ** Add a static library to the list of loaded libraries. If LoadLibrary
01566 ** is called with the name then we will pretend it was already loaded
01567 */
01568 PR_IMPLEMENT(PRLibrary*) 
01569 PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt)
01570 {
01571     PRLibrary *lm=NULL;
01572     PRLibrary* result = NULL;
01573 
01574     if (!_pr_initialized) _PR_ImplicitInitialization();
01575 
01576     /* See if library is already loaded */
01577     PR_EnterMonitor(pr_linker_lock);
01578 
01579     /* If the lbrary is already loaded, then add the static table information... */
01580     result = pr_UnlockedFindLibrary(name);
01581     if (result != NULL) {
01582         PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) );
01583         result->staticTable = slt;
01584         goto unlock;
01585     }
01586 
01587     /* Add library to list...Mark it static */
01588     lm = PR_NEWZAP(PRLibrary);
01589     if (lm == NULL) goto unlock;
01590 
01591     lm->name = strdup(name);
01592     lm->refCount    = 1;
01593     lm->dlh         = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0;
01594     lm->staticTable = slt;
01595     lm->next        = pr_loadmap;
01596     pr_loadmap      = lm;
01597 
01598     result = lm;    /* success */
01599     PR_ASSERT(lm->refCount == 1);
01600   unlock:
01601     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name));
01602     PR_ExitMonitor(pr_linker_lock);
01603     return result;
01604 }
01605 
01606 PR_IMPLEMENT(char *)
01607 PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr)
01608 {
01609 #if defined(SOLARIS) || defined(LINUX) || defined(FREEBSD)
01610     Dl_info dli;
01611     char *result;
01612 
01613     if (dladdr((void *)addr, &dli) == 0) {
01614         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
01615         DLLErrorInternal(_MD_ERRNO());
01616         return NULL;
01617     }
01618     result = PR_Malloc(strlen(dli.dli_fname)+1);
01619     if (result != NULL) {
01620         strcpy(result, dli.dli_fname);
01621     }
01622     return result;
01623 #elif defined(USE_MACH_DYLD)
01624     char *result;
01625     char *image_name;
01626     int i, count = _dyld_image_count();
01627 
01628     for (i = 0; i < count; i++) {
01629         image_name = _dyld_get_image_name(i);
01630         if (strstr(image_name, name) != NULL) {
01631             result = PR_Malloc(strlen(image_name)+1);
01632             if (result != NULL) {
01633                 strcpy(result, image_name);
01634             }
01635             return result;
01636         }
01637     }
01638     PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
01639     return NULL;
01640 #elif defined(AIX)
01641     char *result;
01642 #define LD_INFO_INCREMENT 64
01643     struct ld_info *info;
01644     unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info);
01645     struct ld_info *infop;
01646     int loadflags = L_GETINFO | L_IGNOREUNLOAD;
01647 
01648     for (;;) {
01649         info = PR_Malloc(info_length);
01650         if (info == NULL) {
01651             return NULL;
01652         }
01653         /* If buffer is too small, loadquery fails with ENOMEM. */
01654         if (loadquery(loadflags, info, info_length) != -1) {
01655             break;
01656         }
01657         /*
01658          * Calling loadquery when compiled for 64-bit with the
01659          * L_IGNOREUNLOAD flag can cause an invalid argument error
01660          * on AIX 5.1. Detect this error the first time that
01661          * loadquery is called, and try calling it again without
01662          * this flag set.
01663          */
01664         if (errno == EINVAL && (loadflags & L_IGNOREUNLOAD)) {
01665             loadflags &= ~L_IGNOREUNLOAD;
01666             if (loadquery(loadflags, info, info_length) != -1) {
01667                 break;
01668             }
01669         }
01670         PR_Free(info);
01671         if (errno != ENOMEM) {
01672             /* should not happen */
01673             _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
01674             return NULL;
01675         }
01676         /* retry with a larger buffer */
01677         info_length += LD_INFO_INCREMENT * sizeof(struct ld_info);
01678     }
01679 
01680     for (infop = info;
01681          ;
01682          infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) {
01683         unsigned long start = (unsigned long)infop->ldinfo_dataorg;
01684         unsigned long end = start + infop->ldinfo_datasize;
01685         if (start <= (unsigned long)addr && end > (unsigned long)addr) {
01686             result = PR_Malloc(strlen(infop->ldinfo_filename)+1);
01687             if (result != NULL) {
01688                 strcpy(result, infop->ldinfo_filename);
01689             }
01690             break;
01691         }
01692         if (!infop->ldinfo_next) {
01693             PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
01694             result = NULL;
01695             break;
01696         }
01697     }
01698     PR_Free(info);
01699     return result;
01700 #elif defined(OSF1)
01701     /* Contributed by Steve Streeter of HP */
01702     ldr_process_t process, ldr_my_process();
01703     ldr_module_t mod_id;
01704     ldr_module_info_t info;
01705     ldr_region_t regno;
01706     ldr_region_info_t reginfo;
01707     size_t retsize;
01708     int rv;
01709     char *result;
01710 
01711     /* Get process for which dynamic modules will be listed */
01712 
01713     process = ldr_my_process();
01714 
01715     /* Attach to process */
01716 
01717     rv = ldr_xattach(process);
01718     if (rv) {
01719         /* should not happen */
01720         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
01721         return NULL;
01722     }
01723 
01724     /* Print information for list of modules */
01725 
01726     mod_id = LDR_NULL_MODULE;
01727 
01728     for (;;) {
01729 
01730         /* Get information for the next module in the module list. */
01731 
01732         ldr_next_module(process, &mod_id);
01733         if (ldr_inq_module(process, mod_id, &info, sizeof(info),
01734                            &retsize) != 0) {
01735             /* No more modules */
01736             break;
01737         }
01738         if (retsize < sizeof(info)) {
01739             continue;
01740         }
01741 
01742         /*
01743          * Get information for each region in the module and check if any
01744          * contain the address of this function.
01745          */
01746 
01747         for (regno = 0; ; regno++) {
01748             if (ldr_inq_region(process, mod_id, regno, &reginfo,
01749                                sizeof(reginfo), &retsize) != 0) {
01750                 /* No more regions */
01751                 break;
01752             }
01753             if (((unsigned long)reginfo.lri_mapaddr <=
01754                 (unsigned long)addr) &&
01755                 (((unsigned long)reginfo.lri_mapaddr + reginfo.lri_size) >
01756                 (unsigned long)addr)) {
01757                 /* Found it. */
01758                 result = PR_Malloc(strlen(info.lmi_name)+1);
01759                 if (result != NULL) {
01760                     strcpy(result, info.lmi_name);
01761                 }
01762                 return result;
01763             }
01764         }
01765     }
01766     PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
01767     return NULL;
01768 #elif defined(VMS)
01769     /* Contributed by Colin Blake of HP */
01770     struct _imcb     *icb;
01771     ulong_t          status;
01772     char                device_name[MAX_DEVNAM];
01773     int                 device_name_len;
01774     $DESCRIPTOR         (device_name_desc, device_name);
01775     struct fibdef    fib;
01776     struct dsc$descriptor_s fib_desc = 
01777        { sizeof(struct fibdef), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (char *)&fib } ;
01778     IOSB             iosb;
01779     ITMLST           devlst[2] = {
01780                      {MAX_DEVNAM, DVI$_ALLDEVNAM, device_name, &device_name_len},
01781                      {0,0,0,0}};
01782     short               file_name_len;
01783     char                file_name[MAX_FILNAM+1];
01784     char             *result = NULL;
01785     struct dsc$descriptor_s file_name_desc = 
01786        { MAX_FILNAM, DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) &file_name[0] } ;
01787 
01788     /*
01789     ** The address for the process image list could change in future versions
01790     ** of the operating system. 7FFD0688 is valid for V7.2 and V7.3 releases,
01791     ** so we use that for the default, but allow an environment variable
01792     ** (logical name) to override.
01793     */
01794     if (IAC$GL_IMAGE_LIST == NULL) {
01795         char *p = getenv("MOZILLA_IAC_GL_IMAGE_LIST");
01796         if (p)
01797             IAC$GL_IMAGE_LIST = (struct _imcb *) strtol(p,NULL,0);
01798         else
01799             IAC$GL_IMAGE_LIST = (struct _imcb *) 0x7FFD0688;
01800     }
01801 
01802     for (icb = IAC$GL_IMAGE_LIST->imcb$l_flink;
01803          icb != IAC$GL_IMAGE_LIST;
01804          icb = icb->imcb$l_flink) {
01805         if (((void *)addr >= icb->imcb$l_starting_address) && 
01806            ((void *)addr <= icb->imcb$l_end_address)) {
01807            /*
01808            ** This is the correct image.
01809            ** Get the device name.
01810            */
01811            status = sys$getdviw(0,icb->imcb$w_chan,0,&devlst,0,0,0,0);
01812            if ($VMS_STATUS_SUCCESS(status))
01813               device_name_desc.dsc$w_length = device_name_len;
01814 
01815            /*
01816            ** Get the FID.
01817            */
01818            memset(&fib,0,sizeof(struct fibdef));
01819            status = sys$qiow(0,icb->imcb$w_chan,IO$_ACCESS,&iosb,
01820                             0,0,&fib_desc,0,0,0,0,0);
01821 
01822            /*
01823            ** If we got the FID, now look up its name (if for some reason
01824            ** we didn't get the device name, this call will fail).
01825            */
01826            if (($VMS_STATUS_SUCCESS(status)) && ($VMS_STATUS_SUCCESS(iosb.cond))) {
01827               status = lib$fid_to_name (
01828                     &device_name_desc,
01829                     &fib.fib$w_fid,
01830                     &file_name_desc,
01831                     &file_name_len,
01832                     0, 0);
01833 
01834               /*
01835               ** If we succeeded then remove the version number and
01836               ** return a copy of the UNIX format version of the file name.
01837               */
01838               if ($VMS_STATUS_SUCCESS(status)) {
01839                   char *p, *result;
01840                   file_name[file_name_len] = 0;
01841                   p = strrchr(file_name,';');
01842                   if (p) *p = 0;
01843                   p = decc$translate_vms(&file_name[0]);
01844                   result = PR_Malloc(strlen(p)+1);
01845                   if (result != NULL) {
01846                      strcpy(result, p);
01847                   }
01848                   return result;
01849               }
01850             }
01851        }
01852     }
01853 
01854     /* Didn't find it */
01855     PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
01856     return NULL;
01857 
01858 #elif defined(HPUX) && defined(USE_HPSHL)
01859     int index;
01860     struct shl_descriptor desc;
01861     char *result;
01862 
01863     for (index = 0; shl_get_r(index, &desc) == 0; index++) {
01864         if (strstr(desc.filename, name) != NULL) {
01865             result = PR_Malloc(strlen(desc.filename)+1);
01866             if (result != NULL) {
01867                 strcpy(result, desc.filename);
01868             }
01869             return result;
01870         }
01871     }
01872     /*
01873      * Since the index value of a library is decremented if
01874      * a library preceding it in the shared library search
01875      * list was unloaded, it is possible that we missed some
01876      * libraries as we went up the list.  So we should go
01877      * down the list to be sure that we not miss anything.
01878      */
01879     for (index--; index >= 0; index--) {
01880         if ((shl_get_r(index, &desc) == 0)
01881                 && (strstr(desc.filename, name) != NULL)) {
01882             result = PR_Malloc(strlen(desc.filename)+1);
01883             if (result != NULL) {
01884                 strcpy(result, desc.filename);
01885             }
01886             return result;
01887         }
01888     }
01889     PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
01890     return NULL;
01891 #elif defined(HPUX) && defined(USE_DLFCN)
01892     struct load_module_desc desc;
01893     char *result;
01894     const char *module_name;
01895 
01896     if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) {
01897         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
01898         DLLErrorInternal(_MD_ERRNO());
01899         return NULL;
01900     }
01901     module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0);
01902     if (module_name == NULL) {
01903         /* should not happen */
01904         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
01905         DLLErrorInternal(_MD_ERRNO());
01906         return NULL;
01907     }
01908     result = PR_Malloc(strlen(module_name)+1);
01909     if (result != NULL) {
01910         strcpy(result, module_name);
01911     }
01912     return result;
01913 #elif defined(WIN32)
01914     HMODULE handle;
01915     char module_name[MAX_PATH];
01916     char *result;
01917 
01918     handle = GetModuleHandle(name);
01919     if (handle == NULL) {
01920         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
01921         DLLErrorInternal(_MD_ERRNO());
01922         return NULL;
01923     }
01924     if (GetModuleFileName(handle, module_name, sizeof module_name) == 0) {
01925         /* should not happen */
01926         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
01927         return NULL;
01928     }
01929     result = PR_Malloc(strlen(module_name)+1);
01930     if (result != NULL) {
01931         strcpy(result, module_name);
01932     }
01933     return result;
01934 #elif defined(XP_OS2)
01935     HMODULE module = NULL;
01936     char module_name[_MAX_PATH];
01937     char *result;
01938     APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr);
01939     if ((NO_ERROR != ulrc) || (NULL == module) ) {
01940         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
01941         DLLErrorInternal(_MD_ERRNO());
01942         return NULL;
01943     }
01944     ulrc = DosQueryModuleName(module, sizeof module_name, module_name);
01945     if (NO_ERROR != ulrc) {
01946         /* should not happen */
01947         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
01948         return NULL;
01949     }
01950     result = PR_Malloc(strlen(module_name)+1);
01951     if (result != NULL) {
01952         strcpy(result, module_name);
01953     }
01954     return result;
01955 #else
01956     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
01957     return NULL;
01958 #endif
01959 }