155682Smarkm/*
255682Smarkm * @(#)dlfcn.c	1.11 revision of 96/04/10  20:12:51
355682Smarkm * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
455682Smarkm * 30159 Hannover, Germany
555682Smarkm */
655682Smarkm
755682Smarkm/*
855682Smarkm * Changes marked with `--jwe' were made on April 7 1996 by John W. Eaton
955682Smarkm * <jwe@bevo.che.wisc.edu> to support g++ and/or use with Octave.
1055682Smarkm */
1155682Smarkm
1255682Smarkm/*
1355682Smarkm * This makes my life easier with Octave.  --jwe
1455682Smarkm */
1555682Smarkm#ifdef HAVE_CONFIG_H
1655682Smarkm#include <config.h>
1755682Smarkm#endif
1855682Smarkm
1955682Smarkm#include <stdio.h>
2055682Smarkm#include <errno.h>
2155682Smarkm#include <string.h>
2255682Smarkm#include <stdlib.h>
2355682Smarkm#include <sys/types.h>
2455682Smarkm#include <sys/ldr.h>
2555682Smarkm#include <a.out.h>
2655682Smarkm#include <ldfcn.h>
2755682Smarkm#include "dlfcn.h"
2855682Smarkm
2955682Smarkm/*
3055682Smarkm * We simulate dlopen() et al. through a call to load. Because AIX has
3155682Smarkm * no call to find an exported symbol we read the loader section of the
3255682Smarkm * loaded module and build a list of exported symbols and their virtual
3355682Smarkm * address.
3455682Smarkm */
3555682Smarkm
3655682Smarkmtypedef struct {
3755682Smarkm	char		*name;		/* the symbols's name */
3855682Smarkm	void		*addr;		/* its relocated virtual address */
3955682Smarkm} Export, *ExportPtr;
4055682Smarkm
4155682Smarkm/*
4255682Smarkm * xlC uses the following structure to list its constructors and
4355682Smarkm * destructors. This is gleaned from the output of munch.
4455682Smarkm */
4555682Smarkmtypedef struct {
4655682Smarkm	void (*init)(void);		/* call static constructors */
4755682Smarkm	void (*term)(void);		/* call static destructors */
4855682Smarkm} Cdtor, *CdtorPtr;
4955682Smarkm
5055682Smarkmtypedef void (*GccCDtorPtr)(void);
5155682Smarkm
5255682Smarkm/*
5355682Smarkm * The void * handle returned from dlopen is actually a ModulePtr.
5455682Smarkm */
5555682Smarkmtypedef struct Module {
5655682Smarkm	struct Module	*next;
5755682Smarkm	char		*name;		/* module name for refcounting */
5855682Smarkm	int		refCnt;		/* the number of references */
5955682Smarkm	void		*entry;		/* entry point from load */
6055682Smarkm	struct dl_info	*info;		/* optional init/terminate functions */
6155682Smarkm	CdtorPtr	cdtors;		/* optional C++ constructors */
6255682Smarkm	GccCDtorPtr	gcc_ctor;	/* g++ constructors  --jwe */
6355682Smarkm	GccCDtorPtr	gcc_dtor;	/* g++ destructors  --jwe */
6455682Smarkm	int		nExports;	/* the number of exports found */
6555682Smarkm	ExportPtr	exports;	/* the array of exports */
6655682Smarkm} Module, *ModulePtr;
6755682Smarkm
6855682Smarkm/*
6955682Smarkm * We keep a list of all loaded modules to be able to call the fini
7055682Smarkm * handlers and destructors at atexit() time.
7155682Smarkm */
7255682Smarkmstatic ModulePtr modList;
7355682Smarkm
7455682Smarkm/*
7555682Smarkm * The last error from one of the dl* routines is kept in static
7655682Smarkm * variables here. Each error is returned only once to the caller.
7755682Smarkm */
7855682Smarkmstatic char errbuf[BUFSIZ];
7955682Smarkmstatic int errvalid;
8055682Smarkm
8155682Smarkm/*
8255682Smarkm * The `fixed' gcc header files on AIX 3.2.5 provide a prototype for
8355682Smarkm * strdup().  --jwe
8455682Smarkm */
8555682Smarkm#ifndef HAVE_STRDUP
8655682Smarkmextern char *strdup(const char *);
8755682Smarkm#endif
8855682Smarkmstatic void caterr(char *);
8955682Smarkmstatic int readExports(ModulePtr);
9055682Smarkmstatic void terminate(void);
9155682Smarkmstatic void *findMain(void);
9255682Smarkm
9355682Smarkmvoid *dlopen(const char *path, int mode)
9455682Smarkm{
9555682Smarkm	ModulePtr mp;
9655682Smarkm	static void *mainModule;
9755682Smarkm
9855682Smarkm	/*
9955682Smarkm	 * Upon the first call register a terminate handler that will
10055682Smarkm	 * close all libraries. Also get a reference to the main module
10155682Smarkm	 * for use with loadbind.
10255682Smarkm	 */
10355682Smarkm	if (!mainModule) {
10455682Smarkm		if ((mainModule = findMain()) == NULL)
10555682Smarkm			return NULL;
10655682Smarkm		atexit(terminate);
10755682Smarkm	}
10855682Smarkm	/*
10955682Smarkm	 * Scan the list of modules if we have the module already loaded.
11055682Smarkm	 */
11155682Smarkm	for (mp = modList; mp; mp = mp->next)
11255682Smarkm		if (strcmp(mp->name, path) == 0) {
11355682Smarkm			mp->refCnt++;
11455682Smarkm			return mp;
11555682Smarkm		}
11655682Smarkm	if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) {
11755682Smarkm		errvalid++;
11872445Sassar		snprintf (errbuf, sizeof(errbuf), "calloc: %s", strerror(errno));
11955682Smarkm		return NULL;
12055682Smarkm	}
12155682Smarkm	if ((mp->name = strdup(path)) == NULL) {
12255682Smarkm		errvalid++;
12372445Sassar		snprintf (errbuf, sizeof(errbuf), "strdup: %s", strerror(errno));
12455682Smarkm		free(mp);
12555682Smarkm		return NULL;
12655682Smarkm	}
12755682Smarkm	/*
12855682Smarkm	 * load should be declared load(const char *...). Thus we
12955682Smarkm	 * cast the path to a normal char *. Ugly.
13055682Smarkm	 */
13155682Smarkm	if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
13255682Smarkm		free(mp->name);
13355682Smarkm		free(mp);
13455682Smarkm		errvalid++;
13555682Smarkm		snprintf (errbuf, sizeof(errbuf),
13655682Smarkm			  "dlopen: %s: ", path);
13755682Smarkm		/*
13855682Smarkm		 * If AIX says the file is not executable, the error
13955682Smarkm		 * can be further described by querying the loader about
14055682Smarkm		 * the last error.
14155682Smarkm		 */
14255682Smarkm		if (errno == ENOEXEC) {
14355682Smarkm			char *tmp[BUFSIZ/sizeof(char *)];
14455682Smarkm			if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
14555682Smarkm				strlcpy(errbuf,
14655682Smarkm						strerror(errno),
14755682Smarkm						sizeof(errbuf));
14855682Smarkm			else {
14955682Smarkm				char **p;
15055682Smarkm				for (p = tmp; *p; p++)
15155682Smarkm					caterr(*p);
15255682Smarkm			}
15355682Smarkm		} else
15455682Smarkm			strlcat(errbuf,
15555682Smarkm					strerror(errno),
15655682Smarkm					sizeof(errbuf));
15755682Smarkm		return NULL;
15855682Smarkm	}
15955682Smarkm	mp->refCnt = 1;
16055682Smarkm	mp->next = modList;
16155682Smarkm	modList = mp;
16255682Smarkm	if (loadbind(0, mainModule, mp->entry) == -1) {
16355682Smarkm		dlclose(mp);
16455682Smarkm		errvalid++;
16555682Smarkm		snprintf (errbuf, sizeof(errbuf),
16655682Smarkm			  "loadbind: %s", strerror(errno));
16755682Smarkm		return NULL;
16855682Smarkm	}
16955682Smarkm	/*
17055682Smarkm	 * If the user wants global binding, loadbind against all other
17155682Smarkm	 * loaded modules.
17255682Smarkm	 */
17355682Smarkm	if (mode & RTLD_GLOBAL) {
17455682Smarkm		ModulePtr mp1;
17555682Smarkm		for (mp1 = mp->next; mp1; mp1 = mp1->next)
17655682Smarkm			if (loadbind(0, mp1->entry, mp->entry) == -1) {
17755682Smarkm				dlclose(mp);
17855682Smarkm				errvalid++;
17955682Smarkm				snprintf (errbuf, sizeof(errbuf),
18055682Smarkm					  "loadbind: %s",
18155682Smarkm					  strerror(errno));
18255682Smarkm				return NULL;
18355682Smarkm			}
18455682Smarkm	}
18555682Smarkm	if (readExports(mp) == -1) {
18655682Smarkm		dlclose(mp);
18755682Smarkm		return NULL;
18855682Smarkm	}
18955682Smarkm	/*
19055682Smarkm	 * If there is a dl_info structure, call the init function.
19155682Smarkm	 */
19255682Smarkm	if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {
19355682Smarkm		if (mp->info->init)
19455682Smarkm			(*mp->info->init)();
19555682Smarkm	} else
19655682Smarkm		errvalid = 0;
19755682Smarkm	/*
19855682Smarkm	 * If the shared object was compiled using xlC we will need
19955682Smarkm	 * to call static constructors (and later on dlclose destructors).
20055682Smarkm	 */
20155682Smarkm	if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) {
20255682Smarkm		CdtorPtr cp = mp->cdtors;
20355682Smarkm		while (cp->init || cp->term) {
20455682Smarkm			if (cp->init && cp->init != (void (*)(void))0xffffffff)
20555682Smarkm				(*cp->init)();
20655682Smarkm			cp++;
20755682Smarkm		}
20855682Smarkm	/*
20955682Smarkm	 * If the shared object was compiled using g++, we will need
21055682Smarkm	 * to call global constructors using the _GLOBAL__DI function,
21155682Smarkm	 * and later, global destructors using the _GLOBAL_DD
21255682Smarkm	 * funciton.  --jwe
21355682Smarkm	 */
21455682Smarkm	} else if (mp->gcc_ctor = (GccCDtorPtr)dlsym(mp, "_GLOBAL__DI")) {
21555682Smarkm		(*mp->gcc_ctor)();
21655682Smarkm		mp->gcc_dtor = (GccCDtorPtr)dlsym(mp, "_GLOBAL__DD");
21755682Smarkm	} else
21855682Smarkm		errvalid = 0;
21955682Smarkm	return mp;
22055682Smarkm}
22155682Smarkm
22255682Smarkm/*
22355682Smarkm * Attempt to decipher an AIX loader error message and append it
22455682Smarkm * to our static error message buffer.
22555682Smarkm */
22655682Smarkmstatic void caterr(char *s)
22755682Smarkm{
22855682Smarkm	char *p = s;
22955682Smarkm
23055682Smarkm	while (*p >= '0' && *p <= '9')
23155682Smarkm		p++;
23255682Smarkm	switch(atoi(s)) {
23355682Smarkm	case L_ERROR_TOOMANY:
23455682Smarkm		strlcat(errbuf, "to many errors", sizeof(errbuf));
23555682Smarkm		break;
23655682Smarkm	case L_ERROR_NOLIB:
23755682Smarkm		strlcat(errbuf, "can't load library", sizeof(errbuf));
23855682Smarkm		strlcat(errbuf, p, sizeof(errbuf));
23955682Smarkm		break;
24055682Smarkm	case L_ERROR_UNDEF:
24155682Smarkm		strlcat(errbuf, "can't find symbol", sizeof(errbuf));
24255682Smarkm		strlcat(errbuf, p, sizeof(errbuf));
24355682Smarkm		break;
24455682Smarkm	case L_ERROR_RLDBAD:
24555682Smarkm		strlcat(errbuf, "bad RLD", sizeof(errbuf));
24655682Smarkm		strlcat(errbuf, p, sizeof(errbuf));
24755682Smarkm		break;
24855682Smarkm	case L_ERROR_FORMAT:
24955682Smarkm		strlcat(errbuf, "bad exec format in", sizeof(errbuf));
25055682Smarkm		strlcat(errbuf, p, sizeof(errbuf));
25155682Smarkm		break;
25255682Smarkm	case L_ERROR_ERRNO:
25355682Smarkm		strlcat(errbuf, strerror(atoi(++p)), sizeof(errbuf));
25455682Smarkm		break;
25555682Smarkm	default:
25655682Smarkm		strlcat(errbuf, s, sizeof(errbuf));
25755682Smarkm		break;
25855682Smarkm	}
25955682Smarkm}
26055682Smarkm
26155682Smarkmvoid *dlsym(void *handle, const char *symbol)
26255682Smarkm{
26355682Smarkm	ModulePtr mp = (ModulePtr)handle;
26455682Smarkm	ExportPtr ep;
26555682Smarkm	int i;
26655682Smarkm
26755682Smarkm	/*
26855682Smarkm	 * Could speed up the search, but I assume that one assigns
26955682Smarkm	 * the result to function pointers anyways.
27055682Smarkm	 */
27155682Smarkm	for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
27255682Smarkm		if (strcmp(ep->name, symbol) == 0)
27355682Smarkm			return ep->addr;
27455682Smarkm	errvalid++;
27555682Smarkm	snprintf (errbuf, sizeof(errbuf),
27655682Smarkm		  "dlsym: undefined symbol %s", symbol);
27755682Smarkm	return NULL;
27855682Smarkm}
27955682Smarkm
28055682Smarkmchar *dlerror(void)
28155682Smarkm{
28255682Smarkm	if (errvalid) {
28355682Smarkm		errvalid = 0;
28455682Smarkm		return errbuf;
28555682Smarkm	}
28655682Smarkm	return NULL;
28755682Smarkm}
28855682Smarkm
28955682Smarkmint dlclose(void *handle)
29055682Smarkm{
29155682Smarkm	ModulePtr mp = (ModulePtr)handle;
29255682Smarkm	int result;
29355682Smarkm	ModulePtr mp1;
29455682Smarkm
29555682Smarkm	if (--mp->refCnt > 0)
29655682Smarkm		return 0;
29755682Smarkm	if (mp->info && mp->info->fini)
29855682Smarkm		(*mp->info->fini)();
29955682Smarkm	if (mp->cdtors) {
30055682Smarkm		CdtorPtr cp = mp->cdtors;
30155682Smarkm		while (cp->init || cp->term) {
30255682Smarkm			if (cp->term && cp->init != (void (*)(void))0xffffffff)
30355682Smarkm				(*cp->term)();
30455682Smarkm			cp++;
30555682Smarkm		}
30655682Smarkm	/*
30755682Smarkm	 * If the function to handle global destructors for g++
30855682Smarkm	 * exists, call it.  --jwe
30955682Smarkm	 */
31055682Smarkm	} else if (mp->gcc_dtor) {
31155682Smarkm	        (*mp->gcc_dtor)();
31255682Smarkm	}
31355682Smarkm	result = unload(mp->entry);
31455682Smarkm	if (result == -1) {
31555682Smarkm		errvalid++;
31655682Smarkm		snprintf (errbuf, sizeof(errbuf),
31755682Smarkm			  "%s", strerror(errno));
31855682Smarkm	}
31955682Smarkm	if (mp->exports) {
32055682Smarkm		ExportPtr ep;
32155682Smarkm		int i;
32255682Smarkm		for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
32355682Smarkm			if (ep->name)
32455682Smarkm				free(ep->name);
32555682Smarkm		free(mp->exports);
32655682Smarkm	}
32755682Smarkm	if (mp == modList)
32855682Smarkm		modList = mp->next;
32955682Smarkm	else {
33055682Smarkm		for (mp1 = modList; mp1; mp1 = mp1->next)
33155682Smarkm			if (mp1->next == mp) {
33255682Smarkm				mp1->next = mp->next;
33355682Smarkm				break;
33455682Smarkm			}
33555682Smarkm	}
33655682Smarkm	free(mp->name);
33755682Smarkm	free(mp);
33855682Smarkm	return result;
33955682Smarkm}
34055682Smarkm
34155682Smarkmstatic void terminate(void)
34255682Smarkm{
34355682Smarkm	while (modList)
34455682Smarkm		dlclose(modList);
34555682Smarkm}
34655682Smarkm
34755682Smarkm/*
34855682Smarkm * Build the export table from the XCOFF .loader section.
34955682Smarkm */
35055682Smarkmstatic int readExports(ModulePtr mp)
35155682Smarkm{
35255682Smarkm	LDFILE *ldp = NULL;
35355682Smarkm	SCNHDR sh, shdata;
35455682Smarkm	LDHDR *lhp;
35555682Smarkm	char *ldbuf;
35655682Smarkm	LDSYM *ls;
35755682Smarkm	int i;
35855682Smarkm	ExportPtr ep;
35955682Smarkm
36055682Smarkm	if ((ldp = ldopen(mp->name, ldp)) == NULL) {
36155682Smarkm		struct ld_info *lp;
36255682Smarkm		char *buf;
36355682Smarkm		int size = 4*1024;
36455682Smarkm		if (errno != ENOENT) {
36555682Smarkm			errvalid++;
36655682Smarkm			snprintf(errbuf, sizeof(errbuf),
36755682Smarkm				 "readExports: %s",
36855682Smarkm				 strerror(errno));
36955682Smarkm			return -1;
37055682Smarkm		}
37155682Smarkm		/*
37255682Smarkm		 * The module might be loaded due to the LIBPATH
37355682Smarkm		 * environment variable. Search for the loaded
37455682Smarkm		 * module using L_GETINFO.
37555682Smarkm		 */
37655682Smarkm		if ((buf = malloc(size)) == NULL) {
37755682Smarkm			errvalid++;
37855682Smarkm			snprintf(errbuf, sizeof(errbuf),
37955682Smarkm				 "readExports: %s",
38055682Smarkm				 strerror(errno));
38155682Smarkm			return -1;
38255682Smarkm		}
38355682Smarkm		while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
38455682Smarkm			free(buf);
38555682Smarkm			size += 4*1024;
38655682Smarkm			if ((buf = malloc(size)) == NULL) {
38755682Smarkm				errvalid++;
38855682Smarkm				snprintf(errbuf, sizeof(errbuf),
38955682Smarkm					 "readExports: %s",
39055682Smarkm					 strerror(errno));
39155682Smarkm				return -1;
39255682Smarkm			}
39355682Smarkm		}
39455682Smarkm		if (i == -1) {
39555682Smarkm			errvalid++;
39655682Smarkm			snprintf(errbuf, sizeof(errbuf),
39755682Smarkm				 "readExports: %s",
39855682Smarkm				 strerror(errno));
39955682Smarkm			free(buf);
40055682Smarkm			return -1;
40155682Smarkm		}
40255682Smarkm		/*
40355682Smarkm		 * Traverse the list of loaded modules. The entry point
40455682Smarkm		 * returned by load() does actually point to the data
40555682Smarkm		 * segment origin.
40655682Smarkm		 */
40755682Smarkm		lp = (struct ld_info *)buf;
40855682Smarkm		while (lp) {
40955682Smarkm			if (lp->ldinfo_dataorg == mp->entry) {
41055682Smarkm				ldp = ldopen(lp->ldinfo_filename, ldp);
41155682Smarkm				break;
41255682Smarkm			}
41355682Smarkm			if (lp->ldinfo_next == 0)
41455682Smarkm				lp = NULL;
41555682Smarkm			else
41655682Smarkm				lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
41755682Smarkm		}
41855682Smarkm		free(buf);
41955682Smarkm		if (!ldp) {
42055682Smarkm			errvalid++;
42155682Smarkm			snprintf (errbuf, sizeof(errbuf),
42255682Smarkm				  "readExports: %s", strerror(errno));
42355682Smarkm			return -1;
42455682Smarkm		}
42555682Smarkm	}
42655682Smarkm	if (TYPE(ldp) != U802TOCMAGIC) {
42755682Smarkm		errvalid++;
42855682Smarkm		snprintf(errbuf, sizeof(errbuf), "readExports: bad magic");
42955682Smarkm		while(ldclose(ldp) == FAILURE)
43055682Smarkm			;
43155682Smarkm		return -1;
43255682Smarkm	}
43355682Smarkm	/*
43455682Smarkm	 * Get the padding for the data section. This is needed for
43555682Smarkm	 * AIX 4.1 compilers. This is used when building the final
43655682Smarkm	 * function pointer to the exported symbol.
43755682Smarkm	 */
43855682Smarkm	if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
43955682Smarkm		errvalid++;
44055682Smarkm		snprintf(errbuf, sizeof(errbuf),
44155682Smarkm			 "readExports: cannot read data section header");
44255682Smarkm		while(ldclose(ldp) == FAILURE)
44355682Smarkm			;
44455682Smarkm		return -1;
44555682Smarkm	}
44655682Smarkm	if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
44755682Smarkm		errvalid++;
44855682Smarkm		snprintf(errbuf, sizeof(errbuf),
44955682Smarkm			 "readExports: cannot read loader section header");
45055682Smarkm		while(ldclose(ldp) == FAILURE)
45155682Smarkm			;
45255682Smarkm		return -1;
45355682Smarkm	}
45455682Smarkm	/*
45555682Smarkm	 * We read the complete loader section in one chunk, this makes
45655682Smarkm	 * finding long symbol names residing in the string table easier.
45755682Smarkm	 */
45855682Smarkm	if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) {
45955682Smarkm		errvalid++;
46055682Smarkm		snprintf (errbuf, sizeof(errbuf),
46155682Smarkm			  "readExports: %s", strerror(errno));
46255682Smarkm		while(ldclose(ldp) == FAILURE)
46355682Smarkm			;
46455682Smarkm		return -1;
46555682Smarkm	}
46655682Smarkm	if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
46755682Smarkm		errvalid++;
46855682Smarkm		snprintf(errbuf, sizeof(errbuf),
46955682Smarkm			 "readExports: cannot seek to loader section");
47055682Smarkm		free(ldbuf);
47155682Smarkm		while(ldclose(ldp) == FAILURE)
47255682Smarkm			;
47355682Smarkm		return -1;
47455682Smarkm	}
47555682Smarkm	if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
47655682Smarkm		errvalid++;
47755682Smarkm		snprintf(errbuf, sizeof(errbuf),
47855682Smarkm			 "readExports: cannot read loader section");
47955682Smarkm		free(ldbuf);
48055682Smarkm		while(ldclose(ldp) == FAILURE)
48155682Smarkm			;
48255682Smarkm		return -1;
48355682Smarkm	}
48455682Smarkm	lhp = (LDHDR *)ldbuf;
48555682Smarkm	ls = (LDSYM *)(ldbuf+LDHDRSZ);
48655682Smarkm	/*
48755682Smarkm	 * Count the number of exports to include in our export table.
48855682Smarkm	 */
48955682Smarkm	for (i = lhp->l_nsyms; i; i--, ls++) {
49055682Smarkm		if (!LDR_EXPORT(*ls))
49155682Smarkm			continue;
49255682Smarkm		mp->nExports++;
49355682Smarkm	}
49455682Smarkm	if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
49555682Smarkm		errvalid++;
49655682Smarkm		snprintf (errbuf, sizeof(errbuf),
49755682Smarkm			  "readExports: %s", strerror(errno));
49855682Smarkm		free(ldbuf);
49955682Smarkm		while(ldclose(ldp) == FAILURE)
50055682Smarkm			;
50155682Smarkm		return -1;
50255682Smarkm	}
50355682Smarkm	/*
50455682Smarkm	 * Fill in the export table. All entries are relative to
50555682Smarkm	 * the entry point we got from load.
50655682Smarkm	 */
50755682Smarkm	ep = mp->exports;
50855682Smarkm	ls = (LDSYM *)(ldbuf+LDHDRSZ);
50955682Smarkm	for (i = lhp->l_nsyms; i; i--, ls++) {
51055682Smarkm		char *symname;
51155682Smarkm		char tmpsym[SYMNMLEN+1];
51255682Smarkm		if (!LDR_EXPORT(*ls))
51355682Smarkm			continue;
51455682Smarkm		if (ls->l_zeroes == 0)
51555682Smarkm			symname = ls->l_offset+lhp->l_stoff+ldbuf;
51655682Smarkm		else {
51755682Smarkm			/*
51855682Smarkm			 * The l_name member is not zero terminated, we
51955682Smarkm			 * must copy the first SYMNMLEN chars and make
52055682Smarkm			 * sure we have a zero byte at the end.
52155682Smarkm			 */
52255682Smarkm		        strlcpy (tmpsym, ls->l_name,
52355682Smarkm					 SYMNMLEN + 1);
52455682Smarkm			symname = tmpsym;
52555682Smarkm		}
52655682Smarkm		ep->name = strdup(symname);
52755682Smarkm		ep->addr = (void *)((unsigned long)mp->entry +
52855682Smarkm					ls->l_value - shdata.s_vaddr);
52955682Smarkm		ep++;
53055682Smarkm	}
53155682Smarkm	free(ldbuf);
53255682Smarkm	while(ldclose(ldp) == FAILURE)
53355682Smarkm		;
53455682Smarkm	return 0;
53555682Smarkm}
53655682Smarkm
53755682Smarkm/*
53855682Smarkm * Find the main modules entry point. This is used as export pointer
53955682Smarkm * for loadbind() to be able to resolve references to the main part.
54055682Smarkm */
54155682Smarkmstatic void * findMain(void)
54255682Smarkm{
54355682Smarkm	struct ld_info *lp;
54455682Smarkm	char *buf;
54555682Smarkm	int size = 4*1024;
54655682Smarkm	int i;
54755682Smarkm	void *ret;
54855682Smarkm
54955682Smarkm	if ((buf = malloc(size)) == NULL) {
55055682Smarkm		errvalid++;
55155682Smarkm		snprintf (errbuf, sizeof(errbuf),
55255682Smarkm			  "findMail: %s", strerror(errno));
55355682Smarkm		return NULL;
55455682Smarkm	}
55555682Smarkm	while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
55655682Smarkm		free(buf);
55755682Smarkm		size += 4*1024;
55855682Smarkm		if ((buf = malloc(size)) == NULL) {
55955682Smarkm			errvalid++;
56055682Smarkm			snprintf (errbuf, sizeof(errbuf),
56155682Smarkm				  "findMail: %s", strerror(errno));
56255682Smarkm			return NULL;
56355682Smarkm		}
56455682Smarkm	}
56555682Smarkm	if (i == -1) {
56655682Smarkm		errvalid++;
56755682Smarkm		snprintf (errbuf, sizeof(errbuf),
56855682Smarkm			  "findMail: %s", strerror(errno));
56955682Smarkm		free(buf);
57055682Smarkm		return NULL;
57155682Smarkm	}
57255682Smarkm	/*
57355682Smarkm	 * The first entry is the main module. The entry point
57455682Smarkm	 * returned by load() does actually point to the data
57555682Smarkm	 * segment origin.
57655682Smarkm	 */
57755682Smarkm	lp = (struct ld_info *)buf;
57855682Smarkm	ret = lp->ldinfo_dataorg;
57955682Smarkm	free(buf);
58055682Smarkm	return ret;
58155682Smarkm}
582