Actual source code: dlimpl.c
  1: /*
  2:    Low-level routines for managing dynamic link libraries (DLLs).
  3: */
  5: #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for dlopen() */
  6: #include <petsc/private/petscimpl.h>
  8: #if defined(PETSC_HAVE_WINDOWS_H)
  9:   #include <windows.h>
 10: #endif
 11: #if defined(PETSC_HAVE_DLFCN_H)
 12:   #include <dlfcn.h>
 13: #endif
 15: #if defined(PETSC_HAVE_WINDOWS_H)
 16: typedef HMODULE dlhandle_t;
 17: typedef FARPROC dlsymbol_t;
 18: #elif defined(PETSC_HAVE_DLFCN_H)
 19: typedef void *dlhandle_t;
 20: typedef void *dlsymbol_t;
 21: #else
 22: typedef void *dlhandle_t;
 23: typedef void *dlsymbol_t;
 24: #endif
 26: /*@C
 27:   PetscDLOpen - opens a dynamic library
 29:   Not Collective, No Fortran Support
 31:   Input Parameters:
 32: + name - name of library
 33: - mode - options on how to open library
 35:   Output Parameter:
 36: . handle - opaque pointer to be used with `PetscDLSym()`
 38:   Level: developer
 40: .seealso: `PetscDLClose()`, `PetscDLSym()`, `PetscDLAddr()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
 41:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
 42: @*/
 43: PetscErrorCode PetscDLOpen(const char name[], PetscDLMode mode, PetscDLHandle *handle)
 44: {
 45:   PETSC_UNUSED int dlflags1, dlflags2; /* There are some preprocessor paths where these variables are set, but not used */
 46:   dlhandle_t       dlhandle;
 48:   PetscFunctionBegin;
 49:   PetscAssertPointer(name, 1);
 50:   PetscAssertPointer(handle, 3);
 52:   dlflags1 = 0;
 53:   dlflags2 = 0;
 54:   dlhandle = (dlhandle_t)0;
 55:   *handle  = (PetscDLHandle)0;
 57:   /*
 58:      --- LoadLibrary ---
 59:   */
 60: #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_LOADLIBRARY)
 61:   dlhandle = LoadLibrary(name);
 62:   if (!dlhandle) {
 63:     /* TODO: Seem to need fixing, why not just return with an error with SETERRQ() */
 64:   #if defined(PETSC_HAVE_GETLASTERROR)
 65:     DWORD erc;
 66:     char *buff = NULL;
 67:     erc        = GetLastError();
 68:     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
 69:     PetscCall(PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, PETSC_ERR_FILE_OPEN, PETSC_ERROR_REPEAT, "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n", name, buff));
 70:     LocalFree(buff);
 71:     PetscFunctionReturn(PETSC_SUCCESS);
 72:   #else
 73:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s", name, "unavailable");
 74:   #endif
 75:   }
 77:   /*
 78:      --- dlopen ---
 79:   */
 80: #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN)
 81:   /*
 82:       Mode indicates symbols required by symbol loaded with dlsym()
 83:      are only loaded when required (not all together) also indicates
 84:      symbols required can be contained in other libraries also opened
 85:      with dlopen()
 86:   */
 87:   #if defined(PETSC_HAVE_RTLD_LAZY)
 88:   dlflags1 = RTLD_LAZY;
 89:   #endif
 90:   #if defined(PETSC_HAVE_RTLD_NOW)
 91:   if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW;
 92:   #endif
 93:   #if defined(PETSC_HAVE_RTLD_GLOBAL)
 94:   dlflags2 = RTLD_GLOBAL;
 95:   #endif
 96:   #if defined(PETSC_HAVE_RTLD_LOCAL)
 97:   if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL;
 98:   #endif
 99:   #if defined(PETSC_HAVE_DLERROR)
