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