0
|
1 /*
|
|
2
|
|
3 Package: dyncall
|
|
4 Library: dynload
|
|
5 File: dynload/dynload_unix.c
|
|
6 Description:
|
|
7 License:
|
|
8
|
242
|
9 Copyright (c) 2007-2017 Daniel Adler <dadler@uni-goettingen.de>,
|
0
|
10 Tassilo Philipp <tphilipp@potion-studios.com>
|
|
11
|
|
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
|
|
14 copyright notice and this permission notice appear in all copies.
|
|
15
|
|
16 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
17 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
18 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
19 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
21 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
23
|
|
24 */
|
|
25
|
|
26
|
|
27 /*
|
|
28
|
|
29 dynload_unix.c
|
|
30
|
|
31 dynload module for .so (unix) and .dylib (mach-o darwin/OS X) files
|
|
32
|
|
33 */
|
|
34
|
|
35
|
|
36 #include "dynload.h"
|
242
|
37 #include "../autovar/autovar_OS.h"
|
0
|
38
|
242
|
39 #include <string.h>
|
|
40
|
|
41 #if defined(__GLIBC__) /* to access dlinfo */
|
|
42 # define _GNU_SOURCE
|
|
43 # define __USE_GNU
|
|
44 #endif
|
0
|
45 #include <dlfcn.h>
|
|
46
|
|
47
|
|
48 DLLib* dlLoadLibrary(const char* libPath)
|
|
49 {
|
232
|
50 return (DLLib*)dlopen(libPath, RTLD_NOW|RTLD_GLOBAL); //@@@ should use RTLD_LAZY, maybe?
|
0
|
51 }
|
|
52
|
|
53
|
242
|
54 void* dlFindSymbol(DLLib* pLib, const char* pSymbolName)
|
0
|
55 {
|
242
|
56 return dlsym((void*)pLib, pSymbolName);
|
|
57 }
|
|
58
|
|
59
|
|
60 void dlFreeLibrary(DLLib* pLib)
|
|
61 {
|
|
62 /* Check for NULL for cross-platform consistency. *BSD seems to do that in
|
|
63 dlclose, Linux does not. POSIX states "if handle does not refer to an open
|
|
64 object, dlclose() returns a non-zero value", which unfortunately sounds
|
|
65 like it's not explicitly specified. */
|
|
66 if(pLib)
|
|
67 dlclose((void*)pLib);
|
0
|
68 }
|
|
69
|
|
70
|
246
|
71 /* prefer RTLD_NOLOAD for code below that merely checks lib names */
|
|
72 #if defined(RTLD_NOLOAD)
|
|
73 # define RTLD_LIGHTEST RTLD_NOLOAD
|
|
74 #else
|
|
75 # define RTLD_LIGHTEST RTLD_LAZY
|
|
76 #endif
|
|
77
|
|
78
|
242
|
79 /* code for dlGetLibraryPath differs on Darwin */
|
|
80 #if defined(OS_Darwin)
|
|
81
|
|
82 #include <stdint.h>
|
|
83 #include <mach-o/dyld.h>
|
|
84
|
|
85 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
0
|
86 {
|
242
|
87 uint32_t i;
|
|
88 int l = -1;
|
|
89
|
|
90 /*if(pLib == RTLD_DEFAULT)
|
|
91 return NULL; @@@ return exec's path */
|
0
|
92
|
242
|
93 /* Darwin's code doesn't come with (non-standard) dlinfo(), so use dyld(1) */
|
|
94 /* code. There doesn't seem to be a direct way to query the library path, */
|
|
95 /* so "double-load" temporarily all already loaded images (just increases */
|
|
96 /* ref count) and compare handles until we found ours. Return the name. */
|
|
97 for(i=_dyld_image_count(); i>0;) /* iterate libs from end, more likely ours */
|
|
98 {
|
|
99 const char* libPath = _dyld_get_image_name(--i);
|
246
|
100 void* lib = dlopen(libPath, RTLD_LIGHTEST);
|
242
|
101 if(lib) {
|
246
|
102 dlclose(lib);
|
|
103 /* compare handle pointers' high bits (in low 2 bits some flags might */
|
|
104 /* be stored - should be safe b/c address needs alignment, anywas) */
|
|
105 if(((intptr_t)pLib ^ (intptr_t)lib) < 4) {
|
242
|
106 l = strlen(libPath);
|
|
107 if(l < bufSize) /* l+'\0' <= bufSize */
|
|
108 strcpy(sOut, libPath);
|
|
109 break;
|
|
110 }
|
|
111 }
|
|
112 }
|
|
113
|
|
114 return l+1; /* strlen + '\0' */
|
0
|
115 }
|
|
116
|
242
|
117 #else /* non-Darwin --> */
|
|
118
|
|
119 #if defined(OS_OpenBSD) /* doesn't have dlinfo() but dl_iterate_phdr() --> */
|
|
120
|
|
121 /* @@@ dl_iterate_phdr() only exists on OpenBSD >= 3.7 */
|
|
122
|
|
123 #include <sys/types.h>
|
|
124 #include <link.h>
|
|
125
|
|
126 typedef struct {
|
|
127 DLLib* pLib;
|
|
128 char* sOut;
|
|
129 int bufSize;
|
|
130 } iter_phdr_data;
|
|
131
|
|
132 static int iter_phdr_cb(struct dl_phdr_info* info, size_t size, void* data)
|
|
133 {
|
|
134 int l = -1;
|
|
135 iter_phdr_data* d = (iter_phdr_data*)data;
|
|
136 /* unable to relate info->dlpi_addr directly to our dlopen handle, let's */
|
|
137 /* do what we do on macOS above, re-dlopen the already loaded lib (just */
|
|
138 /* increases ref count) and compare handles. */
|
246
|
139 void* lib = dlopen(info->dlpi_name, RTLD_LIGHTEST);
|
242
|
140 if(lib) {
|
246
|
141 dlclose(lib);
|
|
142 if(lib == (void*)d->pLib) {
|
242
|
143 l = strlen(info->dlpi_name);
|
|
144 if(l < d->bufSize) /* l+'\0' <= bufSize */
|
|
145 strcpy(d->sOut, info->dlpi_name);
|
|
146 }
|
|
147 }
|
|
148 return l+1; /* strlen + '\0'; is 0 if lib not found, which continues iter */
|
|
149 }
|
|
150
|
|
151 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
|
152 {
|
|
153 iter_phdr_data d = { pLib, sOut, bufSize };
|
|
154 return dl_iterate_phdr(iter_phdr_cb, &d);
|
|
155 }
|
|
156
|
|
157 #else /* use dlinfo() --> */
|
|
158
|
|
159 #include <link.h>
|
|
160
|
|
161 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
|
|
162 {
|
|
163 struct link_map* p;
|
|
164 int l = -1;
|
|
165 if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) {
|
|
166 l = strlen(p->l_name);
|
|
167 if(l < bufSize) /* l+'\0' <= bufSize */
|
|
168 strcpy(sOut, p->l_name);
|
|
169 }
|
|
170 return l+1; /* strlen + '\0' */
|
|
171 }
|
|
172
|
|
173 #endif
|
|
174
|
|
175 #endif
|
|
176
|