~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr/dso/aix/dso.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
 
2
 * applicable.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
/*
 
18
 *  dso.c -- DSO system function emulation for AIX
 
19
 *
 
20
 *  This is *only* intended for AIX < 4.3.
 
21
 */
 
22
 
 
23
/*
 
24
 *  Based on libdl (dlfcn.c/dlfcn.h) which is
 
25
 *  Copyright (c) 1992,1993,1995,1996,1997,1988
 
26
 *  Jens-Uwe Mager, Helios Software GmbH, Hannover, Germany.
 
27
 *
 
28
 *  Not derived from licensed software.
 
29
 *
 
30
 *  Permission is granted to freely use, copy, modify, and redistribute
 
31
 *  this software, provided that the author is not construed to be liable
 
32
 *  for any results of using the software, alterations are clearly marked
 
33
 *  as such, and this notice is not modified.
 
34
 *
 
35
 *  Changes marked with `--jwe' were made on April 7 1996 by
 
36
 *  John W. Eaton <jwe@bevo.che.wisc.edu> to support g++ 
 
37
 *
 
38
 *  Bundled, stripped and adjusted on April 1998 as one single source file 
 
39
 *  for inclusion into the Apache HTTP server by 
 
40
 *  Ralf S. Engelschall <rse@apache.org>
 
41
 *
 
42
 *  Added to APR by David Reid April 2000
 
43
 */
 
44
 
 
45
#include <stdio.h>
 
46
#include <errno.h>
 
47
#include <string.h>
 
48
#include <stdlib.h>
 
49
#include <sys/types.h>
 
50
#include <sys/ldr.h>
 
51
#include <a.out.h>
 
52
#include "apr_arch_dso.h"
 
53
#include "apr_portable.h"
 
54
 
 
55
#if APR_HAS_DSO
 
56
 
 
57
#undef FREAD
 
58
#undef FWRITE
 
59
#include <ldfcn.h>
 
60
 
 
61
/*
 
62
 * AIX 4.3 does remove some useful definitions from ldfcn.h. Define
 
63
 * these here to compensate for that lossage.
 
64
 */
 
65
#ifndef BEGINNING
 
66
#define BEGINNING SEEK_SET
 
67
#endif
 
68
#ifndef FSEEK
 
69
#define FSEEK(ldptr,o,p)   fseek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr) +o):o,p)
 
70
#endif
 
71
#ifndef FREAD
 
72
#define FREAD(p,s,n,ldptr) fread(p,s,n,IOPTR(ldptr))
 
73
#endif
 
74
 
 
75
/*
 
76
 * Mode flags for the dlopen routine.
 
77
 */
 
78
#undef  RTLD_LAZY
 
79
#define RTLD_LAZY       1       /* lazy function call binding */
 
80
#undef  RTLD_NOW
 
81
#define RTLD_NOW        2       /* immediate function call binding */
 
82
#undef  RTLD_GLOBAL
 
83
#define RTLD_GLOBAL     0x100   /* allow symbols to be global */
 
84
 
 
85
/*
 
86
 * To be able to initialize, a library may provide a dl_info structure
 
87
 * that contains functions to be called to initialize and terminate.
 
88
 */
 
89
struct dl_info {
 
90
    void (*init) (void);
 
91
    void (*fini) (void);
 
92
};
 
93
 
 
94
/* APR functions...
 
95
 *
 
96
 * As the AIX functions have been declared in the header file we just
 
97
 * add the basic "wrappers" here.
 
98
 */
 
99
 
 
100
APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso,
 
101
                                                apr_os_dso_handle_t osdso,
 
102
                                                apr_pool_t *pool)
 
103
{
 
104
    *aprdso = apr_pcalloc(pool, sizeof **aprdso);
 
105
    (*aprdso)->handle = osdso;
 
106
    (*aprdso)->pool = pool;
 
107
    return APR_SUCCESS;
 
108
}
 
