Mercurial > pub > dyncall > dyncall
diff dynload/dynload_unix.c @ 253:5cfe4322c500
- improved support for older OS versions for dynloads dlGetLibraryPath
author | Tassilo Philipp |
---|---|
date | Mon, 15 May 2017 02:50:03 +0200 |
parents | ab23f9f2934a |
children | 9d70178c1ded |
line wrap: on
line diff
--- a/dynload/dynload_unix.c Sun May 14 02:29:55 2017 +0200 +++ b/dynload/dynload_unix.c Mon May 15 02:50:03 2017 +0200 @@ -68,7 +68,9 @@ } -/* prefer RTLD_NOLOAD for code below that merely checks lib names */ + +/* for dlopen-based dlGetLibraryPath impls below, prefer RTLD_NOLOAD */ +/* that merely checks lib names */ #if defined(RTLD_NOLOAD) # define RTLD_LIGHTEST RTLD_NOLOAD #else @@ -76,8 +78,29 @@ #endif -/* code for dlGetLibraryPath differs on Darwin */ -#if defined(OS_Darwin) +/* code for dlGetLibraryPath is platform specific - if dlinfo() exists use */ +/* that (checked through existance of RTLD_DI_LINKMAP, usually a #define */ +/* for dlinfo(), or by OS (always on Solaris where it's from, usually on */ +/* Linux, where the flag might be an enum instead, ...) */ +#if defined(RTLD_DI_LINKMAP) || defined(OS_SunOS) || (defined(OS_Linux) && !defined(DL_DLADDR_TO_LIBPATH)) + +#include <link.h> + +int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) +{ + struct link_map* p; + int l = -1; + if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) { + l = strlen(p->l_name); + if(l < bufSize) /* l+'\0' <= bufSize */ + strcpy(sOut, p->l_name); + } + return l+1; /* strlen + '\0' */ +} + + +/* specific implementation needed on Darwin -----> */ +#elif defined(OS_Darwin) #include <stdint.h> #include <mach-o/dyld.h> @@ -114,9 +137,10 @@ return l+1; /* strlen + '\0' */ } -#elif defined(OS_OpenBSD) /* doesn't have dlinfo() but dl_iterate_phdr() --> */ -/* @@@ dl_iterate_phdr() only exists on OpenBSD >= 3.7 */ +/* OpenBSD >= 3.7 has dl_iterate_phdr(), use it if not explicitly requesting */ +/* to use dladdr()-based guessing (set by configure) -----> */ +#elif defined(OS_OpenBSD) && !defined(DL_DLADDR_TO_LIBPATH) #include <sys/types.h> #include <link.h> @@ -152,55 +176,21 @@ return dl_iterate_phdr(iter_phdr_cb, &d); } -#elif defined(OS_BeOS) /* neither dlinfo(), nor dl_iterate_phdr(), but ltdl stuff*/ -#if 0 -#include <ltdl.h> - -typedef struct { // @@@share - DLLib* pLib; - char* sOut; - int bufSize; -} iter_phdr_data; +/* fallback to dladdr() hack */ +#else -static int handle_map_cb(lt_dlhandle h, void* data) -{ - int l = -1; - iter_phdr_data* d = (iter_phdr_data*)data; - /* same idea as with dl_iterate_phdr, see above */ - const lt_dlinfo* dli = lt_dlgetinfo(h); - if(dli) { - void* lib = dlopen(dli->filename, RTLD_LIGHTEST); - if(lib) { - dlclose(lib); - if(lib == (void*)d->pLib) { - l = strlen(dli->filename); - if(l < d->bufSize) /* l+'\0' <= bufSize */ - strcpy(d->sOut, dli->filename); - } - } - } - return l+1; /* strlen + '\0'; is 0 if lib not found, which continues iter */ -} +/* if nothing else is available, fall back to guessing using dladdr() - this */ +/* might not always work, as it's trying to getit via the _fini() symbol, */ +/* which is usually defined in ELF files, but not guaranteed */ + +/* @@@Note: On some platforms this might be improved, e.g. on BeOS we have */ +/* lt_dlgetinfo, which requires iterating over ltdl stuff, but was unable */ +/* to get that to work (would also introduce a link dependency on libltdl) */ int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) { - iter_phdr_data d = { pLib, sOut, bufSize }; - lt_dlinterface_id ii = lt_dlinterface_register("not_sure_here...", NULL); - int l = lt_dlhandle_map(ii, handle_map_cb, &d); - lt_dlinterface_free(ii); - return l; -} -#endif - -/* we have lt_dlgetinfo on BeOS, which requires iterating over ltdl stuff, */ -/* but was unable to get that to work (would also have introduced a link */ -/* dependency on libltdl); so do a hacky dladdr() based attempt, instead, */ -/* which might not always work, but probably is ok for nearly all libs */ - -int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) -{ - /* BeOS uses ELF, cross fingers that .so is standard and look for _fini */ + /* cross fingers that shared object is standard ELF and look for _fini */ int l = -1; void* s = dlsym((void*)pLib, "_fini"); if(s) { @@ -214,21 +204,5 @@ return l+1; /* strlen + '\0' */ } -#else /* use dlinfo() --> */ - -#include <link.h> - -int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) -{ - struct link_map* p; - int l = -1; - if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) { - l = strlen(p->l_name); - if(l < bufSize) /* l+'\0' <= bufSize */ - strcpy(sOut, p->l_name); - } - return l+1; /* strlen + '\0' */ -} - #endif