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/. */
5 
6 #include "primpl.h"
7 
8 #include <string.h>
9 
10 #ifdef XP_BEOS
11 #include <image.h>
12 #endif
13 
14 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
15 #include <Carbon/Carbon.h>
16 #include <CoreFoundation/CoreFoundation.h>
17 #endif
18 
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 */
51 
52 #define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY
53 
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
62 
63 #define PR_LD_PATHW 0x8000  /* for PR_LibSpec_PathnameU */
64 
65 /************************************************************************/
66 
67 struct PRLibrary {
68     char*                       name;  /* Our own copy of the name string */
69     PRLibrary*                  next;
70     int                         refCount;
71     const PRStaticLinkTable*    staticTable;
72 
73 #ifdef XP_PC
74 #ifdef XP_OS2
75     HMODULE                     dlh;
76 #else
77     HINSTANCE                   dlh;
78 #endif
79 #endif
80 
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
88 
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
98 
99 #ifdef XP_BEOS
100     void*                       dlh;
101     void*                       stub_dlh;
102 #endif
103 };
104 
105 static PRLibrary *pr_loadmap;
106 static PRLibrary *pr_exe_loadmap;
107 static PRMonitor *pr_linker_lock;
108 static char* _pr_currentLibPath = NULL;
109 
110 static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags);
111 
112 /************************************************************************/
113 
114 #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR)
115 #define ERR_STR_BUF_LENGTH    20
116 #endif
117 
DLLErrorInternal(PRIntn oserr)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 */
138 
_PR_InitLinker(void)139 void _PR_InitLinker(void)
140 {
141     PRLibrary *lm = NULL;
142 #if defined(XP_UNIX)
143     void *h;
144 #endif
145 
146     if (!pr_linker_lock) {
147         pr_linker_lock = PR_NewNamedMonitor("linker-lock");
148     }
149     PR_EnterMonitor(pr_linker_lock);
150 
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 */
160 
161     lm->refCount    = 1;
162     lm->staticTable = NULL;
163     pr_exe_loadmap  = lm;
164     pr_loadmap      = lm;
165 
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;
172 
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 */
189 
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 */
201 
202     if (lm) {
203         PR_LOG(_pr_linker_lm, PR_LOG_MIN,
204             ("Loaded library %s (init)", lm->name));
205     }
206 
207     PR_ExitMonitor(pr_linker_lock);
208 }
209 
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  */
_PR_ShutdownLinker(void)217 void _PR_ShutdownLinker(void)
218 {
219     /* FIXME: pr_exe_loadmap should be destroyed. */
220 
221     PR_DestroyMonitor(pr_linker_lock);
222     pr_linker_lock = NULL;
223 
224     if (_pr_currentLibPath) {
225         free(_pr_currentLibPath);
226         _pr_currentLibPath = NULL;
227     }
228 }
229 
230 /******************************************************************************/
231 
PR_SetLibraryPath(const char * path)232 PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path)
233 {
234     PRStatus rv = PR_SUCCESS;
235 
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 }
253 
254 /*
255 ** Return the library path for finding shared libraries.
256 */
257 PR_IMPLEMENT(char *)
PR_GetLibraryPath(void)258 PR_GetLibraryPath(void)
259 {
260     char *ev;
261     char *copy = NULL;  /* a copy of _pr_currentLibPath */
262 
263     if (!_pr_initialized) _PR_ImplicitInitialization();
264     PR_EnterMonitor(pr_linker_lock);
265     if (_pr_currentLibPath != NULL) {
266         goto exit;
267     }
268 
269     /* initialize pr_currentLibPath */
270 
271 #ifdef XP_PC
272     ev = getenv("LD_LIBRARY_PATH");
273     if (!ev) {
274     ev = ".;\\lib";
275     }
276     ev = strdup(ev);
277 #endif
278 
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;
284 
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 */
297 
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));
304 
305     }
306 #else
307     /* AFAIK there isn't a library path with the HP SHL interface --Rob */
308     ev = strdup("");
309 #endif
310 #endif
311 
312     /*
313      * If ev is NULL, we have run out of memory
314      */
315     _pr_currentLibPath = ev;
316 
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 }
327 
328 /*
329 ** Build library name from path, lib and extensions
330 */
331 PR_IMPLEMENT(char*)
PR_GetLibraryName(const char * path,const char * lib)332 PR_GetLibraryName(const char *path, const char *lib)
333 {
334     char *fullname;
335 
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 }
370 
371 /*
372 ** Free the memory allocated, for the caller, by PR_GetLibraryName
373 */
374 PR_IMPLEMENT(void)
PR_FreeLibraryName(char * mem)375 PR_FreeLibraryName(char *mem)
376 {
377     PR_smprintf_free(mem);
378 }
379 
380 static PRLibrary*
pr_UnlockedFindLibrary(const char * name)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 }
409 
410 PR_IMPLEMENT(PRLibrary*)
PR_LoadLibraryWithFlags(PRLibSpec libSpec,PRIntn flags)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 }
434 
435 PR_IMPLEMENT(PRLibrary*)
PR_LoadLibrary(const char * name)436 PR_LoadLibrary(const char *name)
437 {
438     PRLibSpec libSpec;
439 
440     libSpec.type = PR_LibSpec_Pathname;
441     libSpec.value.pathname = name;
442     return PR_LoadLibraryWithFlags(libSpec, 0);
443 }
444 
445 #if defined(USE_MACH_DYLD)
446 static NSModule
pr_LoadMachDyldModule(const char * name)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
475 
476 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
477 
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 */
485 
486 typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm);
487 
488 #ifdef __ppc__
489 
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 */
494 
TV2FP(CFMutableDictionaryRef dict,const char * name,void * tvp)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;
499 
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);
514 
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));
519 
520                 newGlue = (uint32*) CFDataGetMutableBytePtr(glueData);
521             }
522             CFRelease(nameRef);
523         }
524     }
525 
526     return newGlue;
527 }
528 
529 static PRStatus
pr_LoadViaCFM(const char * name,PRLibrary * lm)530 pr_LoadViaCFM(const char *name, PRLibrary *lm)
531 {
532     OSErr err;
533     Str255 errName;
534     FSRef ref;
535     FSSpec fileSpec;
536     Boolean tempUnusedBool;
537 
538     /*
539      * Make an FSSpec from the path name and call GetDiskFragment.
540      */
541 
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;
550 
551     /* Resolve an alias if this was one */
552     err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool,
553                            &tempUnusedBool);
554     if (err != noErr)
555         return PR_FAILURE;
556 
557     /* Finally, try to load the library */
558     err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name,
559                           kLoadCFrag, &lm->connection, &lm->main, errName);
560 
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__ */
578 
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 */
584 
585 static PRStatus
pr_LoadCFBundle(const char * name,PRLibrary * lm)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;
593 
594     /* Takes care of relative paths and symlinks */
595     resolvedPath = realpath(name, pathBuf);
596     if (!resolvedPath)
597         return PR_FAILURE;
598 
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     }
609 
610     lm->bundle = bundle;
611     return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE;
612 }
613 
614 static PRStatus
pr_LoadViaDyld(const char * name,PRLibrary * lm)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 }
634 
635 #endif /* XP_MACOSX && USE_MACH_DYLD */
636 
637 /*
638 ** Dynamically load a library. Only load libraries once, so scan the load
639 ** map first.
640 */
641 static PRLibrary*
pr_LoadLibraryByPathname(const char * name,PRIntn flags)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
656 
657     if (!_pr_initialized) _PR_ImplicitInitialization();
658 
659     /* See if library is already loaded */
660     PR_EnterMonitor(pr_linker_lock);
661 
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
691 
692     if (result != NULL) goto unlock;
693 
694     lm = PR_NEWZAP(PRLibrary);
695     if (lm == NULL) {
696         oserr = _MD_ERRNO();
697         goto unlock;
698     }
699     lm->staticTable = NULL;
700 
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;
706 
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 */
719 
720 #ifdef WIN32
721     {
722     HINSTANCE h;
723 
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 */
738 
739 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD)
740     {
741     int     i;
742     PRStatus status;
743 
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     };
751 
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
766 
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;
781 
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;
808 
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) */
842 
843     lm->refCount = 1;
844 
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;
852 
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         }
863 
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];
867 
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.
874 
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             */
885 
886             strcpy(stubName, name);
887             strcat(stubName, ".stub");
888 
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;
894 
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                 }
913 
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         }
921 
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
934 
935     result = lm;    /* success */
936     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name));
937 
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 }
952 
953 /*
954 ** Unload a shared library which was loaded via PR_LoadLibrary
955 */
956 PR_IMPLEMENT(PRStatus)
PR_UnloadLibrary(PRLibrary * lib)957 PR_UnloadLibrary(PRLibrary *lib)
958 {
959     int result = 0;
960     PRStatus status = PR_SUCCESS;
961 
962     if (lib == 0) {
963         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
964         return PR_FAILURE;
965     }
966 
967     PR_EnterMonitor(pr_linker_lock);
968 
969     if (lib->refCount <= 0) {
970         PR_ExitMonitor(pr_linker_lock);
971         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
972         return PR_FAILURE;
973     }
974 
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     }
981 
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
988 
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;
1007     }
1008 #endif  /* XP_PC */
1009 
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
1020 
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;
1031             }
1032             prev = next;
1033             next = next->next;
1034         }
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_NOT_REACHED("_pr_loadmap and lib->refCount inconsistent");
1040         if (result == 0) {
1041             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1042             status = PR_FAILURE;
1043         }
1044     }
1045     /*
1046      * We free the PRLibrary structure whether dlclose/shl_unload
1047      * succeeds or not.
1048      */
1049 
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;
1059     }
1060 
1061 done:
1062     PR_ExitMonitor(pr_linker_lock);
1063     return status;
1064 }
1065 
1066 static void*
pr_FindSymbolInLib(PRLibrary * lm,const char * name)1067 pr_FindSymbolInLib(PRLibrary *lm, const char *name)
1068 {
1069     void *f = NULL;
1070 #ifdef XP_OS2
1071     int rc;
1072 #endif
1073 
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;
1079             }
1080         }
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
1089     }
1090 
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);
1101     }
1102 #endif
1103 #endif  /* XP_OS2 */
1104 
1105 #ifdef WIN32
1106     f = GetProcAddress(lm->dlh, name);
1107 #endif  /* WIN32 */
1108 
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);
1117         }
1118     }
1119     if (lm->connection) {
1120         Ptr                 symAddr;
1121         CFragSymbolClass    symClass;
1122         Str255              pName;
1123 
1124         PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET));
1125 
1126         c2pstrcpy(pName, name + SYM_OFFSET);
1127 
1128         f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL;
1129 
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);
1134         }
1135 #endif /* __ppc__ */
1136 
1137         if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main;
1138     }
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;
1148     }
1149 #undef SYM_OFFSET
1150 #endif /* XP_MACOSX && USE_MACH_DYLD */
1151 
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;
1155     }
1156 #endif
1157 
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;
1165     }
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;
1174     }
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());
1181     }
1182     return f;
1183 }
1184 
1185 /*
1186 ** Called by class loader to resolve missing native's
1187 */
1188 PR_IMPLEMENT(void*)
PR_FindSymbol(PRLibrary * lib,const char * raw_name)1189 PR_FindSymbol(PRLibrary *lib, const char *raw_name)
1190 {
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
1213 
1214     PR_EnterMonitor(pr_linker_lock);
1215     PR_ASSERT(lib != NULL);
1216     f = pr_FindSymbolInLib(lib, name);
1217 
1218 #if defined(NEED_LEADING_UNDERSCORE)
1219     PR_smprintf_free(name);
1220 #endif
1221 
1222     PR_ExitMonitor(pr_linker_lock);
1223     return f;
1224 }
1225 
1226 /*
1227 ** Return the address of the function 'raw_name' in the library 'lib'
1228 */
1229 PR_IMPLEMENT(PRFuncPtr)
PR_FindFunctionSymbol(PRLibrary * lib,const char * raw_name)1230 PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name)
1231 {
1232     return ((PRFuncPtr) PR_FindSymbol(lib, raw_name));
1233 }
1234 
1235 PR_IMPLEMENT(void*)
PR_FindSymbolAndLibrary(const char * raw_name,PRLibrary ** lib)1236 PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
1237 {
1238     void *f = NULL;
1239 #if defined(NEED_LEADING_UNDERSCORE)
1240     char *name;
1241 #else
1242     const char *name;
1243 #endif
1244     PRLibrary* lm;
1245 
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
1263 
1264     PR_EnterMonitor(pr_linker_lock);
1265 
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;
1276         }
1277     }
1278 #if defined(NEED_LEADING_UNDERSCORE)
1279     PR_smprintf_free(name);
1280 #endif
1281 
1282     PR_ExitMonitor(pr_linker_lock);
1283     return f;
1284 }
1285 
1286 PR_IMPLEMENT(PRFuncPtr)
PR_FindFunctionSymbolAndLibrary(const char * raw_name,PRLibrary ** lib)1287 PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
1288 {
1289     return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib));
1290 }
1291 
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*)
PR_LoadStaticLibrary(const char * name,const PRStaticLinkTable * slt)1297 PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt)
1298 {
1299     PRLibrary *lm=NULL;
1300     PRLibrary* result = NULL;
1301 
1302     if (!_pr_initialized) _PR_ImplicitInitialization();
1303 
1304     /* See if library is already loaded */
1305     PR_EnterMonitor(pr_linker_lock);
1306 
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;
1313     }
1314 
1315     /* Add library to list...Mark it static */
1316     lm = PR_NEWZAP(PRLibrary);
1317     if (lm == NULL) goto unlock;
1318 
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;
1325 
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;
1332 }
1333 
1334 PR_IMPLEMENT(char *)
PR_GetLibraryFilePathname(const char * name,PRFuncPtr addr)1335 PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr)
1336 {
1337 #if defined(USE_DLFCN) && defined(HAVE_DLADDR)
1338     Dl_info dli;
1339     char *result;
1340 
1341     if (dladdr((void *)addr, &dli) == 0) {
1342         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
1343         DLLErrorInternal(_MD_ERRNO());
1344         return NULL;
1345     }
1346     result = PR_Malloc(strlen(dli.dli_fname)+1);
1347     if (result != NULL) {
1348         strcpy(result, dli.dli_fname);
1349     }
1350     return result;
1351 #elif defined(USE_MACH_DYLD)
1352     char *result;
1353     const char *image_name;
1354     int i, count = _dyld_image_count();
1355 
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);
1362             }
1363             return result;
1364         }
1365     }
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;
1375 
1376     for (;;) {
1377         info = PR_Malloc(info_length);
1378         if (info == NULL) {
1379             return NULL;
1380         }
1381         /* If buffer is too small, loadquery fails with ENOMEM. */
1382         if (loadquery(loadflags, info, info_length) != -1) {
1383             break;
1384         }
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;
1396             }
1397         }
1398         PR_Free(info);
1399         if (errno != ENOMEM) {
1400             /* should not happen */
1401             _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
1402             return NULL;
1403         }
1404         /* retry with a larger buffer */
1405         info_length += LD_INFO_INCREMENT * sizeof(struct ld_info);
1406     }
1407 
1408     for (infop = info;
1409          ;
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);
1417             }
1418             break;
1419         }
1420         if (!infop->ldinfo_next) {
1421             PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
1422             result = NULL;
1423             break;
1424         }
1425     }
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;
1438 
1439     /* Get process for which dynamic modules will be listed */
1440 
1441     process = ldr_my_process();
1442 
1443     /* Attach to process */
1444 
1445     rv = ldr_xattach(process);
1446     if (rv) {
1447         /* should not happen */
1448         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
1449         return NULL;
1450     }
1451 
1452     /* Print information for list of modules */
1453 
1454     mod_id = LDR_NULL_MODULE;
1455 
1456     for (;;) {
1457 
1458         /* Get information for the next module in the module list. */
1459 
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;
1465         }
1466         if (retsize < sizeof(info)) {
1467             continue;
1468         }
1469 
1470         /*
1471          * Get information for each region in the module and check if any
1472          * contain the address of this function.
1473          */
1474 
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;
1480             }
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);
1489                 }
1490                 return result;
1491             }
1492         }
1493     }
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;
1500 
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);
1506             }
1507             return result;
1508         }
1509     }
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);
1523             }
1524             return result;
1525         }
1526     }
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;
1533 
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;
1538     }
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;
1545     }
1546     result = PR_Malloc(strlen(module_name)+1);
1547     if (result != NULL) {
1548         strcpy(result, module_name);
1549     }
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;
1557 
1558     if (MultiByteToWideChar(CP_ACP, 0, name, -1, wname, MAX_PATH)) {
1559         handle = GetModuleHandleW(wname);
1560     }
1561     if (handle == NULL) {
1562         PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
1563         DLLErrorInternal(_MD_ERRNO());
1564         return NULL;
1565     }
1566     if (GetModuleFileNameW(handle, module_name, MAX_PATH) == 0) {
1567         /* should not happen */
1568         _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
1569         return NULL;
1570     }
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;
1576     }
1577     result = PR_Malloc(len * sizeof(PRUnichar));
1578     if (result != NULL) {
1579         WideCharToMultiByte(CP_ACP, 0, module_name, -1,
1580                             result, len, NULL, NULL);
1581     }
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;
1592     }
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;
1598     }
1599     result = PR_Malloc(strlen(module_name)+1);
1600     if (result != NULL) {
1601         strcpy(result, module_name);
1602     }
1603     return result;
1604 #else
1605     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1606     return NULL;
1607 #endif
1608 }
1609