2 Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> &
3 Peter O'Gorman <ogorman@users.sourceforge.net>
5 Portions may be copyright others, see the AUTHORS file included with this
8 Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
10 Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
12 Permission is hereby granted, free of charge, to any person obtaining
13 a copy of this software and associated documentation files (the
14 "Software"), to deal in the Software without restriction, including
15 without limitation the rights to use, copy, modify, merge, publish,
16 distribute, sublicense, and/or sell copies of the Software, and to
17 permit persons to whom the Software is furnished to do so, subject to
18 the following conditions:
20 The above copyright notice and this permission notice shall be
21 included in all copies or substantial portions of the Software.
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 #include <sys/types.h>
40 #include <mach-o/dyld.h>
41 #include <mach-o/nlist.h>
42 #include <mach-o/getsect.h>
43 /* Just playing to see if it would compile with the freebsd headers, it does,
44 * but because of the different values for RTLD_LOCAL etc, it would break binary
48 #define __BSD_VISIBLE 1
51 #include "asterisk/dlfcn-compat.h"
54 #define dl_restrict __restrict
56 /* This is not available on 10.1 */
57 #ifndef LC_LOAD_WEAK_DYLIB
58 #define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
61 /* With this stuff here, this thing may actually compile/run on 10.0 systems
62 * Not that I have a 10.0 system to test it on anylonger
65 #define LC_REQ_DYLD 0x80000000
67 #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
68 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
70 #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
71 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
73 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
74 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
76 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
77 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
79 /* These symbols will be looked for in dyld */
80 static const struct mach_header
*(*dyld_NSAddImage
) (const char *, unsigned long) = 0;
81 static int (*dyld_NSIsSymbolNameDefinedInImage
) (const struct mach_header
*, const char *) = 0;
82 static NSSymbol(*dyld_NSLookupSymbolInImage
)
83 (const struct mach_header
*, const char *, unsigned long) = 0;
85 /* Define this to make dlcompat reuse data block. This way in theory we save
86 * a little bit of overhead. However we then couldn't correctly catch excess
87 * calls to dlclose(). Hence we don't use this feature
91 /* Size of the internal error message buffer (used by dlerror()) */
92 #define ERR_STR_LEN 251
94 /* Maximum number of search paths supported by getSearchPath */
95 #define MAX_SEARCH_PATHS 32
98 #define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
99 #define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
102 #define DL_IN_LIST 0x01
105 static pthread_mutex_t dlcompat_mutex
;
106 /* Our thread specific storage
108 static pthread_key_t dlerror_key
;
113 unsigned char errset
;
114 char errstr
[ERR_STR_LEN
];
117 /* This is our central data structure. Whenever a module is loaded via
118 * dlopen(), we create such a struct.
122 struct dlstatus
*next
; /* pointer to next element in the linked list */
124 const struct mach_header
*lib
;
125 int refs
; /* reference count */
126 int mode
; /* mode in which this module was loaded */
129 int flags
; /* Any internal flags we may need */
132 /* Head node of the dlstatus list */
133 static struct dlstatus mainStatus
= { 0, MAGIC_DYLIB_MOD
, NULL
, -1, RTLD_GLOBAL
, 0, 0, 0 };
134 static struct dlstatus
*stqueue
= &mainStatus
;
137 /* Storage for the last error message (used by dlerror()) */
138 /* static char err_str[ERR_STR_LEN]; */
139 /* static int err_filled = 0; */
141 /* Prototypes to internal functions */
142 static void debug(const char *fmt
, ...);
143 static void error(const char *str
, ...);
144 static const char *safegetenv(const char *s
);
145 static const char *searchList(void);
146 static const char *getSearchPath(int i
);
147 static const char *getFullPath(int i
, const char *file
);
148 static const struct stat
*findFile(const char *file
, const char **fullPath
);
149 static int isValidStatus(struct dlstatus
*status
);
150 static inline int isFlagSet(int mode
, int flag
);
151 static struct dlstatus
*lookupStatus(const struct stat
*sbuf
);
152 static void insertStatus(struct dlstatus
*dls
, const struct stat
*sbuf
);
153 static int promoteLocalToGlobal(struct dlstatus
*dls
);
154 static void *reference(struct dlstatus
*dls
, int mode
);
155 static void *dlsymIntern(struct dlstatus
*dls
, const char *symbol
, int canSetError
);
156 static struct dlstatus
*allocStatus(void);
157 static struct dlstatus
*loadModule(const char *path
, const struct stat
*sbuf
, int mode
);
158 static NSSymbol
*search_linked_libs(const struct mach_header
*mh
, const char *symbol
);
159 static const char *get_lib_name(const struct mach_header
*mh
);
160 static const struct mach_header
*get_mach_header_from_NSModule(NSModule
* mod
);
161 static void dlcompat_init_func(void);
162 static inline void dolock(void);
163 static inline void dounlock(void);
164 static void dlerrorfree(void *data
);
165 static void resetdlerror(void);
166 static const struct mach_header
*my_find_image(const char *name
);
167 static const struct mach_header
*image_for_address(const void *address
);
168 static void dlcompat_cleanup(void);
169 static inline const char *dyld_error_str(void);
172 /* Two Global Functions */
173 void *dlsym_prepend_underscore(void *handle
, const char *symbol
);
174 void *dlsym_auto_underscore(void *handle
, const char *symbol
);
176 /* And their _intern counterparts */
177 static void *dlsym_prepend_underscore_intern(void *handle
, const char *symbol
);
178 static void *dlsym_auto_underscore_intern(void *handle
, const char *symbol
);
183 static void debug(const char *fmt
, ...)
188 fprintf(stderr
, "DLDEBUG: ");
189 vfprintf(stderr
, fmt
, arg
);
190 fprintf(stderr
, "\n");
196 static void error(const char *str
, ...)
199 struct dlthread
*tss
;
202 tss
= pthread_getspecific(dlerror_key
);
203 err_str
= tss
->errstr
;
204 strncpy(err_str
, "dlcompat: ", ERR_STR_LEN
);
205 vsnprintf(err_str
+ 10, ERR_STR_LEN
- 10, str
, arg
);
207 debug("ERROR: %s\n", err_str
);
211 static void warning(const char *str
)
214 fprintf(stderr
, "WARNING: dlcompat: %s\n", str
);
218 static const char *safegetenv(const char *s
)
220 const char *ss
= getenv(s
);
224 /* because this is only used for debugging and error reporting functions, we
225 * don't really care about how elegant it is... it could use the load
226 * commands to find the install name of the library, but...
228 static const char *get_lib_name(const struct mach_header
*mh
)
230 unsigned long count
= _dyld_image_count();
232 const char *val
= NULL
;
235 for (i
= 0; i
< count
; i
++)
237 if (mh
== _dyld_get_image_header(i
))
239 val
= _dyld_get_image_name(i
);
247 /* Returns the mach_header for the module bu going through all the loaded images
248 * and finding the one with the same name as the module. There really ought to be
249 * an api for doing this, would be faster, but there isn't one right now
251 static const struct mach_header
*get_mach_header_from_NSModule(NSModule
* mod
)
253 const char *mod_name
= NSNameOfModule(mod
);
254 struct mach_header
*mh
= NULL
;
255 unsigned long count
= _dyld_image_count();
257 debug("Module name: %s", mod_name
);
258 for (i
= 0; i
< count
; i
++)
260 if (!strcmp(mod_name
, _dyld_get_image_name(i
)))
262 mh
= _dyld_get_image_header(i
);
270 /* Compute and return a list of all directories that we should search when
271 * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
272 * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
273 * /usr/lib and /lib. Since both of the environments variables can contain a
274 * list of colon separated paths, we simply concat them and the two other paths
275 * into one big string, which we then can easily parse.
276 * Splitting this string into the actual path list is done by getSearchPath()
278 static const char *searchList()
281 static char *buf
=NULL
;
282 const char *ldlp
= safegetenv("LD_LIBRARY_PATH");
283 const char *dyldlp
= safegetenv("DYLD_LIBRARY_PATH");
284 const char *stdpath
= getenv("DYLD_FALLBACK_LIBRARY_PATH");
286 stdpath
= "/usr/local/lib:/lib:/usr/lib";
289 buf_size
= strlen(ldlp
) + strlen(dyldlp
) + strlen(stdpath
) + 4;
290 buf
= malloc(buf_size
);
291 snprintf(buf
, buf_size
, "%s%s%s%s%s%c", dyldlp
, (dyldlp
[0] ? ":" : ""), ldlp
, (ldlp
[0] ? ":" : ""),
297 /* Returns the ith search path from the list as computed by searchList() */
298 static const char *getSearchPath(int i
)
300 static const char *list
= 0;
301 static char **path
= (char **)0;
303 static int numsize
= MAX_SEARCH_PATHS
;
305 /* So we can call free() in the "destructor" we use i=-1 to return the alloc'd array */
308 return (const char*)path
;
312 path
= (char **)calloc(MAX_SEARCH_PATHS
, sizeof(char **));
318 debug("Increasing size for long PATH");
319 tmp
= (char **)calloc((MAX_SEARCH_PATHS
+ numsize
), sizeof(char **));
322 memcpy(tmp
, path
, sizeof(char **) * numsize
);
325 numsize
+= MAX_SEARCH_PATHS
;
333 while (!path
[i
] && !end
)
335 path
[i
] = strsep((char **)&list
, ":");
344 static const char *getFullPath(int i
, const char *file
)
346 static char buf
[PATH_MAX
];
347 const char *path
= getSearchPath(i
);
350 snprintf(buf
, PATH_MAX
, "%s/%s", path
, file
);
352 return path
? buf
: 0;
355 /* Given a file name, try to determine the full path for that file. Starts
356 * its search in the current directory, and then tries all paths in the
357 * search list in the order they are specified there.
359 static const struct stat
*findFile(const char *file
, const char **fullPath
)
362 static struct stat sbuf
;
364 debug("finding file %s", file
);
366 if (0 == stat(file
, &sbuf
))
368 if (strchr(file
, '/'))
369 return 0; /* If the path had a / we don't look in env var places */
372 fileName
= (char *)file
;
373 while ((*fullPath
= getFullPath(i
++, fileName
)))
375 if (0 == stat(*fullPath
, &sbuf
))
382 /* Determine whether a given dlstatus is valid or not */
383 static int isValidStatus(struct dlstatus
*status
)
385 /* Walk the list to verify status is contained in it */
386 struct dlstatus
*dls
= stqueue
;
387 while (dls
&& status
!= dls
)
390 error("invalid handle");
391 else if ((dls
->module
== 0) || (dls
->refs
== 0))
392 error("handle to closed library");
398 static inline int isFlagSet(int mode
, int flag
)
400 return (mode
& flag
) == flag
;
403 static struct dlstatus
*lookupStatus(const struct stat
*sbuf
)
405 struct dlstatus
*dls
= stqueue
;
406 debug("looking for status");
407 while (dls
&& ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
408 || sbuf
->st_dev
!= dls
->device
|| sbuf
->st_ino
!= dls
->inode
))
413 static void insertStatus(struct dlstatus
*dls
, const struct stat
*sbuf
)
415 debug("inserting status");
416 dls
->inode
= sbuf
->st_ino
;
417 dls
->device
= sbuf
->st_dev
;
420 if ((dls
->flags
& DL_IN_LIST
) == 0)
424 dls
->flags
|= DL_IN_LIST
;
428 static struct dlstatus
*allocStatus()
430 struct dlstatus
*dls
;
433 while (dls
&& dls
->module
)
437 dls
= malloc(sizeof(*dls
));
442 static int promoteLocalToGlobal(struct dlstatus
*dls
)
444 static int (*p
) (NSModule module
) = 0;
447 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p
);
448 return (dls
->module
== MAGIC_DYLIB_MOD
) || (p
&& p(dls
->module
));
451 static void *reference(struct dlstatus
*dls
, int mode
)
455 if (dls
->module
== MAGIC_DYLIB_MOD
&& !isFlagSet(mode
, RTLD_GLOBAL
))
457 warning("trying to open a .dylib with RTLD_LOCAL");
458 error("unable to open a .dylib with RTLD_LOCAL");
461 if (isFlagSet(mode
, RTLD_GLOBAL
) &&
462 !isFlagSet(dls
->mode
, RTLD_GLOBAL
) && !promoteLocalToGlobal(dls
))
464 error("unable to promote local module to global");
471 debug("reference called with NULL argument");
476 static const struct mach_header
*my_find_image(const char *name
)
478 const struct mach_header
*mh
= 0;
479 const char *id
= NULL
;
480 int i
= _dyld_image_count();
482 mh
= (struct mach_header
*)
483 dyld_NSAddImage(name
, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
|
484 NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
487 for (j
= 0; j
< i
; j
++)
489 id
= _dyld_get_image_name(j
);
490 if (!strcmp(id
, name
))
492 mh
= _dyld_get_image_header(j
);
501 * dyld adds libraries by first adding the directly dependant libraries in link order, and
502 * then adding the dependencies for those libraries, so we should do the same... but we don't
503 * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
504 * any of it's direct dependencies, then it probably isn't there.
506 NSSymbol
*search_linked_libs(const struct mach_header
* mh
, const char *symbol
)
509 struct load_command
*lc
= 0;
510 struct mach_header
*wh
;
512 if (dyld_NSAddImage
&& dyld_NSIsSymbolNameDefinedInImage
&& dyld_NSLookupSymbolInImage
)
514 lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
515 for (n
= 0; n
< mh
->ncmds
; n
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
))
517 if ((LC_LOAD_DYLIB
== lc
->cmd
) || (LC_LOAD_WEAK_DYLIB
== lc
->cmd
))
519 if ((wh
= (struct mach_header
*)
520 my_find_image((char *)(((struct dylib_command
*)lc
)->dylib
.name
.offset
+
523 if (dyld_NSIsSymbolNameDefinedInImage(wh
, symbol
))
525 nssym
= dyld_NSLookupSymbolInImage(wh
,
527 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|
528 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
534 if ((!nssym
) && NSIsSymbolNameDefined(symbol
))
536 /* I've never seen this debug message...*/
537 debug("Symbol \"%s\" is defined but was not found", symbol
);
543 /* Up to the caller to free() returned string */
544 static inline const char *dyld_error_str()
546 NSLinkEditErrors dylder
;
548 const char *dylderrstr
;
549 const char *dyldfile
;
550 const char* retStr
= NULL
;
551 NSLinkEditError(&dylder
, &dylderno
, &dyldfile
, &dylderrstr
);
552 if (dylderrstr
&& strlen(dylderrstr
))
554 retStr
= malloc(strlen(dylderrstr
) +1);
555 strcpy((char*)retStr
,dylderrstr
);
560 static void *dlsymIntern(struct dlstatus
*dls
, const char *symbol
, int canSetError
)
563 void *caller
= __builtin_return_address(1); /* Be *very* careful about inlining */
564 const struct mach_header
*caller_mh
= 0;
565 const char* savedErrorStr
= NULL
;
568 #define RTLD_SELF ((void *) -3)
572 if ((RTLD_NEXT
== dls
) || (RTLD_SELF
== dls
))
574 if (dyld_NSIsSymbolNameDefinedInImage
&& dyld_NSLookupSymbolInImage
)
576 caller_mh
= image_for_address(caller
);
577 if (RTLD_SELF
== dls
)
579 /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
580 * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
581 * this is acceptable.
583 if (dyld_NSIsSymbolNameDefinedInImage(caller_mh
, symbol
))
585 nssym
= dyld_NSLookupSymbolInImage(caller_mh
,
587 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|
588 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
593 if (RTLD_SELF
== dls
)
594 savedErrorStr
= dyld_error_str();
595 nssym
= search_linked_libs(caller_mh
, symbol
);
601 error("RTLD_SELF and RTLD_NEXT are not supported");
608 if (RTLD_DEFAULT
== dls
)
612 if (!isValidStatus(dls
))
615 if (dls
->module
!= MAGIC_DYLIB_MOD
)
617 nssym
= NSLookupSymbolInModule(dls
->module
, symbol
);
618 if (!nssym
&& NSIsSymbolNameDefined(symbol
))
620 debug("Searching dependencies");
621 savedErrorStr
= dyld_error_str();
622 nssym
= search_linked_libs(get_mach_header_from_NSModule(dls
->module
), symbol
);
625 else if (dls
->lib
&& dyld_NSIsSymbolNameDefinedInImage
&& dyld_NSLookupSymbolInImage
)
627 if (dyld_NSIsSymbolNameDefinedInImage(dls
->lib
, symbol
))
629 nssym
= dyld_NSLookupSymbolInImage(dls
->lib
,
631 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|
632 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
634 else if (NSIsSymbolNameDefined(symbol
))
636 debug("Searching dependencies");
637 savedErrorStr
= dyld_error_str();
638 nssym
= search_linked_libs(dls
->lib
, symbol
);
641 else if (dls
->module
== MAGIC_DYLIB_MOD
)
643 /* Global context, use NSLookupAndBindSymbol */
644 if (NSIsSymbolNameDefined(symbol
))
646 /* There doesn't seem to be a return on error option for this call???
647 this is potentially broken, if binding fails, it will improperly
648 exit the application. */
649 nssym
= NSLookupAndBindSymbol(symbol
);
654 free((char*)savedErrorStr
);
655 savedErrorStr
= malloc(256);
656 snprintf((char*)savedErrorStr
, 256, "Symbol \"%s\" not in global context",symbol
);
660 /* Error reporting */
663 if (!savedErrorStr
|| !strlen(savedErrorStr
))
666 free((char*)savedErrorStr
);
667 savedErrorStr
= malloc(256);
668 snprintf((char*)savedErrorStr
, 256,"Symbol \"%s\" not found",symbol
);
672 error(savedErrorStr
);
676 debug(savedErrorStr
);
679 free((char*)savedErrorStr
);
682 return NSAddressOfSymbol(nssym
);
685 static struct dlstatus
*loadModule(const char *path
, const struct stat
*sbuf
, int mode
)
687 NSObjectFileImage ofi
= 0;
688 NSObjectFileImageReturnCode ofirc
;
689 struct dlstatus
*dls
;
690 NSLinkEditErrors ler
;
695 ofirc
= NSCreateObjectFileImageFromFile(path
, &ofi
);
698 case NSObjectFileImageSuccess
:
700 case NSObjectFileImageInappropriateFile
:
701 if (dyld_NSAddImage
&& dyld_NSIsSymbolNameDefinedInImage
&& dyld_NSLookupSymbolInImage
)
703 if (!isFlagSet(mode
, RTLD_GLOBAL
))
705 warning("trying to open a .dylib with RTLD_LOCAL");
706 error("unable to open this file with RTLD_LOCAL");
712 error("opening this file is unsupported on this system");
716 case NSObjectFileImageFailure
:
717 error("object file setup failure");
719 case NSObjectFileImageArch
:
720 error("no object for this architecture");
722 case NSObjectFileImageFormat
:
723 error("bad object file format");
725 case NSObjectFileImageAccess
:
726 error("can't read object file");
729 error("unknown error from NSCreateObjectFileImageFromFile()");
732 dls
= lookupStatus(sbuf
);
739 error("unable to allocate memory");
743 if (ofirc
== NSObjectFileImageInappropriateFile
)
745 if ((dls
->lib
= dyld_NSAddImage(path
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
)))
747 debug("Dynamic lib loaded at %ld", dls
->lib
);
748 ofi
= MAGIC_DYLIB_OFI
;
749 dls
->module
= MAGIC_DYLIB_MOD
;
750 ofirc
= NSObjectFileImageSuccess
;
751 /* Although it is possible with a bit of work to modify this so it works and
752 functions with RTLD_NOW, I don't deem it necessary at the moment */
756 NSLinkEditError(&ler
, &lerno
, &file
, &errstr
);
757 if (!errstr
|| (!strlen(errstr
)))
758 error("Can't open this file type");
761 if ((dls
->flags
& DL_IN_LIST
) == 0)
770 dls
->module
= NSLinkModule(ofi
, path
,
771 NSLINKMODULE_OPTION_RETURN_ON_ERROR
|
772 NSLINKMODULE_OPTION_PRIVATE
|
773 (isFlagSet(mode
, RTLD_NOW
) ? NSLINKMODULE_OPTION_BINDNOW
: 0));
774 NSDestroyObjectFileImage(ofi
);
777 dls
->lib
= get_mach_header_from_NSModule(dls
->module
);
782 NSLinkEditError(&ler
, &lerno
, &file
, &errstr
);
783 if ((dls
->flags
& DL_IN_LIST
) == 0)
791 insertStatus(dls
, sbuf
);
792 dls
= reference(dls
, mode
);
793 if ((init
= dlsymIntern(dls
, "__init", 0)))
795 debug("calling _init()");
801 static void dlcompat_init_func(void)
803 static int inited
= 0;
807 _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage
);
808 _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
809 (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage
);
810 _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage
);
811 if (pthread_mutex_init(&dlcompat_mutex
, NULL
))
813 if (pthread_key_create(&dlerror_key
, &dlerrorfree
))
815 /* And be neat and tidy and clean up after ourselves */
816 atexit(dlcompat_cleanup
);
821 #pragma CALL_ON_LOAD dlcompat_init_func
824 static void dlcompat_cleanup(void)
826 struct dlstatus
*dls
;
827 struct dlstatus
*next
;
829 data
= (char *)searchList();
832 data
= (char *)getSearchPath(-1);
835 pthread_mutex_destroy(&dlcompat_mutex
);
836 pthread_key_delete(dlerror_key
);
838 while (next
&& (next
!= &mainStatus
))
846 static void resetdlerror()
848 struct dlthread
*tss
;
849 tss
= pthread_getspecific(dlerror_key
);
853 static void dlerrorfree(void *data
)
858 /* We kind of want a recursive lock here, but meet a little trouble
859 * because they are not available pre OS X 10.2, so we fake it
860 * using thread specific storage to keep a lock count
862 static inline void dolock(void)
865 struct dlthread
*tss
;
866 tss
= pthread_getspecific(dlerror_key
);
869 tss
= malloc(sizeof(struct dlthread
));
872 if (pthread_setspecific(dlerror_key
, tss
))
874 fprintf(stderr
,"dlcompat: pthread_setspecific failed\n");
879 err
= pthread_mutex_lock(&dlcompat_mutex
);
880 tss
->lockcnt
= tss
->lockcnt
+1;
885 static inline void dounlock(void)
888 struct dlthread
*tss
;
889 tss
= pthread_getspecific(dlerror_key
);
890 tss
->lockcnt
= tss
->lockcnt
-1;
892 err
= pthread_mutex_unlock(&dlcompat_mutex
);
897 void *dlopen(const char *path
, int mode
)
899 const struct stat
*sbuf
;
900 struct dlstatus
*dls
;
901 const char *fullPath
;
902 dlcompat_init_func(); /* Just in case */
910 if (!(sbuf
= findFile(path
, &fullPath
)))
912 error("file \"%s\" not found", path
);
915 /* Now checks that it hasn't been closed already */
916 if ((dls
= lookupStatus(sbuf
)) && (dls
->refs
> 0))
918 /* debug("status found"); */
919 dls
= reference(dls
, mode
);
923 if (isFlagSet(mode
, RTLD_NOLOAD
))
925 error("no existing handle and RTLD_NOLOAD specified");
929 if (isFlagSet(mode
, RTLD_LAZY
) && isFlagSet(mode
, RTLD_NOW
))
931 error("how can I load something both RTLD_LAZY and RTLD_NOW?");
934 dls
= loadModule(fullPath
, sbuf
, mode
);
945 void *dlsym(void * dl_restrict handle
, const char * dl_restrict symbol
)
947 int sym_len
= strlen(symbol
);
949 char *malloc_sym
= NULL
;
951 malloc_sym
= malloc(sym_len
+ 2);
954 sprintf(malloc_sym
, "_%s", symbol
);
955 value
= dlsymIntern(handle
, malloc_sym
, 1);
960 error("Unable to allocate memory");
973 void *dlsym_prepend_underscore(void *handle
, const char *symbol
)
977 answer
= dlsym_prepend_underscore_intern(handle
, symbol
);
982 static void *dlsym_prepend_underscore_intern(void *handle
, const char *symbol
)
985 * A quick and easy way for porting packages which call dlsym(handle,"sym")
986 * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
987 * this function will be called, and will add the required underscore.
989 * Note that I haven't figured out yet which should be "standard", prepend
990 * the underscore always, or not at all. These global functions need to go away
993 int sym_len
= strlen(symbol
);
995 char *malloc_sym
= NULL
;
996 malloc_sym
= malloc(sym_len
+ 2);
999 sprintf(malloc_sym
, "_%s", symbol
);
1000 value
= dlsymIntern(handle
, malloc_sym
, 1);
1005 error("Unable to allocate memory");
1010 void *dlsym_auto_underscore(void *handle
, const char *symbol
)
1014 answer
= dlsym_auto_underscore_intern(handle
, symbol
);
1019 static void *dlsym_auto_underscore_intern(void *handle
, const char *symbol
)
1021 struct dlstatus
*dls
= handle
;
1023 addr
= dlsymIntern(dls
, symbol
, 0);
1025 addr
= dlsym_prepend_underscore_intern(handle
, symbol
);
1030 void *dlsym(void * dl_restrict handle
, const char * dl_restrict symbol
)
1032 struct dlstatus
*dls
= handle
;
1035 addr
= dlsymIntern(dls
, symbol
, 1);
1041 int dlclose(void *handle
)
1043 struct dlstatus
*dls
= handle
;
1046 if (!isValidStatus(dls
))
1050 if (dls
->module
== MAGIC_DYLIB_MOD
)
1055 name
= "global context";
1059 name
= get_lib_name(dls
->lib
);
1061 warning("trying to close a .dylib!");
1062 error("Not closing \"%s\" - dynamic libraries cannot be closed", name
);
1067 error("module already closed");
1073 unsigned long options
= 0;
1074 void (*fini
) (void);
1075 if ((fini
= dlsymIntern(dls
, "__fini", 0)))
1077 debug("calling _fini()");
1081 options
|= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES
;
1084 /* Currently, if a module contains c++ static destructors and it is unloaded, we
1085 * get a segfault in atexit(), due to compiler and dynamic loader differences of
1086 * opinion, this works around that.
1087 * I really need a way to figure out from code if this is still necessary.
1089 if ((const struct section
*)NULL
!=
1090 getsectbynamefromheader(get_mach_header_from_NSModule(dls
->module
),
1091 "__DATA", "__mod_term_func"))
1093 options
|= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED
;
1096 #ifdef RTLD_NODELETE
1097 if (isFlagSet(dls
->mode
, RTLD_NODELETE
))
1098 options
|= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED
;
1100 if (!NSUnLinkModule(dls
->module
, options
))
1102 error("unable to unlink module");
1107 /* Note: the dlstatus struct dls is neither removed from the list
1108 * nor is the memory it occupies freed. This shouldn't pose a
1109 * problem in mostly all cases, though.
1119 const char *dlerror(void)
1121 struct dlthread
*tss
;
1123 tss
= pthread_getspecific(dlerror_key
);
1124 err_str
= tss
->errstr
;
1125 tss
= pthread_getspecific(dlerror_key
);
1126 if (tss
->errset
== 0)
1132 /* Given an address, return the mach_header for the image containing it
1133 * or zero if the given address is not contained in any loaded images.
1135 const struct mach_header
*image_for_address(const void *address
)
1139 unsigned long count
= _dyld_image_count();
1140 struct mach_header
*mh
= 0;
1141 struct load_command
*lc
= 0;
1142 unsigned long addr
= NULL
;
1143 for (i
= 0; i
< count
; i
++)
1145 addr
= (unsigned long)address
- _dyld_get_image_vmaddr_slide(i
);
1146 mh
= _dyld_get_image_header(i
);
1149 lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
1150 for (j
= 0; j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
))
1152 if (LC_SEGMENT
== lc
->cmd
&&
1153 addr
>= ((struct segment_command
*)lc
)->vmaddr
&&
1155 ((struct segment_command
*)lc
)->vmaddr
+ ((struct segment_command
*)lc
)->vmsize
)
1167 int dladdr(const void * dl_restrict p
, Dl_info
* dl_restrict info
)
1170 FIXME: USe the routine image_for_address.
1174 unsigned long count
= _dyld_image_count();
1175 struct mach_header
*mh
= 0;
1176 struct load_command
*lc
= 0;
1177 unsigned long addr
= NULL
;
1178 unsigned long table_off
= (unsigned long)0;
1184 info
->dli_fname
= 0;
1185 info
->dli_fbase
= 0;
1186 info
->dli_sname
= 0;
1187 info
->dli_saddr
= 0;
1188 /* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
1189 * to darwin-development AT lists DOT apple DOT com and slightly modified
1191 for (i
= 0; i
< count
; i
++)
1193 addr
= (unsigned long)p
- _dyld_get_image_vmaddr_slide(i
);
1194 mh
= _dyld_get_image_header(i
);
1197 lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
1198 for (j
= 0; j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
))
1200 if (LC_SEGMENT
== lc
->cmd
&&
1201 addr
>= ((struct segment_command
*)lc
)->vmaddr
&&
1203 ((struct segment_command
*)lc
)->vmaddr
+ ((struct segment_command
*)lc
)->vmsize
)
1205 info
->dli_fname
= _dyld_get_image_name(i
);
1206 info
->dli_fbase
= (void *)mh
;
1220 lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
1221 for (j
= 0; j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
))
1223 if (LC_SEGMENT
== lc
->cmd
)
1225 if (!strcmp(((struct segment_command
*)lc
)->segname
, "__LINKEDIT"))
1230 ((unsigned long)((struct segment_command
*)lc
)->vmaddr
) -
1231 ((unsigned long)((struct segment_command
*)lc
)->fileoff
) + _dyld_get_image_vmaddr_slide(i
);
1232 debug("table off %x", table_off
);
1234 lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
1235 for (j
= 0; j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
))
1237 if (LC_SYMTAB
== lc
->cmd
)
1240 struct nlist
*symtable
= (struct nlist
*)(((struct symtab_command
*)lc
)->symoff
+ table_off
);
1241 unsigned long numsyms
= ((struct symtab_command
*)lc
)->nsyms
;
1242 struct nlist
*nearest
= NULL
;
1243 unsigned long diff
= 0xffffffff;
1244 unsigned long strtable
= (unsigned long)(((struct symtab_command
*)lc
)->stroff
+ table_off
);
1245 debug("symtable %x", symtable
);
1246 for (i
= 0; i
< numsyms
; i
++)
1248 /* Ignore the following kinds of Symbols */
1249 if ((!symtable
->n_value
) /* Undefined */
1250 || (symtable
->n_type
>= N_PEXT
) /* Debug symbol */
1251 || (!(symtable
->n_type
& N_EXT
)) /* Local Symbol */
1257 if ((addr
>= symtable
->n_value
) && (diff
>= (symtable
->n_value
- addr
)))
1259 diff
= (unsigned long)symtable
->n_value
- addr
;
1266 info
->dli_saddr
= nearest
->n_value
+ ((void *)p
- addr
);
1267 info
->dli_sname
= (char *)(strtable
+ nearest
->n_un
.n_strx
);
1277 * Implement the dlfunc() interface, which behaves exactly the same as
1278 * dlsym() except that it returns a function pointer instead of a data
1279 * pointer. This can be used by applications to avoid compiler warnings
1280 * about undefined behavior, and is intended as prior art for future
1281 * POSIX standardization. This function requires that all pointer types
1282 * have the same representation, which is true on all platforms FreeBSD
1283 * runs on, but is not guaranteed by the C standard.
1286 dlfunc_t
dlfunc(void * dl_restrict handle
, const char * dl_restrict symbol
)
1293 int sym_len
= strlen(symbol
);
1294 char *malloc_sym
= NULL
;
1296 malloc_sym
= malloc(sym_len
+ 2);
1299 sprintf(malloc_sym
, "_%s", symbol
);
1300 rv
.d
= dlsymIntern(handle
, malloc_sym
, 1);
1305 error("Unable to allocate memory");