Home | History | Annotate | Download | only in macosx
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Lesser General Public
      7     License as published by the Free Software Foundation; either
      8     version 2.1 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Lesser General Public License for more details.
     14 
     15     You should have received a copy of the GNU Lesser General Public
     16     License along with this library; if not, write to the Free Software
     17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 #ifdef SDL_LOADSO_DLCOMPAT
     25 
     26 /* Please note that dlcompat apparently ships in current Mac OS X versions
     27  *  as a system library that provides compatibility with the Unix "dlopen"
     28  *  interface. In order to allow SDL to work on older OS X releases and also
     29  *  not conflict with the system lib on newer versions, we include dlcompat
     30  *  in SDL and change the symbols to prevent symbol clash with any existing
     31  *  system libraries.  --ryan.
     32  */
     33 
     34 /* here is the dlcompat license: */
     35 
     36 /*
     37 Copyright (c) 2002 Jorge Acereda  <jacereda (at) users.sourceforge.net> &
     38                    Peter O'Gorman <ogorman (at) users.sourceforge.net>
     39 
     40 Portions may be copyright others, see the AUTHORS file included with this
     41 distribution.
     42 
     43 Maintained by Peter O'Gorman <ogorman (at) users.sourceforge.net>
     44 
     45 Bug Reports and other queries should go to <ogorman (at) users.sourceforge.net>
     46 
     47 Permission is hereby granted, free of charge, to any person obtaining
     48 a copy of this software and associated documentation files (the
     49 "Software"), to deal in the Software without restriction, including
     50 without limitation the rights to use, copy, modify, merge, publish,
     51 distribute, sublicense, and/or sell copies of the Software, and to
     52 permit persons to whom the Software is furnished to do so, subject to
     53 the following conditions:
     54 
     55 The above copyright notice and this permission notice shall be
     56 included in all copies or substantial portions of the Software.
     57 
     58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     59 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     60 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     61 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     62 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     63 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     64 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     65 */
     66 
     67 #include <pthread.h>
     68 #include <sys/types.h>
     69 #include <sys/stat.h>
     70 #include <stdarg.h>
     71 #include <limits.h>
     72 #include <mach-o/dyld.h>
     73 #include <mach-o/nlist.h>
     74 #include <mach-o/getsect.h>
     75 
     76 #include "SDL_stdinc.h"
     77 
     78 /* Just playing to see if it would compile with the freebsd headers, it does,
     79  * but because of the different values for RTLD_LOCAL etc, it would break binary
     80  * compat... oh well
     81  */
     82 #ifndef __BSD_VISIBLE
     83 #define __BSD_VISIBLE 1
     84 #endif
     85 
     86 /*include "dlfcn.h"*/
     87 #ifdef __cplusplus
     88 extern "C" {
     89 #endif
     90 
     91 #if defined (__GNUC__) && __GNUC__ > 3
     92 #define dl_restrict __restrict
     93 #else
     94 #define dl_restrict
     95 #endif
     96 
     97 #if 0
     98 #ifndef _POSIX_SOURCE
     99 /*
    100  * Structure filled in by dladdr().
    101  */
    102 typedef struct SDL_OSX_dl_info {
    103         const char      *dli_fname;     /* Pathname of shared object */
    104         void            *dli_fbase;     /* Base address of shared object */
    105         const char      *dli_sname;     /* Name of nearest symbol */
    106         void            *dli_saddr;     /* Address of nearest symbol */
    107 } SDL_OSX_Dl_info;
    108 
    109 static int SDL_OSX_dladdr(const void * dl_restrict, SDL_OSX_Dl_info * dl_restrict);
    110 #endif /* ! _POSIX_SOURCE */
    111 #endif /* 0 */
    112 
    113 static int SDL_OSX_dlclose(void * handle);
    114 static const char * SDL_OSX_dlerror(void);
    115 static void * SDL_OSX_dlopen(const char *path, int mode);
    116 static void * SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol);
    117 
    118 #define RTLD_LAZY	0x1
    119 #define RTLD_NOW	0x2
    120 #define RTLD_LOCAL	0x4
    121 #define RTLD_GLOBAL	0x8
    122 
    123 #ifndef _POSIX_SOURCE
    124 #define RTLD_NOLOAD	0x10
    125 #define RTLD_NODELETE	0x80
    126 
    127 /*
    128  * Special handle arguments for SDL_OSX_dlsym().
    129  */
    130 #define	RTLD_NEXT		((void *) -1)	/* Search subsequent objects. */
    131 #define	RTLD_DEFAULT	((void *) -2)	/* Use default search algorithm. */
    132 #endif /* ! _POSIX_SOURCE */
    133 
    134 #ifdef __cplusplus
    135 }
    136 #endif
    137 
    138 #ifndef dl_restrict
    139 #define dl_restrict __restrict
    140 #endif
    141 /* This is not available on 10.1 */
    142 #ifndef LC_LOAD_WEAK_DYLIB
    143 #define	LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
    144 #endif
    145 
    146 /* With this stuff here, this thing may actually compile/run on 10.0 systems
    147  * Not that I have a 10.0 system to test it on anylonger
    148  */
    149 #ifndef LC_REQ_DYLD
    150 #define LC_REQ_DYLD 0x80000000
    151 #endif
    152 #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
    153 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
    154 #endif
    155 #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
    156 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
    157 #endif
    158 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
    159 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
    160 #endif
    161 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
    162 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
    163 #endif
    164 /* These symbols will be looked for in dyld */
    165 static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
    166 static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
    167 static NSSymbol(*dyld_NSLookupSymbolInImage)
    168 	(const struct mach_header *, const char *, unsigned long) = 0;
    169 
    170 /* Define this to make dlcompat reuse data block. This way in theory we save
    171  * a little bit of overhead. However we then couldn't correctly catch excess
    172  * calls to SDL_OSX_dlclose(). Hence we don't use this feature
    173  */
    174 #undef REUSE_STATUS
    175 
    176 /* Size of the internal error message buffer (used by dlerror()) */
    177 #define ERR_STR_LEN			251
    178 
    179 /* Maximum number of search paths supported by getSearchPath */
    180 #define MAX_SEARCH_PATHS	32
    181 
    182 
    183 #define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
    184 #define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
    185 
    186 /* internal flags */
    187 #define DL_IN_LIST 0x01
    188 
    189 /* our mutex */
    190 static pthread_mutex_t dlcompat_mutex;
    191 /* Our thread specific storage
    192  */
    193 static pthread_key_t dlerror_key;
    194 
    195 struct dlthread
    196 {
    197 	int lockcnt;
    198 	unsigned char errset;
    199 	char errstr[ERR_STR_LEN];
    200 };
    201 
    202 /* This is our central data structure. Whenever a module is loaded via
    203  * SDL_OSX_dlopen(), we create such a struct.
    204  */
    205 struct dlstatus
    206 {
    207 	struct dlstatus *next;		/* pointer to next element in the linked list */
    208 	NSModule module;
    209 	const struct mach_header *lib;
    210 	int refs;					/* reference count */
    211 	int mode;					/* mode in which this module was loaded */
    212 	dev_t device;
    213 	ino_t inode;
    214 	int flags;					/* Any internal flags we may need */
    215 };
    216 
    217 /* Head node of the dlstatus list */
    218 static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
    219 static struct dlstatus *stqueue = &mainStatus;
    220 
    221 
    222 /* Storage for the last error message (used by dlerror()) */
    223 /* static char err_str[ERR_STR_LEN]; */
    224 /* static int err_filled = 0; */
    225 
    226 /* Prototypes to internal functions */
    227 static void debug(const char *fmt, ...);
    228 static void error(const char *str, ...);
    229 static const char *safegetenv(const char *s);
    230 static const char *searchList(void);
    231 static const char *getSearchPath(int i);
    232 static const char *getFullPath(int i, const char *file);
    233 static const struct stat *findFile(const char *file, const char **fullPath);
    234 static int isValidStatus(struct dlstatus *status);
    235 static inline int isFlagSet(int mode, int flag);
    236 static struct dlstatus *lookupStatus(const struct stat *sbuf);
    237 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
    238 static int promoteLocalToGlobal(struct dlstatus *dls);
    239 static void *reference(struct dlstatus *dls, int mode);
    240 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
    241 static struct dlstatus *allocStatus(void);
    242 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
    243 static NSSymbol search_linked_libs(const struct mach_header *mh, const char *symbol);
    244 static const char *get_lib_name(const struct mach_header *mh);
    245 static const struct mach_header *get_mach_header_from_NSModule(NSModule mod);
    246 static void dlcompat_init_func(void);
    247 static inline void dlcompat_init_check(void);
    248 static inline void dolock(void);
    249 static inline void dounlock(void);
    250 static void dlerrorfree(void *data);
    251 static void resetdlerror(void);
    252 static const struct mach_header *my_find_image(const char *name);
    253 static const struct mach_header *image_for_address(const void *address);
    254 static inline char *dyld_error_str(void);
    255 
    256 #if FINK_BUILD
    257 /* Two Global Functions */
    258 static void *dlsym_prepend_underscore(void *handle, const char *symbol);
    259 static void *dlsym_auto_underscore(void *handle, const char *symbol);
    260 
    261 /* And their _intern counterparts */
    262 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
    263 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
    264 #endif
    265 
    266 /* Functions */
    267 
    268 static void debug(const char *fmt, ...)
    269 {
    270 #if DEBUG > 1
    271 	va_list arg;
    272 	va_start(arg, fmt);
    273 	fprintf(stderr, "DLDEBUG: ");
    274 	vfprintf(stderr, fmt, arg);
    275 	fprintf(stderr, "\n");
    276 	fflush(stderr);
    277 	va_end(arg);
    278 #endif
    279 }
    280 
    281 static void error(const char *str, ...)
    282 {
    283 	va_list arg;
    284 	struct dlthread  *tss;
    285 	char * err_str;
    286 	va_start(arg, str);
    287 	tss = pthread_getspecific(dlerror_key);
    288 	err_str = tss->errstr;
    289 	SDL_strlcpy(err_str, "dlcompat: ", ERR_STR_LEN);
    290 	vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
    291 	va_end(arg);
    292 	debug("ERROR: %s\n", err_str);
    293 	tss->errset = 1;
    294 }
    295 
    296 static void warning(const char *str)
    297 {
    298 #if DEBUG > 0
    299 	fprintf(stderr, "WARNING: dlcompat: %s\n", str);
    300 #endif
    301 }
    302 
    303 static const char *safegetenv(const char *s)
    304 {
    305 	const char *ss = SDL_getenv(s);
    306 	return ss ? ss : "";
    307 }
    308 
    309 /* because this is only used for debugging and error reporting functions, we
    310  * don't really care about how elegant it is... it could use the load
    311  * commands to find the install name of the library, but...
    312  */
    313 static const char *get_lib_name(const struct mach_header *mh)
    314 {
    315 	unsigned long count = _dyld_image_count();
    316 	unsigned long i;
    317 	const char *val = NULL;
    318 	if (mh)
    319 	{
    320 		for (i = 0; i < count; i++)
    321 		{
    322 			if (mh == _dyld_get_image_header(i))
    323 			{
    324 				val = _dyld_get_image_name(i);
    325 				break;
    326 			}
    327 		}
    328 	}
    329 	return val;
    330 }
    331 
    332 /* Returns the mach_header for the module bu going through all the loaded images
    333  * and finding the one with the same name as the module. There really ought to be
    334  * an api for doing this, would be faster, but there isn't one right now
    335  */
    336 static const struct mach_header *get_mach_header_from_NSModule(NSModule mod)
    337 {
    338 	const char *mod_name = NSNameOfModule(mod);
    339 	const struct mach_header *mh = NULL;
    340 	unsigned long count = _dyld_image_count();
    341 	unsigned long i;
    342 	debug("Module name: %s", mod_name);
    343 	for (i = 0; i < count; i++)
    344 	{
    345 		if (!SDL_strcmp(mod_name, _dyld_get_image_name(i)))
    346 		{
    347 			mh = _dyld_get_image_header(i);
    348 			break;
    349 		}
    350 	}
    351 	return mh;
    352 }
    353 
    354 
    355 /* Compute and return a list of all directories that we should search when
    356  * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
    357  * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
    358  * /usr/lib and /lib. Since both of the environments variables can contain a
    359  * list of colon seperated paths, we simply concat them and the two other paths
    360  * into one big string, which we then can easily parse.
    361  * Splitting this string into the actual path list is done by getSearchPath()
    362  */
    363 static const char *searchList()
    364 {
    365 	size_t buf_size;
    366 	static char *buf=NULL;
    367 	const char *ldlp = safegetenv("LD_LIBRARY_PATH");
    368 	const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
    369 	const char *stdpath = SDL_getenv("DYLD_FALLBACK_LIBRARY_PATH");
    370 	if (!stdpath)
    371 		stdpath = "/usr/local/lib:/lib:/usr/lib";
    372 	if (!buf)
    373 	{
    374 		buf_size = SDL_strlen(ldlp) + SDL_strlen(dyldlp) + SDL_strlen(stdpath) + 4;
    375 		buf = SDL_malloc(buf_size);
    376 		SDL_snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
    377 				 stdpath, '\0');
    378 	}
    379 	return buf;
    380 }
    381 
    382 /* Returns the ith search path from the list as computed by searchList() */
    383 static const char *getSearchPath(int i)
    384 {
    385 	static const char *list = 0;
    386 	static char **path = (char **)0;
    387 	static int end = 0;
    388 	static int numsize = MAX_SEARCH_PATHS;
    389 	static char **tmp;
    390 	/* So we can call SDL_free() in the "destructor" we use i=-1 to return the alloc'd array */
    391 	if (i == -1)
    392 	{
    393 		return (const char*)path;
    394 	}
    395 	if (!path)
    396 	{
    397 		path = (char **)SDL_calloc(MAX_SEARCH_PATHS, sizeof(char **));
    398 	}
    399 	if (!list && !end)
    400 		list = searchList();
    401 	if (i >= (numsize))
    402 	{
    403 		debug("Increasing size for long PATH");
    404 		tmp = (char **)SDL_calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
    405 		if (tmp)
    406 		{
    407 			SDL_memcpy(tmp, path, sizeof(char **) * numsize);
    408 			SDL_free(path);
    409 			path = tmp;
    410 			numsize += MAX_SEARCH_PATHS;
    411 		}
    412 		else
    413 		{
    414 			return 0;
    415 		}
    416 	}
    417 
    418 	while (!path[i] && !end)
    419 	{
    420 		path[i] = strsep((char **)&list, ":");
    421 
    422 		if (path[i][0] == 0)
    423 			path[i] = 0;
    424 		end = (list == 0);
    425 	}
    426 	return path[i];
    427 }
    428 
    429 static const char *getFullPath(int i, const char *file)
    430 {
    431 	static char buf[PATH_MAX];
    432 	const char *path = getSearchPath(i);
    433 	if (path)
    434 	{
    435 		SDL_snprintf(buf, PATH_MAX, "%s/%s", path, file);
    436 	}
    437 	return path ? buf : 0;
    438 }
    439 
    440 /* Given a file name, try to determine the full path for that file. Starts
    441  * its search in the current directory, and then tries all paths in the
    442  * search list in the order they are specified there.
    443  */
    444 static const struct stat *findFile(const char *file, const char **fullPath)
    445 {
    446 	int i = 0;
    447 	static struct stat sbuf;
    448 	char *fileName;
    449 	debug("finding file %s", file);
    450 	*fullPath = file;
    451 	if (0 == stat(file, &sbuf))
    452 		return &sbuf;
    453 	if (SDL_strchr(file, '/'))
    454 		return 0;				/* If the path had a / we don't look in env var places */
    455 	fileName = NULL;
    456 	if (!fileName)
    457 		fileName = (char *)file;
    458 	while ((*fullPath = getFullPath(i++, fileName)))
    459 	{
    460 		if (0 == stat(*fullPath, &sbuf))
    461 			return &sbuf;
    462 	}
    463 	;
    464 	return 0;
    465 }
    466 
    467 /* Determine whether a given dlstatus is valid or not */
    468 static int isValidStatus(struct dlstatus *status)
    469 {
    470 	/* Walk the list to verify status is contained in it */
    471 	struct dlstatus *dls = stqueue;
    472 	while (dls && status != dls)
    473 		dls = dls->next;
    474 	if (dls == 0)
    475 		error("invalid handle");
    476 	else if ((dls->module == 0) || (dls->refs == 0))
    477 		error("handle to closed library");
    478 	else
    479 		return TRUE;
    480 	return FALSE;
    481 }
    482 
    483 static inline int isFlagSet(int mode, int flag)
    484 {
    485 	return (mode & flag) == flag;
    486 }
    487 
    488 static struct dlstatus *lookupStatus(const struct stat *sbuf)
    489 {
    490 	struct dlstatus *dls = stqueue;
    491 	debug("looking for status");
    492 	while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
    493 				   || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
    494 		dls = dls->next;
    495 	return dls;
    496 }
    497 
    498 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
    499 {
    500 	debug("inserting status");
    501 	dls->inode = sbuf->st_ino;
    502 	dls->device = sbuf->st_dev;
    503 	dls->refs = 0;
    504 	dls->mode = 0;
    505 	if ((dls->flags & DL_IN_LIST) == 0)
    506 	{
    507 		dls->next = stqueue;
    508 		stqueue = dls;
    509 		dls->flags |= DL_IN_LIST;
    510 	}
    511 }
    512 
    513 static struct dlstatus *allocStatus()
    514 {
    515 	struct dlstatus *dls;
    516 #ifdef REUSE_STATUS
    517 	dls = stqueue;
    518 	while (dls && dls->module)
    519 		dls = dls->next;
    520 	if (!dls)
    521 #endif
    522 		dls = SDL_calloc(sizeof(*dls),1);
    523 	return dls;
    524 }
    525 
    526 static int promoteLocalToGlobal(struct dlstatus *dls)
    527 {
    528 	static int (*p) (NSModule module) = 0;
    529 	debug("promoting");
    530 	if (!p)
    531 		_dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (void **)&p);
    532 	return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
    533 }
    534 
    535 static void *reference(struct dlstatus *dls, int mode)
    536 {
    537 	if (dls)
    538 	{
    539 		if (dls->module == MAGIC_DYLIB_MOD && isFlagSet(mode, RTLD_LOCAL))
    540 		{
    541 			warning("trying to open a .dylib with RTLD_LOCAL");
    542 			error("unable to open a .dylib with RTLD_LOCAL");
    543 			return NULL;
    544 		}
    545 		if (isFlagSet(mode, RTLD_GLOBAL) &&
    546 			!isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
    547 		{
    548 			error("unable to promote local module to global");
    549 			return NULL;
    550 		}
    551 		dls->mode |= mode;
    552 		dls->refs++;
    553 	}
    554 	else
    555 		debug("reference called with NULL argument");
    556 
    557 	return dls;
    558 }
    559 
    560 static const struct mach_header *my_find_image(const char *name)
    561 {
    562 	const struct mach_header *mh = 0;
    563 	const char *id = NULL;
    564 	int i = _dyld_image_count();
    565 	int j;
    566 	mh = (struct mach_header *)
    567 		dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
    568 						NSADDIMAGE_OPTION_RETURN_ON_ERROR);
    569 	if (!mh)
    570 	{
    571 		for (j = 0; j < i; j++)
    572 		{
    573 			id = _dyld_get_image_name(j);
    574 			if (!SDL_strcmp(id, name))
    575 			{
    576 				mh = _dyld_get_image_header(j);
    577 				break;
    578 			}
    579 		}
    580 	}
    581 	return mh;
    582 }
    583 
    584 /*
    585  * dyld adds libraries by first adding the directly dependant libraries in link order, and
    586  * then adding the dependencies for those libraries, so we should do the same... but we don't
    587  * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
    588  * any of it's direct dependencies, then it probably isn't there.
    589  */
    590 static NSSymbol search_linked_libs(const struct mach_header * mh, const char *symbol)
    591 {
    592 	unsigned int n;
    593 	struct load_command *lc = 0;
    594 	struct mach_header *wh;
    595 	NSSymbol nssym = 0;
    596 	if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
    597 	{
    598 		lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
    599 		for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
    600 		{
    601 			if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
    602 			{
    603 				if ((wh = (struct mach_header *)
    604 					 my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
    605 											(char *)lc))))
    606 				{
    607 					if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
    608 					{
    609 						nssym = dyld_NSLookupSymbolInImage(wh,
    610 														   symbol,
    611 														   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
    612 														   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
    613 						break;
    614 					}
    615 				}
    616 			}
    617 		}
    618 		if ((!nssym) && NSIsSymbolNameDefined(symbol))
    619 		{
    620 			/* I've never seen this debug message...*/
    621 			debug("Symbol \"%s\" is defined but was not found", symbol);
    622 		}
    623 	}
    624 	return nssym;
    625 }
    626 
    627 /* Up to the caller to SDL_free() returned string */
    628 static inline char *dyld_error_str()
    629 {
    630 	NSLinkEditErrors dylder;
    631 	int dylderno;
    632 	const char *dylderrstr;
    633 	const char *dyldfile;
    634 	char* retStr = NULL;
    635 	NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
    636 	if (dylderrstr && *dylderrstr)
    637 	{
    638 		retStr = SDL_strdup(dylderrstr);
    639 	}
    640 	return retStr;
    641 }
    642 
    643 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
    644 {
    645   NSSymbol nssym = 0;
    646 #ifdef __GCC__
    647 	void *caller = __builtin_return_address(1);	/* Be *very* careful about inlining */
    648 #else
    649 	void *caller = NULL;
    650 #endif
    651 	const struct mach_header *caller_mh = 0;
    652 	char *savedErrorStr = NULL;
    653 	resetdlerror();
    654 #ifndef RTLD_SELF
    655 #define	RTLD_SELF		((void *) -3)
    656 #endif
    657 	if (NULL == dls)
    658 		dls = RTLD_SELF;
    659 	if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
    660 	{
    661 		if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage && caller)
    662 		  {
    663 			caller_mh = image_for_address(caller);
    664 			if (RTLD_SELF == dls)
    665 			{
    666 				/* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
    667 				 * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
    668 				 * this is acceptable.
    669 				 */
    670 				if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
    671 				{
    672 					nssym = dyld_NSLookupSymbolInImage(caller_mh,
    673 													   symbol,
    674 													   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
    675 													   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
    676 				}
    677 			}
    678 			if (!nssym)
    679 			{
    680 				if (RTLD_SELF == dls)
    681 					savedErrorStr = dyld_error_str();
    682 				nssym = search_linked_libs(caller_mh, symbol);
    683 			}
    684 		}
    685 		else
    686 		{
    687 			if (canSetError)
    688 				error("RTLD_SELF and RTLD_NEXT are not supported");
    689 			return NULL;
    690 		}
    691 	}
    692 	if (!nssym)
    693 	{
    694 
    695 		if (RTLD_DEFAULT == dls)
    696 		{
    697 			dls = &mainStatus;
    698 		}
    699 		if (!isValidStatus(dls))
    700 			return NULL;
    701 
    702 		if (dls->module != MAGIC_DYLIB_MOD)
    703 		{
    704 			nssym = NSLookupSymbolInModule(dls->module, symbol);
    705 			if (!nssym && NSIsSymbolNameDefined(symbol))
    706 			{
    707 				debug("Searching dependencies");
    708 				savedErrorStr = dyld_error_str();
    709 				nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
    710 			}
    711 		}
    712 		else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
    713 		{
    714 			if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
    715 			{
    716 				nssym = dyld_NSLookupSymbolInImage(dls->lib,
    717 												   symbol,
    718 												   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
    719 												   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
    720 			}
    721 			else if (NSIsSymbolNameDefined(symbol))
    722 			{
    723 				debug("Searching dependencies");
    724 				savedErrorStr = dyld_error_str();
    725 				nssym = search_linked_libs(dls->lib, symbol);
    726 			}
    727 		}
    728 		else if (dls->module == MAGIC_DYLIB_MOD)
    729 		{
    730 			/* Global context, use NSLookupAndBindSymbol */
    731 			if (NSIsSymbolNameDefined(symbol))
    732 			{
    733 				/* There doesn't seem to be a return on error option for this call???
    734 				   this is potentially broken, if binding fails, it will improperly
    735 				   exit the application. */
    736 				nssym = NSLookupAndBindSymbol(symbol);
    737 			}
    738 			else
    739 			{
    740 				if (savedErrorStr)
    741 					SDL_free(savedErrorStr);
    742 				savedErrorStr = SDL_malloc(256);
    743 				SDL_snprintf(savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);
    744 			}
    745 		}
    746 	}
    747 	/* Error reporting */
    748 	if (!nssym)
    749 	{
    750 		if (!savedErrorStr || !SDL_strlen(savedErrorStr))
    751 		{
    752 			if (savedErrorStr)
    753 				SDL_free(savedErrorStr);
    754 			savedErrorStr = SDL_malloc(256);
    755 			SDL_snprintf(savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
    756 		}
    757 		if (canSetError)
    758 		{
    759 			error(savedErrorStr);
    760 		}
    761 		else
    762 		{
    763 			debug(savedErrorStr);
    764 		}
    765 		if (savedErrorStr)
    766 			SDL_free(savedErrorStr);
    767 		return NULL;
    768 	}
    769 	return NSAddressOfSymbol(nssym);
    770 }
    771 
    772 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
    773 {
    774 	NSObjectFileImage ofi = 0;
    775 	NSObjectFileImageReturnCode ofirc;
    776 	struct dlstatus *dls;
    777 	NSLinkEditErrors ler;
    778 	int lerno;
    779 	const char *errstr;
    780 	const char *file;
    781 	void (*init) (void);
    782 
    783 	ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
    784 	switch (ofirc)
    785 	{
    786 		case NSObjectFileImageSuccess:
    787 			break;
    788 		case NSObjectFileImageInappropriateFile:
    789 			if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
    790 			{
    791 				if (isFlagSet(mode, RTLD_LOCAL))
    792 				{
    793 					warning("trying to open a .dylib with RTLD_LOCAL");
    794 					error("unable to open this file with RTLD_LOCAL");
    795 					return NULL;
    796 				}
    797 			}
    798 			else
    799 			{
    800 				error("opening this file is unsupported on this system");
    801 				return NULL;
    802 			}
    803 			break;
    804 		case NSObjectFileImageFailure:
    805 			error("object file setup failure");
    806 			return NULL;
    807 		case NSObjectFileImageArch:
    808 			error("no object for this architecture");
    809 			return NULL;
    810 		case NSObjectFileImageFormat:
    811 			error("bad object file format");
    812 			return NULL;
    813 		case NSObjectFileImageAccess:
    814 			error("can't read object file");
    815 			return NULL;
    816 		default:
    817 			error("unknown error from NSCreateObjectFileImageFromFile()");
    818 			return NULL;
    819 	}
    820 	dls = lookupStatus(sbuf);
    821 	if (!dls)
    822 	{
    823 		dls = allocStatus();
    824 	}
    825 	if (!dls)
    826 	{
    827 		error("unable to allocate memory");
    828 		return NULL;
    829 	}
    830 	//	dls->lib = 0;
    831 	if (ofirc == NSObjectFileImageInappropriateFile)
    832 	{
    833 		if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
    834 		{
    835 			debug("Dynamic lib loaded at %ld", dls->lib);
    836 			ofi = MAGIC_DYLIB_OFI;
    837 			dls->module = MAGIC_DYLIB_MOD;
    838 			ofirc = NSObjectFileImageSuccess;
    839 			/* Although it is possible with a bit of work to modify this so it works and
    840 			   functions with RTLD_NOW, I don't deem it necessary at the moment */
    841 		}
    842 		if (!(dls->module))
    843 		{
    844 			NSLinkEditError(&ler, &lerno, &file, &errstr);
    845 			if (!errstr || (!SDL_strlen(errstr)))
    846 				error("Can't open this file type");
    847 			else
    848 				error(errstr);
    849 			if ((dls->flags & DL_IN_LIST) == 0)
    850 			{
    851 				SDL_free(dls);
    852 			}
    853 			return NULL;
    854 		}
    855 	}
    856 	else
    857 	{
    858 		dls->module = NSLinkModule(ofi, path,
    859 								   NSLINKMODULE_OPTION_RETURN_ON_ERROR |
    860 								   NSLINKMODULE_OPTION_PRIVATE |
    861 								   (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
    862 		NSDestroyObjectFileImage(ofi);
    863 		if (dls->module)
    864 		{
    865 			dls->lib = get_mach_header_from_NSModule(dls->module);
    866 		}
    867 	}
    868 	if (!dls->module)
    869 	{
    870 		NSLinkEditError(&ler, &lerno, &file, &errstr);
    871 		if ((dls->flags & DL_IN_LIST) == 0)
    872 		{
    873 			SDL_free(dls);
    874 		}
    875 		error(errstr);
    876 		return NULL;
    877 	}
    878 
    879 	insertStatus(dls, sbuf);
    880 	dls = reference(dls, mode);
    881 	if ((init = dlsymIntern(dls, "__init", 0)))
    882 	{
    883 		debug("calling _init()");
    884 		init();
    885 	}
    886 	return dls;
    887 }
    888 
    889 inline static void dlcompat_init_check(void)
    890 {
    891 	static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
    892 	static int init_done = 0;
    893 
    894 	pthread_mutex_lock(&l);
    895 	if (!init_done) {
    896 		dlcompat_init_func();
    897 		init_done = 1;
    898 	}
    899 	pthread_mutex_unlock(&l);
    900 }
    901 
    902 static void dlcompat_init_func(void)
    903 {
    904         _dyld_func_lookup("__dyld_NSAddImage", (void **)&dyld_NSAddImage);
    905 	_dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
    906 			  (void **)&dyld_NSIsSymbolNameDefinedInImage);
    907 	_dyld_func_lookup("__dyld_NSLookupSymbolInImage", (void **)&dyld_NSLookupSymbolInImage);
    908 	if (pthread_mutex_init(&dlcompat_mutex, NULL))
    909 	    exit(1);
    910 	if (pthread_key_create(&dlerror_key, &dlerrorfree))
    911 	    exit(1);
    912 }
    913 
    914 static void resetdlerror()
    915 {
    916 	struct dlthread *tss;
    917 	tss = pthread_getspecific(dlerror_key);
    918 	tss->errset = 0;
    919 }
    920 
    921 static void dlerrorfree(void *data)
    922 {
    923 	SDL_free(data);
    924 }
    925 
    926 /* We kind of want a recursive lock here, but meet a little trouble
    927  * because they are not available pre OS X 10.2, so we fake it
    928  * using thread specific storage to keep a lock count
    929  */
    930 static inline void dolock(void)
    931 {
    932 	int err = 0;
    933 	struct dlthread *tss;
    934 	dlcompat_init_check();
    935 	tss = pthread_getspecific(dlerror_key);
    936 	if (!tss)
    937 	{
    938 		tss = SDL_malloc(sizeof(struct dlthread));
    939 		tss->lockcnt = 0;
    940 		tss->errset = 0;
    941 		if (pthread_setspecific(dlerror_key, tss))
    942 		{
    943 			fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
    944 			exit(1);
    945 		}
    946 	}
    947 	if (!tss->lockcnt)
    948 		err = pthread_mutex_lock(&dlcompat_mutex);
    949 	tss->lockcnt = tss->lockcnt +1;
    950 	if (err)
    951 		exit(err);
    952 }
    953 
    954 static inline void dounlock(void)
    955 {
    956 	int err = 0;
    957 	struct dlthread *tss;
    958 	tss = pthread_getspecific(dlerror_key);
    959 	tss->lockcnt = tss->lockcnt -1;
    960 	if (!tss->lockcnt)
    961 		err = pthread_mutex_unlock(&dlcompat_mutex);
    962 	if (err)
    963 		exit(err);
    964 }
    965 
    966 static void *SDL_OSX_dlopen(const char *path, int mode)
    967 {
    968 	const struct stat *sbuf;
    969 	struct dlstatus *dls;
    970 	const char *fullPath;
    971 
    972 	dolock();
    973 	resetdlerror();
    974 	if (!path)
    975 	{
    976 		dls = &mainStatus;
    977 		goto dlopenok;
    978 	}
    979 	if (!(sbuf = findFile(path, &fullPath)))
    980 	{
    981 		error("file \"%s\" not found", path);
    982 		goto dlopenerror;
    983 	}
    984 	/* Now checks that it hasn't been closed already */
    985 	if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
    986 	{
    987 		/* debug("status found"); */
    988 		dls = reference(dls, mode);
    989 		goto dlopenok;
    990 	}
    991 #ifdef 	RTLD_NOLOAD
    992 	if (isFlagSet(mode, RTLD_NOLOAD))
    993 	{
    994 		error("no existing handle and RTLD_NOLOAD specified");
    995 		goto dlopenerror;
    996 	}
    997 #endif
    998 	if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
    999 	{
   1000 		error("how can I load something both RTLD_LAZY and RTLD_NOW?");
   1001 		goto dlopenerror;
   1002 	}
   1003 	dls = loadModule(fullPath, sbuf, mode);
   1004 
   1005   dlopenok:
   1006 	dounlock();
   1007 	return (void *)dls;
   1008   dlopenerror:
   1009 	dounlock();
   1010 	return NULL;
   1011 }
   1012 
   1013 #if !FINK_BUILD
   1014 static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
   1015 {
   1016 	int sym_len = SDL_strlen(symbol);
   1017 	void *value = NULL;
   1018 	char *malloc_sym = NULL;
   1019 	dolock();
   1020 	malloc_sym = SDL_malloc(sym_len + 2);
   1021 	if (malloc_sym)
   1022 	{
   1023 		SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
   1024 		value = dlsymIntern(handle, malloc_sym, 1);
   1025 		SDL_free(malloc_sym);
   1026 	}
   1027 	else
   1028 	{
   1029 		error("Unable to allocate memory");
   1030 		goto dlsymerror;
   1031 	}
   1032 	dounlock();
   1033 	return value;
   1034   dlsymerror:
   1035 	dounlock();
   1036 	return NULL;
   1037 }
   1038 #endif
   1039 
   1040 #if FINK_BUILD
   1041 
   1042 static void *dlsym_prepend_underscore(void *handle, const char *symbol)
   1043 {
   1044 	void *answer;
   1045 	dolock();
   1046 	answer = dlsym_prepend_underscore_intern(handle, symbol);
   1047 	dounlock();
   1048 	return answer;
   1049 }
   1050 
   1051 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
   1052 {
   1053 /*
   1054  *	A quick and easy way for porting packages which call dlsym(handle,"sym")
   1055  *	If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
   1056  *	this function will be called, and will add the required underscore.
   1057  *
   1058  *	Note that I haven't figured out yet which should be "standard", prepend
   1059  *	the underscore always, or not at all. These global functions need to go away
   1060  *	for opendarwin.
   1061  */
   1062 	int sym_len = SDL_strlen(symbol);
   1063 	void *value = NULL;
   1064 	char *malloc_sym = NULL;
   1065 	malloc_sym = SDL_malloc(sym_len + 2);
   1066 	if (malloc_sym)
   1067 	{
   1068 		SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
   1069 		value = dlsymIntern(handle, malloc_sym, 1);
   1070 		SDL_free(malloc_sym);
   1071 	}
   1072 	else
   1073 	{
   1074 		error("Unable to allocate memory");
   1075 	}
   1076 	return value;
   1077 }
   1078 
   1079 static void *dlsym_auto_underscore(void *handle, const char *symbol)
   1080 {
   1081 	void *answer;
   1082 	dolock();
   1083 	answer = dlsym_auto_underscore_intern(handle, symbol);
   1084 	dounlock();
   1085 	return answer;
   1086 
   1087 }
   1088 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
   1089 {
   1090 	struct dlstatus *dls = handle;
   1091 	void *addr = 0;
   1092 	addr = dlsymIntern(dls, symbol, 0);
   1093 	if (!addr)
   1094 		addr = dlsym_prepend_underscore_intern(handle, symbol);
   1095 	return addr;
   1096 }
   1097 
   1098 
   1099 static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
   1100 {
   1101 	struct dlstatus *dls = handle;
   1102 	void *addr = 0;
   1103 	dolock();
   1104 	addr = dlsymIntern(dls, symbol, 1);
   1105 	dounlock();
   1106 	return addr;
   1107 }
   1108 #endif
   1109 
   1110 static int SDL_OSX_dlclose(void *handle)
   1111 {
   1112 	struct dlstatus *dls = handle;
   1113 	dolock();
   1114 	resetdlerror();
   1115 	if (!isValidStatus(dls))
   1116 	{
   1117 		goto dlcloseerror;
   1118 	}
   1119 	if (dls->module == MAGIC_DYLIB_MOD)
   1120 	{
   1121 		const char *name;
   1122 		if (!dls->lib)
   1123 		{
   1124 			name = "global context";
   1125 		}
   1126 		else
   1127 		{
   1128 			name = get_lib_name(dls->lib);
   1129 		}
   1130 		warning("trying to close a .dylib!");
   1131 		error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
   1132 		goto dlcloseerror;
   1133 	}
   1134 	if (!dls->module)
   1135 	{
   1136 		error("module already closed");
   1137 		goto dlcloseerror;
   1138 	}
   1139 
   1140 	if (dls->refs == 1)
   1141 	{
   1142 		unsigned long options = 0;
   1143 		void (*fini) (void);
   1144 		if ((fini = dlsymIntern(dls, "__fini", 0)))
   1145 		{
   1146 			debug("calling _fini()");
   1147 			fini();
   1148 		}
   1149 		options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
   1150 #ifdef RTLD_NODELETE
   1151 		if (isFlagSet(dls->mode, RTLD_NODELETE))
   1152 			options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
   1153 #endif
   1154 		if (!NSUnLinkModule(dls->module, options))
   1155 		{
   1156 			error("unable to unlink module");
   1157 			goto dlcloseerror;
   1158 		}
   1159 		dls->refs--;
   1160 		dls->module = 0;
   1161 		/* Note: the dlstatus struct dls is neither removed from the list
   1162 		 * nor is the memory it occupies freed. This shouldn't pose a
   1163 		 * problem in mostly all cases, though.
   1164 		 */
   1165 	}
   1166 	dounlock();
   1167 	return 0;
   1168   dlcloseerror:
   1169 	dounlock();
   1170 	return 1;
   1171 }
   1172 
   1173 static const char *SDL_OSX_dlerror(void)
   1174 {
   1175 	struct dlthread  *tss;
   1176 	const char * err_str = NULL;
   1177 	dlcompat_init_check();
   1178 	tss = pthread_getspecific(dlerror_key);
   1179 	if (tss != NULL && tss->errset != 0) {
   1180 		tss->errset = 0;
   1181 		err_str = tss->errstr;
   1182 	}
   1183 	return (err_str);
   1184 }
   1185 
   1186 /* Given an address, return the mach_header for the image containing it
   1187  * or zero if the given address is not contained in any loaded images.
   1188  */
   1189 static const struct mach_header *image_for_address(const void *address)
   1190 {
   1191 	unsigned long i;
   1192 	unsigned long j;
   1193 	unsigned long count = _dyld_image_count();
   1194 	const struct mach_header *mh = 0;
   1195 	struct load_command *lc = 0;
   1196 	unsigned long addr = 0;
   1197 	for (i = 0; i < count; i++)
   1198 	{
   1199 		addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
   1200 		mh = _dyld_get_image_header(i);
   1201 		if (mh)
   1202 		{
   1203 			lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
   1204 			for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
   1205 			{
   1206 				if (LC_SEGMENT == lc->cmd &&
   1207 					addr >= ((struct segment_command *)lc)->vmaddr &&
   1208 					addr <
   1209 					((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
   1210 				{
   1211 					goto image_found;
   1212 				}
   1213 			}
   1214 		}
   1215 		mh = 0;
   1216 	}
   1217   image_found:
   1218 	return mh;
   1219 }
   1220 
   1221 #if 0 /* unused */
   1222 static int SDL_OSX_dladdr(const void * dl_restrict p, SDL_OSX_Dl_info * dl_restrict info)
   1223 {
   1224 /*
   1225 	FIXME: USe the routine image_for_address.
   1226 */
   1227 	unsigned long i;
   1228 	unsigned long j;
   1229 	unsigned long count = _dyld_image_count();
   1230 	struct mach_header *mh = 0;
   1231 	struct load_command *lc = 0;
   1232 	unsigned long addr = NULL;
   1233 	unsigned long table_off = (unsigned long)0;
   1234 	int found = 0;
   1235 	if (!info)
   1236 		return 0;
   1237 	dolock();
   1238 	resetdlerror();
   1239 	info->dli_fname = 0;
   1240 	info->dli_fbase = 0;
   1241 	info->dli_sname = 0;
   1242 	info->dli_saddr = 0;
   1243 /* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
   1244  * to darwin-development AT lists DOT apple DOT com and slightly modified
   1245  */
   1246 	for (i = 0; i < count; i++)
   1247 	{
   1248 		addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
   1249 		mh = _dyld_get_image_header(i);
   1250 		if (mh)
   1251 		{
   1252 			lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
   1253 			for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
   1254 			{
   1255 				if (LC_SEGMENT == lc->cmd &&
   1256 					addr >= ((struct segment_command *)lc)->vmaddr &&
   1257 					addr <
   1258 					((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
   1259 				{
   1260 					info->dli_fname = _dyld_get_image_name(i);
   1261 					info->dli_fbase = (void *)mh;
   1262 					found = 1;
   1263 					break;
   1264 				}
   1265 			}
   1266 			if (found)
   1267 				break;
   1268 		}
   1269 	}
   1270 	if (!found)
   1271 	{
   1272 		dounlock();
   1273 		return 0;
   1274 	}
   1275 	lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
   1276 	for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
   1277 	{
   1278 		if (LC_SEGMENT == lc->cmd)
   1279 		{
   1280 			if (!SDL_strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
   1281 				break;
   1282 		}
   1283 	}
   1284 	table_off =
   1285 		((unsigned long)((struct segment_command *)lc)->vmaddr) -
   1286 		((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i);
   1287 	debug("table off %x", table_off);
   1288 
   1289 	lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
   1290 	for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
   1291 	{
   1292 		if (LC_SYMTAB == lc->cmd)
   1293 		{
   1294 
   1295 			struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off);
   1296 			unsigned long numsyms = ((struct symtab_command *)lc)->nsyms;
   1297 			struct nlist *nearest = NULL;
   1298 			unsigned long diff = 0xffffffff;
   1299 			unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off);
   1300 			debug("symtable %x", symtable);
   1301 			for (i = 0; i < numsyms; i++)
   1302 			{
   1303 				/* Ignore the following kinds of Symbols */
   1304 				if ((!symtable->n_value)	/* Undefined */
   1305 					|| (symtable->n_type >= N_PEXT)	/* Debug symbol */
   1306 					|| (!(symtable->n_type & N_EXT))	/* Local Symbol */
   1307 					)
   1308 				{
   1309 					symtable++;
   1310 					continue;
   1311 				}
   1312 				if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
   1313 				{
   1314 					diff = (unsigned long)symtable->n_value - addr;
   1315 					nearest = symtable;
   1316 				}
   1317 				symtable++;
   1318 			}
   1319 			if (nearest)
   1320 			{
   1321 				info->dli_saddr = nearest->n_value + ((void *)p - addr);
   1322 				info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
   1323 			}
   1324 		}
   1325 	}
   1326 	dounlock();
   1327 	return 1;
   1328 }
   1329 #endif
   1330 
   1331 /*
   1332  * Implement the dlfunc() interface, which behaves exactly the same as
   1333  * dlsym() except that it returns a function pointer instead of a data
   1334  * pointer.  This can be used by applications to avoid compiler warnings
   1335  * about undefined behavior, and is intended as prior art for future
   1336  * POSIX standardization.  This function requires that all pointer types
   1337  * have the same representation, which is true on all platforms FreeBSD
   1338  * runs on, but is not guaranteed by the C standard.
   1339  */
   1340 #if 0
   1341 static dlfunc_t SDL_OSX_dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
   1342 {
   1343 	union
   1344 	{
   1345 		void *d;
   1346 		dlfunc_t f;
   1347 	} rv;
   1348 	int sym_len = SDL_strlen(symbol);
   1349 	char *malloc_sym = NULL;
   1350 	dolock();
   1351 	malloc_sym = SDL_malloc(sym_len + 2);
   1352 	if (malloc_sym)
   1353 	{
   1354 		SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
   1355 		rv.d = dlsymIntern(handle, malloc_sym, 1);
   1356 		SDL_free(malloc_sym);
   1357 	}
   1358 	else
   1359 	{
   1360 		error("Unable to allocate memory");
   1361 		goto dlfuncerror;
   1362 	}
   1363 	dounlock();
   1364 	return rv.f;
   1365   dlfuncerror:
   1366 	dounlock();
   1367 	return NULL;
   1368 }
   1369 #endif
   1370 
   1371 
   1372 
   1373 /* dlcompat ends, here's the SDL interface...  --ryan.  */
   1374 
   1375 
   1376 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
   1377 /* System dependent library loading routines                           */
   1378 
   1379 #include "SDL_loadso.h"
   1380 
   1381 void *SDL_LoadObject(const char *sofile)
   1382 {
   1383 	void *handle = SDL_OSX_dlopen(sofile, RTLD_NOW);
   1384 	const char *loaderror = SDL_OSX_dlerror();
   1385 	if ( handle == NULL ) {
   1386 		SDL_SetError("Failed loading %s: %s", sofile, loaderror);
   1387 	}
   1388 	return(handle);
   1389 }
   1390 
   1391 void *SDL_LoadFunction(void *handle, const char *name)
   1392 {
   1393 	void *symbol = SDL_OSX_dlsym(handle, name);
   1394 	if ( symbol == NULL ) {
   1395 		SDL_SetError("Failed loading %s: %s", name, SDL_OSX_dlerror());
   1396 	}
   1397 	return(symbol);
   1398 }
   1399 
   1400 void SDL_UnloadObject(void *handle)
   1401 {
   1402 	if ( handle != NULL ) {
   1403 		SDL_OSX_dlclose(handle);
   1404 	}
   1405 }
   1406 
   1407 #endif /* SDL_LOADSO_DLCOMPAT */
   1408