xref: /petsc/src/sys/dll/dlimpl.c (revision ef46b1a67e276116c83b5d4ce8efc2932ea4fc0a)
1 /*
2    Low-level routines for managing dynamic link libraries (DLLs).
3 */
4 
5 #include <petscconf.h>
6 #if defined(PETSC__GNU_SOURCE)
7   #if !defined(_GNU_SOURCE)
8     #define _GNU_SOURCE 1
9   #endif
10 #endif
11 
12 #include <petsc/private/petscimpl.h>
13 
14 #if defined(PETSC_HAVE_WINDOWS_H)
15 #include <windows.h>
16 #endif
17 #if defined(PETSC_HAVE_DLFCN_H)
18 #include <dlfcn.h>
19 #endif
20 
21 #if defined(PETSC_HAVE_WINDOWS_H)
22 typedef HMODULE dlhandle_t;
23 typedef FARPROC dlsymbol_t;
24 #elif defined(PETSC_HAVE_DLFCN_H)
25 typedef void* dlhandle_t;
26 typedef void* dlsymbol_t;
27 #else
28 typedef void* dlhandle_t;
29 typedef void* dlsymbol_t;
30 #endif
31 
32 /*@C
33    PetscDLOpen - opens dynamic library
34 
35    Not Collective
36 
37    Input Parameters:
38 +    name - name of library
39 -    mode - options on how to open library
40 
41    Output Parameter:
42 .    handle - opaque pointer to be used with PetscDLSym()
43 
44    Level: developer
45 
46 .seealso: PetscDLClose(), PetscDLSym(), PetscDLAddr()
47 @*/
48 PetscErrorCode  PetscDLOpen(const char name[],PetscDLMode mode,PetscDLHandle *handle)
49 {
50   PETSC_UNUSED int dlflags1,dlflags2; /* There are some preprocessor paths where these variables are set, but not used */
51   dlhandle_t       dlhandle;
52 
53   PetscFunctionBegin;
54   PetscValidCharPointer(name,1);
55   PetscValidPointer(handle,3);
56 
57   dlflags1 = 0;
58   dlflags2 = 0;
59   dlhandle = (dlhandle_t) 0;
60   *handle  = (PetscDLHandle) 0;
61 
62   /*
63      --- LoadLibrary ---
64   */
65 #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_LOADLIBRARY)
66   dlhandle = LoadLibrary(name);
67   if (!dlhandle) {
68     /* TODO: Seem to need fixing, why not just return with an error with SETERRQ() */
69 #if defined(PETSC_HAVE_GETLASTERROR)
70     PetscErrorCode ierr;
71     DWORD          erc;
72     char           *buff = NULL;
73     erc = GetLastError();
74     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
75                   NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
76     ierr = PetscError(PETSC_COMM_SELF,__LINE__,PETSC_FUNCTION_NAME,__FILE__,PETSC_ERR_FILE_OPEN,PETSC_ERROR_REPEAT,
77                       "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,buff);
78     LocalFree(buff);
79     PetscFunctionReturn(ierr);
80 #else
81     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s",name,"unavailable");
82 #endif
83   }
84 
85   /*
86      --- dlopen ---
87   */
88 #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN)
89   /*
90       Mode indicates symbols required by symbol loaded with dlsym()
91      are only loaded when required (not all together) also indicates
92      symbols required can be contained in other libraries also opened
93      with dlopen()
94   */
95 #if defined(PETSC_HAVE_RTLD_LAZY)
96   dlflags1 = RTLD_LAZY;
97 #endif
98 #if defined(PETSC_HAVE_RTLD_NOW)
99   if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW;
100 #endif
101 #if defined(PETSC_HAVE_RTLD_GLOBAL)
102   dlflags2 = RTLD_GLOBAL;
103 #endif
104 #if defined(PETSC_HAVE_RTLD_LOCAL)
105   if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL;
106 #endif
107 #if defined(PETSC_HAVE_DLERROR)
108   dlerror(); /* clear any previous error */
109 #endif
110   dlhandle = dlopen(name,dlflags1|dlflags2);
111   if (!dlhandle) {
112 #if defined(PETSC_HAVE_DLERROR)
113     const char *errmsg = dlerror();
114 #else
115     const char *errmsg = "unavailable";
116 #endif
117     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from dlopen() %s",name,errmsg);
118   }
119   /*
120      --- unimplemented ---
121   */
122 #else
123   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
124 #endif
125 
126   *handle = (PetscDLHandle) dlhandle;
127   PetscFunctionReturn(0);
128 }
129 
130 /*@C
131    PetscDLClose -  closes a dynamic library
132 
133    Not Collective
134 
135   Input Parameter:
136 .   handle - the handle for the library obtained with PetscDLOpen()
137 
138   Level: developer
139 
140 .seealso: PetscDLOpen(), PetscDLSym(), PetscDLAddr()
141 @*/
142 PetscErrorCode  PetscDLClose(PetscDLHandle *handle)
143 {
144   PetscFunctionBegin;
145   PetscValidPointer(handle,1);
146 
147   /*
148      --- FreeLibrary ---
149   */
150 #if defined(PETSC_HAVE_WINDOWS_H)
151 #if defined(PETSC_HAVE_FREELIBRARY)
152   if (FreeLibrary((dlhandle_t)*handle) == 0) {
153 #if defined(PETSC_HAVE_GETLASTERROR)
154     char  *buff = NULL;
155     DWORD erc   = GetLastError();
156     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
157     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n",buff);
158     LocalFree(buff);
159 #else
160     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n","unavailable");
161 #endif
162   }
163 #endif /* !PETSC_HAVE_FREELIBRARY */
164 
165   /*
166      --- dclose ---
167   */
168 #elif defined(PETSC_HAVE_DLFCN_H)
169 #if defined(PETSC_HAVE_DLCLOSE)
170 #if defined(PETSC_HAVE_DLERROR)
171   dlerror(); /* clear any previous error */
172 #endif
173   if (dlclose((dlhandle_t)*handle) < 0) {
174 #if defined(PETSC_HAVE_DLERROR)
175     const char *errmsg = dlerror();
176 #else
177     const char *errmsg = "unavailable";
178 #endif
179     PetscErrorPrintf("Error closing dynamic library:\n  Error message from dlclose() %s\n", errmsg);
180   }
181 #endif /* !PETSC_HAVE_DLCLOSE */
182 
183   /*
184      --- unimplemented ---
185   */
186 #else
187   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
188 #endif
189 
190   *handle = NULL;
191   PetscFunctionReturn(0);
192 }
193 
194 /*@C
195    PetscDLSym - finds a symbol in a dynamic library
196 
197    Not Collective
198 
199    Input Parameters:
200 +   handle - obtained with PetscDLOpen() or NULL
201 -   symbol - name of symbol
202 
203    Output Parameter:
204 .   value - pointer to the function, NULL if not found
205 
206    Level: developer
207 
208   Notes:
209    If handle is NULL, the symbol is looked for in the main executable's dynamic symbol table.
210    In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
211    systems this requires platform-specific linker flags.
212 
213 .seealso: PetscDLClose(), PetscDLOpen(), PetscDLAddr()
214 @*/
215 PetscErrorCode  PetscDLSym(PetscDLHandle handle,const char symbol[],void **value)
216 {
217   PETSC_UNUSED dlhandle_t dlhandle;
218   dlsymbol_t              dlsymbol;
219 
220   PetscValidCharPointer(symbol,2);
221   PetscValidPointer(value,3);
222 
223   dlhandle = (dlhandle_t) 0;
224   dlsymbol = (dlsymbol_t) 0;
225   *value   = (void*) 0;
226 
227   /*
228      --- GetProcAddress ---
229   */
230 #if defined(PETSC_HAVE_WINDOWS_H)
231 #if defined(PETSC_HAVE_GETPROCADDRESS)
232   if (handle) dlhandle = (dlhandle_t) handle;
233   else dlhandle = (dlhandle_t) GetCurrentProcess();
234   dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol);
235 #if defined(PETSC_HAVE_SETLASTERROR)
236   SetLastError((DWORD)0); /* clear any previous error */
237 #endif
238 #endif /* !PETSC_HAVE_GETPROCADDRESS */
239 
240   /*
241      --- dlsym ---
242   */
243 #elif defined(PETSC_HAVE_DLFCN_H)
244 #if defined(PETSC_HAVE_DLSYM)
245   if (handle) dlhandle = (dlhandle_t) handle;
246   else {
247 
248 #if defined(PETSC_HAVE_DLOPEN)
249     /* Attempt to retrieve the main executable's dlhandle. */
250     { int dlflags1 = 0, dlflags2 = 0;
251 #if defined(PETSC_HAVE_RTLD_LAZY)
252       dlflags1 = RTLD_LAZY;
253 #endif
254       if (!dlflags1) {
255 #if defined(PETSC_HAVE_RTLD_NOW)
256         dlflags1 = RTLD_NOW;
257 #endif
258       }
259 #if defined(PETSC_HAVE_RTLD_LOCAL)
260       dlflags2 = RTLD_LOCAL;
261 #endif
262       if (!dlflags2) {
263 #if defined(PETSC_HAVE_RTLD_GLOBAL)
264         dlflags2 = RTLD_GLOBAL;
265 #endif
266       }
267 #if defined(PETSC_HAVE_DLERROR)
268       if (!(PETSC_RUNNING_ON_VALGRIND)) {
269         dlerror(); /* clear any previous error; valgrind does not like this */
270       }
271 #endif
272       /* Attempt to open the main executable as a dynamic library. */
273 #if defined(PETSC_HAVE_RTDL_DEFAULT)
274       dlhandle = RTLD_DEFAULT;
275 #else
276       dlhandle = dlopen(NULL, dlflags1|dlflags2);
277 #if defined(PETSC_HAVE_DLERROR)
278       { const char *e = (const char*) dlerror();
279         PetscCheck(!e,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library:\n  Error message from dlopen(): '%s'", e);
280       }
281 #endif
282 #endif
283     }
284 #endif
285 #endif /* PETSC_HAVE_DLOPEN && PETSC_HAVE_DYNAMIC_LIBRARIES */
286   }
287 #if defined(PETSC_HAVE_DLERROR)
288   dlerror(); /* clear any previous error */
289 #endif
290   dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol);
291   /*
292      --- unimplemented ---
293   */
294 #else
295   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
296 #endif
297 
298   *value = *((void**)&dlsymbol);
299 
300 #if defined(PETSC_SERIALIZE_FUNCTIONS)
301   if (*value) PetscCall(PetscFPTAdd(*value,symbol));
302 #endif
303   return(0);
304 }
305 
306 /*@C
307   PetscDLAddr - find the name of a symbol in a dynamic library
308 
309   Not Collective
310 
311   Input Parameters:
312 + handle - obtained with PetscDLOpen() or NULL
313 - func   - pointer to the function, NULL if not found
314 
315   Output Parameter:
316 . name   - name of symbol, or NULL if name lookup is not supported.
317 
318   Level: developer
319 
320   Notes:
321   The caller must free the returned name.
322 
323   In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
324   systems this requires platform-specific linker flags.
325 
326 .seealso: PetscDLClose(), PetscDLSym(), PetscDLOpen()
327 @*/
328 PetscErrorCode PetscDLAddr(void (*func)(void), char **name)
329 {
330   PetscFunctionBegin;
331   PetscValidPointer(name,2);
332   *name = NULL;
333 #if defined(PETSC_HAVE_DLADDR)
334   dlerror(); /* clear any previous error */
335   {
336     Dl_info info;
337 
338     PetscCheck(dladdr(*(void **) &func, &info),PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror());
339 #ifdef PETSC_HAVE_CXX
340     PetscCall(PetscDemangleSymbol(info.dli_sname, name));
341 #else
342     PetscCall(PetscStrallocpy(info.dli_sname, name));
343 #endif
344   }
345 #endif
346   PetscFunctionReturn(0);
347 }
348