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()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
 47:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
 48: @*/
 49: PetscErrorCode PetscDLOpen(const char name[], PetscDLMode mode, PetscDLHandle *handle)
 50: {
 51:   PETSC_UNUSED int dlflags1, dlflags2; /* There are some preprocessor paths where these variables are set, but not used */
 52:   dlhandle_t       dlhandle;

 54:   PetscFunctionBegin;
 55:   PetscAssertPointer(name, 1);
 56:   PetscAssertPointer(handle, 3);

 58:   dlflags1 = 0;
 59:   dlflags2 = 0;
 60:   dlhandle = (dlhandle_t)0;
 61:   *handle  = (PetscDLHandle)0;

 63:   /*
 64:      --- LoadLibrary ---
 65:   */
 66: #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_LOADLIBRARY)
 67:   dlhandle = LoadLibrary(name);
 68:   if (!dlhandle) {
 69:     /* TODO: Seem to need fixing, why not just return with an error with SETERRQ() */
 70:   #if defined(PETSC_HAVE_GETLASTERROR)
 71:     DWORD erc;
 72:     char *buff = NULL;
 73:     erc        = GetLastError();
 74:     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
 75:     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));
 76:     LocalFree(buff);
 77:     PetscFunctionReturn(PETSC_SUCCESS);
 78:   #else
 79:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s", name, "unavailable");
 80:   #endif
 81:   }

 83:   /*
 84:      --- dlopen ---
 85:   */
 86: #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN)
 87:   /*
 88:       Mode indicates symbols required by symbol loaded with dlsym()
 89:      are only loaded when required (not all together) also indicates
 90:      symbols required can be contained in other libraries also opened
 91:      with dlopen()
 92:   */
 93:   #if defined(PETSC_HAVE_RTLD_LAZY)
 94:   dlflags1 = RTLD_LAZY;
 95:   #endif
 96:   #if defined(PETSC_HAVE_RTLD_NOW)
 97:   if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW;
 98:   #endif
 99:   #if defined(PETSC_HAVE_RTLD_GLOBAL)
100:   dlflags2 = RTLD_GLOBAL;
101:   #endif
102:   #if defined(PETSC_HAVE_RTLD_LOCAL)
103:   if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL;
104:   #endif
105:   #if defined(PETSC_HAVE_DLERROR)
106:   dlerror(); /* clear any previous error */
107:   #endif
108:   dlhandle = dlopen(name, dlflags1 | dlflags2);
109:   if (!dlhandle) {
110:   #if defined(PETSC_HAVE_DLERROR)
111:     const char *errmsg = dlerror();
112:   #else
113:     const char *errmsg = "unavailable";
114:   #endif
115:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n  %s\n  Error message from dlopen() %s", name, errmsg);
116:   }
117:   /*
118:      --- unimplemented ---
119:   */
120: #else
121:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
122: #endif

124:   *handle = (PetscDLHandle)dlhandle;
125:   PetscFunctionReturn(PETSC_SUCCESS);
126: }

