source: trunk/third/cyrus-sasl/dlcompat-20010505/dlopen.c @ 18842

Revision 18842, 13.6 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18841, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * This file was modified by Christoph Pfisterer <cp@chrisp.de>
3 * on Tue, Jan 23 2001. See the file "ChangeLog" for details of what
4 * was changed.
5 *
6 *
7 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
8 *
9 * @APPLE_LICENSE_HEADER_START@
10 *
11 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
12 * Reserved.  This file contains Original Code and/or Modifications of
13 * Original Code as defined in and that are subject to the Apple Public
14 * Source License Version 1.1 (the "License").  You may not use this file
15 * except in compliance with the License.  Please obtain a copy of the
16 * License at http://www.apple.com/publicsource and read it before using
17 * this file.
18 *
19 * The Original Code and all software distributed under the License are
20 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
21 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
22 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
24 * License for the specific language governing rights and limitations
25 * under the License.
26 *
27 * @APPLE_LICENSE_HEADER_END@
28 */
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <errno.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <limits.h>
36#include "mach-o/dyld.h"
37#include "dlfcn.h"
38
39/*
40 * debugging macros
41 */
42#if DEBUG > 0
43#define DEBUG_PRINT(format) fprintf(stderr,(format));fflush(stderr)
44#define DEBUG_PRINT1(format,arg1) fprintf(stderr,(format),(arg1));\
45  fflush(stderr)
46#define DEBUG_PRINT2(format,arg1,arg2) fprintf(stderr,(format),\
47  (arg1),(arg2));fflush(stderr)
48#define DEBUG_PRINT3(format,arg1,arg2,arg3) fprintf(stderr,(format),\
49  (arg1),(arg2),(arg3));fflush(stderr)
50#else
51#define DEBUG_PRINT(format) /**/
52#define DEBUG_PRINT1(format,arg1) /**/
53#define DEBUG_PRINT2(format,arg1,arg2) /**/
54#define DEBUG_PRINT3(format,arg1,arg2,arg3) /**/
55#undef DEBUG
56#endif
57
58/*
59 * The structure of a dlopen() handle.
60 */
61struct dlopen_handle {
62    dev_t dev;          /* the path's device and inode number from stat(2) */
63    ino_t ino;
64    int dlopen_mode;    /* current dlopen mode for this handle */
65    int dlopen_count;   /* number of times dlopen() called on this handle */
66    NSModule module;    /* the NSModule returned by NSLinkModule() */
67    struct dlopen_handle *prev;
68    struct dlopen_handle *next;
69};
70static struct dlopen_handle *dlopen_handles = NULL;
71static const struct dlopen_handle main_program_handle = {NULL};
72static char *dlerror_pointer = NULL;
73
74/*
75 * NSMakePrivateModulePublic() is not part of the public dyld API so we define
76 * it here.  The internal dyld function pointer for
77 * __dyld_NSMakePrivateModulePublic is returned so thats all that maters to get
78 * the functionality need to implement the dlopen() interfaces.
79 */
80static
81int
82NSMakePrivateModulePublic(
83NSModule module)
84{
85    static int (*p)(NSModule module) = NULL;
86
87        if(p == NULL)
88            _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
89                              (unsigned long *)&p);
90        if(p == NULL){
91#ifdef DEBUG
92            printf("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
93                   "failed\n");
94#endif
95            return(FALSE);
96        }
97        return(p(module));
98}
99
100/*
101 * helper routine: search for a named module in various locations
102 */
103static
104int
105_dl_search_paths(
106const char *filename,
107char *pathbuf,
108struct stat *stat_buf)
109{
110    const char *pathspec;
111    const char *element;
112    const char *p;
113    char *q;
114    char *pathbuf_end;
115    const char *envvars[] = {
116        "$DYLD_LIBRARY_PATH",
117        "$LD_LIBRARY_PATH",
118        "/usr/lib:/lib",
119        NULL };
120    int envvar_index;
121
122        pathbuf_end = pathbuf + PATH_MAX - 8;
123
124        for(envvar_index = 0; envvars[envvar_index]; envvar_index++){
125            if(envvars[envvar_index][0] == '$'){
126                pathspec = getenv(envvars[envvar_index]+1);
127            }
128            else {
129                pathspec = envvars[envvar_index];
130            }
131
132            if(pathspec != NULL){
133                element = pathspec;
134                while(*element){
135                    /* extract path list element */
136                    p = element;
137                    q = pathbuf;
138                    while(*p && *p != PATHS_DELIMITER && q < pathbuf_end) {
139                        *q++ = *p++;
140                    }
141                    if(q == pathbuf){  /* empty element */
142                        if(*p){
143                            element = p+1;
144                            continue;
145                        }
146                        break;
147                    }
148                    if (*p){
149                        element = p+1;
150                    }
151                    else{
152                        element = p;  /* this terminates the loop */
153                    }
154
155                    /* add slash if neccessary */
156                    if(*(q-1) != '/' && q < pathbuf_end){
157                        *q++ = '/';
158                    }
159
160                    /* append module name */
161                    p = filename;
162                    while(*p && q < pathbuf_end) *q++ = *p++;
163                    *q++ = 0;
164
165                    if(q >= pathbuf_end){
166                        /* maybe add an error message here */
167                        break;
168                    }
169
170                    if(stat(pathbuf, stat_buf) == 0){
171                        return 0;
172                    }
173                }
174            }
175        }
176
177        /* we have searched everywhere, now we give up */
178        return -1;
179}
180
181/*
182 * dlopen() the MacOS X version of the FreeBSD dlopen() interface.
183 */
184void *
185dlopen(
186const char *path,
187int mode)
188{
189    const char *module_path;
190    void *retval;
191    struct stat stat_buf;
192    NSObjectFileImage objectFileImage;
193    NSObjectFileImageReturnCode ofile_result_code;
194    NSModule module;
195    struct dlopen_handle *p;
196    unsigned long options;
197    NSSymbol NSSymbol;
198    void (*init)(void);
199    char pathbuf[PATH_MAX];
200
201        DEBUG_PRINT2("libdl: dlopen(%s,0x%x) -> ", path, (unsigned int)mode);
202
203        dlerror_pointer = NULL;
204        /*
205         * A NULL path is to indicate the caller wants a handle for the
206         * main program.
207         */
208        if(path == NULL){
209            retval = (void *)&main_program_handle;
210            DEBUG_PRINT1("main / %p\n", retval);
211            return(retval);
212        }
213
214        /* see if the path exists and if so get the device and inode number */
215        if(stat(path, &stat_buf) == -1){
216            dlerror_pointer = strerror(errno);
217
218            if(path[0] == '/'){
219                DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
220                return(NULL);
221            }
222
223            /* search for the module in various places */
224            if(_dl_search_paths(path, pathbuf, &stat_buf)){
225                /* dlerror_pointer is unmodified */
226                DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
227                return(NULL);
228            }
229            DEBUG_PRINT1("found %s -> ", pathbuf);
230            module_path = pathbuf;
231            dlerror_pointer = NULL;
232        }
233        else{
234            module_path = path;
235        }
236
237        /*
238         * If we don't want an unshared handle see if we already have a handle
239         * for this path.
240         */
241        if((mode & RTLD_UNSHARED) != RTLD_UNSHARED){
242            p = dlopen_handles;
243            while(p != NULL){
244                if(p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino){
245                    /* skip unshared handles */
246                    if((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED)
247                        continue;
248                    /*
249                     * We have already created a handle for this path.  The
250                     * caller might be trying to promote an RTLD_LOCAL handle
251                     * to a RTLD_GLOBAL.  Or just looking it up with
252                     * RTLD_NOLOAD.
253                     */
254                    if((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL &&
255                       (mode & RTLD_GLOBAL) == RTLD_GLOBAL){
256                        /* promote the handle */
257                        if(NSMakePrivateModulePublic(p->module) == TRUE){
258                            p->dlopen_mode &= ~RTLD_LOCAL;
259                            p->dlopen_mode |= RTLD_GLOBAL;
260                            p->dlopen_count++;
261                            DEBUG_PRINT1("%p\n", p);
262                            return(p);
263                        }
264                        else{
265                            dlerror_pointer = "can't promote handle from "
266                                              "RTLD_LOCAL to RTLD_GLOBAL";
267                            DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
268                            return(NULL);
269                        }
270                    }
271                    p->dlopen_count++;
272                    DEBUG_PRINT1("%p\n", p);
273                    return(p);
274                }
275                p = p->next;
276            }
277        }
278       
279        /*
280         * We do not have a handle for this path if we were just trying to
281         * look it up return NULL to indicate we don't have it.
282         */
283        if((mode & RTLD_NOLOAD) == RTLD_NOLOAD){
284            dlerror_pointer = "no existing handle for path RTLD_NOLOAD test";
285            DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
286            return(NULL);
287        }
288
289        /* try to create an object file image from this path */
290        ofile_result_code = NSCreateObjectFileImageFromFile(module_path,
291                                                            &objectFileImage);
292        if(ofile_result_code != NSObjectFileImageSuccess){
293            switch(ofile_result_code){
294            case NSObjectFileImageFailure:
295                dlerror_pointer = "object file setup failure";
296                DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
297                return(NULL);
298            case NSObjectFileImageInappropriateFile:
299                dlerror_pointer = "not a Mach-O MH_BUNDLE file type";
300                DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
301                return(NULL);
302            case NSObjectFileImageArch:
303                dlerror_pointer = "no object for this architecture";
304                DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
305                return(NULL);
306            case NSObjectFileImageFormat:
307                dlerror_pointer = "bad object file format";
308                DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
309                return(NULL);
310            case NSObjectFileImageAccess:
311                dlerror_pointer = "can't read object file";
312                DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
313                return(NULL);
314            default:
315                dlerror_pointer = "unknown error from "
316                                  "NSCreateObjectFileImageFromFile()";
317                DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
318                return(NULL);
319            }
320        }
321
322        /* try to link in this object file image */
323        options = NSLINKMODULE_OPTION_PRIVATE;
324        if((mode & RTLD_NOW) == RTLD_NOW)
325            options |= NSLINKMODULE_OPTION_BINDNOW;
326        module = NSLinkModule(objectFileImage, module_path, options);
327        NSDestroyObjectFileImage(objectFileImage) ;
328        if(module == NULL){
329            dlerror_pointer = "NSLinkModule() failed for dlopen()";
330            DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
331            return(NULL);
332        }
333
334        /*
335         * If the handle is to be global promote the handle.  It is done this
336         * way to avoid multiply defined symbols.
337         */
338        if((mode & RTLD_GLOBAL) == RTLD_GLOBAL){
339            if(NSMakePrivateModulePublic(module) == FALSE){
340                dlerror_pointer = "can't promote handle from RTLD_LOCAL to "
341                                  "RTLD_GLOBAL";
342                DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
343                return(NULL);
344            }
345        }
346
347        p = malloc(sizeof(struct dlopen_handle));
348        if(p == NULL){
349            dlerror_pointer = "can't allocate memory for the dlopen handle";
350            DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
351            return(NULL);
352        }
353
354        /* fill in the handle */
355        p->dev = stat_buf.st_dev;
356        p->ino = stat_buf.st_ino;
357        if(mode & RTLD_GLOBAL)
358            p->dlopen_mode = RTLD_GLOBAL;
359        else
360            p->dlopen_mode = RTLD_LOCAL;
361        p->dlopen_mode |= (mode & RTLD_UNSHARED) |
362                          (mode & RTLD_NODELETE) |
363                          (mode & RTLD_LAZY_UNDEF);
364        p->dlopen_count = 1;
365        p->module = module;
366        p->prev = NULL;
367        p->next = dlopen_handles;
368        if(dlopen_handles != NULL)
369            dlopen_handles->prev = p;
370        dlopen_handles = p;
371
372        /* call the init function if one exists */
373        NSSymbol = NSLookupSymbolInModule(p->module, "__init");
374        if(NSSymbol != NULL){
375            init = NSAddressOfSymbol(NSSymbol);
376            init();
377        }
378       
379        DEBUG_PRINT1("%p\n", p);
380        return(p);
381}
382
383/*
384 * dlsym() the MacOS X version of the FreeBSD dlopen() interface.
385 */
386void *
387dlsym(
388void * handle,
389const char *symbol)
390{
391    struct dlopen_handle *dlopen_handle, *p;
392    NSSymbol NSSymbol;
393    void *address;
394
395        DEBUG_PRINT2("libdl: dlsym(%p,%s) -> ", handle, symbol);
396
397        dlopen_handle = (struct dlopen_handle *)handle;
398
399        /*
400         * If this is the handle for the main program do a global lookup.
401         */
402        if(dlopen_handle == (struct dlopen_handle *)&main_program_handle){
403            if(NSIsSymbolNameDefined(symbol) == TRUE){
404                NSSymbol = NSLookupAndBindSymbol(symbol);
405                address = NSAddressOfSymbol(NSSymbol);
406                dlerror_pointer = NULL;
407                DEBUG_PRINT1("%p\n", address);
408                return(address);
409            }
410            else{
411                dlerror_pointer = "symbol not found";
412                DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
413                return(NULL);
414            }
415        }
416
417        /*
418         * Find this handle and do a lookup in just this module.
419         */
420        p = dlopen_handles;
421        while(p != NULL){
422            if(dlopen_handle == p){
423                NSSymbol = NSLookupSymbolInModule(p->module, symbol);
424                if(NSSymbol != NULL){
425                    address = NSAddressOfSymbol(NSSymbol);
426                    dlerror_pointer = NULL;
427                    DEBUG_PRINT1("%p\n", address);
428                    return(address);
429                }
430                else{
431                    dlerror_pointer = "symbol not found";
432                    DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
433                    return(NULL);
434                }
435            }
436            p = p->next;
437        }
438
439        dlerror_pointer = "bad handle passed to dlsym()";
440        DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
441        return(NULL);
442}
443
444/*
445 * dlerror() the MacOS X version of the FreeBSD dlopen() interface.
446 */
447const char *
448dlerror(
449void)
450{
451    const char *p;
452
453        p = (const char *)dlerror_pointer;
454        dlerror_pointer = NULL;
455        return(p);
456}
457
458/*
459 * dlclose() the MacOS X version of the FreeBSD dlopen() interface.
460 */
461int
462dlclose(
463void * handle)
464{
465    struct dlopen_handle *p, *q;
466    unsigned long options;
467    NSSymbol NSSymbol;
468    void (*fini)(void);
469
470        DEBUG_PRINT1("libdl: dlclose(%p) -> ", handle);
471
472        dlerror_pointer = NULL;
473        q = (struct dlopen_handle *)handle;
474        p = dlopen_handles;
475        while(p != NULL){
476            if(p == q){
477                /* if the dlopen() count is not zero we are done */
478                p->dlopen_count--;
479                if(p->dlopen_count != 0){
480                    DEBUG_PRINT("OK");
481                    return(0);
482                }
483
484                /* call the fini function if one exists */
485                NSSymbol = NSLookupSymbolInModule(p->module, "__fini");
486                if(NSSymbol != NULL){
487                    fini = NSAddressOfSymbol(NSSymbol);
488                    fini();
489                }
490
491                /* unlink the module for this handle */
492                options = 0;
493                if(p->dlopen_mode & RTLD_NODELETE)
494                    options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
495                if(p->dlopen_mode & RTLD_LAZY_UNDEF)
496                    options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
497                if(NSUnLinkModule(p->module, options) == FALSE){
498                    dlerror_pointer = "NSUnLinkModule() failed for dlclose()";
499                    DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
500                    return(-1);
501                }
502                if(p->prev != NULL)
503                    p->prev->next = p->next;
504                if(p->next != NULL)
505                    p->next->prev = p->prev;
506                if(dlopen_handles == p)
507                    dlopen_handles = p->next;
508                free(p);
509                DEBUG_PRINT("OK");
510                return(0);
511            }
512            p = p->next;
513        }
514        dlerror_pointer = "invalid handle passed to dlclose()";
515        DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
516        return(-1);
517}
Note: See TracBrowser for help on using the repository browser.