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