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