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, see `PetscDLMode`
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: `PetscDLMode`, `PetscDLHandle`
43: @*/
44: PetscErrorCode PetscDLOpen(const char name[], PetscDLMode mode, PetscDLHandle *handle)
45: {
46: PETSC_UNUSED int dlflags1, dlflags2; /* There are some preprocessor paths where these variables are set, but not used */
47: dlhandle_t dlhandle;
49: PetscFunctionBegin;
50: PetscAssertPointer(name, 1);
51: PetscAssertPointer(handle, 3);
53: dlflags1 = 0;
54: dlflags2 = 0;
55: dlhandle = (dlhandle_t)0;
56: *handle = (PetscDLHandle)0;
58: /*
59: --- LoadLibrary ---
60: */
61: #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_LOADLIBRARY)
62: dlhandle = LoadLibrary(name);
63: if (!dlhandle) {
64: /* TODO: Seem to need fixing, why not just return with an error with SETERRQ() */
65: #if defined(PETSC_HAVE_GETLASTERROR)
66: DWORD erc;
67: char *buff = NULL;
68: erc = GetLastError();
69: FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
70: 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));
71: LocalFree(buff);
72: PetscFunctionReturn(PETSC_SUCCESS);
73: #else
74: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n %s\n Error message from LoadLibrary() %s", name, "unavailable");
75: #endif
76: }
78: /*
79: --- dlopen ---
80: */
81: #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN)
82: /*
83: Mode indicates symbols required by symbol loaded with dlsym()
84: are only loaded when required (not all together) also indicates
85: symbols required can be contained in other libraries also opened
86: with dlopen()
87: */
88: #if defined(PETSC_HAVE_RTLD_LAZY)
89: dlflags1 = RTLD_LAZY;
90: #endif
91: #if defined(PETSC_HAVE_RTLD_NOW)
92: if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW;
93: #endif
94: #if defined(PETSC_HAVE_RTLD_GLOBAL)
95: dlflags2 = RTLD_GLOBAL;
96: #endif
97: #if defined(PETSC_HAVE_RTLD_LOCAL)
98: if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL;
99: #endif
100: #if defined(PETSC_HAVE_DLERROR)
101: dlerror(); /* clear any previous error */
102: #endif
103: dlhandle = dlopen(name, dlflags1 | dlflags2);
104: if (!dlhandle) {
105: #if defined(PETSC_HAVE_DLERROR)
106: const char *errmsg = dlerror();
107: #else
108: const char *errmsg = "unavailable";
109: #endif
110: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n %s\n Error message from dlopen() %s", name, errmsg);
111: }
112: /*
113: --- unimplemented ---
114: */
115: #else
116: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
117: #endif
119: *handle = (PetscDLHandle)dlhandle;
120: PetscFunctionReturn(PETSC_SUCCESS);
121: }
123: /*@C
124: PetscDLClose - closes a dynamic library
126: Not Collective, No Fortran Support
128: Input Parameter:
129: . handle - the handle for the library obtained with `PetscDLOpen()`
131: Level: developer
133: .seealso: `PetscDLOpen()`, `PetscDLSym()`, `PetscDLAddr()`
134: @*/
135: PetscErrorCode PetscDLClose(PetscDLHandle *handle)
136: {
137: PetscFunctionBegin;
138: PetscAssertPointer(handle, 1);
140: /*
141: --- FreeLibrary ---
142: */
143: #if defined(PETSC_HAVE_WINDOWS_H)
144: #if defined(PETSC_HAVE_FREELIBRARY)
145: if (FreeLibrary((dlhandle_t)*handle) == 0) {
146: #if defined(PETSC_HAVE_GETLASTERROR)
147: char *buff = NULL;
148: DWORD erc = GetLastError();
149: FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
150: PetscCall(PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n", buff));
151: LocalFree(buff);
152: #else
153: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n Error message from FreeLibrary() %s", "unavailable");
154: #endif
155: }
156: #endif /* !PETSC_HAVE_FREELIBRARY */
158: /*
159: --- dclose ---
160: */
161: #elif defined(PETSC_HAVE_DLFCN_H)
162: #if defined(PETSC_HAVE_DLCLOSE)
163: #if defined(PETSC_HAVE_DLERROR)
164: dlerror(); /* clear any previous error */
165: #endif
166: if (dlclose((dlhandle_t)*handle) < 0) {
167: #if defined(PETSC_HAVE_DLERROR)
168: const char *errmsg = dlerror();
169: #else
170: const char *errmsg = "unavailable";
171: #endif
172: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n Error message from dlclose() %s", errmsg);
173: }
174: #endif /* !PETSC_HAVE_DLCLOSE */
176: /*
177: --- unimplemented ---
178: */
179: #else
180: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
181: #endif
183: *handle = NULL;
184: PetscFunctionReturn(PETSC_SUCCESS);
185: }
187: // clang-format off
188: /*@C
189: PetscDLSym - finds a symbol in a dynamic library
191: Not Collective, No Fortran Support
193: Input Parameters:
194: + handle - obtained with `PetscDLOpen()` or `NULL`
195: - symbol - name of symbol
197: Output Parameter:
198: . value - returns pointer to the function, `NULL` if not found
200: Level: developer
202: Note:
203: If handle is `NULL`, the symbol is looked for in the main executable's dynamic symbol table.
204: In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like
205: systems this requires platform-specific linker flags.
207: .seealso: `PetscDLClose()`, `PetscDLOpen()`, `PetscDLAddr()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
208: `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`, `PetscDLHandle`
209: @*/
210: PetscErrorCode PetscDLSym(PetscDLHandle handle, const char symbol[], void **value)
211: {
212: dlhandle_t dlhandle;
213: dlsymbol_t dlsymbol;
215: PetscFunctionBegin;
216: PetscAssertPointer(symbol, 2);
217: PetscAssertPointer(value, 3);
219: dlhandle = (dlhandle_t)0;
220: dlsymbol = (dlsymbol_t)0;
221: *value = NULL;
223: /*
224: --- GetProcAddress ---
225: */
226: #if defined(PETSC_HAVE_WINDOWS_H)
227: #if defined(PETSC_HAVE_GETPROCADDRESS)
228: if (handle) dlhandle = (dlhandle_t)handle;
229: else dlhandle = (dlhandle_t)GetCurrentProcess();
230: dlsymbol = (dlsymbol_t)GetProcAddress(dlhandle, symbol);
231: #if defined(PETSC_HAVE_SETLASTERROR)
232: SetLastError((DWORD)0); /* clear any previous error */
233: #endif /* PETSC_HAVE_SETLASTERROR */
234: #endif /* !PETSC_HAVE_GETPROCADDRESS */
236: /*
237: --- dlsym ---
238: */
239: #elif defined(PETSC_HAVE_DLFCN_H) /* PETSC_HAVE_WINDOWS_H */
240: #if defined(PETSC_HAVE_DLSYM)
241: if (handle) dlhandle = (dlhandle_t)handle;
242: else {
243: #if defined(PETSC_HAVE_DLOPEN)
244: /* Attempt to retrieve the main executable's dlhandle. */
245: {
246: #if !defined(PETSC_HAVE_RTLD_DEFAULT)
247: int dlflags1 = 0, dlflags2 = 0;
248: #if defined(PETSC_HAVE_RTLD_LAZY)
249: dlflags1 = RTLD_LAZY;
250: #endif /* PETSC_HAVE_RTLD_LAZY */
251: #if defined(PETSC_HAVE_RTLD_NOW)
252: if (!dlflags1) dlflags1 = RTLD_NOW;
253: #endif /* PETSC_HAVE_RTLD_NOW */
254: #if defined(PETSC_HAVE_RTLD_LOCAL)
255: dlflags2 = RTLD_LOCAL;
256: #endif /* PETSC_HAVE_RTLD_LOCAL */
257: #if defined(PETSC_HAVE_RTLD_GLOBAL)
258: if (!dlflags2) dlflags2 = RTLD_GLOBAL;
259: #endif /* PETSC_HAVE_RTLD_GLOBAL */
260: #endif /* !PETSC_HAVE_RTLD_DEFAULT */
261: #if defined(PETSC_HAVE_DLERROR)
262: if (!(PETSC_RUNNING_ON_VALGRIND)) dlerror(); /* clear any previous error, valgrind does not like this */
263: #endif /* PETSC_HAVE_DLERROR */
264: #if defined(PETSC_HAVE_RTLD_DEFAULT)
265: dlhandle = RTLD_DEFAULT;
266: #else /* PETSC_HAVE_RTLD_DEFAULT */
267: /* Attempt to open the main executable as a dynamic library. */
268: dlhandle = dlopen(NULL, dlflags1 | dlflags2);
269: #if defined(PETSC_HAVE_DLERROR)
270: {
271: const char *e = (const char *)dlerror();
272: PetscCheck(!e, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library: error message from dlopen(): '%s'", e);
273: }
274: #endif /* PETSC_HAVE_DLERROR */
275: #endif /* !PETSC_HAVE_RTLD_DEFAULT */
276: }
277: #endif /* PETSC_HAVE_DLOPEN */
278: }
279: #if defined(PETSC_HAVE_DLERROR)
280: dlerror(); /* clear any previous error */
281: #endif /* PETSC_HAVE_DLERROR */
282: dlsymbol = (dlsymbol_t)dlsym(dlhandle, symbol);
283: #else /* PETSC_HAVE_DLSYM */
284: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
285: #endif /* PETSC_HAVE_DLSYM */
286: #else /* PETSC_HAVE_DLFCN_H */
287: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
288: #endif /* PETSC_HAVE_WINDOWS_H */
289: // clang-format on
291: *value = *((void **)&dlsymbol);
293: #if defined(PETSC_SERIALIZE_FUNCTIONS)
294: if (*value) PetscCall(PetscFPTAdd(*value, symbol));
295: #endif /* PETSC_SERIALIZE_FUNCTIONS */
296: PetscFunctionReturn(PETSC_SUCCESS);
297: }
299: /*@C
300: PetscDLAddr - find the name of a symbol in a dynamic library
302: Not Collective, No Fortran Support
304: Input Parameters:
305: . func - pointer to the function, `NULL` if not found
307: Output Parameter:
308: . name - name of symbol, or `NULL` if name lookup is not supported.
310: Level: developer
312: Notes:
313: The caller must free the returned name.
315: In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like
316: systems this requires platform-specific linker flags.
318: .seealso: `PetscDLClose()`, `PetscDLSym()`, `PetscDLOpen()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
319: `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
320: @*/
321: PetscErrorCode PetscDLAddr(PetscVoidFn *func, char *name[])
322: {
323: PetscFunctionBegin;
324: PetscAssertPointer(name, 2);
325: *name = NULL;
326: #if defined(PETSC_HAVE_DLADDR) && !(defined(__cray__) && defined(__clang__))
327: dlerror(); /* clear any previous error */
328: {
329: Dl_info info;
331: PetscCheck(dladdr(*(void **)&func, &info), PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror());
332: PetscCall(PetscDemangleSymbol(info.dli_sname, name));
333: }
334: #endif
335: PetscFunctionReturn(PETSC_SUCCESS);
336: }