| OLD | NEW |
| (Empty) |
| 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, 0x
7C0903A6, 0x4E800420 }; | |
| 498 uint32* newGlue = NULL; | |
| 499 | |
| 500 if (tvp != NULL) { | |
| 501 CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEnc
odingASCII); | |
| 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 f
or 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_NOT_REACHED("_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_O
FFSET)); | |
| 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 g
lue. */ | |
| 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_T
EXT, &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->nam
e)); | |
| 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 } | |
| OLD | NEW |