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