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_UNIX
11 #ifdef USE_DLFCN
12 #include <dlfcn.h>
13 /* Define these on systems that don't have them. */
14 #ifndef RTLD_NOW
15 #define RTLD_NOW 0
16 #endif
17 #ifndef RTLD_LAZY
18 #define RTLD_LAZY RTLD_NOW
19 #endif
20 #ifndef RTLD_GLOBAL
21 #define RTLD_GLOBAL 0
22 #endif
23 #ifndef RTLD_LOCAL
24 #define RTLD_LOCAL 0
25 #endif
26 #ifdef AIX
27 #include <sys/ldr.h>
28 #ifndef L_IGNOREUNLOAD /* AIX 4.3.3 does not have L_IGNOREUNLOAD. */
29 #define L_IGNOREUNLOAD 0x10000000
30 #endif
31 #endif
32 #elif defined(USE_HPSHL)
33 #include <dl.h>
34 #endif
35 #endif /* XP_UNIX */
36
37 #define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY
38
39 /*
40 * On these platforms, symbols have a leading '_'.
41 */
42 #if defined(XP_OS2) \
43 || ((defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__))
44 #define NEED_LEADING_UNDERSCORE
45 #endif
46
47 #define PR_LD_PATHW 0x8000 /* for PR_LibSpec_PathnameU */
48
49 /************************************************************************/
50
51 struct PRLibrary {
52 char* name; /* Our own copy of the name string */
53 PRLibrary* next;
54 int refCount;
55 const PRStaticLinkTable* staticTable;
56
57 #ifdef XP_PC
58 #ifdef XP_OS2
59 HMODULE dlh;
60 #else
61 HINSTANCE dlh;
62 #endif
63 #endif
64
65 #ifdef XP_UNIX
66 #if defined(USE_HPSHL)
67 shl_t dlh;
68 #else
69 void* dlh;
70 #endif
71 #endif
72
73 };
74
75 static PRLibrary *pr_loadmap;
76 static PRLibrary *pr_exe_loadmap;
77 static PRMonitor *pr_linker_lock;
78 static char* _pr_currentLibPath = NULL;
79
80 static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags);
81
82 /************************************************************************/
83
84 #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR)
85 #define ERR_STR_BUF_LENGTH 20
86 #endif
87
DLLErrorInternal(PRIntn oserr)88 static void DLLErrorInternal(PRIntn oserr)
89 /*
90 ** This whole function, and most of the code in this file, are run
91 ** with a big hairy lock wrapped around it. Not the best of situations,
92 ** but will eventually come up with the right answer.
93 */
94 {
95 const char *error = NULL;
96 #ifdef USE_DLFCN
97 error = dlerror(); /* $$$ That'll be wrong some of the time - AOF */
98 #elif defined(HAVE_STRERROR)
99 error = strerror(oserr); /* this should be okay */
100 #else
101 char errStrBuf[ERR_STR_BUF_LENGTH];
102 PR_snprintf(errStrBuf, sizeof(errStrBuf), "error %d", oserr);
103 error = errStrBuf;
104 #endif
105 if (NULL != error) {
106 PR_SetErrorText(strlen(error), error);
107 }
108 } /* DLLErrorInternal */
109
_PR_InitLinker(void)110 void _PR_InitLinker(void)
111 {
112 PRLibrary *lm = NULL;
113 #if defined(XP_UNIX)
114 void *h;
115 #endif
116
117 if (!pr_linker_lock) {
118 pr_linker_lock = PR_NewNamedMonitor("linker-lock");
119 }
120 PR_EnterMonitor(pr_linker_lock);
121
122 #if defined(XP_PC)
123 lm = PR_NEWZAP(PRLibrary);
124 lm->name = strdup("Executable");
125 #if defined(XP_OS2)
126 lm->dlh = NULLHANDLE;
127 #else
128 /* A module handle for the executable. */
129 lm->dlh = GetModuleHandle(NULL);
130 #endif /* ! XP_OS2 */
131
132 lm->refCount = 1;
133 lm->staticTable = NULL;
134 pr_exe_loadmap = lm;
135 pr_loadmap = lm;
136
137 #elif defined(XP_UNIX)
138 #ifdef HAVE_DLL
139 #if defined(USE_DLFCN) && !defined(NO_DLOPEN_NULL)
140 h = dlopen(0, RTLD_LAZY);
141 if (!h) {
142 char *error;
143
144 DLLErrorInternal(_MD_ERRNO());
145 error = (char*)PR_MALLOC(PR_GetErrorTextLength());
146 (void) PR_GetErrorText(error);
147 fprintf(stderr, "failed to initialize shared libraries [%s]\n",
148 error);
149 PR_DELETE(error);
150 abort();/* XXX */
151 }
152 #elif defined(USE_HPSHL)
153 h = NULL;
154 /* don't abort with this NULL */
155 #elif defined(NO_DLOPEN_NULL)
156 h = NULL; /* XXXX toshok */ /* XXXX vlad */
157 #else
158 #error no dll strategy
159 #endif /* USE_DLFCN */
160
161 lm = PR_NEWZAP(PRLibrary);
162 if (lm) {
163 lm->name = strdup("a.out");
164 lm->refCount = 1;
165 lm->dlh = h;
166 lm->staticTable = NULL;
167 }
168 pr_exe_loadmap = lm;
169 pr_loadmap = lm;
170 #endif /* HAVE_DLL */
171 #endif /* XP_UNIX */
172
173 if (lm) {
174 PR_LOG(_pr_linker_lm, PR_LOG_MIN,
175 ("Loaded library %s (init)", lm->name));
176 }
177
178 PR_ExitMonitor(pr_linker_lock);
179 }
180
181 /*
182 * _PR_ShutdownLinker does not unload the dlls loaded by the application
183 * via calls to PR_LoadLibrary. Any dlls that still remain on the
184 * pr_loadmap list when NSPR shuts down are application programming errors.
185 * The only exception is pr_exe_loadmap, which was added to the list by
186 * NSPR and hence should be cleaned up by NSPR.
187 */
_PR_ShutdownLinker(void)188 void _PR_ShutdownLinker(void)
189 {
190 /* FIXME: pr_exe_loadmap should be destroyed. */
191
192 PR_DestroyMonitor(pr_linker_lock);
193 pr_linker_lock = NULL;
194
195 if (_pr_currentLibPath) {
196 free(_pr_currentLibPath);
197 _pr_currentLibPath = NULL;
198 }
199 }
200
201 /******************************************************************************/
202
PR_SetLibraryPath(const char * path)203 PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path)
204 {
205 PRStatus rv = PR_SUCCESS;
206
207 if (!_pr_initialized) {
208 _PR_ImplicitInitialization();
209 }
210 PR_EnterMonitor(pr_linker_lock);
211 if (_pr_currentLibPath) {
212 free(_pr_currentLibPath);
213 }
214 if (path) {
215 _pr_currentLibPath = strdup(path);
216 if (!_pr_currentLibPath) {
217 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
218 rv = PR_FAILURE;
219 }
220 } else {
221 _pr_currentLibPath = 0;
222 }
223 PR_ExitMonitor(pr_linker_lock);
224 return rv;
225 }
226
227 /*
228 ** Return the library path for finding shared libraries.
229 */
230 PR_IMPLEMENT(char *)
PR_GetLibraryPath(void)231 PR_GetLibraryPath(void)
232 {
233 char *ev;
234 char *copy = NULL; /* a copy of _pr_currentLibPath */
235
236 if (!_pr_initialized) {
237 _PR_ImplicitInitialization();
238 }
239 PR_EnterMonitor(pr_linker_lock);
240 if (_pr_currentLibPath != NULL) {
241 goto exit;
242 }
243
244 /* initialize pr_currentLibPath */
245
246 #ifdef XP_PC
247 ev = getenv("LD_LIBRARY_PATH");
248 if (!ev) {
249 ev = ".;\\lib";
250 }
251 ev = strdup(ev);
252 #endif
253
254 #if defined(XP_UNIX)
255 #if defined(USE_DLFCN)
256 {
257 char *p=NULL;
258 int len;
259
260 ev = getenv("LD_LIBRARY_PATH");
261 if (!ev) {
262 ev = "/usr/lib:/lib";
263 }
264 len = strlen(ev) + 1; /* +1 for the null */
265
266 p = (char*) malloc(len);
267 if (p) {
268 strcpy(p, ev);
269 } /* if (p) */
270 ev = p;
271 PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev));
272
273 }
274 #else
275 /* AFAIK there isn't a library path with the HP SHL interface --Rob */
276 ev = strdup("");
277 #endif
278 #endif
279
280 /*
281 * If ev is NULL, we have run out of memory
282 */
283 _pr_currentLibPath = ev;
284
285 exit:
286 if (_pr_currentLibPath) {
287 copy = strdup(_pr_currentLibPath);
288 }
289 PR_ExitMonitor(pr_linker_lock);
290 if (!copy) {
291 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
292 }
293 return copy;
294 }
295
296 /*
297 ** Build library name from path, lib and extensions
298 */
299 PR_IMPLEMENT(char*)
PR_GetLibraryName(const char * path,const char * lib)300 PR_GetLibraryName(const char *path, const char *lib)
301 {
302 char *fullname;
303
304 #ifdef XP_PC
305 if (strstr(lib, PR_DLL_SUFFIX) == NULL)
306 {
307 if (path) {
308 fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX);
309 } else {
310 fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX);
311 }
312 } else {
313 if (path) {
314 fullname = PR_smprintf("%s\\%s", path, lib);
315 } else {
316 fullname = PR_smprintf("%s", lib);
317 }
318 }
319 #endif /* XP_PC */
320 #if defined(XP_UNIX)
321 if (strstr(lib, PR_DLL_SUFFIX) == NULL)
322 {
323 if (path) {
324 fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX);
325 } else {
326 fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX);
327 }
328 } else {
329 if (path) {
330 fullname = PR_smprintf("%s/%s", path, lib);
331 } else {
332 fullname = PR_smprintf("%s", lib);
333 }
334 }
335 #endif /* XP_UNIX */
336 return fullname;
337 }
338
339 /*
340 ** Free the memory allocated, for the caller, by PR_GetLibraryName
341 */
342 PR_IMPLEMENT(void)
PR_FreeLibraryName(char * mem)343 PR_FreeLibraryName(char *mem)
344 {
345 PR_smprintf_free(mem);
346 }
347
348 static PRLibrary*
pr_UnlockedFindLibrary(const char * name)349 pr_UnlockedFindLibrary(const char *name)
350 {
351 PRLibrary* lm = pr_loadmap;
352 const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR);
353 np = np ? np + 1 : name;
354 while (lm) {
355 const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR);
356 cp = cp ? cp + 1 : lm->name;
357 #ifdef WIN32
358 /* Windows DLL names are case insensitive... */
359 if (strcmpi(np, cp) == 0)
360 #elif defined(XP_OS2)
361 if (stricmp(np, cp) == 0)
362 #else
363 if (strcmp(np, cp) == 0)
364 #endif
365 {
366 /* found */
367 lm->refCount++;
368 PR_LOG(_pr_linker_lm, PR_LOG_MIN,
369 ("%s incr => %d (find lib)",
370 lm->name, lm->refCount));
371 return lm;
372 }
373 lm = lm->next;
374 }
375 return NULL;
376 }
377
378 PR_IMPLEMENT(PRLibrary*)
PR_LoadLibraryWithFlags(PRLibSpec libSpec,PRIntn flags)379 PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags)
380 {
381 if (flags == 0) {
382 flags = _PR_DEFAULT_LD_FLAGS;
383 }
384 switch (libSpec.type) {
385 case PR_LibSpec_Pathname:
386 return pr_LoadLibraryByPathname(libSpec.value.pathname, flags);
387 #ifdef WIN32
388 case PR_LibSpec_PathnameU:
389 /*
390 * cast to |char *| and set PR_LD_PATHW flag so that
391 * it can be cast back to PRUnichar* in the callee.
392 */
393 return pr_LoadLibraryByPathname((const char*)
394 libSpec.value.pathname_u,
395 flags | PR_LD_PATHW);
396 #endif
397 default:
398 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
399 return NULL;
400 }
401 }
402
403 PR_IMPLEMENT(PRLibrary*)
PR_LoadLibrary(const char * name)404 PR_LoadLibrary(const char *name)
405 {
406 PRLibSpec libSpec;
407
408 libSpec.type = PR_LibSpec_Pathname;
409 libSpec.value.pathname = name;
410 return PR_LoadLibraryWithFlags(libSpec, 0);
411 }
412
413 /*
414 ** Dynamically load a library. Only load libraries once, so scan the load
415 ** map first.
416 */
417 static PRLibrary*
pr_LoadLibraryByPathname(const char * name,PRIntn flags)418 pr_LoadLibraryByPathname(const char *name, PRIntn flags)
419 {
420 PRLibrary *lm;
421 PRLibrary* result = NULL;
422 PRInt32 oserr;
423 #ifdef WIN32
424 char utf8name_stack[MAX_PATH];
425 char *utf8name_malloc = NULL;
426 char *utf8name = utf8name_stack;
427 PRUnichar wname_stack[MAX_PATH];
428 PRUnichar *wname_malloc = NULL;
429 PRUnichar *wname = wname_stack;
430 int len;
431 #endif
432
433 if (!_pr_initialized) {
434 _PR_ImplicitInitialization();
435 }
436
437 /* See if library is already loaded */
438 PR_EnterMonitor(pr_linker_lock);
439
440 #ifdef WIN32
441 if (flags & PR_LD_PATHW) {
442 /* cast back what's cast to |char *| for the argument passing. */
443 wname = (LPWSTR) name;
444 } else {
445 int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
446 if (wlen > MAX_PATH) {
447 wname = wname_malloc = PR_Malloc(wlen * sizeof(PRUnichar));
448 }
449 if (wname == NULL ||
450 !MultiByteToWideChar(CP_ACP, 0, name, -1, wname, wlen)) {
451 oserr = _MD_ERRNO();
452 goto unlock;
453 }
454 }
455 len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
456 if (len > MAX_PATH) {
457 utf8name = utf8name_malloc = PR_Malloc(len);
458 }
459 if (utf8name == NULL ||
460 !WideCharToMultiByte(CP_UTF8, 0, wname, -1,
461 utf8name, len, NULL, NULL)) {
462 oserr = _MD_ERRNO();
463 goto unlock;
464 }
465 /* the list of loaded library names are always kept in UTF-8
466 * on Win32 platforms */
467 result = pr_UnlockedFindLibrary(utf8name);
468 #else
469 result = pr_UnlockedFindLibrary(name);
470 #endif
471
472 if (result != NULL) {
473 goto unlock;
474 }
475
476 lm = PR_NEWZAP(PRLibrary);
477 if (lm == NULL) {
478 oserr = _MD_ERRNO();
479 goto unlock;
480 }
481 lm->staticTable = NULL;
482
483 #ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */
484 {
485 HMODULE h;
486 UCHAR pszError[_MAX_PATH];
487 ULONG ulRc = NO_ERROR;
488
489 ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h);
490 if (ulRc != NO_ERROR) {
491 oserr = ulRc;
492 PR_DELETE(lm);
493 goto unlock;
494 }
495 lm->name = strdup(name);
496 lm->dlh = h;
497 lm->next = pr_loadmap;
498 pr_loadmap = lm;
499 }
500 #endif /* XP_OS2 */
501
502 #ifdef WIN32
503 {
504 HINSTANCE h;
505
506 h = LoadLibraryExW(wname, NULL,
507 (flags & PR_LD_ALT_SEARCH_PATH) ?
508 LOAD_WITH_ALTERED_SEARCH_PATH : 0);
509 if (h == NULL) {
510 oserr = _MD_ERRNO();
511 PR_DELETE(lm);
512 goto unlock;
513 }
514 lm->name = strdup(utf8name);
515 lm->dlh = h;
516 lm->next = pr_loadmap;
517 pr_loadmap = lm;
518 }
519 #endif /* WIN32 */
520
521 #if defined(XP_UNIX)
522 #ifdef HAVE_DLL
523 {
524 #if defined(USE_DLFCN)
525 #ifdef NTO
526 /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */
527 int dl_flags = RTLD_GROUP;
528 #elif defined(AIX)
529 /* AIX needs RTLD_MEMBER to load an archive member. (bug 228899) */
530 int dl_flags = RTLD_MEMBER;
531 #else
532 int dl_flags = 0;
533 #endif
534 void *h = NULL;
535 #if defined(DARWIN)
536 PRBool okToLoad = PR_FALSE;
537 #endif
538
539 if (flags & PR_LD_LAZY) {
540 dl_flags |= RTLD_LAZY;
541 }
542 if (flags & PR_LD_NOW) {
543 dl_flags |= RTLD_NOW;
544 }
545 if (flags & PR_LD_GLOBAL) {
546 dl_flags |= RTLD_GLOBAL;
547 }
548 if (flags & PR_LD_LOCAL) {
549 dl_flags |= RTLD_LOCAL;
550 }
551 #if defined(DARWIN)
552 /* If the file contains an absolute or relative path (slash)
553 * and the path doesn't look like a System path, then require
554 * the file exists.
555 * The reason is that DARWIN's dlopen ignores the provided path
556 * and checks for the plain filename in DYLD_LIBRARY_PATH,
557 * which could load an unexpected version of a library. */
558 if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) {
559 /* no slash, allow to load from any location */
560 okToLoad = PR_TRUE;
561 } else {
562 const char systemPrefix1[] = "/System/";
563 const size_t systemPrefixLen1 = strlen(systemPrefix1);
564 const char systemPrefix2[] = "/usr/lib/";
565 const size_t systemPrefixLen2 = strlen(systemPrefix2);
566 const size_t name_len = strlen(name);
567 if (((name_len > systemPrefixLen1) &&
568 (strncmp(name, systemPrefix1, systemPrefixLen1) == 0)) ||
569 ((name_len > systemPrefixLen2) &&
570 (strncmp(name, systemPrefix2, systemPrefixLen2) == 0))) {
571 /* found at beginning, it's a system library.
572 * Skip filesystem check (required for macOS 11),
573 * allow loading from any location */
574 okToLoad = PR_TRUE;
575 } else if (PR_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) {
576 /* file exists, allow to load */
577 okToLoad = PR_TRUE;
578 }
579 }
580 if (okToLoad) {
581 h = dlopen(name, dl_flags);
582 }
583 #else
584 h = dlopen(name, dl_flags);
585 #endif
586 #elif defined(USE_HPSHL)
587 int shl_flags = 0;
588 shl_t h;
589
590 /*
591 * Use the DYNAMIC_PATH flag only if 'name' is a plain file
592 * name (containing no directory) to match the behavior of
593 * dlopen().
594 */
595 if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) {
596 shl_flags |= DYNAMIC_PATH;
597 }
598 if (flags & PR_LD_LAZY) {
599 shl_flags |= BIND_DEFERRED;
600 }
601 if (flags & PR_LD_NOW) {
602 shl_flags |= BIND_IMMEDIATE;
603 }
604 /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */
605 h = shl_load(name, shl_flags, 0L);
606 #else
607 #error Configuration error
608 #endif
609 if (!h) {
610 oserr = _MD_ERRNO();
611 PR_DELETE(lm);
612 goto unlock;
613 }
614 lm->name = strdup(name);
615 lm->dlh = h;
616 lm->next = pr_loadmap;
617 pr_loadmap = lm;
618 }
619 #endif /* HAVE_DLL */
620 #endif /* XP_UNIX */
621
622 lm->refCount = 1;
623
624 result = lm; /* success */
625 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name));
626
627 unlock:
628 if (result == NULL) {
629 PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr);
630 DLLErrorInternal(oserr); /* sets error text */
631 }
632 #ifdef WIN32
633 if (utf8name_malloc) {
634 PR_Free(utf8name_malloc);
635 }
636 if (wname_malloc) {
637 PR_Free(wname_malloc);
638 }
639 #endif
640 PR_ExitMonitor(pr_linker_lock);
641 return result;
642 }
643
644 /*
645 ** Unload a shared library which was loaded via PR_LoadLibrary
646 */
647 PR_IMPLEMENT(PRStatus)
PR_UnloadLibrary(PRLibrary * lib)648 PR_UnloadLibrary(PRLibrary *lib)
649 {
650 int result = 0;
651 PRStatus status = PR_SUCCESS;
652
653 if (lib == 0) {
654 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
655 return PR_FAILURE;
656 }
657
658 PR_EnterMonitor(pr_linker_lock);
659
660 if (lib->refCount <= 0) {
661 PR_ExitMonitor(pr_linker_lock);
662 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
663 return PR_FAILURE;
664 }
665
666 if (--lib->refCount > 0) {
667 PR_LOG(_pr_linker_lm, PR_LOG_MIN,
668 ("%s decr => %d",
669 lib->name, lib->refCount));
670 goto done;
671 }
672
673 #ifdef XP_UNIX
674 #ifdef HAVE_DLL
675 #ifdef USE_DLFCN
676 result = dlclose(lib->dlh);
677 #elif defined(USE_HPSHL)
678 result = shl_unload(lib->dlh);
679 #else
680 #error Configuration error
681 #endif
682 #endif /* HAVE_DLL */
683 #endif /* XP_UNIX */
684 #ifdef XP_PC
685 if (lib->dlh) {
686 FreeLibrary((HINSTANCE)(lib->dlh));
687 lib->dlh = (HINSTANCE)NULL;
688 }
689 #endif /* XP_PC */
690
691 /* unlink from library search list */
692 if (pr_loadmap == lib) {
693 pr_loadmap = pr_loadmap->next;
694 }
695 else if (pr_loadmap != NULL) {
696 PRLibrary* prev = pr_loadmap;
697 PRLibrary* next = pr_loadmap->next;
698 while (next != NULL) {
699 if (next == lib) {
700 prev->next = next->next;
701 goto freeLib;
702 }
703 prev = next;
704 next = next->next;
705 }
706 /*
707 * fail (the library is not on the _pr_loadmap list),
708 * but don't wipe out an error from dlclose/shl_unload.
709 */
710 PR_NOT_REACHED("_pr_loadmap and lib->refCount inconsistent");
711 if (result == 0) {
712 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
713 status = PR_FAILURE;
714 }
715 }
716 /*
717 * We free the PRLibrary structure whether dlclose/shl_unload
718 * succeeds or not.
719 */
720
721 freeLib:
722 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name));
723 free(lib->name);
724 lib->name = NULL;
725 PR_DELETE(lib);
726 if (result != 0) {
727 PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO());
728 DLLErrorInternal(_MD_ERRNO());
729 status = PR_FAILURE;
730 }
731
732 done:
733 PR_ExitMonitor(pr_linker_lock);
734 return status;
735 }
736
737 static void*
pr_FindSymbolInLib(PRLibrary * lm,const char * name)738 pr_FindSymbolInLib(PRLibrary *lm, const char *name)
739 {
740 void *f = NULL;
741 #ifdef XP_OS2
742 int rc;
743 #endif
744
745 if (lm->staticTable != NULL) {
746 const PRStaticLinkTable* tp;
747 for (tp = lm->staticTable; tp->name; tp++) {
748 if (strcmp(name, tp->name) == 0) {
749 return (void*) tp->fp;
750 }
751 }
752 /*
753 ** If the symbol was not found in the static table then check if
754 ** the symbol was exported in the DLL... Win16 only!!
755 */
756 #if !defined(WIN16)
757 PR_SetError(PR_FIND_SYMBOL_ERROR, 0);
758 return (void*)NULL;
759 #endif
760 }
761
762 #ifdef XP_OS2
763 rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
764 #if defined(NEED_LEADING_UNDERSCORE)
765 /*
766 * Older plugins (not built using GCC) will have symbols that are not
767 * underscore prefixed. We check for that here.
768 */
769 if (rc != NO_ERROR) {
770 name++;
771 DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
772 }
773 #endif
774 #endif /* XP_OS2 */
775
776 #ifdef WIN32
777 f = GetProcAddress(lm->dlh, name);
778 #endif /* WIN32 */
779
780 #ifdef XP_UNIX
781 #ifdef HAVE_DLL
782 #ifdef USE_DLFCN
783 f = dlsym(lm->dlh, name);
784 #elif defined(USE_HPSHL)
785 if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) {
786 f = NULL;
787 }
788 #endif
789 #endif /* HAVE_DLL */
790 #endif /* XP_UNIX */
791 if (f == NULL) {
792 PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO());
793 DLLErrorInternal(_MD_ERRNO());
794 }
795 return f;
796 }
797
798 /*
799 ** Called by class loader to resolve missing native's
800 */
801 PR_IMPLEMENT(void*)
PR_FindSymbol(PRLibrary * lib,const char * raw_name)802 PR_FindSymbol(PRLibrary *lib, const char *raw_name)
803 {
804 void *f = NULL;
805 #if defined(NEED_LEADING_UNDERSCORE)
806 char *name;
807 #else
808 const char *name;
809 #endif
810 /*
811 ** Mangle the raw symbol name in any way that is platform specific.
812 */
813 #if defined(NEED_LEADING_UNDERSCORE)
814 /* Need a leading _ */
815 name = PR_smprintf("_%s", raw_name);
816 #elif defined(AIX)
817 /*
818 ** AIX with the normal linker put's a "." in front of the symbol
819 ** name. When use "svcc" and "svld" then the "." disappears. Go
820 ** figure.
821 */
822 name = raw_name;
823 #else
824 name = raw_name;
825 #endif
826
827 PR_EnterMonitor(pr_linker_lock);
828 PR_ASSERT(lib != NULL);
829 f = pr_FindSymbolInLib(lib, name);
830
831 #if defined(NEED_LEADING_UNDERSCORE)
832 PR_smprintf_free(name);
833 #endif
834
835 PR_ExitMonitor(pr_linker_lock);
836 return f;
837 }
838
839 /*
840 ** Return the address of the function 'raw_name' in the library 'lib'
841 */
842 PR_IMPLEMENT(PRFuncPtr)
PR_FindFunctionSymbol(PRLibrary * lib,const char * raw_name)843 PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name)
844 {
845 return ((PRFuncPtr) PR_FindSymbol(lib, raw_name));
846 }
847
848 PR_IMPLEMENT(void*)
PR_FindSymbolAndLibrary(const char * raw_name,PRLibrary ** lib)849 PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
850 {
851 void *f = NULL;
852 #if defined(NEED_LEADING_UNDERSCORE)
853 char *name;
854 #else
855 const char *name;
856 #endif
857 PRLibrary* lm;
858
859 if (!_pr_initialized) {
860 _PR_ImplicitInitialization();
861 }
862 /*
863 ** Mangle the raw symbol name in any way that is platform specific.
864 */
865 #if defined(NEED_LEADING_UNDERSCORE)
866 /* Need a leading _ */
867 name = PR_smprintf("_%s", raw_name);
868 #elif defined(AIX)
869 /*
870 ** AIX with the normal linker put's a "." in front of the symbol
871 ** name. When use "svcc" and "svld" then the "." disappears. Go
872 ** figure.
873 */
874 name = raw_name;
875 #else
876 name = raw_name;
877 #endif
878
879 PR_EnterMonitor(pr_linker_lock);
880
881 /* search all libraries */
882 for (lm = pr_loadmap; lm != NULL; lm = lm->next) {
883 f = pr_FindSymbolInLib(lm, name);
884 if (f != NULL) {
885 *lib = lm;
886 lm->refCount++;
887 PR_LOG(_pr_linker_lm, PR_LOG_MIN,
888 ("%s incr => %d (for %s)",
889 lm->name, lm->refCount, name));
890 break;
891 }
892 }
893 #if defined(NEED_LEADING_UNDERSCORE)
894 PR_smprintf_free(name);
895 #endif
896
897 PR_ExitMonitor(pr_linker_lock);
898 return f;
899 }
900
901 PR_IMPLEMENT(PRFuncPtr)
PR_FindFunctionSymbolAndLibrary(const char * raw_name,PRLibrary ** lib)902 PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
903 {
904 return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib));
905 }
906
907 /*
908 ** Add a static library to the list of loaded libraries. If LoadLibrary
909 ** is called with the name then we will pretend it was already loaded
910 */
911 PR_IMPLEMENT(PRLibrary*)
PR_LoadStaticLibrary(const char * name,const PRStaticLinkTable * slt)912 PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt)
913 {
914 PRLibrary *lm=NULL;
915 PRLibrary* result = NULL;
916
917 if (!_pr_initialized) {
918 _PR_ImplicitInitialization();
919 }
920
921 /* See if library is already loaded */
922 PR_EnterMonitor(pr_linker_lock);
923
924 /* If the lbrary is already loaded, then add the static table information... */
925 result = pr_UnlockedFindLibrary(name);
926 if (result != NULL) {
927 PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) );
928 result->staticTable = slt;
929 goto unlock;
930 }
931
932 /* Add library to list...Mark it static */
933 lm = PR_NEWZAP(PRLibrary);
934 if (lm == NULL) {
935 goto unlock;
936 }
937
938 lm->name = strdup(name);
939 lm->refCount = 1;
940 lm->dlh = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0;
941 lm->staticTable = slt;
942 lm->next = pr_loadmap;
943 pr_loadmap = lm;
944
945 result = lm; /* success */
946 PR_ASSERT(lm->refCount == 1);
947 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name));
948 unlock:
949 PR_ExitMonitor(pr_linker_lock);
950 return result;
951 }
952
953 PR_IMPLEMENT(char *)
PR_GetLibraryFilePathname(const char * name,PRFuncPtr addr)954 PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr)
955 {
956 #if defined(USE_DLFCN) && defined(HAVE_DLADDR)
957 Dl_info dli;
958 char *result;
959
960 if (dladdr((void *)addr, &dli) == 0) {
961 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
962 DLLErrorInternal(_MD_ERRNO());
963 return NULL;
964 }
965 result = PR_Malloc(strlen(dli.dli_fname)+1);
966 if (result != NULL) {
967 strcpy(result, dli.dli_fname);
968 }
969 return result;
970 #elif defined(AIX)
971 char *result;
972 #define LD_INFO_INCREMENT 64
973 struct ld_info *info;
974 unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info);
975 struct ld_info *infop;
976 int loadflags = L_GETINFO | L_IGNOREUNLOAD;
977
978 for (;;) {
979 info = PR_Malloc(info_length);
980 if (info == NULL) {
981 return NULL;
982 }
983 /* If buffer is too small, loadquery fails with ENOMEM. */
984 if (loadquery(loadflags, info, info_length) != -1) {
985 break;
986 }
987 /*
988 * Calling loadquery when compiled for 64-bit with the
989 * L_IGNOREUNLOAD flag can cause an invalid argument error
990 * on AIX 5.1. Detect this error the first time that
991 * loadquery is called, and try calling it again without
992 * this flag set.
993 */
994 if (errno == EINVAL && (loadflags & L_IGNOREUNLOAD)) {
995 loadflags &= ~L_IGNOREUNLOAD;
996 if (loadquery(loadflags, info, info_length) != -1) {
997 break;
998 }
999 }
1000 PR_Free(info);
1001 if (errno != ENOMEM) {
1002 /* should not happen */
1003 _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
1004 return NULL;
1005 }
1006 /* retry with a larger buffer */
1007 info_length += LD_INFO_INCREMENT * sizeof(struct ld_info);
1008 }
1009
1010 for (infop = info;
1011 ;
1012 infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) {
1013 unsigned long start = (unsigned long)infop->ldinfo_dataorg;
1014 unsigned long end = start + infop->ldinfo_datasize;
1015 if (start <= (unsigned long)addr && end > (unsigned long)addr) {
1016 result = PR_Malloc(strlen(infop->ldinfo_filename)+1);
1017 if (result != NULL) {
1018 strcpy(result, infop->ldinfo_filename);
1019 }
1020 break;
1021 }
1022 if (!infop->ldinfo_next) {
1023 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
1024 result = NULL;
1025 break;
1026 }
1027 }
1028 PR_Free(info);
1029 return result;
1030 #elif defined(HPUX) && defined(USE_HPSHL)
1031 int index;
1032 struct shl_descriptor desc;
1033 char *result;
1034
1035 for (index = 0; shl_get_r(index, &desc) == 0; index++) {
1036 if (strstr(desc.filename, name) != NULL) {
1037 result = PR_Malloc(strlen(desc.filename)+1);
1038 if (result != NULL) {
1039 strcpy(result, desc.filename);
1040 }
1041 return result;
1042 }
1043 }
1044 /*
1045 * Since the index value of a library is decremented if
1046 * a library preceding it in the shared library search
1047 * list was unloaded, it is possible that we missed some
1048 * libraries as we went up the list. So we should go
1049 * down the list to be sure that we not miss anything.
1050 */
1051 for (index--; index >= 0; index--) {
1052 if ((shl_get_r(index, &desc) == 0)
1053 && (strstr(desc.filename, name) != NULL)) {
1054 result = PR_Malloc(strlen(desc.filename)+1);
1055 if (result != NULL) {
1056 strcpy(result, desc.filename);
1057 }
1058 return result;
1059 }
1060 }
1061 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);
1062 return NULL;
1063 #elif defined(HPUX) && defined(USE_DLFCN)
1064 struct load_module_desc desc;
1065 char *result;
1066 const char *module_name;
1067
1068 if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) {
1069 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
1070 DLLErrorInternal(_MD_ERRNO());
1071 return NULL;
1072 }
1073 module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0);
1074 if (module_name == NULL) {
1075 /* should not happen */
1076 _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
1077 DLLErrorInternal(_MD_ERRNO());
1078 return NULL;
1079 }
1080 result = PR_Malloc(strlen(module_name)+1);
1081 if (result != NULL) {
1082 strcpy(result, module_name);
1083 }
1084 return result;
1085 #elif defined(WIN32)
1086 PRUnichar wname[MAX_PATH];
1087 HMODULE handle = NULL;
1088 PRUnichar module_name[MAX_PATH];
1089 int len;
1090 char *result;
1091
1092 if (MultiByteToWideChar(CP_ACP, 0, name, -1, wname, MAX_PATH)) {
1093 handle = GetModuleHandleW(wname);
1094 }
1095 if (handle == NULL) {
1096 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
1097 DLLErrorInternal(_MD_ERRNO());
1098 return NULL;
1099 }
1100 if (GetModuleFileNameW(handle, module_name, MAX_PATH) == 0) {
1101 /* should not happen */
1102 _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
1103 return NULL;
1104 }
1105 len = WideCharToMultiByte(CP_ACP, 0, module_name, -1,
1106 NULL, 0, NULL, NULL);
1107 if (len == 0) {
1108 _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
1109 return NULL;
1110 }
1111 result = PR_Malloc(len * sizeof(PRUnichar));
1112 if (result != NULL) {
1113 WideCharToMultiByte(CP_ACP, 0, module_name, -1,
1114 result, len, NULL, NULL);
1115 }
1116 return result;
1117 #elif defined(XP_OS2)
1118 HMODULE module = NULL;
1119 char module_name[_MAX_PATH];
1120 char *result;
1121 APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr);
1122 if ((NO_ERROR != ulrc) || (NULL == module) ) {
1123 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
1124 DLLErrorInternal(_MD_ERRNO());
1125 return NULL;
1126 }
1127 ulrc = DosQueryModuleName(module, sizeof module_name, module_name);
1128 if (NO_ERROR != ulrc) {
1129 /* should not happen */
1130 _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());
1131 return NULL;
1132 }
1133 result = PR_Malloc(strlen(module_name)+1);
1134 if (result != NULL) {
1135 strcpy(result, module_name);
1136 }
1137 return result;
1138 #else
1139 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1140 return NULL;
1141 #endif
1142 }
1143