Coverage Report

Created: 2025-07-01 06:26

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