xref: /petsc/src/sys/dll/dlimpl.c (revision 7d5fd1e4d9337468ad3f05b65b7facdcd2dfd2a4)
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 #if defined(PETSC_HAVE_GETLASTERROR)
69     PetscErrorCode ierr;
70     DWORD          erc;
71     char           *buff = NULL;
72     erc = GetLastError();
73     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
74                   NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
75     ierr = PetscError(PETSC_COMM_SELF,__LINE__,PETSC_FUNCTION_NAME,__FILE__,PETSC_ERR_FILE_OPEN,PETSC_ERROR_REPEAT,
76                       "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,buff);
77     LocalFree(buff);
78     PetscFunctionReturn(ierr);
79 #else
80     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,"unavailable");
81 #endif
82   }
83 
84   /*
85      --- dlopen ---
86   */
87 #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN)
88   /*
89       Mode indicates symbols required by symbol loaded with dlsym()
90      are only loaded when required (not all together) also indicates
91      symbols required can be contained in other libraries also opened
92      with dlopen()
93   */
94 #if defined(PETSC_HAVE_RTLD_LAZY)
95   dlflags1 = RTLD_LAZY;
96 #endif
97 #if defined(PETSC_HAVE_RTLD_NOW)
98   if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW;
99 #endif
100 #if defined(PETSC_HAVE_RTLD_GLOBAL)
101   dlflags2 = RTLD_GLOBAL;
102 #endif
103 #if defined(PETSC_HAVE_RTLD_LOCAL)
104   if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL;
105 #endif
106 #if defined(PETSC_HAVE_DLERROR)
107   dlerror(); /* clear any previous error */
108 #endif
109   dlhandle = dlopen(name,dlflags1|dlflags2);
110   if (!dlhandle) {
111 #if defined(PETSC_HAVE_DLERROR)
112     const char *errmsg = dlerror();
113 #else
114     const char *errmsg = "unavailable";
115 #endif
116     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from dlopen() %s\n",name,errmsg);
117   }
118   /*
119      --- unimplemented ---
120   */
121 #else
122   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
123 #endif
124 
125   *handle = (PetscDLHandle) dlhandle;
126   PetscFunctionReturn(0);
127 }
128 
129 /*@C
130    PetscDLClose -  closes a dynamic library
131 
132    Not Collective
133 
134   Input Parameter:
135 .   handle - the handle for the library obtained with PetscDLOpen()
136 
137   Level: developer
138 
139 .seealso: PetscDLOpen(), PetscDLSym(), PetscDLAddr()
140 @*/
141 PetscErrorCode  PetscDLClose(PetscDLHandle *handle)
142 {
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         if (e) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library:\n  Error message from dlopen(): '%s'\n", 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) {
302     PetscErrorCode ierr;
303     ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr);
304   }
305 #endif
306   return(0);
307 }
308 
309 /*@C
310   PetscDLAddr - find the name of a symbol in a dynamic library
311 
312   Not Collective
313 
314   Input Parameters:
315 + handle - obtained with PetscDLOpen() or NULL
316 - func   - pointer to the function, NULL if not found
317 
318   Output Parameter:
319 . name   - name of symbol, or NULL if name lookup is not supported.
320 
321   Level: developer
322 
323   Notes:
324   The caller must free the returned name.
325 
326   In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
327   systems this requires platform-specific linker flags.
328 
329 .seealso: PetscDLClose(), PetscDLSym(), PetscDLOpen()
330 @*/
331 PetscErrorCode PetscDLAddr(void (*func)(void), char **name)
332 {
333   PetscFunctionBegin;
334   PetscValidCharPointer(name,2);
335   *name = NULL;
336 #if defined(PETSC_HAVE_DLADDR)
337   dlerror(); /* clear any previous error */
338   {
339     Dl_info        info;
340     PetscErrorCode ierr;
341 
342     ierr = dladdr(*(void **) &func, &info);if (!ierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror());
343 #ifdef PETSC_HAVE_CXX
344     ierr = PetscDemangleSymbol(info.dli_sname, name);CHKERRQ(ierr);
345 #else
346     ierr = PetscStrallocpy(info.dli_sname, name);CHKERRQ(ierr);
347 #endif
348   }
349 #endif
350   PetscFunctionReturn(0);
351 }
352