os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclLoadAix.c
changeset 0 bde4ae8d615e
     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 +