0.9.0.39:
[sbcl.git] / src / runtime / ppc-darwin-dlshim.c
1 /*
2  * These functions emulate a small subset of the dlopen / dlsym
3  * functionality under Darwin's Mach-O dyld system.
4  */
5
6 /*
7  * This software is part of the SBCL system. See the README file for
8  * more information.
9  *
10  * This software is derived from the CMU CL system, which was
11  * written at Carnegie Mellon University and released into the
12  * public domain. The software is in the public domain and is
13  * provided with absolutely no warranty. See the COPYING and CREDITS
14  * files for more information.
15  */
16
17
18 #include <mach-o/dyld.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "ppc-darwin-dlshim.h"
23
24 /* Darwin does not define the standard ELF
25  * dlopen/dlclose/dlsym/dlerror interface to shared libraries, so this
26  * is an attempt at a minimal wrapper to allow SBCL to work without
27  * external dependency on pogma's dlcompat library.
28  */
29
30 /* For now, there is no RTLD_GLOBAL emulation either. */
31
32 static char dl_self; /* I'm going to abuse this */
33
34 static int callback_count;
35 static struct mach_header* last_header;
36 static int last_was_error = 0;
37
38 void dlshim_image_callback(struct mach_header* ptr, unsigned long phooey)
39 {
40     callback_count++;
41     last_header = ptr;
42 }
43
44 int lib_path_count(void)
45 {
46     char* libpath;
47     int i;
48     int count;
49     libpath = getenv("DYLD_LIBRARY_PATH");
50     count = 1;
51     if (libpath) {
52         for (i = 0; libpath[i] != '\0'; i++) {
53             if (libpath[i] == ':') count++;
54         }
55     }
56     return count;
57 }
58
59 const char* lib_path_prefixify(int index, const char* filename)
60 {
61     static char* retbuf = NULL;
62     int fi, li, i, count;
63     char* libpath;
64     if (!retbuf) {
65         retbuf = (char*) malloc(1024*sizeof(char));
66     }
67     count = 0;
68     fi = 0;
69     li = -1;
70     libpath = getenv("DYLD_LIBRARY_PATH");
71     if (libpath) {
72         i = 0;
73         while (count != index && libpath[i] != '\0') {
74             if (libpath[i] == ':') count++;
75             i++;
76         }
77         fi = i;
78         while (libpath[i] != '\0' && libpath[i] != ':') {
79             i++;
80         }
81         li = i - 1;
82     }
83     if (li - fi > 0) {
84         if (li - fi + 1 > 1022 - strlen(filename)) {
85             retbuf = (char*) realloc(retbuf, (li - fi + 3 + strlen(filename))*sizeof(char));
86         }
87         memcpy(retbuf, libpath + fi, (li - fi + 1)*sizeof(char));
88         retbuf[li - fi + 1] = '/';
89         memcpy(retbuf + li - fi + 2, filename, strlen(filename) + 1);
90         return retbuf;
91     } else {
92         return filename;
93     }
94 }
95
96 void* dlopen(const char* filename, int flags)
97 {
98     static char has_callback = 0;
99     if (!has_callback) {
100         _dyld_register_func_for_add_image(dlshim_image_callback);
101     }
102     if (!filename) {
103         return &dl_self;
104     } else {
105         struct mach_header* img = NULL;
106         if (!img) img = NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
107         if (!img) img = NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_WITH_SEARCHING);
108         if (!img) {
109             NSObjectFileImage fileImage;
110             callback_count = 0;
111             last_header = NULL;
112             if (NSCreateObjectFileImageFromFile(filename, &fileImage) == NSObjectFileImageSuccess) {
113                 NSLinkModule(fileImage, filename, NSLINKMODULE_OPTION_BINDNOW | ((flags & RTLD_GLOBAL)?NSLINKMODULE_OPTION_PRIVATE:0) | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
114                 if (callback_count && last_header) img = last_header;
115             }
116         }
117         if (!img) {
118             NSObjectFileImage fileImage;
119             int i, maxi;
120             char* prefixfilename;
121             maxi = lib_path_count();
122             for (i = 0; i < maxi && !img; i++) {
123                 prefixfilename = lib_path_prefixify(i, filename);
124                 callback_count = 0;
125                 last_header = NULL;
126                 if (NSCreateObjectFileImageFromFile(prefixfilename, &fileImage) == NSObjectFileImageSuccess) {
127                     NSLinkModule(fileImage, filename, NSLINKMODULE_OPTION_BINDNOW | ((flags & RTLD_GLOBAL)?NSLINKMODULE_OPTION_PRIVATE:0) | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
128                     if (callback_count && last_header) img = last_header;
129                 }
130             }
131         }
132         if (img) {
133             if (flags & RTLD_NOW) {
134                 NSLookupSymbolInImage(img, "", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
135             }
136             if (NSIsSymbolNameDefinedInImage(img, "__init")) {
137                 NSSymbol* initsymbol;
138                 void (*initfunc) (void);
139                 initsymbol = NSLookupSymbolInImage(img, "__init", 0);
140                 initfunc = NSAddressOfSymbol(initsymbol);
141                 initfunc();
142             }
143         }
144         return img;
145     }
146 }
147
148 const char* dlerror()
149 {
150     static char* errbuf = NULL;
151     NSLinkEditErrors a;
152     int b;
153     char *c, *d;
154     NSLinkEditError(&a, &b, &c, &d);
155     if (!errbuf) {
156         errbuf = (char*) malloc(256*sizeof(char));
157     }
158     if (!(c || d)) {
159         last_was_error = 0;
160         snprintf(errbuf, 255, "%s in %s: %d %d", c, d, a, b);
161         return errbuf;
162     } else if (last_was_error) {
163         last_was_error = 0;
164         snprintf(errbuf, 255, "Can't find symbol");
165         return errbuf;
166     }
167     last_was_error = 0;
168     return NULL;
169 }
170
171 void* dlsym(void* handle, char* symbol)
172 {
173     if (handle == &dl_self) {
174         if (NSIsSymbolNameDefined(symbol)) {
175             NSSymbol* retsym;
176             retsym = NSLookupAndBindSymbol(symbol);
177             return NSAddressOfSymbol(retsym);
178         } else {
179             last_was_error = 1;
180             return NULL;
181         }
182     } else {
183         if (NSIsSymbolNameDefinedInImage(handle, symbol)) {
184             NSSymbol* retsym;
185             retsym = NSLookupSymbolInImage(handle, symbol, 0);
186             return NSAddressOfSymbol(retsym);
187         } else {
188             last_was_error = 1;
189             return NULL;
190         }
191     }
192 }
193
194 int dlclose(void *handle)
195 {
196     /* dlclose is not implemented, and never will be for dylibs.
197      * return -1 to signal an error; it's not used by SBCL anyhow */
198     return -1;
199 }