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