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: }