3 * Written: 8/31/94 by Wayne Scott (wscott@ichips.intel.com)
5 * All I did was take Jens-Uwe Mager's libdl emulation library for
6 * AIX and merged it with the dl_dlopen.xs file to create a dynamic library
7 * package that works for AIX.
9 * I did change all malloc's, free's, strdup's, calloc's to use the perl
10 * equilvant. I also removed some stuff we will not need. Call fini()
11 * on statup... It can probably be trimmed more.
15 * @(#)dlfcn.c 1.5 revision of 93/02/14 20:14:17
16 * This is an unpublished work copyright (c) 1992 Helios Software GmbH
17 * 3000 Hannover 1, Germany
27 #include <sys/types.h>
32 /* If using PerlIO, redefine these macros from <ldfcn.h> */
34 #define FSEEK(ldptr,o,p) PerlIO_seek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr)+o):o,p)
35 #define FREAD(p,s,n,ldptr) PerlIO_read(IOPTR(ldptr),p,s*n)
39 * We simulate dlopen() et al. through a call to load. Because AIX has
40 * no call to find an exported symbol we read the loader section of the
41 * loaded module and build a list of exported symbols and their virtual
46 char *name; /* the symbols's name */
47 void *addr; /* its relocated virtual address */
51 * The void * handle returned from dlopen is actually a ModulePtr.
53 typedef struct Module {
55 char *name; /* module name for refcounting */
56 int refCnt; /* the number of references */
57 void *entry; /* entry point from load */
58 int nExports; /* the number of exports found */
59 ExportPtr exports; /* the array of exports */
63 * We keep a list of all loaded modules to be able to call the fini
64 * handlers at atexit() time.
66 static ModulePtr modList;
69 * The last error from one of the dl* routines is kept in static
70 * variables here. Each error is returned only once to the caller.
72 static char errbuf[BUFSIZ];
75 static void caterr(char *);
76 static int readExports(ModulePtr);
77 static void terminate(void);
78 static void *findMain(void);
80 static char *strerror_failed = "(strerror failed)";
81 static char *strerror_r_failed = "(strerror_r failed)";
83 char *strerrorcat(char *str, int err) {
84 int strsiz = strlen(str);
89 char *buf = malloc(BUFSIZ);
93 if (strerror_r(err, buf, sizeof(buf)) == 0)
96 msg = strerror_r_failed;
98 if (strsiz + msgsiz < BUFSIZ)
102 if ((msg = strerror(err)) == 0)
103 msg = strerror_failed;
104 msgsiz = strlen(msg); /* Note msg = buf and free() above. */
105 if (strsiz + msgsiz < BUFSIZ) /* Do not move this after #endif. */
112 char *strerrorcpy(char *str, int err) {
117 char *buf = malloc(BUFSIZ);
121 if (strerror_r(err, buf, sizeof(buf)) == 0)
124 msg = strerror_r_failed;
125 msgsiz = strlen(msg);
130 if ((msg = strerror(err)) == 0)
131 msg = strerror_failed;
132 msgsiz = strlen(msg); /* Note msg = buf and free() above. */
133 if (msgsiz < BUFSIZ) /* Do not move this after #endif. */
141 void *dlopen(char *path, int mode)
143 register ModulePtr mp;
144 static void *mainModule;
147 * Upon the first call register a terminate handler that will
148 * close all libraries. Also get a reference to the main module
149 * for use with loadbind.
152 if ((mainModule = findMain()) == NULL)
157 * Scan the list of modules if have the module already loaded.
159 for (mp = modList; mp; mp = mp->next)
160 if (strcmp(mp->name, path) == 0) {
164 Newz(1000,mp,1,Module);
167 strcpy(errbuf, "Newz: ");
168 strerrorcat(errbuf, errno);
172 if ((mp->name = savepv(path)) == NULL) {
174 strcpy(errbuf, "savepv: ");
175 strerrorcat(errbuf, errno);
180 * load should be declared load(const char *...). Thus we
181 * cast the path to a normal char *. Ugly.
183 if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
187 strcpy(errbuf, "dlopen: ");
188 strcat(errbuf, path);
189 strcat(errbuf, ": ");
191 * If AIX says the file is not executable, the error
192 * can be further described by querying the loader about
195 if (errno == ENOEXEC) {
196 char *tmp[BUFSIZ/sizeof(char *)];
197 if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
198 strerrorcpy(errbuf, errno);
201 for (p = tmp; *p; p++)
205 strerrorcat(errbuf, errno);
211 if (loadbind(0, mainModule, mp->entry) == -1) {
214 strcpy(errbuf, "loadbind: ");
215 strerrorcat(errbuf, errno);
218 if (readExports(mp) == -1) {
226 * Attempt to decipher an AIX loader error message and append it
227 * to our static error message buffer.
229 static void caterr(char *s)
231 register char *p = s;
233 while (*p >= '0' && *p <= '9')
236 case L_ERROR_TOOMANY:
237 strcat(errbuf, "to many errors");
240 strcat(errbuf, "can't load library");
244 strcat(errbuf, "can't find symbol");
248 strcat(errbuf, "bad RLD");
252 strcat(errbuf, "bad exec format in");
256 strerrorcat(errbuf, atoi(++p));
264 void *dlsym(void *handle, const char *symbol)
266 register ModulePtr mp = (ModulePtr)handle;
267 register ExportPtr ep;
271 * Could speed up search, but I assume that one assigns
272 * the result to function pointers anyways.
274 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
275 if (strcmp(ep->name, symbol) == 0)
278 strcpy(errbuf, "dlsym: undefined symbol ");
279 strcat(errbuf, symbol);
292 int dlclose(void *handle)
294 register ModulePtr mp = (ModulePtr)handle;
296 register ModulePtr mp1;
298 if (--mp->refCnt > 0)
300 result = unload(mp->entry);
303 strerrorcpy(errbuf, errno);
306 register ExportPtr ep;
308 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
311 safefree(mp->exports);
316 for (mp1 = modList; mp1; mp1 = mp1->next)
317 if (mp1->next == mp) {
318 mp1->next = mp->next;
327 static void terminate(void)
333 /* Added by Wayne Scott
334 * This is needed because the ldopen system call calls
335 * calloc to allocated a block of date. The ldclose call calls free.
336 * Without this we get this system calloc and perl's free, resulting
337 * in a "Bad free" message. This way we always use perl's malloc.
339 void *calloc(size_t ne, size_t sz)
343 out = (void *) safemalloc(ne*sz);
349 * Build the export table from the XCOFF .loader section.
351 static int readExports(ModulePtr mp)
361 if ((ldp = ldopen(mp->name, ldp)) == NULL) {
365 if (errno != ENOENT) {
367 strcpy(errbuf, "readExports: ");
368 strerrorcat(errbuf, errno);
372 * The module might be loaded due to the LIBPATH
373 * environment variable. Search for the loaded
374 * module using L_GETINFO.
376 if ((buf = safemalloc(size)) == NULL) {
378 strcpy(errbuf, "readExports: ");
379 strerrorcat(errbuf, errno);
382 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
385 if ((buf = safemalloc(size)) == NULL) {
387 strcpy(errbuf, "readExports: ");
388 strerrorcat(errbuf, errno);
394 strcpy(errbuf, "readExports: ");
395 strerrorcat(errbuf, errno);
400 * Traverse the list of loaded modules. The entry point
401 * returned by load() does actually point to the data
404 lp = (struct ld_info *)buf;
406 if (lp->ldinfo_dataorg == mp->entry) {
407 ldp = ldopen(lp->ldinfo_filename, ldp);
410 if (lp->ldinfo_next == 0)
413 lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
418 strcpy(errbuf, "readExports: ");
419 strerrorcat(errbuf, errno);
423 if (TYPE(ldp) != U802TOCMAGIC) {
425 strcpy(errbuf, "readExports: bad magic");
426 while(ldclose(ldp) == FAILURE)
430 if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
432 strcpy(errbuf, "readExports: cannot read loader section header");
433 while(ldclose(ldp) == FAILURE)
438 * We read the complete loader section in one chunk, this makes
439 * finding long symbol names residing in the string table easier.
441 if ((ldbuf = (char *)safemalloc(sh.s_size)) == NULL) {
443 strcpy(errbuf, "readExports: ");
444 strerrorcat(errbuf, errno);
445 while(ldclose(ldp) == FAILURE)
449 if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
451 strcpy(errbuf, "readExports: cannot seek to loader section");
453 while(ldclose(ldp) == FAILURE)
457 /* This first case is a hack, since it assumes that the 3rd parameter to
458 FREAD is 1. See the redefinition of FREAD above to see how this works. */
460 if (FREAD(ldbuf, sh.s_size, 1, ldp) != sh.s_size) {
462 if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
465 strcpy(errbuf, "readExports: cannot read loader section");
467 while(ldclose(ldp) == FAILURE)
471 lhp = (LDHDR *)ldbuf;
472 ls = (LDSYM *)(ldbuf+LDHDRSZ);
474 * Count the number of exports to include in our export table.
476 for (i = lhp->l_nsyms; i; i--, ls++) {
477 if (!LDR_EXPORT(*ls))
481 Newz(1001, mp->exports, mp->nExports, Export);
482 if (mp->exports == NULL) {
484 strcpy(errbuf, "readExports: ");
485 strerrorcat(errbuf, errno);
487 while(ldclose(ldp) == FAILURE)
492 * Fill in the export table. All entries are relative to
493 * the entry point we got from load.
496 ls = (LDSYM *)(ldbuf+LDHDRSZ);
497 for (i = lhp->l_nsyms; i; i--, ls++) {
499 if (!LDR_EXPORT(*ls))
501 if (ls->l_zeroes == 0)
502 symname = ls->l_offset+lhp->l_stoff+ldbuf;
504 symname = ls->l_name;
505 ep->name = savepv(symname);
506 ep->addr = (void *)((unsigned long)mp->entry + ls->l_value);
510 while(ldclose(ldp) == FAILURE)
516 * Find the main modules entry point. This is used as export pointer
517 * for loadbind() to be able to resolve references to the main part.
519 static void * findMain(void)
527 if ((buf = safemalloc(size)) == NULL) {
529 strcpy(errbuf, "findMain: ");
530 strerrorcat(errbuf, errno);
533 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
536 if ((buf = safemalloc(size)) == NULL) {
538 strcpy(errbuf, "findMain: ");
539 strerrorcat(errbuf, errno);
545 strcpy(errbuf, "findMain: ");
546 strerrorcat(errbuf, errno);
551 * The first entry is the main module. The entry point
552 * returned by load() does actually point to the data
555 lp = (struct ld_info *)buf;
556 ret = lp->ldinfo_dataorg;
563 * Platform: SunOS/Solaris, possibly others which use dlopen.
564 * Author: Paul Marquess (pmarquess@bfsec.bt.co.uk)
565 * Created: 10th July 1994
568 * 15th July 1994 - Added code to explicitly save any error messages.
569 * 3rd August 1994 - Upgraded to v3 spec.
570 * 9th August 1994 - Changed to use IV
571 * 10th August 1994 - Tim Bunce: Added RTLD_LAZY, switchable debugging,
572 * basic FreeBSD support, removed ClearError
582 #include "dlutils.c" /* SaveError() etc */
588 (void)dl_generic_private_init();
591 MODULE = DynaLoader PACKAGE = DynaLoader
594 (void)dl_private_init();
598 dl_load_file(filename, flags=0)
602 DLDEBUG(1,PerlIO_printf(PerlIO_stderr(), "dl_load_file(%s,%x):\n", filename,flags));
604 warn("Can't make loaded symbols global on this platform while loading %s",filename);
605 RETVAL = dlopen(filename, 1) ;
606 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), " libref=%x\n", RETVAL));
607 ST(0) = sv_newmortal() ;
609 SaveError("%s",dlerror()) ;
611 sv_setiv( ST(0), (IV)RETVAL);
615 dl_find_symbol(libhandle, symbolname)
619 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), "dl_find_symbol(handle=%x, symbol=%s)\n",
620 libhandle, symbolname));
621 RETVAL = dlsym(libhandle, symbolname);
622 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), " symbolref = %x\n", RETVAL));
623 ST(0) = sv_newmortal() ;
625 SaveError("%s",dlerror()) ;
627 sv_setiv( ST(0), (IV)RETVAL);
636 # These functions should not need changing on any platform:
639 dl_install_xsub(perl_name, symref, filename="$Package")
644 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), "dl_install_xsub(name=%s, symref=%x)\n",
646 ST(0)=sv_2mortal(newRV((SV*)newXS(perl_name, (void(*)())symref, filename)));