109
 
 
110
APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso,
 
111
                                                apr_dso_handle_t *aprdso)
 
112
{
 
113
    *osdso = aprdso->handle;
 
114
    return APR_SUCCESS;
 
115
}
 
116
 
 
117
static apr_status_t dso_cleanup(void *thedso)
 
118
{
 
119
    apr_dso_handle_t *dso = thedso;
 
120
 
 
121
    if (dso->handle != NULL && dlclose(dso->handle) != 0)
 
122
        return APR_EINIT;
 
123
    dso->handle = NULL;
 
124
 
 
125
    return APR_SUCCESS;
 
126
}
 
127
 
 
128
APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, 
 
129
                                       const char *path, apr_pool_t *ctx)
 
130
{
 
131
    void *os_handle = dlopen((char *)path, RTLD_NOW | RTLD_GLOBAL);
 
132
 
 
133
    *res_handle = apr_pcalloc(ctx, sizeof(*res_handle));
 
134
 
 
135
    if(os_handle == NULL) {
 
136
        (*res_handle)->errormsg = dlerror();       
 
137
        return APR_EDSOOPEN;
 
138
    }
 
139
 
 
140
    (*res_handle)->handle = (void*)os_handle;
 
141
    (*res_handle)->pool = ctx;
 
142
    (*res_handle)->errormsg = NULL;
 
143
 
 
144
    apr_pool_cleanup_register(ctx, *res_handle, dso_cleanup, apr_pool_cleanup_null);
 
145
 
 
146
    return APR_SUCCESS;
 
147
}
 
148
 
 
149
APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle)
 
150
{
 
151
    return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup);
 
152
}
 
153
 
 
154
APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, 
 
155
                                      apr_dso_handle_t *handle, 
 
156
                                      const char *symname)
 
157
{
 
158
    void *retval = dlsym(handle->handle, symname);
 
159
 
 
160
    if (retval == NULL) {
 
161
        handle->errormsg = dlerror();
 
162
        return APR_ESYMNOTFOUND;
 
163
    }
 
164
 
 
165
    *ressym = retval;
 
166
    return APR_SUCCESS;
 
167
}
 
168
 
 
169
APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, apr_size_t buflen)
 
170
{
 
171
    if (dso->errormsg) {
 
172
        apr_cpystrn(buffer, dso->errormsg, buflen);
 
173
        return dso->errormsg;
 
174
    }
 
175
    return "No Error";
 
176
}
 
177
 
 
178
 
 
179
 
 
180
/*
 
181
 * We simulate dlopen() et al. through a call to load. Because AIX has
 
182
 * no call to find an exported symbol we read the loader section of the
 
183
 * loaded module and build a list of exported symbols and their virtual
 
184
 * address.
 
185
 */
 
186
 
 
187
typedef struct {
 
188
    char *name;                 /* the symbols's name */
 
189
    void *addr;                 /* its relocated virtual address */
 
190
} Export, *ExportPtr;
 
191
 
 
192
/*
 
193
 * xlC uses the following structure to list its constructors and
 
194
 * destructors. This is gleaned from the output of munch.
 
195
 */
 
196
typedef struct {
 
197
    void (*init) (void);        /* call static constructors */
 
198
    void (*term) (void);        /* call static destructors */
 
199
} Cdtor, *CdtorPtr;
 
200
 
 
201
typedef void (*GccCDtorPtr) (void);
 
202
 
 
203
/*
 
204
 * The void * handle returned from dlopen is actually a ModulePtr.
 
205
 */
 
206
typedef struct Module {
 
207
    struct Module *next;
 
208
    char *name;                 /* module name for refcounting */
 
209
    int refCnt;                 /* the number of references */
 
210
    void *entry;                /* entry point from load */
 
211
    struct dl_info *info;       /* optional init/terminate functions */
 
212
    CdtorPtr cdtors;            /* optional C++ constructors */
 
213
    GccCDtorPtr gcc_ctor;       /* g++ constructors  --jwe */
 
214
    GccCDtorPtr gcc_dtor;       /* g++ destructors  --jwe */
 
215
    int nExports;               /* the number of exports found */
 
216
    ExportPtr exports;          /* the array of exports */
 
217
} Module, *ModulePtr;
 
