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