100:   dlerror(); /* clear any previous error */
101:   #endif
102:   dlhandle = dlopen(name, dlflags1 | dlflags2);
103:   if (!dlhandle) {
104:   #if defined(PETSC_HAVE_DLERROR)
105:     const char *errmsg = dlerror();
106:   #else
107:     const char *errmsg = "unavailable";
108:   #endif
109:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n  %s\n  Error message from dlopen() %s", name, errmsg);
110:   }
111:   /*
112:      --- unimplemented ---
113:   */
114: #else
115:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
116: #endif
118:   *handle = (PetscDLHandle)dlhandle;
119:   PetscFunctionReturn(PETSC_SUCCESS);
120: }
122: /*@C
123:   PetscDLClose -  closes a dynamic library
125:   Not Collective, No Fortran Support
127:   Input Parameter:
128: . handle - the handle for the library obtained with `PetscDLOpen()`
130:   Level: developer
132: .seealso: `PetscDLOpen()`, `PetscDLSym()`, `PetscDLAddr()`
133: @*/
134: PetscErrorCode PetscDLClose(PetscDLHandle *handle)
135: {
136:   PetscFunctionBegin;
137:   PetscAssertPointer(handle, 1);
139:   /*
140:      --- FreeLibrary ---
141:   */
142: #if defined(PETSC_HAVE_WINDOWS_H)
143:   #if defined(PETSC_HAVE_FREELIBRARY)
144:   if (FreeLibrary((dlhandle_t)*handle) == 0) {
145:     #if defined(PETSC_HAVE_GETLASTERROR)
146:     char *buff = NULL;
147:     DWORD erc  = GetLastError();
148:     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
149:     PetscCall(PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n", buff));
150:     LocalFree(buff);
151:     #else
152:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n  Error message from FreeLibrary() %s", "unavailable");
153:     #endif
154:   }
155:   #endif /* !PETSC_HAVE_FREELIBRARY */
157:   /*
158:      --- dclose ---
159:   */
160: #elif defined(PETSC_HAVE_DLFCN_H)
161:   #if defined(PETSC_HAVE_DLCLOSE)
162:     #if defined(PETSC_HAVE_DLERROR)
163:   dlerror(); /* clear any previous error */
164:     #endif
165:   if (dlclose((dlhandle_t)*handle) < 0) {
166:     #if defined(PETSC_HAVE_DLERROR)
167:     const char *errmsg = dlerror();
168:     #else
169:     const char *errmsg = "unavailable";
170:     #endif
171:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n  Error message from dlclose() %s", errmsg);
172:   }
173:   #endif /* !PETSC_HAVE_DLCLOSE */
175:   /*
176:      --- unimplemented ---
177:   */
178: #else
179:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
180: #endif
182:   *handle = NULL;
183:   PetscFunctionReturn(PETSC_SUCCESS);
184: }
186: // clang-format off
187: /*@C
188:   PetscDLSym - finds a symbol in a dynamic library
190:   Not Collective, No Fortran Support
192:   Input Parameters:
193: + handle - obtained with `PetscDLOpen()` or `NULL`
194: - symbol - name of symbol
196:   Output Parameter:
197: . value - pointer to the function, `NULL` if not found
199:   Level: developer
201:   Note:
202:   If handle is `NULL`, the symbol is looked for in the main executable's dynamic symbol table.
203:   In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
204:   systems this requires platform-specific linker flags.
206: .seealso: `PetscDLClose()`, `PetscDLOpen()`, `PetscDLAddr()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
207:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
208: @*/
209: PetscErrorCode PetscDLSym(PetscDLHandle handle, const char symbol[], void **value)
210: {
211:   dlhandle_t dlhandle;
212:   dlsymbol_t dlsymbol;
214:   PetscFunctionBegin;
215:   PetscAssertPointer(symbol, 2);
216:   PetscAssertPointer(value, 3);
218:   dlhandle = (dlhandle_t)0;
219:   dlsymbol = (dlsymbol_t)0;
220:   *value   = NULL;
222:   /*
223:      --- GetProcAddress ---
224:   */
225:   #if defined(PETSC_HAVE_WINDOWS_H)
226:     #if defined(PETSC_HAVE_GETPROCADDRESS)
227:       if (handle) dlhandle = (dlhandle_t)handle;
228:       else dlhandle = (dlhandle_t)GetCurrentProcess();
229:       dlsymbol = (dlsymbol_t)GetProcAddress(dlhandle, symbol);
230:       #if defined(PETSC_HAVE_SETLASTERROR)
231:         SetLastError((DWORD)0); /* clear any previous error */
232:       #endif /* PETSC_HAVE_SETLASTERROR */
233:     #endif /* !PETSC_HAVE_GETPROCADDRESS */
235:   /*
236:      --- dlsym ---
237:   */
238:   #elif defined(PETSC_HAVE_DLFCN_H) /* PETSC_HAVE_WINDOWS_H */
239:     #if defined(PETSC_HAVE_DLSYM)
240:       if (handle) dlhandle = (dlhandle_t)handle;
241:       else {
242:         #if defined(PETSC_HAVE_DLOPEN)
243:           /* Attempt to retrieve the main executable's dlhandle. */
244:           {
245:             #if !defined(PETSC_HAVE_RTLD_DEFAULT)
246:             int dlflags1 = 0, dlflags2 = 0;
247:               #if defined(PETSC_HAVE_RTLD_LAZY)
248:               dlflags1 = RTLD_LAZY;
249:               #endif /* PETSC_HAVE_RTLD_LAZY */
250:               #if defined(PETSC_HAVE_RTLD_NOW)
251:               if (!dlflags1) dlflags1 = RTLD_NOW;
252:               #endif /* PETSC_HAVE_RTLD_NOW */
253:               #if defined(PETSC_HAVE_RTLD_LOCAL)
254:               dlflags2 = RTLD_LOCAL;
255:               #endif /* PETSC_HAVE_RTLD_LOCAL */
256:               #if defined(PETSC_HAVE_RTLD_GLOBAL)
257:               if (!dlflags2) dlflags2 = RTLD_GLOBAL;
258:               #endif /* PETSC_HAVE_RTLD_GLOBAL */
259:             #endif /* !PETSC_HAVE_RTLD_DEFAULT */
260:             #if defined(PETSC_HAVE_DLERROR)
261:               if (!(PETSC_RUNNING_ON_VALGRIND)) dlerror(); /* clear any previous error, valgrind does not like this */
262:             #endif /* PETSC_HAVE_DLERROR */
263:             #if defined(PETSC_HAVE_RTLD_DEFAULT)
264:               dlhandle = RTLD_DEFAULT;
265:             #else /* PETSC_HAVE_RTLD_DEFAULT */
266:               /* Attempt to open the main executable as a dynamic library. */
267:               dlhandle = dlopen(NULL, dlflags1 | dlflags2);
268:               #if defined(PETSC_HAVE_DLERROR)
269:                 {
270:                   const char *e = (const char *)dlerror();
271:                   PetscCheck(!e, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library: error message from dlopen(): '%s'", e);
272:                 }
273:               #endif /* PETSC_HAVE_DLERROR */
274:             #endif /* !PETSC_HAVE_RTLD_DEFAULT */
275:           }
276:         #endif /* PETSC_HAVE_DLOPEN */
277:       }
278:       #if defined(PETSC_HAVE_DLERROR)
279:         dlerror(); /* clear any previous error */
280:       #endif /* PETSC_HAVE_DLERROR */
281:       dlsymbol = (dlsymbol_t)dlsym(dlhandle, symbol);
282:     #else /* PETSC_HAVE_DLSYM */
283:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
284:     #endif /* PETSC_HAVE_DLSYM */
285:   #else /* PETSC_HAVE_DLFCN_H */
286:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
287:   #endif /* PETSC_HAVE_WINDOWS_H */
288:   // clang-format on
290:   *value = *((void **)&dlsymbol);
292: #if defined(PETSC_SERIALIZE_FUNCTIONS)
293:   if (*value) PetscCall(PetscFPTAdd(*value, symbol));
294: #endif /* PETSC_SERIALIZE_FUNCTIONS */
295:   PetscFunctionReturn(PETSC_SUCCESS);
296: }
298: /*@C
299:   PetscDLAddr - find the name of a symbol in a dynamic library
301:   Not Collective, No Fortran Support
303:   Input Parameters:
304: . func - pointer to the function, `NULL` if not found
306:   Output Parameter:
307: . name - name of symbol, or `NULL` if name lookup is not supported.
309:   Level: developer
311:   Notes:
312:   The caller must free the returned name.
314:   In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
315:   systems this requires platform-specific linker flags.
317: .seealso: `PetscDLClose()`, `PetscDLSym()`, `PetscDLOpen()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
318:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
319: @*/
320: PetscErrorCode PetscDLAddr(PetscVoidFn *func, char *name[])
321: {
322:   PetscFunctionBegin;
323:   PetscAssertPointer(name, 2);
324:   *name = NULL;
325: #if defined(PETSC_HAVE_DLADDR) && !(defined(__cray__) && defined(__clang__))
326:   dlerror(); /* clear any previous error */
327:   {
328:     Dl_info info;
330:     PetscCheck(dladdr(*(void **)&func, &info), PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror());
331:     PetscCall(PetscDemangleSymbol(info.dli_sname, name));
332:   }
333: #endif
334:   PetscFunctionReturn(PETSC_SUCCESS);
335: }