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