218
 
 
219
/*
 
220
 * We keep a list of all loaded modules to be able to call the fini
 
221
 * handlers and destructors at atexit() time.
 
222
 */
 
223
static ModulePtr modList;
 
224
 
 
225
/*
 
226
 * The last error from one of the dl* routines is kept in static
 
227
 * variables here. Each error is returned only once to the caller.
 
228
 */
 
229
static char errbuf[BUFSIZ];
 
230
static int errvalid;
 
231
 
 
232
/*
 
233
 * The `fixed' gcc header files on AIX 3.2.5 provide a prototype for
 
234
 * strdup().  --jwe
 
235
 */
 
236
extern char *strdup(const char *);
 
237
static void caterr(char *);
 
238
static int readExports(ModulePtr);
 
239
static void terminate(void);
 
240
static void *findMain(void);
 
241
 
 
242
void *dlopen(const char *path, int mode)
 
243
{
 
244
    register ModulePtr mp;
 
245
    static void *mainModule;
 
246
 
 
247
    /*
 
248
     * Upon the first call register a terminate handler that will
 
249
     * close all libraries. Also get a reference to the main module
 
250
     * for use with loadbind.
 
251
     */
 
252
    if (!mainModule) {
 
253
        if ((mainModule = findMain()) == NULL)
 
254
            return NULL;
 
255
        atexit(terminate);
 
256
    }
 
257
    /*
 
258
     * Scan the list of modules if we have the module already loaded.
 
259
     */
 
260
    for (mp = modList; mp; mp = mp->next)
 
261
        if (strcmp(mp->name, path) == 0) {
 
262
            mp->refCnt++;
 
263
            return mp;
 
264
        }
 
265
    if ((mp = (ModulePtr) calloc(1, sizeof(*mp))) == NULL) {
 
266
        errvalid++;
 
267
        strcpy(errbuf, "calloc: ");
 
268
        strcat(errbuf, strerror(errno));
 
269
        return NULL;
 
270
    }
 
271
    if ((mp->name = strdup(path)) == NULL) {
 
272
        errvalid++;
 
273
        strcpy(errbuf, "strdup: ");
 
274
        strcat(errbuf, strerror(errno));
 
275
        free(mp);
 
276
        return NULL;
 
277
    }
 
278
    /*
 
279
     * load should be declared load(const char *...). Thus we
 
280
     * cast the path to a normal char *. Ugly.
 
281
     */
 
282
    if ((mp->entry = (void *) loadAndInit((char *) path, L_NOAUTODEFER, NULL)) == NULL) {
 
283
        free(mp->name);
 
284
        free(mp);
 
285
        errvalid++;
 
286
        strcpy(errbuf, "dlopen: ");
 
287
        strcat(errbuf, path);
 
288
        strcat(errbuf, ": ");
 
289
        /*
 
290
         * If AIX says the file is not executable, the error
 
291
         * can be further described by querying the loader about
 
292
         * the last error.
 
293
         */
 
294
        if (errno == ENOEXEC) {
 
295
            char *tmp[BUFSIZ / sizeof(char *)];
 
296
            if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
 
297
                strcpy(errbuf, strerror(errno));
 
298
            else {
 
299
                char **p;
 
300
                for (p = tmp; *p; p++)
 
301
                    caterr(*p);
 
302
            }
 
303
        }
 
304
        else
 
305
            strcat(errbuf, strerror(errno));
 
306
        return NULL;
 
307
    }
 
308
    mp->refCnt = 1;
 
309
    mp->next = modList;
 
310
    modList = mp;
 
311
    if (loadbind(0, mainModule, mp->entry) == -1) {
 
312
        dlclose(mp);
 
313
        errvalid++;
 
314
        strcpy(errbuf, "loadbind: ");
 
315
        strcat(errbuf, strerror(errno));
 
316
        return NULL;
 
317
    }
 
318
    /*
 
319
     * If the user wants global binding, loadbind against all other
 
320
     * loaded modules.
 
321
     */
 
322
    if (mode & RTLD_GLOBAL) {
 
323
        register ModulePtr mp1;
 
324
        for (mp1 = mp->next; mp1; mp1 = mp1->next)
 
325
            if (loadbind(0, mp1->entry, mp->entry) == -1) {
 
326
                dlclose(mp);
 
327
                errvalid++;
 
328
                strcpy(errbuf, "loadbind: ");
 
329
                strcat(errbuf, strerror(errno));
 
330
                return NULL;
 
331
            }
 
332
    }
 
333
    if (readExports(mp) == -1) {
 
334
        dlclose(mp);
 
335
        return NULL;
 
336
    }
 
337
    /*
 
338
     * If there is a dl_info structure, call the init function.
 
339
     */
 
340
    if (mp->info = (struct dl_info *) dlsym(mp, "dl_info")) {
 
341
        if (mp->info->init)
 
342
            (*mp->info->init) ();
 
343
    }
 
344
    else
 
345
        errvalid = 0;
 
346
    /*
 
347
     * If the shared object was compiled using xlC we will need
 
348
     * to call static constructors (and later on dlclose destructors).
 
349
     */
 
350
    if (mp->cdtors = (CdtorPtr) dlsym(mp, "__cdtors")) {
 
351
        CdtorPtr cp = mp->cdtors;
 
352
        while (cp->init || cp->term) {
 
353
            if (cp->init && cp->init != (void (*)(void)) 0xffffffff)
 
354
                (*cp->init) ();
 
355
            cp++;
 
356
        }
 
357
        /*
 
358
         * If the shared object was compiled using g++, we will need
 
359
         * to call global constructors using the _GLOBAL__DI function,
 
360
         * and later, global destructors using the _GLOBAL_DD
 
361
         * funciton.  --jwe
 
362
         */
 
363
    }
 
364
    else if (mp->gcc_ctor = (GccCDtorPtr) dlsym(mp, "_GLOBAL__DI")) {
 
365
        (*mp->gcc_ctor) ();
 
366
        mp->gcc_dtor = (GccCDtorPtr) dlsym(mp, "_GLOBAL__DD");
 
367
    }
 
368
    else
 
369
        errvalid = 0;
 
370
    return mp;
 
371
}
 
