blob: 2b293bb8695bce9e9e7dea1ddced2aabc8726bea [file] [log] [blame]
Thomas Hellerd4c93202006-03-08 19:35:11 +00001/*
2Copyright (c) 2002 Peter O'Gorman <ogorman@users.sourceforge.net>
3
4Permission is hereby granted, free of charge, to any person obtaining
5a copy of this software and associated documentation files (the
6"Software"), to deal in the Software without restriction, including
7without limitation the rights to use, copy, modify, merge, publish,
8distribute, sublicense, and/or sell copies of the Software, and to
9permit persons to whom the Software is furnished to do so, subject to
10the following conditions:
11
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21WITH 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
53extern void * dlopen(const char *path, int mode) __attribute__((weak_import));
54extern void * dlsym(void * handle, const char *symbol) __attribute__((weak_import));
55extern const char * dlerror(void) __attribute__((weak_import));
56extern int dlclose(void * handle) __attribute__((weak_import));
57extern 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
68void * (*ctypes_dlopen)(const char *path, int mode);
69void * (*ctypes_dlsym)(void * handle, const char *symbol);
70const char * (*ctypes_dlerror)(void);
71int (*ctypes_dlclose)(void * handle);
72int (*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
77static void *dlsymIntern(void *handle, const char *symbol);
78
79static const char *error(int setget, const char *str, ...);
80
81/* Set and get the error string for use by dlerror */
82static const char *error(int setget, const char *str, ...)
83{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000084 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;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000106}
107
108/* darwin_dlopen */
109static void *darwin_dlopen(const char *path, int mode)
110{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000111 void *module = 0;
112 NSObjectFileImage ofi = 0;
113 NSObjectFileImageReturnCode ofirc;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000114
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000115 /* 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;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000119
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000120 /* 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;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000144
145}
146
147/* dlsymIntern is used by dlsym to find the symbol */
148static void *dlsymIntern(void *handle, const char *symbol)
149{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000150 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 }
Thomas Hellerd4c93202006-03-08 19:35:11 +0000159
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000160 }
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 }
Thomas Hellerd4c93202006-03-08 19:35:11 +0000176
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000177 }
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);
Thomas Hellerd4c93202006-03-08 19:35:11 +0000189}
190
191static const char *darwin_dlerror(void)
192{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 return error(1, (char *)NULL);
Thomas Hellerd4c93202006-03-08 19:35:11 +0000194}
195
196static int darwin_dlclose(void *handle)
197{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000198 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;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000210}
211
212
213/* dlsym, prepend the underscore and call dlsymIntern */
214static void *darwin_dlsym(void *handle, const char *symbol)
215{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000216 static char undersym[257]; /* Saves calls to malloc(3) */
217 int sym_len = strlen(symbol);
218 void *value = NULL;
219 char *malloc_sym = NULL;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000220
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000221 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;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000241}
242
243static int darwin_dladdr(const void *handle, Dl_info *info) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000244 return 0;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000245}
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
251static void __attribute__ ((constructor)) ctypes_dlfcn_init(void);
252static
253#endif
254void ctypes_dlfcn_init(void) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000255 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 {
Thomas Hellerd4c93202006-03-08 19:35:11 +0000262#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 ctypes_dlsym = darwin_dlsym;
264 ctypes_dlopen = darwin_dlopen;
265 ctypes_dlerror = darwin_dlerror;
266 ctypes_dlclose = darwin_dlclose;
267 ctypes_dladdr = darwin_dladdr;
Thomas Hellerd4c93202006-03-08 19:35:11 +0000268#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 }
Thomas Hellerd4c93202006-03-08 19:35:11 +0000270}
271
272#endif /* CTYPES_DARWIN_DLFCN */