os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclLoadAix.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclLoadAix.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,549 @@
1.4 +/*
1.5 + * tclLoadAix.c --
1.6 + *
1.7 + * This file implements the dlopen and dlsym APIs under the
1.8 + * AIX operating system, to enable the Tcl "load" command to
1.9 + * work. This code was provided by Jens-Uwe Mager.
1.10 + *
1.11 + * This file is subject to the following copyright notice, which is
1.12 + * different from the notice used elsewhere in Tcl. The file has
1.13 + * been modified to incorporate the file dlfcn.h in-line.
1.14 + *
1.15 + * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH
1.16 + * Not derived from licensed software.
1.17 +
1.18 + * Permission is granted to freely use, copy, modify, and redistribute
1.19 + * this software, provided that the author is not construed to be liable
1.20 + * for any results of using the software, alterations are clearly marked
1.21 + * as such, and this notice is not modified.
1.22 + *
1.23 + * RCS: @(#) $Id: tclLoadAix.c,v 1.3 1999/04/16 00:48:04 stanton Exp $
1.24 + *
1.25 + * Note: this file has been altered from the original in a few
1.26 + * ways in order to work properly with Tcl.
1.27 + */
1.28 +
1.29 +/*
1.30 + * @(#)dlfcn.c 1.7 revision of 95/08/14 19:08:38
1.31 + * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
1.32 + * 30159 Hannover, Germany
1.33 + */
1.34 +
1.35 +#include <stdio.h>
1.36 +#include <errno.h>
1.37 +#include <string.h>
1.38 +#include <stdlib.h>
1.39 +#include <sys/types.h>
1.40 +#include <sys/ldr.h>
1.41 +#include <a.out.h>
1.42 +#include <ldfcn.h>
1.43 +#include "../compat/dlfcn.h"
1.44 +
1.45 +/*
1.46 + * We simulate dlopen() et al. through a call to load. Because AIX has
1.47 + * no call to find an exported symbol we read the loader section of the
1.48 + * loaded module and build a list of exported symbols and their virtual
1.49 + * address.
1.50 + */
1.51 +
1.52 +typedef struct {
1.53 + char *name; /* the symbols's name */
1.54 + void *addr; /* its relocated virtual address */
1.55 +} Export, *ExportPtr;
1.56 +
1.57 +/*
1.58 + * xlC uses the following structure to list its constructors and
1.59 + * destructors. This is gleaned from the output of munch.
1.60 + */
1.61 +typedef struct {
1.62 + void (*init)(void); /* call static constructors */
1.63 + void (*term)(void); /* call static destructors */
1.64 +} Cdtor, *CdtorPtr;
1.65 +
1.66 +/*
1.67 + * The void * handle returned from dlopen is actually a ModulePtr.
1.68 + */
1.69 +typedef struct Module {
1.70 + struct Module *next;
1.71 + char *name; /* module name for refcounting */
1.72 + int refCnt; /* the number of references */
1.73 + void *entry; /* entry point from load */
1.74 + struct dl_info *info; /* optional init/terminate functions */
1.75 + CdtorPtr cdtors; /* optional C++ constructors */
1.76 + int nExports; /* the number of exports found */
1.77 + ExportPtr exports; /* the array of exports */
1.78 +} Module, *ModulePtr;
1.79 +
1.80 +/*
1.81 + * We keep a list of all loaded modules to be able to call the fini
1.82 + * handlers and destructors at atexit() time.
1.83 + */
1.84 +static ModulePtr modList;
1.85 +
1.86 +/*
1.87 + * The last error from one of the dl* routines is kept in static
1.88 + * variables here. Each error is returned only once to the caller.
1.89 + */
1.90 +static char errbuf[BUFSIZ];
1.91 +static int errvalid;
1.92 +
1.93 +static void caterr(char *);
1.94 +static int readExports(ModulePtr);
1.95 +static void terminate(void);
1.96 +static void *findMain(void);
1.97 +
1.98 +VOID *dlopen(const char *path, int mode)
1.99 +{
1.100 + register ModulePtr mp;
1.101 + static void *mainModule;
1.102 +
1.103 + /*
1.104 + * Upon the first call register a terminate handler that will
1.105 + * close all libraries. Also get a reference to the main module
1.106 + * for use with loadbind.
1.107 + */
1.108 + if (!mainModule) {
1.109 + if ((mainModule = findMain()) == NULL)
1.110 + return NULL;
1.111 + atexit(terminate);
1.112 + }
1.113 + /*
1.114 + * Scan the list of modules if we have the module already loaded.
1.115 + */
1.116 + for (mp = modList; mp; mp = mp->next)
1.117 + if (strcmp(mp->name, path) == 0) {
1.118 + mp->refCnt++;
1.119 + return (VOID *) mp;
1.120 + }
1.121 + if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) {
1.122 + errvalid++;
1.123 + strcpy(errbuf, "calloc: ");
1.124 + strcat(errbuf, strerror(errno));
1.125 + return (VOID *) NULL;
1.126 + }
1.127 + mp->name = malloc((unsigned) (strlen(path) + 1));
1.128 + strcpy(mp->name, path);
1.129 + /*
1.130 + * load should be declared load(const char *...). Thus we
1.131 + * cast the path to a normal char *. Ugly.
1.132 + */
1.133 + if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
1.134 + free(mp->name);
1.135 + free(mp);
1.136 + errvalid++;
1.137 + strcpy(errbuf, "dlopen: ");
1.138 + strcat(errbuf, path);
1.139 + strcat(errbuf, ": ");
1.140 + /*
1.141 + * If AIX says the file is not executable, the error
1.142 + * can be further described by querying the loader about
1.143 + * the last error.
1.144 + */
1.145 + if (errno == ENOEXEC) {
1.146 + char *tmp[BUFSIZ/sizeof(char *)];
1.147 + if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
1.148 + strcpy(errbuf, strerror(errno));
1.149 + else {
1.150 + char **p;
1.151 + for (p = tmp; *p; p++)
1.152 + caterr(*p);
1.153 + }
1.154 + } else
1.155 + strcat(errbuf, strerror(errno));
1.156 + return (VOID *) NULL;
1.157 + }
1.158 + mp->refCnt = 1;
1.159 + mp->next = modList;
1.160 + modList = mp;
1.161 + if (loadbind(0, mainModule, mp->entry) == -1) {
1.162 + dlclose(mp);
1.163 + errvalid++;
1.164 + strcpy(errbuf, "loadbind: ");
1.165 + strcat(errbuf, strerror(errno));
1.166 + return (VOID *) NULL;
1.167 + }
1.168 + /*
1.169 + * If the user wants global binding, loadbind against all other
1.170 + * loaded modules.
1.171 + */
1.172 + if (mode & RTLD_GLOBAL) {
1.173 + register ModulePtr mp1;
1.174 + for (mp1 = mp->next; mp1; mp1 = mp1->next)
1.175 + if (loadbind(0, mp1->entry, mp->entry) == -1) {
1.176 + dlclose(mp);
1.177 + errvalid++;
1.178 + strcpy(errbuf, "loadbind: ");
1.179 + strcat(errbuf, strerror(errno));
1.180 + return (VOID *) NULL;
1.181 + }
1.182 + }
1.183 + if (readExports(mp) == -1) {
1.184 + dlclose(mp);
1.185 + return (VOID *) NULL;
1.186 + }
1.187 + /*
1.188 + * If there is a dl_info structure, call the init function.
1.189 + */
1.190 + if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {
1.191 + if (mp->info->init)
1.192 + (*mp->info->init)();
1.193 + } else
1.194 + errvalid = 0;
1.195 + /*
1.196 + * If the shared object was compiled using xlC we will need
1.197 + * to call static constructors (and later on dlclose destructors).
1.198 + */
1.199 + if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) {
1.200 + while (mp->cdtors->init) {
1.201 + (*mp->cdtors->init)();
1.202 + mp->cdtors++;
1.203 + }
1.204 + } else
1.205 + errvalid = 0;
1.206 + return (VOID *) mp;
1.207 +}
1.208 +
1.209 +/*
1.210 + * Attempt to decipher an AIX loader error message and append it
1.211 + * to our static error message buffer.
1.212 + */
1.213 +static void caterr(char *s)
1.214 +{
1.215 + register char *p = s;
1.216 +
1.217 + while (*p >= '0' && *p <= '9')
1.218 + p++;
1.219 + switch(atoi(s)) { /* INTL: "C", UTF safe. */
1.220 + case L_ERROR_TOOMANY:
1.221 + strcat(errbuf, "to many errors");
1.222 + break;
1.223 + case L_ERROR_NOLIB:
1.224 + strcat(errbuf, "can't load library");
1.225 + strcat(errbuf, p);
1.226 + break;
1.227 + case L_ERROR_UNDEF:
1.228 + strcat(errbuf, "can't find symbol");
1.229 + strcat(errbuf, p);
1.230 + break;
1.231 + case L_ERROR_RLDBAD:
1.232 + strcat(errbuf, "bad RLD");
1.233 + strcat(errbuf, p);
1.234 + break;
1.235 + case L_ERROR_FORMAT:
1.236 + strcat(errbuf, "bad exec format in");
1.237 + strcat(errbuf, p);
1.238 + break;
1.239 + case L_ERROR_ERRNO:
1.240 + strcat(errbuf, strerror(atoi(++p))); /* INTL: "C", UTF safe. */
1.241 + break;
1.242 + default:
1.243 + strcat(errbuf, s);
1.244 + break;
1.245 + }
1.246 +}
1.247 +
1.248 +VOID *dlsym(void *handle, const char *symbol)
1.249 +{
1.250 + register ModulePtr mp = (ModulePtr)handle;
1.251 + register ExportPtr ep;
1.252 + register int i;
1.253 +
1.254 + /*
1.255 + * Could speed up the search, but I assume that one assigns
1.256 + * the result to function pointers anyways.
1.257 + */
1.258 + for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
1.259 + if (strcmp(ep->name, symbol) == 0)
1.260 + return ep->addr;
1.261 + errvalid++;
1.262 + strcpy(errbuf, "dlsym: undefined symbol ");
1.263 + strcat(errbuf, symbol);
1.264 + return NULL;
1.265 +}
1.266 +
1.267 +char *dlerror(void)
1.268 +{
1.269 + if (errvalid) {
1.270 + errvalid = 0;
1.271 + return errbuf;
1.272 + }
1.273 + return NULL;
1.274 +}
1.275 +
1.276 +int dlclose(void *handle)
1.277 +{
1.278 + register ModulePtr mp = (ModulePtr)handle;
1.279 + int result;
1.280 + register ModulePtr mp1;
1.281 +
1.282 + if (--mp->refCnt > 0)
1.283 + return 0;
1.284 + if (mp->info && mp->info->fini)
1.285 + (*mp->info->fini)();
1.286 + if (mp->cdtors)
1.287 + while (mp->cdtors->term) {
1.288 + (*mp->cdtors->term)();
1.289 + mp->cdtors++;
1.290 + }
1.291 + result = unload(mp->entry);
1.292 + if (result == -1) {
1.293 + errvalid++;
1.294 + strcpy(errbuf, strerror(errno));
1.295 + }
1.296 + if (mp->exports) {
1.297 + register ExportPtr ep;
1.298 + register int i;
1.299 + for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
1.300 + if (ep->name)
1.301 + free(ep->name);
1.302 + free(mp->exports);
1.303 + }
1.304 + if (mp == modList)
1.305 + modList = mp->next;
1.306 + else {
1.307 + for (mp1 = modList; mp1; mp1 = mp1->next)
1.308 + if (mp1->next == mp) {
1.309 + mp1->next = mp->next;
1.310 + break;
1.311 + }
1.312 + }
1.313 + free(mp->name);
1.314 + free(mp);
1.315 + return result;
1.316 +}
1.317 +
1.318 +static void terminate(void)
1.319 +{
1.320 + while (modList)
1.321 + dlclose(modList);
1.322 +}
1.323 +
1.324 +/*
1.325 + * Build the export table from the XCOFF .loader section.
1.326 + */
1.327 +static int readExports(ModulePtr mp)
1.328 +{
1.329 + LDFILE *ldp = NULL;
1.330 + SCNHDR sh, shdata;
1.331 + LDHDR *lhp;
1.332 + char *ldbuf;
1.333 + LDSYM *ls;
1.334 + int i;
1.335 + ExportPtr ep;
1.336 +
1.337 + if ((ldp = ldopen(mp->name, ldp)) == NULL) {
1.338 + struct ld_info *lp;
1.339 + char *buf;
1.340 + int size = 4*1024;
1.341 + if (errno != ENOENT) {
1.342 + errvalid++;
1.343 + strcpy(errbuf, "readExports: ");
1.344 + strcat(errbuf, strerror(errno));
1.345 + return -1;
1.346 + }
1.347 + /*
1.348 + * The module might be loaded due to the LIBPATH
1.349 + * environment variable. Search for the loaded
1.350 + * module using L_GETINFO.
1.351 + */
1.352 + if ((buf = malloc(size)) == NULL) {
1.353 + errvalid++;
1.354 + strcpy(errbuf, "readExports: ");
1.355 + strcat(errbuf, strerror(errno));
1.356 + return -1;
1.357 + }
1.358 + while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
1.359 + free(buf);
1.360 + size += 4*1024;
1.361 + if ((buf = malloc(size)) == NULL) {
1.362 + errvalid++;
1.363 + strcpy(errbuf, "readExports: ");
1.364 + strcat(errbuf, strerror(errno));
1.365 + return -1;
1.366 + }
1.367 + }
1.368 + if (i == -1) {
1.369 + errvalid++;
1.370 + strcpy(errbuf, "readExports: ");
1.371 + strcat(errbuf, strerror(errno));
1.372 + free(buf);
1.373 + return -1;
1.374 + }
1.375 + /*
1.376 + * Traverse the list of loaded modules. The entry point
1.377 + * returned by load() does actually point to the data
1.378 + * segment origin.
1.379 + */
1.380 + lp = (struct ld_info *)buf;
1.381 + while (lp) {
1.382 + if (lp->ldinfo_dataorg == mp->entry) {
1.383 + ldp = ldopen(lp->ldinfo_filename, ldp);
1.384 + break;
1.385 + }
1.386 + if (lp->ldinfo_next == 0)
1.387 + lp = NULL;
1.388 + else
1.389 + lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
1.390 + }
1.391 + free(buf);
1.392 + if (!ldp) {
1.393 + errvalid++;
1.394 + strcpy(errbuf, "readExports: ");
1.395 + strcat(errbuf, strerror(errno));
1.396 + return -1;
1.397 + }
1.398 + }
1.399 + if (TYPE(ldp) != U802TOCMAGIC) {
1.400 + errvalid++;
1.401 + strcpy(errbuf, "readExports: bad magic");
1.402 + while(ldclose(ldp) == FAILURE)
1.403 + ;
1.404 + return -1;
1.405 + }
1.406 + /*
1.407 + * Get the padding for the data section. This is needed for
1.408 + * AIX 4.1 compilers. This is used when building the final
1.409 + * function pointer to the exported symbol.
1.410 + */
1.411 + if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
1.412 + errvalid++;
1.413 + strcpy(errbuf, "readExports: cannot read data section header");
1.414 + while(ldclose(ldp) == FAILURE)
1.415 + ;
1.416 + return -1;
1.417 + }
1.418 + if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
1.419 + errvalid++;
1.420 + strcpy(errbuf, "readExports: cannot read loader section header");
1.421 + while(ldclose(ldp) == FAILURE)
1.422 + ;
1.423 + return -1;
1.424 + }
1.425 + /*
1.426 + * We read the complete loader section in one chunk, this makes
1.427 + * finding long symbol names residing in the string table easier.
1.428 + */
1.429 + if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) {
1.430 + errvalid++;
1.431 + strcpy(errbuf, "readExports: ");
1.432 + strcat(errbuf, strerror(errno));
1.433 + while(ldclose(ldp) == FAILURE)
1.434 + ;
1.435 + return -1;
1.436 + }
1.437 + if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
1.438 + errvalid++;
1.439 + strcpy(errbuf, "readExports: cannot seek to loader section");
1.440 + free(ldbuf);
1.441 + while(ldclose(ldp) == FAILURE)
1.442 + ;
1.443 + return -1;
1.444 + }
1.445 + if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
1.446 + errvalid++;
1.447 + strcpy(errbuf, "readExports: cannot read loader section");
1.448 + free(ldbuf);
1.449 + while(ldclose(ldp) == FAILURE)
1.450 + ;
1.451 + return -1;
1.452 + }
1.453 + lhp = (LDHDR *)ldbuf;
1.454 + ls = (LDSYM *)(ldbuf+LDHDRSZ);
1.455 + /*
1.456 + * Count the number of exports to include in our export table.
1.457 + */
1.458 + for (i = lhp->l_nsyms; i; i--, ls++) {
1.459 + if (!LDR_EXPORT(*ls))
1.460 + continue;
1.461 + mp->nExports++;
1.462 + }
1.463 + if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
1.464 + errvalid++;
1.465 + strcpy(errbuf, "readExports: ");
1.466 + strcat(errbuf, strerror(errno));
1.467 + free(ldbuf);
1.468 + while(ldclose(ldp) == FAILURE)
1.469 + ;
1.470 + return -1;
1.471 + }
1.472 + /*
1.473 + * Fill in the export table. All entries are relative to
1.474 + * the entry point we got from load.
1.475 + */
1.476 + ep = mp->exports;
1.477 + ls = (LDSYM *)(ldbuf+LDHDRSZ);
1.478 + for (i = lhp->l_nsyms; i; i--, ls++) {
1.479 + char *symname;
1.480 + char tmpsym[SYMNMLEN+1];
1.481 + if (!LDR_EXPORT(*ls))
1.482 + continue;
1.483 + if (ls->l_zeroes == 0)
1.484 + symname = ls->l_offset+lhp->l_stoff+ldbuf;
1.485 + else {
1.486 + /*
1.487 + * The l_name member is not zero terminated, we
1.488 + * must copy the first SYMNMLEN chars and make
1.489 + * sure we have a zero byte at the end.
1.490 + */
1.491 + strncpy(tmpsym, ls->l_name, SYMNMLEN);
1.492 + tmpsym[SYMNMLEN] = '\0';
1.493 + symname = tmpsym;
1.494 + }
1.495 + ep->name = malloc((unsigned) (strlen(symname) + 1));
1.496 + strcpy(ep->name, symname);
1.497 + ep->addr = (void *)((unsigned long)mp->entry +
1.498 + ls->l_value - shdata.s_vaddr);
1.499 + ep++;
1.500 + }
1.501 + free(ldbuf);
1.502 + while(ldclose(ldp) == FAILURE)
1.503 + ;
1.504 + return 0;
1.505 +}
1.506 +
1.507 +/*
1.508 + * Find the main modules entry point. This is used as export pointer
1.509 + * for loadbind() to be able to resolve references to the main part.
1.510 + */
1.511 +static void * findMain(void)
1.512 +{
1.513 + struct ld_info *lp;
1.514 + char *buf;
1.515 + int size = 4*1024;
1.516 + int i;
1.517 + void *ret;
1.518 +
1.519 + if ((buf = malloc(size)) == NULL) {
1.520 + errvalid++;
1.521 + strcpy(errbuf, "findMain: ");
1.522 + strcat(errbuf, strerror(errno));
1.523 + return NULL;
1.524 + }
1.525 + while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
1.526 + free(buf);
1.527 + size += 4*1024;
1.528 + if ((buf = malloc(size)) == NULL) {
1.529 + errvalid++;
1.530 + strcpy(errbuf, "findMain: ");
1.531 + strcat(errbuf, strerror(errno));
1.532 + return NULL;
1.533 + }
1.534 + }
1.535 + if (i == -1) {
1.536 + errvalid++;
1.537 + strcpy(errbuf, "findMain: ");
1.538 + strcat(errbuf, strerror(errno));
1.539 + free(buf);
1.540 + return NULL;
1.541 + }
1.542 + /*
1.543 + * The first entry is the main module. The entry point
1.544 + * returned by load() does actually point to the data
1.545 + * segment origin.
1.546 + */
1.547 + lp = (struct ld_info *)buf;
1.548 + ret = lp->ldinfo_dataorg;
1.549 + free(buf);
1.550 + return ret;
1.551 +}
1.552 +