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