• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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