OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [unix/] [tclLoadAix.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclLoadAix.c --
3
 *
4
 *      This file implements the dlopen and dlsym APIs under the
5
 *      AIX operating system, to enable the Tcl "load" command to
6
 *      work.  This code was provided by Jens-Uwe Mager.
7
 *
8
 *      This file is subject to the following copyright notice, which is
9
 *      different from the notice used elsewhere in Tcl.  The file has
10
 *      been modified to incorporate the file dlfcn.h in-line.
11
 *
12
 *      Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH
13
 *      Not derived from licensed software.
14
 
15
 *      Permission is granted to freely use, copy, modify, and redistribute
16
 *      this software, provided that the author is not construed to be liable
17
 *      for any results of using the software, alterations are clearly marked
18
 *      as such, and this notice is not modified.
19
 *
20
 * RCS: @(#) $Id: tclLoadAix.c,v 1.1.1.1 2002-01-16 10:25:37 markom Exp $
21
 *
22
 * Note:  this file has been altered from the original in a few
23
 * ways in order to work properly with Tcl.
24
 */
25
 
26
/*
27
 * @(#)dlfcn.c  1.7 revision of 95/08/14  19:08:38
28
 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
29
 * 30159 Hannover, Germany
30
 */
31
 
32
#include <stdio.h>
33
#include <errno.h>
34
#include <string.h>
35
#include <stdlib.h>
36
#include <sys/types.h>
37
#include <sys/ldr.h>
38
#include <a.out.h>
39
#include <ldfcn.h>
40
#include "../compat/dlfcn.h"
41
 
42
/*
43
 * We simulate dlopen() et al. through a call to load. Because AIX has
44
 * no call to find an exported symbol we read the loader section of the
45
 * loaded module and build a list of exported symbols and their virtual
46
 * address.
47
 */
48
 
49
typedef struct {
50
        char            *name;          /* the symbols's name */
51
        void            *addr;          /* its relocated virtual address */
52
} Export, *ExportPtr;
53
 
54
/*
55
 * xlC uses the following structure to list its constructors and
56
 * destructors. This is gleaned from the output of munch.
57
 */
58
typedef struct {
59
        void (*init)(void);             /* call static constructors */
60
        void (*term)(void);             /* call static destructors */
61
} Cdtor, *CdtorPtr;
62
 
63
/*
64
 * The void * handle returned from dlopen is actually a ModulePtr.
65
 */
66
typedef struct Module {
67
        struct Module   *next;
68
        char            *name;          /* module name for refcounting */
69
        int             refCnt;         /* the number of references */
70
        void            *entry;         /* entry point from load */
71
        struct dl_info  *info;          /* optional init/terminate functions */
72
        CdtorPtr        cdtors;         /* optional C++ constructors */
73
        int             nExports;       /* the number of exports found */
74
        ExportPtr       exports;        /* the array of exports */
75
} Module, *ModulePtr;
76
 
77
/*
78
 * We keep a list of all loaded modules to be able to call the fini
79
 * handlers and destructors at atexit() time.
80
 */
81
static ModulePtr modList;
82
 
83
/*
84
 * The last error from one of the dl* routines is kept in static
85
 * variables here. Each error is returned only once to the caller.
86
 */
87
static char errbuf[BUFSIZ];
88
static int errvalid;
89
 
90
static void caterr(char *);
91
static int readExports(ModulePtr);
92
static void terminate(void);
93
static void *findMain(void);
94
 
95
VOID *dlopen(const char *path, int mode)
96
{
97
        register ModulePtr mp;
98
        static void *mainModule;
99
 
100
        /*
101
         * Upon the first call register a terminate handler that will
102
         * close all libraries. Also get a reference to the main module
103
         * for use with loadbind.
104
         */
105
        if (!mainModule) {
106
                if ((mainModule = findMain()) == NULL)
107
                        return NULL;
108
                atexit(terminate);
109
        }
110
        /*
111
         * Scan the list of modules if we have the module already loaded.
112
         */
113
        for (mp = modList; mp; mp = mp->next)
114
                if (strcmp(mp->name, path) == 0) {
115
                        mp->refCnt++;
116
                        return (VOID *) mp;
117
                }
118
        if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) {
119
                errvalid++;
120
                strcpy(errbuf, "calloc: ");
121
                strcat(errbuf, strerror(errno));
122
                return (VOID *) NULL;
123
        }
124
        mp->name = malloc((unsigned) (strlen(path) + 1));
125
        strcpy(mp->name, path);
126
        /*
127
         * load should be declared load(const char *...). Thus we
128
         * cast the path to a normal char *. Ugly.
129
         */
130
        if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
131
                free(mp->name);
132
                free(mp);
133
                errvalid++;
134
                strcpy(errbuf, "dlopen: ");
135
                strcat(errbuf, path);
136
                strcat(errbuf, ": ");
137
                /*
138
                 * If AIX says the file is not executable, the error
139
                 * can be further described by querying the loader about
140
                 * the last error.
141
                 */
142
                if (errno == ENOEXEC) {
143
                        char *tmp[BUFSIZ/sizeof(char *)];
144
                        if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
145
                                strcpy(errbuf, strerror(errno));
146
                        else {
147
                                char **p;
148
                                for (p = tmp; *p; p++)
149
                                        caterr(*p);
150
                        }
151
                } else
152
                        strcat(errbuf, strerror(errno));
153
                return (VOID *) NULL;
154
        }
155
        mp->refCnt = 1;
156
        mp->next = modList;
157
        modList = mp;
158
        if (loadbind(0, mainModule, mp->entry) == -1) {
159
                dlclose(mp);
160
                errvalid++;
161
                strcpy(errbuf, "loadbind: ");
162
                strcat(errbuf, strerror(errno));
163
                return (VOID *) NULL;
164
        }
165
        /*
166
         * If the user wants global binding, loadbind against all other
167
         * loaded modules.
168
         */
169
        if (mode & RTLD_GLOBAL) {
170
                register ModulePtr mp1;
171
                for (mp1 = mp->next; mp1; mp1 = mp1->next)
172
                        if (loadbind(0, mp1->entry, mp->entry) == -1) {
173
                                dlclose(mp);
174
                                errvalid++;
175
                                strcpy(errbuf, "loadbind: ");
176
                                strcat(errbuf, strerror(errno));
177
                                return (VOID *) NULL;
178
                        }
179
        }
180
        if (readExports(mp) == -1) {
181
                dlclose(mp);
182
                return (VOID *) NULL;
183
        }
184
        /*
185
         * If there is a dl_info structure, call the init function.
186
         */
187
        if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {
188
                if (mp->info->init)
189
                        (*mp->info->init)();
190
        } else
191
                errvalid = 0;
192
        /*
193
         * If the shared object was compiled using xlC we will need
194
         * to call static constructors (and later on dlclose destructors).
195
         */
196
        if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) {
197
                while (mp->cdtors->init) {
198
                        (*mp->cdtors->init)();
199
                        mp->cdtors++;
200
                }
201
        } else
