|
1 /* |
|
2 Copyright (c) 2002 Peter O'Gorman <ogorman@users.sourceforge.net> |
|
3 |
|
4 Permission is hereby granted, free of charge, to any person obtaining |
|
5 a copy of this software and associated documentation files (the |
|
6 "Software"), to deal in the Software without restriction, including |
|
7 without limitation the rights to use, copy, modify, merge, publish, |
|
8 distribute, sublicense, and/or sell copies of the Software, and to |
|
9 permit persons to whom the Software is furnished to do so, subject to |
|
10 the following conditions: |
|
11 |
|
12 The above copyright notice and this permission notice shall be |
|
13 included in all copies or substantial portions of the Software. |
|
14 |
|
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
19 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
20 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
21 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
22 */ |
|
23 |
|
24 |
|
25 /* Just to prove that it isn't that hard to add Mac calls to your code :) |
|
26 This works with pretty much everything, including kde3 xemacs and the gimp, |
|
27 I'd guess that it'd work in at least 95% of cases, use this as your starting |
|
28 point, rather than the mess that is dlfcn.c, assuming that your code does not |
|
29 require ref counting or symbol lookups in dependent libraries |
|
30 */ |
|
31 |
|
32 #include <stdio.h> |
|
33 #include <stdlib.h> |
|
34 #include <string.h> |
|
35 #include <sys/types.h> |
|
36 #include <sys/stat.h> |
|
37 #include <stdarg.h> |
|
38 #include <limits.h> |
|
39 #include <mach-o/dyld.h> |
|
40 #include <AvailabilityMacros.h> |
|
41 #include "dlfcn.h" |
|
42 |
|
43 #ifdef CTYPES_DARWIN_DLFCN |
|
44 |
|
45 #define ERR_STR_LEN 256 |
|
46 |
|
47 #ifndef MAC_OS_X_VERSION_10_3 |
|
48 #define MAC_OS_X_VERSION_10_3 1030 |
|
49 #endif |
|
50 |
|
51 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 |
|
52 #define DARWIN_HAS_DLOPEN |
|
53 extern void * dlopen(const char *path, int mode) __attribute__((weak_import)); |
|
54 extern void * dlsym(void * handle, const char *symbol) __attribute__((weak_import)); |
|
55 extern const char * dlerror(void) __attribute__((weak_import)); |
|
56 extern int dlclose(void * handle) __attribute__((weak_import)); |
|
57 extern int dladdr(const void *, Dl_info *) __attribute__((weak_import)); |
|
58 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 */ |
|
59 |
|
60 #ifndef DARWIN_HAS_DLOPEN |
|
61 #define dlopen darwin_dlopen |
|
62 #define dlsym darwin_dlsym |
|
63 #define dlerror darwin_dlerror |
|
64 #define dlclose darwin_dlclose |
|
65 #define dladdr darwin_dladdr |
|
66 #endif |
|
67 |
|
68 void * (*ctypes_dlopen)(const char *path, int mode); |
|
69 void * (*ctypes_dlsym)(void * handle, const char *symbol); |
|
70 const char * (*ctypes_dlerror)(void); |
|
71 int (*ctypes_dlclose)(void * handle); |
|
72 int (*ctypes_dladdr)(const void *, Dl_info *); |
|
73 |
|
74 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 |
|
75 /* Mac OS X 10.3+ has dlopen, so strip all this dead code to avoid warnings */ |
|
76 |
|
77 static void *dlsymIntern(void *handle, const char *symbol); |
|
78 |
|
79 static const char *error(int setget, const char *str, ...); |
|
80 |
|
81 /* Set and get the error string for use by dlerror */ |
|
82 static const char *error(int setget, const char *str, ...) |
|
83 { |
|
84 static char errstr[ERR_STR_LEN]; |
|
85 static int err_filled = 0; |
|
86 const char *retval; |
|
87 va_list arg; |
|
88 if (setget == 0) |
|
89 { |
|
90 va_start(arg, str); |
|
91 strncpy(errstr, "dlcompat: ", ERR_STR_LEN); |
|
92 vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg); |
|
93 va_end(arg); |
|
94 err_filled = 1; |
|
95 retval = NULL; |
|
96 } |
|
97 else |
|
98 { |
|
99 if (!err_filled) |
|
100 retval = NULL; |
|
101 else |
|
102 retval = errstr; |
|
103 err_filled = 0; |
|
104 } |
|
105 return retval; |
|
106 } |
|
107 |
|
108 /* darwin_dlopen */ |
|
109 static void *darwin_dlopen(const char *path, int mode) |
|
110 { |
|
111 void *module = 0; |
|
112 NSObjectFileImage ofi = 0; |
|
113 NSObjectFileImageReturnCode ofirc; |
|
114 |
|
115 /* If we got no path, the app wants the global namespace, use -1 as the marker |
|
116 in this case */ |
|
117 if (!path) |
|
118 return (void *)-1; |
|
119 |
|
120 /* Create the object file image, works for things linked with the -bundle arg to ld */ |
|
121 ofirc = NSCreateObjectFileImageFromFile(path, &ofi); |
|
122 switch (ofirc) |
|
123 { |
|
124 case NSObjectFileImageSuccess: |
|
125 /* It was okay, so use NSLinkModule to link in the image */ |
|
126 module = NSLinkModule(ofi, path, |
|
127 NSLINKMODULE_OPTION_RETURN_ON_ERROR |
|
128 | (mode & RTLD_GLOBAL) ? 0 : NSLINKMODULE_OPTION_PRIVATE |
|
129 | (mode & RTLD_LAZY) ? 0 : NSLINKMODULE_OPTION_BINDNOW); |
|
130 NSDestroyObjectFileImage(ofi); |
|
131 break; |
|
132 case NSObjectFileImageInappropriateFile: |
|
133 /* It may have been a dynamic library rather than a bundle, try to load it */ |
|
134 module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR); |
|
135 break; |
|
136 default: |
|
137 /* God knows what we got */ |
|
138 error(0, "Can not open \"%s\"", path); |
|
139 return 0; |
|
140 } |
|
141 if (!module) |
|
142 error(0, "Can not open \"%s\"", path); |
|
143 return module; |
|
144 |
|
145 } |
|
146 |
|
147 /* dlsymIntern is used by dlsym to find the symbol */ |
|
148 static void *dlsymIntern(void *handle, const char *symbol) |
|
149 { |
|
150 NSSymbol nssym = 0; |
|
151 /* If the handle is -1, if is the app global context */ |
|
152 if (handle == (void *)-1) |
|
153 { |
|
154 /* Global context, use NSLookupAndBindSymbol */ |
|
155 if (NSIsSymbolNameDefined(symbol)) |
|
156 { |
|
157 nssym = NSLookupAndBindSymbol(symbol); |
|
158 } |
|
159 |
|
160 } |
|
161 /* Now see if the handle is a struch mach_header* or not, use NSLookupSymbol in image |
|
162 for libraries, and NSLookupSymbolInModule for bundles */ |
|
163 else |
|
164 { |
|
165 /* Check for both possible magic numbers depending on x86/ppc byte order */ |
|
166 if ((((struct mach_header *)handle)->magic == MH_MAGIC) || |
|
167 (((struct mach_header *)handle)->magic == MH_CIGAM)) |
|
168 { |
|
169 if (NSIsSymbolNameDefinedInImage((struct mach_header *)handle, symbol)) |
|
170 { |
|
171 nssym = NSLookupSymbolInImage((struct mach_header *)handle, |
|
172 symbol, |
|
173 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
|
174 | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); |
|
175 } |
|
176 |
|
177 } |
|
178 else |
|
179 { |
|
180 nssym = NSLookupSymbolInModule(handle, symbol); |
|
181 } |
|
182 } |
|
183 if (!nssym) |
|
184 { |
|
185 error(0, "Symbol \"%s\" Not found", symbol); |
|
186 return NULL; |
|
187 } |
|
188 return NSAddressOfSymbol(nssym); |
|
189 } |
|
190 |
|
191 static const char *darwin_dlerror(void) |
|
192 { |
|
193 return error(1, (char *)NULL); |
|
194 } |
|
195 |
|
196 static int darwin_dlclose(void *handle) |
|
197 { |
|
198 if ((((struct mach_header *)handle)->magic == MH_MAGIC) || |
|
199 (((struct mach_header *)handle)->magic == MH_CIGAM)) |
|
200 { |
|
201 error(0, "Can't remove dynamic libraries on darwin"); |
|
202 return 0; |
|
203 } |
|
204 if (!NSUnLinkModule(handle, 0)) |
|
205 { |
|
206 error(0, "unable to unlink module %s", NSNameOfModule(handle)); |
|
207 return 1; |
|
208 } |
|
209 return 0; |
|
210 } |
|
211 |
|
212 |
|
213 /* dlsym, prepend the underscore and call dlsymIntern */ |
|
214 static void *darwin_dlsym(void *handle, const char *symbol) |
|
215 { |
|
216 static char undersym[257]; /* Saves calls to malloc(3) */ |
|
217 int sym_len = strlen(symbol); |
|
218 void *value = NULL; |
|
219 char *malloc_sym = NULL; |
|
220 |
|
221 if (sym_len < 256) |
|
222 { |
|
223 snprintf(undersym, 256, "_%s", symbol); |
|
224 value = dlsymIntern(handle, undersym); |
|
225 } |
|
226 else |
|
227 { |
|
228 malloc_sym = malloc(sym_len + 2); |
|
229 if (malloc_sym) |
|
230 { |
|
231 sprintf(malloc_sym, "_%s", symbol); |
|
232 value = dlsymIntern(handle, malloc_sym); |
|
233 free(malloc_sym); |
|
234 } |
|
235 else |
|
236 { |
|
237 error(0, "Unable to allocate memory"); |
|
238 } |
|
239 } |
|
240 return value; |
|
241 } |
|
242 |
|
243 static int darwin_dladdr(const void *handle, Dl_info *info) { |
|
244 return 0; |
|
245 } |
|
246 #endif /* MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 */ |
|
247 |
|
248 #if __GNUC__ < 4 |
|
249 #pragma CALL_ON_LOAD ctypes_dlfcn_init |
|
250 #else |
|
251 static void __attribute__ ((constructor)) ctypes_dlfcn_init(void); |
|
252 static |
|
253 #endif |
|
254 void ctypes_dlfcn_init(void) { |
|
255 if (dlopen != NULL) { |
|
256 ctypes_dlsym = dlsym; |
|
257 ctypes_dlopen = dlopen; |
|
258 ctypes_dlerror = dlerror; |
|
259 ctypes_dlclose = dlclose; |
|
260 ctypes_dladdr = dladdr; |
|
261 } else { |
|
262 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 |
|
263 ctypes_dlsym = darwin_dlsym; |
|
264 ctypes_dlopen = darwin_dlopen; |
|
265 ctypes_dlerror = darwin_dlerror; |
|
266 ctypes_dlclose = darwin_dlclose; |
|
267 ctypes_dladdr = darwin_dladdr; |
|
268 #endif /* MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 */ |
|
269 } |
|
270 } |
|
271 |
|
272 #endif /* CTYPES_DARWIN_DLFCN */ |