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