Xcode has trouble compiling different files with the same name for two architectures
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/loadso/macosx/SDL_dlcompat.c Wed May 10 06:12:45 2006 +0000
1.3 @@ -0,0 +1,1407 @@
1.4 +/*
1.5 + SDL - Simple DirectMedia Layer
1.6 + Copyright (C) 1997-2006 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 Lesser General Public
1.10 + License as published by the Free Software Foundation; either
1.11 + version 2.1 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 + Lesser General Public License for more details.
1.17 +
1.18 + You should have received a copy of the GNU Lesser General Public
1.19 + License along with this library; if not, write to the Free Software
1.20 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1.21 +
1.22 + Sam Lantinga
1.23 + slouken@libsdl.org
1.24 +*/
1.25 +#include "SDL_config.h"
1.26 +
1.27 +#ifdef SDL_LOADSO_DLCOMPAT
1.28 +
1.29 +/* Please note that dlcompat apparently ships in current Mac OS X versions
1.30 + * as a system library that provides compatibility with the Unix "dlopen"
1.31 + * interface. In order to allow SDL to work on older OS X releases and also
1.32 + * not conflict with the system lib on newer versions, we include dlcompat
1.33 + * in SDL and change the symbols to prevent symbol clash with any existing
1.34 + * system libraries. --ryan.
1.35 + */
1.36 +
1.37 +/* here is the dlcompat license: */
1.38 +
1.39 +/*
1.40 +Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> &
1.41 + Peter O'Gorman <ogorman@users.sourceforge.net>
1.42 +
1.43 +Portions may be copyright others, see the AUTHORS file included with this
1.44 +distribution.
1.45 +
1.46 +Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
1.47 +
1.48 +Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
1.49 +
1.50 +Permission is hereby granted, free of charge, to any person obtaining
1.51 +a copy of this software and associated documentation files (the
1.52 +"Software"), to deal in the Software without restriction, including
1.53 +without limitation the rights to use, copy, modify, merge, publish,
1.54 +distribute, sublicense, and/or sell copies of the Software, and to
1.55 +permit persons to whom the Software is furnished to do so, subject to
1.56 +the following conditions:
1.57 +
1.58 +The above copyright notice and this permission notice shall be
1.59 +included in all copies or substantial portions of the Software.
1.60 +
1.61 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1.62 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1.63 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1.64 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1.65 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1.66 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1.67 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1.68 +*/
1.69 +
1.70 +#include <pthread.h>
1.71 +#include <sys/types.h>
1.72 +#include <sys/stat.h>
1.73 +#include <stdarg.h>
1.74 +#include <limits.h>
1.75 +#include <mach-o/dyld.h>
1.76 +#include <mach-o/nlist.h>
1.77 +#include <mach-o/getsect.h>
1.78 +
1.79 +#include "SDL_stdinc.h"
1.80 +
1.81 +/* Just playing to see if it would compile with the freebsd headers, it does,
1.82 + * but because of the different values for RTLD_LOCAL etc, it would break binary
1.83 + * compat... oh well
1.84 + */
1.85 +#ifndef __BSD_VISIBLE
1.86 +#define __BSD_VISIBLE 1
1.87 +#endif
1.88 +
1.89 +/*include "dlfcn.h"*/
1.90 +#ifdef __cplusplus
1.91 +extern "C" {
1.92 +#endif
1.93 +
1.94 +#if defined (__GNUC__) && __GNUC__ > 3
1.95 +#define dl_restrict __restrict
1.96 +#else
1.97 +#define dl_restrict
1.98 +#endif
1.99 +
1.100 +#if 0
1.101 +#ifndef _POSIX_SOURCE
1.102 +/*
1.103 + * Structure filled in by dladdr().
1.104 + */
1.105 +typedef struct SDL_OSX_dl_info {
1.106 + const char *dli_fname; /* Pathname of shared object */
1.107 + void *dli_fbase; /* Base address of shared object */
1.108 + const char *dli_sname; /* Name of nearest symbol */
1.109 + void *dli_saddr; /* Address of nearest symbol */
1.110 +} SDL_OSX_Dl_info;
1.111 +
1.112 +static int SDL_OSX_dladdr(const void * dl_restrict, SDL_OSX_Dl_info * dl_restrict);
1.113 +#endif /* ! _POSIX_SOURCE */
1.114 +#endif /* 0 */
1.115 +
1.116 +static int SDL_OSX_dlclose(void * handle);
1.117 +static const char * SDL_OSX_dlerror(void);
1.118 +static void * SDL_OSX_dlopen(const char *path, int mode);
1.119 +static void * SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol);
1.120 +
1.121 +#define RTLD_LAZY 0x1
1.122 +#define RTLD_NOW 0x2
1.123 +#define RTLD_LOCAL 0x4
1.124 +#define RTLD_GLOBAL 0x8
1.125 +
1.126 +#ifndef _POSIX_SOURCE
1.127 +#define RTLD_NOLOAD 0x10
1.128 +#define RTLD_NODELETE 0x80
1.129 +
1.130 +/*
1.131 + * Special handle arguments for SDL_OSX_dlsym().
1.132 + */
1.133 +#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
1.134 +#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
1.135 +#endif /* ! _POSIX_SOURCE */
1.136 +
1.137 +#ifdef __cplusplus
1.138 +}
1.139 +#endif
1.140 +
1.141 +#ifndef dl_restrict
1.142 +#define dl_restrict __restrict
1.143 +#endif
1.144 +/* This is not available on 10.1 */
1.145 +#ifndef LC_LOAD_WEAK_DYLIB
1.146 +#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
1.147 +#endif
1.148 +
1.149 +/* With this stuff here, this thing may actually compile/run on 10.0 systems
1.150 + * Not that I have a 10.0 system to test it on anylonger
1.151 + */
1.152 +#ifndef LC_REQ_DYLD
1.153 +#define LC_REQ_DYLD 0x80000000
1.154 +#endif
1.155 +#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
1.156 +#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
1.157 +#endif
1.158 +#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
1.159 +#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
1.160 +#endif
1.161 +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
1.162 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
1.163 +#endif
1.164 +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
1.165 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
1.166 +#endif
1.167 +/* These symbols will be looked for in dyld */
1.168 +static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
1.169 +static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
1.170 +static NSSymbol(*dyld_NSLookupSymbolInImage)
1.171 + (const struct mach_header *, const char *, unsigned long) = 0;
1.172 +
1.173 +/* Define this to make dlcompat reuse data block. This way in theory we save
1.174 + * a little bit of overhead. However we then couldn't correctly catch excess
1.175 + * calls to SDL_OSX_dlclose(). Hence we don't use this feature
1.176 + */
1.177 +#undef REUSE_STATUS
1.178 +
1.179 +/* Size of the internal error message buffer (used by dlerror()) */
1.180 +#define ERR_STR_LEN 251
1.181 +
1.182 +/* Maximum number of search paths supported by getSearchPath */
1.183 +#define MAX_SEARCH_PATHS 32
1.184 +
1.185 +
1.186 +#define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
1.187 +#define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
1.188 +
1.189 +/* internal flags */
1.190 +#define DL_IN_LIST 0x01
1.191 +
1.192 +/* our mutex */
1.193 +static pthread_mutex_t dlcompat_mutex;
1.194 +/* Our thread specific storage
1.195 + */
1.196 +static pthread_key_t dlerror_key;
1.197 +
1.198 +struct dlthread
1.199 +{
1.200 + int lockcnt;
1.201 + unsigned char errset;
1.202 + char errstr[ERR_STR_LEN];
1.203 +};
1.204 +
1.205 +/* This is our central data structure. Whenever a module is loaded via
1.206 + * SDL_OSX_dlopen(), we create such a struct.
1.207 + */
1.208 +struct dlstatus
1.209 +{
1.210 + struct dlstatus *next; /* pointer to next element in the linked list */
1.211 + NSModule module;
1.212 + const struct mach_header *lib;
1.213 + int refs; /* reference count */
1.214 + int mode; /* mode in which this module was loaded */
1.215 + dev_t device;
1.216 + ino_t inode;
1.217 + int flags; /* Any internal flags we may need */
1.218 +};
1.219 +
1.220 +/* Head node of the dlstatus list */
1.221 +static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
1.222 +static struct dlstatus *stqueue = &mainStatus;
1.223 +
1.224 +
1.225 +/* Storage for the last error message (used by dlerror()) */
1.226 +/* static char err_str[ERR_STR_LEN]; */
1.227 +/* static int err_filled = 0; */
1.228 +
1.229 +/* Prototypes to internal functions */
1.230 +static void debug(const char *fmt, ...);
1.231 +static void error(const char *str, ...);
1.232 +static const char *safegetenv(const char *s);
1.233 +static const char *searchList(void);
1.234 +static const char *getSearchPath(int i);
1.235 +static const char *getFullPath(int i, const char *file);
1.236 +static const struct stat *findFile(const char *file, const char **fullPath);
1.237 +static int isValidStatus(struct dlstatus *status);
1.238 +static inline int isFlagSet(int mode, int flag);
1.239 +static struct dlstatus *lookupStatus(const struct stat *sbuf);
1.240 +static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
1.241 +static int promoteLocalToGlobal(struct dlstatus *dls);
1.242 +static void *reference(struct dlstatus *dls, int mode);
1.243 +static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
1.244 +static struct dlstatus *allocStatus(void);
1.245 +static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
1.246 +static NSSymbol search_linked_libs(const struct mach_header *mh, const char *symbol);
1.247 +static const char *get_lib_name(const struct mach_header *mh);
1.248 +static const struct mach_header *get_mach_header_from_NSModule(NSModule mod);
1.249 +static void dlcompat_init_func(void);
1.250 +static inline void dlcompat_init_check(void);
1.251 +static inline void dolock(void);
1.252 +static inline void dounlock(void);
1.253 +static void dlerrorfree(void *data);
1.254 +static void resetdlerror(void);
1.255 +static const struct mach_header *my_find_image(const char *name);
1.256 +static const struct mach_header *image_for_address(const void *address);
1.257 +static inline char *dyld_error_str(void);
1.258 +
1.259 +#if FINK_BUILD
1.260 +/* Two Global Functions */
1.261 +static void *dlsym_prepend_underscore(void *handle, const char *symbol);
1.262 +static void *dlsym_auto_underscore(void *handle, const char *symbol);
1.263 +
1.264 +/* And their _intern counterparts */
1.265 +static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
1.266 +static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
1.267 +#endif
1.268 +
1.269 +/* Functions */
1.270 +
1.271 +static void debug(const char *fmt, ...)
1.272 +{
1.273 +#if DEBUG > 1
1.274 + va_list arg;
1.275 + va_start(arg, fmt);
1.276 + fprintf(stderr, "DLDEBUG: ");
1.277 + vfprintf(stderr, fmt, arg);
1.278 + fprintf(stderr, "\n");
1.279 + fflush(stderr);
1.280 + va_end(arg);
1.281 +#endif
1.282 +}
1.283 +
1.284 +static void error(const char *str, ...)
1.285 +{
1.286 + va_list arg;
1.287 + struct dlthread *tss;
1.288 + char * err_str;
1.289 + va_start(arg, str);
1.290 + tss = pthread_getspecific(dlerror_key);
1.291 + err_str = tss->errstr;
1.292 + SDL_strlcpy(err_str, "dlcompat: ", ERR_STR_LEN);
1.293 + vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
1.294 + va_end(arg);
1.295 + debug("ERROR: %s\n", err_str);
1.296 + tss->errset = 1;
1.297 +}
1.298 +
1.299 +static void warning(const char *str)
1.300 +{
1.301 +#if DEBUG > 0
1.302 + fprintf(stderr, "WARNING: dlcompat: %s\n", str);
1.303 +#endif
1.304 +}
1.305 +
1.306 +static const char *safegetenv(const char *s)
1.307 +{
1.308 + const char *ss = SDL_getenv(s);
1.309 + return ss ? ss : "";
1.310 +}
1.311 +
1.312 +/* because this is only used for debugging and error reporting functions, we
1.313 + * don't really care about how elegant it is... it could use the load
1.314 + * commands to find the install name of the library, but...
1.315 + */
1.316 +static const char *get_lib_name(const struct mach_header *mh)
1.317 +{
1.318 + unsigned long count = _dyld_image_count();
1.319 + unsigned long i;
1.320 + const char *val = NULL;
1.321 + if (mh)
1.322 + {
1.323 + for (i = 0; i < count; i++)
1.324 + {
1.325 + if (mh == _dyld_get_image_header(i))
1.326 + {
1.327 + val = _dyld_get_image_name(i);
1.328 + break;
1.329 + }
1.330 + }
1.331 + }
1.332 + return val;
1.333 +}
1.334 +
1.335 +/* Returns the mach_header for the module bu going through all the loaded images
1.336 + * and finding the one with the same name as the module. There really ought to be
1.337 + * an api for doing this, would be faster, but there isn't one right now
1.338 + */
1.339 +static const struct mach_header *get_mach_header_from_NSModule(NSModule mod)
1.340 +{
1.341 + const char *mod_name = NSNameOfModule(mod);
1.342 + const struct mach_header *mh = NULL;
1.343 + unsigned long count = _dyld_image_count();
1.344 + unsigned long i;
1.345 + debug("Module name: %s", mod_name);
1.346 + for (i = 0; i < count; i++)
1.347 + {
1.348 + if (!SDL_strcmp(mod_name, _dyld_get_image_name(i)))
1.349 + {
1.350 + mh = _dyld_get_image_header(i);
1.351 + break;
1.352 + }
1.353 + }
1.354 + return mh;
1.355 +}
1.356 +
1.357 +
1.358 +/* Compute and return a list of all directories that we should search when
1.359 + * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
1.360 + * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
1.361 + * /usr/lib and /lib. Since both of the environments variables can contain a
1.362 + * list of colon seperated paths, we simply concat them and the two other paths
1.363 + * into one big string, which we then can easily parse.
1.364 + * Splitting this string into the actual path list is done by getSearchPath()
1.365 + */
1.366 +static const char *searchList()
1.367 +{
1.368 + size_t buf_size;
1.369 + static char *buf=NULL;
1.370 + const char *ldlp = safegetenv("LD_LIBRARY_PATH");
1.371 + const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
1.372 + const char *stdpath = SDL_getenv("DYLD_FALLBACK_LIBRARY_PATH");
1.373 + if (!stdpath)
1.374 + stdpath = "/usr/local/lib:/lib:/usr/lib";
1.375 + if (!buf)
1.376 + {
1.377 + buf_size = SDL_strlen(ldlp) + SDL_strlen(dyldlp) + SDL_strlen(stdpath) + 4;
1.378 + buf = SDL_malloc(buf_size);
1.379 + SDL_snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
1.380 + stdpath, '\0');
1.381 + }
1.382 + return buf;
1.383 +}
1.384 +
1.385 +/* Returns the ith search path from the list as computed by searchList() */
1.386 +static const char *getSearchPath(int i)
1.387 +{
1.388 + static const char *list = 0;
1.389 + static char **path = (char **)0;
1.390 + static int end = 0;
1.391 + static int numsize = MAX_SEARCH_PATHS;
1.392 + static char **tmp;
1.393 + /* So we can call SDL_free() in the "destructor" we use i=-1 to return the alloc'd array */
1.394 + if (i == -1)
1.395 + {
1.396 + return (const char*)path;
1.397 + }
1.398 + if (!path)
1.399 + {
1.400 + path = (char **)SDL_calloc(MAX_SEARCH_PATHS, sizeof(char **));
1.401 + }
1.402 + if (!list && !end)
1.403 + list = searchList();
1.404 + if (i >= (numsize))
1.405 + {
1.406 + debug("Increasing size for long PATH");
1.407 + tmp = (char **)SDL_calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
1.408 + if (tmp)
1.409 + {
1.410 + SDL_memcpy(tmp, path, sizeof(char **) * numsize);
1.411 + SDL_free(path);
1.412 + path = tmp;
1.413 + numsize += MAX_SEARCH_PATHS;
1.414 + }
1.415 + else
1.416 + {
1.417 + return 0;
1.418 + }
1.419 + }
1.420 +
1.421 + while (!path[i] && !end)
1.422 + {
1.423 + path[i] = strsep((char **)&list, ":");
1.424 +
1.425 + if (path[i][0] == 0)
1.426 + path[i] = 0;
1.427 + end = (list == 0);
1.428 + }
1.429 + return path[i];
1.430 +}
1.431 +
1.432 +static const char *getFullPath(int i, const char *file)
1.433 +{
1.434 + static char buf[PATH_MAX];
1.435 + const char *path = getSearchPath(i);
1.436 + if (path)
1.437 + {
1.438 + SDL_snprintf(buf, PATH_MAX, "%s/%s", path, file);
1.439 + }
1.440 + return path ? buf : 0;
1.441 +}
1.442 +
1.443 +/* Given a file name, try to determine the full path for that file. Starts
1.444 + * its search in the current directory, and then tries all paths in the
1.445 + * search list in the order they are specified there.
1.446 + */
1.447 +static const struct stat *findFile(const char *file, const char **fullPath)
1.448 +{
1.449 + int i = 0;
1.450 + static struct stat sbuf;
1.451 + char *fileName;
1.452 + debug("finding file %s", file);
1.453 + *fullPath = file;
1.454 + if (0 == stat(file, &sbuf))
1.455 + return &sbuf;
1.456 + if (SDL_strchr(file, '/'))
1.457 + return 0; /* If the path had a / we don't look in env var places */
1.458 + fileName = NULL;
1.459 + if (!fileName)
1.460 + fileName = (char *)file;
1.461 + while ((*fullPath = getFullPath(i++, fileName)))
1.462 + {
1.463 + if (0 == stat(*fullPath, &sbuf))
1.464 + return &sbuf;
1.465 + }
1.466 + ;
1.467 + return 0;
1.468 +}
1.469 +
1.470 +/* Determine whether a given dlstatus is valid or not */
1.471 +static int isValidStatus(struct dlstatus *status)
1.472 +{
1.473 + /* Walk the list to verify status is contained in it */
1.474 + struct dlstatus *dls = stqueue;
1.475 + while (dls && status != dls)
1.476 + dls = dls->next;
1.477 + if (dls == 0)
1.478 + error("invalid handle");
1.479 + else if ((dls->module == 0) || (dls->refs == 0))
1.480 + error("handle to closed library");
1.481 + else
1.482 + return TRUE;
1.483 + return FALSE;
1.484 +}
1.485 +
1.486 +static inline int isFlagSet(int mode, int flag)
1.487 +{
1.488 + return (mode & flag) == flag;
1.489 +}
1.490 +
1.491 +static struct dlstatus *lookupStatus(const struct stat *sbuf)
1.492 +{
1.493 + struct dlstatus *dls = stqueue;
1.494 + debug("looking for status");
1.495 + while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
1.496 + || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
1.497 + dls = dls->next;
1.498 + return dls;
1.499 +}
1.500 +
1.501 +static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
1.502 +{
1.503 + debug("inserting status");
1.504 + dls->inode = sbuf->st_ino;
1.505 + dls->device = sbuf->st_dev;
1.506 + dls->refs = 0;
1.507 + dls->mode = 0;
1.508 + if ((dls->flags & DL_IN_LIST) == 0)
1.509 + {
1.510 + dls->next = stqueue;
1.511 + stqueue = dls;
1.512 + dls->flags |= DL_IN_LIST;
1.513 + }
1.514 +}
1.515 +
1.516 +static struct dlstatus *allocStatus()
1.517 +{
1.518 + struct dlstatus *dls;
1.519 +#ifdef REUSE_STATUS
1.520 + dls = stqueue;
1.521 + while (dls && dls->module)
1.522 + dls = dls->next;
1.523 + if (!dls)
1.524 +#endif
1.525 + dls = SDL_calloc(sizeof(*dls),1);
1.526 + return dls;
1.527 +}
1.528 +
1.529 +static int promoteLocalToGlobal(struct dlstatus *dls)
1.530 +{
1.531 + static int (*p) (NSModule module) = 0;
1.532 + debug("promoting");
1.533 + if (!p)
1.534 + _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (void **)&p);
1.535 + return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
1.536 +}
1.537 +
1.538 +static void *reference(struct dlstatus *dls, int mode)
1.539 +{
1.540 + if (dls)
1.541 + {
1.542 + if (dls->module == MAGIC_DYLIB_MOD && isFlagSet(mode, RTLD_LOCAL))
1.543 + {
1.544 + warning("trying to open a .dylib with RTLD_LOCAL");
1.545 + error("unable to open a .dylib with RTLD_LOCAL");
1.546 + return NULL;
1.547 + }
1.548 + if (isFlagSet(mode, RTLD_GLOBAL) &&
1.549 + !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
1.550 + {
1.551 + error("unable to promote local module to global");
1.552 + return NULL;
1.553 + }
1.554 + dls->mode |= mode;
1.555 + dls->refs++;
1.556 + }
1.557 + else
1.558 + debug("reference called with NULL argument");
1.559 +
1.560 + return dls;
1.561 +}
1.562 +
1.563 +static const struct mach_header *my_find_image(const char *name)
1.564 +{
1.565 + const struct mach_header *mh = 0;
1.566 + const char *id = NULL;
1.567 + int i = _dyld_image_count();
1.568 + int j;
1.569 + mh = (struct mach_header *)
1.570 + dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
1.571 + NSADDIMAGE_OPTION_RETURN_ON_ERROR);
1.572 + if (!mh)
1.573 + {
1.574 + for (j = 0; j < i; j++)
1.575 + {
1.576 + id = _dyld_get_image_name(j);
1.577 + if (!SDL_strcmp(id, name))
1.578 + {
1.579 + mh = _dyld_get_image_header(j);
1.580 + break;
1.581 + }
1.582 + }
1.583 + }
1.584 + return mh;
1.585 +}
1.586 +
1.587 +/*
1.588 + * dyld adds libraries by first adding the directly dependant libraries in link order, and
1.589 + * then adding the dependencies for those libraries, so we should do the same... but we don't
1.590 + * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
1.591 + * any of it's direct dependencies, then it probably isn't there.
1.592 + */
1.593 +static NSSymbol search_linked_libs(const struct mach_header * mh, const char *symbol)
1.594 +{
1.595 + unsigned int n;
1.596 + struct load_command *lc = 0;
1.597 + struct mach_header *wh;
1.598 + NSSymbol nssym = 0;
1.599 + if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
1.600 + {
1.601 + lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1.602 + for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1.603 + {
1.604 + if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
1.605 + {
1.606 + if ((wh = (struct mach_header *)
1.607 + my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
1.608 + (char *)lc))))
1.609 + {
1.610 + if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
1.611 + {
1.612 + nssym = dyld_NSLookupSymbolInImage(wh,
1.613 + symbol,
1.614 + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
1.615 + NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
1.616 + break;
1.617 + }
1.618 + }
1.619 + }
1.620 + }
1.621 + if ((!nssym) && NSIsSymbolNameDefined(symbol))
1.622 + {
1.623 + /* I've never seen this debug message...*/
1.624 + debug("Symbol \"%s\" is defined but was not found", symbol);
1.625 + }
1.626 + }
1.627 + return nssym;
1.628 +}
1.629 +
1.630 +/* Up to the caller to SDL_free() returned string */
1.631 +static inline char *dyld_error_str()
1.632 +{
1.633 + NSLinkEditErrors dylder;
1.634 + int dylderno;
1.635 + const char *dylderrstr;
1.636 + const char *dyldfile;
1.637 + char* retStr = NULL;
1.638 + NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
1.639 + if (dylderrstr && *dylderrstr)
1.640 + {
1.641 + retStr = SDL_strdup(dylderrstr);
1.642 + }
1.643 + return retStr;
1.644 +}
1.645 +
1.646 +static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
1.647 +{
1.648 + NSSymbol nssym = 0;
1.649 +#ifdef __GCC__
1.650 + void *caller = __builtin_return_address(1); /* Be *very* careful about inlining */
1.651 +#else
1.652 + void *caller = NULL;
1.653 +#endif
1.654 + const struct mach_header *caller_mh = 0;
1.655 + char *savedErrorStr = NULL;
1.656 + resetdlerror();
1.657 +#ifndef RTLD_SELF
1.658 +#define RTLD_SELF ((void *) -3)
1.659 +#endif
1.660 + if (NULL == dls)
1.661 + dls = RTLD_SELF;
1.662 + if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
1.663 + {
1.664 + if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage && caller)
1.665 + {
1.666 + caller_mh = image_for_address(caller);
1.667 + if (RTLD_SELF == dls)
1.668 + {
1.669 + /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
1.670 + * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
1.671 + * this is acceptable.
1.672 + */
1.673 + if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
1.674 + {
1.675 + nssym = dyld_NSLookupSymbolInImage(caller_mh,
1.676 + symbol,
1.677 + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
1.678 + NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
1.679 + }
1.680 + }
1.681 + if (!nssym)
1.682 + {
1.683 + if (RTLD_SELF == dls)
1.684 + savedErrorStr = dyld_error_str();
1.685 + nssym = search_linked_libs(caller_mh, symbol);
1.686 + }
1.687 + }
1.688 + else
1.689 + {
1.690 + if (canSetError)
1.691 + error("RTLD_SELF and RTLD_NEXT are not supported");
1.692 + return NULL;
1.693 + }
1.694 + }
1.695 + if (!nssym)
1.696 + {
1.697 +
1.698 + if (RTLD_DEFAULT == dls)
1.699 + {
1.700 + dls = &mainStatus;
1.701 + }
1.702 + if (!isValidStatus(dls))
1.703 + return NULL;
1.704 +
1.705 + if (dls->module != MAGIC_DYLIB_MOD)
1.706 + {
1.707 + nssym = NSLookupSymbolInModule(dls->module, symbol);
1.708 + if (!nssym && NSIsSymbolNameDefined(symbol))
1.709 + {
1.710 + debug("Searching dependencies");
1.711 + savedErrorStr = dyld_error_str();
1.712 + nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
1.713 + }
1.714 + }
1.715 + else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
1.716 + {
1.717 + if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
1.718 + {
1.719 + nssym = dyld_NSLookupSymbolInImage(dls->lib,
1.720 + symbol,
1.721 + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
1.722 + NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
1.723 + }
1.724 + else if (NSIsSymbolNameDefined(symbol))
1.725 + {
1.726 + debug("Searching dependencies");
1.727 + savedErrorStr = dyld_error_str();
1.728 + nssym = search_linked_libs(dls->lib, symbol);
1.729 + }
1.730 + }
1.731 + else if (dls->module == MAGIC_DYLIB_MOD)
1.732 + {
1.733 + /* Global context, use NSLookupAndBindSymbol */
1.734 + if (NSIsSymbolNameDefined(symbol))
1.735 + {
1.736 + /* There doesn't seem to be a return on error option for this call???
1.737 + this is potentially broken, if binding fails, it will improperly
1.738 + exit the application. */
1.739 + nssym = NSLookupAndBindSymbol(symbol);
1.740 + }
1.741 + else
1.742 + {
1.743 + if (savedErrorStr)
1.744 + SDL_free(savedErrorStr);
1.745 + savedErrorStr = SDL_malloc(256);
1.746 + SDL_snprintf(savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);
1.747 + }
1.748 + }
1.749 + }
1.750 + /* Error reporting */
1.751 + if (!nssym)
1.752 + {
1.753 + if (!savedErrorStr || !SDL_strlen(savedErrorStr))
1.754 + {
1.755 + if (savedErrorStr)
1.756 + SDL_free(savedErrorStr);
1.757 + savedErrorStr = SDL_malloc(256);
1.758 + SDL_snprintf(savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
1.759 + }
1.760 + if (canSetError)
1.761 + {
1.762 + error(savedErrorStr);
1.763 + }
1.764 + else
1.765 + {
1.766 + debug(savedErrorStr);
1.767 + }
1.768 + if (savedErrorStr)
1.769 + SDL_free(savedErrorStr);
1.770 + return NULL;
1.771 + }
1.772 + return NSAddressOfSymbol(nssym);
1.773 +}
1.774 +
1.775 +static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
1.776 +{
1.777 + NSObjectFileImage ofi = 0;
1.778 + NSObjectFileImageReturnCode ofirc;
1.779 + struct dlstatus *dls;
1.780 + NSLinkEditErrors ler;
1.781 + int lerno;
1.782 + const char *errstr;
1.783 + const char *file;
1.784 + void (*init) (void);
1.785 +
1.786 + ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
1.787 + switch (ofirc)
1.788 + {
1.789 + case NSObjectFileImageSuccess:
1.790 + break;
1.791 + case NSObjectFileImageInappropriateFile:
1.792 + if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
1.793 + {
1.794 + if (isFlagSet(mode, RTLD_LOCAL))
1.795 + {
1.796 + warning("trying to open a .dylib with RTLD_LOCAL");
1.797 + error("unable to open this file with RTLD_LOCAL");
1.798 + return NULL;
1.799 + }
1.800 + }
1.801 + else
1.802 + {
1.803 + error("opening this file is unsupported on this system");
1.804 + return NULL;
1.805 + }
1.806 + break;
1.807 + case NSObjectFileImageFailure:
1.808 + error("object file setup failure");
1.809 + return NULL;
1.810 + case NSObjectFileImageArch:
1.811 + error("no object for this architecture");
1.812 + return NULL;
1.813 + case NSObjectFileImageFormat:
1.814 + error("bad object file format");
1.815 + return NULL;
1.816 + case NSObjectFileImageAccess:
1.817 + error("can't read object file");
1.818 + return NULL;
1.819 + default:
1.820 + error("unknown error from NSCreateObjectFileImageFromFile()");
1.821 + return NULL;
1.822 + }
1.823 + dls = lookupStatus(sbuf);
1.824 + if (!dls)
1.825 + {
1.826 + dls = allocStatus();
1.827 + }
1.828 + if (!dls)
1.829 + {
1.830 + error("unable to allocate memory");
1.831 + return NULL;
1.832 + }
1.833 + // dls->lib = 0;
1.834 + if (ofirc == NSObjectFileImageInappropriateFile)
1.835 + {
1.836 + if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
1.837 + {
1.838 + debug("Dynamic lib loaded at %ld", dls->lib);
1.839 + ofi = MAGIC_DYLIB_OFI;
1.840 + dls->module = MAGIC_DYLIB_MOD;
1.841 + ofirc = NSObjectFileImageSuccess;
1.842 + /* Although it is possible with a bit of work to modify this so it works and
1.843 + functions with RTLD_NOW, I don't deem it necessary at the moment */
1.844 + }
1.845 + if (!(dls->module))
1.846 + {
1.847 + NSLinkEditError(&ler, &lerno, &file, &errstr);
1.848 + if (!errstr || (!SDL_strlen(errstr)))
1.849 + error("Can't open this file type");
1.850 + else
1.851 + error(errstr);
1.852 + if ((dls->flags & DL_IN_LIST) == 0)
1.853 + {
1.854 + SDL_free(dls);
1.855 + }
1.856 + return NULL;
1.857 + }
1.858 + }
1.859 + else
1.860 + {
1.861 + dls->module = NSLinkModule(ofi, path,
1.862 + NSLINKMODULE_OPTION_RETURN_ON_ERROR |
1.863 + NSLINKMODULE_OPTION_PRIVATE |
1.864 + (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
1.865 + NSDestroyObjectFileImage(ofi);
1.866 + if (dls->module)
1.867 + {
1.868 + dls->lib = get_mach_header_from_NSModule(dls->module);
1.869 + }
1.870 + }
1.871 + if (!dls->module)
1.872 + {
1.873 + NSLinkEditError(&ler, &lerno, &file, &errstr);
1.874 + if ((dls->flags & DL_IN_LIST) == 0)
1.875 + {
1.876 + SDL_free(dls);
1.877 + }
1.878 + error(errstr);
1.879 + return NULL;
1.880 + }
1.881 +
1.882 + insertStatus(dls, sbuf);
1.883 + dls = reference(dls, mode);
1.884 + if ((init = dlsymIntern(dls, "__init", 0)))
1.885 + {
1.886 + debug("calling _init()");
1.887 + init();
1.888 + }
1.889 + return dls;
1.890 +}
1.891 +
1.892 +inline static void dlcompat_init_check(void)
1.893 +{
1.894 + static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
1.895 + static int init_done = 0;
1.896 +
1.897 + pthread_mutex_lock(&l);
1.898 + if (!init_done) {
1.899 + dlcompat_init_func();
1.900 + init_done = 1;
1.901 + }
1.902 + pthread_mutex_unlock(&l);
1.903 +}
1.904 +
1.905 +static void dlcompat_init_func(void)
1.906 +{
1.907 + _dyld_func_lookup("__dyld_NSAddImage", (void **)&dyld_NSAddImage);
1.908 + _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
1.909 + (void **)&dyld_NSIsSymbolNameDefinedInImage);
1.910 + _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (void **)&dyld_NSLookupSymbolInImage);
1.911 + if (pthread_mutex_init(&dlcompat_mutex, NULL))
1.912 + exit(1);
1.913 + if (pthread_key_create(&dlerror_key, &dlerrorfree))
1.914 + exit(1);
1.915 +}
1.916 +
1.917 +static void resetdlerror()
1.918 +{
1.919 + struct dlthread *tss;
1.920 + tss = pthread_getspecific(dlerror_key);
1.921 + tss->errset = 0;
1.922 +}
1.923 +
1.924 +static void dlerrorfree(void *data)
1.925 +{
1.926 + SDL_free(data);
1.927 +}
1.928 +
1.929 +/* We kind of want a recursive lock here, but meet a little trouble
1.930 + * because they are not available pre OS X 10.2, so we fake it
1.931 + * using thread specific storage to keep a lock count
1.932 + */
1.933 +static inline void dolock(void)
1.934 +{
1.935 + int err = 0;
1.936 + struct dlthread *tss;
1.937 + dlcompat_init_check();
1.938 + tss = pthread_getspecific(dlerror_key);
1.939 + if (!tss)
1.940 + {
1.941 + tss = SDL_malloc(sizeof(struct dlthread));
1.942 + tss->lockcnt = 0;
1.943 + tss->errset = 0;
1.944 + if (pthread_setspecific(dlerror_key, tss))
1.945 + {
1.946 + fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
1.947 + exit(1);
1.948 + }
1.949 + }
1.950 + if (!tss->lockcnt)
1.951 + err = pthread_mutex_lock(&dlcompat_mutex);
1.952 + tss->lockcnt = tss->lockcnt +1;
1.953 + if (err)
1.954 + exit(err);
1.955 +}
1.956 +
1.957 +static inline void dounlock(void)
1.958 +{
1.959 + int err = 0;
1.960 + struct dlthread *tss;
1.961 + tss = pthread_getspecific(dlerror_key);
1.962 + tss->lockcnt = tss->lockcnt -1;
1.963 + if (!tss->lockcnt)
1.964 + err = pthread_mutex_unlock(&dlcompat_mutex);
1.965 + if (err)
1.966 + exit(err);
1.967 +}
1.968 +
1.969 +static void *SDL_OSX_dlopen(const char *path, int mode)
1.970 +{
1.971 + const struct stat *sbuf;
1.972 + struct dlstatus *dls;
1.973 + const char *fullPath;
1.974 +
1.975 + dolock();
1.976 + resetdlerror();
1.977 + if (!path)
1.978 + {
1.979 + dls = &mainStatus;
1.980 + goto dlopenok;
1.981 + }
1.982 + if (!(sbuf = findFile(path, &fullPath)))
1.983 + {
1.984 + error("file \"%s\" not found", path);
1.985 + goto dlopenerror;
1.986 + }
1.987 + /* Now checks that it hasn't been closed already */
1.988 + if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
1.989 + {
1.990 + /* debug("status found"); */
1.991 + dls = reference(dls, mode);
1.992 + goto dlopenok;
1.993 + }
1.994 +#ifdef RTLD_NOLOAD
1.995 + if (isFlagSet(mode, RTLD_NOLOAD))
1.996 + {
1.997 + error("no existing handle and RTLD_NOLOAD specified");
1.998 + goto dlopenerror;
1.999 + }
1.1000 +#endif
1.1001 + if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
1.1002 + {
1.1003 + error("how can I load something both RTLD_LAZY and RTLD_NOW?");
1.1004 + goto dlopenerror;
1.1005 + }
1.1006 + dls = loadModule(fullPath, sbuf, mode);
1.1007 +
1.1008 + dlopenok:
1.1009 + dounlock();
1.1010 + return (void *)dls;
1.1011 + dlopenerror:
1.1012 + dounlock();
1.1013 + return NULL;
1.1014 +}
1.1015 +
1.1016 +#if !FINK_BUILD
1.1017 +static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
1.1018 +{
1.1019 + int sym_len = SDL_strlen(symbol);
1.1020 + void *value = NULL;
1.1021 + char *malloc_sym = NULL;
1.1022 + dolock();
1.1023 + malloc_sym = SDL_malloc(sym_len + 2);
1.1024 + if (malloc_sym)
1.1025 + {
1.1026 + SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
1.1027 + value = dlsymIntern(handle, malloc_sym, 1);
1.1028 + SDL_free(malloc_sym);
1.1029 + }
1.1030 + else
1.1031 + {
1.1032 + error("Unable to allocate memory");
1.1033 + goto dlsymerror;
1.1034 + }
1.1035 + dounlock();
1.1036 + return value;
1.1037 + dlsymerror:
1.1038 + dounlock();
1.1039 + return NULL;
1.1040 +}
1.1041 +#endif
1.1042 +
1.1043 +#if FINK_BUILD
1.1044 +
1.1045 +static void *dlsym_prepend_underscore(void *handle, const char *symbol)
1.1046 +{
1.1047 + void *answer;
1.1048 + dolock();
1.1049 + answer = dlsym_prepend_underscore_intern(handle, symbol);
1.1050 + dounlock();
1.1051 + return answer;
1.1052 +}
1.1053 +
1.1054 +static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
1.1055 +{
1.1056 +/*
1.1057 + * A quick and easy way for porting packages which call dlsym(handle,"sym")
1.1058 + * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
1.1059 + * this function will be called, and will add the required underscore.
1.1060 + *
1.1061 + * Note that I haven't figured out yet which should be "standard", prepend
1.1062 + * the underscore always, or not at all. These global functions need to go away
1.1063 + * for opendarwin.
1.1064 + */
1.1065 + int sym_len = SDL_strlen(symbol);
1.1066 + void *value = NULL;
1.1067 + char *malloc_sym = NULL;
1.1068 + malloc_sym = SDL_malloc(sym_len + 2);
1.1069 + if (malloc_sym)
1.1070 + {
1.1071 + SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
1.1072 + value = dlsymIntern(handle, malloc_sym, 1);
1.1073 + SDL_free(malloc_sym);
1.1074 + }
1.1075 + else
1.1076 + {
1.1077 + error("Unable to allocate memory");
1.1078 + }
1.1079 + return value;
1.1080 +}
1.1081 +
1.1082 +static void *dlsym_auto_underscore(void *handle, const char *symbol)
1.1083 +{
1.1084 + void *answer;
1.1085 + dolock();
1.1086 + answer = dlsym_auto_underscore_intern(handle, symbol);
1.1087 + dounlock();
1.1088 + return answer;
1.1089 +
1.1090 +}
1.1091 +static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
1.1092 +{
1.1093 + struct dlstatus *dls = handle;
1.1094 + void *addr = 0;
1.1095 + addr = dlsymIntern(dls, symbol, 0);
1.1096 + if (!addr)
1.1097 + addr = dlsym_prepend_underscore_intern(handle, symbol);
1.1098 + return addr;
1.1099 +}
1.1100 +
1.1101 +
1.1102 +static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
1.1103 +{
1.1104 + struct dlstatus *dls = handle;
1.1105 + void *addr = 0;
1.1106 + dolock();
1.1107 + addr = dlsymIntern(dls, symbol, 1);
1.1108 + dounlock();
1.1109 + return addr;
1.1110 +}
1.1111 +#endif
1.1112 +
1.1113 +static int SDL_OSX_dlclose(void *handle)
1.1114 +{
1.1115 + struct dlstatus *dls = handle;
1.1116 + dolock();
1.1117 + resetdlerror();
1.1118 + if (!isValidStatus(dls))
1.1119 + {
1.1120 + goto dlcloseerror;
1.1121 + }
1.1122 + if (dls->module == MAGIC_DYLIB_MOD)
1.1123 + {
1.1124 + const char *name;
1.1125 + if (!dls->lib)
1.1126 + {
1.1127 + name = "global context";
1.1128 + }
1.1129 + else
1.1130 + {
1.1131 + name = get_lib_name(dls->lib);
1.1132 + }
1.1133 + warning("trying to close a .dylib!");
1.1134 + error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
1.1135 + goto dlcloseerror;
1.1136 + }
1.1137 + if (!dls->module)
1.1138 + {
1.1139 + error("module already closed");
1.1140 + goto dlcloseerror;
1.1141 + }
1.1142 +
1.1143 + if (dls->refs == 1)
1.1144 + {
1.1145 + unsigned long options = 0;
1.1146 + void (*fini) (void);
1.1147 + if ((fini = dlsymIntern(dls, "__fini", 0)))
1.1148 + {
1.1149 + debug("calling _fini()");
1.1150 + fini();
1.1151 + }
1.1152 + options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
1.1153 +#ifdef RTLD_NODELETE
1.1154 + if (isFlagSet(dls->mode, RTLD_NODELETE))
1.1155 + options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
1.1156 +#endif
1.1157 + if (!NSUnLinkModule(dls->module, options))
1.1158 + {
1.1159 + error("unable to unlink module");
1.1160 + goto dlcloseerror;
1.1161 + }
1.1162 + dls->refs--;
1.1163 + dls->module = 0;
1.1164 + /* Note: the dlstatus struct dls is neither removed from the list
1.1165 + * nor is the memory it occupies freed. This shouldn't pose a
1.1166 + * problem in mostly all cases, though.
1.1167 + */
1.1168 + }
1.1169 + dounlock();
1.1170 + return 0;
1.1171 + dlcloseerror:
1.1172 + dounlock();
1.1173 + return 1;
1.1174 +}
1.1175 +
1.1176 +static const char *SDL_OSX_dlerror(void)
1.1177 +{
1.1178 + struct dlthread *tss;
1.1179 + const char * err_str = NULL;
1.1180 + dlcompat_init_check();
1.1181 + tss = pthread_getspecific(dlerror_key);
1.1182 + if (tss != NULL && tss->errset != 0) {
1.1183 + tss->errset = 0;
1.1184 + err_str = tss->errstr;
1.1185 + }
1.1186 + return (err_str);
1.1187 +}
1.1188 +
1.1189 +/* Given an address, return the mach_header for the image containing it
1.1190 + * or zero if the given address is not contained in any loaded images.
1.1191 + */
1.1192 +static const struct mach_header *image_for_address(const void *address)
1.1193 +{
1.1194 + unsigned long i;
1.1195 + unsigned long j;
1.1196 + unsigned long count = _dyld_image_count();
1.1197 + const struct mach_header *mh = 0;
1.1198 + struct load_command *lc = 0;
1.1199 + unsigned long addr = 0;
1.1200 + for (i = 0; i < count; i++)
1.1201 + {
1.1202 + addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
1.1203 + mh = _dyld_get_image_header(i);
1.1204 + if (mh)
1.1205 + {
1.1206 + lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1.1207 + for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1.1208 + {
1.1209 + if (LC_SEGMENT == lc->cmd &&
1.1210 + addr >= ((struct segment_command *)lc)->vmaddr &&
1.1211 + addr <
1.1212 + ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
1.1213 + {
1.1214 + goto image_found;
1.1215 + }
1.1216 + }
1.1217 + }
1.1218 + mh = 0;
1.1219 + }
1.1220 + image_found:
1.1221 + return mh;
1.1222 +}
1.1223 +
1.1224 +#if 0 /* unused */
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 (!SDL_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 +#endif
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 = SDL_strlen(symbol);
1.1352 + char *malloc_sym = NULL;
1.1353 + dolock();
1.1354 + malloc_sym = SDL_malloc(sym_len + 2);
1.1355 + if (malloc_sym)
1.1356 + {
1.1357 + SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
1.1358 + rv.d = dlsymIntern(handle, malloc_sym, 1);
1.1359 + SDL_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 +#include "SDL_loadso.h"
1.1383 +
1.1384 +void *SDL_LoadObject(const char *sofile)
1.1385 +{
1.1386 + void *handle = SDL_OSX_dlopen(sofile, RTLD_NOW);
1.1387 + const char *loaderror = SDL_OSX_dlerror();
1.1388 + if ( handle == NULL ) {
1.1389 + SDL_SetError("Failed loading %s: %s", sofile, loaderror);
1.1390 + }
1.1391 + return(handle);
1.1392 +}
1.1393 +
1.1394 +void *SDL_LoadFunction(void *handle, const char *name)
1.1395 +{
1.1396 + void *symbol = SDL_OSX_dlsym(handle, name);
1.1397 + if ( symbol == NULL ) {
1.1398 + SDL_SetError("Failed loading %s: %s", name, SDL_OSX_dlerror());
1.1399 + }
1.1400 + return(symbol);
1.1401 +}
1.1402 +
1.1403 +void SDL_UnloadObject(void *handle)
1.1404 +{
1.1405 + if ( handle != NULL ) {
1.1406 + SDL_OSX_dlclose(handle);
1.1407 + }
1.1408 +}
1.1409 +
1.1410 +#endif /* SDL_LOADSO_DLCOMPAT */
2.1 --- a/src/loadso/macosx/SDL_sysloadso.c Wed May 10 06:07:47 2006 +0000
2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2.3 @@ -1,1407 +0,0 @@
2.4 -/*
2.5 - SDL - Simple DirectMedia Layer
2.6 - Copyright (C) 1997-2006 Sam Lantinga
2.7 -
2.8 - This library is free software; you can redistribute it and/or
2.9 - modify it under the terms of the GNU Lesser General Public
2.10 - License as published by the Free Software Foundation; either
2.11 - version 2.1 of the License, or (at your option) any later version.
2.12 -
2.13 - This library is distributed in the hope that it will be useful,
2.14 - but WITHOUT ANY WARRANTY; without even the implied warranty of
2.15 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2.16 - Lesser General Public License for more details.
2.17 -
2.18 - You should have received a copy of the GNU Lesser General Public
2.19 - License along with this library; if not, write to the Free Software
2.20 - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2.21 -
2.22 - Sam Lantinga
2.23 - slouken@libsdl.org
2.24 -*/
2.25 -#include "SDL_config.h"
2.26 -
2.27 -#ifdef SDL_LOADSO_DLCOMPAT
2.28 -
2.29 -/* Please note that dlcompat apparently ships in current Mac OS X versions
2.30 - * as a system library that provides compatibility with the Unix "dlopen"
2.31 - * interface. In order to allow SDL to work on older OS X releases and also
2.32 - * not conflict with the system lib on newer versions, we include dlcompat
2.33 - * in SDL and change the symbols to prevent symbol clash with any existing
2.34 - * system libraries. --ryan.
2.35 - */
2.36 -
2.37 -/* here is the dlcompat license: */
2.38 -
2.39 -/*
2.40 -Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> &
2.41 - Peter O'Gorman <ogorman@users.sourceforge.net>
2.42 -
2.43 -Portions may be copyright others, see the AUTHORS file included with this
2.44 -distribution.
2.45 -
2.46 -Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
2.47 -
2.48 -Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
2.49 -
2.50 -Permission is hereby granted, free of charge, to any person obtaining
2.51 -a copy of this software and associated documentation files (the
2.52 -"Software"), to deal in the Software without restriction, including
2.53 -without limitation the rights to use, copy, modify, merge, publish,
2.54 -distribute, sublicense, and/or sell copies of the Software, and to
2.55 -permit persons to whom the Software is furnished to do so, subject to
2.56 -the following conditions:
2.57 -
2.58 -The above copyright notice and this permission notice shall be
2.59 -included in all copies or substantial portions of the Software.
2.60 -
2.61 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2.62 -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2.63 -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2.64 -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2.65 -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2.66 -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2.67 -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2.68 -*/
2.69 -
2.70 -#include <pthread.h>
2.71 -#include <sys/types.h>
2.72 -#include <sys/stat.h>
2.73 -#include <stdarg.h>
2.74 -#include <limits.h>
2.75 -#include <mach-o/dyld.h>
2.76 -#include <mach-o/nlist.h>
2.77 -#include <mach-o/getsect.h>
2.78 -
2.79 -#include "SDL_stdinc.h"
2.80 -
2.81 -/* Just playing to see if it would compile with the freebsd headers, it does,
2.82 - * but because of the different values for RTLD_LOCAL etc, it would break binary
2.83 - * compat... oh well
2.84 - */
2.85 -#ifndef __BSD_VISIBLE
2.86 -#define __BSD_VISIBLE 1
2.87 -#endif
2.88 -
2.89 -/*include "dlfcn.h"*/
2.90 -#ifdef __cplusplus
2.91 -extern "C" {
2.92 -#endif
2.93 -
2.94 -#if defined (__GNUC__) && __GNUC__ > 3
2.95 -#define dl_restrict __restrict
2.96 -#else
2.97 -#define dl_restrict
2.98 -#endif
2.99 -
2.100 -#if 0
2.101 -#ifndef _POSIX_SOURCE
2.102 -/*
2.103 - * Structure filled in by dladdr().
2.104 - */
2.105 -typedef struct SDL_OSX_dl_info {
2.106 - const char *dli_fname; /* Pathname of shared object */
2.107 - void *dli_fbase; /* Base address of shared object */
2.108 - const char *dli_sname; /* Name of nearest symbol */
2.109 - void *dli_saddr; /* Address of nearest symbol */
2.110 -} SDL_OSX_Dl_info;
2.111 -
2.112 -static int SDL_OSX_dladdr(const void * dl_restrict, SDL_OSX_Dl_info * dl_restrict);
2.113 -#endif /* ! _POSIX_SOURCE */
2.114 -#endif /* 0 */
2.115 -
2.116 -static int SDL_OSX_dlclose(void * handle);
2.117 -static const char * SDL_OSX_dlerror(void);
2.118 -static void * SDL_OSX_dlopen(const char *path, int mode);
2.119 -static void * SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol);
2.120 -
2.121 -#define RTLD_LAZY 0x1
2.122 -#define RTLD_NOW 0x2
2.123 -#define RTLD_LOCAL 0x4
2.124 -#define RTLD_GLOBAL 0x8
2.125 -
2.126 -#ifndef _POSIX_SOURCE
2.127 -#define RTLD_NOLOAD 0x10
2.128 -#define RTLD_NODELETE 0x80
2.129 -
2.130 -/*
2.131 - * Special handle arguments for SDL_OSX_dlsym().
2.132 - */
2.133 -#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
2.134 -#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
2.135 -#endif /* ! _POSIX_SOURCE */
2.136 -
2.137 -#ifdef __cplusplus
2.138 -}
2.139 -#endif
2.140 -
2.141 -#ifndef dl_restrict
2.142 -#define dl_restrict __restrict
2.143 -#endif
2.144 -/* This is not available on 10.1 */
2.145 -#ifndef LC_LOAD_WEAK_DYLIB
2.146 -#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
2.147 -#endif
2.148 -
2.149 -/* With this stuff here, this thing may actually compile/run on 10.0 systems
2.150 - * Not that I have a 10.0 system to test it on anylonger
2.151 - */
2.152 -#ifndef LC_REQ_DYLD
2.153 -#define LC_REQ_DYLD 0x80000000
2.154 -#endif
2.155 -#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
2.156 -#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
2.157 -#endif
2.158 -#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
2.159 -#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
2.160 -#endif
2.161 -#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
2.162 -#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
2.163 -#endif
2.164 -#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
2.165 -#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
2.166 -#endif
2.167 -/* These symbols will be looked for in dyld */
2.168 -static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
2.169 -static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
2.170 -static NSSymbol(*dyld_NSLookupSymbolInImage)
2.171 - (const struct mach_header *, const char *, unsigned long) = 0;
2.172 -
2.173 -/* Define this to make dlcompat reuse data block. This way in theory we save
2.174 - * a little bit of overhead. However we then couldn't correctly catch excess
2.175 - * calls to SDL_OSX_dlclose(). Hence we don't use this feature
2.176 - */
2.177 -#undef REUSE_STATUS
2.178 -
2.179 -/* Size of the internal error message buffer (used by dlerror()) */
2.180 -#define ERR_STR_LEN 251
2.181 -
2.182 -/* Maximum number of search paths supported by getSearchPath */
2.183 -#define MAX_SEARCH_PATHS 32
2.184 -
2.185 -
2.186 -#define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
2.187 -#define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
2.188 -
2.189 -/* internal flags */
2.190 -#define DL_IN_LIST 0x01
2.191 -
2.192 -/* our mutex */
2.193 -static pthread_mutex_t dlcompat_mutex;
2.194 -/* Our thread specific storage
2.195 - */
2.196 -static pthread_key_t dlerror_key;
2.197 -
2.198 -struct dlthread
2.199 -{
2.200 - int lockcnt;
2.201 - unsigned char errset;
2.202 - char errstr[ERR_STR_LEN];
2.203 -};
2.204 -
2.205 -/* This is our central data structure. Whenever a module is loaded via
2.206 - * SDL_OSX_dlopen(), we create such a struct.
2.207 - */
2.208 -struct dlstatus
2.209 -{
2.210 - struct dlstatus *next; /* pointer to next element in the linked list */
2.211 - NSModule module;
2.212 - const struct mach_header *lib;
2.213 - int refs; /* reference count */
2.214 - int mode; /* mode in which this module was loaded */
2.215 - dev_t device;
2.216 - ino_t inode;
2.217 - int flags; /* Any internal flags we may need */
2.218 -};
2.219 -
2.220 -/* Head node of the dlstatus list */
2.221 -static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
2.222 -static struct dlstatus *stqueue = &mainStatus;
2.223 -
2.224 -
2.225 -/* Storage for the last error message (used by dlerror()) */
2.226 -/* static char err_str[ERR_STR_LEN]; */
2.227 -/* static int err_filled = 0; */
2.228 -
2.229 -/* Prototypes to internal functions */
2.230 -static void debug(const char *fmt, ...);
2.231 -static void error(const char *str, ...);
2.232 -static const char *safegetenv(const char *s);
2.233 -static const char *searchList(void);
2.234 -static const char *getSearchPath(int i);
2.235 -static const char *getFullPath(int i, const char *file);
2.236 -static const struct stat *findFile(const char *file, const char **fullPath);
2.237 -static int isValidStatus(struct dlstatus *status);
2.238 -static inline int isFlagSet(int mode, int flag);
2.239 -static struct dlstatus *lookupStatus(const struct stat *sbuf);
2.240 -static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
2.241 -static int promoteLocalToGlobal(struct dlstatus *dls);
2.242 -static void *reference(struct dlstatus *dls, int mode);
2.243 -static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
2.244 -static struct dlstatus *allocStatus(void);
2.245 -static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
2.246 -static NSSymbol search_linked_libs(const struct mach_header *mh, const char *symbol);
2.247 -static const char *get_lib_name(const struct mach_header *mh);
2.248 -static const struct mach_header *get_mach_header_from_NSModule(NSModule mod);
2.249 -static void dlcompat_init_func(void);
2.250 -static inline void dlcompat_init_check(void);
2.251 -static inline void dolock(void);
2.252 -static inline void dounlock(void);
2.253 -static void dlerrorfree(void *data);
2.254 -static void resetdlerror(void);
2.255 -static const struct mach_header *my_find_image(const char *name);
2.256 -static const struct mach_header *image_for_address(const void *address);
2.257 -static inline char *dyld_error_str(void);
2.258 -
2.259 -#if FINK_BUILD
2.260 -/* Two Global Functions */
2.261 -static void *dlsym_prepend_underscore(void *handle, const char *symbol);
2.262 -static void *dlsym_auto_underscore(void *handle, const char *symbol);
2.263 -
2.264 -/* And their _intern counterparts */
2.265 -static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
2.266 -static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
2.267 -#endif
2.268 -
2.269 -/* Functions */
2.270 -
2.271 -static void debug(const char *fmt, ...)
2.272 -{
2.273 -#if DEBUG > 1
2.274 - va_list arg;
2.275 - va_start(arg, fmt);
2.276 - fprintf(stderr, "DLDEBUG: ");
2.277 - vfprintf(stderr, fmt, arg);
2.278 - fprintf(stderr, "\n");
2.279 - fflush(stderr);
2.280 - va_end(arg);
2.281 -#endif
2.282 -}
2.283 -
2.284 -static void error(const char *str, ...)
2.285 -{
2.286 - va_list arg;
2.287 - struct dlthread *tss;
2.288 - char * err_str;
2.289 - va_start(arg, str);
2.290 - tss = pthread_getspecific(dlerror_key);
2.291 - err_str = tss->errstr;
2.292 - SDL_strlcpy(err_str, "dlcompat: ", ERR_STR_LEN);
2.293 - vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
2.294 - va_end(arg);
2.295 - debug("ERROR: %s\n", err_str);
2.296 - tss->errset = 1;
2.297 -}
2.298 -
2.299 -static void warning(const char *str)
2.300 -{
2.301 -#if DEBUG > 0
2.302 - fprintf(stderr, "WARNING: dlcompat: %s\n", str);
2.303 -#endif
2.304 -}
2.305 -
2.306 -static const char *safegetenv(const char *s)
2.307 -{
2.308 - const char *ss = SDL_getenv(s);
2.309 - return ss ? ss : "";
2.310 -}
2.311 -
2.312 -/* because this is only used for debugging and error reporting functions, we
2.313 - * don't really care about how elegant it is... it could use the load
2.314 - * commands to find the install name of the library, but...
2.315 - */
2.316 -static const char *get_lib_name(const struct mach_header *mh)
2.317 -{
2.318 - unsigned long count = _dyld_image_count();
2.319 - unsigned long i;
2.320 - const char *val = NULL;
2.321 - if (mh)
2.322 - {
2.323 - for (i = 0; i < count; i++)
2.324 - {
2.325 - if (mh == _dyld_get_image_header(i))
2.326 - {
2.327 - val = _dyld_get_image_name(i);
2.328 - break;
2.329 - }
2.330 - }
2.331 - }
2.332 - return val;
2.333 -}
2.334 -
2.335 -/* Returns the mach_header for the module bu going through all the loaded images
2.336 - * and finding the one with the same name as the module. There really ought to be
2.337 - * an api for doing this, would be faster, but there isn't one right now
2.338 - */
2.339 -static const struct mach_header *get_mach_header_from_NSModule(NSModule mod)
2.340 -{
2.341 - const char *mod_name = NSNameOfModule(mod);
2.342 - const struct mach_header *mh = NULL;
2.343 - unsigned long count = _dyld_image_count();
2.344 - unsigned long i;
2.345 - debug("Module name: %s", mod_name);
2.346 - for (i = 0; i < count; i++)
2.347 - {
2.348 - if (!SDL_strcmp(mod_name, _dyld_get_image_name(i)))
2.349 - {
2.350 - mh = _dyld_get_image_header(i);
2.351 - break;
2.352 - }
2.353 - }
2.354 - return mh;
2.355 -}
2.356 -
2.357 -
2.358 -/* Compute and return a list of all directories that we should search when
2.359 - * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
2.360 - * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
2.361 - * /usr/lib and /lib. Since both of the environments variables can contain a
2.362 - * list of colon seperated paths, we simply concat them and the two other paths
2.363 - * into one big string, which we then can easily parse.
2.364 - * Splitting this string into the actual path list is done by getSearchPath()
2.365 - */
2.366 -static const char *searchList()
2.367 -{
2.368 - size_t buf_size;
2.369 - static char *buf=NULL;
2.370 - const char *ldlp = safegetenv("LD_LIBRARY_PATH");
2.371 - const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
2.372 - const char *stdpath = SDL_getenv("DYLD_FALLBACK_LIBRARY_PATH");
2.373 - if (!stdpath)
2.374 - stdpath = "/usr/local/lib:/lib:/usr/lib";
2.375 - if (!buf)
2.376 - {
2.377 - buf_size = SDL_strlen(ldlp) + SDL_strlen(dyldlp) + SDL_strlen(stdpath) + 4;
2.378 - buf = SDL_malloc(buf_size);
2.379 - SDL_snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
2.380 - stdpath, '\0');
2.381 - }
2.382 - return buf;
2.383 -}
2.384 -
2.385 -/* Returns the ith search path from the list as computed by searchList() */
2.386 -static const char *getSearchPath(int i)
2.387 -{
2.388 - static const char *list = 0;
2.389 - static char **path = (char **)0;
2.390 - static int end = 0;
2.391 - static int numsize = MAX_SEARCH_PATHS;
2.392 - static char **tmp;
2.393 - /* So we can call SDL_free() in the "destructor" we use i=-1 to return the alloc'd array */
2.394 - if (i == -1)
2.395 - {
2.396 - return (const char*)path;
2.397 - }
2.398 - if (!path)
2.399 - {
2.400 - path = (char **)SDL_calloc(MAX_SEARCH_PATHS, sizeof(char **));
2.401 - }
2.402 - if (!list && !end)
2.403 - list = searchList();
2.404 - if (i >= (numsize))
2.405 - {
2.406 - debug("Increasing size for long PATH");
2.407 - tmp = (char **)SDL_calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
2.408 - if (tmp)
2.409 - {
2.410 - SDL_memcpy(tmp, path, sizeof(char **) * numsize);
2.411 - SDL_free(path);
2.412 - path = tmp;
2.413 - numsize += MAX_SEARCH_PATHS;
2.414 - }
2.415 - else
2.416 - {
2.417 - return 0;
2.418 - }
2.419 - }
2.420 -
2.421 - while (!path[i] && !end)
2.422 - {
2.423 - path[i] = strsep((char **)&list, ":");
2.424 -
2.425 - if (path[i][0] == 0)
2.426 - path[i] = 0;
2.427 - end = (list == 0);
2.428 - }
2.429 - return path[i];
2.430 -}
2.431 -
2.432 -static const char *getFullPath(int i, const char *file)
2.433 -{
2.434 - static char buf[PATH_MAX];
2.435 - const char *path = getSearchPath(i);
2.436 - if (path)
2.437 - {
2.438 - SDL_snprintf(buf, PATH_MAX, "%s/%s", path, file);
2.439 - }
2.440 - return path ? buf : 0;
2.441 -}
2.442 -
2.443 -/* Given a file name, try to determine the full path for that file. Starts
2.444 - * its search in the current directory, and then tries all paths in the
2.445 - * search list in the order they are specified there.
2.446 - */
2.447 -static const struct stat *findFile(const char *file, const char **fullPath)
2.448 -{
2.449 - int i = 0;
2.450 - static struct stat sbuf;
2.451 - char *fileName;
2.452 - debug("finding file %s", file);
2.453 - *fullPath = file;
2.454 - if (0 == stat(file, &sbuf))
2.455 - return &sbuf;
2.456 - if (SDL_strchr(file, '/'))
2.457 - return 0; /* If the path had a / we don't look in env var places */
2.458 - fileName = NULL;
2.459 - if (!fileName)
2.460 - fileName = (char *)file;
2.461 - while ((*fullPath = getFullPath(i++, fileName)))
2.462 - {
2.463 - if (0 == stat(*fullPath, &sbuf))
2.464 - return &sbuf;
2.465 - }
2.466 - ;
2.467 - return 0;
2.468 -}
2.469 -
2.470 -/* Determine whether a given dlstatus is valid or not */
2.471 -static int isValidStatus(struct dlstatus *status)
2.472 -{
2.473 - /* Walk the list to verify status is contained in it */
2.474 - struct dlstatus *dls = stqueue;
2.475 - while (dls && status != dls)
2.476 - dls = dls->next;
2.477 - if (dls == 0)
2.478 - error("invalid handle");
2.479 - else if ((dls->module == 0) || (dls->refs == 0))
2.480 - error("handle to closed library");
2.481 - else
2.482 - return TRUE;
2.483 - return FALSE;
2.484 -}
2.485 -
2.486 -static inline int isFlagSet(int mode, int flag)
2.487 -{
2.488 - return (mode & flag) == flag;
2.489 -}
2.490 -
2.491 -static struct dlstatus *lookupStatus(const struct stat *sbuf)
2.492 -{
2.493 - struct dlstatus *dls = stqueue;
2.494 - debug("looking for status");
2.495 - while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
2.496 - || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
2.497 - dls = dls->next;
2.498 - return dls;
2.499 -}
2.500 -
2.501 -static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
2.502 -{
2.503 - debug("inserting status");
2.504 - dls->inode = sbuf->st_ino;
2.505 - dls->device = sbuf->st_dev;
2.506 - dls->refs = 0;
2.507 - dls->mode = 0;
2.508 - if ((dls->flags & DL_IN_LIST) == 0)
2.509 - {
2.510 - dls->next = stqueue;
2.511 - stqueue = dls;
2.512 - dls->flags |= DL_IN_LIST;
2.513 - }
2.514 -}
2.515 -
2.516 -static struct dlstatus *allocStatus()
2.517 -{
2.518 - struct dlstatus *dls;
2.519 -#ifdef REUSE_STATUS
2.520 - dls = stqueue;
2.521 - while (dls && dls->module)
2.522 - dls = dls->next;
2.523 - if (!dls)
2.524 -#endif
2.525 - dls = SDL_calloc(sizeof(*dls),1);
2.526 - return dls;
2.527 -}
2.528 -
2.529 -static int promoteLocalToGlobal(struct dlstatus *dls)
2.530 -{
2.531 - static int (*p) (NSModule module) = 0;
2.532 - debug("promoting");
2.533 - if (!p)
2.534 - _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (void **)&p);
2.535 - return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
2.536 -}
2.537 -
2.538 -static void *reference(struct dlstatus *dls, int mode)
2.539 -{
2.540 - if (dls)
2.541 - {
2.542 - if (dls->module == MAGIC_DYLIB_MOD && isFlagSet(mode, RTLD_LOCAL))
2.543 - {
2.544 - warning("trying to open a .dylib with RTLD_LOCAL");
2.545 - error("unable to open a .dylib with RTLD_LOCAL");
2.546 - return NULL;
2.547 - }
2.548 - if (isFlagSet(mode, RTLD_GLOBAL) &&
2.549 - !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
2.550 - {
2.551 - error("unable to promote local module to global");
2.552 - return NULL;
2.553 - }
2.554 - dls->mode |= mode;
2.555 - dls->refs++;
2.556 - }
2.557 - else
2.558 - debug("reference called with NULL argument");
2.559 -
2.560 - return dls;
2.561 -}
2.562 -
2.563 -static const struct mach_header *my_find_image(const char *name)
2.564 -{
2.565 - const struct mach_header *mh = 0;
2.566 - const char *id = NULL;
2.567 - int i = _dyld_image_count();
2.568 - int j;
2.569 - mh = (struct mach_header *)
2.570 - dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
2.571 - NSADDIMAGE_OPTION_RETURN_ON_ERROR);
2.572 - if (!mh)
2.573 - {
2.574 - for (j = 0; j < i; j++)
2.575 - {
2.576 - id = _dyld_get_image_name(j);
2.577 - if (!SDL_strcmp(id, name))
2.578 - {
2.579 - mh = _dyld_get_image_header(j);
2.580 - break;
2.581 - }
2.582 - }
2.583 - }
2.584 - return mh;
2.585 -}
2.586 -
2.587 -/*
2.588 - * dyld adds libraries by first adding the directly dependant libraries in link order, and
2.589 - * then adding the dependencies for those libraries, so we should do the same... but we don't
2.590 - * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
2.591 - * any of it's direct dependencies, then it probably isn't there.
2.592 - */
2.593 -static NSSymbol search_linked_libs(const struct mach_header * mh, const char *symbol)
2.594 -{
2.595 - unsigned int n;
2.596 - struct load_command *lc = 0;
2.597 - struct mach_header *wh;
2.598 - NSSymbol nssym = 0;
2.599 - if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
2.600 - {
2.601 - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
2.602 - for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
2.603 - {
2.604 - if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
2.605 - {
2.606 - if ((wh = (struct mach_header *)
2.607 - my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
2.608 - (char *)lc))))
2.609 - {
2.610 - if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
2.611 - {
2.612 - nssym = dyld_NSLookupSymbolInImage(wh,
2.613 - symbol,
2.614 - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
2.615 - NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
2.616 - break;
2.617 - }
2.618 - }
2.619 - }
2.620 - }
2.621 - if ((!nssym) && NSIsSymbolNameDefined(symbol))
2.622 - {
2.623 - /* I've never seen this debug message...*/
2.624 - debug("Symbol \"%s\" is defined but was not found", symbol);
2.625 - }
2.626 - }
2.627 - return nssym;
2.628 -}
2.629 -
2.630 -/* Up to the caller to SDL_free() returned string */
2.631 -static inline char *dyld_error_str()
2.632 -{
2.633 - NSLinkEditErrors dylder;
2.634 - int dylderno;
2.635 - const char *dylderrstr;
2.636 - const char *dyldfile;
2.637 - char* retStr = NULL;
2.638 - NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
2.639 - if (dylderrstr && *dylderrstr)
2.640 - {
2.641 - retStr = SDL_strdup(dylderrstr);
2.642 - }
2.643 - return retStr;
2.644 -}
2.645 -
2.646 -static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
2.647 -{
2.648 - NSSymbol nssym = 0;
2.649 -#ifdef __GCC__
2.650 - void *caller = __builtin_return_address(1); /* Be *very* careful about inlining */
2.651 -#else
2.652 - void *caller = NULL;
2.653 -#endif
2.654 - const struct mach_header *caller_mh = 0;
2.655 - char *savedErrorStr = NULL;
2.656 - resetdlerror();
2.657 -#ifndef RTLD_SELF
2.658 -#define RTLD_SELF ((void *) -3)
2.659 -#endif
2.660 - if (NULL == dls)
2.661 - dls = RTLD_SELF;
2.662 - if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
2.663 - {
2.664 - if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage && caller)
2.665 - {
2.666 - caller_mh = image_for_address(caller);
2.667 - if (RTLD_SELF == dls)
2.668 - {
2.669 - /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
2.670 - * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
2.671 - * this is acceptable.
2.672 - */
2.673 - if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
2.674 - {
2.675 - nssym = dyld_NSLookupSymbolInImage(caller_mh,
2.676 - symbol,
2.677 - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
2.678 - NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
2.679 - }
2.680 - }
2.681 - if (!nssym)
2.682 - {
2.683 - if (RTLD_SELF == dls)
2.684 - savedErrorStr = dyld_error_str();
2.685 - nssym = search_linked_libs(caller_mh, symbol);
2.686 - }
2.687 - }
2.688 - else
2.689 - {
2.690 - if (canSetError)
2.691 - error("RTLD_SELF and RTLD_NEXT are not supported");
2.692 - return NULL;
2.693 - }
2.694 - }
2.695 - if (!nssym)
2.696 - {
2.697 -
2.698 - if (RTLD_DEFAULT == dls)
2.699 - {
2.700 - dls = &mainStatus;
2.701 - }
2.702 - if (!isValidStatus(dls))
2.703 - return NULL;
2.704 -
2.705 - if (dls->module != MAGIC_DYLIB_MOD)
2.706 - {
2.707 - nssym = NSLookupSymbolInModule(dls->module, symbol);
2.708 - if (!nssym && NSIsSymbolNameDefined(symbol))
2.709 - {
2.710 - debug("Searching dependencies");
2.711 - savedErrorStr = dyld_error_str();
2.712 - nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
2.713 - }
2.714 - }
2.715 - else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
2.716 - {
2.717 - if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
2.718 - {
2.719 - nssym = dyld_NSLookupSymbolInImage(dls->lib,
2.720 - symbol,
2.721 - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
2.722 - NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
2.723 - }
2.724 - else if (NSIsSymbolNameDefined(symbol))
2.725 - {
2.726 - debug("Searching dependencies");
2.727 - savedErrorStr = dyld_error_str();
2.728 - nssym = search_linked_libs(dls->lib, symbol);
2.729 - }
2.730 - }
2.731 - else if (dls->module == MAGIC_DYLIB_MOD)
2.732 - {
2.733 - /* Global context, use NSLookupAndBindSymbol */
2.734 - if (NSIsSymbolNameDefined(symbol))
2.735 - {
2.736 - /* There doesn't seem to be a return on error option for this call???
2.737 - this is potentially broken, if binding fails, it will improperly
2.738 - exit the application. */
2.739 - nssym = NSLookupAndBindSymbol(symbol);
2.740 - }
2.741 - else
2.742 - {
2.743 - if (savedErrorStr)
2.744 - SDL_free(savedErrorStr);
2.745 - savedErrorStr = SDL_malloc(256);
2.746 - SDL_snprintf(savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);
2.747 - }
2.748 - }
2.749 - }
2.750 - /* Error reporting */
2.751 - if (!nssym)
2.752 - {
2.753 - if (!savedErrorStr || !SDL_strlen(savedErrorStr))
2.754 - {
2.755 - if (savedErrorStr)
2.756 - SDL_free(savedErrorStr);
2.757 - savedErrorStr = SDL_malloc(256);
2.758 - SDL_snprintf(savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
2.759 - }
2.760 - if (canSetError)
2.761 - {
2.762 - error(savedErrorStr);
2.763 - }
2.764 - else
2.765 - {
2.766 - debug(savedErrorStr);
2.767 - }
2.768 - if (savedErrorStr)
2.769 - SDL_free(savedErrorStr);
2.770 - return NULL;
2.771 - }
2.772 - return NSAddressOfSymbol(nssym);
2.773 -}
2.774 -
2.775 -static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
2.776 -{
2.777 - NSObjectFileImage ofi = 0;
2.778 - NSObjectFileImageReturnCode ofirc;
2.779 - struct dlstatus *dls;
2.780 - NSLinkEditErrors ler;
2.781 - int lerno;
2.782 - const char *errstr;
2.783 - const char *file;
2.784 - void (*init) (void);
2.785 -
2.786 - ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
2.787 - switch (ofirc)
2.788 - {
2.789 - case NSObjectFileImageSuccess:
2.790 - break;
2.791 - case NSObjectFileImageInappropriateFile:
2.792 - if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
2.793 - {
2.794 - if (isFlagSet(mode, RTLD_LOCAL))
2.795 - {
2.796 - warning("trying to open a .dylib with RTLD_LOCAL");
2.797 - error("unable to open this file with RTLD_LOCAL");
2.798 - return NULL;
2.799 - }
2.800 - }
2.801 - else
2.802 - {
2.803 - error("opening this file is unsupported on this system");
2.804 - return NULL;
2.805 - }
2.806 - break;
2.807 - case NSObjectFileImageFailure:
2.808 - error("object file setup failure");
2.809 - return NULL;
2.810 - case NSObjectFileImageArch:
2.811 - error("no object for this architecture");
2.812 - return NULL;
2.813 - case NSObjectFileImageFormat:
2.814 - error("bad object file format");
2.815 - return NULL;
2.816 - case NSObjectFileImageAccess:
2.817 - error("can't read object file");
2.818 - return NULL;
2.819 - default:
2.820 - error("unknown error from NSCreateObjectFileImageFromFile()");
2.821 - return NULL;
2.822 - }
2.823 - dls = lookupStatus(sbuf);
2.824 - if (!dls)
2.825 - {
2.826 - dls = allocStatus();
2.827 - }
2.828 - if (!dls)
2.829 - {
2.830 - error("unable to allocate memory");
2.831 - return NULL;
2.832 - }
2.833 - // dls->lib = 0;
2.834 - if (ofirc == NSObjectFileImageInappropriateFile)
2.835 - {
2.836 - if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
2.837 - {
2.838 - debug("Dynamic lib loaded at %ld", dls->lib);
2.839 - ofi = MAGIC_DYLIB_OFI;
2.840 - dls->module = MAGIC_DYLIB_MOD;
2.841 - ofirc = NSObjectFileImageSuccess;
2.842 - /* Although it is possible with a bit of work to modify this so it works and
2.843 - functions with RTLD_NOW, I don't deem it necessary at the moment */
2.844 - }
2.845 - if (!(dls->module))
2.846 - {
2.847 - NSLinkEditError(&ler, &lerno, &file, &errstr);
2.848 - if (!errstr || (!SDL_strlen(errstr)))
2.849 - error("Can't open this file type");
2.850 - else
2.851 - error(errstr);
2.852 - if ((dls->flags & DL_IN_LIST) == 0)
2.853 - {
2.854 - SDL_free(dls);
2.855 - }
2.856 - return NULL;
2.857 - }
2.858 - }
2.859 - else
2.860 - {
2.861 - dls->module = NSLinkModule(ofi, path,
2.862 - NSLINKMODULE_OPTION_RETURN_ON_ERROR |
2.863 - NSLINKMODULE_OPTION_PRIVATE |
2.864 - (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
2.865 - NSDestroyObjectFileImage(ofi);
2.866 - if (dls->module)
2.867 - {
2.868 - dls->lib = get_mach_header_from_NSModule(dls->module);
2.869 - }
2.870 - }
2.871 - if (!dls->module)
2.872 - {
2.873 - NSLinkEditError(&ler, &lerno, &file, &errstr);
2.874 - if ((dls->flags & DL_IN_LIST) == 0)
2.875 - {
2.876 - SDL_free(dls);
2.877 - }
2.878 - error(errstr);
2.879 - return NULL;
2.880 - }
2.881 -
2.882 - insertStatus(dls, sbuf);
2.883 - dls = reference(dls, mode);
2.884 - if ((init = dlsymIntern(dls, "__init", 0)))
2.885 - {
2.886 - debug("calling _init()");
2.887 - init();
2.888 - }
2.889 - return dls;
2.890 -}
2.891 -
2.892 -inline static void dlcompat_init_check(void)
2.893 -{
2.894 - static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
2.895 - static int init_done = 0;
2.896 -
2.897 - pthread_mutex_lock(&l);
2.898 - if (!init_done) {
2.899 - dlcompat_init_func();
2.900 - init_done = 1;
2.901 - }
2.902 - pthread_mutex_unlock(&l);
2.903 -}
2.904 -
2.905 -static void dlcompat_init_func(void)
2.906 -{
2.907 - _dyld_func_lookup("__dyld_NSAddImage", (void **)&dyld_NSAddImage);
2.908 - _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
2.909 - (void **)&dyld_NSIsSymbolNameDefinedInImage);
2.910 - _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (void **)&dyld_NSLookupSymbolInImage);
2.911 - if (pthread_mutex_init(&dlcompat_mutex, NULL))
2.912 - exit(1);
2.913 - if (pthread_key_create(&dlerror_key, &dlerrorfree))
2.914 - exit(1);
2.915 -}
2.916 -
2.917 -static void resetdlerror()
2.918 -{
2.919 - struct dlthread *tss;
2.920 - tss = pthread_getspecific(dlerror_key);
2.921 - tss->errset = 0;
2.922 -}
2.923 -
2.924 -static void dlerrorfree(void *data)
2.925 -{
2.926 - SDL_free(data);
2.927 -}
2.928 -
2.929 -/* We kind of want a recursive lock here, but meet a little trouble
2.930 - * because they are not available pre OS X 10.2, so we fake it
2.931 - * using thread specific storage to keep a lock count
2.932 - */
2.933 -static inline void dolock(void)
2.934 -{
2.935 - int err = 0;
2.936 - struct dlthread *tss;
2.937 - dlcompat_init_check();
2.938 - tss = pthread_getspecific(dlerror_key);
2.939 - if (!tss)
2.940 - {
2.941 - tss = SDL_malloc(sizeof(struct dlthread));
2.942 - tss->lockcnt = 0;
2.943 - tss->errset = 0;
2.944 - if (pthread_setspecific(dlerror_key, tss))
2.945 - {
2.946 - fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
2.947 - exit(1);
2.948 - }
2.949 - }
2.950 - if (!tss->lockcnt)
2.951 - err = pthread_mutex_lock(&dlcompat_mutex);
2.952 - tss->lockcnt = tss->lockcnt +1;
2.953 - if (err)
2.954 - exit(err);
2.955 -}
2.956 -
2.957 -static inline void dounlock(void)
2.958 -{
2.959 - int err = 0;
2.960 - struct dlthread *tss;
2.961 - tss = pthread_getspecific(dlerror_key);
2.962 - tss->lockcnt = tss->lockcnt -1;
2.963 - if (!tss->lockcnt)
2.964 - err = pthread_mutex_unlock(&dlcompat_mutex);
2.965 - if (err)
2.966 - exit(err);
2.967 -}
2.968 -
2.969 -static void *SDL_OSX_dlopen(const char *path, int mode)
2.970 -{
2.971 - const struct stat *sbuf;
2.972 - struct dlstatus *dls;
2.973 - const char *fullPath;
2.974 -
2.975 - dolock();
2.976 - resetdlerror();
2.977 - if (!path)
2.978 - {
2.979 - dls = &mainStatus;
2.980 - goto dlopenok;
2.981 - }
2.982 - if (!(sbuf = findFile(path, &fullPath)))
2.983 - {
2.984 - error("file \"%s\" not found", path);
2.985 - goto dlopenerror;
2.986 - }
2.987 - /* Now checks that it hasn't been closed already */
2.988 - if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
2.989 - {
2.990 - /* debug("status found"); */
2.991 - dls = reference(dls, mode);
2.992 - goto dlopenok;
2.993 - }
2.994 -#ifdef RTLD_NOLOAD
2.995 - if (isFlagSet(mode, RTLD_NOLOAD))
2.996 - {
2.997 - error("no existing handle and RTLD_NOLOAD specified");
2.998 - goto dlopenerror;
2.999 - }
2.1000 -#endif
2.1001 - if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
2.1002 - {
2.1003 - error("how can I load something both RTLD_LAZY and RTLD_NOW?");
2.1004 - goto dlopenerror;
2.1005 - }
2.1006 - dls = loadModule(fullPath, sbuf, mode);
2.1007 -
2.1008 - dlopenok:
2.1009 - dounlock();
2.1010 - return (void *)dls;
2.1011 - dlopenerror:
2.1012 - dounlock();
2.1013 - return NULL;
2.1014 -}
2.1015 -
2.1016 -#if !FINK_BUILD
2.1017 -static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
2.1018 -{
2.1019 - int sym_len = SDL_strlen(symbol);
2.1020 - void *value = NULL;
2.1021 - char *malloc_sym = NULL;
2.1022 - dolock();
2.1023 - malloc_sym = SDL_malloc(sym_len + 2);
2.1024 - if (malloc_sym)
2.1025 - {
2.1026 - SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
2.1027 - value = dlsymIntern(handle, malloc_sym, 1);
2.1028 - SDL_free(malloc_sym);
2.1029 - }
2.1030 - else
2.1031 - {
2.1032 - error("Unable to allocate memory");
2.1033 - goto dlsymerror;
2.1034 - }
2.1035 - dounlock();
2.1036 - return value;
2.1037 - dlsymerror:
2.1038 - dounlock();
2.1039 - return NULL;
2.1040 -}
2.1041 -#endif
2.1042 -
2.1043 -#if FINK_BUILD
2.1044 -
2.1045 -static void *dlsym_prepend_underscore(void *handle, const char *symbol)
2.1046 -{
2.1047 - void *answer;
2.1048 - dolock();
2.1049 - answer = dlsym_prepend_underscore_intern(handle, symbol);
2.1050 - dounlock();
2.1051 - return answer;
2.1052 -}
2.1053 -
2.1054 -static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
2.1055 -{
2.1056 -/*
2.1057 - * A quick and easy way for porting packages which call dlsym(handle,"sym")
2.1058 - * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
2.1059 - * this function will be called, and will add the required underscore.
2.1060 - *
2.1061 - * Note that I haven't figured out yet which should be "standard", prepend
2.1062 - * the underscore always, or not at all. These global functions need to go away
2.1063 - * for opendarwin.
2.1064 - */
2.1065 - int sym_len = SDL_strlen(symbol);
2.1066 - void *value = NULL;
2.1067 - char *malloc_sym = NULL;
2.1068 - malloc_sym = SDL_malloc(sym_len + 2);
2.1069 - if (malloc_sym)
2.1070 - {
2.1071 - SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
2.1072 - value = dlsymIntern(handle, malloc_sym, 1);
2.1073 - SDL_free(malloc_sym);
2.1074 - }
2.1075 - else
2.1076 - {
2.1077 - error("Unable to allocate memory");
2.1078 - }
2.1079 - return value;
2.1080 -}
2.1081 -
2.1082 -static void *dlsym_auto_underscore(void *handle, const char *symbol)
2.1083 -{
2.1084 - void *answer;
2.1085 - dolock();
2.1086 - answer = dlsym_auto_underscore_intern(handle, symbol);
2.1087 - dounlock();
2.1088 - return answer;
2.1089 -
2.1090 -}
2.1091 -static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
2.1092 -{
2.1093 - struct dlstatus *dls = handle;
2.1094 - void *addr = 0;
2.1095 - addr = dlsymIntern(dls, symbol, 0);
2.1096 - if (!addr)
2.1097 - addr = dlsym_prepend_underscore_intern(handle, symbol);
2.1098 - return addr;
2.1099 -}
2.1100 -
2.1101 -
2.1102 -static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
2.1103 -{
2.1104 - struct dlstatus *dls = handle;
2.1105 - void *addr = 0;
2.1106 - dolock();
2.1107 - addr = dlsymIntern(dls, symbol, 1);
2.1108 - dounlock();
2.1109 - return addr;
2.1110 -}
2.1111 -#endif
2.1112 -
2.1113 -static int SDL_OSX_dlclose(void *handle)
2.1114 -{
2.1115 - struct dlstatus *dls = handle;
2.1116 - dolock();
2.1117 - resetdlerror();
2.1118 - if (!isValidStatus(dls))
2.1119 - {
2.1120 - goto dlcloseerror;
2.1121 - }
2.1122 - if (dls->module == MAGIC_DYLIB_MOD)
2.1123 - {
2.1124 - const char *name;
2.1125 - if (!dls->lib)
2.1126 - {
2.1127 - name = "global context";
2.1128 - }
2.1129 - else
2.1130 - {
2.1131 - name = get_lib_name(dls->lib);
2.1132 - }
2.1133 - warning("trying to close a .dylib!");
2.1134 - error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
2.1135 - goto dlcloseerror;
2.1136 - }
2.1137 - if (!dls->module)
2.1138 - {
2.1139 - error("module already closed");
2.1140 - goto dlcloseerror;
2.1141 - }
2.1142 -
2.1143 - if (dls->refs == 1)
2.1144 - {
2.1145 - unsigned long options = 0;
2.1146 - void (*fini) (void);
2.1147 - if ((fini = dlsymIntern(dls, "__fini", 0)))
2.1148 - {
2.1149 - debug("calling _fini()");
2.1150 - fini();
2.1151 - }
2.1152 - options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
2.1153 -#ifdef RTLD_NODELETE
2.1154 - if (isFlagSet(dls->mode, RTLD_NODELETE))
2.1155 - options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
2.1156 -#endif
2.1157 - if (!NSUnLinkModule(dls->module, options))
2.1158 - {
2.1159 - error("unable to unlink module");
2.1160 - goto dlcloseerror;
2.1161 - }
2.1162 - dls->refs--;
2.1163 - dls->module = 0;
2.1164 - /* Note: the dlstatus struct dls is neither removed from the list
2.1165 - * nor is the memory it occupies freed. This shouldn't pose a
2.1166 - * problem in mostly all cases, though.
2.1167 - */
2.1168 - }
2.1169 - dounlock();
2.1170 - return 0;
2.1171 - dlcloseerror:
2.1172 - dounlock();
2.1173 - return 1;
2.1174 -}
2.1175 -
2.1176 -static const char *SDL_OSX_dlerror(void)
2.1177 -{
2.1178 - struct dlthread *tss;
2.1179 - const char * err_str = NULL;
2.1180 - dlcompat_init_check();
2.1181 - tss = pthread_getspecific(dlerror_key);
2.1182 - if (tss != NULL && tss->errset != 0) {
2.1183 - tss->errset = 0;
2.1184 - err_str = tss->errstr;
2.1185 - }
2.1186 - return (err_str);
2.1187 -}
2.1188 -
2.1189 -/* Given an address, return the mach_header for the image containing it
2.1190 - * or zero if the given address is not contained in any loaded images.
2.1191 - */
2.1192 -static const struct mach_header *image_for_address(const void *address)
2.1193 -{
2.1194 - unsigned long i;
2.1195 - unsigned long j;
2.1196 - unsigned long count = _dyld_image_count();
2.1197 - const struct mach_header *mh = 0;
2.1198 - struct load_command *lc = 0;
2.1199 - unsigned long addr = 0;
2.1200 - for (i = 0; i < count; i++)
2.1201 - {
2.1202 - addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
2.1203 - mh = _dyld_get_image_header(i);
2.1204 - if (mh)
2.1205 - {
2.1206 - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
2.1207 - for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
2.1208 - {
2.1209 - if (LC_SEGMENT == lc->cmd &&
2.1210 - addr >= ((struct segment_command *)lc)->vmaddr &&
2.1211 - addr <
2.1212 - ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
2.1213 - {
2.1214 - goto image_found;
2.1215 - }
2.1216 - }
2.1217 - }
2.1218 - mh = 0;
2.1219 - }
2.1220 - image_found:
2.1221 - return mh;
2.1222 -}
2.1223 -
2.1224 -#if 0 /* unused */
2.1225 -static int SDL_OSX_dladdr(const void * dl_restrict p, SDL_OSX_Dl_info * dl_restrict info)
2.1226 -{
2.1227 -/*
2.1228 - FIXME: USe the routine image_for_address.
2.1229 -*/
2.1230 - unsigned long i;
2.1231 - unsigned long j;
2.1232 - unsigned long count = _dyld_image_count();
2.1233 - struct mach_header *mh = 0;
2.1234 - struct load_command *lc = 0;
2.1235 - unsigned long addr = NULL;
2.1236 - unsigned long table_off = (unsigned long)0;
2.1237 - int found = 0;
2.1238 - if (!info)
2.1239 - return 0;
2.1240 - dolock();
2.1241 - resetdlerror();
2.1242 - info->dli_fname = 0;
2.1243 - info->dli_fbase = 0;
2.1244 - info->dli_sname = 0;
2.1245 - info->dli_saddr = 0;
2.1246 -/* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
2.1247 - * to darwin-development AT lists DOT apple DOT com and slightly modified
2.1248 - */
2.1249 - for (i = 0; i < count; i++)
2.1250 - {
2.1251 - addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
2.1252 - mh = _dyld_get_image_header(i);
2.1253 - if (mh)
2.1254 - {
2.1255 - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
2.1256 - for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
2.1257 - {
2.1258 - if (LC_SEGMENT == lc->cmd &&
2.1259 - addr >= ((struct segment_command *)lc)->vmaddr &&
2.1260 - addr <
2.1261 - ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
2.1262 - {
2.1263 - info->dli_fname = _dyld_get_image_name(i);
2.1264 - info->dli_fbase = (void *)mh;
2.1265 - found = 1;
2.1266 - break;
2.1267 - }
2.1268 - }
2.1269 - if (found)
2.1270 - break;
2.1271 - }
2.1272 - }
2.1273 - if (!found)
2.1274 - {
2.1275 - dounlock();
2.1276 - return 0;
2.1277 - }
2.1278 - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
2.1279 - for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
2.1280 - {
2.1281 - if (LC_SEGMENT == lc->cmd)
2.1282 - {
2.1283 - if (!SDL_strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
2.1284 - break;
2.1285 - }
2.1286 - }
2.1287 - table_off =
2.1288 - ((unsigned long)((struct segment_command *)lc)->vmaddr) -
2.1289 - ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i);
2.1290 - debug("table off %x", table_off);
2.1291 -
2.1292 - lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
2.1293 - for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
2.1294 - {
2.1295 - if (LC_SYMTAB == lc->cmd)
2.1296 - {
2.1297 -
2.1298 - struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off);
2.1299 - unsigned long numsyms = ((struct symtab_command *)lc)->nsyms;
2.1300 - struct nlist *nearest = NULL;
2.1301 - unsigned long diff = 0xffffffff;
2.1302 - unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off);
2.1303 - debug("symtable %x", symtable);
2.1304 - for (i = 0; i < numsyms; i++)
2.1305 - {
2.1306 - /* Ignore the following kinds of Symbols */
2.1307 - if ((!symtable->n_value) /* Undefined */
2.1308 - || (symtable->n_type >= N_PEXT) /* Debug symbol */
2.1309 - || (!(symtable->n_type & N_EXT)) /* Local Symbol */
2.1310 - )
2.1311 - {
2.1312 - symtable++;
2.1313 - continue;
2.1314 - }
2.1315 - if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
2.1316 - {
2.1317 - diff = (unsigned long)symtable->n_value - addr;
2.1318 - nearest = symtable;
2.1319 - }
2.1320 - symtable++;
2.1321 - }
2.1322 - if (nearest)
2.1323 - {
2.1324 - info->dli_saddr = nearest->n_value + ((void *)p - addr);
2.1325 - info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
2.1326 - }
2.1327 - }
2.1328 - }
2.1329 - dounlock();
2.1330 - return 1;
2.1331 -}
2.1332 -#endif
2.1333 -
2.1334 -/*
2.1335 - * Implement the dlfunc() interface, which behaves exactly the same as
2.1336 - * dlsym() except that it returns a function pointer instead of a data
2.1337 - * pointer. This can be used by applications to avoid compiler warnings
2.1338 - * about undefined behavior, and is intended as prior art for future
2.1339 - * POSIX standardization. This function requires that all pointer types
2.1340 - * have the same representation, which is true on all platforms FreeBSD
2.1341 - * runs on, but is not guaranteed by the C standard.
2.1342 - */
2.1343 -#if 0
2.1344 -static dlfunc_t SDL_OSX_dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
2.1345 -{
2.1346 - union
2.1347 - {
2.1348 - void *d;
2.1349 - dlfunc_t f;
2.1350 - } rv;
2.1351 - int sym_len = SDL_strlen(symbol);
2.1352 - char *malloc_sym = NULL;
2.1353 - dolock();
2.1354 - malloc_sym = SDL_malloc(sym_len + 2);
2.1355 - if (malloc_sym)
2.1356 - {
2.1357 - SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
2.1358 - rv.d = dlsymIntern(handle, malloc_sym, 1);
2.1359 - SDL_free(malloc_sym);
2.1360 - }
2.1361 - else
2.1362 - {
2.1363 - error("Unable to allocate memory");
2.1364 - goto dlfuncerror;
2.1365 - }
2.1366 - dounlock();
2.1367 - return rv.f;
2.1368 - dlfuncerror:
2.1369 - dounlock();
2.1370 - return NULL;
2.1371 -}
2.1372 -#endif
2.1373 -
2.1374 -
2.1375 -
2.1376 -/* dlcompat ends, here's the SDL interface... --ryan. */
2.1377 -
2.1378 -
2.1379 -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2.1380 -/* System dependent library loading routines */
2.1381 -
2.1382 -#include "SDL_loadso.h"
2.1383 -
2.1384 -void *SDL_LoadObject(const char *sofile)
2.1385 -{
2.1386 - void *handle = SDL_OSX_dlopen(sofile, RTLD_NOW);
2.1387 - const char *loaderror = SDL_OSX_dlerror();
2.1388 - if ( handle == NULL ) {
2.1389 - SDL_SetError("Failed loading %s: %s", sofile, loaderror);
2.1390 - }
2.1391 - return(handle);
2.1392 -}
2.1393 -
2.1394 -void *SDL_LoadFunction(void *handle, const char *name)
2.1395 -{
2.1396 - void *symbol = SDL_OSX_dlsym(handle, name);
2.1397 - if ( symbol == NULL ) {
2.1398 - SDL_SetError("Failed loading %s: %s", name, SDL_OSX_dlerror());
2.1399 - }
2.1400 - return(symbol);
2.1401 -}
2.1402 -
2.1403 -void SDL_UnloadObject(void *handle)
2.1404 -{
2.1405 - if ( handle != NULL ) {
2.1406 - SDL_OSX_dlclose(handle);
2.1407 - }
2.1408 -}
2.1409 -
2.1410 -#endif /* SDL_LOADSO_DLCOMPAT */