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