pod nits (from A. C. Yardley <yardley@tanet.net>)
[p5sagit/p5-mst-13.2.git] / ext / DynaLoader / dl_aix.xs
CommitLineData
a0d0e21e 1/* dl_aix.xs
2 *
3 * Written: 8/31/94 by Wayne Scott (wscott@ichips.intel.com)
4 *
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.
8 *
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.
12 */
13
14/*
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
18 */
19#include "EXTERN.h"
20#include "perl.h"
21#include "XSUB.h"
22
19e194ad 23/* When building as a 64-bit binary on AIX, define this to get the
24 * correct structure definitions. Also determines the field-name
25 * macros and gates some logic in readEntries(). -- Steven N. Hirsch
26 * <hirschs@btv.ibm.com> */
27#ifdef USE_64_BIT_ALL
28# define __XCOFF64__
29# define __XCOFF32__
30#endif
31
a0d0e21e 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
19e194ad 41#ifdef USE_64_BIT_ALL
42# define AIX_SCNHDR SCNHDR_64
43# define AIX_LDHDR LDHDR_64
44# define AIX_LDSYM LDSYM_64
45# define AIX_LDHDRSZ LDHDRSZ_64
46#else
47# define AIX_SCNHDR SCNHDR
48# define AIX_LDHDR LDHDR
49# define AIX_LDSYM LDSYM
50# define AIX_LDHDRSZ LDHDRSZ
51#endif
52
4e774c84 53/* When using Perl extensions written in C++ the longer versions
54 * of load() and unload() from libC and libC_r need to be used,
55 * otherwise statics in the extensions won't get initialized right.
56 * -- Stephanie Beals <bealzy@us.ibm.com> */
bab3591f 57
58/* Older AIX C compilers cannot deal with C++ double-slash comments in
59 the ibmcxx and/or xlC includes. Since we only need a single file,
60 be more fine-grained about what's included <hirschs@btv.ibm.com> */
c88be79f 61#ifdef USE_libC /* The define comes, when it comes, from hints/aix.pl. */
62# define LOAD loadAndInit
4e774c84 63# define UNLOAD terminateAndUnload
bab3591f 64# if defined(USE_xlC_load_h)
65# include "/usr/lpp/xlC/include/load.h"
66# elif defined(USE_ibmcxx_load_h)
67# include "/usr/ibmcxx/include/load.h"
c88be79f 68# endif
4e774c84 69#else
70# define LOAD load
71# define UNLOAD unload
72#endif
73
ee580363 74/*
75 * AIX 4.3 does remove some useful definitions from ldfcn.h. Define
76 * these here to compensate for that lossage.
77 */
78#ifndef BEGINNING
79# define BEGINNING SEEK_SET
80#endif
81#ifndef FSEEK
82# define FSEEK(ldptr,o,p) fseek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr) +o):o,p)
83#endif
84#ifndef FREAD
85# define FREAD(p,s,n,ldptr) fread(p,s,n,IOPTR(ldptr))
86#endif
87
1553ab04 88/* If using PerlIO, redefine these macros from <ldfcn.h> */
89#ifdef USE_PERLIO
90#define FSEEK(ldptr,o,p) PerlIO_seek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr)+o):o,p)
91#define FREAD(p,s,n,ldptr) PerlIO_read(IOPTR(ldptr),p,s*n)
92#endif
93
a0d0e21e 94/*
95 * We simulate dlopen() et al. through a call to load. Because AIX has
96 * no call to find an exported symbol we read the loader section of the
97 * loaded module and build a list of exported symbols and their virtual
98 * address.
99 */
100
101typedef struct {
102 char *name; /* the symbols's name */
103 void *addr; /* its relocated virtual address */
104} Export, *ExportPtr;
105
106/*
107 * The void * handle returned from dlopen is actually a ModulePtr.
108 */
109typedef struct Module {
110 struct Module *next;
111 char *name; /* module name for refcounting */
112 int refCnt; /* the number of references */
113 void *entry; /* entry point from load */
114 int nExports; /* the number of exports found */
115 ExportPtr exports; /* the array of exports */
116} Module, *ModulePtr;
117
118/*
119 * We keep a list of all loaded modules to be able to call the fini
120 * handlers at atexit() time.
121 */
549a6b10 122static ModulePtr modList; /* XXX threaded */
a0d0e21e 123
124/*
125 * The last error from one of the dl* routines is kept in static
126 * variables here. Each error is returned only once to the caller.
127 */
549a6b10 128static char errbuf[BUFSIZ]; /* XXX threaded */
129static int errvalid; /* XXX threaded */
a0d0e21e 130
131static void caterr(char *);
132static int readExports(ModulePtr);
133static void terminate(void);
a0d0e21e 134
ce637636 135static char *strerror_failed = "(strerror failed)";
136static char *strerror_r_failed = "(strerror_r failed)";
137
fd206186 138char *strerrorcat(char *str, int err) {
ce637636 139 int strsiz = strlen(str);
140 int msgsiz;
141 char *msg;
142
143#ifdef USE_THREADS
144 char *buf = malloc(BUFSIZ);
145
146 if (buf == 0)
147 return 0;
549a6b10 148 if (strerror_r(err, buf, BUFSIZ) == 0)
ce637636 149 msg = buf;
150 else
151 msg = strerror_r_failed;
152 msgsiz = strlen(msg);
153 if (strsiz + msgsiz < BUFSIZ)
154 strcat(str, msg);
155 free(buf);
156#else
157 if ((msg = strerror(err)) == 0)
158 msg = strerror_failed;
159 msgsiz = strlen(msg); /* Note msg = buf and free() above. */
160 if (strsiz + msgsiz < BUFSIZ) /* Do not move this after #endif. */
161 strcat(str, msg);
162#endif
163
fd206186 164 return str;
165}
ce637636 166
fd206186 167char *strerrorcpy(char *str, int err) {
ce637636 168 int msgsiz;
169 char *msg;
170
171#ifdef USE_THREADS
172 char *buf = malloc(BUFSIZ);
173
174 if (buf == 0)
175 return 0;
549a6b10 176 if (strerror_r(err, buf, BUFSIZ) == 0)
ce637636 177 msg = buf;
178 else
179 msg = strerror_r_failed;
180 msgsiz = strlen(msg);
181 if (msgsiz < BUFSIZ)
182 strcpy(str, msg);
183 free(buf);
184#else
185 if ((msg = strerror(err)) == 0)
186 msg = strerror_failed;
187 msgsiz = strlen(msg); /* Note msg = buf and free() above. */
188 if (msgsiz < BUFSIZ) /* Do not move this after #endif. */
189 strcpy(str, msg);
190#endif
191
fd206186 192 return str;
193}
a0d0e21e 194
195/* ARGSUSED */
196void *dlopen(char *path, int mode)
197{
5b877257 198 dTHX;
a0d0e21e 199 register ModulePtr mp;
549a6b10 200 static int inited; /* XXX threaded */
a0d0e21e 201
202 /*
203 * Upon the first call register a terminate handler that will
f6b3007c 204 * close all libraries.
a0d0e21e 205 */
f6b3007c 206 if (!inited) {
207 inited++;
a0d0e21e 208 atexit(terminate);
209 }
210 /*
211 * Scan the list of modules if have the module already loaded.
212 */
213 for (mp = modList; mp; mp = mp->next)
214 if (strcmp(mp->name, path) == 0) {
215 mp->refCnt++;
216 return mp;
217 }
218 Newz(1000,mp,1,Module);
219 if (mp == NULL) {
220 errvalid++;
221 strcpy(errbuf, "Newz: ");
fd206186 222 strerrorcat(errbuf, errno);
a0d0e21e 223 return NULL;
224 }
225
226 if ((mp->name = savepv(path)) == NULL) {
227 errvalid++;
228 strcpy(errbuf, "savepv: ");
fd206186 229 strerrorcat(errbuf, errno);
a0d0e21e 230 safefree(mp);
231 return NULL;
232 }
549a6b10 233
a0d0e21e 234 /*
235 * load should be declared load(const char *...). Thus we
236 * cast the path to a normal char *. Ugly.
237 */
4e774c84 238 if ((mp->entry = (void *)LOAD((char *)path,
549a6b10 239#ifdef L_LIBPATH_EXEC
240 L_LIBPATH_EXEC |
241#endif
242 L_NOAUTODEFER,
243 NULL)) == NULL) {
244 int saverrno = errno;
245
a0d0e21e 246 safefree(mp->name);
247 safefree(mp);
248 errvalid++;
249 strcpy(errbuf, "dlopen: ");
250 strcat(errbuf, path);
251 strcat(errbuf, ": ");
252 /*
253 * If AIX says the file is not executable, the error
254 * can be further described by querying the loader about
255 * the last error.
256 */
549a6b10 257 if (saverrno == ENOEXEC) {
258 char *moreinfo[BUFSIZ/sizeof(char *)];
259 if (loadquery(L_GETMESSAGES, moreinfo, sizeof(moreinfo)) == -1)
260 strerrorcpy(errbuf, saverrno);
a0d0e21e 261 else {
262 char **p;
549a6b10 263 for (p = moreinfo; *p; p++)
a0d0e21e 264 caterr(*p);
265 }
266 } else
549a6b10 267 strerrorcat(errbuf, saverrno);
a0d0e21e 268 return NULL;
269 }
270 mp->refCnt = 1;
271 mp->next = modList;
272 modList = mp;
f6b3007c 273 /*
274 * Assume anonymous exports come from the module this dlopen
275 * is linked into, that holds true as long as dlopen and all
276 * of the perl core are in the same shared object.
277 */
278 if (loadbind(0, (void *)dlopen, mp->entry) == -1) {
549a6b10 279 int saverrno = errno;
280
a0d0e21e 281 dlclose(mp);
282 errvalid++;
283 strcpy(errbuf, "loadbind: ");
549a6b10 284 strerrorcat(errbuf, saverrno);
a0d0e21e 285 return NULL;
286 }
287 if (readExports(mp) == -1) {
288 dlclose(mp);
289 return NULL;
290 }
291 return mp;
292}
293
294/*
295 * Attempt to decipher an AIX loader error message and append it
296 * to our static error message buffer.
297 */
298static void caterr(char *s)
299{
300 register char *p = s;
301
302 while (*p >= '0' && *p <= '9')
303 p++;
304 switch(atoi(s)) {
305 case L_ERROR_TOOMANY:
306 strcat(errbuf, "to many errors");
307 break;
308 case L_ERROR_NOLIB:
309 strcat(errbuf, "can't load library");
310 strcat(errbuf, p);
311 break;
312 case L_ERROR_UNDEF:
313 strcat(errbuf, "can't find symbol");
314 strcat(errbuf, p);
315 break;
316 case L_ERROR_RLDBAD:
317 strcat(errbuf, "bad RLD");
318 strcat(errbuf, p);
319 break;
320 case L_ERROR_FORMAT:
321 strcat(errbuf, "bad exec format in");
322 strcat(errbuf, p);
323 break;
324 case L_ERROR_ERRNO:
fd206186 325 strerrorcat(errbuf, atoi(++p));
a0d0e21e 326 break;
327 default:
328 strcat(errbuf, s);
329 break;
330 }
331}
332
333void *dlsym(void *handle, const char *symbol)
334{
335 register ModulePtr mp = (ModulePtr)handle;
336 register ExportPtr ep;
337 register int i;
338
339 /*
340 * Could speed up search, but I assume that one assigns
341 * the result to function pointers anyways.
342 */
343 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
344 if (strcmp(ep->name, symbol) == 0)
345 return ep->addr;
346 errvalid++;
347 strcpy(errbuf, "dlsym: undefined symbol ");
348 strcat(errbuf, symbol);
349 return NULL;
350}
351
352char *dlerror(void)
353{
354 if (errvalid) {
355 errvalid = 0;
356 return errbuf;
357 }
358 return NULL;
359}
360
361int dlclose(void *handle)
362{
363 register ModulePtr mp = (ModulePtr)handle;
364 int result;
365 register ModulePtr mp1;
366
367 if (--mp->refCnt > 0)
368 return 0;
4e774c84 369 result = UNLOAD(mp->entry);
a0d0e21e 370 if (result == -1) {
371 errvalid++;
fd206186 372 strerrorcpy(errbuf, errno);
a0d0e21e 373 }
374 if (mp->exports) {
375 register ExportPtr ep;
376 register int i;
377 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
378 if (ep->name)
379 safefree(ep->name);
380 safefree(mp->exports);
381 }
382 if (mp == modList)
383 modList = mp->next;
384 else {
385 for (mp1 = modList; mp1; mp1 = mp1->next)
386 if (mp1->next == mp) {
387 mp1->next = mp->next;
388 break;
389 }
390 }
391 safefree(mp->name);
392 safefree(mp);
393 return result;
394}
395
396static void terminate(void)
397{
398 while (modList)
399 dlclose(modList);
400}
401
402/* Added by Wayne Scott
403 * This is needed because the ldopen system call calls
404 * calloc to allocated a block of date. The ldclose call calls free.
405 * Without this we get this system calloc and perl's free, resulting
406 * in a "Bad free" message. This way we always use perl's malloc.
407 */
408void *calloc(size_t ne, size_t sz)
409{
410 void *out;
411
412 out = (void *) safemalloc(ne*sz);
413 memzero(out, ne*sz);
414 return(out);
415}
416
417/*
418 * Build the export table from the XCOFF .loader section.
419 */
420static int readExports(ModulePtr mp)
421{
5b877257 422 dTHX;
a0d0e21e 423 LDFILE *ldp = NULL;
19e194ad 424 AIX_SCNHDR sh;
425 AIX_LDHDR *lhp;
a0d0e21e 426 char *ldbuf;
19e194ad 427 AIX_LDSYM *ls;
a0d0e21e 428 int i;
429 ExportPtr ep;
430
431 if ((ldp = ldopen(mp->name, ldp)) == NULL) {
432 struct ld_info *lp;
433 char *buf;
434 int size = 4*1024;
435 if (errno != ENOENT) {
436 errvalid++;
437 strcpy(errbuf, "readExports: ");
fd206186 438 strerrorcat(errbuf, errno);
a0d0e21e 439 return -1;
440 }
441 /*
442 * The module might be loaded due to the LIBPATH
443 * environment variable. Search for the loaded
444 * module using L_GETINFO.
445 */
446 if ((buf = safemalloc(size)) == NULL) {
447 errvalid++;
448 strcpy(errbuf, "readExports: ");
fd206186 449 strerrorcat(errbuf, errno);
a0d0e21e 450 return -1;
451 }
452 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
453 safefree(buf);
454 size += 4*1024;
455 if ((buf = safemalloc(size)) == NULL) {
456 errvalid++;
457 strcpy(errbuf, "readExports: ");
fd206186 458 strerrorcat(errbuf, errno);
a0d0e21e 459 return -1;
460 }
461 }
462 if (i == -1) {
463 errvalid++;
464 strcpy(errbuf, "readExports: ");
fd206186 465 strerrorcat(errbuf, errno);
a0d0e21e 466 safefree(buf);
467 return -1;
468 }
469 /*
470 * Traverse the list of loaded modules. The entry point
4e774c84 471 * returned by LOAD() does actually point to the data
a0d0e21e 472 * segment origin.
473 */
474 lp = (struct ld_info *)buf;
475 while (lp) {
476 if (lp->ldinfo_dataorg == mp->entry) {
477 ldp = ldopen(lp->ldinfo_filename, ldp);
478 break;
479 }
480 if (lp->ldinfo_next == 0)
481 lp = NULL;
482 else
483 lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
484 }
485 safefree(buf);
486 if (!ldp) {
487 errvalid++;
488 strcpy(errbuf, "readExports: ");
fd206186 489 strerrorcat(errbuf, errno);
a0d0e21e 490 return -1;
491 }
492 }
19e194ad 493#ifdef USE_64_BIT_ALL
494 if (TYPE(ldp) != U803XTOCMAGIC) {
495#else
a0d0e21e 496 if (TYPE(ldp) != U802TOCMAGIC) {
19e194ad 497#endif
a0d0e21e 498 errvalid++;
499 strcpy(errbuf, "readExports: bad magic");
500 while(ldclose(ldp) == FAILURE)
501 ;
502 return -1;
503 }
504 if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
505 errvalid++;
506 strcpy(errbuf, "readExports: cannot read loader section header");
507 while(ldclose(ldp) == FAILURE)
508 ;
509 return -1;
510 }
511 /*
512 * We read the complete loader section in one chunk, this makes
513 * finding long symbol names residing in the string table easier.
514 */
515 if ((ldbuf = (char *)safemalloc(sh.s_size)) == NULL) {
516 errvalid++;
517 strcpy(errbuf, "readExports: ");
fd206186 518 strerrorcat(errbuf, errno);
a0d0e21e 519 while(ldclose(ldp) == FAILURE)
520 ;
521 return -1;
522 }
523 if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
524 errvalid++;
525 strcpy(errbuf, "readExports: cannot seek to loader section");
526 safefree(ldbuf);
527 while(ldclose(ldp) == FAILURE)
528 ;
529 return -1;
530 }
1553ab04 531/* This first case is a hack, since it assumes that the 3rd parameter to
532 FREAD is 1. See the redefinition of FREAD above to see how this works. */
533#ifdef USE_PERLIO
534 if (FREAD(ldbuf, sh.s_size, 1, ldp) != sh.s_size) {
535#else
a0d0e21e 536 if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
1553ab04 537#endif
a0d0e21e 538 errvalid++;
539 strcpy(errbuf, "readExports: cannot read loader section");
540 safefree(ldbuf);
541 while(ldclose(ldp) == FAILURE)
542 ;
543 return -1;
544 }
19e194ad 545 lhp = (AIX_LDHDR *)ldbuf;
546 ls = (AIX_LDSYM *)(ldbuf+AIX_LDHDRSZ);
a0d0e21e 547 /*
548 * Count the number of exports to include in our export table.
549 */
550 for (i = lhp->l_nsyms; i; i--, ls++) {
551 if (!LDR_EXPORT(*ls))
552 continue;
553 mp->nExports++;
554 }
555 Newz(1001, mp->exports, mp->nExports, Export);
556 if (mp->exports == NULL) {
557 errvalid++;
558 strcpy(errbuf, "readExports: ");
fd206186 559 strerrorcat(errbuf, errno);
a0d0e21e 560 safefree(ldbuf);
561 while(ldclose(ldp) == FAILURE)
562 ;
563 return -1;
564 }
565 /*
566 * Fill in the export table. All entries are relative to
567 * the entry point we got from load.
568 */
569 ep = mp->exports;
19e194ad 570 ls = (AIX_LDSYM *)(ldbuf+AIX_LDHDRSZ);
a0d0e21e 571 for (i = lhp->l_nsyms; i; i--, ls++) {
572 char *symname;
573 if (!LDR_EXPORT(*ls))
574 continue;
19e194ad 575#ifndef USE_64_BIT_ALL
a0d0e21e 576 if (ls->l_zeroes == 0)
19e194ad 577#endif
a0d0e21e 578 symname = ls->l_offset+lhp->l_stoff+ldbuf;
19e194ad 579#ifndef USE_64_BIT_ALL
a0d0e21e 580 else
581 symname = ls->l_name;
19e194ad 582#endif
a0d0e21e 583 ep->name = savepv(symname);
584 ep->addr = (void *)((unsigned long)mp->entry + ls->l_value);
585 ep++;
586 }
587 safefree(ldbuf);
588 while(ldclose(ldp) == FAILURE)
589 ;
590 return 0;
591}
592
a0d0e21e 593/* dl_dlopen.xs
594 *
595 * Platform: SunOS/Solaris, possibly others which use dlopen.
0536e0eb 596 * Author: Paul Marquess (Paul.Marquess@btinternet.com)
a0d0e21e 597 * Created: 10th July 1994
598 *
599 * Modified:
600 * 15th July 1994 - Added code to explicitly save any error messages.
601 * 3rd August 1994 - Upgraded to v3 spec.
602 * 9th August 1994 - Changed to use IV
603 * 10th August 1994 - Tim Bunce: Added RTLD_LAZY, switchable debugging,
604 * basic FreeBSD support, removed ClearError
605 *
606 */
607
608/* Porting notes:
609
610 see dl_dlopen.xs
611
612*/
613
614#include "dlutils.c" /* SaveError() etc */
615
616
617static void
cea2e8a9 618dl_private_init(pTHX)
a0d0e21e 619{
cea2e8a9 620 (void)dl_generic_private_init(aTHX);
a0d0e21e 621}
622
623MODULE = DynaLoader PACKAGE = DynaLoader
624
625BOOT:
cea2e8a9 626 (void)dl_private_init(aTHX);
a0d0e21e 627
628
629void *
ff7f3c60 630dl_load_file(filename, flags=0)
631 char * filename
632 int flags
a0d0e21e 633 CODE:
bf49b057 634 DLDEBUG(1,PerlIO_printf(Perl_debug_log, "dl_load_file(%s,%x):\n", filename,flags));
ff7f3c60 635 if (flags & 0x01)
cea2e8a9 636 Perl_warn(aTHX_ "Can't make loaded symbols global on this platform while loading %s",filename);
a0d0e21e 637 RETVAL = dlopen(filename, 1) ;
bf49b057 638 DLDEBUG(2,PerlIO_printf(Perl_debug_log, " libref=%x\n", RETVAL));
a0d0e21e 639 ST(0) = sv_newmortal() ;
640 if (RETVAL == NULL)
cea2e8a9 641 SaveError(aTHX_ "%s",dlerror()) ;
a0d0e21e 642 else
3175b8cd 643 sv_setiv( ST(0), PTR2IV(RETVAL) );
a0d0e21e 644
645
646void *
647dl_find_symbol(libhandle, symbolname)
648 void * libhandle
649 char * symbolname
650 CODE:
bf49b057 651 DLDEBUG(2,PerlIO_printf(Perl_debug_log, "dl_find_symbol(handle=%x, symbol=%s)\n",
a0d0e21e 652 libhandle, symbolname));
653 RETVAL = dlsym(libhandle, symbolname);
bf49b057 654 DLDEBUG(2,PerlIO_printf(Perl_debug_log, " symbolref = %x\n", RETVAL));
a0d0e21e 655 ST(0) = sv_newmortal() ;
656 if (RETVAL == NULL)
cea2e8a9 657 SaveError(aTHX_ "%s",dlerror()) ;
a0d0e21e 658 else
f66f545a 659 sv_setiv( ST(0), PTR2IV(RETVAL));
a0d0e21e 660
661
662void
663dl_undef_symbols()
664 PPCODE:
665
666
667
668# These functions should not need changing on any platform:
669
670void
671dl_install_xsub(perl_name, symref, filename="$Package")
672 char * perl_name
673 void * symref
674 char * filename
675 CODE:
bf49b057 676 DLDEBUG(2,PerlIO_printf(Perl_debug_log, "dl_install_xsub(name=%s, symref=%x)\n",
a0d0e21e 677 perl_name, symref));
cea2e8a9 678 ST(0) = sv_2mortal(newRV((SV*)newXS(perl_name,
679 (void(*)(pTHX_ CV *))symref,
680 filename)));
a0d0e21e 681
682
683char *
684dl_error()
685 CODE:
686 RETVAL = LastError ;
687 OUTPUT:
688 RETVAL
689
690# end.