xref: /petsc/src/sys/dll/dlimpl.c (revision 2fb1d9daa8d289b4e375fe89ef72d82069342f85)
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 
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 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 @*/
221 PetscErrorCode  PetscDLSym(PetscDLHandle handle,const char symbol[],void **value)
222 {
223   PETSC_UNUSED dlhandle_t dlhandle;
224   dlsymbol_t              dlsymbol;
225 
226   PetscValidCharPointer(symbol,2);
227   PetscValidPointer(value,3);
228 
229   dlhandle = (dlhandle_t) 0;
230   dlsymbol = (dlsymbol_t) 0;
231   *value   = (void*) 0;
232 
233   /*
234      --- GetProcAddress ---
235   */
236 #if defined(PETSC_HAVE_WINDOWS_H)
237 #if defined(PETSC_HAVE_GETPROCADDRESS)
238   if (handle) dlhandle = (dlhandle_t) handle;
239   else dlhandle = (dlhandle_t) GetCurrentProcess();
240   dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol);
241 #if defined(PETSC_HAVE_SETLASTERROR)
242   SetLastError((DWORD)0); /* clear any previous error */
243 #endif
244 #endif /* !PETSC_HAVE_GETPROCADDRESS */
245 
246   /*
247      --- dlsym ---
248   */
249 #elif defined(PETSC_HAVE_DLFCN_H)
250 #if defined(PETSC_HAVE_DLSYM)
251   if (handle) dlhandle = (dlhandle_t) handle;
252   else {
253 
254 #if defined(PETSC_HAVE_DLOPEN) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
255     /* Attempt to retrieve the main executable's dlhandle. */
256     { int dlflags1 = 0, dlflags2 = 0;
257 #if defined(PETSC_HAVE_RTLD_LAZY)
258       dlflags1 = RTLD_LAZY;
259 #endif
260       if (!dlflags1) {
261 #if defined(PETSC_HAVE_RTLD_NOW)
262         dlflags1 = RTLD_NOW;
263 #endif
264       }
265 #if defined(PETSC_HAVE_RTLD_LOCAL)
266       dlflags2 = RTLD_LOCAL;
267 #endif
268       if (!dlflags2) {
269 #if defined(PETSC_HAVE_RTLD_GLOBAL)
270         dlflags2 = RTLD_GLOBAL;
271 #endif
272       }
273 #if defined(PETSC_HAVE_DLERROR)
274       if (!(PETSC_RUNNING_ON_VALGRIND)) {
275         dlerror(); /* clear any previous error; valgrind does not like this */
276       }
277 #endif
278       /* Attempt to open the main executable as a dynamic library. */
279 #if defined(PETSC_HAVE_RTDL_DEFAULT)
280       dlhandle = RTLD_DEFAULT;
281 #else
282       dlhandle = dlopen(NULL, dlflags1|dlflags2);
283 #if defined(PETSC_HAVE_DLERROR)
284       { const char *e = (const char*) dlerror();
285         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);
286       }
287 #endif
288 #endif
289     }
290 #endif
291 #endif /* PETSC_HAVE_DLOPEN && PETSC_HAVE_DYNAMIC_LIBRARIES */
292   }
293 #if defined(PETSC_HAVE_DLERROR)
294   dlerror(); /* clear any previous error */
295 #endif
296   dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol);
297   /*
298      --- unimplemented ---
299   */
300 #else
301   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
302 #endif
303 
304   *value = *((void**)&dlsymbol);
305 
306 #if defined(PETSC_SERIALIZE_FUNCTIONS)
307   if (*value) {
308     PetscErrorCode ierr;
309     ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr);
310   }
311 #endif
312   return(0);
313 }
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   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), const char **name)
335 {
336   PetscFunctionBegin;
337   PetscValidCharPointer(name,3);
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     *name = info.dli_sname;
347   }
348 #endif
349   PetscFunctionReturn(0);
350 }
351