Mercurial > pub > dyncall > dyncall
comparison dynload/dynload_unix.c @ 242:85b61e8facfe
dynload:
- added new function dlGetLibraryPath to get path of already loaded lib
- covered new function in dynload_plain test
- cleanups/cosmetics for consistency
author | Tassilo Philipp |
---|---|
date | Thu, 04 May 2017 13:42:17 +0200 |
parents | 76ed51a690a6 |
children | 0ba6189a51dd |
comparison
equal
deleted
inserted
replaced
241:cde7b1f3b8f2 | 242:85b61e8facfe |
---|---|
4 Library: dynload | 4 Library: dynload |
5 File: dynload/dynload_unix.c | 5 File: dynload/dynload_unix.c |
6 Description: | 6 Description: |
7 License: | 7 License: |
8 | 8 |
9 Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>, | 9 Copyright (c) 2007-2017 Daniel Adler <dadler@uni-goettingen.de>, |
10 Tassilo Philipp <tphilipp@potion-studios.com> | 10 Tassilo Philipp <tphilipp@potion-studios.com> |
11 | 11 |
12 Permission to use, copy, modify, and distribute this software for any | 12 Permission to use, copy, modify, and distribute this software for any |
13 purpose with or without fee is hereby granted, provided that the above | 13 purpose with or without fee is hereby granted, provided that the above |
14 copyright notice and this permission notice appear in all copies. | 14 copyright notice and this permission notice appear in all copies. |
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
23 | 23 |
24 */ | 24 */ |
25 | 25 |
26 | 26 |
27 | |
28 /* | 27 /* |
29 | 28 |
30 dynload_unix.c | 29 dynload_unix.c |
31 | 30 |
32 dynload module for .so (unix) and .dylib (mach-o darwin/OS X) files | 31 dynload module for .so (unix) and .dylib (mach-o darwin/OS X) files |
33 | 32 |
34 */ | 33 */ |
35 | 34 |
36 | 35 |
37 #include "dynload.h" | 36 #include "dynload.h" |
37 #include "../autovar/autovar_OS.h" | |
38 | 38 |
39 #include <string.h> | |
40 | |
41 #if defined(__GLIBC__) /* to access dlinfo */ | |
42 # define _GNU_SOURCE | |
43 # define __USE_GNU | |
44 #endif | |
39 #include <dlfcn.h> | 45 #include <dlfcn.h> |
40 | 46 |
41 | 47 |
42 DLLib* dlLoadLibrary(const char* libPath) | 48 DLLib* dlLoadLibrary(const char* libPath) |
43 { | 49 { |
44 return (DLLib*)dlopen(libPath, RTLD_NOW|RTLD_GLOBAL); //@@@ should use RTLD_LAZY, maybe? | 50 return (DLLib*)dlopen(libPath, RTLD_NOW|RTLD_GLOBAL); //@@@ should use RTLD_LAZY, maybe? |
45 } | 51 } |
46 | 52 |
47 | 53 |
48 void* dlFindSymbol(DLLib* libHandle, const char* symbol) | 54 void* dlFindSymbol(DLLib* pLib, const char* pSymbolName) |
49 { | 55 { |
50 return dlsym((void*)libHandle, symbol); | 56 return dlsym((void*)pLib, pSymbolName); |
51 } | 57 } |
52 | 58 |
53 | 59 |
54 void dlFreeLibrary(DLLib* libHandle) | 60 void dlFreeLibrary(DLLib* pLib) |
55 { | 61 { |
56 | |
57 /* Check for NULL for cross-platform consistency. *BSD seems to do that in | 62 /* Check for NULL for cross-platform consistency. *BSD seems to do that in |
58 dlclose, Linux does not. POSIX states "if handle does not refer to an open | 63 dlclose, Linux does not. POSIX states "if handle does not refer to an open |
59 object, dlclose() returns a non-zero value", which unfortunately sounds | 64 object, dlclose() returns a non-zero value", which unfortunately sounds |
60 like it's not explicitly specified. */ | 65 like it's not explicitly specified. */ |
61 if(libHandle) | 66 if(pLib) |
62 dlclose((void*)libHandle); | 67 dlclose((void*)pLib); |
63 } | 68 } |
64 | 69 |
70 | |
71 /* code for dlGetLibraryPath differs on Darwin */ | |
72 #if defined(OS_Darwin) | |
73 | |
74 #include <stdint.h> | |
75 #include <mach-o/dyld.h> | |
76 | |
77 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) | |
78 { | |
79 uint32_t i; | |
80 int l = -1; | |
81 | |
82 /*if(pLib == RTLD_DEFAULT) | |
83 return NULL; @@@ return exec's path */ | |
84 | |
85 /* Darwin's code doesn't come with (non-standard) dlinfo(), so use dyld(1) */ | |
86 /* code. There doesn't seem to be a direct way to query the library path, */ | |
87 /* so "double-load" temporarily all already loaded images (just increases */ | |
88 /* ref count) and compare handles until we found ours. Return the name. */ | |
89 for(i=_dyld_image_count(); i>0;) /* iterate libs from end, more likely ours */ | |
90 { | |
91 const char* libPath = _dyld_get_image_name(--i); | |
92 void* lib = dlopen(libPath, RTLD_LAZY); | |
93 if(lib) { | |
94 dlclose(lib); | |
95 /* compare handle pointers' high bits (in low 2 bits some flags might */ | |
96 /* be stored - should be safe b/c address needs alignment, anywas) */ | |
97 if(((intptr_t)pLib ^ (intptr_t)lib) < 4) { | |
98 l = strlen(libPath); | |
99 if(l < bufSize) /* l+'\0' <= bufSize */ | |
100 strcpy(sOut, libPath); | |
101 break; | |
102 } | |
103 } | |
104 } | |
105 | |
106 return l+1; /* strlen + '\0' */ | |
107 } | |
108 | |
109 #else /* non-Darwin --> */ | |
110 | |
111 #if defined(OS_OpenBSD) /* doesn't have dlinfo() but dl_iterate_phdr() --> */ | |
112 | |
113 /* @@@ dl_iterate_phdr() only exists on OpenBSD >= 3.7 */ | |
114 | |
115 #include <sys/types.h> | |
116 #include <link.h> | |
117 | |
118 typedef struct { | |
119 DLLib* pLib; | |
120 char* sOut; | |
121 int bufSize; | |
122 } iter_phdr_data; | |
123 | |
124 static int iter_phdr_cb(struct dl_phdr_info* info, size_t size, void* data) | |
125 { | |
126 int l = -1; | |
127 iter_phdr_data* d = (iter_phdr_data*)data; | |
128 /* unable to relate info->dlpi_addr directly to our dlopen handle, let's */ | |
129 /* do what we do on macOS above, re-dlopen the already loaded lib (just */ | |
130 /* increases ref count) and compare handles. */ | |
131 void* lib = dlopen(info->dlpi_name, RTLD_LAZY); | |
132 if(lib) { | |
133 dlclose(lib); | |
134 if(lib == (void*)d->pLib) { | |
135 l = strlen(info->dlpi_name); | |
136 if(l < d->bufSize) /* l+'\0' <= bufSize */ | |
137 strcpy(d->sOut, info->dlpi_name); | |
138 } | |
139 } | |
140 return l+1; /* strlen + '\0'; is 0 if lib not found, which continues iter */ | |
141 } | |
142 | |
143 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) | |
144 { | |
145 iter_phdr_data d = { pLib, sOut, bufSize }; | |
146 return dl_iterate_phdr(iter_phdr_cb, &d); | |
147 } | |
148 | |
149 #else /* use dlinfo() --> */ | |
150 | |
151 #include <link.h> | |
152 | |
153 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize) | |
154 { | |
155 struct link_map* p; | |
156 int l = -1; | |
157 if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) { | |
158 l = strlen(p->l_name); | |
159 if(l < bufSize) /* l+'\0' <= bufSize */ | |
160 strcpy(sOut, p->l_name); | |
161 } | |
162 return l+1; /* strlen + '\0' */ | |
163 } | |
164 | |
165 #endif | |
166 | |
167 #endif | |
168 |