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 */
89struct 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
100APR_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
110APR_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
117static 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
128APR_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
149APR_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
154APR_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
169APR_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
187typedef 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 */
196typedef struct {
197    void (*init) (void);	/* call static constructors */
198    void (*term) (void);	/* call static destructors */
199} Cdtor, *CdtorPtr;
200
201typedef void (*GccCDtorPtr) (void);
202
203/*
204 * The void * handle returned from dlopen is actually a ModulePtr.
205 */
206typedef 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 */
223static 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 */
229static char errbuf[BUFSIZ];
230static int errvalid;
231
232/*
233 * The `fixed' gcc header files on AIX 3.2.5 provide a prototype for
234 * strdup().  --jwe
235 */
236extern char *strdup(const char *);
237static void caterr(char *);
238static int readExports(ModulePtr);
239static void terminate(void);
240static void *findMain(void);
241
242void *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 */
377static 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
412void *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
431const char *dlerror(void)
432{
433    if (errvalid) {
434	errvalid = 0;
435	return errbuf;
436    }
437    return NULL;
438}
439
440int 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
492static void terminate(void)
493{
494    while (modList)
495	dlclose(modList);
496}
497
498/*
499 * Build the export table from the XCOFF .loader section.
500 */
501static 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 */
672static 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