1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/loadso/macosx/SDL_loadso.c Thu Nov 17 03:15:05 2005 +0000
1.3 @@ -0,0 +1,1419 @@
1.4 +/*
1.5 + SDL - Simple DirectMedia Layer
1.6 + Copyright (C) 1997-2004 Sam Lantinga
1.7 +
1.8 + This library is free software; you can redistribute it and/or
1.9 + modify it under the terms of the GNU Library General Public
1.10 + License as published by the Free Software Foundation; either
1.11 + version 2 of the License, or (at your option) any later version.
1.12 +
1.13 + This library is distributed in the hope that it will be useful,
1.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.16 + Library General Public License for more details.
1.17 +
1.18 + You should have received a copy of the GNU Library General Public
1.19 + License along with this library; if not, write to the Free
1.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.21 +
1.22 + Sam Lantinga
1.23 + slouken@libsdl.org
1.24 +*/
1.25 +
1.26 +#ifdef SAVE_RCSID
1.27 +static char rcsid =
1.28 + "@(#) $Id$";
1.29 +#endif
1.30 +
1.31 +/* Please note that dlcompat apparently ships in current Mac OS X versions
1.32 + * as a system library that provides compatibility with the Unix "dlopen"
1.33 + * interface. In order to allow SDL to work on older OS X releases and also
1.34 + * not conflict with the system lib on newer versions, we include dlcompat
1.35 + * in SDL and change the symbols to prevent symbol clash with any existing
1.36 + * system libraries. --ryan.
1.37 + */
1.38 +
1.39 +/* here is the dlcompat license: */
1.40 +
1.41 +/*
1.42 +Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> &
1.43 + Peter O'Gorman <ogorman@users.sourceforge.net>
1.44 +
1.45 +Portions may be copyright others, see the AUTHORS file included with this
1.46 +distribution.
1.47 +
1.48 +Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
1.49 +
1.50 +Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
1.51 +
1.52 +Permission is hereby granted, free of charge, to any person obtaining
1.53 +a copy of this software and associated documentation files (the
1.54 +"Software"), to deal in the Software without restriction, including
1.55 +without limitation the rights to use, copy, modify, merge, publish,
1.56 +distribute, sublicense, and/or sell copies of the Software, and to
1.57 +permit persons to whom the Software is furnished to do so, subject to
1.58 +the following conditions:
1.59 +
1.60 +The above copyright notice and this permission notice shall be
1.61 +included in all copies or substantial portions of the Software.
1.62 +
1.63 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1.64 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1.65 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1.66 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1.67 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1.68 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1.69 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1.70 +*/
1.71 +
1.72 +#include <pthread.h>
1.73 +#include <stdio.h>
1.74 +#include <stdlib.h>
1.75 +#include <string.h>
1.76 +#include <sys/types.h>
1.77 +#include <sys/stat.h>
1.78 +#include <stdarg.h>
1.79 +#include <limits.h>
1.80 +#include <mach-o/dyld.h>
1.81 +#include <mach-o/nlist.h>
1.82 +#include <mach-o/getsect.h>
1.83 +
1.84 +/* Just playing to see if it would compile with the freebsd headers, it does,
1.85 + * but because of the different values for RTLD_LOCAL etc, it would break binary
1.86 + * compat... oh well
1.87 + */
1.88 +#ifndef __BSD_VISIBLE
1.89 +#define __BSD_VISIBLE 1
1.90 +#endif
1.91 +
1.92 +/*include "dlfcn.h"*/
1.93 +#ifdef __cplusplus
1.94 +extern "C" {
1.95 +#endif
1.96 +
1.97 +#if defined (__GNUC__) && __GNUC__ > 3
1.98 +#define dl_restrict __restrict
1.99 +#else
1.100 +#define dl_restrict
1.101 +#endif
1.102 +
1.103 +#ifndef _POSIX_SOURCE
1.104 +/*
1.105 + * Structure filled in by dladdr().
1.106 + */
1.107 +typedef struct SDL_OSX_dl_info {
1.108 + const char *dli_fname; /* Pathname of shared object */
1.109 + void *dli_fbase; /* Base address of shared object */
1.110 + const char *dli_sname; /* Name of nearest symbol */
1.111 + void *dli_saddr; /* Address of nearest symbol */
1.112 +} SDL_OSX_Dl_info;
1.113 +
1.114 +static int SDL_OSX_dladdr(const void * dl_restrict, SDL_OSX_Dl_info * dl_restrict);
1.115 +#endif /* ! _POSIX_SOURCE */
1.116 +
1.117 +static int SDL_OSX_dlclose(void * handle);
1.118 +static char * SDL_OSX_dlerror(void);
1.119 +static void * SDL_OSX_dlopen(const char *path, int mode);
1.120 +static void * SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol);
1.121 +
1.122 +#define RTLD_LAZY 0x1
1.123 +#define RTLD_NOW 0x2
1.124 +#define RTLD_LOCAL 0x4
1.125 +#define RTLD_GLOBAL 0x8
1.126 +
1.127 +#ifndef _POSIX_SOURCE
1.128 +#define RTLD_NOLOAD 0x10
1.129 +#define RTLD_NODELETE 0x80
1.130 +
1.131 +/*
1.132 + * Special handle arguments for SDL_OSX_dlsym().
1.133 + */
1.134 +#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
1.135 +#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
1.136 +#endif /* ! _POSIX_SOURCE */
1.137 +
1.138 +#ifdef __cplusplus
1.139 +}
1.140 +#endif
1.141 +
1.142 +#ifndef dl_restrict
1.143 +#define dl_restrict __restrict
1.144 +#endif
1.145 +/* This is not available on 10.1 */
1.146 +#ifndef LC_LOAD_WEAK_DYLIB
1.147 +#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
1.148 +#endif
1.149 +
1.150 +/* With this stuff here, this thing may actually compile/run on 10.0 systems
1.151 + * Not that I have a 10.0 system to test it on anylonger
1.152 + */
1.153 +#ifndef LC_REQ_DYLD
1.154 +#define LC_REQ_DYLD 0x80000000
1.155 +#endif
1.156 +#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
1.157 +#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
1.158 +#endif
1.159 +#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
1.160 +#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
1.161 +#endif
1.162 +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
1.163 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
1.164 +#endif
1.165 +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
1.166 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
1.167 +#endif
1.168 +/* These symbols will be looked for in dyld */
1.169 +static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
1.170 +static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
1.171 +static NSSymbol(*dyld_NSLookupSymbolInImage)
1.172 + (const struct mach_header *, const char *, unsigned long) = 0;
1.173 +
1.174 +/* Define this to make dlcompat reuse data block. This way in theory we save
1.175 + * a little bit of overhead. However we then couldn't correctly catch excess
1.176 + * calls to SDL_OSX_dlclose(). Hence we don't use this feature
1.177 + */
1.178 +#undef REUSE_STATUS
1.179 +
1.180 +/* Size of the internal error message buffer (used by dlerror()) */
1.181 +#define ERR_STR_LEN 251
1.182 +
1.183 +/* Maximum number of search paths supported by getSearchPath */
1.184 +#define MAX_SEARCH_PATHS 32
1.185 +
1.186 +
1.187 +#define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
1.188 +#define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
1.189 +
1.190 +/* internal flags */
1.191 +#define DL_IN_LIST 0x01
1.192 +
1.193 +/* our mutex */
1.194 +static pthread_mutex_t dlcompat_mutex;
1.195 +/* Our thread specific storage
1.196 + */
1.197 +static pthread_key_t dlerror_key;
1.198 +
1.199 +struct dlthread
1.200 +{
1.201 + int lockcnt;
1.202 + unsigned char errset;
1.203 + char errstr[ERR_STR_LEN];
1.204 +};
1.205 +
1.206 +/* This is our central data structure. Whenever a module is loaded via
1.207 + * SDL_OSX_dlopen(), we create such a struct.
1.208 + */
1.209 +struct dlstatus
1.210 +{
1.211 + struct dlstatus *next; /* pointer to next element in the linked list */
1.212 + NSModule module;
1.213 + const struct mach_header *lib;
1.214 + int refs; /* reference count */
1.215 + int mode; /* mode in which this module was loaded */
1.216 + dev_t device;
1.217 + ino_t inode;
1.218 + int flags; /* Any internal flags we may need */
1.219 +};
1.220 +
1.221 +/* Head node of the dlstatus list */
1.222 +static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
1.223 +static struct dlstatus *stqueue = &mainStatus;
1.224 +
1.225 +
1.226 +/* Storage for the last error message (used by dlerror()) */
1.227 +/* static char err_str[ERR_STR_LEN]; */
1.228 +/* static int err_filled = 0; */
1.229 +
1.230 +/* Prototypes to internal functions */
1.231 +static void debug(const char *fmt, ...);
1.232 +static void error(const char *str, ...);
1.233 +static const char *safegetenv(const char *s);
1.234 +static const char *searchList(void);
1.235 +static const char *getSearchPath(int i);
1.236 +static const char *getFullPath(int i, const char *file);
1.237 +static const struct stat *findFile(const char *file, const char **fullPath);
1.238 +static int isValidStatus(struct dlstatus *status);
1.239 +static inline int isFlagSet(int mode, int flag);
1.240 +static struct dlstatus *lookupStatus(const struct stat *sbuf);
1.241 +static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
1.242 +static int promoteLocalToGlobal(struct dlstatus *dls);
1.243 +static void *reference(struct dlstatus *dls, int mode);
1.244 +static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
1.245 +static struct dlstatus *allocStatus(void);
1.246 +static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
1.247 +static NSSymbol *search_linked_libs(const struct mach_header *mh, const char *symbol);
1.248 +static const char *get_lib_name(const struct mach_header *mh);
1.249 +static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod);
1.250 +static void dlcompat_init_func(void);
1.251 +static inline void dlcompat_init_check(void);
1.252 +static inline void dolock(void);
1.253 +static inline void dounlock(void);
1.254 +static void dlerrorfree(void *data);
1.255 +static void resetdlerror(void);
1.256 +static const struct mach_header *my_find_image(const char *name);
1.257 +static const struct mach_header *image_for_address(const void *address);
1.258 +static inline const char *dyld_error_str(void);
1.259 +
1.260 +#if FINK_BUILD
1.261 +/* Two Global Functions */
1.262 +static void *dlsym_prepend_underscore(void *handle, const char *symbol);
1.263 +static void *dlsym_auto_underscore(void *handle, const char *symbol);
1.264 +
1.265 +/* And their _intern counterparts */
1.266 +static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
1.267 +static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
1.268 +#endif
1.269 +
1.270 +/* Functions */
1.271 +
1.272 +static void debug(const char *fmt, ...)
1.273 +{
1.274 +#if DEBUG > 1
1.275 + va_list arg;
1.276 + va_start(arg, fmt);
1.277 + fprintf(stderr, "DLDEBUG: ");
1.278 + vfprintf(stderr, fmt, arg);
1.279 + fprintf(stderr, "\n");
1.280 + fflush(stderr);
1.281 + va_end(arg);
1.282 +#endif
1.283 +}
1.284 +
1.285 +static void error(const char *str, ...)
1.286 +{
1.287 + va_list arg;
1.288 + struct dlthread *tss;
1.289 + char * err_str;
1.290 + va_start(arg, str);
1.291 + tss = pthread_getspecific(dlerror_key);
1.292 + err_str = tss->errstr;
1.293 + strncpy(err_str, "dlcompat: ", ERR_STR_LEN);
1.294 + vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
1.295 + va_end(arg);
1.296 + debug("ERROR: %s\n", err_str);
1.297 + tss->errset = 1;
1.298 +}
1.299 +
1.300 +static void warning(const char *str)
1.301 +{
1.302 +#if DEBUG > 0
1.303 + fprintf(stderr, "WARNING: dlcompat: %s\n", str);
1.304 +#endif
1.305 +}
1.306 +
1.307 +static const char *safegetenv(const char *s)
1.308 +{
1.309 + const char *ss = getenv(s);
1.310 + return ss ? ss : "";
1.311 +}
1.312 +
1.313 +/* because this is only used for debugging and error reporting functions, we
1.314 + * don't really care about how elegant it is... it could use the load
1.315 + * commands to find the install name of the library, but...
1.316 + */
1.317 +static const char *get_lib_name(const struct mach_header *mh)
1.318 +{
1.319 + unsigned long count = _dyld_image_count();
1.320 + unsigned long i;
1.321 + const char *val = NULL;
1.322 + if (mh)
1.323 + {
1.324 + for (i = 0; i < count; i++)
1.325 + {
1.326 + if (mh == _dyld_get_image_header(i))
1.327 + {
1.328 + val = _dyld_get_image_name(i);
1.329 + break;
1.330 + }
1.331 + }
1.332 + }
1.333 + return val;
1.334 +}
1.335 +
1.336 +/* Returns the mach_header for the module bu going through all the loaded images
1.337 + * and finding the one with the same name as the module. There really ought to be
1.338 + * an api for doing this, would be faster, but there isn't one right now
1.339 + */
1.340 +static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod)
1.341 +{
1.342 + const char *mod_name = NSNameOfModule(mod);
1.343 + struct mach_header *mh = NULL;
1.344 + unsigned long count = _dyld_image_count();
1.345 + unsigned long i;
1.346 + debug("Module name: %s", mod_name);
1.347 + for (i = 0; i < count; i++)
1.348 + {
1.349 + if (!strcmp(mod_name, _dyld_get_image_name(i)))
1.350 + {
1.351 + mh = _dyld_get_image_header(i);
1.352 + break;
1.353 + }
1.354 + }
1.355 + return mh;
1.356 +}
1.357 +
1.358 +
1.359 +/* Compute and return a list of all directories that we should search when
1.360 + * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
1.361 + * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
1.362 + * /usr/lib and /lib. Since both of the environments variables can contain a
1.363 + * list of colon seperated paths, we simply concat them and the two other paths
1.364 + * into one big string, which we then can easily parse.
1.365 + * Splitting this string into the actual path list is done by getSearchPath()
1.366 + */
1.367 +static const char *searchList()
1.368 +{
1.369 + size_t buf_size;
1.370 + static char *buf=NULL;
1.371 + const char *ldlp = safegetenv("LD_LIBRARY_PATH");
1.372 + const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
1.373 + const char *stdpath = getenv("DYLD_FALLBACK_LIBRARY_PATH");
1.374 + if (!stdpath)
1.375 + stdpath = "/usr/local/lib:/lib:/usr/lib";
1.376 + if (!buf)
1.377 + {
1.378 + buf_size = strlen(ldlp) + strlen(dyldlp) + strlen(stdpath) + 4;
1.379 + buf = malloc(buf_size);
1.380 + snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
1.381 + stdpath, '\0');
1.382 + }
1.383 + return buf;
1.384 +}
1.385 +
1.386 +/* Returns the ith search path from the list as computed by searchList() */
1.387 +static const char *getSearchPath(int i)
1.388 +{
1.389 + static const char *list = 0;
1.390 + static char **path = (char **)0;
1.391 + static int end = 0;
1.392 + static int numsize = MAX_SEARCH_PATHS;
1.393 + static char **tmp;
1.394 + /* So we can call free() in the "destructor" we use i=-1 to return the alloc'd array */
1.395 + if (i == -1)
1.396 + {
1.397 + return (const char*)path;
1.398 + }
1.399 + if (!path)
1.400 + {
1.401 + path = (char **)calloc(MAX_SEARCH_PATHS, sizeof(char **));
1.402 + }
1.403 + if (!list && !end)
1.404 + list = searchList();
1.405 + if (i >= (numsize))
1.406 + {
1.407 + debug("Increasing size for long PATH");
1.408 + tmp = (char **)calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
1.409 + if (tmp)
1.410 + {
1.411 + memcpy(tmp, path, sizeof(char **) * numsize);
1.412 + free(path);
1.413 + path = tmp;
1.414 + numsize += MAX_SEARCH_PATHS;
1.415 + }
1.416 + else
1.417 + {
1.418 + return 0;
1.419 + }
1.420 + }
1.421 +
1.422 + while (!path[i] && !end)
1.423 + {
1.424 + path[i] = strsep((char **)&list, ":");
1.425 +
1.426 + if (path[i][0] == 0)
1.427 + path[i] = 0;
1.428 + end = (list == 0);
1.429 + }
1.430 + return path[i];
1.431 +}
1.432 +
1.433 +static const char *getFullPath(int i, const char *file)
1.434 +{
1.435 + static char buf[PATH_MAX];
1.436 + const char *path = getSearchPath(i);
1.437 + if (path)
1.438 + {
1.439 + snprintf(buf, PATH_MAX, "%s/%s", path, file);
1.440 + }
1.441 + return path ? buf : 0;
1.442 +}
1.443 +
1.444 +/* Given a file name, try to determine the full path for that file. Starts
1.445 + * its search in the current directory, and then tries all paths in the
1.446 + * search list in the order they are specified there.
1.447 + */
1.448 +static const struct stat *findFile(const char *file, const char **fullPath)
1.449 +{
1.450 + int i = 0;
1.451 + static struct stat sbuf;
1.452 + char *fileName;
1.453 + debug("finding file %s", file);
1.454 + *fullPath = file;
1.455 + if (0 == stat(file, &sbuf))
1.456 + return &sbuf;
1.457 + if (strchr(file, '/'))
1.458 + return 0; /* If the path had a / we don't look in env var places */
1.459 + fileName = NULL;
1.460 + if (!fileName)
1.461 + fileName = (char *)file;
1.462 + while ((*fullPath = getFullPath(i++, fileName)))
1.463 + {
1.464 + if (0 == stat(*fullPath, &sbuf))
1.465 + return &sbuf;
1.466 + }
1.467 + ;
1.468 + return 0;
1.469 +}
1.470 +
1.471 +/* Determine whether a given dlstatus is valid or not */
1.472 +static int isValidStatus(struct dlstatus *status)
1.473 +{
1.474 + /* Walk the list to verify status is contained in it */
1.475 + struct dlstatus *dls = stqueue;
1.476 + while (dls && status != dls)
1.477 + dls = dls->next;
1.478 + if (dls == 0)
1.479 + error("invalid handle");
1.480 + else if ((dls->module == 0) || (dls->refs == 0))
1.481 + error("handle to closed library");
1.482 + else
1.483 + return TRUE;
1.484 + return FALSE;
1.485 +}
1.486 +
1.487 +static inline int isFlagSet(int mode, int flag)
1.488 +{
1.489 + return (mode & flag) == flag;
1.490 +}
1.491 +
1.492 +static struct dlstatus *lookupStatus(const struct stat *sbuf)
1.493 +{
1.494 + struct dlstatus *dls = stqueue;
1.495 + debug("looking for status");
1.496 + while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
1.497 + || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
1.498 + dls = dls->next;
1.499 + return dls;
1.500 +}
1.501 +
1.502 +static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
1.503 +{
1.504 + debug("inserting status");
1.505 + dls->inode = sbuf->st_ino;
1.506 + dls->device = sbuf->st_dev;
1.507 + dls->refs = 0;
1.508 + dls->mode = 0;
1.509 + if ((dls->flags & DL_IN_LIST) == 0)
1.510 + {
1.511 + dls->next = stqueue;
1.512 + stqueue = dls;
1.513 + dls->flags |= DL_IN_LIST;
1.514 + }
1.515 +}
1.516 +
1.517 +static struct dlstatus *allocStatus()
1.518 +{
1.519 + struct dlstatus *dls;
1.520 +#ifdef REUSE_STATUS
1.521 + dls = stqueue;
1.522 + while (dls && dls->module)
1.523 + dls = dls->next;
1.524 + if (!dls)
1.525 +#endif
1.526 + dls = calloc(sizeof(*dls),1);
1.527 + return dls;
1.528 +}
1.529 +
1.530 +static int promoteLocalToGlobal(struct dlstatus *dls)
1.531 +{
1.532 + static int (*p) (NSModule module) = 0;
1.533 + debug("promoting");
1.534 + if (!p)
1.535 + _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p);
1.536 + return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
1.537 +}
1.538 +
1.539 +static void *reference(struct dlstatus *dls, int mode)
1.540 +{
1.541 + if (dls)
1.542 + {
1.543 + if (dls->module == MAGIC_DYLIB_MOD && isFlagSet(mode, RTLD_LOCAL))
1.544 + {
1.545 + warning("trying to open a .dylib with RTLD_LOCAL");
1.546 + error("unable to open a .dylib with RTLD_LOCAL");
1.547 + return NULL;
1.548 + }
1.549 + if (isFlagSet(mode, RTLD_GLOBAL) &&
1.550 + !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
1.551 + {
1.552 + error("unable to promote local module to global");
1.553 + return NULL;
1.554 + }
1.555 + dls->mode |= mode;
1.556 + dls->refs++;
1.557 + }
1.558 + else
1.559 + debug("reference called with NULL argument");
1.560 +
1.561 + return dls;
1.562 +}
1.563 +
1.564 +static const struct mach_header *my_find_image(const char *name)
1.565 +{
1.566 + const struct mach_header *mh = 0;
1.567 + const char *id = NULL;
1.568 + int i = _dyld_image_count();
1.569 + int j;
1.570 + mh = (struct mach_header *)
1.571 + dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
1.572 + NSADDIMAGE_OPTION_RETURN_ON_ERROR);
1.573 + if (!mh)
1.574 + {
1.575 + for (j = 0; j < i; j++)
1.576 + {
1.577 + id = _dyld_get_image_name(j);
1.578 + if (!strcmp(id, name))
1.579 + {
1.580 + mh = _dyld_get_image_header(j);
1.581 + break;
1.582 + }
1.583 + }
1.584 + }
1.585 + return mh;
1.586 +}
1.587 +
1.588 +/*
1.589 + * dyld adds libraries by first adding the directly dependant libraries in link order, and
1.590 + * then adding the dependencies for those libraries, so we should do the same... but we don't
1.591 + * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
1.592 + * any of it's direct dependencies, then it probably isn't there.
1.593 + */
1.594 +static NSSymbol *search_linked_libs(const struct mach_header * mh, const char *symbol)
1.595 +{
1.596 + unsigned int n;
1.597 + struct load_command *lc = 0;
1.598 + struct mach_header *wh;
1.599 + NSSymbol *nssym = 0;
1.600 + if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
1.601 + {
1.602 + lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1.603 + for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1.604 + {
1.605 + if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
1.606 + {
1.607 + if ((wh = (struct mach_header *)
1.608 + my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
1.609 + (char *)lc))))
1.610 + {
1.611 + if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
1.612 + {
1.613 + nssym = dyld_NSLookupSymbolInImage(wh,
1.614 + symbol,
1.615 + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
1.616 + NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
1.617 + break;
1.618 + }
1.619 + }
1.620 + }
1.621 + }
1.622 + if ((!nssym) && NSIsSymbolNameDefined(symbol))
1.623 + {
1.624 + /* I've never seen this debug message...*/
1.625 + debug("Symbol \"%s\" is defined but was not found", symbol);
1.626 + }
1.627 + }
1.628 + return nssym;
1.629 +}
1.630 +
1.631 +/* Up to the caller to free() returned string */
1.632 +static inline const char *dyld_error_str()
1.633 +{
1.634 + NSLinkEditErrors dylder;
1.635 + int dylderno;
1.636 + const char *dylderrstr;
1.637 + const char *dyldfile;
1.638 + const char* retStr = NULL;
1.639 + NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
1.640 + if (dylderrstr && strlen(dylderrstr))
1.641 + {
1.642 + retStr = malloc(strlen(dylderrstr) +1);
1.643 + strcpy((char*)retStr,dylderrstr);
1.644 + }
1.645 + return retStr;
1.646 +}
1.647 +
1.648 +static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
1.649 +{
1.650 + NSSymbol *nssym = 0;
1.651 +#ifdef __GCC__
1.652 + void *caller = __builtin_return_address(1); /* Be *very* careful about inlining */
1.653 +#else
1.654 + void *caller = NULL;
1.655 +#endif
1.656 + const struct mach_header *caller_mh = 0;
1.657 + const char* savedErrorStr = NULL;
1.658 + resetdlerror();
1.659 +#ifndef RTLD_SELF
1.660 +#define RTLD_SELF ((void *) -3)
1.661 +#endif
1.662 + if (NULL == dls)
1.663 + dls = RTLD_SELF;
1.664 + if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
1.665 + {
1.666 + if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage && caller)
1.667 + {
1.668 + caller_mh = image_for_address(caller);
1.669 + if (RTLD_SELF == dls)
1.670 + {
1.671 + /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
1.672 + * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
1.673 + * this is acceptable.
1.674 + */
1.675 + if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
1.676 + {
1.677 + nssym = dyld_NSLookupSymbolInImage(caller_mh,
1.678 + symbol,
1.679 + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
1.680 + NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
1.681 + }
1.682 + }
1.683 + if (!nssym)
1.684 + {
1.685 + if (RTLD_SELF == dls)
1.686 + savedErrorStr = dyld_error_str();
1.687 + nssym = search_linked_libs(caller_mh, symbol);
1.688 + }
1.689 + }
1.690 + else
1.691 + {
1.692 + if (canSetError)
1.693 + error("RTLD_SELF and RTLD_NEXT are not supported");
1.694 + return NULL;
1.695 + }
1.696 + }
1.697 + if (!nssym)
1.698 + {
1.699 +
1.700 + if (RTLD_DEFAULT == dls)
1.701 + {
1.702 + dls = &mainStatus;
1.703 + }
1.704 + if (!isValidStatus(dls))
1.705 + return NULL;
1.706 +
1.707 + if (dls->module != MAGIC_DYLIB_MOD)
1.708 + {
1.709 + nssym = NSLookupSymbolInModule(dls->module, symbol);
1.710 + if (!nssym && NSIsSymbolNameDefined(symbol))
1.711 + {
1.712 + debug("Searching dependencies");
1.713 + savedErrorStr = dyld_error_str();
1.714 + nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
1.715 + }
1.716 + }
1.717 + else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
1.718 + {
1.719 + if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
1.720 + {
1.721 + nssym = dyld_NSLookupSymbolInImage(dls->lib,
1.722 + symbol,
1.723 + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
1.724 + NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
1.725 + }
1.726 + else if (NSIsSymbolNameDefined(symbol))
1.727 + {
1.728 + debug("Searching dependencies");
1.729 + savedErrorStr = dyld_error_str();
1.730 + nssym = search_linked_libs(dls->lib, symbol);
1.731 + }
1.732 + }
1.733 + else if (dls->module == MAGIC_DYLIB_MOD)
1.734 + {
1.735 + /* Global context, use NSLookupAndBindSymbol */
1.736 + if (NSIsSymbolNameDefined(symbol))
1.737 + {
1.738 + /* There doesn't seem to be a return on error option for this call???
1.739 + this is potentially broken, if binding fails, it will improperly
1.740 + exit the application. */
1.741 + nssym = NSLookupAndBindSymbol(symbol);
1.742 + }
1.743 + else
1.744 + {
1.745 + if (savedErrorStr)
1.746 + free((char*)savedErrorStr);
1.747 + savedErrorStr = malloc(256);
1.748 + snprintf((char*)savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);
1.749 + }
1.750 + }
1.751 + }
1.752 + /* Error reporting */
1.753 + if (!nssym)
1.754 + {
1.755 + if (!savedErrorStr || !strlen(savedErrorStr))
1.756 + {
1.757 + if (savedErrorStr)
1.758 + free((char*)savedErrorStr);
1.759 + savedErrorStr = malloc(256);
1.760 + snprintf((char*)savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
1.761 + }
1.762 + if (canSetError)
1.763 + {
1.764 + error(savedErrorStr);
1.765 + }
1.766 + else
1.767 + {
1.768 + debug(savedErrorStr);
1.769 + }
1.770 + if (savedErrorStr)
1.771 + free((char*)savedErrorStr);
1.772 + return NULL;
1.773 + }
1.774 + return NSAddressOfSymbol(nssym);
1.775 +}
1.776 +
1.777 +static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
1.778 +{
1.779 + NSObjectFileImage ofi = 0;
1.780 + NSObjectFileImageReturnCode ofirc;
1.781 + struct dlstatus *dls;
1.782 + NSLinkEditErrors ler;
1.783 + int lerno;
1.784 + const char *errstr;
1.785 + const char *file;
1.786 + void (*init) (void);
1.787 + ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
1.788 + switch (ofirc)
1.789 + {
1.790 + case NSObjectFileImageSuccess:
1.791 + break;
1.792 + case NSObjectFileImageInappropriateFile:
1.793 + if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
1.794 + {
1.795 + if (isFlagSet(mode, RTLD_LOCAL))
1.796 + {
1.797 + warning("trying to open a .dylib with RTLD_LOCAL");
1.798 + error("unable to open this file with RTLD_LOCAL");
1.799 + return NULL;
1.800 + }
1.801 + }
1.802 + else
1.803 + {
1.804 + error("opening this file is unsupported on this system");
1.805 + return NULL;
1.806 + }
1.807 + break;
1.808 + case NSObjectFileImageFailure:
1.809 + error("object file setup failure");
1.810 + return NULL;
1.811 + case NSObjectFileImageArch:
1.812 + error("no object for this architecture");
1.813 + return NULL;
1.814 + case NSObjectFileImageFormat:
1.815 + error("bad object file format");
1.816 + return NULL;
1.817 + case NSObjectFileImageAccess:
1.818 + error("can't read object file");
1.819 + return NULL;
1.820 + default:
1.821 + error("unknown error from NSCreateObjectFileImageFromFile()");
1.822 + return NULL;
1.823 + }
1.824 + dls = lookupStatus(sbuf);
1.825 + if (!dls)
1.826 + {
1.827 + dls = allocStatus();
1.828 + }
1.829 + if (!dls)
1.830 + {
1.831 + error("unable to allocate memory");
1.832 + return NULL;
1.833 + }
1.834 + // dls->lib = 0;
1.835 + if (ofirc == NSObjectFileImageInappropriateFile)
1.836 + {
1.837 + if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
1.838 + {
1.839 + debug("Dynamic lib loaded at %ld", dls->lib);
1.840 + ofi = MAGIC_DYLIB_OFI;
1.841 + dls->module = MAGIC_DYLIB_MOD;
1.842 + ofirc = NSObjectFileImageSuccess;
1.843 + /* Although it is possible with a bit of work to modify this so it works and
1.844 + functions with RTLD_NOW, I don't deem it necessary at the moment */
1.845 + }
1.846 + if (!(dls->module))
1.847 + {
1.848 + NSLinkEditError(&ler, &lerno, &file, &errstr);
1.849 + if (!errstr || (!strlen(errstr)))
1.850 + error("Can't open this file type");
1.851 + else
1.852 + error(errstr);
1.853 + if ((dls->flags & DL_IN_LIST) == 0)
1.854 + {
1.855 + free(dls);
1.856 + }
1.857 + return NULL;
1.858 + }
1.859 + }
1.860 + else
1.861 + {
1.862 + dls->module = NSLinkModule(ofi, path,
1.863 + NSLINKMODULE_OPTION_RETURN_ON_ERROR |
1.864 + NSLINKMODULE_OPTION_PRIVATE |
1.865 + (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
1.866 + NSDestroyObjectFileImage(ofi);
1.867 + if (dls->module)
1.868 + {
1.869 + dls->lib = get_mach_header_from_NSModule(dls->module);
1.870 + }
1.871 + }
1.872 + if (!dls->module)
1.873 + {
1.874 + NSLinkEditError(&ler, &lerno, &file, &errstr);
1.875 + if ((dls->flags & DL_IN_LIST) == 0)
1.876 + {
1.877 + free(dls);
1.878 + }
1.879 + error(errstr);
1.880 + return NULL;
1.881 + }
1.882 +
1.883 + insertStatus(dls, sbuf);
1.884 + dls = reference(dls, mode);
1.885 + if ((init = dlsymIntern(dls, "__init", 0)))
1.886 + {
1.887 + debug("calling _init()");
1.888 + init();
1.889 + }
1.890 + return dls;
1.891 +}
1.892 +
1.893 +inline static void dlcompat_init_check(void)
1.894 +{
1.895 + static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
1.896 + static int init_done = 0;
1.897 +
1.898 + pthread_mutex_lock(&l);
1.899 + if (!init_done) {
1.900 + dlcompat_init_func();
1.901 + init_done = 1;
1.902 + }
1.903 + pthread_mutex_unlock(&l);
1.904 +}
1.905 +
1.906 +static void dlcompat_init_func(void)
1.907 +{
1.908 + _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage);
1.909 + _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
1.910 + (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage);
1.911 + _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage);
1.912 + if (pthread_mutex_init(&dlcompat_mutex, NULL))
1.913 + exit(1);
1.914 + if (pthread_key_create(&dlerror_key, &dlerrorfree))
1.915 + exit(1);
1.916 +}
1.917 +
1.918 +static void resetdlerror()
1.919 +{
1.920 + struct dlthread *tss;
1.921 + tss = pthread_getspecific(dlerror_key);
1.922 + tss->errset = 0;
1.923 +}
1.924 +
1.925 +static void dlerrorfree(void *data)
1.926 +{
1.927 + free(data);
1.928 +}
1.929 +
1.930 +/* We kind of want a recursive lock here, but meet a little trouble
1.931 + * because they are not available pre OS X 10.2, so we fake it
1.932 + * using thread specific storage to keep a lock count
1.933 + */
1.934 +static inline void dolock(void)
1.935 +{
1.936 + int err = 0;
1.937 + struct dlthread *tss;
1.938 + dlcompat_init_check();
1.939 + tss = pthread_getspecific(dlerror_key);
1.940 + if (!tss)
1.941 + {
1.942 + tss = malloc(sizeof(struct dlthread));
1.943 + tss->lockcnt = 0;
1.944 + tss->errset = 0;
1.945 + if (pthread_setspecific(dlerror_key, tss))
1.946 + {
1.947 + fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
1.948 + exit(1);
1.949 + }
1.950 + }
1.951 + if (!tss->lockcnt)
1.952 + err = pthread_mutex_lock(&dlcompat_mutex);
1.953 + tss->lockcnt = tss->lockcnt +1;
1.954 + if (err)
1.955 + exit(err);
1.956 +}
1.957 +
1.958 +static inline void dounlock(void)
1.959 +{
1.960 + int err = 0;
1.961 + struct dlthread *tss;
1.962 + tss = pthread_getspecific(dlerror_key);
1.963 + tss->lockcnt = tss->lockcnt -1;
1.964 + if (!tss->lockcnt)
1.965 + err = pthread_mutex_unlock(&dlcompat_mutex);
1.966 + if (err)
1.967 + exit(err);
1.968 +}
1.969 +
1.970 +static void *SDL_OSX_dlopen(const char *path, int mode)
1.971 +{
1.972 + const struct stat *sbuf;
1.973 + struct dlstatus *dls;
1.974 + const char *fullPath;
1.975 +
1.976 + dolock();
1.977 + resetdlerror();
1.978 + if (!path)
1.979 + {
1.980 + dls = &mainStatus;
1.981 + goto dlopenok;
1.982 + }
1.983 + if (!(sbuf = findFile(path, &fullPath)))
1.984 + {
1.985 + error("file \"%s\" not found", path);
1.986 + goto dlopenerror;
1.987 + }
1.988 + /* Now checks that it hasn't been closed already */
1.989 + if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
1.990 + {
1.991 + /* debug("status found"); */
1.992 + dls = reference(dls, mode);
1.993 + goto dlopenok;
1.994 + }
1.995 +#ifdef RTLD_NOLOAD
1.996 + if (isFlagSet(mode, RTLD_NOLOAD))
1.997 + {
1.998 + error("no existing handle and RTLD_NOLOAD specified");
1.999 + goto dlopenerror;
1.1000 + }
1.1001 +#endif
1.1002 + if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
1.1003 + {
1.1004 + error("how can I load something both RTLD_LAZY and RTLD_NOW?");
1.1005 + goto dlopenerror;
1.1006 + }
1.1007 + dls = loadModule(fullPath, sbuf, mode);
1.1008 +
1.1009 + dlopenok:
1.1010 + dounlock();
1.1011 + return (void *)dls;
1.1012 + dlopenerror:
1.1013 + dounlock();
1.1014 + return NULL;
1.1015 +}
1.1016 +
1.1017 +#if !FINK_BUILD
1.1018 +static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
1.1019 +{
1.1020 + int sym_len = strlen(symbol);
1.1021 + void *value = NULL;
1.1022 + char *malloc_sym = NULL;
1.1023 + dolock();
1.1024 + malloc_sym = malloc(sym_len + 2);
1.1025 + if (malloc_sym)
1.1026 + {
1.1027 + sprintf(malloc_sym, "_%s", symbol);
1.1028 + value = dlsymIntern(handle, malloc_sym, 1);
1.1029 + free(malloc_sym);
1.1030 + }
1.1031 + else
1.1032 + {
1.1033 + error("Unable to allocate memory");
1.1034 + goto dlsymerror;
1.1035 + }
1.1036 + dounlock();
1.1037 + return value;
1.1038 + dlsymerror:
1.1039 + dounlock();
1.1040 + return NULL;
1.1041 +}
1.1042 +#endif
1.1043 +
1.1044 +#if FINK_BUILD
1.1045 +
1.1046 +static void *dlsym_prepend_underscore(void *handle, const char *symbol)
1.1047 +{
1.1048 + void *answer;
1.1049 + dolock();
1.1050 + answer = dlsym_prepend_underscore_intern(handle, symbol);
1.1051 + dounlock();
1.1052 + return answer;
1.1053 +}
1.1054 +
1.1055 +static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
1.1056 +{
1.1057 +/*
1.1058 + * A quick and easy way for porting packages which call dlsym(handle,"sym")
1.1059 + * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
1.1060 + * this function will be called, and will add the required underscore.
1.1061 + *
1.1062 + * Note that I haven't figured out yet which should be "standard", prepend
1.1063 + * the underscore always, or not at all. These global functions need to go away
1.1064 + * for opendarwin.
1.1065 + */
1.1066 + int sym_len = strlen(symbol);
1.1067 + void *value = NULL;
1.1068 + char *malloc_sym = NULL;
1.1069 + malloc_sym = malloc(sym_len + 2);
1.1070 + if (malloc_sym)
1.1071 + {
1.1072 + sprintf(malloc_sym, "_%s", symbol);
1.1073 + value = dlsymIntern(handle, malloc_sym, 1);
1.1074 + free(malloc_sym);
1.1075 + }
1.1076 + else
1.1077 + {
1.1078 + error("Unable to allocate memory");
1.1079 + }
1.1080 + return value;
1.1081 +}
1.1082 +
1.1083 +static void *dlsym_auto_underscore(void *handle, const char *symbol)
1.1084 +{
1.1085 + void *answer;
1.1086 + dolock();
1.1087 + answer = dlsym_auto_underscore_intern(handle, symbol);
1.1088 + dounlock();
1.1089 + return answer;
1.1090 +
1.1091 +}
1.1092 +static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
1.1093 +{
1.1094 + struct dlstatus *dls = handle;
1.1095 + void *addr = 0;
1.1096 + addr = dlsymIntern(dls, symbol, 0);
1.1097 + if (!addr)
1.1098 + addr = dlsym_prepend_underscore_intern(handle, symbol);
1.1099 + return addr;
1.1100 +}
1.1101 +
1.1102 +
1.1103 +static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
1.1104 +{
1.1105 + struct dlstatus *dls = handle;
1.1106 + void *addr = 0;
1.1107 + dolock();
1.1108 + addr = dlsymIntern(dls, symbol, 1);
1.1109 + dounlock();
1.1110 + return addr;
1.1111 +}
1.1112 +#endif
1.1113 +
1.1114 +static int SDL_OSX_dlclose(void *handle)
1.1115 +{
1.1116 + struct dlstatus *dls = handle;
1.1117 + dolock();
1.1118 + resetdlerror();
1.1119 + if (!isValidStatus(dls))
1.1120 + {
1.1121 + goto dlcloseerror;
1.1122 + }
1.1123 + if (dls->module == MAGIC_DYLIB_MOD)
1.1124 + {
1.1125 + const char *name;
1.1126 + if (!dls->lib)
1.1127 + {
1.1128 + name = "global context";
1.1129 + }
1.1130 + else
1.1131 + {
1.1132 + name = get_lib_name(dls->lib);
1.1133 + }
1.1134 + warning("trying to close a .dylib!");
1.1135 + error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
1.1136 + goto dlcloseerror;
1.1137 + }
1.1138 + if (!dls->module)
1.1139 + {
1.1140 + error("module already closed");
1.1141 + goto dlcloseerror;
1.1142 + }
1.1143 +
1.1144 + if (dls->refs == 1)
1.1145 + {
1.1146 + unsigned long options = 0;
1.1147 + void (*fini) (void);
1.1148 + if ((fini = dlsymIntern(dls, "__fini", 0)))
1.1149 + {
1.1150 + debug("calling _fini()");
1.1151 + fini();
1.1152 + }
1.1153 + options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
1.1154 +#ifdef RTLD_NODELETE
1.1155 + if (isFlagSet(dls->mode, RTLD_NODELETE))
1.1156 + options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
1.1157 +#endif
1.1158 + if (!NSUnLinkModule(dls->module, options))
1.1159 + {
1.1160 + error("unable to unlink module");
1.1161 + goto dlcloseerror;
1.1162 + }
1.1163 + dls->refs--;
1.1164 + dls->module = 0;
1.1165 + /* Note: the dlstatus struct dls is neither removed from the list
1.1166 + * nor is the memory it occupies freed. This shouldn't pose a
1.1167 + * problem in mostly all cases, though.
1.1168 + */
1.1169 + }
1.1170 + dounlock();
1.1171 + return 0;
1.1172 + dlcloseerror:
1.1173 + dounlock();
1.1174 + return 1;
1.1175 +}
1.1176 +
1.1177 +static char *SDL_OSX_dlerror(void)
1.1178 +{
1.1179 + struct dlthread *tss;
1.1180 + const char * err_str = NULL;
1.1181 + dlcompat_init_check();
1.1182 + tss = pthread_getspecific(dlerror_key);
1.1183 + if (tss != NULL && tss->errset != 0) {
1.1184 + tss->errset = 0;
1.1185 + err_str = tss->errstr;
1.1186 + }
1.1187 + return (err_str);
1.1188 +}
1.1189 +
1.1190 +/* Given an address, return the mach_header for the image containing it
1.1191 + * or zero if the given address is not contained in any loaded images.
1.1192 + */
1.1193 +static const struct mach_header *image_for_address(const void *address)
1.1194 +{
1.1195 + unsigned long i;
1.1196 + unsigned long j;
1.1197 + unsigned long count = _dyld_image_count();
1.1198 + struct mach_header *mh = 0;
1.1199 + struct load_command *lc = 0;
1.1200 + unsigned long addr = NULL;
1.1201 + for (i = 0; i < count; i++)
1.1202 + {
1.1203 + addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
1.1204 + mh = _dyld_get_image_header(i);
1.1205 + if (mh)
1.1206 + {
1.1207 + lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1.1208 + for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1.1209 + {
1.1210 + if (LC_SEGMENT == lc->cmd &&
1.1211 + addr >= ((struct segment_command *)lc)->vmaddr &&
1.1212 + addr <
1.1213 + ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
1.1214 + {
1.1215 + goto image_found;
1.1216 + }
1.1217 + }
1.1218 + }
1.1219 + mh = 0;
1.1220 + }
1.1221 + image_found:
1.1222 + return mh;
1.1223 +}
1.1224 +
1.1225 +static int SDL_OSX_dladdr(const void * dl_restrict p, SDL_OSX_Dl_info * dl_restrict info)
1.1226 +{
1.1227 +/*
1.1228 + FIXME: USe the routine image_for_address.
1.1229 +*/
1.1230 + unsigned long i;
1.1231 + unsigned long j;
1.1232 + unsigned long count = _dyld_image_count();
1.1233 + struct mach_header *mh = 0;
1.1234 + struct load_command *lc = 0;
1.1235 + unsigned long addr = NULL;
1.1236 + unsigned long table_off = (unsigned long)0;
1.1237 + int found = 0;
1.1238 + if (!info)
1.1239 + return 0;
1.1240 + dolock();
1.1241 + resetdlerror();
1.1242 + info->dli_fname = 0;
1.1243 + info->dli_fbase = 0;
1.1244 + info->dli_sname = 0;
1.1245 + info->dli_saddr = 0;
1.1246 +/* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
1.1247 + * to darwin-development AT lists DOT apple DOT com and slightly modified
1.1248 + */
1.1249 + for (i = 0; i < count; i++)
1.1250 + {
1.1251 + addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
1.1252 + mh = _dyld_get_image_header(i);
1.1253 + if (mh)
1.1254 + {
1.1255 + lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1.1256 + for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1.1257 + {
1.1258 + if (LC_SEGMENT == lc->cmd &&
1.1259 + addr >= ((struct segment_command *)lc)->vmaddr &&
1.1260 + addr <
1.1261 + ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
1.1262 + {
1.1263 + info->dli_fname = _dyld_get_image_name(i);
1.1264 + info->dli_fbase = (void *)mh;
1.1265 + found = 1;
1.1266 + break;
1.1267 + }
1.1268 + }
1.1269 + if (found)
1.1270 + break;
1.1271 + }
1.1272 + }
1.1273 + if (!found)
1.1274 + {
1.1275 + dounlock();
1.1276 + return 0;
1.1277 + }
1.1278 + lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1.1279 + for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1.1280 + {
1.1281 + if (LC_SEGMENT == lc->cmd)
1.1282 + {
1.1283 + if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
1.1284 + break;
1.1285 + }
1.1286 + }
1.1287 + table_off =
1.1288 + ((unsigned long)((struct segment_command *)lc)->vmaddr) -
1.1289 + ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i);
1.1290 + debug("table off %x", table_off);
1.1291 +
1.1292 + lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1.1293 + for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1.1294 + {
1.1295 + if (LC_SYMTAB == lc->cmd)
1.1296 + {
1.1297 +
1.1298 + struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off);
1.1299 + unsigned long numsyms = ((struct symtab_command *)lc)->nsyms;
1.1300 + struct nlist *nearest = NULL;
1.1301 + unsigned long diff = 0xffffffff;
1.1302 + unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off);
1.1303 + debug("symtable %x", symtable);
1.1304 + for (i = 0; i < numsyms; i++)
1.1305 + {
1.1306 + /* Ignore the following kinds of Symbols */
1.1307 + if ((!symtable->n_value) /* Undefined */
1.1308 + || (symtable->n_type >= N_PEXT) /* Debug symbol */
1.1309 + || (!(symtable->n_type & N_EXT)) /* Local Symbol */
1.1310 + )
1.1311 + {
1.1312 + symtable++;
1.1313 + continue;
1.1314 + }
1.1315 + if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
1.1316 + {
1.1317 + diff = (unsigned long)symtable->n_value - addr;
1.1318 + nearest = symtable;
1.1319 + }
1.1320 + symtable++;
1.1321 + }
1.1322 + if (nearest)
1.1323 + {
1.1324 + info->dli_saddr = nearest->n_value + ((void *)p - addr);
1.1325 + info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
1.1326 + }
1.1327 + }
1.1328 + }
1.1329 + dounlock();
1.1330 + return 1;
1.1331 +}
1.1332 +
1.1333 +
1.1334 +/*
1.1335 + * Implement the dlfunc() interface, which behaves exactly the same as
1.1336 + * dlsym() except that it returns a function pointer instead of a data
1.1337 + * pointer. This can be used by applications to avoid compiler warnings
1.1338 + * about undefined behavior, and is intended as prior art for future
1.1339 + * POSIX standardization. This function requires that all pointer types
1.1340 + * have the same representation, which is true on all platforms FreeBSD
1.1341 + * runs on, but is not guaranteed by the C standard.
1.1342 + */
1.1343 +#if 0
1.1344 +static dlfunc_t SDL_OSX_dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
1.1345 +{
1.1346 + union
1.1347 + {
1.1348 + void *d;
1.1349 + dlfunc_t f;
1.1350 + } rv;
1.1351 + int sym_len = strlen(symbol);
1.1352 + char *malloc_sym = NULL;
1.1353 + dolock();
1.1354 + malloc_sym = malloc(sym_len + 2);
1.1355 + if (malloc_sym)
1.1356 + {
1.1357 + sprintf(malloc_sym, "_%s", symbol);
1.1358 + rv.d = dlsymIntern(handle, malloc_sym, 1);
1.1359 + free(malloc_sym);
1.1360 + }
1.1361 + else
1.1362 + {
1.1363 + error("Unable to allocate memory");
1.1364 + goto dlfuncerror;
1.1365 + }
1.1366 + dounlock();
1.1367 + return rv.f;
1.1368 + dlfuncerror:
1.1369 + dounlock();
1.1370 + return NULL;
1.1371 +}
1.1372 +#endif
1.1373 +
1.1374 +
1.1375 +
1.1376 +/* dlcompat ends, here's the SDL interface... --ryan. */
1.1377 +
1.1378 +
1.1379 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1.1380 +/* System dependent library loading routines */
1.1381 +
1.1382 +#if !SDL_INTERNAL_BUILDING_LOADSO
1.1383 +#error Do not compile directly...compile src/SDL_loadso.c instead!
1.1384 +#endif
1.1385 +
1.1386 +#if !defined(MACOSX)
1.1387 +#error Compiling for the wrong platform?
1.1388 +#elif defined(USE_DLOPEN)
1.1389 +#error Do not use USE_DLOPEN on Mac OS X.
1.1390 +#endif
1.1391 +
1.1392 +#include "SDL_types.h"
1.1393 +#include "SDL_error.h"
1.1394 +#include "SDL_loadso.h"
1.1395 +
1.1396 +void *SDL_LoadObject(const char *sofile)
1.1397 +{
1.1398 + void *handle = SDL_OSX_dlopen(sofile, RTLD_NOW);
1.1399 + const char *loaderror = (char *)SDL_OSX_dlerror();
1.1400 + if ( handle == NULL ) {
1.1401 + SDL_SetError("Failed loading %s: %s", sofile, loaderror);
1.1402 + }
1.1403 + return(handle);
1.1404 +}
1.1405 +
1.1406 +void *SDL_LoadFunction(void *handle, const char *name)
1.1407 +{
1.1408 + void *symbol = SDL_OSX_dlsym(handle, name);
1.1409 + if ( symbol == NULL ) {
1.1410 + SDL_SetError("Failed loading %s: %s", name, (const char *)SDL_OSX_dlerror());
1.1411 + }
1.1412 + return(symbol);
1.1413 +}
1.1414 +
1.1415 +void SDL_UnloadObject(void *handle)
1.1416 +{
1.1417 + if ( handle != NULL ) {
1.1418 + SDL_OSX_dlclose(handle);
1.1419 + }
1.1420 +}
1.1421 +
1.1422 +