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