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.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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 
  1071 static void *
  1072 dlsym_auto_underscore_intern(void *handle, const char *symbol)
  1073 {
  1074     struct dlstatus *dls = handle;
  1075     void *addr = 0;
  1076     addr = dlsymIntern(dls, symbol, 0);
  1077     if (!addr)
  1078         addr = dlsym_prepend_underscore_intern(handle, symbol);
  1079     return addr;
  1080 }
  1081 
  1082 
  1083 static void *
  1084 SDL_OSX_dlsym(void *dl_restrict handle, const char *dl_restrict symbol)
  1085 {
  1086     struct dlstatus *dls = handle;
  1087     void *addr = 0;
  1088     dolock();
  1089     addr = dlsymIntern(dls, symbol, 1);
  1090     dounlock();
  1091     return addr;
  1092 }
  1093 #endif
  1094 
  1095 static int
  1096 SDL_OSX_dlclose(void *handle)
  1097 {
  1098     struct dlstatus *dls = handle;
  1099     dolock();
  1100     resetdlerror();
  1101     if (!isValidStatus(dls)) {
  1102         goto dlcloseerror;
  1103     }
  1104     if (dls->module == MAGIC_DYLIB_MOD) {
  1105         const char *name;
  1106         if (!dls->lib) {
  1107             name = "global context";
  1108         } else {
  1109             name = get_lib_name(dls->lib);
  1110         }
  1111         warning("trying to close a .dylib!");
  1112         error("Not closing \"%s\" - dynamic libraries cannot be closed",
  1113               name);
  1114         goto dlcloseerror;
  1115     }
  1116     if (!dls->module) {
  1117         error("module already closed");
  1118         goto dlcloseerror;
  1119     }
  1120 
  1121     if (dls->refs == 1) {
  1122         unsigned long options = 0;
  1123         void (*fini) (void);
  1124         if ((fini = dlsymIntern(dls, "__fini", 0))) {
  1125             debug("calling _fini()");
  1126             fini();
  1127         }
  1128         options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
  1129 #ifdef RTLD_NODELETE
  1130         if (isFlagSet(dls->mode, RTLD_NODELETE))
  1131             options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
  1132 #endif
  1133         if (!NSUnLinkModule(dls->module, options)) {
  1134             error("unable to unlink module");
  1135             goto dlcloseerror;
  1136         }
  1137         dls->refs--;
  1138         dls->module = 0;
  1139         /* Note: the dlstatus struct dls is neither removed from the list
  1140          * nor is the memory it occupies freed. This shouldn't pose a 
  1141          * problem in mostly all cases, though.
  1142          */
  1143     }
  1144     dounlock();
  1145     return 0;
  1146   dlcloseerror:
  1147     dounlock();
  1148     return 1;
  1149 }
  1150 
  1151 static const char *
  1152 SDL_OSX_dlerror(void)
  1153 {
  1154     struct dlthread *tss;
  1155     const char *err_str = NULL;
  1156     dlcompat_init_check();
  1157     tss = pthread_getspecific(dlerror_key);
  1158     if (tss != NULL && tss->errset != 0) {
  1159         tss->errset = 0;
  1160         err_str = tss->errstr;
  1161     }
  1162     return (err_str);
  1163 }
  1164 
  1165 /* Given an address, return the mach_header for the image containing it
  1166  * or zero if the given address is not contained in any loaded images.
  1167  */
  1168 static const struct mach_header *
  1169 image_for_address(const void *address)
  1170 {
  1171     unsigned long i;
  1172     unsigned long j;
  1173     unsigned long count = _dyld_image_count();
  1174     const struct mach_header *mh = 0;
  1175     struct load_command *lc = 0;
  1176     unsigned long addr = 0;
  1177     for (i = 0; i < count; i++) {
  1178         addr = (unsigned long) address - _dyld_get_image_vmaddr_slide(i);
  1179         mh = _dyld_get_image_header(i);
  1180         if (mh) {
  1181             lc = (struct load_command *) ((char *) mh +
  1182                                           sizeof(struct mach_header));
  1183             for (j = 0; j < mh->ncmds;
  1184                  j++, lc =
  1185                  (struct load_command *) ((char *) lc + lc->cmdsize)) {
  1186                 if (LC_SEGMENT == lc->cmd &&
  1187                     addr >= ((struct segment_command *) lc)->vmaddr &&
  1188                     addr <
  1189                     ((struct segment_command *) lc)->vmaddr +
  1190                     ((struct segment_command *) lc)->vmsize) {
  1191                     goto image_found;
  1192                 }
  1193             }
  1194         }
  1195         mh = 0;
  1196     }
  1197   image_found:
  1198     return mh;
  1199 }
  1200 
  1201 #if 0                           /* unused */
  1202 static int
  1203 SDL_OSX_dladdr(const void *dl_restrict p, SDL_OSX_Dl_info * dl_restrict info)
  1204 {
  1205 /*
  1206 	FIXME: USe the routine image_for_address.
  1207 */
  1208     unsigned long i;
  1209     unsigned long j;
  1210     unsigned long count = _dyld_image_count();
  1211     struct mach_header *mh = 0;
  1212     struct load_command *lc = 0;
  1213     unsigned long addr = NULL;
  1214     unsigned long table_off = (unsigned long) 0;
  1215     int found = 0;
  1216     if (!info)
  1217         return 0;
  1218     dolock();
  1219     resetdlerror();
  1220     info->dli_fname = 0;
  1221     info->dli_fbase = 0;
  1222     info->dli_sname = 0;
  1223     info->dli_saddr = 0;
  1224 /* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
  1225  * to darwin-development AT lists DOT apple DOT com and slightly modified
  1226  */
  1227     for (i = 0; i < count; i++) {
  1228         addr = (unsigned long) p - _dyld_get_image_vmaddr_slide(i);
  1229         mh = _dyld_get_image_header(i);
  1230         if (mh) {
  1231             lc = (struct load_command *) ((char *) mh +
  1232                                           sizeof(struct mach_header));
  1233             for (j = 0; j < mh->ncmds;
  1234                  j++, lc =
  1235                  (struct load_command *) ((char *) lc + lc->cmdsize)) {
  1236                 if (LC_SEGMENT == lc->cmd &&
  1237                     addr >= ((struct segment_command *) lc)->vmaddr &&
  1238                     addr <
  1239                     ((struct segment_command *) lc)->vmaddr +
  1240                     ((struct segment_command *) lc)->vmsize) {
  1241                     info->dli_fname = _dyld_get_image_name(i);
  1242                     info->dli_fbase = (void *) mh;
  1243                     found = 1;
  1244                     break;
  1245                 }
  1246             }
  1247             if (found)
  1248                 break;
  1249         }
  1250     }
  1251     if (!found) {
  1252         dounlock();
  1253         return 0;
  1254     }
  1255     lc = (struct load_command *) ((char *) mh + sizeof(struct mach_header));
  1256     for (j = 0; j < mh->ncmds;
  1257          j++, lc = (struct load_command *) ((char *) lc + lc->cmdsize)) {
  1258         if (LC_SEGMENT == lc->cmd) {
  1259             if (!SDL_strcmp
  1260                 (((struct segment_command *) lc)->segname, "__LINKEDIT"))
  1261                 break;
  1262         }
  1263     }
  1264     table_off =
  1265         ((unsigned long) ((struct segment_command *) lc)->vmaddr) -
  1266         ((unsigned long) ((struct segment_command *) lc)->fileoff) +
  1267         _dyld_get_image_vmaddr_slide(i);
  1268     debug("table off %x", table_off);
  1269 
  1270     lc = (struct load_command *) ((char *) mh + sizeof(struct mach_header));
  1271     for (j = 0; j < mh->ncmds;
  1272          j++, lc = (struct load_command *) ((char *) lc + lc->cmdsize)) {
  1273         if (LC_SYMTAB == lc->cmd) {
  1274 
  1275             struct nlist *symtable =
  1276                 (struct nlist *) (((struct symtab_command *) lc)->symoff +
  1277                                   table_off);
  1278             unsigned long numsyms = ((struct symtab_command *) lc)->nsyms;
  1279             struct nlist *nearest = NULL;
  1280             unsigned long diff = 0xffffffff;
  1281             unsigned long strtable =
  1282                 (unsigned long) (((struct symtab_command *) lc)->stroff +
  1283                                  table_off);
  1284             debug("symtable %x", symtable);
  1285             for (i = 0; i < numsyms; i++) {
  1286                 /* Ignore the following kinds of Symbols */
  1287                 if ((!symtable->n_value)        /* Undefined */
  1288                     ||(symtable->n_type >= N_PEXT)      /* Debug symbol */
  1289                     ||(!(symtable->n_type & N_EXT))     /* Local Symbol */
  1290                     ) {
  1291                     symtable++;
  1292                     continue;
  1293                 }
  1294                 if ((addr >= symtable->n_value)
  1295                     && (diff >= (symtable->n_value - addr))) {
  1296                     diff = (unsigned long) symtable->n_value - addr;
  1297                     nearest = symtable;
  1298                 }
  1299                 symtable++;
  1300             }
  1301             if (nearest) {
  1302                 info->dli_saddr = nearest->n_value + ((void *) p - addr);
  1303                 info->dli_sname = (char *) (strtable + nearest->n_un.n_strx);
  1304             }
  1305         }
  1306     }
  1307     dounlock();
  1308     return 1;
  1309 }
  1310 #endif
  1311 
  1312 /*
  1313  * Implement the dlfunc() interface, which behaves exactly the same as
  1314  * dlsym() except that it returns a function pointer instead of a data
  1315  * pointer.  This can be used by applications to avoid compiler warnings
  1316  * about undefined behavior, and is intended as prior art for future
  1317  * POSIX standardization.  This function requires that all pointer types
  1318  * have the same representation, which is true on all platforms FreeBSD
  1319  * runs on, but is not guaranteed by the C standard.
  1320  */
  1321 #if 0
  1322 static dlfunc_t
  1323 SDL_OSX_dlfunc(void *dl_restrict handle, const char *dl_restrict symbol)
  1324 {
  1325     union
  1326     {
  1327         void *d;
  1328         dlfunc_t f;
  1329     } rv;
  1330     int sym_len = SDL_strlen(symbol);
  1331     char *malloc_sym = NULL;
  1332     dolock();
  1333     malloc_sym = SDL_malloc(sym_len + 2);
  1334     if (malloc_sym) {
  1335         SDL_snprintf(malloc_sym, sym_len + 2, "_%s", symbol);
  1336         rv.d = dlsymIntern(handle, malloc_sym, 1);
  1337         SDL_free(malloc_sym);
  1338     } else {
  1339         error("Unable to allocate memory");
  1340         goto dlfuncerror;
  1341     }
  1342     dounlock();
  1343     return rv.f;
  1344   dlfuncerror:
  1345     dounlock();
  1346     return NULL;
  1347 }
  1348 #endif
  1349 
  1350 
  1351 
  1352 /* dlcompat ends, here's the SDL interface...  --ryan.  */
  1353 
  1354 
  1355 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1356 /* System dependent library loading routines                           */
  1357 
  1358 #include "SDL_loadso.h"
  1359 
  1360 void *
  1361 SDL_LoadObject(const char *sofile)
  1362 {
  1363     void *handle = SDL_OSX_dlopen(sofile, RTLD_NOW);
  1364     const char *loaderror = SDL_OSX_dlerror();
  1365     if (handle == NULL) {
  1366         SDL_SetError("Failed loading %s: %s", sofile, loaderror);
  1367     }
  1368     return (handle);
  1369 }
  1370 
  1371 void *
  1372 SDL_LoadFunction(void *handle, const char *name)
  1373 {
  1374     void *symbol = SDL_OSX_dlsym(handle, name);
  1375     if (symbol == NULL) {
  1376         SDL_SetError("Failed loading %s: %s", name, SDL_OSX_dlerror());
  1377     }
  1378     return (symbol);
  1379 }
  1380 
  1381 void
  1382 SDL_UnloadObject(void *handle)
  1383 {
  1384     if (handle != NULL) {
  1385         SDL_OSX_dlclose(handle);
  1386     }
  1387 }
  1388 
  1389 #endif /* SDL_LOADSO_DLCOMPAT */
  1390 
  1391 /* vi: set ts=4 sw=4 expandtab: */