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
|
242
|
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)
|
0
|
78 {
|
242
|
79 uint32_t i;
|
|
80 int l = -1;
|
|
81
|
|
82 /*if(pLib == RTLD_DEFAULT)
|
|
83 return NULL; @@@ return exec's path */
|
0
|
84
|
242
|
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' */
|
0
|
107 }
|
|
108
|
242
|
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
|