372
 
 
373
/*
 
374
 * Attempt to decipher an AIX loader error message and append it
 
375
 * to our static error message buffer.
 
376
 */
 
377
static void caterr(char *s)
 
378
{
 
379
    register char *p = s;
 
380
 
 
381
    while (*p >= '0' && *p <= '9')
 
382
        p++;
 
383
    switch (atoi(s)) {
 
384
    case L_ERROR_TOOMANY:
 
385
        strcat(errbuf, "to many errors");
 
386
        break;
 
387
    case L_ERROR_NOLIB:
 
388
        strcat(errbuf, "can't load library");
 
389
        strcat(errbuf, p);
 
390
        break;
 
391
    case L_ERROR_UNDEF:
 
392
        strcat(errbuf, "can't find symbol");
 
393
        strcat(errbuf, p);
 
394
        break;
 
395
    case L_ERROR_RLDBAD:
 
396
        strcat(errbuf, "bad RLD");
 
397
        strcat(errbuf, p);
 
398
        break;
 
399
    case L_ERROR_FORMAT:
 
400
        strcat(errbuf, "bad exec format in");
 
401
        strcat(errbuf, p);
 
402
        break;
 
403
    case L_ERROR_ERRNO:
 
404
        strcat(errbuf, strerror(atoi(++p)));
 
405
        break;
 
406
    default:
 
407
        strcat(errbuf, s);
 
408
        break;
 
409
    }
 
410
}
 
