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