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, No Fortran Support

 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, No Fortran Support

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
193: /*@C
194:   PetscDLSym - finds a symbol in a dynamic library

196:   Not Collective, No Fortran Support

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()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
213:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
214: @*/
215: PetscErrorCode PetscDLSym(PetscDLHandle handle, const char symbol[], void **value)
216: {
217:   dlhandle_t dlhandle;
218:   dlsymbol_t dlsymbol;

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

224:   dlhandle = (dlhandle_t)0;
225:   dlsymbol = (dlsymbol_t)0;
226:   *value   = NULL;

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

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

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

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

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

311:   Not Collective, No Fortran Support

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

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

319:   Level: developer

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

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

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

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