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