src/loadso/macosx/SDL_loadso.c
changeset 1173 e9cf8c1b4590
child 1190 173c063d4f55
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/loadso/macosx/SDL_loadso.c	Thu Nov 17 03:15:05 2005 +0000
     1.3 @@ -0,0 +1,1419 @@
     1.4 +/*
     1.5 +    SDL - Simple DirectMedia Layer
     1.6 +    Copyright (C) 1997-2004 Sam Lantinga
     1.7 +
     1.8 +    This library is free software; you can redistribute it and/or
     1.9 +    modify it under the terms of the GNU Library General Public
    1.10 +    License as published by the Free Software Foundation; either
    1.11 +    version 2 of the License, or (at your option) any later version.
    1.12 +
    1.13 +    This library is distributed in the hope that it will be useful,
    1.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.16 +    Library General Public License for more details.
    1.17 +
    1.18 +    You should have received a copy of the GNU Library General Public
    1.19 +    License along with this library; if not, write to the Free
    1.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.21 +
    1.22 +    Sam Lantinga
    1.23 +    slouken@libsdl.org
    1.24 +*/
    1.25 +
    1.26 +#ifdef SAVE_RCSID
    1.27 +static char rcsid =
    1.28 + "@(#) $Id$";
    1.29 +#endif
    1.30 +
    1.31 +/* Please note that dlcompat apparently ships in current Mac OS X versions
    1.32 + *  as a system library that provides compatibility with the Unix "dlopen"
    1.33 + *  interface. In order to allow SDL to work on older OS X releases and also
    1.34 + *  not conflict with the system lib on newer versions, we include dlcompat
    1.35 + *  in SDL and change the symbols to prevent symbol clash with any existing
    1.36 + *  system libraries.  --ryan.
    1.37 + */
    1.38 +
    1.39 +/* here is the dlcompat license: */
    1.40 +
    1.41 +/*
    1.42 +Copyright (c) 2002 Jorge Acereda  <jacereda@users.sourceforge.net> &
    1.43 +                   Peter O'Gorman <ogorman@users.sourceforge.net>
    1.44 +                   
    1.45 +Portions may be copyright others, see the AUTHORS file included with this
    1.46 +distribution.
    1.47 +
    1.48 +Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
    1.49 +
    1.50 +Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
    1.51 +
    1.52 +Permission is hereby granted, free of charge, to any person obtaining
    1.53 +a copy of this software and associated documentation files (the
    1.54 +"Software"), to deal in the Software without restriction, including
    1.55 +without limitation the rights to use, copy, modify, merge, publish,
    1.56 +distribute, sublicense, and/or sell copies of the Software, and to
    1.57 +permit persons to whom the Software is furnished to do so, subject to
    1.58 +the following conditions:
    1.59 +
    1.60 +The above copyright notice and this permission notice shall be
    1.61 +included in all copies or substantial portions of the Software.
    1.62 +
    1.63 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    1.64 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    1.65 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    1.66 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    1.67 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    1.68 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    1.69 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    1.70 +*/
    1.71 +
    1.72 +#include <pthread.h>
    1.73 +#include <stdio.h>
    1.74 +#include <stdlib.h>
    1.75 +#include <string.h>
    1.76 +#include <sys/types.h>
    1.77 +#include <sys/stat.h>
    1.78 +#include <stdarg.h>
    1.79 +#include <limits.h>
    1.80 +#include <mach-o/dyld.h>
    1.81 +#include <mach-o/nlist.h>
    1.82 +#include <mach-o/getsect.h>
    1.83 +
    1.84 +/* Just playing to see if it would compile with the freebsd headers, it does,
    1.85 + * but because of the different values for RTLD_LOCAL etc, it would break binary
    1.86 + * compat... oh well
    1.87 + */
    1.88 +#ifndef __BSD_VISIBLE
    1.89 +#define __BSD_VISIBLE 1
    1.90 +#endif
    1.91 +
    1.92 +/*include "dlfcn.h"*/
    1.93 +#ifdef __cplusplus
    1.94 +extern "C" {
    1.95 +#endif
    1.96 +
    1.97 +#if defined (__GNUC__) && __GNUC__ > 3
    1.98 +#define dl_restrict __restrict
    1.99 +#else
   1.100 +#define dl_restrict
   1.101 +#endif
   1.102 +
   1.103 +#ifndef _POSIX_SOURCE
   1.104 +/*
   1.105 + * Structure filled in by dladdr().
   1.106 + */
   1.107 +typedef struct SDL_OSX_dl_info {
   1.108 +        const char      *dli_fname;     /* Pathname of shared object */
   1.109 +        void            *dli_fbase;     /* Base address of shared object */
   1.110 +        const char      *dli_sname;     /* Name of nearest symbol */
   1.111 +        void            *dli_saddr;     /* Address of nearest symbol */
   1.112 +} SDL_OSX_Dl_info;
   1.113 +
   1.114 +static int SDL_OSX_dladdr(const void * dl_restrict, SDL_OSX_Dl_info * dl_restrict);
   1.115 +#endif /* ! _POSIX_SOURCE */
   1.116 +
   1.117 +static int SDL_OSX_dlclose(void * handle);
   1.118 +static char * SDL_OSX_dlerror(void);
   1.119 +static void * SDL_OSX_dlopen(const char *path, int mode);
   1.120 +static void * SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol);
   1.121 +
   1.122 +#define RTLD_LAZY	0x1
   1.123 +#define RTLD_NOW	0x2
   1.124 +#define RTLD_LOCAL	0x4
   1.125 +#define RTLD_GLOBAL	0x8
   1.126 +
   1.127 +#ifndef _POSIX_SOURCE
   1.128 +#define RTLD_NOLOAD	0x10
   1.129 +#define RTLD_NODELETE	0x80
   1.130 +
   1.131 +/*
   1.132 + * Special handle arguments for SDL_OSX_dlsym().
   1.133 + */
   1.134 +#define	RTLD_NEXT		((void *) -1)	/* Search subsequent objects. */
   1.135 +#define	RTLD_DEFAULT	((void *) -2)	/* Use default search algorithm. */
   1.136 +#endif /* ! _POSIX_SOURCE */
   1.137 +
   1.138 +#ifdef __cplusplus
   1.139 +}
   1.140 +#endif
   1.141 +
   1.142 +#ifndef dl_restrict
   1.143 +#define dl_restrict __restrict
   1.144 +#endif
   1.145 +/* This is not available on 10.1 */
   1.146 +#ifndef LC_LOAD_WEAK_DYLIB
   1.147 +#define	LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
   1.148 +#endif
   1.149 +
   1.150 +/* With this stuff here, this thing may actually compile/run on 10.0 systems
   1.151 + * Not that I have a 10.0 system to test it on anylonger
   1.152 + */
   1.153 +#ifndef LC_REQ_DYLD
   1.154 +#define LC_REQ_DYLD 0x80000000
   1.155 +#endif
   1.156 +#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
   1.157 +#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
   1.158 +#endif
   1.159 +#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
   1.160 +#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
   1.161 +#endif
   1.162 +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
   1.163 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
   1.164 +#endif
   1.165 +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
   1.166 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
   1.167 +#endif
   1.168 +/* These symbols will be looked for in dyld */
   1.169 +static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
   1.170 +static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
   1.171 +static NSSymbol(*dyld_NSLookupSymbolInImage)
   1.172 +	(const struct mach_header *, const char *, unsigned long) = 0;
   1.173 +
   1.174 +/* Define this to make dlcompat reuse data block. This way in theory we save
   1.175 + * a little bit of overhead. However we then couldn't correctly catch excess
   1.176 + * calls to SDL_OSX_dlclose(). Hence we don't use this feature
   1.177 + */
   1.178 +#undef REUSE_STATUS
   1.179 +
   1.180 +/* Size of the internal error message buffer (used by dlerror()) */
   1.181 +#define ERR_STR_LEN			251
   1.182 +
   1.183 +/* Maximum number of search paths supported by getSearchPath */
   1.184 +#define MAX_SEARCH_PATHS	32
   1.185 +
   1.186 +
   1.187 +#define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
   1.188 +#define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
   1.189 +
   1.190 +/* internal flags */
   1.191 +#define DL_IN_LIST 0x01
   1.192 +
   1.193 +/* our mutex */
   1.194 +static pthread_mutex_t dlcompat_mutex;
   1.195 +/* Our thread specific storage
   1.196 + */
   1.197 +static pthread_key_t dlerror_key;
   1.198 +
   1.199 +struct dlthread
   1.200 +{
   1.201 +	int lockcnt;
   1.202 +	unsigned char errset;
   1.203 +	char errstr[ERR_STR_LEN];
   1.204 +};
   1.205 +
   1.206 +/* This is our central data structure. Whenever a module is loaded via
   1.207 + * SDL_OSX_dlopen(), we create such a struct.
   1.208 + */
   1.209 +struct dlstatus
   1.210 +{
   1.211 +	struct dlstatus *next;		/* pointer to next element in the linked list */
   1.212 +	NSModule module;
   1.213 +	const struct mach_header *lib;
   1.214 +	int refs;					/* reference count */
   1.215 +	int mode;					/* mode in which this module was loaded */
   1.216 +	dev_t device;
   1.217 +	ino_t inode;
   1.218 +	int flags;					/* Any internal flags we may need */
   1.219 +};
   1.220 +
   1.221 +/* Head node of the dlstatus list */
   1.222 +static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
   1.223 +static struct dlstatus *stqueue = &mainStatus;
   1.224 +
   1.225 +
   1.226 +/* Storage for the last error message (used by dlerror()) */
   1.227 +/* static char err_str[ERR_STR_LEN]; */
   1.228 +/* static int err_filled = 0; */
   1.229 +
   1.230 +/* Prototypes to internal functions */
   1.231 +static void debug(const char *fmt, ...);
   1.232 +static void error(const char *str, ...);
   1.233 +static const char *safegetenv(const char *s);
   1.234 +static const char *searchList(void);
   1.235 +static const char *getSearchPath(int i);
   1.236 +static const char *getFullPath(int i, const char *file);
   1.237 +static const struct stat *findFile(const char *file, const char **fullPath);
   1.238 +static int isValidStatus(struct dlstatus *status);
   1.239 +static inline int isFlagSet(int mode, int flag);
   1.240 +static struct dlstatus *lookupStatus(const struct stat *sbuf);
   1.241 +static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
   1.242 +static int promoteLocalToGlobal(struct dlstatus *dls);
   1.243 +static void *reference(struct dlstatus *dls, int mode);
   1.244 +static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
   1.245 +static struct dlstatus *allocStatus(void);
   1.246 +static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
   1.247 +static NSSymbol *search_linked_libs(const struct mach_header *mh, const char *symbol);
   1.248 +static const char *get_lib_name(const struct mach_header *mh);
   1.249 +static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod);
   1.250 +static void dlcompat_init_func(void);
   1.251 +static inline void dlcompat_init_check(void);
   1.252 +static inline void dolock(void);
   1.253 +static inline void dounlock(void);
   1.254 +static void dlerrorfree(void *data);
   1.255 +static void resetdlerror(void);
   1.256 +static const struct mach_header *my_find_image(const char *name);
   1.257 +static const struct mach_header *image_for_address(const void *address);
   1.258 +static inline const char *dyld_error_str(void);
   1.259 +
   1.260 +#if FINK_BUILD
   1.261 +/* Two Global Functions */
   1.262 +static void *dlsym_prepend_underscore(void *handle, const char *symbol);
   1.263 +static void *dlsym_auto_underscore(void *handle, const char *symbol);
   1.264 +
   1.265 +/* And their _intern counterparts */
   1.266 +static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
   1.267 +static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
   1.268 +#endif
   1.269 +
   1.270 +/* Functions */
   1.271 +
   1.272 +static void debug(const char *fmt, ...)
   1.273 +{
   1.274 +#if DEBUG > 1
   1.275 +	va_list arg;
   1.276 +	va_start(arg, fmt);
   1.277 +	fprintf(stderr, "DLDEBUG: ");
   1.278 +	vfprintf(stderr, fmt, arg);
   1.279 +	fprintf(stderr, "\n");
   1.280 +	fflush(stderr);
   1.281 +	va_end(arg);
   1.282 +#endif
   1.283 +}
   1.284 +
   1.285 +static void error(const char *str, ...)
   1.286 +{
   1.287 +	va_list arg;
   1.288 +	struct dlthread  *tss;
   1.289 +	char * err_str;
   1.290 +	va_start(arg, str);
   1.291 +	tss = pthread_getspecific(dlerror_key);
   1.292 +	err_str = tss->errstr;
   1.293 +	strncpy(err_str, "dlcompat: ", ERR_STR_LEN);
   1.294 +	vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
   1.295 +	va_end(arg);
   1.296 +	debug("ERROR: %s\n", err_str);
   1.297 +	tss->errset = 1;
   1.298 +}
   1.299 +
   1.300 +static void warning(const char *str)
   1.301 +{
   1.302 +#if DEBUG > 0
   1.303 +	fprintf(stderr, "WARNING: dlcompat: %s\n", str);
   1.304 +#endif
   1.305 +}
   1.306 +
   1.307 +static const char *safegetenv(const char *s)
   1.308 +{
   1.309 +	const char *ss = getenv(s);
   1.310 +	return ss ? ss : "";
   1.311 +}
   1.312 +
   1.313 +/* because this is only used for debugging and error reporting functions, we
   1.314 + * don't really care about how elegant it is... it could use the load
   1.315 + * commands to find the install name of the library, but...
   1.316 + */
   1.317 +static const char *get_lib_name(const struct mach_header *mh)
   1.318 +{
   1.319 +	unsigned long count = _dyld_image_count();
   1.320 +	unsigned long i;
   1.321 +	const char *val = NULL;
   1.322 +	if (mh)
   1.323 +	{
   1.324 +		for (i = 0; i < count; i++)
   1.325 +		{
   1.326 +			if (mh == _dyld_get_image_header(i))
   1.327 +			{
   1.328 +				val = _dyld_get_image_name(i);
   1.329 +				break;
   1.330 +			}
   1.331 +		}
   1.332 +	}
   1.333 +	return val;
   1.334 +}
   1.335 +
   1.336 +/* Returns the mach_header for the module bu going through all the loaded images
   1.337 + * and finding the one with the same name as the module. There really ought to be
   1.338 + * an api for doing this, would be faster, but there isn't one right now
   1.339 + */
   1.340 +static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod)
   1.341 +{
   1.342 +	const char *mod_name = NSNameOfModule(mod);
   1.343 +	struct mach_header *mh = NULL;
   1.344 +	unsigned long count = _dyld_image_count();
   1.345 +	unsigned long i;
   1.346 +	debug("Module name: %s", mod_name);
   1.347 +	for (i = 0; i < count; i++)
   1.348 +	{
   1.349 +		if (!strcmp(mod_name, _dyld_get_image_name(i)))
   1.350 +		{
   1.351 +			mh = _dyld_get_image_header(i);
   1.352 +			break;
   1.353 +		}
   1.354 +	}
   1.355 +	return mh;
   1.356 +}
   1.357 +
   1.358 +
   1.359 +/* Compute and return a list of all directories that we should search when
   1.360 + * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
   1.361 + * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
   1.362 + * /usr/lib and /lib. Since both of the environments variables can contain a
   1.363 + * list of colon seperated paths, we simply concat them and the two other paths
   1.364 + * into one big string, which we then can easily parse.
   1.365 + * Splitting this string into the actual path list is done by getSearchPath()
   1.366 + */
   1.367 +static const char *searchList()
   1.368 +{
   1.369 +	size_t buf_size;
   1.370 +	static char *buf=NULL;
   1.371 +	const char *ldlp = safegetenv("LD_LIBRARY_PATH");
   1.372 +	const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
   1.373 +	const char *stdpath = getenv("DYLD_FALLBACK_LIBRARY_PATH");
   1.374 +	if (!stdpath)
   1.375 +		stdpath = "/usr/local/lib:/lib:/usr/lib";
   1.376 +	if (!buf)
   1.377 +	{	
   1.378 +		buf_size = strlen(ldlp) + strlen(dyldlp) + strlen(stdpath) + 4;
   1.379 +		buf = malloc(buf_size);
   1.380 +		snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
   1.381 +				 stdpath, '\0');
   1.382 +	}
   1.383 +	return buf;
   1.384 +}
   1.385 +
   1.386 +/* Returns the ith search path from the list as computed by searchList() */
   1.387 +static const char *getSearchPath(int i)
   1.388 +{
   1.389 +	static const char *list = 0;
   1.390 +	static char **path = (char **)0;
   1.391 +	static int end = 0;
   1.392 +	static int numsize = MAX_SEARCH_PATHS;
   1.393 +	static char **tmp;
   1.394 +	/* So we can call free() in the "destructor" we use i=-1 to return the alloc'd array */
   1.395 +	if (i == -1)
   1.396 +	{
   1.397 +		return (const char*)path;
   1.398 +	}
   1.399 +	if (!path)
   1.400 +	{
   1.401 +		path = (char **)calloc(MAX_SEARCH_PATHS, sizeof(char **));
   1.402 +	}
   1.403 +	if (!list && !end)
   1.404 +		list = searchList();
   1.405 +	if (i >= (numsize))
   1.406 +	{
   1.407 +		debug("Increasing size for long PATH");
   1.408 +		tmp = (char **)calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
   1.409 +		if (tmp)
   1.410 +		{
   1.411 +			memcpy(tmp, path, sizeof(char **) * numsize);
   1.412 +			free(path);
   1.413 +			path = tmp;
   1.414 +			numsize += MAX_SEARCH_PATHS;
   1.415 +		}
   1.416 +		else
   1.417 +		{
   1.418 +			return 0;
   1.419 +		}
   1.420 +	}
   1.421 +
   1.422 +	while (!path[i] && !end)
   1.423 +	{
   1.424 +		path[i] = strsep((char **)&list, ":");
   1.425 +
   1.426 +		if (path[i][0] == 0)
   1.427 +			path[i] = 0;
   1.428 +		end = (list == 0);
   1.429 +	}
   1.430 +	return path[i];
   1.431 +}
   1.432 +
   1.433 +static const char *getFullPath(int i, const char *file)
   1.434 +{
   1.435 +	static char buf[PATH_MAX];
   1.436 +	const char *path = getSearchPath(i);
   1.437 +	if (path)
   1.438 +	{
   1.439 +		snprintf(buf, PATH_MAX, "%s/%s", path, file);
   1.440 +	}
   1.441 +	return path ? buf : 0;
   1.442 +}
   1.443 +
   1.444 +/* Given a file name, try to determine the full path for that file. Starts
   1.445 + * its search in the current directory, and then tries all paths in the 
   1.446 + * search list in the order they are specified there.
   1.447 + */
   1.448 +static const struct stat *findFile(const char *file, const char **fullPath)
   1.449 +{
   1.450 +	int i = 0;
   1.451 +	static struct stat sbuf;
   1.452 +	char *fileName;
   1.453 +	debug("finding file %s", file);
   1.454 +	*fullPath = file;
   1.455 +	if (0 == stat(file, &sbuf))
   1.456 +		return &sbuf;
   1.457 +	if (strchr(file, '/'))
   1.458 +		return 0;				/* If the path had a / we don't look in env var places */
   1.459 +	fileName = NULL;
   1.460 +	if (!fileName)
   1.461 +		fileName = (char *)file;
   1.462 +	while ((*fullPath = getFullPath(i++, fileName)))
   1.463 +	{
   1.464 +		if (0 == stat(*fullPath, &sbuf))
   1.465 +			return &sbuf;
   1.466 +	}
   1.467 +	;
   1.468 +	return 0;
   1.469 +}
   1.470 +
   1.471 +/* Determine whether a given dlstatus is valid or not */
   1.472 +static int isValidStatus(struct dlstatus *status)
   1.473 +{
   1.474 +	/* Walk the list to verify status is contained in it */
   1.475 +	struct dlstatus *dls = stqueue;
   1.476 +	while (dls && status != dls)
   1.477 +		dls = dls->next;
   1.478 +	if (dls == 0)
   1.479 +		error("invalid handle");
   1.480 +	else if ((dls->module == 0) || (dls->refs == 0))
   1.481 +		error("handle to closed library");
   1.482 +	else
   1.483 +		return TRUE;
   1.484 +	return FALSE;
   1.485 +}
   1.486 +
   1.487 +static inline int isFlagSet(int mode, int flag)
   1.488 +{
   1.489 +	return (mode & flag) == flag;
   1.490 +}
   1.491 +
   1.492 +static struct dlstatus *lookupStatus(const struct stat *sbuf)
   1.493 +{
   1.494 +	struct dlstatus *dls = stqueue;
   1.495 +	debug("looking for status");
   1.496 +	while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
   1.497 +				   || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
   1.498 +		dls = dls->next;
   1.499 +	return dls;
   1.500 +}
   1.501 +
   1.502 +static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
   1.503 +{
   1.504 +	debug("inserting status");
   1.505 +	dls->inode = sbuf->st_ino;
   1.506 +	dls->device = sbuf->st_dev;
   1.507 +	dls->refs = 0;
   1.508 +	dls->mode = 0;
   1.509 +	if ((dls->flags & DL_IN_LIST) == 0)
   1.510 +	{
   1.511 +		dls->next = stqueue;
   1.512 +		stqueue = dls;
   1.513 +		dls->flags |= DL_IN_LIST;
   1.514 +	}
   1.515 +}
   1.516 +
   1.517 +static struct dlstatus *allocStatus()
   1.518 +{
   1.519 +	struct dlstatus *dls;
   1.520 +#ifdef REUSE_STATUS
   1.521 +	dls = stqueue;
   1.522 +	while (dls && dls->module)
   1.523 +		dls = dls->next;
   1.524 +	if (!dls)
   1.525 +#endif
   1.526 +		dls = calloc(sizeof(*dls),1);
   1.527 +	return dls;
   1.528 +}
   1.529 +
   1.530 +static int promoteLocalToGlobal(struct dlstatus *dls)
   1.531 +{
   1.532 +	static int (*p) (NSModule module) = 0;
   1.533 +	debug("promoting");
   1.534 +	if (!p)
   1.535 +		_dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p);
   1.536 +	return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
   1.537 +}
   1.538 +
   1.539 +static void *reference(struct dlstatus *dls, int mode)
   1.540 +{
   1.541 +	if (dls)
   1.542 +	{
   1.543 +		if (dls->module == MAGIC_DYLIB_MOD && isFlagSet(mode, RTLD_LOCAL))
   1.544 +		{
   1.545 +			warning("trying to open a .dylib with RTLD_LOCAL");
   1.546 +			error("unable to open a .dylib with RTLD_LOCAL");
   1.547 +			return NULL;
   1.548 +		}
   1.549 +		if (isFlagSet(mode, RTLD_GLOBAL) &&
   1.550 +			!isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
   1.551 +		{
   1.552 +			error("unable to promote local module to global");
   1.553 +			return NULL;
   1.554 +		}
   1.555 +		dls->mode |= mode;
   1.556 +		dls->refs++;
   1.557 +	}
   1.558 +	else
   1.559 +		debug("reference called with NULL argument");
   1.560 +
   1.561 +	return dls;
   1.562 +}
   1.563 +
   1.564 +static const struct mach_header *my_find_image(const char *name)
   1.565 +{
   1.566 +	const struct mach_header *mh = 0;
   1.567 +	const char *id = NULL;
   1.568 +	int i = _dyld_image_count();
   1.569 +	int j;
   1.570 +	mh = (struct mach_header *)
   1.571 +		dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
   1.572 +						NSADDIMAGE_OPTION_RETURN_ON_ERROR);
   1.573 +	if (!mh)
   1.574 +	{
   1.575 +		for (j = 0; j < i; j++)
   1.576 +		{
   1.577 +			id = _dyld_get_image_name(j);
   1.578 +			if (!strcmp(id, name))
   1.579 +			{
   1.580 +				mh = _dyld_get_image_header(j);
   1.581 +				break;
   1.582 +			}
   1.583 +		}
   1.584 +	}
   1.585 +	return mh;
   1.586 +}
   1.587 +
   1.588 +/*
   1.589 + * dyld adds libraries by first adding the directly dependant libraries in link order, and
   1.590 + * then adding the dependencies for those libraries, so we should do the same... but we don't
   1.591 + * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
   1.592 + * any of it's direct dependencies, then it probably isn't there.
   1.593 + */
   1.594 +static NSSymbol *search_linked_libs(const struct mach_header * mh, const char *symbol)
   1.595 +{
   1.596 +	unsigned int n;
   1.597 +	struct load_command *lc = 0;
   1.598 +	struct mach_header *wh;
   1.599 +	NSSymbol *nssym = 0;
   1.600 +	if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
   1.601 +	{
   1.602 +		lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
   1.603 +		for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
   1.604 +		{
   1.605 +			if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
   1.606 +			{
   1.607 +				if ((wh = (struct mach_header *)
   1.608 +					 my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
   1.609 +											(char *)lc))))
   1.610 +				{
   1.611 +					if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
   1.612 +					{
   1.613 +						nssym = dyld_NSLookupSymbolInImage(wh,
   1.614 +														   symbol,
   1.615 +														   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
   1.616 +														   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
   1.617 +						break;
   1.618 +					}
   1.619 +				}
   1.620 +			}
   1.621 +		}
   1.622 +		if ((!nssym) && NSIsSymbolNameDefined(symbol))
   1.623 +		{
   1.624 +			/* I've never seen this debug message...*/
   1.625 +			debug("Symbol \"%s\" is defined but was not found", symbol);
   1.626 +		}
   1.627 +	}
   1.628 +	return nssym;
   1.629 +}
   1.630 +
   1.631 +/* Up to the caller to free() returned string */
   1.632 +static inline const char *dyld_error_str()
   1.633 +{
   1.634 +	NSLinkEditErrors dylder;
   1.635 +	int dylderno;
   1.636 +	const char *dylderrstr;
   1.637 +	const char *dyldfile;
   1.638 +	const char* retStr = NULL;
   1.639 +	NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
   1.640 +	if (dylderrstr && strlen(dylderrstr))
   1.641 +	{
   1.642 +		retStr = malloc(strlen(dylderrstr) +1);
   1.643 +		strcpy((char*)retStr,dylderrstr);
   1.644 +	}
   1.645 +	return retStr;
   1.646 +}
   1.647 +
   1.648 +static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
   1.649 +{
   1.650 +  NSSymbol *nssym = 0;
   1.651 +#ifdef __GCC__  
   1.652 +	void *caller = __builtin_return_address(1);	/* Be *very* careful about inlining */
   1.653 +#else
   1.654 +	void *caller = NULL;
   1.655 +#endif
   1.656 +	const struct mach_header *caller_mh = 0;
   1.657 +	const char* savedErrorStr = NULL;
   1.658 +	resetdlerror();
   1.659 +#ifndef RTLD_SELF
   1.660 +#define	RTLD_SELF		((void *) -3)
   1.661 +#endif
   1.662 +	if (NULL == dls)
   1.663 +		dls = RTLD_SELF;
   1.664 +	if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
   1.665 +	{
   1.666 +		if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage && caller)
   1.667 +		  {
   1.668 +			caller_mh = image_for_address(caller);
   1.669 +			if (RTLD_SELF == dls)
   1.670 +			{
   1.671 +				/* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
   1.672 +				 * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
   1.673 +				 * this is acceptable.
   1.674 +				 */
   1.675 +				if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
   1.676 +				{
   1.677 +					nssym = dyld_NSLookupSymbolInImage(caller_mh,
   1.678 +													   symbol,
   1.679 +													   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
   1.680 +													   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
   1.681 +				}
   1.682 +			}
   1.683 +			if (!nssym)
   1.684 +			{
   1.685 +				if (RTLD_SELF == dls)
   1.686 +					savedErrorStr = dyld_error_str();
   1.687 +				nssym = search_linked_libs(caller_mh, symbol);
   1.688 +			}
   1.689 +		}
   1.690 +		else
   1.691 +		{
   1.692 +			if (canSetError)
   1.693 +				error("RTLD_SELF and RTLD_NEXT are not supported");
   1.694 +			return NULL;
   1.695 +		}
   1.696 +	}
   1.697 +	if (!nssym)
   1.698 +	{
   1.699 +
   1.700 +		if (RTLD_DEFAULT == dls)
   1.701 +		{
   1.702 +			dls = &mainStatus;
   1.703 +		}
   1.704 +		if (!isValidStatus(dls))
   1.705 +			return NULL;
   1.706 +
   1.707 +		if (dls->module != MAGIC_DYLIB_MOD)
   1.708 +		{
   1.709 +			nssym = NSLookupSymbolInModule(dls->module, symbol);
   1.710 +			if (!nssym && NSIsSymbolNameDefined(symbol))
   1.711 +			{
   1.712 +				debug("Searching dependencies");
   1.713 +				savedErrorStr = dyld_error_str();
   1.714 +				nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
   1.715 +			}
   1.716 +		}
   1.717 +		else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
   1.718 +		{
   1.719 +			if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
   1.720 +			{
   1.721 +				nssym = dyld_NSLookupSymbolInImage(dls->lib,
   1.722 +												   symbol,
   1.723 +												   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
   1.724 +												   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
   1.725 +			}
   1.726 +			else if (NSIsSymbolNameDefined(symbol))
   1.727 +			{
   1.728 +				debug("Searching dependencies");
   1.729 +				savedErrorStr = dyld_error_str();
   1.730 +				nssym = search_linked_libs(dls->lib, symbol);
   1.731 +			}
   1.732 +		}
   1.733 +		else if (dls->module == MAGIC_DYLIB_MOD)
   1.734 +		{
   1.735 +			/* Global context, use NSLookupAndBindSymbol */
   1.736 +			if (NSIsSymbolNameDefined(symbol))
   1.737 +			{
   1.738 +				/* There doesn't seem to be a return on error option for this call???
   1.739 +				   this is potentially broken, if binding fails, it will improperly
   1.740 +				   exit the application. */
   1.741 +				nssym = NSLookupAndBindSymbol(symbol);
   1.742 +			}
   1.743 +			else
   1.744 +			{
   1.745 +				if (savedErrorStr)
   1.746 +					free((char*)savedErrorStr);			
   1.747 +				savedErrorStr = malloc(256);
   1.748 +				snprintf((char*)savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);	
   1.749 +			}
   1.750 +		}
   1.751 +	}
   1.752 +	/* Error reporting */
   1.753 +	if (!nssym)
   1.754 +	{
   1.755 +		if (!savedErrorStr || !strlen(savedErrorStr))
   1.756 +		{
   1.757 +			if (savedErrorStr)
   1.758 +				free((char*)savedErrorStr);
   1.759 +			savedErrorStr = malloc(256);
   1.760 +			snprintf((char*)savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
   1.761 +		}
   1.762 +		if (canSetError)
   1.763 +		{
   1.764 +			error(savedErrorStr);
   1.765 +		}
   1.766 +		else
   1.767 +		{
   1.768 +			debug(savedErrorStr);
   1.769 +		}
   1.770 +		if (savedErrorStr)
   1.771 +			free((char*)savedErrorStr);
   1.772 +		return NULL;
   1.773 +	}
   1.774 +	return NSAddressOfSymbol(nssym);
   1.775 +}
   1.776 +
   1.777 +static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
   1.778 +{
   1.779 +	NSObjectFileImage ofi = 0;
   1.780 +	NSObjectFileImageReturnCode ofirc;
   1.781 +	struct dlstatus *dls;
   1.782 +	NSLinkEditErrors ler;
   1.783 +	int lerno;
   1.784 +	const char *errstr;
   1.785 +	const char *file;
   1.786 +	void (*init) (void);
   1.787 +	ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
   1.788 +	switch (ofirc)
   1.789 +	{
   1.790 +		case NSObjectFileImageSuccess:
   1.791 +			break;
   1.792 +		case NSObjectFileImageInappropriateFile:
   1.793 +			if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
   1.794 +			{	
   1.795 +				if (isFlagSet(mode, RTLD_LOCAL))
   1.796 +				{
   1.797 +					warning("trying to open a .dylib with RTLD_LOCAL");
   1.798 +					error("unable to open this file with RTLD_LOCAL");
   1.799 +					return NULL;
   1.800 +				}
   1.801 +			}
   1.802 +			else
   1.803 +			{
   1.804 +				error("opening this file is unsupported on this system");
   1.805 +				return NULL;
   1.806 +			}
   1.807 +			break;
   1.808 +		case NSObjectFileImageFailure:
   1.809 +			error("object file setup failure");
   1.810 +			return NULL;
   1.811 +		case NSObjectFileImageArch:
   1.812 +			error("no object for this architecture");
   1.813 +			return NULL;
   1.814 +		case NSObjectFileImageFormat:
   1.815 +			error("bad object file format");
   1.816 +			return NULL;
   1.817 +		case NSObjectFileImageAccess:
   1.818 +			error("can't read object file");
   1.819 +			return NULL;
   1.820 +		default:
   1.821 +			error("unknown error from NSCreateObjectFileImageFromFile()");
   1.822 +			return NULL;
   1.823 +	}
   1.824 +	dls = lookupStatus(sbuf);
   1.825 +	if (!dls)
   1.826 +	{
   1.827 +		dls = allocStatus();
   1.828 +	}
   1.829 +	if (!dls)
   1.830 +	{
   1.831 +		error("unable to allocate memory");
   1.832 +		return NULL;
   1.833 +	}
   1.834 +	//	dls->lib = 0;
   1.835 +	if (ofirc == NSObjectFileImageInappropriateFile)
   1.836 +	{
   1.837 +		if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
   1.838 +		{
   1.839 +			debug("Dynamic lib loaded at %ld", dls->lib);
   1.840 +			ofi = MAGIC_DYLIB_OFI;
   1.841 +			dls->module = MAGIC_DYLIB_MOD;
   1.842 +			ofirc = NSObjectFileImageSuccess;
   1.843 +			/* Although it is possible with a bit of work to modify this so it works and
   1.844 +			   functions with RTLD_NOW, I don't deem it necessary at the moment */
   1.845 +		}
   1.846 +		if (!(dls->module))
   1.847 +		{
   1.848 +			NSLinkEditError(&ler, &lerno, &file, &errstr);
   1.849 +			if (!errstr || (!strlen(errstr)))
   1.850 +				error("Can't open this file type");
   1.851 +			else
   1.852 +				error(errstr);
   1.853 +			if ((dls->flags & DL_IN_LIST) == 0)
   1.854 +			{
   1.855 +				free(dls);
   1.856 +			}
   1.857 +			return NULL;
   1.858 +		}
   1.859 +	}
   1.860 +	else
   1.861 +	{
   1.862 +		dls->module = NSLinkModule(ofi, path,
   1.863 +								   NSLINKMODULE_OPTION_RETURN_ON_ERROR |
   1.864 +								   NSLINKMODULE_OPTION_PRIVATE |
   1.865 +								   (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
   1.866 +		NSDestroyObjectFileImage(ofi);
   1.867 +		if (dls->module)
   1.868 +		{
   1.869 +			dls->lib = get_mach_header_from_NSModule(dls->module);
   1.870 +		}
   1.871 +	}
   1.872 +	if (!dls->module)
   1.873 +	{
   1.874 +		NSLinkEditError(&ler, &lerno, &file, &errstr);
   1.875 +		if ((dls->flags & DL_IN_LIST) == 0)
   1.876 +		{
   1.877 +			free(dls);
   1.878 +		}
   1.879 +		error(errstr);
   1.880 +		return NULL;
   1.881 +	}
   1.882 +
   1.883 +	insertStatus(dls, sbuf);
   1.884 +	dls = reference(dls, mode);
   1.885 +	if ((init = dlsymIntern(dls, "__init", 0)))
   1.886 +	{
   1.887 +		debug("calling _init()");
   1.888 +		init();
   1.889 +	}
   1.890 +	return dls;
   1.891 +}
   1.892 +
   1.893 +inline static void dlcompat_init_check(void)
   1.894 +{
   1.895 +	static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
   1.896 +	static int init_done = 0;
   1.897 +
   1.898 +	pthread_mutex_lock(&l);
   1.899 +	if (!init_done) {
   1.900 +		dlcompat_init_func();
   1.901 +		init_done = 1;
   1.902 +	}
   1.903 +	pthread_mutex_unlock(&l);
   1.904 +}
   1.905 +
   1.906 +static void dlcompat_init_func(void)
   1.907 +{
   1.908 +        _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage);
   1.909 +	_dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
   1.910 +			  (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage);
   1.911 +	_dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage);
   1.912 +	if (pthread_mutex_init(&dlcompat_mutex, NULL))
   1.913 +	    exit(1);
   1.914 +	if (pthread_key_create(&dlerror_key, &dlerrorfree))
   1.915 +	    exit(1);
   1.916 +}
   1.917 +
   1.918 +static void resetdlerror()
   1.919 +{
   1.920 +	struct dlthread *tss;
   1.921 +	tss = pthread_getspecific(dlerror_key);
   1.922 +	tss->errset = 0;
   1.923 +}
   1.924 +
   1.925 +static void dlerrorfree(void *data)
   1.926 +{
   1.927 +	free(data);
   1.928 +}
   1.929 +
   1.930 +/* We kind of want a recursive lock here, but meet a little trouble
   1.931 + * because they are not available pre OS X 10.2, so we fake it
   1.932 + * using thread specific storage to keep a lock count
   1.933 + */ 
   1.934 +static inline void dolock(void)
   1.935 +{
   1.936 +	int err = 0;
   1.937 +	struct dlthread *tss;
   1.938 +	dlcompat_init_check();
   1.939 +	tss = pthread_getspecific(dlerror_key);
   1.940 +	if (!tss)
   1.941 +	{
   1.942 +		tss = malloc(sizeof(struct dlthread));
   1.943 +		tss->lockcnt = 0;
   1.944 +		tss->errset = 0;
   1.945 +		if (pthread_setspecific(dlerror_key, tss))
   1.946 +		{
   1.947 +			fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
   1.948 +			exit(1);
   1.949 +		}
   1.950 +	}
   1.951 +	if (!tss->lockcnt)
   1.952 +		err = pthread_mutex_lock(&dlcompat_mutex);
   1.953 +	tss->lockcnt = tss->lockcnt +1;	
   1.954 +	if (err)
   1.955 +		exit(err);
   1.956 +}
   1.957 +
   1.958 +static inline void dounlock(void)
   1.959 +{
   1.960 +	int err = 0;
   1.961 +	struct dlthread *tss;
   1.962 +	tss = pthread_getspecific(dlerror_key);
   1.963 +	tss->lockcnt = tss->lockcnt -1;
   1.964 +	if (!tss->lockcnt)
   1.965 +		err = pthread_mutex_unlock(&dlcompat_mutex);
   1.966 +	if (err)
   1.967 +		exit(err);
   1.968 +}
   1.969 +
   1.970 +static void *SDL_OSX_dlopen(const char *path, int mode)
   1.971 +{
   1.972 +	const struct stat *sbuf;
   1.973 +	struct dlstatus *dls;
   1.974 +	const char *fullPath;
   1.975 +
   1.976 +	dolock();
   1.977 +	resetdlerror();
   1.978 +	if (!path)
   1.979 +	{
   1.980 +		dls = &mainStatus;
   1.981 +		goto dlopenok;
   1.982 +	}
   1.983 +	if (!(sbuf = findFile(path, &fullPath)))
   1.984 +	{
   1.985 +		error("file \"%s\" not found", path);
   1.986 +		goto dlopenerror;
   1.987 +	}
   1.988 +	/* Now checks that it hasn't been closed already */
   1.989 +	if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
   1.990 +	{
   1.991 +		/* debug("status found"); */
   1.992 +		dls = reference(dls, mode);
   1.993 +		goto dlopenok;
   1.994 +	}
   1.995 +#ifdef 	RTLD_NOLOAD
   1.996 +	if (isFlagSet(mode, RTLD_NOLOAD))
   1.997 +	{
   1.998 +		error("no existing handle and RTLD_NOLOAD specified");
   1.999 +		goto dlopenerror;
  1.1000 +	}
  1.1001 +#endif
  1.1002 +	if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
  1.1003 +	{
  1.1004 +		error("how can I load something both RTLD_LAZY and RTLD_NOW?");
  1.1005 +		goto dlopenerror;
  1.1006 +	}
  1.1007 +	dls = loadModule(fullPath, sbuf, mode);
  1.1008 +	
  1.1009 +  dlopenok:
  1.1010 +	dounlock();
  1.1011 +	return (void *)dls;
  1.1012 +  dlopenerror:
  1.1013 +	dounlock();
  1.1014 +	return NULL;
  1.1015 +}
  1.1016 +
  1.1017 +#if !FINK_BUILD
  1.1018 +static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
  1.1019 +{
  1.1020 +	int sym_len = strlen(symbol);
  1.1021 +	void *value = NULL;
  1.1022 +	char *malloc_sym = NULL;
  1.1023 +	dolock();
  1.1024 +	malloc_sym = malloc(sym_len + 2);
  1.1025 +	if (malloc_sym)
  1.1026 +	{
  1.1027 +		sprintf(malloc_sym, "_%s", symbol);
  1.1028 +		value = dlsymIntern(handle, malloc_sym, 1);
  1.1029 +		free(malloc_sym);
  1.1030 +	}
  1.1031 +	else
  1.1032 +	{
  1.1033 +		error("Unable to allocate memory");
  1.1034 +		goto dlsymerror;
  1.1035 +	}
  1.1036 +	dounlock();
  1.1037 +	return value;
  1.1038 +  dlsymerror:
  1.1039 +	dounlock();
  1.1040 +	return NULL;
  1.1041 +}
  1.1042 +#endif
  1.1043 +
  1.1044 +#if FINK_BUILD
  1.1045 +
  1.1046 +static void *dlsym_prepend_underscore(void *handle, const char *symbol)
  1.1047 +{
  1.1048 +	void *answer;
  1.1049 +	dolock();
  1.1050 +	answer = dlsym_prepend_underscore_intern(handle, symbol);
  1.1051 +	dounlock();
  1.1052 +	return answer;
  1.1053 +}
  1.1054 +
  1.1055 +static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
  1.1056 +{
  1.1057 +/*
  1.1058 + *	A quick and easy way for porting packages which call dlsym(handle,"sym")
  1.1059 + *	If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
  1.1060 + *	this function will be called, and will add the required underscore.
  1.1061 + *	
  1.1062 + *	Note that I haven't figured out yet which should be "standard", prepend
  1.1063 + *	the underscore always, or not at all. These global functions need to go away
  1.1064 + *	for opendarwin.
  1.1065 + */
  1.1066 +	int sym_len = strlen(symbol);
  1.1067 +	void *value = NULL;
  1.1068 +	char *malloc_sym = NULL;
  1.1069 +	malloc_sym = malloc(sym_len + 2);
  1.1070 +	if (malloc_sym)
  1.1071 +	{
  1.1072 +		sprintf(malloc_sym, "_%s", symbol);
  1.1073 +		value = dlsymIntern(handle, malloc_sym, 1);
  1.1074 +		free(malloc_sym);
  1.1075 +	}
  1.1076 +	else
  1.1077 +	{
  1.1078 +		error("Unable to allocate memory");
  1.1079 +	}
  1.1080 +	return value;
  1.1081 +}
  1.1082 +
  1.1083 +static void *dlsym_auto_underscore(void *handle, const char *symbol)
  1.1084 +{
  1.1085 +	void *answer;
  1.1086 +	dolock();
  1.1087 +	answer = dlsym_auto_underscore_intern(handle, symbol);
  1.1088 +	dounlock();
  1.1089 +	return answer;
  1.1090 +
  1.1091 +}
  1.1092 +static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
  1.1093 +{
  1.1094 +	struct dlstatus *dls = handle;
  1.1095 +	void *addr = 0;
  1.1096 +	addr = dlsymIntern(dls, symbol, 0);
  1.1097 +	if (!addr)
  1.1098 +		addr = dlsym_prepend_underscore_intern(handle, symbol);
  1.1099 +	return addr;
  1.1100 +}
  1.1101 +
  1.1102 +
  1.1103 +static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
  1.1104 +{
  1.1105 +	struct dlstatus *dls = handle;
  1.1106 +	void *addr = 0;
  1.1107 +	dolock();
  1.1108 +	addr = dlsymIntern(dls, symbol, 1);
  1.1109 +	dounlock();
  1.1110 +	return addr;
  1.1111 +}
  1.1112 +#endif
  1.1113 +
  1.1114 +static int SDL_OSX_dlclose(void *handle)
  1.1115 +{
  1.1116 +	struct dlstatus *dls = handle;
  1.1117 +	dolock();
  1.1118 +	resetdlerror();
  1.1119 +	if (!isValidStatus(dls))
  1.1120 +	{
  1.1121 +		goto dlcloseerror;
  1.1122 +	}
  1.1123 +	if (dls->module == MAGIC_DYLIB_MOD)
  1.1124 +	{
  1.1125 +		const char *name;
  1.1126 +		if (!dls->lib)
  1.1127 +		{
  1.1128 +			name = "global context";
  1.1129 +		}
  1.1130 +		else
  1.1131 +		{
  1.1132 +			name = get_lib_name(dls->lib);
  1.1133 +		}
  1.1134 +		warning("trying to close a .dylib!");
  1.1135 +		error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
  1.1136 +		goto dlcloseerror;
  1.1137 +	}
  1.1138 +	if (!dls->module)
  1.1139 +	{
  1.1140 +		error("module already closed");
  1.1141 +		goto dlcloseerror;
  1.1142 +	}
  1.1143 +	
  1.1144 +	if (dls->refs == 1)
  1.1145 +	{
  1.1146 +		unsigned long options = 0;
  1.1147 +		void (*fini) (void);
  1.1148 +		if ((fini = dlsymIntern(dls, "__fini", 0)))
  1.1149 +		{
  1.1150 +			debug("calling _fini()");
  1.1151 +			fini();
  1.1152 +		}
  1.1153 +		options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
  1.1154 +#ifdef RTLD_NODELETE
  1.1155 +		if (isFlagSet(dls->mode, RTLD_NODELETE))
  1.1156 +			options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
  1.1157 +#endif
  1.1158 +		if (!NSUnLinkModule(dls->module, options))
  1.1159 +		{
  1.1160 +			error("unable to unlink module");
  1.1161 +			goto dlcloseerror;
  1.1162 +		}
  1.1163 +		dls->refs--;
  1.1164 +		dls->module = 0;
  1.1165 +		/* Note: the dlstatus struct dls is neither removed from the list
  1.1166 +		 * nor is the memory it occupies freed. This shouldn't pose a 
  1.1167 +		 * problem in mostly all cases, though.
  1.1168 +		 */
  1.1169 +	}
  1.1170 +	dounlock();
  1.1171 +	return 0;
  1.1172 +  dlcloseerror:
  1.1173 +	dounlock();
  1.1174 +	return 1;
  1.1175 +}
  1.1176 +
  1.1177 +static char *SDL_OSX_dlerror(void)
  1.1178 +{
  1.1179 +	struct dlthread  *tss;
  1.1180 +	const char * err_str = NULL;
  1.1181 +	dlcompat_init_check();
  1.1182 +	tss = pthread_getspecific(dlerror_key);
  1.1183 +	if (tss != NULL && tss->errset != 0) {
  1.1184 +		tss->errset = 0;	
  1.1185 +		err_str = tss->errstr;
  1.1186 +	}
  1.1187 +	return (err_str);
  1.1188 +}
  1.1189 +
  1.1190 +/* Given an address, return the mach_header for the image containing it
  1.1191 + * or zero if the given address is not contained in any loaded images.
  1.1192 + */
  1.1193 +static const struct mach_header *image_for_address(const void *address)
  1.1194 +{
  1.1195 +	unsigned long i;
  1.1196 +	unsigned long j;
  1.1197 +	unsigned long count = _dyld_image_count();
  1.1198 +	struct mach_header *mh = 0;
  1.1199 +	struct load_command *lc = 0;
  1.1200 +	unsigned long addr = NULL;
  1.1201 +	for (i = 0; i < count; i++)
  1.1202 +	{
  1.1203 +		addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
  1.1204 +		mh = _dyld_get_image_header(i);
  1.1205 +		if (mh)
  1.1206 +		{
  1.1207 +			lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
  1.1208 +			for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
  1.1209 +			{
  1.1210 +				if (LC_SEGMENT == lc->cmd &&
  1.1211 +					addr >= ((struct segment_command *)lc)->vmaddr &&
  1.1212 +					addr <
  1.1213 +					((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
  1.1214 +				{
  1.1215 +					goto image_found;
  1.1216 +				}
  1.1217 +			}
  1.1218 +		}
  1.1219 +		mh = 0;
  1.1220 +	}
  1.1221 +  image_found:
  1.1222 +	return mh;
  1.1223 +}
  1.1224 +
  1.1225 +static int SDL_OSX_dladdr(const void * dl_restrict p, SDL_OSX_Dl_info * dl_restrict info)
  1.1226 +{
  1.1227 +/*
  1.1228 +	FIXME: USe the routine image_for_address.
  1.1229 +*/
  1.1230 +	unsigned long i;
  1.1231 +	unsigned long j;
  1.1232 +	unsigned long count = _dyld_image_count();
  1.1233 +	struct mach_header *mh = 0;
  1.1234 +	struct load_command *lc = 0;
  1.1235 +	unsigned long addr = NULL;
  1.1236 +	unsigned long table_off = (unsigned long)0;
  1.1237 +	int found = 0;
  1.1238 +	if (!info)
  1.1239 +		return 0;
  1.1240 +	dolock();
  1.1241 +	resetdlerror();
  1.1242 +	info->dli_fname = 0;
  1.1243 +	info->dli_fbase = 0;
  1.1244 +	info->dli_sname = 0;
  1.1245 +	info->dli_saddr = 0;
  1.1246 +/* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
  1.1247 + * to darwin-development AT lists DOT apple DOT com and slightly modified
  1.1248 + */
  1.1249 +	for (i = 0; i < count; i++)
  1.1250 +	{
  1.1251 +		addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
  1.1252 +		mh = _dyld_get_image_header(i);
  1.1253 +		if (mh)
  1.1254 +		{
  1.1255 +			lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
  1.1256 +			for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
  1.1257 +			{
  1.1258 +				if (LC_SEGMENT == lc->cmd &&
  1.1259 +					addr >= ((struct segment_command *)lc)->vmaddr &&
  1.1260 +					addr <
  1.1261 +					((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
  1.1262 +				{
  1.1263 +					info->dli_fname = _dyld_get_image_name(i);
  1.1264 +					info->dli_fbase = (void *)mh;
  1.1265 +					found = 1;
  1.1266 +					break;
  1.1267 +				}
  1.1268 +			}
  1.1269 +			if (found)
  1.1270 +				break;
  1.1271 +		}
  1.1272 +	}
  1.1273 +	if (!found)
  1.1274 +	{
  1.1275 +		dounlock();
  1.1276 +		return 0;
  1.1277 +	}
  1.1278 +	lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
  1.1279 +	for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
  1.1280 +	{
  1.1281 +		if (LC_SEGMENT == lc->cmd)
  1.1282 +		{
  1.1283 +			if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
  1.1284 +				break;
  1.1285 +		}
  1.1286 +	}
  1.1287 +	table_off =
  1.1288 +		((unsigned long)((struct segment_command *)lc)->vmaddr) -
  1.1289 +		((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i);
  1.1290 +	debug("table off %x", table_off);
  1.1291 +
  1.1292 +	lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
  1.1293 +	for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
  1.1294 +	{
  1.1295 +		if (LC_SYMTAB == lc->cmd)
  1.1296 +		{
  1.1297 +
  1.1298 +			struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off);
  1.1299 +			unsigned long numsyms = ((struct symtab_command *)lc)->nsyms;
  1.1300 +			struct nlist *nearest = NULL;
  1.1301 +			unsigned long diff = 0xffffffff;
  1.1302 +			unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off);
  1.1303 +			debug("symtable %x", symtable);
  1.1304 +			for (i = 0; i < numsyms; i++)
  1.1305 +			{
  1.1306 +				/* Ignore the following kinds of Symbols */
  1.1307 +				if ((!symtable->n_value)	/* Undefined */
  1.1308 +					|| (symtable->n_type >= N_PEXT)	/* Debug symbol */
  1.1309 +					|| (!(symtable->n_type & N_EXT))	/* Local Symbol */
  1.1310 +					)
  1.1311 +				{
  1.1312 +					symtable++;
  1.1313 +					continue;
  1.1314 +				}
  1.1315 +				if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
  1.1316 +				{
  1.1317 +					diff = (unsigned long)symtable->n_value - addr;
  1.1318 +					nearest = symtable;
  1.1319 +				}
  1.1320 +				symtable++;
  1.1321 +			}
  1.1322 +			if (nearest)
  1.1323 +			{
  1.1324 +				info->dli_saddr = nearest->n_value + ((void *)p - addr);
  1.1325 +				info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
  1.1326 +			}
  1.1327 +		}
  1.1328 +	}
  1.1329 +	dounlock();
  1.1330 +	return 1;
  1.1331 +}
  1.1332 +
  1.1333 +
  1.1334 +/*
  1.1335 + * Implement the dlfunc() interface, which behaves exactly the same as
  1.1336 + * dlsym() except that it returns a function pointer instead of a data
  1.1337 + * pointer.  This can be used by applications to avoid compiler warnings
  1.1338 + * about undefined behavior, and is intended as prior art for future
  1.1339 + * POSIX standardization.  This function requires that all pointer types
  1.1340 + * have the same representation, which is true on all platforms FreeBSD
  1.1341 + * runs on, but is not guaranteed by the C standard.
  1.1342 + */
  1.1343 +#if 0 
  1.1344 +static dlfunc_t SDL_OSX_dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
  1.1345 +{
  1.1346 +	union
  1.1347 +	{
  1.1348 +		void *d;
  1.1349 +		dlfunc_t f;
  1.1350 +	} rv;
  1.1351 +	int sym_len = strlen(symbol);
  1.1352 +	char *malloc_sym = NULL;
  1.1353 +	dolock();
  1.1354 +	malloc_sym = malloc(sym_len + 2);
  1.1355 +	if (malloc_sym)
  1.1356 +	{
  1.1357 +		sprintf(malloc_sym, "_%s", symbol);
  1.1358 +		rv.d = dlsymIntern(handle, malloc_sym, 1);
  1.1359 +		free(malloc_sym);
  1.1360 +	}
  1.1361 +	else
  1.1362 +	{
  1.1363 +		error("Unable to allocate memory");
  1.1364 +		goto dlfuncerror;
  1.1365 +	}
  1.1366 +	dounlock();
  1.1367 +	return rv.f;
  1.1368 +  dlfuncerror:
  1.1369 +	dounlock();
  1.1370 +	return NULL;
  1.1371 +}
  1.1372 +#endif
  1.1373 +
  1.1374 +
  1.1375 +
  1.1376 +/* dlcompat ends, here's the SDL interface...  --ryan.  */
  1.1377 +
  1.1378 +
  1.1379 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1.1380 +/* System dependent library loading routines                           */
  1.1381 +
  1.1382 +#if !SDL_INTERNAL_BUILDING_LOADSO
  1.1383 +#error Do not compile directly...compile src/SDL_loadso.c instead!
  1.1384 +#endif
  1.1385 +
  1.1386 +#if !defined(MACOSX)
  1.1387 +#error Compiling for the wrong platform?
  1.1388 +#elif defined(USE_DLOPEN)
  1.1389 +#error Do not use USE_DLOPEN on Mac OS X.
  1.1390 +#endif
  1.1391 +
  1.1392 +#include "SDL_types.h"
  1.1393 +#include "SDL_error.h"
  1.1394 +#include "SDL_loadso.h"
  1.1395 +
  1.1396 +void *SDL_LoadObject(const char *sofile)
  1.1397 +{
  1.1398 +	void *handle = SDL_OSX_dlopen(sofile, RTLD_NOW);
  1.1399 +	const char *loaderror = (char *)SDL_OSX_dlerror();
  1.1400 +	if ( handle == NULL ) {
  1.1401 +		SDL_SetError("Failed loading %s: %s", sofile, loaderror);
  1.1402 +	}
  1.1403 +	return(handle);
  1.1404 +}
  1.1405 +
  1.1406 +void *SDL_LoadFunction(void *handle, const char *name)
  1.1407 +{
  1.1408 +	void *symbol = SDL_OSX_dlsym(handle, name);
  1.1409 +	if ( symbol == NULL ) {
  1.1410 +		SDL_SetError("Failed loading %s: %s", name, (const char *)SDL_OSX_dlerror());
  1.1411 +	}
  1.1412 +	return(symbol);
  1.1413 +}
  1.1414 +
  1.1415 +void SDL_UnloadObject(void *handle)
  1.1416 +{
  1.1417 +	if ( handle != NULL ) {
  1.1418 +		SDL_OSX_dlclose(handle);
  1.1419 +	}
  1.1420 +}
  1.1421 +
  1.1422 +