202
                errvalid = 0;
203
        return (VOID *) mp;
204
}
205
 
206
/*
207
 * Attempt to decipher an AIX loader error message and append it
208
 * to our static error message buffer.
209
 */
210
static void caterr(char *s)
211
{
212
        register char *p = s;
213
 
214
        while (*p >= '0' && *p <= '9')
215
                p++;
216
        switch(atoi(s)) {
217
        case L_ERROR_TOOMANY:
218
                strcat(errbuf, "to many errors");
219
                break;
220
        case L_ERROR_NOLIB:
221
                strcat(errbuf, "can't load library");
222
                strcat(errbuf, p);
223
                break;
224
        case L_ERROR_UNDEF:
225
                strcat(errbuf, "can't find symbol");
226
                strcat(errbuf, p);
227
                break;
228
        case L_ERROR_RLDBAD:
229
                strcat(errbuf, "bad RLD");
230
                strcat(errbuf, p);
231
                break;
232
        case L_ERROR_FORMAT:
233
                strcat(errbuf, "bad exec format in");
234
                strcat(errbuf, p);
235
                break;
236
        case L_ERROR_ERRNO:
237
                strcat(errbuf, strerror(atoi(++p)));
238
                break;
239
        default:
240
                strcat(errbuf, s);
241
                break;
242
        }
243
}
244
 
245
VOID *dlsym(void *handle, const char *symbol)
246
{
247
        register ModulePtr mp = (ModulePtr)handle;
248
        register ExportPtr ep;
249
        register int i;
250
 
251
        /*
252
         * Could speed up the search, but I assume that one assigns
253
         * the result to function pointers anyways.
254
         */
255
        for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
256
                if (strcmp(ep->name, symbol) == 0)
257
                        return ep->addr;
258
        errvalid++;
259
        strcpy(errbuf, "dlsym: undefined symbol ");
260
        strcat(errbuf, symbol);
261
        return NULL;
262
}
263
 
264
char *dlerror(void)
265
{
266
        if (errvalid) {
267
                errvalid = 0;
268
                return errbuf;
269
        }
270
        return NULL;
271
}
272
 
