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