Mercurial > pub > dyncall > dyncall
comparison 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 |
comparison
equal
deleted
inserted
replaced
252:047d2829bdf6 | 253:5cfe4322c500 |
---|---|
66 if(pLib) | 66 if(pLib) |
67 dlclose((void*)pLib); | 67 dlclose((void*)pLib); |
68 } | 68 } |
69 | 69 |
70 | 70 |
71 /* prefer RTLD_NOLOAD for code below that merely checks lib names */ | 71 |
72 /* for dlopen-based dlGetLibraryPath impls below, prefer RTLD_NOLOAD */ | |
73 /* that merely checks lib names */ | |
72 #if defined(RTLD_NOLOAD) | 74 #if defined(RTLD_NOLOAD) |
73 # define RTLD_LIGHTEST RTLD_NOLOAD | 75 # define RTLD_LIGHTEST RTLD_NOLOAD |
74 #else | 76 #else |
75 # define RTLD_LIGHTEST RTLD_LAZY | 77 # define RTLD_LIGHTEST RTLD_LAZY |
76 #endif | 78 #endif |
77 | 79 |
78 | 80 |
79 /* code for dlGetLibraryPath differs on Darwin */ | 81 /* code for dlGetLibraryPath is platform specific - if dlinfo() exists use */ |
80 #if defined(OS_Darwin) | 82 /* that (checked through existance of RTLD_DI_LINKMAP, usually a #define */ |
83 /* for dlinfo(), or by OS (always on Solaris where it's from, usually on */ | |
84 /* Linux, where the flag might be an enum instead, ...) */ | |
85 #if defined(RTLD_DI_LINKMAP) || defined(OS_SunOS) || (defined(OS_Linux) && !defined(DL_DLADDR_TO_LIBPATH)) | |
86 | |
87 #include <link.h> | |
88 | |
89 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) | |
90 { | |
91 struct link_map* p; | |
92 int l = -1; | |
93 if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) { | |
94 l = strlen(p->l_name); | |
95 if(l < bufSize) /* l+'\0' <= bufSize */ | |
96 strcpy(sOut, p->l_name); | |
97 } | |
98 return l+1; /* strlen + '\0' */ | |
99 } | |
100 | |
101 | |
102 /* specific implementation needed on Darwin -----> */ | |
103 #elif defined(OS_Darwin) | |
81 | 104 |
82 #include <stdint.h> | 105 #include <stdint.h> |
83 #include <mach-o/dyld.h> | 106 #include <mach-o/dyld.h> |
84 | 107 |
85 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) | 108 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) |
112 } | 135 } |
113 | 136 |
114 return l+1; /* strlen + '\0' */ | 137 return l+1; /* strlen + '\0' */ |
115 } | 138 } |
116 | 139 |
117 #elif defined(OS_OpenBSD) /* doesn't have dlinfo() but dl_iterate_phdr() --> */ | 140 |
118 | 141 /* OpenBSD >= 3.7 has dl_iterate_phdr(), use it if not explicitly requesting */ |
119 /* @@@ dl_iterate_phdr() only exists on OpenBSD >= 3.7 */ | 142 /* to use dladdr()-based guessing (set by configure) -----> */ |
143 #elif defined(OS_OpenBSD) && !defined(DL_DLADDR_TO_LIBPATH) | |
120 | 144 |
121 #include <sys/types.h> | 145 #include <sys/types.h> |
122 #include <link.h> | 146 #include <link.h> |
123 | 147 |
124 typedef struct { | 148 typedef struct { |
150 { | 174 { |
151 iter_phdr_data d = { pLib, sOut, bufSize }; | 175 iter_phdr_data d = { pLib, sOut, bufSize }; |
152 return dl_iterate_phdr(iter_phdr_cb, &d); | 176 return dl_iterate_phdr(iter_phdr_cb, &d); |
153 } | 177 } |
154 | 178 |
155 #elif defined(OS_BeOS) /* neither dlinfo(), nor dl_iterate_phdr(), but ltdl stuff*/ | 179 |
156 | 180 /* fallback to dladdr() hack */ |
157 #if 0 | 181 #else |
158 #include <ltdl.h> | 182 |
159 | 183 /* if nothing else is available, fall back to guessing using dladdr() - this */ |
160 typedef struct { // @@@share | 184 /* might not always work, as it's trying to getit via the _fini() symbol, */ |
161 DLLib* pLib; | 185 /* which is usually defined in ELF files, but not guaranteed */ |
162 char* sOut; | 186 |
163 int bufSize; | 187 /* @@@Note: On some platforms this might be improved, e.g. on BeOS we have */ |
164 } iter_phdr_data; | 188 /* lt_dlgetinfo, which requires iterating over ltdl stuff, but was unable */ |
165 | 189 /* to get that to work (would also introduce a link dependency on libltdl) */ |
166 static int handle_map_cb(lt_dlhandle h, void* data) | 190 |
167 { | 191 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) |
168 int l = -1; | 192 { |
169 iter_phdr_data* d = (iter_phdr_data*)data; | 193 /* cross fingers that shared object is standard ELF and look for _fini */ |
170 /* same idea as with dl_iterate_phdr, see above */ | |
171 const lt_dlinfo* dli = lt_dlgetinfo(h); | |
172 if(dli) { | |
173 void* lib = dlopen(dli->filename, RTLD_LIGHTEST); | |
174 if(lib) { | |
175 dlclose(lib); | |
176 if(lib == (void*)d->pLib) { | |
177 l = strlen(dli->filename); | |
178 if(l < d->bufSize) /* l+'\0' <= bufSize */ | |
179 strcpy(d->sOut, dli->filename); | |
180 } | |
181 } | |
182 } | |
183 return l+1; /* strlen + '\0'; is 0 if lib not found, which continues iter */ | |
184 } | |
185 | |
186 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) | |
187 { | |
188 iter_phdr_data d = { pLib, sOut, bufSize }; | |
189 lt_dlinterface_id ii = lt_dlinterface_register("not_sure_here...", NULL); | |
190 int l = lt_dlhandle_map(ii, handle_map_cb, &d); | |
191 lt_dlinterface_free(ii); | |
192 return l; | |
193 } | |
194 #endif | |
195 | |
196 /* we have lt_dlgetinfo on BeOS, which requires iterating over ltdl stuff, */ | |
197 /* but was unable to get that to work (would also have introduced a link */ | |
198 /* dependency on libltdl); so do a hacky dladdr() based attempt, instead, */ | |
199 /* which might not always work, but probably is ok for nearly all libs */ | |
200 | |
201 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) | |
202 { | |
203 /* BeOS uses ELF, cross fingers that .so is standard and look for _fini */ | |
204 int l = -1; | 194 int l = -1; |
205 void* s = dlsym((void*)pLib, "_fini"); | 195 void* s = dlsym((void*)pLib, "_fini"); |
206 if(s) { | 196 if(s) { |
207 Dl_info i; | 197 Dl_info i; |
208 if(dladdr(s, &i) != 0) { | 198 if(dladdr(s, &i) != 0) { |
212 } | 202 } |
213 } | 203 } |
214 return l+1; /* strlen + '\0' */ | 204 return l+1; /* strlen + '\0' */ |
215 } | 205 } |
216 | 206 |
217 #else /* use dlinfo() --> */ | |
218 | |
219 #include <link.h> | |
220 | |
221 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) | |
222 { | |
223 struct link_map* p; | |
224 int l = -1; | |
225 if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) { | |
226 l = strlen(p->l_name); | |
227 if(l < bufSize) /* l+'\0' <= bufSize */ | |
228 strcpy(sOut, p->l_name); | |
229 } | |
230 return l+1; /* strlen + '\0' */ | |
231 } | |
232 | |
233 #endif | 207 #endif |
234 | 208 |