273
int dlclose(void *handle)
274
{
275
        register ModulePtr mp = (ModulePtr)handle;
276
        int result;
277
        register ModulePtr mp1;
278
 
279
        if (--mp->refCnt > 0)
280
                return 0;
281
        if (mp->info && mp->info->fini)
282
                (*mp->info->fini)();
283
        if (mp->cdtors)
284
                while (mp->cdtors->term) {
285
                        (*mp->cdtors->term)();
286
                        mp->cdtors++;
287
                }
288
        result = unload(mp->entry);
289
        if (result == -1) {
290
                errvalid++;
291
                strcpy(errbuf, strerror(errno));
292
        }
293
        if (mp->exports) {
294
                register ExportPtr ep;
295
                register int i;
296
                for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
297
                        if (ep->name)
298
                                free(ep->name);
299
                free(mp->exports);
300
        }
301
        if (mp == modList)
302
                modList = mp->next;
303
        else {
304
                for (mp1 = modList; mp1; mp1 = mp1->next)
305
                        if (mp1->next == mp) {
306
                                mp1->next = mp->next;
307
                                break;
308
                        }
309
        }
310
        free(mp->name);
311
        free(mp);
312
        return result;
313
}
314
 
315
static void terminate(void)
316
{
317
        while (modList)
318
                dlclose(modList);
319
}
320
 
321
/*
322
 * Build the export table from the XCOFF .loader section.
323
 */
324
static int readExports(ModulePtr mp)
325
{
326
        LDFILE *ldp = NULL;
327
        SCNHDR sh, shdata;
328
        LDHDR *lhp;
329
        char *ldbuf;
330
        LDSYM *ls;
331
        int i;
332
        ExportPtr ep;
333
 
334
        if ((ldp = ldopen(mp->name, ldp)) == NULL) {
335
                struct ld_info *lp;
336
                char *buf;
337
                int size = 4*1024;
338
                if (errno != ENOENT) {
339
                        errvalid++;
340
                        strcpy(errbuf, "readExports: ");
341
                        strcat(errbuf, strerror(errno));
342
                        return -1;
343
                }
344
                /*
345
                 * The module might be loaded due to the LIBPATH
346
                 * environment variable. Search for the loaded
347
                 * module using L_GETINFO.
348
                 */
349
                if ((buf = malloc(size)) == NULL) {
350
                        errvalid++;
351
                        strcpy(errbuf, "readExports: ");
352
                        strcat(errbuf, strerror(errno));
353
                        return -1;
354
                }
355
                while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
356
                        free(buf);
357
                        size += 4*1024;
358
                        if ((buf = malloc(size)) == NULL) {
359
                                errvalid++;
360
                                strcpy(errbuf, "readExports: ");
361
                                strcat(errbuf, strerror(errno));
362
                                return -1;
363
                        }
364
                }
365
                if (i == -1) {
366
                        errvalid++;
367
                        strcpy(errbuf, "readExports: ");
368
                        strcat(errbuf, strerror(errno));
369
                        free(buf);
370
                        return -1;
371
                }
372
                /*
373
                 * Traverse the list of loaded modules. The entry point
374
                 * returned by load() does actually point to the data
375
                 * segment origin.
376
                 */
377
                lp = (struct ld_info *)buf;
378
                while (lp) {
379
                        if (lp->ldinfo_dataorg == mp->entry) {
380
                                ldp = ldopen(lp->ldinfo_filename, ldp);
381
                                break;
382
                        }
383
                        if (lp->ldinfo_next == 0)
384
                                lp = NULL;
385
                        else
386
                                lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
387
                }
388
                free(buf);
389
                if (!ldp) {
390
                        errvalid++;
391
                        strcpy(errbuf, "readExports: ");
392
                        strcat(errbuf, strerror(errno));
393
                        return -1;
394
                }
395
        }
396
        if (TYPE(ldp) != U802TOCMAGIC) {
397
                errvalid++;
398
                strcpy(errbuf, "readExports: bad magic");
399
                while(ldclose(ldp) == FAILURE)
400
                        ;
401
                return -1;
402
        }
403
        /*
404
         * Get the padding for the data section. This is needed for
405
         * AIX 4.1 compilers. This is used when building the final
406
         * function pointer to the exported symbol.
407
         */
408
        if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
409
                errvalid++;
410
                strcpy(errbuf, "readExports: cannot read data section header");
411
                while(ldclose(ldp) == FAILURE)
412
                        ;
413
                return -1;
