xref: /petsc/src/sys/dll/dlimpl.c (revision d57bb9db46f99bff4aaa690e4e9a7e55805ae415)
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
51 
52    Level: developer
53 
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   /*
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 /*@C
138    PetscDLClose -  closes a dynamic library
139 
140    Not Collective
141 
142   Input Parameter:
143 .   handle - the handle for the library obtained with PetscDLOpen()
144 
145   Level: developer
146 @*/
147 PetscErrorCode  PetscDLClose(PetscDLHandle *handle)
148 {
149 
150   PetscFunctionBegin;
151   PetscValidPointer(handle,1);
152 
153   /*
154      --- FreeLibrary ---
155   */
156 #if defined(PETSC_HAVE_WINDOWS_H)
157 #if defined(PETSC_HAVE_FREELIBRARY)
158   if (FreeLibrary((dlhandle_t)*handle) == 0) {
159 #if defined(PETSC_HAVE_GETLASTERROR)
160     char  *buff = NULL;
161     DWORD erc   = GetLastError();
162     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
163     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n",buff);
164     LocalFree(buff);
165 #else
166     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n","unavailable");
167 #endif
168   }
169 #endif /* !PETSC_HAVE_FREELIBRARY */
170 
171   /*
172      --- dclose ---
173   */
174 #elif defined(PETSC_HAVE_DLFCN_H)
175 #if defined(PETSC_HAVE_DLCLOSE)
176 #if defined(PETSC_HAVE_DLERROR)
177   dlerror(); /* clear any previous error */
178 #endif
179   if (dlclose((dlhandle_t)*handle) < 0) {
180 #if defined(PETSC_HAVE_DLERROR)
181     const char *errmsg = dlerror();
182 #else
183     const char *errmsg = "unavailable";
184 #endif
185     PetscErrorPrintf("Error closing dynamic library:\n  Error message from dlclose() %s\n", errmsg);
186   }
187 #endif /* !PETSC_HAVE_DLCLOSE */
188 
189   /*
190      --- unimplemented ---
191   */
192 #else
193   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
194 #endif
195 
196   *handle = NULL;
197   PetscFunctionReturn(0);
198 }
199 
200 /*@C
201    PetscDLSym - finds a symbol in a dynamic library
202 
203    Not Collective
204 
205    Input Parameters:
206 +   handle - obtained with PetscDLOpen() or NULL
207 -   symbol - name of symbol
208 
209    Output Parameter:
210 .   value - pointer to the function, NULL if not found
211 
212    Level: developer
213 
214   Notes:
215    If handle is NULL, the symbol is looked for in the main executable's dynamic symbol table.
216    In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
217    systems this requires platform-specific linker flags.
218 
219 @*/
220 PetscErrorCode  PetscDLSym(PetscDLHandle handle,const char symbol[],void **value)
221 {
222   PETSC_UNUSED dlhandle_t dlhandle;
223   dlsymbol_t              dlsymbol;
224 
225   PetscValidCharPointer(symbol,2);
226   PetscValidPointer(value,3);
227 
228   dlhandle = (dlhandle_t) 0;
229   dlsymbol = (dlsymbol_t) 0;
230   *value   = (void*) 0;
231 
232   /*
233      --- GetProcAddress ---
234   */
235 #if defined(PETSC_HAVE_WINDOWS_H)
236 #if defined(PETSC_HAVE_GETPROCADDRESS)
237   if (handle) dlhandle = (dlhandle_t) handle;
238   else dlhandle = (dlhandle_t) GetCurrentProcess();
239   dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol);
240 #if defined(PETSC_HAVE_SETLASTERROR)
241   SetLastError((DWORD)0); /* clear any previous error */
242 #endif
243 #endif /* !PETSC_HAVE_GETPROCADDRESS */
244 
245   /*
246      --- dlsym ---
247   */
248 #elif defined(PETSC_HAVE_DLFCN_H)
249 #if defined(PETSC_HAVE_DLSYM)
250   if (handle) dlhandle = (dlhandle_t) handle;
251   else {
252 
253 #if defined(PETSC_HAVE_DLOPEN) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
254     /* Attempt to retrieve the main executable's dlhandle. */
255     { int dlflags1 = 0, dlflags2 = 0;
256 #if defined(PETSC_HAVE_RTLD_LAZY)
257       dlflags1 = RTLD_LAZY;
258 #endif
259       if (!dlflags1) {
260 #if defined(PETSC_HAVE_RTLD_NOW)
261         dlflags1 = RTLD_NOW;
262 #endif
263       }
264 #if defined(PETSC_HAVE_RTLD_LOCAL)
265       dlflags2 = RTLD_LOCAL;
266 #endif
267       if (!dlflags2) {
268 #if defined(PETSC_HAVE_RTLD_GLOBAL)
269         dlflags2 = RTLD_GLOBAL;
270 #endif
271       }
272 #if defined(PETSC_HAVE_DLERROR)
273       if (!(PETSC_RUNNING_ON_VALGRIND)) {
274         dlerror(); /* clear any previous error; valgrind does not like this */
275       }
276 #endif
277       /* Attempt to open the main executable as a dynamic library. */
278 #if defined(PETSC_HAVE_RTDL_DEFAULT)
279       dlhandle = RTLD_DEFAULT;
280 #else
281       dlhandle = dlopen(NULL, dlflags1|dlflags2);
282 #if defined(PETSC_HAVE_DLERROR)
283       { const char *e = (const char*) dlerror();
284         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);
285       }
286 #endif
287 #endif
288     }
289 #endif
290 #endif /* PETSC_HAVE_DLOPEN && PETSC_HAVE_DYNAMIC_LIBRARIES */
291   }
292 #if defined(PETSC_HAVE_DLERROR)
293   dlerror(); /* clear any previous error */
294 #endif
295   dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol);
296   /*
297      --- unimplemented ---
298   */
299 #else
300   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
301 #endif
302 
303   *value = *((void**)&dlsymbol);
304 
305 #if defined(PETSC_SERIALIZE_FUNCTIONS)
306   if (*value) {
307     PetscErrorCode ierr;
308     ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr);
309   }
310 #endif
311   return(0);
312 }
313 
314 /*@C
315   PetscDLAddr - find the name of a symbol in a dynamic library
316 
317   Not Collective
318 
319   Input Parameters:
320 + handle - obtained with PetscDLOpen() or NULL
321 - func   - pointer to the function, NULL if not found
322 
323   Output Parameter:
324 . name   - name of symbol, or NULL if name lookup is not supported.
325 
326   Level: developer
327 
328   Notes:
329   The caller must free the returned name.
330 
331   In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
332   systems this requires platform-specific linker flags.
333 @*/
334 PetscErrorCode PetscDLAddr(void (*func)(void), char **name)
335 {
336   PetscFunctionBegin;
337   PetscValidCharPointer(name,2);
338   *name = NULL;
339 #if defined(PETSC_HAVE_DLADDR)
340   dlerror(); /* clear any previous error */
341   {
342     Dl_info        info;
343     PetscErrorCode ierr;
344 
345     ierr = dladdr(*(void **) &func, &info);if (!ierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror());
346 #ifdef PETSC_HAVE_CXX
347     ierr = PetscDemangleSymbol(info.dli_sname, name);CHKERRQ(ierr);
348 #else
349     ierr = PetscStrallocpy(info.dli_sname, name);CHKERRQ(ierr);
350 #endif
351   }
352 #endif
353   PetscFunctionReturn(0);
354 }
355