411
 
 
412
void *dlsym(void *handle, const char *symbol)
 
413
{
 
414
    register ModulePtr mp = (ModulePtr) handle;
 
415
    register ExportPtr ep;
 
416
    register int i;
 
417
 
 
418
    /*
 
419
     * Could speed up the search, but I assume that one assigns
 
420
     * the result to function pointers anyways.
 
421
     */
 
422
    for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
 
423
        if (strcmp(ep->name, symbol) == 0)
 
424
            return ep->addr;
 
425
    errvalid++;
 
426
    strcpy(errbuf, "dlsym: undefined symbol ");
 
427
    strcat(errbuf, symbol);
 
428
    return NULL;
 
429
}
 
430
 
 
431
const char *dlerror(void)
 
432
{
 
433
    if (errvalid) {
 
434
        errvalid = 0;
 
435
        return errbuf;
 
436
    }
 
437
    return NULL;
 
438
}
 
439
 
 
440
int dlclose(void *handle)
 
441
{
 
442
    register ModulePtr mp = (ModulePtr) handle;
 
443
    int result;
 
444
    register ModulePtr mp1;
 
445
 
 
446
    if (--mp->refCnt > 0)
 
447
        return 0;
 
448
    if (mp->info && mp->info->fini)
 
449
        (*mp->info->fini) ();
 
450
    if (mp->cdtors) {
 
451
        CdtorPtr cp = mp->cdtors;
 
452
        while (cp->init || cp->term) {
 
453
            if (cp->term && cp->init != (void (*)(void)) 0xffffffff)
 
454
                (*cp->term) ();
 
455
            cp++;
 
456
        }
 
457
        /*
 
458
         * If the function to handle global destructors for g++
 
459
         * exists, call it.  --jwe
 
460
         */
 
461
    }
 
462
    else if (mp->gcc_dtor) {
 
463
        (*mp->gcc_dtor) ();
 
464
    }
 
465
    result = unload(mp->entry);
 
466
    if (result == -1) {
 
467
        errvalid++;
 
468
        strcpy(errbuf, strerror(errno));
 
469
    }
 
470
    if (mp->exports) {
 
471
        register ExportPtr ep;
 
472
        register int i;
 
473
        for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
 
474
            if (ep->name)
 
475
                free(ep->name);
 
476
        free(mp->exports);
 
477
    }
 
478
    if (mp == modList)
 
479
        modList = mp->next;
 
480
    else {
 
481
        for (mp1 = modList; mp1; mp1 = mp1->next)
 
482
            if (mp1->next == mp) {
 
483
                mp1->next = mp->next;
 
484
                break;
 
485
            }
 
486
    }
 
487
    free(mp->name);
 
488
    free(mp);
 
489
    return result;
 
490
}
 
491
 
 
492
static void terminate(void)
 
493
{
 
494
    while (modList)
 
495
        dlclose(modList);
 
496
}
 
497
 
 
498
/*
 
499
 * Build the export table from the XCOFF .loader section.
 
500
 */
 
501
static int readExports(ModulePtr mp)
 
502
{
 
503
    LDFILE *ldp = NULL;
 
504
    SCNHDR sh, shdata;
 
505
    LDHDR *lhp;
 
506
    char *ldbuf;
 
507
    LDSYM *ls;
 
508
    int i;
 
509
    ExportPtr ep;
 
510
    struct ld_info *lp;
 
511
    char *buf;
 
512
    int size = 4 * 1024;
 
513
    void *dataorg;
 
514
 
 
515
    /*
 
516
     * The module might be loaded due to the LIBPATH
 
517
     * environment variable. Search for the loaded
 
518
     * module using L_GETINFO.
 
519
     */
 
520
    if ((buf = malloc(size)) == NULL) {
 
521
        errvalid++;
 
522
        strcpy(errbuf, "readExports: ");
 
523
        strcat(errbuf, strerror(errno));
 
524
        return -1;
 
525
    }
 
526
    while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
 
527
        free(buf);
 
528
        size += 4 * 1024;
 
529
        if ((buf = malloc(size)) == NULL) {
 
530
            errvalid++;
 
531
            strcpy(errbuf, "readExports: ");
 
532
            strcat(errbuf, strerror(errno));
 
533
            return -1;
 
534
        }
 
535
    }
 
