Mercurial > sdl-ios-xcode
comparison src/loadso/macosx/SDL_dlcompat.c @ 1659:14717b52abc0 SDL-1.3
Merge trunk-1.3-3
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Wed, 17 May 2006 08:18:28 +0000 |
parents | |
children | 782fd950bd46 c121d94672cb a1b03ba2fcd0 |
comparison
equal
deleted
inserted
replaced
1658:e49147870aac | 1659:14717b52abc0 |
---|---|
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 */ |