PageRenderTime 46ms CodeModel.GetById 1ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 1ms

/Modules/_ctypes/darwin/dlfcn_simple.c

http://unladen-swallow.googlecode.com/
C | 272 lines | 200 code | 28 blank | 44 comment | 23 complexity | f8535d5eef40c9fca989432e2d94bd26 MD5 | raw file
  1/*
  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{
 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 */
109static 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 */
148static 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
191static const char *darwin_dlerror(void)
192{
193	return error(1, (char *)NULL);
194}
195
196static 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 */
214static 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
243static 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
251static void __attribute__ ((constructor)) ctypes_dlfcn_init(void);
252static
253#endif
254void 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 */