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