1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * dso.c -- DSO system function emulation for AIX
19 *
20 * This is *only* intended for AIX < 4.3.
21 */
22
23 /*
24 * Based on libdl (dlfcn.c/dlfcn.h) which is
25 * Copyright (c) 1992,1993,1995,1996,1997,1988
26 * Jens-Uwe Mager, Helios Software GmbH, Hannover, Germany.
27 *
28 * Not derived from licensed software.
29 *
30 * Permission is granted to freely use, copy, modify, and redistribute
31 * this software, provided that the author is not construed to be liable
32 * for any results of using the software, alterations are clearly marked
33 * as such, and this notice is not modified.
34 *
35 * Changes marked with `--jwe' were made on April 7 1996 by
36 * John W. Eaton <[email protected]> to support g++
37 *
38 * Bundled, stripped and adjusted on April 1998 as one single source file
39 * for inclusion into the Apache HTTP server by
40 * Ralf S. Engelschall <[email protected]>
41 *
42 * Added to APR by David Reid April 2000
43 */
44
45 #include <stdio.h>
46 #include <errno.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <sys/types.h>
50 #include <sys/ldr.h>
51 #include <a.out.h>
52 #include "apr_arch_dso.h"
53 #include "apr_portable.h"
54
55 #if APR_HAS_DSO
56
57 #undef FREAD
58 #undef FWRITE
59 #include <ldfcn.h>
60
61 /*
62 * AIX 4.3 does remove some useful definitions from ldfcn.h. Define
63 * these here to compensate for that lossage.
64 */
65 #ifndef BEGINNING
66 #define BEGINNING SEEK_SET
67 #endif
68 #ifndef FSEEK
69 #define FSEEK(ldptr,o,p) fseek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr) +o):o,p)
70 #endif
71 #ifndef FREAD
72 #define FREAD(p,s,n,ldptr) fread(p,s,n,IOPTR(ldptr))
73 #endif
74
75 /*
76 * Mode flags for the dlopen routine.
77 */
78 #undef RTLD_LAZY
79 #define RTLD_LAZY 1 /* lazy function call binding */
80 #undef RTLD_NOW
81 #define RTLD_NOW 2 /* immediate function call binding */
82 #undef RTLD_GLOBAL
83 #define RTLD_GLOBAL 0x100 /* allow symbols to be global */
84
85 /*
86 * To be able to initialize, a library may provide a dl_info structure
87 * that contains functions to be called to initialize and terminate.
88 */
89 struct dl_info {
90 void (*init) (void);
91 void (*fini) (void);
92 };
93
94 /* APR functions...
95 *
96 * As the AIX functions have been declared in the header file we just
97 * add the basic "wrappers" here.
98 */
99
apr_os_dso_handle_put(apr_dso_handle_t ** aprdso,apr_os_dso_handle_t osdso,apr_pool_t * pool)100 APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso,
101 apr_os_dso_handle_t osdso,
102 apr_pool_t *pool)
103 {
104 *aprdso = apr_pcalloc(pool, sizeof **aprdso);
105 (*aprdso)->handle = osdso;
106 (*aprdso)->pool = pool;
107 return APR_SUCCESS;
108 }
109
apr_os_dso_handle_get(apr_os_dso_handle_t * osdso,apr_dso_handle_t * aprdso)110 APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso,
111 apr_dso_handle_t *aprdso)
112 {
113 *osdso = aprdso->handle;
114 return APR_SUCCESS;
115 }
116
dso_cleanup(void * thedso)117 static apr_status_t dso_cleanup(void *thedso)
118 {
119 apr_dso_handle_t *dso = thedso;
120
121 if (dso->handle != NULL && dlclose(dso->handle) != 0)
122 return APR_EINIT;
123 dso->handle = NULL;
124
125 return APR_SUCCESS;
126 }
127
apr_dso_load(apr_dso_handle_t ** res_handle,const char * path,apr_pool_t * ctx)128 APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle,
129 const char *path, apr_pool_t *ctx)
130 {
131 void *os_handle = dlopen((char *)path, RTLD_NOW | RTLD_GLOBAL);
132
133 *res_handle = apr_pcalloc(ctx, sizeof(*res_handle));
134
135 if(os_handle == NULL) {
136 (*res_handle)->errormsg = dlerror();
137 return APR_EDSOOPEN;
138 }
139
140 (*res_handle)->handle = (void*)os_handle;
141 (*res_handle)->pool = ctx;
142 (*res_handle)->errormsg = NULL;
143
144 apr_pool_cleanup_register(ctx, *res_handle, dso_cleanup, apr_pool_cleanup_null);
145
146 return APR_SUCCESS;
147 }
148
apr_dso_unload(apr_dso_handle_t * handle)149 APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle)
150 {
151 return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup);
152 }
153
apr_dso_sym(apr_dso_handle_sym_t * ressym,apr_dso_handle_t * handle,const char * symname)154 APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym,
155 apr_dso_handle_t *handle,
156 const char *symname)
157 {
158 void *retval = dlsym(handle->handle, symname);
159
160 if (retval == NULL) {
161 handle->errormsg = dlerror();
162 return APR_ESYMNOTFOUND;
163 }
164
165 *ressym = retval;
166 return APR_SUCCESS;
167 }
168
apr_dso_error(apr_dso_handle_t * dso,char * buffer,apr_size_t buflen)169 APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, apr_size_t buflen)
170 {
171 if (dso->errormsg) {
172 apr_cpystrn(buffer, dso->errormsg, buflen);
173 return dso->errormsg;
174 }
175 return "No Error";
176 }
177
178
179
180 /*
181 * We simulate dlopen() et al. through a call to load. Because AIX has
182 * no call to find an exported symbol we read the loader section of the
183 * loaded module and build a list of exported symbols and their virtual
184 * address.
185 */
186
187 typedef struct {
188 char *name; /* the symbols's name */
189 void *addr; /* its relocated virtual address */
190 } Export, *ExportPtr;
191
192 /*
193 * xlC uses the following structure to list its constructors and
194 * destructors. This is gleaned from the output of munch.
195 */
196 typedef struct {
197 void (*init) (void); /* call static constructors */
198 void (*term) (void); /* call static destructors */
199 } Cdtor, *CdtorPtr;
200
201 typedef void (*GccCDtorPtr) (void);
202
203 /*
204 * The void * handle returned from dlopen is actually a ModulePtr.
205 */
206 typedef struct Module {
207 struct Module *next;
208 char *name; /* module name for refcounting */
209 int refCnt; /* the number of references */
210 void *entry; /* entry point from load */
211 struct dl_info *info; /* optional init/terminate functions */
212 CdtorPtr cdtors; /* optional C++ constructors */
213 GccCDtorPtr gcc_ctor; /* g++ constructors --jwe */
214 GccCDtorPtr gcc_dtor; /* g++ destructors --jwe */
215 int nExports; /* the number of exports found */
216 ExportPtr exports; /* the array of exports */
217 } Module, *ModulePtr;
218
219 /*
220 * We keep a list of all loaded modules to be able to call the fini
221 * handlers and destructors at atexit() time.
222 */
223 static ModulePtr modList;
224
225 /*
226 * The last error from one of the dl* routines is kept in static
227 * variables here. Each error is returned only once to the caller.
228 */
229 static char errbuf[BUFSIZ];
230 static int errvalid;
231
232 /*
233 * The `fixed' gcc header files on AIX 3.2.5 provide a prototype for
234 * strdup(). --jwe
235 */
236 extern char *strdup(const char *);
237 static void caterr(char *);
238 static int readExports(ModulePtr);
239 static void terminate(void);
240 static void *findMain(void);
241
dlopen(const char * path,int mode)242 void *dlopen(const char *path, int mode)
243 {
244 register ModulePtr mp;
245 static void *mainModule;
246
247 /*
248 * Upon the first call register a terminate handler that will
249 * close all libraries. Also get a reference to the main module
250 * for use with loadbind.
251 */
252 if (!mainModule) {
253 if ((mainModule = findMain()) == NULL)
254 return NULL;
255 atexit(terminate);
256 }
257 /*
258 * Scan the list of modules if we have the module already loaded.
259 */
260 for (mp = modList; mp; mp = mp->next)
261 if (strcmp(mp->name, path) == 0) {
262 mp->refCnt++;
263 return mp;
264 }
265 if ((mp = (ModulePtr) calloc(1, sizeof(*mp))) == NULL) {
266 errvalid++;
267 strcpy(errbuf, "calloc: ");
268 strcat(errbuf, strerror(errno));
269 return NULL;
270 }
271 if ((mp->name = strdup(path)) == NULL) {
272 errvalid++;
273 strcpy(errbuf, "strdup: ");
274 strcat(errbuf, strerror(errno));
275 free(mp);
276 return NULL;
277 }
278 /*
279 * load should be declared load(const char *...). Thus we
280 * cast the path to a normal char *. Ugly.
281 */
282 if ((mp->entry = (void *) loadAndInit((char *) path, L_NOAUTODEFER, NULL)) == NULL) {
283 free(mp->name);
284 free(mp);
285 errvalid++;
286 strcpy(errbuf, "dlopen: ");
287 strcat(errbuf, path);
288 strcat(errbuf, ": ");
289 /*
290 * If AIX says the file is not executable, the error
291 * can be further described by querying the loader about
292 * the last error.
293 */
294 if (errno == ENOEXEC) {
295 char *tmp[BUFSIZ / sizeof(char *)];
296 if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
297 strcpy(errbuf, strerror(errno));
298 else {
299 char **p;
300 for (p = tmp; *p; p++)
301 caterr(*p);
302 }
303 }
304 else
305 strcat(errbuf, strerror(errno));
306 return NULL;
307 }
308 mp->refCnt = 1;
309 mp->next = modList;
310 modList = mp;
311 if (loadbind(0, mainModule, mp->entry) == -1) {
312 dlclose(mp);
313 errvalid++;
314 strcpy(errbuf, "loadbind: ");
315 strcat(errbuf, strerror(errno));
316 return NULL;
317 }
318 /*
319 * If the user wants global binding, loadbind against all other
320 * loaded modules.
321 */
322 if (mode & RTLD_GLOBAL) {
323 register ModulePtr mp1;
324 for (mp1 = mp->next; mp1; mp1 = mp1->next)
325 if (loadbind(0, mp1->entry, mp->entry) == -1) {
326 dlclose(mp);
327 errvalid++;
328 strcpy(errbuf, "loadbind: ");
329 strcat(errbuf, strerror(errno));
330 return NULL;
331 }
332 }
333 if (readExports(mp) == -1) {
334 dlclose(mp);
335 return NULL;
336 }
337 /*
338 * If there is a dl_info structure, call the init function.
339 */
340 if (mp->info = (struct dl_info *) dlsym(mp, "dl_info")) {
341 if (mp->info->init)
342 (*mp->info->init) ();
343 }
344 else
345 errvalid = 0;
346 /*
347 * If the shared object was compiled using xlC we will need
348 * to call static constructors (and later on dlclose destructors).
349 */
350 if (mp->cdtors = (CdtorPtr) dlsym(mp, "__cdtors")) {
351 CdtorPtr cp = mp->cdtors;
352 while (cp->init || cp->term) {
353 if (cp->init && cp->init != (void (*)(void)) 0xffffffff)
354 (*cp->init) ();
355 cp++;
356 }
357 /*
358 * If the shared object was compiled using g++, we will need
359 * to call global constructors using the _GLOBAL__DI function,
360 * and later, global destructors using the _GLOBAL_DD
361 * funciton. --jwe
362 */
363 }
364 else if (mp->gcc_ctor = (GccCDtorPtr) dlsym(mp, "_GLOBAL__DI")) {
365 (*mp->gcc_ctor) ();
366 mp->gcc_dtor = (GccCDtorPtr) dlsym(mp, "_GLOBAL__DD");
367 }
368 else
369 errvalid = 0;
370 return mp;
371 }
372
373 /*
374 * Attempt to decipher an AIX loader error message and append it
375 * to our static error message buffer.
376 */
caterr(char * s)377 static void caterr(char *s)
378 {
379 register char *p = s;
380
381 while (*p >= '0' && *p <= '9')
382 p++;
383 switch (atoi(s)) {
384 case L_ERROR_TOOMANY:
385 strcat(errbuf, "to many errors");
386 break;
387 case L_ERROR_NOLIB:
388 strcat(errbuf, "can't load library");
389 strcat(errbuf, p);
390 break;
391 case L_ERROR_UNDEF:
392 strcat(errbuf, "can't find symbol");
393 strcat(errbuf, p);
394 break;
395 case L_ERROR_RLDBAD:
396 strcat(errbuf, "bad RLD");
397 strcat(errbuf, p);
398 break;
399 case L_ERROR_FORMAT:
400 strcat(errbuf, "bad exec format in");
401 strcat(errbuf, p);
402 break;
403 case L_ERROR_ERRNO:
404 strcat(errbuf, strerror(atoi(++p)));
405 break;
406 default:
407 strcat(errbuf, s);
408 break;
409 }
410 }
411
dlsym(void * handle,const char * symbol)412 void *dlsym(void *handle, const char *symbol)
413 {
414 register ModulePtr mp = (ModulePtr) handle;
415 register ExportPtr ep;
416 register int i;
417
418 /*
419 * Could speed up the search, but I assume that one assigns
420 * the result to function pointers anyways.
421 */
422 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
423 if (strcmp(ep->name, symbol) == 0)
424 return ep->addr;
425 errvalid++;
426 strcpy(errbuf, "dlsym: undefined symbol ");
427 strcat(errbuf, symbol);
428 return NULL;
429 }
430
dlerror(void)431 const char *dlerror(void)
432 {
433 if (errvalid) {
434 errvalid = 0;
435 return errbuf;
436 }
437 return NULL;
438 }
439
dlclose(void * handle)440 int dlclose(void *handle)
441 {
442 register ModulePtr mp = (ModulePtr) handle;
443 int result;
444 register ModulePtr mp1;
445
446 if (--mp->refCnt > 0)
447 return 0;
448 if (mp->info && mp->info->fini)
449 (*mp->info->fini) ();
450 if (mp->cdtors) {
451 CdtorPtr cp = mp->cdtors;
452 while (cp->init || cp->term) {
453 if (cp->term && cp->init != (void (*)(void)) 0xffffffff)
454 (*cp->term) ();
455 cp++;
456 }
457 /*
458 * If the function to handle global destructors for g++
459 * exists, call it. --jwe
460 */
461 }
462 else if (mp->gcc_dtor) {
463 (*mp->gcc_dtor) ();
464 }
465 result = unload(mp->entry);
466 if (result == -1) {
467 errvalid++;
468 strcpy(errbuf, strerror(errno));
469 }
470 if (mp->exports) {
471 register ExportPtr ep;
472 register int i;
473 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
474 if (ep->name)
475 free(ep->name);
476 free(mp->exports);
477 }
478 if (mp == modList)
479 modList = mp->next;
480 else {
481 for (mp1 = modList; mp1; mp1 = mp1->next)
482 if (mp1->next == mp) {
483 mp1->next = mp->next;
484 break;
485 }
486 }
487 free(mp->name);
488 free(mp);
489 return result;
490 }
491
terminate(void)492 static void terminate(void)
493 {
494 while (modList)
495 dlclose(modList);
496 }
497
498 /*
499 * Build the export table from the XCOFF .loader section.
500 */
readExports(ModulePtr mp)501 static int readExports(ModulePtr mp)
502 {
503 LDFILE *ldp = NULL;
504 SCNHDR sh, shdata;
505 LDHDR *lhp;
506 char *ldbuf;
507 LDSYM *ls;
508 int i;
509 ExportPtr ep;
510 struct ld_info *lp;
511 char *buf;
512 int size = 4 * 1024;
513 void *dataorg;
514
515 /*
516 * The module might be loaded due to the LIBPATH
517 * environment variable. Search for the loaded
518 * module using L_GETINFO.
519 */
520 if ((buf = malloc(size)) == NULL) {
521 errvalid++;
522 strcpy(errbuf, "readExports: ");
523 strcat(errbuf, strerror(errno));
524 return -1;
525 }
526 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
527 free(buf);
528 size += 4 * 1024;
529 if ((buf = malloc(size)) == NULL) {
530 errvalid++;
531 strcpy(errbuf, "readExports: ");
532 strcat(errbuf, strerror(errno));
533 return -1;
534 }
535 }
536 if (i == -1) {
537 errvalid++;
538 strcpy(errbuf, "readExports: ");
539 strcat(errbuf, strerror(errno));
540 free(buf);
541 return -1;
542 }
543 /*
544 * Traverse the list of loaded modules. The entry point
545 * returned by load() does actually point to the TOC
546 * entry contained in the data segment.
547 */
548 lp = (struct ld_info *) buf;
549 while (lp) {
550 if ((unsigned long) mp->entry >= (unsigned long) lp->ldinfo_dataorg &&
551 (unsigned long) mp->entry < (unsigned long) lp->ldinfo_dataorg +
552 lp->ldinfo_datasize) {
553 dataorg = lp->ldinfo_dataorg;
554 ldp = ldopen(lp->ldinfo_filename, ldp);
555 break;
556 }
557 if (lp->ldinfo_next == 0)
558 lp = NULL;
559 else
560 lp = (struct ld_info *) ((char *) lp + lp->ldinfo_next);
561 }
562 free(buf);
563 if (!ldp) {
564 errvalid++;
565 strcpy(errbuf, "readExports: ");
566 strcat(errbuf, strerror(errno));
567 return -1;
568 }
569 if (TYPE(ldp) != U802TOCMAGIC) {
570 errvalid++;
571 strcpy(errbuf, "readExports: bad magic");
572 while (ldclose(ldp) == FAILURE);
573 return -1;
574 }
575 /*
576 * Get the padding for the data section. This is needed for
577 * AIX 4.1 compilers. This is used when building the final
578 * function pointer to the exported symbol.
579 */
580 if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
581 errvalid++;
582 strcpy(errbuf, "readExports: cannot read data section header");
583 while (ldclose(ldp) == FAILURE);
584 return -1;
585 }
586 if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
587 errvalid++;
588 strcpy(errbuf, "readExports: cannot read loader section header");
589 while (ldclose(ldp) == FAILURE);
590 return -1;
591 }
592 /*
593 * We read the complete loader section in one chunk, this makes
594 * finding long symbol names residing in the string table easier.
595 */
596 if ((ldbuf = (char *) malloc(sh.s_size)) == NULL) {
597 errvalid++;
598 strcpy(errbuf, "readExports: ");
599 strcat(errbuf, strerror(errno));
600 while (ldclose(ldp) == FAILURE);
601 return -1;
602 }
603 if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
604 errvalid++;
605 strcpy(errbuf, "readExports: cannot seek to loader section");
606 free(ldbuf);
607 while (ldclose(ldp) == FAILURE);
608 return -1;
609 }
610 if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
611 errvalid++;
612 strcpy(errbuf, "readExports: cannot read loader section");
613 free(ldbuf);
614 while (ldclose(ldp) == FAILURE);
615 return -1;
616 }
617 lhp = (LDHDR *) ldbuf;
618 ls = (LDSYM *) (ldbuf + LDHDRSZ);
619 /*
620 * Count the number of exports to include in our export table.
621 */
622 for (i = lhp->l_nsyms; i; i--, ls++) {
623 if (!LDR_EXPORT(*ls))
624 continue;
625 mp->nExports++;
626 }
627 if ((mp->exports = (ExportPtr) calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
628 errvalid++;
629 strcpy(errbuf, "readExports: ");
630 strcat(errbuf, strerror(errno));
631 free(ldbuf);
632 while (ldclose(ldp) == FAILURE);
633 return -1;
634 }
635 /*
636 * Fill in the export table. All entries are relative to
637 * the beginning of the data origin.
638 */
639 ep = mp->exports;
640 ls = (LDSYM *) (ldbuf + LDHDRSZ);
641 for (i = lhp->l_nsyms; i; i--, ls++) {
642 char *symname;
643 char tmpsym[SYMNMLEN + 1];
644 if (!LDR_EXPORT(*ls))
645 continue;
646 if (ls->l_zeroes == 0)
647 symname = ls->l_offset + lhp->l_stoff + ldbuf;
648 else {
649 /*
650 * The l_name member is not zero terminated, we
651 * must copy the first SYMNMLEN chars and make
652 * sure we have a zero byte at the end.
653 */
654 strncpy(tmpsym, ls->l_name, SYMNMLEN);
655 tmpsym[SYMNMLEN] = '\0';
656 symname = tmpsym;
657 }
658 ep->name = strdup(symname);
659 ep->addr = (void *) ((unsigned long) dataorg +
660 ls->l_value - shdata.s_vaddr);
661 ep++;
662 }
663 free(ldbuf);
664 while (ldclose(ldp) == FAILURE);
665 return 0;
666 }
667
668 /*
669 * Find the main modules data origin. This is used as export pointer
670 * for loadbind() to be able to resolve references to the main part.
671 */
findMain(void)672 static void *findMain(void)
673 {
674 struct ld_info *lp;
675 char *buf;
676 int size = 4 * 1024;
677 int i;
678 void *ret;
679
680 if ((buf = malloc(size)) == NULL) {
681 errvalid++;
682 strcpy(errbuf, "findMain: ");
683 strcat(errbuf, strerror(errno));
684 return NULL;
685 }
686 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
687 free(buf);
688 size += 4 * 1024;
689 if ((buf = malloc(size)) == NULL) {
690 errvalid++;
691 strcpy(errbuf, "findMain: ");
692 strcat(errbuf, strerror(errno));
693 return NULL;
694 }
695 }
696 if (i == -1) {
697 errvalid++;
698 strcpy(errbuf, "findMain: ");
699 strcat(errbuf, strerror(errno));
700 free(buf);
701 return NULL;
702 }
703 /*
704 * The first entry is the main module. The data segment
705 * starts with the TOC entries for all exports, so the
706 * data segment origin works as argument for loadbind.
707 */
708 lp = (struct ld_info *) buf;
709 ret = lp->ldinfo_dataorg;
710 free(buf);
711 return ret;
712 }
713
714 #endif
715