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