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