[win32] change all 'sp' to 'SP' in code and in the docs. Explicitly
[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
23#include <stdio.h>
24#include <errno.h>
25#include <string.h>
26#include <stdlib.h>
27#include <sys/types.h>
28#include <sys/ldr.h>
29#include <a.out.h>
30#include <ldfcn.h>
31
1553ab04 32/* If using PerlIO, redefine these macros from <ldfcn.h> */
33#ifdef USE_PERLIO
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)
36#endif
37
a0d0e21e 38/*
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
42 * address.
43 */
44
45typedef struct {
46 char *name; /* the symbols's name */
47 void *addr; /* its relocated virtual address */
48} Export, *ExportPtr;
49
50/*
51 * The void * handle returned from dlopen is actually a ModulePtr.
52 */
53typedef struct Module {
54 struct Module *next;
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 */
60} Module, *ModulePtr;
61
62/*
63 * We keep a list of all loaded modules to be able to call the fini
64 * handlers at atexit() time.
65 */
66static ModulePtr modList;
67
68/*
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.
71 */
72static char errbuf[BUFSIZ];
73static int errvalid;
74
75static void caterr(char *);
76static int readExports(ModulePtr);
77static void terminate(void);
78static void *findMain(void);
79
ce637636 80static char *strerror_failed = "(strerror failed)";
81static char *strerror_r_failed = "(strerror_r failed)";
82
fd206186 83char *strerrorcat(char *str, int err) {
ce637636 84 int strsiz = strlen(str);
85 int msgsiz;
86 char *msg;
87
88#ifdef USE_THREADS
89 char *buf = malloc(BUFSIZ);
90
91 if (buf == 0)
92 return 0;
93 if (strerror_r(err, buf, sizeof(buf)) == 0)
94 msg = buf;
95 else
96 msg = strerror_r_failed;
97 msgsiz = strlen(msg);
98 if (strsiz + msgsiz < BUFSIZ)
99 strcat(str, msg);
100 free(buf);
101#else
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. */
106 strcat(str, msg);
107#endif
108
fd206186 109 return str;
110}
ce637636 111
fd206186 112char *strerrorcpy(char *str, int err) {
ce637636 113 int msgsiz;
114 char *msg;
115
116#ifdef USE_THREADS
117 char *buf = malloc(BUFSIZ);
118
119 if (buf == 0)
120 return 0;
121 if (strerror_r(err, buf, sizeof(buf)) == 0)
122 msg = buf;
123 else
124 msg = strerror_r_failed;
125 msgsiz = strlen(msg);
126 if (msgsiz < BUFSIZ)
127 strcpy(str, msg);
128 free(buf);
129#else
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. */
134 strcpy(str, msg);
135#endif
136
fd206186 137 return str;
138}
a0d0e21e 139
140/* ARGSUSED */
141void *dlopen(char *path, int mode)
142{
143 register ModulePtr mp;
144 static void *mainModule;
145
146 /*
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.
150 */
151 if (!mainModule) {
152 if ((mainModule = findMain()) == NULL)
153 return NULL;
154 atexit(terminate);
155 }
156 /*
157 * Scan the list of modules if have the module already loaded.
158 */
159 for (mp = modList; mp; mp = mp->next)
160 if (strcmp(mp->name, path) == 0) {
161 mp->refCnt++;
162 return mp;
163 }
164 Newz(1000,mp,1,Module);
165 if (mp == NULL) {
166 errvalid++;
167 strcpy(errbuf, "Newz: ");
fd206186 168 strerrorcat(errbuf, errno);
a0d0e21e 169 return NULL;
170 }
171
172 if ((mp->name = savepv(path)) == NULL) {
173 errvalid++;
174 strcpy(errbuf, "savepv: ");
fd206186 175 strerrorcat(errbuf, errno);
a0d0e21e 176 safefree(mp);
177 return NULL;
178 }
179 /*
180 * load should be declared load(const char *...). Thus we
181 * cast the path to a normal char *. Ugly.
182 */
183 if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
184 safefree(mp->name);
185 safefree(mp);
186 errvalid++;
187 strcpy(errbuf, "dlopen: ");
188 strcat(errbuf, path);
189 strcat(errbuf, ": ");
190 /*
191 * If AIX says the file is not executable, the error
192 * can be further described by querying the loader about
193 * the last error.
194 */
195 if (errno == ENOEXEC) {
196 char *tmp[BUFSIZ/sizeof(char *)];
197 if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
fd206186 198 strerrorcpy(errbuf, errno);
a0d0e21e 199 else {
200 char **p;
201 for (p = tmp; *p; p++)
202 caterr(*p);
203 }
204 } else
fd206186 205 strerrorcat(errbuf, errno);
a0d0e21e 206 return NULL;
207 }
208 mp->refCnt = 1;
209 mp->next = modList;
210 modList = mp;
211 if (loadbind(0, mainModule, mp->entry) == -1) {
212 dlclose(mp);
213 errvalid++;
214 strcpy(errbuf, "loadbind: ");
fd206186 215 strerrorcat(errbuf, errno);
a0d0e21e 216 return NULL;
217 }
218 if (readExports(mp) == -1) {
219 dlclose(mp);
220 return NULL;
221 }
222 return mp;
223}
224
225/*
226 * Attempt to decipher an AIX loader error message and append it
227 * to our static error message buffer.
228 */
229static void caterr(char *s)
230{
231 register char *p = s;
232
233 while (*p >= '0' && *p <= '9')
234 p++;
235 switch(atoi(s)) {
236 case L_ERROR_TOOMANY:
237 strcat(errbuf, "to many errors");
238 break;
239 case L_ERROR_NOLIB:
240 strcat(errbuf, "can't load library");
241 strcat(errbuf, p);
242 break;
243 case L_ERROR_UNDEF:
244 strcat(errbuf, "can't find symbol");
245 strcat(errbuf, p);
246 break;
247 case L_ERROR_RLDBAD:
248 strcat(errbuf, "bad RLD");
249 strcat(errbuf, p);
250 break;
251 case L_ERROR_FORMAT:
252 strcat(errbuf, "bad exec format in");
253 strcat(errbuf, p);
254 break;
255 case L_ERROR_ERRNO:
fd206186 256 strerrorcat(errbuf, atoi(++p));
a0d0e21e 257 break;
258 default:
259 strcat(errbuf, s);
260 break;
261 }
262}
263
264void *dlsym(void *handle, const char *symbol)
265{
266 register ModulePtr mp = (ModulePtr)handle;
267 register ExportPtr ep;
268 register int i;
269
270 /*
271 * Could speed up search, but I assume that one assigns
272 * the result to function pointers anyways.
273 */
274 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
275 if (strcmp(ep->name, symbol) == 0)
276 return ep->addr;
277 errvalid++;
278 strcpy(errbuf, "dlsym: undefined symbol ");
279 strcat(errbuf, symbol);
280 return NULL;
281}
282
283char *dlerror(void)
284{
285 if (errvalid) {
286 errvalid = 0;
287 return errbuf;
288 }
289 return NULL;
290}
291
292int dlclose(void *handle)
293{
294 register ModulePtr mp = (ModulePtr)handle;
295 int result;
296 register ModulePtr mp1;
297
298 if (--mp->refCnt > 0)
299 return 0;
300 result = unload(mp->entry);
301 if (result == -1) {
302 errvalid++;
fd206186 303 strerrorcpy(errbuf, errno);
a0d0e21e 304 }
305 if (mp->exports) {
306 register ExportPtr ep;
307 register int i;
308 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
309 if (ep->name)
310 safefree(ep->name);
311 safefree(mp->exports);
312 }
313 if (mp == modList)
314 modList = mp->next;
315 else {
316 for (mp1 = modList; mp1; mp1 = mp1->next)
317 if (mp1->next == mp) {
318 mp1->next = mp->next;
319 break;
320 }
321 }
322 safefree(mp->name);
323 safefree(mp);
324 return result;
325}
326
327static void terminate(void)
328{
329 while (modList)
330 dlclose(modList);
331}
332
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.
338 */
339void *calloc(size_t ne, size_t sz)
340{
341 void *out;
342
343 out = (void *) safemalloc(ne*sz);
344 memzero(out, ne*sz);
345 return(out);
346}
347
348/*
349 * Build the export table from the XCOFF .loader section.
350 */
351static int readExports(ModulePtr mp)
352{
353 LDFILE *ldp = NULL;
354 SCNHDR sh;
355 LDHDR *lhp;
356 char *ldbuf;
357 LDSYM *ls;
358 int i;
359 ExportPtr ep;
360
361 if ((ldp = ldopen(mp->name, ldp)) == NULL) {
362 struct ld_info *lp;
363 char *buf;
364 int size = 4*1024;
365 if (errno != ENOENT) {
366 errvalid++;
367 strcpy(errbuf, "readExports: ");
fd206186 368 strerrorcat(errbuf, errno);
a0d0e21e 369 return -1;
370 }
371 /*
372 * The module might be loaded due to the LIBPATH
373 * environment variable. Search for the loaded
374 * module using L_GETINFO.
375 */
376 if ((buf = safemalloc(size)) == NULL) {
377 errvalid++;
378 strcpy(errbuf, "readExports: ");
fd206186 379 strerrorcat(errbuf, errno);
a0d0e21e 380 return -1;
381 }
382 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
383 safefree(buf);
384 size += 4*1024;
385 if ((buf = safemalloc(size)) == NULL) {
386 errvalid++;
387 strcpy(errbuf, "readExports: ");
fd206186 388 strerrorcat(errbuf, errno);
a0d0e21e 389 return -1;
390 }
391 }
392 if (i == -1) {
393 errvalid++;
394 strcpy(errbuf, "readExports: ");
fd206186 395 strerrorcat(errbuf, errno);
a0d0e21e 396 safefree(buf);
397 return -1;
398 }
399 /*
400 * Traverse the list of loaded modules. The entry point
401 * returned by load() does actually point to the data
402 * segment origin.
403 */
404 lp = (struct ld_info *)buf;
405 while (lp) {
406 if (lp->ldinfo_dataorg == mp->entry) {
407 ldp = ldopen(lp->ldinfo_filename, ldp);
408 break;
409 }
410 if (lp->ldinfo_next == 0)
411 lp = NULL;
412 else
413 lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
414 }
415 safefree(buf);
416 if (!ldp) {
417 errvalid++;
418 strcpy(errbuf, "readExports: ");
fd206186 419 strerrorcat(errbuf, errno);
a0d0e21e 420 return -1;
421 }
422 }
423 if (TYPE(ldp) != U802TOCMAGIC) {
424 errvalid++;
425 strcpy(errbuf, "readExports: bad magic");
426 while(ldclose(ldp) == FAILURE)
427 ;
428 return -1;
429 }
430 if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
431 errvalid++;
432 strcpy(errbuf, "readExports: cannot read loader section header");
433 while(ldclose(ldp) == FAILURE)
434 ;
435 return -1;
436 }
437 /*
438 * We read the complete loader section in one chunk, this makes
439 * finding long symbol names residing in the string table easier.
440 */
441 if ((ldbuf = (char *)safemalloc(sh.s_size)) == NULL) {
442 errvalid++;
443 strcpy(errbuf, "readExports: ");
fd206186 444 strerrorcat(errbuf, errno);
a0d0e21e 445 while(ldclose(ldp) == FAILURE)
446 ;
447 return -1;
448 }
449 if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
450 errvalid++;
451 strcpy(errbuf, "readExports: cannot seek to loader section");
452 safefree(ldbuf);
453 while(ldclose(ldp) == FAILURE)
454 ;
455 return -1;
456 }
1553ab04 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. */
459#ifdef USE_PERLIO
460 if (FREAD(ldbuf, sh.s_size, 1, ldp) != sh.s_size) {
461#else
a0d0e21e 462 if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
1553ab04 463#endif
a0d0e21e 464 errvalid++;
465 strcpy(errbuf, "readExports: cannot read loader section");
466 safefree(ldbuf);
467 while(ldclose(ldp) == FAILURE)
468 ;
469 return -1;
470 }
471 lhp = (LDHDR *)ldbuf;
472 ls = (LDSYM *)(ldbuf+LDHDRSZ);
473 /*
474 * Count the number of exports to include in our export table.
475 */
476 for (i = lhp->l_nsyms; i; i--, ls++) {
477 if (!LDR_EXPORT(*ls))
478 continue;
479 mp->nExports++;
480 }
481 Newz(1001, mp->exports, mp->nExports, Export);
482 if (mp->exports == NULL) {
483 errvalid++;
484 strcpy(errbuf, "readExports: ");
fd206186 485 strerrorcat(errbuf, errno);
a0d0e21e 486 safefree(ldbuf);
487 while(ldclose(ldp) == FAILURE)
488 ;
489 return -1;
490 }
491 /*
492 * Fill in the export table. All entries are relative to
493 * the entry point we got from load.
494 */
495 ep = mp->exports;
496 ls = (LDSYM *)(ldbuf+LDHDRSZ);
497 for (i = lhp->l_nsyms; i; i--, ls++) {
498 char *symname;
499 if (!LDR_EXPORT(*ls))
500 continue;
501 if (ls->l_zeroes == 0)
502 symname = ls->l_offset+lhp->l_stoff+ldbuf;
503 else
504 symname = ls->l_name;
505 ep->name = savepv(symname);
506 ep->addr = (void *)((unsigned long)mp->entry + ls->l_value);
507 ep++;
508 }
509 safefree(ldbuf);
510 while(ldclose(ldp) == FAILURE)
511 ;
512 return 0;
513}
514
515/*
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.
518 */
519static void * findMain(void)
520{
521 struct ld_info *lp;
522 char *buf;
523 int size = 4*1024;
524 int i;
525 void *ret;
526
527 if ((buf = safemalloc(size)) == NULL) {
528 errvalid++;
529 strcpy(errbuf, "findMain: ");
fd206186 530 strerrorcat(errbuf, errno);
a0d0e21e 531 return NULL;
532 }
533 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
534 safefree(buf);
535 size += 4*1024;
536 if ((buf = safemalloc(size)) == NULL) {
537 errvalid++;
538 strcpy(errbuf, "findMain: ");
fd206186 539 strerrorcat(errbuf, errno);
a0d0e21e 540 return NULL;
541 }
542 }
543 if (i == -1) {
544 errvalid++;
545 strcpy(errbuf, "findMain: ");
fd206186 546 strerrorcat(errbuf, errno);
a0d0e21e 547 safefree(buf);
548 return NULL;
549 }
550 /*
551 * The first entry is the main module. The entry point
552 * returned by load() does actually point to the data
553 * segment origin.
554 */
555 lp = (struct ld_info *)buf;
556 ret = lp->ldinfo_dataorg;
557 safefree(buf);
558 return ret;
559}
560
561/* dl_dlopen.xs
562 *
563 * Platform: SunOS/Solaris, possibly others which use dlopen.
564 * Author: Paul Marquess (pmarquess@bfsec.bt.co.uk)
565 * Created: 10th July 1994
566 *
567 * Modified:
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
573 *
574 */
575
576/* Porting notes:
577
578 see dl_dlopen.xs
579
580*/
581
582#include "dlutils.c" /* SaveError() etc */
583
584
585static void
586dl_private_init()
587{
588 (void)dl_generic_private_init();
589}
590
591MODULE = DynaLoader PACKAGE = DynaLoader
592
593BOOT:
594 (void)dl_private_init();
595
596
597void *
ff7f3c60 598dl_load_file(filename, flags=0)
599 char * filename
600 int flags
a0d0e21e 601 CODE:
ff7f3c60 602 DLDEBUG(1,PerlIO_printf(PerlIO_stderr(), "dl_load_file(%s,%x):\n", filename,flags));
603 if (flags & 0x01)
604 warn("Can't make loaded symbols global on this platform while loading %s",filename);
a0d0e21e 605 RETVAL = dlopen(filename, 1) ;
760ac839 606 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), " libref=%x\n", RETVAL));
a0d0e21e 607 ST(0) = sv_newmortal() ;
608 if (RETVAL == NULL)
609 SaveError("%s",dlerror()) ;
610 else
611 sv_setiv( ST(0), (IV)RETVAL);
612
613
614void *
615dl_find_symbol(libhandle, symbolname)
616 void * libhandle
617 char * symbolname
618 CODE:
760ac839 619 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), "dl_find_symbol(handle=%x, symbol=%s)\n",
a0d0e21e 620 libhandle, symbolname));
621 RETVAL = dlsym(libhandle, symbolname);
760ac839 622 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), " symbolref = %x\n", RETVAL));
a0d0e21e 623 ST(0) = sv_newmortal() ;
624 if (RETVAL == NULL)
625 SaveError("%s",dlerror()) ;
626 else
627 sv_setiv( ST(0), (IV)RETVAL);
628
629
630void
631dl_undef_symbols()
632 PPCODE:
633
634
635
636# These functions should not need changing on any platform:
637
638void
639dl_install_xsub(perl_name, symref, filename="$Package")
640 char * perl_name
641 void * symref
642 char * filename
643 CODE:
760ac839 644 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), "dl_install_xsub(name=%s, symref=%x)\n",
a0d0e21e 645 perl_name, symref));
646 ST(0)=sv_2mortal(newRV((SV*)newXS(perl_name, (void(*)())symref, filename)));
647
648
649char *
650dl_error()
651 CODE:
652 RETVAL = LastError ;
653 OUTPUT:
654 RETVAL
655
656# end.