Line data Source code
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 :
118 0 : 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 0 : const char *error = NULL;
126 : #ifdef USE_DLFCN
127 0 : 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 0 : if (NULL != error)
136 0 : PR_SetErrorText(strlen(error), error);
137 0 : } /* DLLErrorInternal */
138 :
139 3 : void _PR_InitLinker(void)
140 : {
141 3 : PRLibrary *lm = NULL;
142 : #if defined(XP_UNIX)
143 : void *h;
144 : #endif
145 :
146 3 : if (!pr_linker_lock) {
147 3 : pr_linker_lock = PR_NewNamedMonitor("linker-lock");
148 : }
149 3 : 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 3 : h = dlopen(0, RTLD_LAZY);
170 3 : if (!h) {
171 : char *error;
172 :
173 0 : DLLErrorInternal(_MD_ERRNO());
174 0 : error = (char*)PR_MALLOC(PR_GetErrorTextLength());
175 0 : (void) PR_GetErrorText(error);
176 0 : fprintf(stderr, "failed to initialize shared libraries [%s]\n",
177 : error);
178 0 : PR_DELETE(error);
179 0 : 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 3 : lm = PR_NEWZAP(PRLibrary);
191 3 : if (lm) {
192 3 : lm->name = strdup("a.out");
193 3 : lm->refCount = 1;
194 3 : lm->dlh = h;
195 3 : lm->staticTable = NULL;
196 : }
197 3 : pr_exe_loadmap = lm;
198 3 : pr_loadmap = lm;
199 : #endif /* HAVE_DLL */
200 : #endif /* XP_UNIX */
201 :
202 3 : if (lm) {
203 3 : PR_LOG(_pr_linker_lm, PR_LOG_MIN,
204 : ("Loaded library %s (init)", lm->name));
205 : }
206 :
207 3 : PR_ExitMonitor(pr_linker_lock);
208 3 : }
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 : */
217 0 : void _PR_ShutdownLinker(void)
218 : {
219 : /* FIXME: pr_exe_loadmap should be destroyed. */
220 :
221 0 : PR_DestroyMonitor(pr_linker_lock);
222 0 : pr_linker_lock = NULL;
223 :
224 0 : if (_pr_currentLibPath) {
225 0 : free(_pr_currentLibPath);
226 0 : _pr_currentLibPath = NULL;
227 : }
228 0 : }
229 :
230 : /******************************************************************************/
231 :
232 : PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path)
233 : {
234 0 : PRStatus rv = PR_SUCCESS;
235 :
236 0 : if (!_pr_initialized) _PR_ImplicitInitialization();
237 0 : PR_EnterMonitor(pr_linker_lock);
238 0 : if (_pr_currentLibPath) {
239 0 : free(_pr_currentLibPath);
240 : }
241 0 : if (path) {
242 0 : _pr_currentLibPath = strdup(path);
243 0 : if (!_pr_currentLibPath) {
244 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
245 0 : rv = PR_FAILURE;
246 : }
247 : } else {
248 0 : _pr_currentLibPath = 0;
249 : }
250 0 : PR_ExitMonitor(pr_linker_lock);
251 0 : return rv;
252 : }
253 :
254 : /*
255 : ** Return the library path for finding shared libraries.
256 : */
257 : PR_IMPLEMENT(char *)
258 : PR_GetLibraryPath(void)
259 : {
260 : char *ev;
261 0 : char *copy = NULL; /* a copy of _pr_currentLibPath */
262 :
263 0 : if (!_pr_initialized) _PR_ImplicitInitialization();
264 0 : PR_EnterMonitor(pr_linker_lock);
265 0 : if (_pr_currentLibPath != NULL) {
266 0 : 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 0 : 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 0 : ev = getenv("LD_LIBRARY_PATH");
292 0 : if (!ev) {
293 0 : ev = "/usr/lib:/lib";
294 : }
295 : #endif
296 0 : len = strlen(ev) + 1; /* +1 for the null */
297 :
298 0 : p = (char*) malloc(len);
299 0 : if (p) {
300 0 : strcpy(p, ev);
301 : } /* if (p) */
302 0 : ev = p;
303 0 : 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 0 : _pr_currentLibPath = ev;
316 :
317 : exit:
318 0 : if (_pr_currentLibPath) {
319 0 : copy = strdup(_pr_currentLibPath);
320 : }
321 0 : PR_ExitMonitor(pr_linker_lock);
322 0 : if (!copy) {
323 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
324 : }
325 0 : return copy;
326 : }
327 :
328 : /*
329 : ** Build library name from path, lib and extensions
330 : */
331 : PR_IMPLEMENT(char*)
332 : PR_GetLibraryName(const char *path, const char *lib)
333 : {
334 : char *fullname;
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 1 : if (strstr(lib, PR_DLL_SUFFIX) == NULL)
354 : {
355 1 : if (path) {
356 1 : fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX);
357 : } else {
358 0 : fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX);
359 : }
360 : } else {
361 0 : if (path) {
362 0 : fullname = PR_smprintf("%s/%s", path, lib);
363 : } else {
364 0 : fullname = PR_smprintf("%s", lib);
365 : }
366 : }
367 : #endif /* XP_UNIX || XP_BEOS */
368 1 : return fullname;
369 : }
370 :
371 : /*
372 : ** Free the memory allocated, for the caller, by PR_GetLibraryName
373 : */
374 : PR_IMPLEMENT(void)
375 : PR_FreeLibraryName(char *mem)
376 : {
377 1 : PR_smprintf_free(mem);
378 1 : }
379 :
380 : static PRLibrary*
381 8 : pr_UnlockedFindLibrary(const char *name)
382 : {
383 8 : PRLibrary* lm = pr_loadmap;
384 8 : const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR);
385 8 : np = np ? np + 1 : name;
386 40 : while (lm) {
387 24 : const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR);
388 24 : 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 24 : if (strcmp(np, cp) == 0)
396 : #endif
397 : {
398 : /* found */
399 0 : lm->refCount++;
400 0 : PR_LOG(_pr_linker_lm, PR_LOG_MIN,
401 : ("%s incr => %d (find lib)",
402 : lm->name, lm->refCount));
403 0 : return lm;
404 : }
405 24 : lm = lm->next;
406 : }
407 8 : return NULL;
408 : }
409 :
410 : PR_IMPLEMENT(PRLibrary*)
411 : PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags)
412 : {
413 8 : if (flags == 0) {
414 3 : flags = _PR_DEFAULT_LD_FLAGS;
415 : }
416 8 : switch (libSpec.type) {
417 : case PR_LibSpec_Pathname:
418 8 : 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 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
431 0 : return NULL;
432 : }
433 : }
434 :
435 : PR_IMPLEMENT(PRLibrary*)
436 : PR_LoadLibrary(const char *name)
437 : {
438 : PRLibSpec libSpec;
439 :
440 3 : libSpec.type = PR_LibSpec_Pathname;
441 3 : libSpec.value.pathname = name;
442 3 : return PR_LoadLibraryWithFlags(libSpec, 0);
443 : }
444 :
445 : #if defined(USE_MACH_DYLD)
446 : static NSModule
447 : pr_LoadMachDyldModule(const char *name)
448 : {
449 : NSObjectFileImage ofi;
450 : NSModule h = NULL;
451 : if (NSCreateObjectFileImageFromFile(name, &ofi)
452 : == NSObjectFileImageSuccess) {
453 : h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE
454 : | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
455 : if (h == NULL) {
456 : NSLinkEditErrors linkEditError;
457 : int errorNum;
458 : const char *fileName;
459 : const char *errorString;
460 : NSLinkEditError(&linkEditError, &errorNum, &fileName, &errorString);
461 : PR_LOG(_pr_linker_lm, PR_LOG_MIN,
462 : ("LoadMachDyldModule error %d:%d for file %s:\n%s",
463 : linkEditError, errorNum, fileName, errorString));
464 : }
465 : if (NSDestroyObjectFileImage(ofi) == FALSE) {
466 : if (h) {
467 : (void)NSUnLinkModule(h, NSUNLINKMODULE_OPTION_NONE);
468 : h = NULL;
469 : }
470 : }
471 : }
472 : return h;
473 : }
474 : #endif
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 :
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
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
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
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*
642 8 : pr_LoadLibraryByPathname(const char *name, PRIntn flags)
643 : {
644 : PRLibrary *lm;
645 8 : 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 8 : if (!_pr_initialized) _PR_ImplicitInitialization();
658 :
659 : /* See if library is already loaded */
660 8 : 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 8 : result = pr_UnlockedFindLibrary(name);
690 : #endif
691 :
692 8 : if (result != NULL) goto unlock;
693 :
694 8 : lm = PR_NEWZAP(PRLibrary);
695 8 : if (lm == NULL) {
696 0 : oserr = _MD_ERRNO();
697 0 : goto unlock;
698 : }
699 8 : 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 8 : int dl_flags = 0;
779 : #endif
780 8 : void *h = NULL;
781 :
782 8 : if (flags & PR_LD_LAZY) {
783 3 : dl_flags |= RTLD_LAZY;
784 : }
785 8 : if (flags & PR_LD_NOW) {
786 5 : dl_flags |= RTLD_NOW;
787 : }
788 8 : if (flags & PR_LD_GLOBAL) {
789 0 : dl_flags |= RTLD_GLOBAL;
790 : }
791 8 : if (flags & PR_LD_LOCAL) {
792 5 : 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 8 : 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 8 : if (!h) {
831 0 : oserr = _MD_ERRNO();
832 0 : PR_DELETE(lm);
833 0 : goto unlock;
834 : }
835 8 : lm->name = strdup(name);
836 8 : lm->dlh = h;
837 8 : lm->next = pr_loadmap;
838 8 : pr_loadmap = lm;
839 : }
840 : #endif /* HAVE_DLL */
841 : #endif /* XP_UNIX && !(XP_MACOSX && USE_MACH_DYLD) */
842 :
843 8 : 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 8 : result = lm; /* success */
936 8 : PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name));
937 :
938 : unlock:
939 8 : if (result == NULL) {
940 0 : PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr);
941 0 : 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 8 : PR_ExitMonitor(pr_linker_lock);
950 8 : return result;
951 : }
952 :
953 : /*
954 : ** Unload a shared library which was loaded via PR_LoadLibrary
955 : */
956 : PR_IMPLEMENT(PRStatus)
957 : PR_UnloadLibrary(PRLibrary *lib)
958 : {
959 0 : int result = 0;
960 0 : PRStatus status = PR_SUCCESS;
961 :
962 0 : if (lib == 0) {
963 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
964 0 : return PR_FAILURE;
965 : }
966 :
967 0 : PR_EnterMonitor(pr_linker_lock);
968 :
969 0 : if (lib->refCount <= 0) {
970 0 : PR_ExitMonitor(pr_linker_lock);
971 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
972 0 : return PR_FAILURE;
973 : }
974 :
975 0 : if (--lib->refCount > 0) {
976 0 : PR_LOG(_pr_linker_lm, PR_LOG_MIN,
977 : ("%s decr => %d",
978 : lib->name, lib->refCount));
979 0 : 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 0 : 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 0 : if (pr_loadmap == lib)
1023 0 : pr_loadmap = pr_loadmap->next;
1024 0 : else if (pr_loadmap != NULL) {
1025 0 : PRLibrary* prev = pr_loadmap;
1026 0 : PRLibrary* next = pr_loadmap->next;
1027 0 : while (next != NULL) {
1028 0 : if (next == lib) {
1029 0 : prev->next = next->next;
1030 0 : goto freeLib;
1031 : }
1032 0 : prev = next;
1033 0 : 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 0 : PR_NOT_REACHED("_pr_loadmap and lib->refCount inconsistent");
1040 0 : if (result == 0) {
1041 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1042 0 : 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 0 : PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name));
1052 0 : free(lib->name);
1053 0 : lib->name = NULL;
1054 0 : PR_DELETE(lib);
1055 0 : if (result != 0) {
1056 0 : PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO());
1057 0 : DLLErrorInternal(_MD_ERRNO());
1058 0 : status = PR_FAILURE;
1059 : }
1060 :
1061 : done:
1062 0 : PR_ExitMonitor(pr_linker_lock);
1063 0 : return status;
1064 : }
1065 :
1066 : static void*
1067 21 : pr_FindSymbolInLib(PRLibrary *lm, const char *name)
1068 : {
1069 21 : void *f = NULL;
1070 : #ifdef XP_OS2
1071 : int rc;
1072 : #endif
1073 :
1074 21 : if (lm->staticTable != NULL) {
1075 : const PRStaticLinkTable* tp;
1076 0 : for (tp = lm->staticTable; tp->name; tp++) {
1077 0 : if (strcmp(name, tp->name) == 0) {
1078 0 : 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 0 : PR_SetError(PR_FIND_SYMBOL_ERROR, 0);
1087 0 : 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 21 : 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 21 : if (f == NULL) {
1179 0 : PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO());
1180 0 : DLLErrorInternal(_MD_ERRNO());
1181 : }
1182 21 : return f;
1183 : }
1184 :
1185 : /*
1186 : ** Called by class loader to resolve missing native's
1187 : */
1188 : PR_IMPLEMENT(void*)
1189 : PR_FindSymbol(PRLibrary *lib, const char *raw_name)
1190 : {
1191 21 : 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 21 : name = raw_name;
1212 : #endif
1213 :
1214 21 : PR_EnterMonitor(pr_linker_lock);
1215 21 : PR_ASSERT(lib != NULL);
1216 21 : f = pr_FindSymbolInLib(lib, name);
1217 :
1218 : #if defined(NEED_LEADING_UNDERSCORE)
1219 : PR_smprintf_free(name);
1220 : #endif
1221 :
1222 21 : PR_ExitMonitor(pr_linker_lock);
1223 21 : return f;
1224 : }
1225 :
1226 : /*
1227 : ** Return the address of the function 'raw_name' in the library 'lib'
1228 : */
1229 : PR_IMPLEMENT(PRFuncPtr)
1230 : PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name)
1231 : {
1232 14 : return ((PRFuncPtr) PR_FindSymbol(lib, raw_name));
1233 : }
1234 :
1235 : PR_IMPLEMENT(void*)
1236 : PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
1237 : {
1238 0 : 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 0 : 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 0 : name = raw_name;
1262 : #endif
1263 :
1264 0 : PR_EnterMonitor(pr_linker_lock);
1265 :
1266 : /* search all libraries */
1267 0 : for (lm = pr_loadmap; lm != NULL; lm = lm->next) {
1268 0 : f = pr_FindSymbolInLib(lm, name);
1269 0 : if (f != NULL) {
1270 0 : *lib = lm;
1271 0 : lm->refCount++;
1272 0 : PR_LOG(_pr_linker_lm, PR_LOG_MIN,
1273 : ("%s incr => %d (for %s)",
1274 : lm->name, lm->refCount, name));
1275 0 : break;
1276 : }
1277 : }
1278 : #if defined(NEED_LEADING_UNDERSCORE)
1279 : PR_smprintf_free(name);
1280 : #endif
1281 :
1282 0 : PR_ExitMonitor(pr_linker_lock);
1283 0 : return f;
1284 : }
1285 :
1286 : PR_IMPLEMENT(PRFuncPtr)
1287 : PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
1288 : {
1289 0 : 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*)
1297 : PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt)
1298 : {
1299 0 : PRLibrary *lm=NULL;
1300 0 : PRLibrary* result = NULL;
1301 :
1302 0 : if (!_pr_initialized) _PR_ImplicitInitialization();
1303 :
1304 : /* See if library is already loaded */
1305 0 : PR_EnterMonitor(pr_linker_lock);
1306 :
1307 : /* If the lbrary is already loaded, then add the static table information... */
1308 0 : result = pr_UnlockedFindLibrary(name);
1309 0 : if (result != NULL) {
1310 0 : PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) );
1311 0 : result->staticTable = slt;
1312 0 : goto unlock;
1313 : }
1314 :
1315 : /* Add library to list...Mark it static */
1316 0 : lm = PR_NEWZAP(PRLibrary);
1317 0 : if (lm == NULL) goto unlock;
1318 :
1319 0 : lm->name = strdup(name);
1320 0 : lm->refCount = 1;
1321 0 : lm->dlh = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0;
1322 0 : lm->staticTable = slt;
1323 0 : lm->next = pr_loadmap;
1324 0 : pr_loadmap = lm;
1325 :
1326 0 : result = lm; /* success */
1327 0 : PR_ASSERT(lm->refCount == 1);
1328 0 : PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name));
1329 : unlock:
1330 0 : PR_ExitMonitor(pr_linker_lock);
1331 0 : return result;
1332 : }
1333 :
1334 : PR_IMPLEMENT(char *)
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 6 : if (dladdr((void *)addr, &dli) == 0) {
1342 0 : PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());
1343 0 : DLLErrorInternal(_MD_ERRNO());
1344 0 : return NULL;
1345 : }
1346 6 : result = PR_Malloc(strlen(dli.dli_fname)+1);
1347 6 : if (result != NULL) {
1348 6 : strcpy(result, dli.dli_fname);
1349 : }
1350 6 : 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, ®info,
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 : }
|