Coverage Report

Created: 2024-05-20 06:23

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