414
        }
415
        if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
416
                errvalid++;
417
                strcpy(errbuf, "readExports: cannot read loader section header");
418
                while(ldclose(ldp) == FAILURE)
419
                        ;
420
                return -1;
421
        }
422
        /*
423
         * We read the complete loader section in one chunk, this makes
424
         * finding long symbol names residing in the string table easier.
425
         */
426
        if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) {
427
                errvalid++;
428
                strcpy(errbuf, "readExports: ");
429
                strcat(errbuf, strerror(errno));
430
                while(ldclose(ldp) == FAILURE)
431
                        ;
432
                return -1;
433
        }
434
        if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
435
                errvalid++;
436
                strcpy(errbuf, "readExports: cannot seek to loader section");
437
                free(ldbuf);
438
                while(ldclose(ldp) == FAILURE)
439
                        ;
440
                return -1;
441
        }
442
        if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
443
                errvalid++;
444
                strcpy(errbuf, "readExports: cannot read loader section");
445
                free(ldbuf);
446
                while(ldclose(ldp) == FAILURE)
447
                        ;
448
                return -1;
449
        }
450
        lhp = (LDHDR *)ldbuf;
451
        ls = (LDSYM *)(ldbuf+LDHDRSZ);
452
        /*
453
         * Count the number of exports to include in our export table.
454
         */
455
        for (i = lhp->l_nsyms; i; i--, ls++) {
456
                if (!LDR_EXPORT(*ls))
457
                        continue;
458
                mp->nExports++;
459
        }
460
        if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
461
                errvalid++;
462
                strcpy(errbuf, "readExports: ");
463
                strcat(errbuf, strerror(errno));
464
                free(ldbuf);
465
                while(ldclose(ldp) == FAILURE)
466
                        ;
467
                return -1;
468
        }
469
        /*
470
         * Fill in the export table. All entries are relative to
471
         * the entry point we got from load.
472
         */
473
        ep = mp->exports;
474
        ls = (LDSYM *)(ldbuf+LDHDRSZ);
475
        for (i = lhp->l_nsyms; i; i--, ls++) {
476
                char *symname;
477
                char tmpsym[SYMNMLEN+1];
478
                if (!LDR_EXPORT(*ls))
479
                        continue;
480
                if (ls->l_zeroes == 0)
481
                        symname = ls->l_offset+lhp->l_stoff+ldbuf;
482
                else {
483
                        /*
484
                         * The l_name member is not zero terminated, we
485
                         * must copy the first SYMNMLEN chars and make
486
                         * sure we have a zero byte at the end.
487
                         */
488
                        strncpy(tmpsym, ls->l_name, SYMNMLEN);
489
                        tmpsym[SYMNMLEN] = '\0';
490
                        symname = tmpsym;
491
                }
492
                ep->name = malloc((unsigned) (strlen(symname) + 1));
493
                strcpy(ep->name, symname);
494
                ep->addr = (void *)((unsigned long)mp->entry +
495
                                        ls->l_value - shdata.s_vaddr);
496
                ep++;
497
        }
498
        free(ldbuf);
499
        while(ldclose(ldp) == FAILURE)
500
                ;
501
        return 0;
502
}
503
 
504
/*
505
 * Find the main modules entry point. This is used as export pointer
506
 * for loadbind() to be able to resolve references to the main part.
507
 */
508
static void * findMain(void)
509
{
510
        struct ld_info *lp;
511
        char *buf;
512
        int size = 4*1024;
513
        int i;
514
        void *ret;
515
 
516
        if ((buf = malloc(size)) == NULL) {
517
                errvalid++;
518
                strcpy(errbuf, "findMain: ");
519
                strcat(errbuf, strerror(errno));
520
                return NULL;
521
        }
522
        while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
523
                free(buf);
524
                size += 4*1024;
525
                if ((buf = malloc(size)) == NULL) {
526
                        errvalid++;
527
                        strcpy(errbuf, "findMain: ");
528
                        strcat(errbuf, strerror(errno));
529
                        return NULL;
530
                }
531
        }
532
        if (i == -1) {
533
                errvalid++;
534
                strcpy(errbuf, "findMain: ");
535
                strcat(errbuf, strerror(errno));
536
                free(buf);
537
                return NULL;
538
        }
539
        /*
540
         * The first entry is the main module. The entry point
541
         * returned by load() does actually point to the data
542
         * segment origin.
543
         */
544
        lp = (struct ld_info *)buf;
545
        ret = lp->ldinfo_dataorg;
546
        free(buf);
547
        return ret;
548
}
549
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.