Mercurial > trustbridge > nss-cmake-static
comparison nspr/pr/src/linking/prlink.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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 static void DLLErrorInternal(PRIntn oserr) | |
119 /* | |
120 ** This whole function, and most of the code in this file, are run | |
121 ** with a big hairy lock wrapped around it. Not the best of situations, | |
122 ** but will eventually come up with the right answer. | |
123 */ | |
124 { | |
125 const char *error = NULL; | |
126 #ifdef USE_DLFCN | |
127 error = dlerror(); /* $$$ That'll be wrong some of the time - AOF */ | |
128 #elif defined(HAVE_STRERROR) | |
129 error = strerror(oserr); /* this should be okay */ | |
130 #else | |
131 char errStrBuf[ERR_STR_BUF_LENGTH]; | |
132 PR_snprintf(errStrBuf, sizeof(errStrBuf), "error %d", oserr); | |
133 error = errStrBuf; | |
134 #endif | |
135 if (NULL != error) | |
136 PR_SetErrorText(strlen(error), error); | |
137 } /* DLLErrorInternal */ | |
138 | |
139 void _PR_InitLinker(void) | |
140 { | |
141 PRLibrary *lm = NULL; | |
142 #if defined(XP_UNIX) | |
143 void *h; | |
144 #endif | |
145 | |
146 if (!pr_linker_lock) { | |
147 pr_linker_lock = PR_NewNamedMonitor("linker-lock"); | |
148 } | |
149 PR_EnterMonitor(pr_linker_lock); | |
150 | |
151 #if defined(XP_PC) | |
152 lm = PR_NEWZAP(PRLibrary); | |
153 lm->name = strdup("Executable"); | |
154 #if defined(XP_OS2) | |
155 lm->dlh = NULLHANDLE; | |
156 #else | |
157 /* A module handle for the executable. */ | |
158 lm->dlh = GetModuleHandle(NULL); | |
159 #endif /* ! XP_OS2 */ | |
160 | |
161 lm->refCount = 1; | |
162 lm->staticTable = NULL; | |
163 pr_exe_loadmap = lm; | |
164 pr_loadmap = lm; | |
165 | |
166 #elif defined(XP_UNIX) | |
167 #ifdef HAVE_DLL | |
168 #if defined(USE_DLFCN) && !defined(NO_DLOPEN_NULL) | |
169 h = dlopen(0, RTLD_LAZY); | |
170 if (!h) { | |
171 char *error; | |
172 | |
173 DLLErrorInternal(_MD_ERRNO()); | |
174 error = (char*)PR_MALLOC(PR_GetErrorTextLength()); | |
175 (void) PR_GetErrorText(error); | |
176 fprintf(stderr, "failed to initialize shared libraries [%s]\n", | |
177 error); | |
178 PR_DELETE(error); | |
179 abort();/* XXX */ | |
180 } | |
181 #elif defined(USE_HPSHL) | |
182 h = NULL; | |
183 /* don't abort with this NULL */ | |
184 #elif defined(USE_MACH_DYLD) || defined(NO_DLOPEN_NULL) | |
185 h = NULL; /* XXXX toshok */ /* XXXX vlad */ | |
186 #else | |
187 #error no dll strategy | |
188 #endif /* USE_DLFCN */ | |
189 | |
190 lm = PR_NEWZAP(PRLibrary); | |
191 if (lm) { | |
192 lm->name = strdup("a.out"); | |
193 lm->refCount = 1; | |
194 lm->dlh = h; | |
195 lm->staticTable = NULL; | |
196 } | |
197 pr_exe_loadmap = lm; | |
198 pr_loadmap = lm; | |
199 #endif /* HAVE_DLL */ | |
200 #endif /* XP_UNIX */ | |
201 | |
202 if (lm) { | |
203 PR_LOG(_pr_linker_lm, PR_LOG_MIN, | |
204 ("Loaded library %s (init)", lm->name)); | |
205 } | |
206 | |
207 PR_ExitMonitor(pr_linker_lock); | |
208 } | |
209 | |
210 /* | |
211 * _PR_ShutdownLinker does not unload the dlls loaded by the application | |
212 * via calls to PR_LoadLibrary. Any dlls that still remain on the | |
213 * pr_loadmap list when NSPR shuts down are application programming errors. | |
214 * The only exception is pr_exe_loadmap, which was added to the list by | |
215 * NSPR and hence should be cleaned up by NSPR. | |
216 */ | |
217 void _PR_ShutdownLinker(void) | |
218 { | |
219 /* FIXME: pr_exe_loadmap should be destroyed. */ | |
220 | |
221 PR_DestroyMonitor(pr_linker_lock); | |
222 pr_linker_lock = NULL; | |
223 | |
224 if (_pr_currentLibPath) { | |
225 free(_pr_currentLibPath); | |
226 _pr_currentLibPath = NULL; | |
227 } | |
228 } | |
229 | |
230 /******************************************************************************/ | |
231 | |
232 PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path) | |
233 { | |
234 PRStatus rv = PR_SUCCESS; | |
235 | |
236 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
237 PR_EnterMonitor(pr_linker_lock); | |
238 if (_pr_currentLibPath) { | |
239 free(_pr_currentLibPath); | |
240 } | |
241 if (path) { | |
242 _pr_currentLibPath = strdup(path); | |
243 if (!_pr_currentLibPath) { | |
244 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
245 rv = PR_FAILURE; | |
246 } | |
247 } else { | |
248 _pr_currentLibPath = 0; | |
249 } | |
250 PR_ExitMonitor(pr_linker_lock); | |
251 return rv; | |
252 } | |
253 | |
254 /* | |
255 ** Return the library path for finding shared libraries. | |
256 */ | |
257 PR_IMPLEMENT(char *) | |
258 PR_GetLibraryPath(void) | |
259 { | |
260 char *ev; | |
261 char *copy = NULL; /* a copy of _pr_currentLibPath */ | |
262 | |
263 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
264 PR_EnterMonitor(pr_linker_lock); | |
265 if (_pr_currentLibPath != NULL) { | |
266 goto exit; | |
267 } | |
268 | |
269 /* initialize pr_currentLibPath */ | |
270 | |
271 #ifdef XP_PC | |
272 ev = getenv("LD_LIBRARY_PATH"); | |
273 if (!ev) { | |
274 ev = ".;\\lib"; | |
275 } | |
276 ev = strdup(ev); | |
277 #endif | |
278 | |
279 #if defined(XP_UNIX) || defined(XP_BEOS) | |
280 #if defined(USE_DLFCN) || defined(USE_MACH_DYLD) || defined(XP_BEOS) | |
281 { | |
282 char *p=NULL; | |
283 int len; | |
284 | |
285 #ifdef XP_BEOS | |
286 ev = getenv("LIBRARY_PATH"); | |
287 if (!ev) { | |
288 ev = "%A/lib:/boot/home/config/lib:/boot/beos/system/lib"; | |
289 } | |
290 #else | |
291 ev = getenv("LD_LIBRARY_PATH"); | |
292 if (!ev) { | |
293 ev = "/usr/lib:/lib"; | |
294 } | |
295 #endif | |
296 len = strlen(ev) + 1; /* +1 for the null */ | |
297 | |
298 p = (char*) malloc(len); | |
299 if (p) { | |
300 strcpy(p, ev); | |
301 } /* if (p) */ | |
302 ev = p; | |
303 PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev)); | |
304 | |
305 } | |
306 #else | |
307 /* AFAIK there isn't a library path with the HP SHL interface --Rob */ | |
308 ev = strdup(""); | |
309 #endif | |
310 #endif | |
311 | |
312 /* | |
313 * If ev is NULL, we have run out of memory | |
314 */ | |
315 _pr_currentLibPath = ev; | |
316 | |
317 exit: | |
318 if (_pr_currentLibPath) { | |
319 copy = strdup(_pr_currentLibPath); | |
320 } | |
321 PR_ExitMonitor(pr_linker_lock); | |
322 if (!copy) { | |
323 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
324 } | |
325 return copy; | |
326 } | |
327 | |
328 /* | |
329 ** Build library name from path, lib and extensions | |
330 */ | |
331 PR_IMPLEMENT(char*) | |
332 PR_GetLibraryName(const char *path, const char *lib) | |
333 { | |
334 char *fullname; | |
335 | |
336 #ifdef XP_PC | |
337 if (strstr(lib, PR_DLL_SUFFIX) == NULL) | |
338 { | |
339 if (path) { | |
340 fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX); | |
341 } else { | |
342 fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX); | |
343 } | |
344 } else { | |
345 if (path) { | |
346 fullname = PR_smprintf("%s\\%s", path, lib); | |
347 } else { | |
348 fullname = PR_smprintf("%s", lib); | |
349 } | |
350 } | |
351 #endif /* XP_PC */ | |
352 #if defined(XP_UNIX) || defined(XP_BEOS) | |
353 if (strstr(lib, PR_DLL_SUFFIX) == NULL) | |
354 { | |
355 if (path) { | |
356 fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX); | |
357 } else { | |
358 fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX); | |
359 } | |
360 } else { | |
361 if (path) { | |
362 fullname = PR_smprintf("%s/%s", path, lib); | |
363 } else { | |
364 fullname = PR_smprintf("%s", lib); | |
365 } | |
366 } | |
367 #endif /* XP_UNIX || XP_BEOS */ | |
368 return fullname; | |
369 } | |
370 | |
371 /* | |
372 ** Free the memory allocated, for the caller, by PR_GetLibraryName | |
373 */ | |
374 PR_IMPLEMENT(void) | |
375 PR_FreeLibraryName(char *mem) | |
376 { | |
377 PR_smprintf_free(mem); | |
378 } | |
379 | |
380 static PRLibrary* | |
381 pr_UnlockedFindLibrary(const char *name) | |
382 { | |
383 PRLibrary* lm = pr_loadmap; | |
384 const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR); | |
385 np = np ? np + 1 : name; | |
386 while (lm) { | |
387 const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR); | |
388 cp = cp ? cp + 1 : lm->name; | |
389 #ifdef WIN32 | |
390 /* Windows DLL names are case insensitive... */ | |
391 if (strcmpi(np, cp) == 0) | |
392 #elif defined(XP_OS2) | |
393 if (stricmp(np, cp) == 0) | |
394 #else | |
395 if (strcmp(np, cp) == 0) | |
396 #endif | |
397 { | |
398 /* found */ | |
399 lm->refCount++; | |
400 PR_LOG(_pr_linker_lm, PR_LOG_MIN, | |
401 ("%s incr => %d (find lib)", | |
402 lm->name, lm->refCount)); | |
403 return lm; | |
404 } | |
405 lm = lm->next; | |
406 } | |
407 return NULL; | |
408 } | |
409 | |
410 PR_IMPLEMENT(PRLibrary*) | |
411 PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags) | |
412 { | |
413 if (flags == 0) { | |
414 flags = _PR_DEFAULT_LD_FLAGS; | |
415 } | |
416 switch (libSpec.type) { | |
417 case PR_LibSpec_Pathname: | |
418 return pr_LoadLibraryByPathname(libSpec.value.pathname, flags); | |
419 #ifdef WIN32 | |
420 case PR_LibSpec_PathnameU: | |
421 /* | |
422 * cast to |char *| and set PR_LD_PATHW flag so that | |
423 * it can be cast back to PRUnichar* in the callee. | |
424 */ | |
425 return pr_LoadLibraryByPathname((const char*) | |
426 libSpec.value.pathname_u, | |
427 flags | PR_LD_PATHW); | |
428 #endif | |
429 default: | |
430 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
431 return NULL; | |
432 } | |
433 } | |
434 | |
435 PR_IMPLEMENT(PRLibrary*) | |
436 PR_LoadLibrary(const char *name) | |
437 { | |
438 PRLibSpec libSpec; | |
439 | |
440 libSpec.type = PR_LibSpec_Pathname; | |
441 libSpec.value.pathname = name; | |
442 return PR_LoadLibraryWithFlags(libSpec, 0); | |
443 } | |
444 | |
445 #if defined(USE_MACH_DYLD) | |
446 static NSModule | |
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 pr_LoadLibraryByPathname(const char *name, PRIntn flags) | |
643 { | |
644 PRLibrary *lm; | |
645 PRLibrary* result = NULL; | |
646 PRInt32 oserr; | |
647 #ifdef WIN32 | |
648 char utf8name_stack[MAX_PATH]; | |
649 char *utf8name_malloc = NULL; | |
650 char *utf8name = utf8name_stack; | |
651 PRUnichar wname_stack[MAX_PATH]; | |
652 PRUnichar *wname_malloc = NULL; | |
653 PRUnichar *wname = wname_stack; | |
654 int len; | |
655 #endif | |
656 | |
657 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
658 | |
659 /* See if library is already loaded */ | |
660 PR_EnterMonitor(pr_linker_lock); | |
661 | |
662 #ifdef WIN32 | |
663 if (flags & PR_LD_PATHW) { | |
664 /* cast back what's cast to |char *| for the argument passing. */ | |
665 wname = (LPWSTR) name; | |
666 } else { | |
667 int wlen = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); | |
668 if (wlen > MAX_PATH) | |
669 wname = wname_malloc = PR_Malloc(wlen * sizeof(PRUnichar)); | |
670 if (wname == NULL || | |
671 !MultiByteToWideChar(CP_ACP, 0, name, -1, wname, wlen)) { | |
672 oserr = _MD_ERRNO(); | |
673 goto unlock; | |
674 } | |
675 } | |
676 len = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL); | |
677 if (len > MAX_PATH) | |
678 utf8name = utf8name_malloc = PR_Malloc(len); | |
679 if (utf8name == NULL || | |
680 !WideCharToMultiByte(CP_UTF8, 0, wname, -1, | |
681 utf8name, len, NULL, NULL)) { | |
682 oserr = _MD_ERRNO(); | |
683 goto unlock; | |
684 } | |
685 /* the list of loaded library names are always kept in UTF-8 | |
686 * on Win32 platforms */ | |
687 result = pr_UnlockedFindLibrary(utf8name); | |
688 #else | |
689 result = pr_UnlockedFindLibrary(name); | |
690 #endif | |
691 | |
692 if (result != NULL) goto unlock; | |
693 | |
694 lm = PR_NEWZAP(PRLibrary); | |
695 if (lm == NULL) { | |
696 oserr = _MD_ERRNO(); | |
697 goto unlock; | |
698 } | |
699 lm->staticTable = NULL; | |
700 | |
701 #ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */ | |
702 { | |
703 HMODULE h; | |
704 UCHAR pszError[_MAX_PATH]; | |
705 ULONG ulRc = NO_ERROR; | |
706 | |
707 ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); | |
708 if (ulRc != NO_ERROR) { | |
709 oserr = ulRc; | |
710 PR_DELETE(lm); | |
711 goto unlock; | |
712 } | |
713 lm->name = strdup(name); | |
714 lm->dlh = h; | |
715 lm->next = pr_loadmap; | |
716 pr_loadmap = lm; | |
717 } | |
718 #endif /* XP_OS2 */ | |
719 | |
720 #ifdef WIN32 | |
721 { | |
722 HINSTANCE h; | |
723 | |
724 h = LoadLibraryExW(wname, NULL, | |
725 (flags & PR_LD_ALT_SEARCH_PATH) ? | |
726 LOAD_WITH_ALTERED_SEARCH_PATH : 0); | |
727 if (h == NULL) { | |
728 oserr = _MD_ERRNO(); | |
729 PR_DELETE(lm); | |
730 goto unlock; | |
731 } | |
732 lm->name = strdup(utf8name); | |
733 lm->dlh = h; | |
734 lm->next = pr_loadmap; | |
735 pr_loadmap = lm; | |
736 } | |
737 #endif /* WIN32 */ | |
738 | |
739 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) | |
740 { | |
741 int i; | |
742 PRStatus status; | |
743 | |
744 static const macLibraryLoadProc loadProcs[] = { | |
745 #ifdef __ppc__ | |
746 pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM | |
747 #else /* __ppc__ */ | |
748 pr_LoadViaDyld, pr_LoadCFBundle | |
749 #endif /* __ppc__ */ | |
750 }; | |
751 | |
752 for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) { | |
753 if ((status = loadProcs[i](name, lm)) == PR_SUCCESS) | |
754 break; | |
755 } | |
756 if (status != PR_SUCCESS) { | |
757 oserr = cfragNoLibraryErr; | |
758 PR_DELETE(lm); | |
759 goto unlock; | |
760 } | |
761 lm->name = strdup(name); | |
762 lm->next = pr_loadmap; | |
763 pr_loadmap = lm; | |
764 } | |
765 #endif | |
766 | |
767 #if defined(XP_UNIX) && !(defined(XP_MACOSX) && defined(USE_MACH_DYLD)) | |
768 #ifdef HAVE_DLL | |
769 { | |
770 #if defined(USE_DLFCN) | |
771 #ifdef NTO | |
772 /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */ | |
773 int dl_flags = RTLD_GROUP; | |
774 #elif defined(AIX) | |
775 /* AIX needs RTLD_MEMBER to load an archive member. (bug 228899) */ | |
776 int dl_flags = RTLD_MEMBER; | |
777 #else | |
778 int dl_flags = 0; | |
779 #endif | |
780 void *h = NULL; | |
781 | |
782 if (flags & PR_LD_LAZY) { | |
783 dl_flags |= RTLD_LAZY; | |
784 } | |
785 if (flags & PR_LD_NOW) { | |
786 dl_flags |= RTLD_NOW; | |
787 } | |
788 if (flags & PR_LD_GLOBAL) { | |
789 dl_flags |= RTLD_GLOBAL; | |
790 } | |
791 if (flags & PR_LD_LOCAL) { | |
792 dl_flags |= RTLD_LOCAL; | |
793 } | |
794 #if defined(DARWIN) | |
795 /* ensure the file exists if it contains a slash character i.e. path */ | |
796 /* DARWIN's dlopen ignores the provided path and checks for the */ | |
797 /* plain filename in DYLD_LIBRARY_PATH */ | |
798 if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL || | |
799 PR_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) { | |
800 h = dlopen(name, dl_flags); | |
801 } | |
802 #else | |
803 h = dlopen(name, dl_flags); | |
804 #endif | |
805 #elif defined(USE_HPSHL) | |
806 int shl_flags = 0; | |
807 shl_t h; | |
808 | |
809 /* | |
810 * Use the DYNAMIC_PATH flag only if 'name' is a plain file | |
811 * name (containing no directory) to match the behavior of | |
812 * dlopen(). | |
813 */ | |
814 if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) { | |
815 shl_flags |= DYNAMIC_PATH; | |
816 } | |
817 if (flags & PR_LD_LAZY) { | |
818 shl_flags |= BIND_DEFERRED; | |
819 } | |
820 if (flags & PR_LD_NOW) { | |
821 shl_flags |= BIND_IMMEDIATE; | |
822 } | |
823 /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */ | |
824 h = shl_load(name, shl_flags, 0L); | |
825 #elif defined(USE_MACH_DYLD) | |
826 NSModule h = pr_LoadMachDyldModule(name); | |
827 #else | |
828 #error Configuration error | |
829 #endif | |
830 if (!h) { | |
831 oserr = _MD_ERRNO(); | |
832 PR_DELETE(lm); | |
833 goto unlock; | |
834 } | |
835 lm->name = strdup(name); | |
836 lm->dlh = h; | |
837 lm->next = pr_loadmap; | |
838 pr_loadmap = lm; | |
839 } | |
840 #endif /* HAVE_DLL */ | |
841 #endif /* XP_UNIX && !(XP_MACOSX && USE_MACH_DYLD) */ | |
842 | |
843 lm->refCount = 1; | |
844 | |
845 #ifdef XP_BEOS | |
846 { | |
847 image_info info; | |
848 int32 cookie = 0; | |
849 image_id imageid = B_ERROR; | |
850 image_id stubid = B_ERROR; | |
851 PRLibrary *p; | |
852 | |
853 for (p = pr_loadmap; p != NULL; p = p->next) { | |
854 /* hopefully, our caller will always use the same string | |
855 to refer to the same library */ | |
856 if (strcmp(name, p->name) == 0) { | |
857 /* we've already loaded this library */ | |
858 imageid = info.id; | |
859 lm->refCount++; | |
860 break; | |
861 } | |
862 } | |
863 | |
864 if(imageid == B_ERROR) { | |
865 /* it appears the library isn't yet loaded - load it now */ | |
866 char stubName [B_PATH_NAME_LENGTH + 1]; | |
867 | |
868 /* the following is a work-around to a "bug" in the beos - | |
869 the beos system loader allows only 32M (system-wide) | |
870 to be used by code loaded as "add-ons" (code loaded | |
871 through the 'load_add_on()' system call, which includes | |
872 mozilla components), but allows 256M to be used by | |
873 shared libraries. | |
874 | |
875 unfortunately, mozilla is too large to fit into the | |
876 "add-on" space, so we must trick the loader into | |
877 loading some of the components as shared libraries. this | |
878 is accomplished by creating a "stub" add-on (an empty | |
879 shared object), and linking it with the component | |
880 (the actual .so file generated by the build process, | |
881 without any modifications). when this stub is loaded | |
882 by load_add_on(), the loader will automatically load the | |
883 component into the shared library space. | |
884 */ | |
885 | |
886 strcpy(stubName, name); | |
887 strcat(stubName, ".stub"); | |
888 | |
889 /* first, attempt to load the stub (thereby loading the | |
890 component as a shared library */ | |
891 if ((stubid = load_add_on(stubName)) > B_ERROR) { | |
892 /* the stub was loaded successfully. */ | |
893 imageid = B_FILE_NOT_FOUND; | |
894 | |
895 cookie = 0; | |
896 while (get_next_image_info(0, &cookie, &info) == B_OK) { | |
897 const char *endOfSystemName = strrchr(info.name, '/'); | |
898 const char *endOfPassedName = strrchr(name, '/'); | |
899 if( 0 == endOfSystemName ) | |
900 endOfSystemName = info.name; | |
901 else | |
902 endOfSystemName++; | |
903 if( 0 == endOfPassedName ) | |
904 endOfPassedName = name; | |
905 else | |
906 endOfPassedName++; | |
907 if (strcmp(endOfSystemName, endOfPassedName) == 0) { | |
908 /* this is the actual component - remember it */ | |
909 imageid = info.id; | |
910 break; | |
911 } | |
912 } | |
913 | |
914 } else { | |
915 /* we failed to load the "stub" - try to load the | |
916 component directly as an add-on */ | |
917 stubid = B_ERROR; | |
918 imageid = load_add_on(name); | |
919 } | |
920 } | |
921 | |
922 if (imageid <= B_ERROR) { | |
923 oserr = imageid; | |
924 PR_DELETE( lm ); | |
925 goto unlock; | |
926 } | |
927 lm->name = strdup(name); | |
928 lm->dlh = (void*)imageid; | |
929 lm->stub_dlh = (void*)stubid; | |
930 lm->next = pr_loadmap; | |
931 pr_loadmap = lm; | |
932 } | |
933 #endif | |
934 | |
935 result = lm; /* success */ | |
936 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name)); | |
937 | |
938 unlock: | |
939 if (result == NULL) { | |
940 PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr); | |
941 DLLErrorInternal(oserr); /* sets error text */ | |
942 } | |
943 #ifdef WIN32 | |
944 if (utf8name_malloc) | |
945 PR_Free(utf8name_malloc); | |
946 if (wname_malloc) | |
947 PR_Free(wname_malloc); | |
948 #endif | |
949 PR_ExitMonitor(pr_linker_lock); | |
950 return result; | |
951 } | |
952 | |
953 /* | |
954 ** Unload a shared library which was loaded via PR_LoadLibrary | |
955 */ | |
956 PR_IMPLEMENT(PRStatus) | |
957 PR_UnloadLibrary(PRLibrary *lib) | |
958 { | |
959 int result = 0; | |
960 PRStatus status = PR_SUCCESS; | |
961 | |
962 if (lib == 0) { | |
963 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
964 return PR_FAILURE; | |
965 } | |
966 | |
967 PR_EnterMonitor(pr_linker_lock); | |
968 | |
969 if (lib->refCount <= 0) { | |
970 PR_ExitMonitor(pr_linker_lock); | |
971 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
972 return PR_FAILURE; | |
973 } | |
974 | |
975 if (--lib->refCount > 0) { | |
976 PR_LOG(_pr_linker_lm, PR_LOG_MIN, | |
977 ("%s decr => %d", | |
978 lib->name, lib->refCount)); | |
979 goto done; | |
980 } | |
981 | |
982 #ifdef XP_BEOS | |
983 if(((image_id)lib->stub_dlh) == B_ERROR) | |
984 unload_add_on( (image_id) lib->dlh ); | |
985 else | |
986 unload_add_on( (image_id) lib->stub_dlh); | |
987 #endif | |
988 | |
989 #ifdef XP_UNIX | |
990 #ifdef HAVE_DLL | |
991 #ifdef USE_DLFCN | |
992 result = dlclose(lib->dlh); | |
993 #elif defined(USE_HPSHL) | |
994 result = shl_unload(lib->dlh); | |
995 #elif defined(USE_MACH_DYLD) | |
996 if (lib->dlh) | |
997 result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1; | |
998 #else | |
999 #error Configuration error | |
1000 #endif | |
1001 #endif /* HAVE_DLL */ | |
1002 #endif /* XP_UNIX */ | |
1003 #ifdef XP_PC | |
1004 if (lib->dlh) { | |
1005 FreeLibrary((HINSTANCE)(lib->dlh)); | |
1006 lib->dlh = (HINSTANCE)NULL; | |
1007 } | |
1008 #endif /* XP_PC */ | |
1009 | |
1010 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) | |
1011 /* Close the connection */ | |
1012 if (lib->connection) | |
1013 CloseConnection(&(lib->connection)); | |
1014 if (lib->bundle) | |
1015 CFRelease(lib->bundle); | |
1016 if (lib->wrappers) | |
1017 CFRelease(lib->wrappers); | |
1018 /* No way to unload an image (lib->image) */ | |
1019 #endif | |
1020 | |
1021 /* unlink from library search list */ | |
1022 if (pr_loadmap == lib) | |
1023 pr_loadmap = pr_loadmap->next; | |
1024 else if (pr_loadmap != NULL) { | |
1025 PRLibrary* prev = pr_loadmap; | |
1026 PRLibrary* next = pr_loadmap->next; | |
1027 while (next != NULL) { | |
1028 if (next == lib) { | |
1029 prev->next = next->next; | |
1030 goto freeLib; | |
1031 } | |
1032 prev = next; | |
1033 next = next->next; | |
1034 } | |
1035 /* | |
1036 * fail (the library is not on the _pr_loadmap list), | |
1037 * but don't wipe out an error from dlclose/shl_unload. | |
1038 */ | |
1039 PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent"); | |
1040 if (result == 0) { | |
1041 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
1042 status = PR_FAILURE; | |
1043 } | |
1044 } | |
1045 /* | |
1046 * We free the PRLibrary structure whether dlclose/shl_unload | |
1047 * succeeds or not. | |
1048 */ | |
1049 | |
1050 freeLib: | |
1051 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name)); | |
1052 free(lib->name); | |
1053 lib->name = NULL; | |
1054 PR_DELETE(lib); | |
1055 if (result != 0) { | |
1056 PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO()); | |
1057 DLLErrorInternal(_MD_ERRNO()); | |
1058 status = PR_FAILURE; | |
1059 } | |
1060 | |
1061 done: | |
1062 PR_ExitMonitor(pr_linker_lock); | |
1063 return status; | |
1064 } | |
1065 | |
1066 static void* | |
1067 pr_FindSymbolInLib(PRLibrary *lm, const char *name) | |
1068 { | |
1069 void *f = NULL; | |
1070 #ifdef XP_OS2 | |
1071 int rc; | |
1072 #endif | |
1073 | |
1074 if (lm->staticTable != NULL) { | |
1075 const PRStaticLinkTable* tp; | |
1076 for (tp = lm->staticTable; tp->name; tp++) { | |
1077 if (strcmp(name, tp->name) == 0) { | |
1078 return (void*) tp->fp; | |
1079 } | |
1080 } | |
1081 /* | |
1082 ** If the symbol was not found in the static table then check if | |
1083 ** the symbol was exported in the DLL... Win16 only!! | |
1084 */ | |
1085 #if !defined(WIN16) && !defined(XP_BEOS) | |
1086 PR_SetError(PR_FIND_SYMBOL_ERROR, 0); | |
1087 return (void*)NULL; | |
1088 #endif | |
1089 } | |
1090 | |
1091 #ifdef XP_OS2 | |
1092 rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); | |
1093 #if defined(NEED_LEADING_UNDERSCORE) | |
1094 /* | |
1095 * Older plugins (not built using GCC) will have symbols that are not | |
1096 * underscore prefixed. We check for that here. | |
1097 */ | |
1098 if (rc != NO_ERROR) { | |
1099 name++; | |
1100 DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); | |
1101 } | |
1102 #endif | |
1103 #endif /* XP_OS2 */ | |
1104 | |
1105 #ifdef WIN32 | |
1106 f = GetProcAddress(lm->dlh, name); | |
1107 #endif /* WIN32 */ | |
1108 | |
1109 #if defined(XP_MACOSX) && defined(USE_MACH_DYLD) | |
1110 /* add this offset to skip the leading underscore in name */ | |
1111 #define SYM_OFFSET 1 | |
1112 if (lm->bundle) { | |
1113 CFStringRef nameRef = CFStringCreateWithCString(NULL, name + SYM_OFFSET, kCFStringEncodingASCII); | |
1114 if (nameRef) { | |
1115 f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef); | |
1116 CFRelease(nameRef); | |
1117 } | |
1118 } | |
1119 if (lm->connection) { | |
1120 Ptr symAddr; | |
1121 CFragSymbolClass symClass; | |
1122 Str255 pName; | |
1123 | |
1124 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET)); | |
1125 | |
1126 c2pstrcpy(pName, name + SYM_OFFSET); | |
1127 | |
1128 f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; | |
1129 | |
1130 #ifdef __ppc__ | |
1131 /* callers expect mach-o function pointers, so must wrap tvectors with glue. */ | |
1132 if (f && symClass == kTVectorCFragSymbol) { | |
1133 f = TV2FP(lm->wrappers, name + SYM_OFFSET, f); | |
1134 } | |
1135 #endif /* __ppc__ */ | |
1136 | |
1137 if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main; | |
1138 } | |
1139 if (lm->image) { | |
1140 NSSymbol symbol; | |
1141 symbol = NSLookupSymbolInImage(lm->image, name, | |
1142 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | |
1143 | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); | |
1144 if (symbol != NULL) | |
1145 f = NSAddressOfSymbol(symbol); | |
1146 else | |
1147 f = NULL; | |
1148 } | |
1149 #undef SYM_OFFSET | |
1150 #endif /* XP_MACOSX && USE_MACH_DYLD */ | |
1151 | |
1152 #ifdef XP_BEOS | |
1153 if( B_NO_ERROR != get_image_symbol( (image_id)lm->dlh, name, B_SYMBOL_TYPE_TEXT, &f ) ) { | |
1154 f = NULL; | |
1155 } | |
1156 #endif | |
1157 | |
1158 #ifdef XP_UNIX | |
1159 #ifdef HAVE_DLL | |
1160 #ifdef USE_DLFCN | |
1161 f = dlsym(lm->dlh, name); | |
1162 #elif defined(USE_HPSHL) | |
1163 if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) { | |
1164 f = NULL; | |
1165 } | |
1166 #elif defined(USE_MACH_DYLD) | |
1167 if (lm->dlh) { | |
1168 NSSymbol symbol; | |
1169 symbol = NSLookupSymbolInModule(lm->dlh, name); | |
1170 if (symbol != NULL) | |
1171 f = NSAddressOfSymbol(symbol); | |
1172 else | |
1173 f = NULL; | |
1174 } | |
1175 #endif | |
1176 #endif /* HAVE_DLL */ | |
1177 #endif /* XP_UNIX */ | |
1178 if (f == NULL) { | |
1179 PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO()); | |
1180 DLLErrorInternal(_MD_ERRNO()); | |
1181 } | |
1182 return f; | |
1183 } | |
1184 | |
1185 /* | |
1186 ** Called by class loader to resolve missing native's | |
1187 */ | |
1188 PR_IMPLEMENT(void*) | |
1189 PR_FindSymbol(PRLibrary *lib, const char *raw_name) | |
1190 { | |
1191 void *f = NULL; | |
1192 #if defined(NEED_LEADING_UNDERSCORE) | |
1193 char *name; | |
1194 #else | |
1195 const char *name; | |
1196 #endif | |
1197 /* | |
1198 ** Mangle the raw symbol name in any way that is platform specific. | |
1199 */ | |
1200 #if defined(NEED_LEADING_UNDERSCORE) | |
1201 /* Need a leading _ */ | |
1202 name = PR_smprintf("_%s", raw_name); | |
1203 #elif defined(AIX) | |
1204 /* | |
1205 ** AIX with the normal linker put's a "." in front of the symbol | |
1206 ** name. When use "svcc" and "svld" then the "." disappears. Go | |
1207 ** figure. | |
1208 */ | |
1209 name = raw_name; | |
1210 #else | |
1211 name = raw_name; | |
1212 #endif | |
1213 | |
1214 PR_EnterMonitor(pr_linker_lock); | |
1215 PR_ASSERT(lib != NULL); | |
1216 f = pr_FindSymbolInLib(lib, name); | |
1217 | |
1218 #if defined(NEED_LEADING_UNDERSCORE) | |
1219 PR_smprintf_free(name); | |
1220 #endif | |
1221 | |
1222 PR_ExitMonitor(pr_linker_lock); | |
1223 return f; | |
1224 } | |
1225 | |
1226 /* | |
1227 ** Return the address of the function 'raw_name' in the library 'lib' | |
1228 */ | |
1229 PR_IMPLEMENT(PRFuncPtr) | |
1230 PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name) | |
1231 { | |
1232 return ((PRFuncPtr) PR_FindSymbol(lib, raw_name)); | |
1233 } | |
1234 | |
1235 PR_IMPLEMENT(void*) | |
1236 PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) | |
1237 { | |
1238 void *f = NULL; | |
1239 #if defined(NEED_LEADING_UNDERSCORE) | |
1240 char *name; | |
1241 #else | |
1242 const char *name; | |
1243 #endif | |
1244 PRLibrary* lm; | |
1245 | |
1246 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
1247 /* | |
1248 ** Mangle the raw symbol name in any way that is platform specific. | |
1249 */ | |
1250 #if defined(NEED_LEADING_UNDERSCORE) | |
1251 /* Need a leading _ */ | |
1252 name = PR_smprintf("_%s", raw_name); | |
1253 #elif defined(AIX) | |
1254 /* | |
1255 ** AIX with the normal linker put's a "." in front of the symbol | |
1256 ** name. When use "svcc" and "svld" then the "." disappears. Go | |
1257 ** figure. | |
1258 */ | |
1259 name = raw_name; | |
1260 #else | |
1261 name = raw_name; | |
1262 #endif | |
1263 | |
1264 PR_EnterMonitor(pr_linker_lock); | |
1265 | |
1266 /* search all libraries */ | |
1267 for (lm = pr_loadmap; lm != NULL; lm = lm->next) { | |
1268 f = pr_FindSymbolInLib(lm, name); | |
1269 if (f != NULL) { | |
1270 *lib = lm; | |
1271 lm->refCount++; | |
1272 PR_LOG(_pr_linker_lm, PR_LOG_MIN, | |
1273 ("%s incr => %d (for %s)", | |
1274 lm->name, lm->refCount, name)); | |
1275 break; | |
1276 } | |
1277 } | |
1278 #if defined(NEED_LEADING_UNDERSCORE) | |
1279 PR_smprintf_free(name); | |
1280 #endif | |
1281 | |
1282 PR_ExitMonitor(pr_linker_lock); | |
1283 return f; | |
1284 } | |
1285 | |
1286 PR_IMPLEMENT(PRFuncPtr) | |
1287 PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) | |
1288 { | |
1289 return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib)); | |
1290 } | |
1291 | |
1292 /* | |
1293 ** Add a static library to the list of loaded libraries. If LoadLibrary | |
1294 ** is called with the name then we will pretend it was already loaded | |
1295 */ | |
1296 PR_IMPLEMENT(PRLibrary*) | |
1297 PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt) | |
1298 { | |
1299 PRLibrary *lm=NULL; | |
1300 PRLibrary* result = NULL; | |
1301 | |
1302 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
1303 | |
1304 /* See if library is already loaded */ | |
1305 PR_EnterMonitor(pr_linker_lock); | |
1306 | |
1307 /* If the lbrary is already loaded, then add the static table information... */ | |
1308 result = pr_UnlockedFindLibrary(name); | |
1309 if (result != NULL) { | |
1310 PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) ); | |
1311 result->staticTable = slt; | |
1312 goto unlock; | |
1313 } | |
1314 | |
1315 /* Add library to list...Mark it static */ | |
1316 lm = PR_NEWZAP(PRLibrary); | |
1317 if (lm == NULL) goto unlock; | |
1318 | |
1319 lm->name = strdup(name); | |
1320 lm->refCount = 1; | |
1321 lm->dlh = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0; | |
1322 lm->staticTable = slt; | |
1323 lm->next = pr_loadmap; | |
1324 pr_loadmap = lm; | |
1325 | |
1326 result = lm; /* success */ | |
1327 PR_ASSERT(lm->refCount == 1); | |
1328 PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name)); | |
1329 unlock: | |
1330 PR_ExitMonitor(pr_linker_lock); | |
1331 return result; | |
1332 } | |
1333 | |
1334 PR_IMPLEMENT(char *) | |
1335 PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr) | |
1336 { | |
1337 #if defined(USE_DLFCN) && defined(HAVE_DLADDR) | |
1338 Dl_info dli; | |
1339 char *result; | |
1340 | |
1341 if (dladdr((void *)addr, &dli) == 0) { | |
1342 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); | |
1343 DLLErrorInternal(_MD_ERRNO()); | |
1344 return NULL; | |
1345 } | |
1346 result = PR_Malloc(strlen(dli.dli_fname)+1); | |
1347 if (result != NULL) { | |
1348 strcpy(result, dli.dli_fname); | |
1349 } | |
1350 return result; | |
1351 #elif defined(USE_MACH_DYLD) | |
1352 char *result; | |
1353 const char *image_name; | |
1354 int i, count = _dyld_image_count(); | |
1355 | |
1356 for (i = 0; i < count; i++) { | |
1357 image_name = _dyld_get_image_name(i); | |
1358 if (strstr(image_name, name) != NULL) { | |
1359 result = PR_Malloc(strlen(image_name)+1); | |
1360 if (result != NULL) { | |
1361 strcpy(result, image_name); | |
1362 } | |
1363 return result; | |
1364 } | |
1365 } | |
1366 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); | |
1367 return NULL; | |
1368 #elif defined(AIX) | |
1369 char *result; | |
1370 #define LD_INFO_INCREMENT 64 | |
1371 struct ld_info *info; | |
1372 unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info); | |
1373 struct ld_info *infop; | |
1374 int loadflags = L_GETINFO | L_IGNOREUNLOAD; | |
1375 | |
1376 for (;;) { | |
1377 info = PR_Malloc(info_length); | |
1378 if (info == NULL) { | |
1379 return NULL; | |
1380 } | |
1381 /* If buffer is too small, loadquery fails with ENOMEM. */ | |
1382 if (loadquery(loadflags, info, info_length) != -1) { | |
1383 break; | |
1384 } | |
1385 /* | |
1386 * Calling loadquery when compiled for 64-bit with the | |
1387 * L_IGNOREUNLOAD flag can cause an invalid argument error | |
1388 * on AIX 5.1. Detect this error the first time that | |
1389 * loadquery is called, and try calling it again without | |
1390 * this flag set. | |
1391 */ | |
1392 if (errno == EINVAL && (loadflags & L_IGNOREUNLOAD)) { | |
1393 loadflags &= ~L_IGNOREUNLOAD; | |
1394 if (loadquery(loadflags, info, info_length) != -1) { | |
1395 break; | |
1396 } | |
1397 } | |
1398 PR_Free(info); | |
1399 if (errno != ENOMEM) { | |
1400 /* should not happen */ | |
1401 _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); | |
1402 return NULL; | |
1403 } | |
1404 /* retry with a larger buffer */ | |
1405 info_length += LD_INFO_INCREMENT * sizeof(struct ld_info); | |
1406 } | |
1407 | |
1408 for (infop = info; | |
1409 ; | |
1410 infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) { | |
1411 unsigned long start = (unsigned long)infop->ldinfo_dataorg; | |
1412 unsigned long end = start + infop->ldinfo_datasize; | |
1413 if (start <= (unsigned long)addr && end > (unsigned long)addr) { | |
1414 result = PR_Malloc(strlen(infop->ldinfo_filename)+1); | |
1415 if (result != NULL) { | |
1416 strcpy(result, infop->ldinfo_filename); | |
1417 } | |
1418 break; | |
1419 } | |
1420 if (!infop->ldinfo_next) { | |
1421 PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); | |
1422 result = NULL; | |
1423 break; | |
1424 } | |
1425 } | |
1426 PR_Free(info); | |
1427 return result; | |
1428 #elif defined(OSF1) | |
1429 /* Contributed by Steve Streeter of HP */ | |
1430 ldr_process_t process, ldr_my_process(); | |
1431 ldr_module_t mod_id; | |
1432 ldr_module_info_t info; | |
1433 ldr_region_t regno; | |
1434 ldr_region_info_t reginfo; | |
1435 size_t retsize; | |
1436 int rv; | |
1437 char *result; | |
1438 | |
1439 /* Get process for which dynamic modules will be listed */ | |
1440 | |
1441 process = ldr_my_process(); | |
1442 | |
1443 /* Attach to process */ | |
1444 | |
1445 rv = ldr_xattach(process); | |
1446 if (rv) { | |
1447 /* should not happen */ | |
1448 _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); | |
1449 return NULL; | |
1450 } | |
1451 | |
1452 /* Print information for list of modules */ | |
1453 | |
1454 mod_id = LDR_NULL_MODULE; | |
1455 | |
1456 for (;;) { | |
1457 | |
1458 /* Get information for the next module in the module list. */ | |
1459 | |
1460 ldr_next_module(process, &mod_id); | |
1461 if (ldr_inq_module(process, mod_id, &info, sizeof(info), | |
1462 &retsize) != 0) { | |
1463 /* No more modules */ | |
1464 break; | |
1465 } | |
1466 if (retsize < sizeof(info)) { | |
1467 continue; | |
1468 } | |
1469 | |
1470 /* | |
1471 * Get information for each region in the module and check if any | |
1472 * contain the address of this function. | |
1473 */ | |
1474 | |
1475 for (regno = 0; ; regno++) { | |
1476 if (ldr_inq_region(process, mod_id, regno, ®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 } |