536
    if (i == -1) {
 
537
        errvalid++;
 
538
        strcpy(errbuf, "readExports: ");
 
539
        strcat(errbuf, strerror(errno));
 
540
        free(buf);
 
541
        return -1;
 
542
    }
 
543
    /*
 
544
     * Traverse the list of loaded modules. The entry point
 
545
     * returned by load() does actually point to the TOC
 
546
     * entry contained in the data segment.
 
547
     */
 
548
    lp = (struct ld_info *) buf;
 
549
    while (lp) {
 
550
        if ((unsigned long) mp->entry >= (unsigned long) lp->ldinfo_dataorg &&
 
551
            (unsigned long) mp->entry < (unsigned long) lp->ldinfo_dataorg +
 
552
            lp->ldinfo_datasize) {
 
553
            dataorg = lp->ldinfo_dataorg;
 
554
            ldp = ldopen(lp->ldinfo_filename, ldp);
 
555
            break;
 
556
        }
 
557
        if (lp->ldinfo_next == 0)
 
558
            lp = NULL;
 
559
        else
 
560
            lp = (struct ld_info *) ((char *) lp + lp->ldinfo_next);
 
561
    }
 
562
    free(buf);
 
563
    if (!ldp) {
 
564
        errvalid++;
 
565
        strcpy(errbuf, "readExports: ");
 
566
        strcat(errbuf, strerror(errno));
 
567
        return -1;
 
568
    }
 
569
    if (TYPE(ldp) != U802TOCMAGIC) {
 
570
        errvalid++;
 
571
        strcpy(errbuf, "readExports: bad magic");
 
572
        while (ldclose(ldp) == FAILURE);
 
573
        return -1;
 
574
    }
 
575
    /*
 
576
     * Get the padding for the data section. This is needed for
 
577
     * AIX 4.1 compilers. This is used when building the final
 
578
     * function pointer to the exported symbol.
 
579
     */
 
580
    if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
 
581
        errvalid++;
 
582
        strcpy(errbuf, "readExports: cannot read data section header");
 
583
        while (ldclose(ldp) == FAILURE);
 
584
        return -1;
 
585
    }
 
586
    if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
 
587
        errvalid++;
 
588
        strcpy(errbuf, "readExports: cannot read loader section header");
 
589
        while (ldclose(ldp) == FAILURE);
 
590
        return -1;
 
591
    }
 
592
    /*
 
593
     * We read the complete loader section in one chunk, this makes
 
594
     * finding long symbol names residing in the string table easier.
 
595
     */
 
596
    if ((ldbuf = (char *) malloc(sh.s_size)) == NULL) {
 
597
        errvalid++;
 
598
        strcpy(errbuf, "readExports: ");
 
599
        strcat(errbuf, strerror(errno));
 
600
        while (ldclose(ldp) == FAILURE);
 
601
        return -1;
 
602
    }
 
603
    if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
 
604
        errvalid++;
 
605
        strcpy(errbuf, "readExports: cannot seek to loader section");
 
606
        free(ldbuf);
 
607
        while (ldclose(ldp) == FAILURE);
 
608
        return -1;
 
609
    }
 
610
    if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
 
611
        errvalid++;
 
612
        strcpy(errbuf, "readExports: cannot read loader section");
 
613
        free(ldbuf);
 
614
        while (ldclose(ldp) == FAILURE);
 
615
        return -1;
 