128: /*@C
129:   PetscDLClose -  closes a dynamic library

131:   Not Collective

133:   Input Parameter:
134: . handle - the handle for the library obtained with `PetscDLOpen()`

136:   Level: developer

138: .seealso: `PetscDLOpen()`, `PetscDLSym()`, `PetscDLAddr()`
139: @*/
140: PetscErrorCode PetscDLClose(PetscDLHandle *handle)
141: {
142:   PetscFunctionBegin;
143:   PetscAssertPointer(handle, 1);

145:   /*
146:      --- FreeLibrary ---
147:   */
148: #if defined(PETSC_HAVE_WINDOWS_H)
149:   #if defined(PETSC_HAVE_FREELIBRARY)
150:   if (FreeLibrary((dlhandle_t)*handle) == 0) {
151:     #if defined(PETSC_HAVE_GETLASTERROR)
152:     char *buff = NULL;
153:     DWORD erc  = GetLastError();
154:     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
155:     PetscCall(PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n", buff));
156:     LocalFree(buff);
157:     #else
158:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n  Error message from FreeLibrary() %s", "unavailable");
159:     #endif
160:   }
161:   #endif /* !PETSC_HAVE_FREELIBRARY */

163:   /*
164:      --- dclose ---
165:   */
166: #elif defined(PETSC_HAVE_DLFCN_H)
167:   #if defined(PETSC_HAVE_DLCLOSE)
168:     #if defined(PETSC_HAVE_DLERROR)
169:   dlerror(); /* clear any previous error */
170:     #endif
171:   if (dlclose((dlhandle_t)*handle) < 0) {
172:     #if defined(PETSC_HAVE_DLERROR)
173:     const char *errmsg = dlerror();
174:     #else
175:     const char *errmsg = "unavailable";
176:     #endif
177:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n  Error message from dlclose() %s", errmsg);
178:   }
179:   #endif /* !PETSC_HAVE_DLCLOSE */

181:   /*
182:      --- unimplemented ---
183:   */
184: #else
185:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
186: #endif

188:   *handle = NULL;
189:   PetscFunctionReturn(PETSC_SUCCESS);
190: }

192: // clang-format off

194: /*@C
195:   PetscDLSym - finds a symbol in a dynamic library

197:   Not Collective

199:   Input Parameters:
200: + handle - obtained with `PetscDLOpen()` or `NULL`
201: - symbol - name of symbol

203:   Output Parameter:
204: . value - pointer to the function, `NULL` if not found

206:   Level: developer

208:   Note:
209:   If handle is `NULL`, the symbol is looked for in the main executable's dynamic symbol table.
210:   In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
211:   systems this requires platform-specific linker flags.

213: .seealso: `PetscDLClose()`, `PetscDLOpen()`, `PetscDLAddr()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
214:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
215: @*/
216: PetscErrorCode PetscDLSym(PetscDLHandle handle, const char symbol[], void **value)
217: {
218:   PETSC_UNUSED dlhandle_t dlhandle;
219:   dlsymbol_t              dlsymbol;

221:   PetscFunctionBegin;
222:   PetscAssertPointer(symbol, 2);
223:   PetscAssertPointer(value, 3);

225:   dlhandle = (dlhandle_t)0;
226:   dlsymbol = (dlsymbol_t)0;
227:   *value   = (void *)0;

229:   /*
230:      --- GetProcAddress ---
231:   */
232:   #if defined(PETSC_HAVE_WINDOWS_H)
233:     #if defined(PETSC_HAVE_GETPROCADDRESS)
234:       if (handle) dlhandle = (dlhandle_t)handle;
235:       else dlhandle = (dlhandle_t)GetCurrentProcess();
236:       dlsymbol = (dlsymbol_t)GetProcAddress(dlhandle, symbol);
237:       #if defined(PETSC_HAVE_SETLASTERROR)
238:         SetLastError((DWORD)0); /* clear any previous error */
239:       #endif /* PETSC_HAVE_SETLASTERROR */
240:     #endif /* !PETSC_HAVE_GETPROCADDRESS */

242:   /*
243:      --- dlsym ---
244:   */
245:   #elif defined(PETSC_HAVE_DLFCN_H) /* PETSC_HAVE_WINDOWS_H */
246:     #if defined(PETSC_HAVE_DLSYM)
247:       if (handle) dlhandle = (dlhandle_t)handle;
248:       else {
249:         #if defined(PETSC_HAVE_DLOPEN)
250:           /* Attempt to retrieve the main executable's dlhandle. */
251:           {
252:             #if !defined(PETSC_HAVE_RTLD_DEFAULT)
253:             int dlflags1 = 0, dlflags2 = 0;
254:               #if defined(PETSC_HAVE_RTLD_LAZY)
255:               dlflags1 = RTLD_LAZY;
256:               #endif /* PETSC_HAVE_RTLD_LAZY */
257:               #if defined(PETSC_HAVE_RTLD_NOW)
258:               if (!dlflags1) {
259:                 dlflags1 = RTLD_NOW;
260:               }
261:               #endif /* PETSC_HAVE_RTLD_NOW */
262:               #if defined(PETSC_HAVE_RTLD_LOCAL)
263:               dlflags2 = RTLD_LOCAL;
264:               #endif /* PETSC_HAVE_RTLD_LOCAL */
265:               #if defined(PETSC_HAVE_RTLD_GLOBAL)
266:               if (!dlflags2) {
267:                 dlflags2 = RTLD_GLOBAL;
268:               }
269:               #endif /* PETSC_HAVE_RTLD_GLOBAL */
270:             #endif /* !PETSC_HAVE_RTLD_DEFAULT */
271:             #if defined(PETSC_HAVE_DLERROR)
272:               if (!(PETSC_RUNNING_ON_VALGRIND)) { dlerror(); /* clear any previous error; valgrind does not like this */ }
273:             #endif /* PETSC_HAVE_DLERROR */
274:             #if defined(PETSC_HAVE_RTLD_DEFAULT)
275:               dlhandle = RTLD_DEFAULT;
276:             #else /* PETSC_HAVE_RTLD_DEFAULT */
277:               /* Attempt to open the main executable as a dynamic library. */
278:               dlhandle = dlopen(NULL, dlflags1 | dlflags2);
279:               #if defined(PETSC_HAVE_DLERROR)
280:                 {
281:                   const char *e = (const char *)dlerror();
282:                   PetscCheck(!e, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library:\n  Error message from dlopen(): '%s'", e);
283:                 }
284:               #endif /* PETSC_HAVE_DLERROR */
285:             #endif /* !PETSC_HAVE_RTLD_DEFAULT */
286:           }
287:         #endif /* PETSC_HAVE_DLOPEN */
288:       }
289:       #if defined(PETSC_HAVE_DLERROR)
290:         dlerror(); /* clear any previous error */
291:       #endif /* PETSC_HAVE_DLERROR */
292:       dlsymbol = (dlsymbol_t)dlsym(dlhandle, symbol);
293:     #else /* PETSC_HAVE_DLSYM */
294:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
295:     #endif /* PETSC_HAVE_DLSYM */
296:   #else /* PETSC_HAVE_DLFCN_H */
297:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
298:   #endif /* PETSC_HAVE_WINDOWS_H */
299:   // clang-format on

301:   *value = *((void **)&dlsymbol);

303: #if defined(PETSC_SERIALIZE_FUNCTIONS)
304:   if (*value) PetscCall(PetscFPTAdd(*value, symbol));
305: #endif /* PETSC_SERIALIZE_FUNCTIONS */
306:   PetscFunctionReturn(PETSC_SUCCESS);
307: }

309: /*@C
310:   PetscDLAddr - find the name of a symbol in a dynamic library

312:   Not Collective

314:   Input Parameters:
315: . func - pointer to the function, `NULL` if not found

317:   Output Parameter:
318: . name - name of symbol, or `NULL` if name lookup is not supported.

320:   Level: developer

322:   Notes:
323:   The caller must free the returned name.

325:   In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
326:   systems this requires platform-specific linker flags.

328: .seealso: `PetscDLClose()`, `PetscDLSym()`, `PetscDLOpen()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
329:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
330: @*/
331: PetscErrorCode PetscDLAddr(void (*func)(void), char **name)
332: {
333:   PetscFunctionBegin;
334:   PetscAssertPointer(name, 2);
335:   *name = NULL;
336: #if defined(PETSC_HAVE_DLADDR) && !(defined(__cray__) && defined(__clang__))
337:   dlerror(); /* clear any previous error */
338:   {
339:     Dl_info info;

341:     PetscCheck(dladdr(*(void **)&func, &info), PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror());
342:   #ifdef PETSC_HAVE_CXX
343:     PetscCall(PetscDemangleSymbol(info.dli_sname, name));
344:   #else
345:     PetscCall(PetscStrallocpy(info.dli_sname, name));
346:   #endif
347:   }
348: #endif
349:   PetscFunctionReturn(PETSC_SUCCESS);
350: }