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