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