616
    }
 
617
    lhp = (LDHDR *) ldbuf;
 
618
    ls = (LDSYM *) (ldbuf + LDHDRSZ);
 
619
    /*
 
620
     * Count the number of exports to include in our export table.
 
621
     */
 
622
    for (i = lhp->l_nsyms; i; i--, ls++) {
 
623
        if (!LDR_EXPORT(*ls))
 
624
            continue;
 
625
        mp->nExports++;
 
626
    }
 
627
    if ((mp->exports = (ExportPtr) calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
 
628
        errvalid++;
 
629
        strcpy(errbuf, "readExports: ");
 
630
        strcat(errbuf, strerror(errno));
 
631
        free(ldbuf);
 
632
        while (ldclose(ldp) == FAILURE);
 
633
        return -1;
 
634
    }
 
635
    /*
 
636
     * Fill in the export table. All entries are relative to
 
637
     * the beginning of the data origin.
 
638
     */
 
639
    ep = mp->exports;
 
640
    ls = (LDSYM *) (ldbuf + LDHDRSZ);
 
641
    for (i = lhp->l_nsyms; i; i--, ls++) {
 
642
        char *symname;
 
643
        char tmpsym[SYMNMLEN + 1];
 
644
        if (!LDR_EXPORT(*ls))
 
645
            continue;
 
646
        if (ls->l_zeroes == 0)
 
647
            symname = ls->l_offset + lhp->l_stoff + ldbuf;
 
648
        else {
 
649
            /*
 
650
             * The l_name member is not zero terminated, we
 
651
             * must copy the first SYMNMLEN chars and make
 
652
             * sure we have a zero byte at the end.
 
653
             */
 
654
            strncpy(tmpsym, ls->l_name, SYMNMLEN);
 
655
            tmpsym[SYMNMLEN] = '\0';
 
656
            symname = tmpsym;
 
657
        }
 
658
        ep->name = strdup(symname);
 
659
        ep->addr = (void *) ((unsigned long) dataorg +
 
660
                             ls->l_value - shdata.s_vaddr);
 
661
        ep++;
 
662
    }
 
663
    free(ldbuf);
 
664
    while (ldclose(ldp) == FAILURE);
 
665
    return 0;
 
666
}
 
667
 
 
668
/*
 
669
 * Find the main modules data origin. This is used as export pointer
 
670
 * for loadbind() to be able to resolve references to the main part.
 
671
 */
 
672
static void *findMain(void)
 
673
{
 
674
    struct ld_info *lp;
 
675
    char *buf;
 
676
    int size = 4 * 1024;
 
677
    int i;
 
678
    void *ret;
 
679
 
 
680
    if ((buf = malloc(size)) == NULL) {
 
681
        errvalid++;
 
682
        strcpy(errbuf, "findMain: ");
 
683
        strcat(errbuf, strerror(errno));
 
684
        return NULL;
 
685
    }
 
686
    while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
 
687
        free(buf);
 
688
        size += 4 * 1024;
 
689
        if ((buf = malloc(size)) == NULL) {
 
690
            errvalid++;
 
691
            strcpy(errbuf, "findMain: ");
 
692
            strcat(errbuf, strerror(errno));
 
693
            return NULL;
 
694
        }
 
695
    }
 
696
    if (i == -1) {
 
697
        errvalid++;
 
698
        strcpy(errbuf, "findMain: ");
 
699
        strcat(errbuf, strerror(errno));
 
700
        free(buf);
 
701
        return NULL;
 
702
    }
 
703
    /*
 
704
     * The first entry is the main module. The data segment
 
705
     * starts with the TOC entries for all exports, so the
 
706
     * data segment origin works as argument for loadbind.
 
707
     */
 
708
    lp = (struct ld_info *) buf;
 
709
    ret = lp->ldinfo_dataorg;
 
710
    free(buf);
 
711
    return ret;
 
712
}
 
713
 
 
714
#endif