upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / dso / aix / dso.c
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 <jwe@bevo.che.wisc.edu> 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 <rse@apache.org>
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
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
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
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
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
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
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
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
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  */
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
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
431 const char *dlerror(void)
432 {
433     if (errvalid) {
434         errvalid = 0;
435         return errbuf;
436     }
437     return NULL;
438 }
439
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
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  */
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  */
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