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;
56: dlflags1 = 0;
57: dlflags2 = 0;
58: dlhandle = (dlhandle_t)0;
59: *handle = (PetscDLHandle)0;
61: /*
62: --- LoadLibrary ---
63: */
64: #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_LOADLIBRARY)
65: dlhandle = LoadLibrary(name);
66: if (!dlhandle) {
67: /* TODO: Seem to need fixing, why not just return with an error with SETERRQ() */
68: #if defined(PETSC_HAVE_GETLASTERROR)
69: DWORD erc;
70: char *buff = NULL;
71: erc = GetLastError();
72: FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
73: 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);
74: LocalFree(buff);
75: return 0;
76: #else
77: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n %s\n Error message from LoadLibrary() %s", name, "unavailable");
78: #endif
79: }
81: /*
82: --- dlopen ---
83: */
84: #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN)
85: /*
86: Mode indicates symbols required by symbol loaded with dlsym()
87: are only loaded when required (not all together) also indicates
88: symbols required can be contained in other libraries also opened
89: with dlopen()
90: */
91: #if defined(PETSC_HAVE_RTLD_LAZY)
92: dlflags1 = RTLD_LAZY;
93: #endif
94: #if defined(PETSC_HAVE_RTLD_NOW)
95: if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW;
96: #endif
97: #if defined(PETSC_HAVE_RTLD_GLOBAL)
98: dlflags2 = RTLD_GLOBAL;
99: #endif
100: #if defined(PETSC_HAVE_RTLD_LOCAL)
101: if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL;
102: #endif
103: #if defined(PETSC_HAVE_DLERROR)
104: dlerror(); /* clear any previous error */
105: #endif
106: dlhandle = dlopen(name, dlflags1 | dlflags2);
107: if (!dlhandle) {
108: #if defined(PETSC_HAVE_DLERROR)
109: const char *errmsg = dlerror();
110: #else
111: const char *errmsg = "unavailable";
112: #endif
113: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n %s\n Error message from dlopen() %s", name, errmsg);
114: }
115: /*
116: --- unimplemented ---
117: */
118: #else
119: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
120: #endif
122: *handle = (PetscDLHandle)dlhandle;
123: return 0;
124: }
126: /*@C
127: PetscDLClose - closes a dynamic library
129: Not Collective
131: Input Parameter:
132: . handle - the handle for the library obtained with `PetscDLOpen()`
134: Level: developer
136: .seealso: `PetscDLOpen()`, `PetscDLSym()`, `PetscDLAddr()`
137: @*/
138: PetscErrorCode PetscDLClose(PetscDLHandle *handle)
139: {
142: /*
143: --- FreeLibrary ---
144: */
145: #if defined(PETSC_HAVE_WINDOWS_H)
146: #if defined(PETSC_HAVE_FREELIBRARY)
147: if (FreeLibrary((dlhandle_t)*handle) == 0) {
148: #if defined(PETSC_HAVE_GETLASTERROR)
149: char *buff = NULL;
150: DWORD erc = GetLastError();
151: FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
152: PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n", buff);
153: LocalFree(buff);
154: #else
155: PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n", "unavailable");
156: #endif
157: }
158: #endif /* !PETSC_HAVE_FREELIBRARY */
160: /*
161: --- dclose ---
162: */
163: #elif defined(PETSC_HAVE_DLFCN_H)
164: #if defined(PETSC_HAVE_DLCLOSE)
165: #if defined(PETSC_HAVE_DLERROR)
166: dlerror(); /* clear any previous error */
167: #endif
168: if (dlclose((dlhandle_t)*handle) < 0) {
169: #if defined(PETSC_HAVE_DLERROR)
170: const char *errmsg = dlerror();
171: #else
172: const char *errmsg = "unavailable";
173: #endif
174: PetscErrorPrintf("Error closing dynamic library:\n Error message from dlclose() %s\n", errmsg);
175: }
176: #endif /* !PETSC_HAVE_DLCLOSE */
178: /*
179: --- unimplemented ---
180: */
181: #else
182: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
183: #endif
185: *handle = NULL;
186: return 0;
187: }
189: /*@C
190: PetscDLSym - finds a symbol in a dynamic library
192: Not Collective
194: Input Parameters:
195: + handle - obtained with `PetscDLOpen()` or NULL
196: - symbol - name of symbol
198: Output Parameter:
199: . value - pointer to the function, NULL if not found
201: Level: developer
203: Note:
204: If handle is NULL, the symbol is looked for in the main executable's dynamic symbol table.
205: In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like
206: systems this requires platform-specific linker flags.
208: .seealso: `PetscDLClose()`, `PetscDLOpen()`, `PetscDLAddr()`
209: @*/
210: PetscErrorCode PetscDLSym(PetscDLHandle handle, const char symbol[], void **value)
211: {
212: PETSC_UNUSED dlhandle_t dlhandle;
213: dlsymbol_t dlsymbol;
218: dlhandle = (dlhandle_t)0;
219: dlsymbol = (dlsymbol_t)0;
220: *value = (void *)0;
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
233: #endif /* !PETSC_HAVE_GETPROCADDRESS */
235: /*
236: --- dlsym ---
237: */
238: #elif defined(PETSC_HAVE_DLFCN_H)
239: #if defined(PETSC_HAVE_DLSYM)
240: if (handle) dlhandle = (dlhandle_t)handle;
241: else {
243: #if defined(PETSC_HAVE_DLOPEN)
244: /* Attempt to retrieve the main executable's dlhandle. */
245: {
246: int dlflags1 = 0, dlflags2 = 0;
247: #if defined(PETSC_HAVE_RTLD_LAZY)
248: dlflags1 = RTLD_LAZY;
249: #endif
250: if (!dlflags1) {
251: #if defined(PETSC_HAVE_RTLD_NOW)
252: dlflags1 = RTLD_NOW;
253: #endif
254: }
255: #if defined(PETSC_HAVE_RTLD_LOCAL)
256: dlflags2 = RTLD_LOCAL;
257: #endif
258: if (!dlflags2) {
259: #if defined(PETSC_HAVE_RTLD_GLOBAL)
260: dlflags2 = RTLD_GLOBAL;
261: #endif
262: }
263: #if defined(PETSC_HAVE_DLERROR)
264: if (!(PETSC_RUNNING_ON_VALGRIND)) { dlerror(); /* clear any previous error; valgrind does not like this */ }
265: #endif
266: /* Attempt to open the main executable as a dynamic library. */
267: #if defined(PETSC_HAVE_RTLD_DEFAULT)
268: dlhandle = RTLD_DEFAULT;
269: #else
270: dlhandle = dlopen(NULL, dlflags1 | dlflags2);
271: #if defined(PETSC_HAVE_DLERROR)
272: {
273: const char *e = (const char *)dlerror();
275: }
276: #endif
277: #endif
278: }
279: #endif
280: #endif /* PETSC_HAVE_DLOPEN && PETSC_HAVE_DYNAMIC_LIBRARIES */
281: }
282: #if defined(PETSC_HAVE_DLERROR)
283: dlerror(); /* clear any previous error */
284: #endif
285: dlsymbol = (dlsymbol_t)dlsym(dlhandle, symbol);
286: /*
287: --- unimplemented ---
288: */
289: #else
290: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
291: #endif
293: *value = *((void **)&dlsymbol);
295: #if defined(PETSC_SERIALIZE_FUNCTIONS)
296: if (*value) PetscFPTAdd(*value, symbol);
297: #endif
298: return (0);
299: }
301: /*@C
302: PetscDLAddr - find the name of a symbol in a dynamic library
304: Not Collective
306: Input Parameters:
307: + handle - obtained with `PetscDLOpen()` or NULL
308: - func - pointer to the function, NULL if not found
310: Output Parameter:
311: . name - name of symbol, or NULL if name lookup is not supported.
313: Level: developer
315: Notes:
316: The caller must free the returned name.
318: In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like
319: systems this requires platform-specific linker flags.
321: .seealso: `PetscDLClose()`, `PetscDLSym()`, `PetscDLOpen()`
322: @*/
323: PetscErrorCode PetscDLAddr(void (*func)(void), char **name)
324: {
326: *name = NULL;
327: #if defined(PETSC_HAVE_DLADDR) && !(defined(__cray__) && defined(__clang__))
328: dlerror(); /* clear any previous error */
329: {
330: Dl_info info;
333: #ifdef PETSC_HAVE_CXX
334: PetscDemangleSymbol(info.dli_sname, name);
335: #else
336: PetscStrallocpy(info.dli_sname, name);
337: #endif
338: }
339: #endif
340: return 0;
341: }