nsprpub/pr/src/linking/prlink.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

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

mercurial