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 */
error(int setget,const char * str,...)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 */
darwin_dlopen(const char * path,int mode)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 */
dlsymIntern(void * handle,const char * 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
darwin_dlerror(void)191 static const char *darwin_dlerror(void)
192 {
193 return error(1, (char *)NULL);
194 }
195
darwin_dlclose(void * handle)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 */
darwin_dlsym(void * handle,const char * symbol)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
darwin_dladdr(const void * handle,Dl_info * info)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
ctypes_dlfcn_init(void)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 */
273