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, see `PetscDLMode`

 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:           `PetscDLMode`, `PetscDLHandle`
 43: @*/
 44: PetscErrorCode PetscDLOpen(const char name[], PetscDLMode mode, PetscDLHandle *handle)
 45: {
 46:   PETSC_UNUSED int dlflags1, dlflags2; /* There are some preprocessor paths where these variables are set, but not used */
 47:   dlhandle_t       dlhandle;

 49:   PetscFunctionBegin;
 50:   PetscAssertPointer(name, 1);
 51:   PetscAssertPointer(handle, 3);

 53:   dlflags1 = 0;
 54:   dlflags2 = 0;
 55:   dlhandle = (dlhandle_t)0;
 56:   *handle  = (PetscDLHandle)0;

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

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

119:   *handle = (PetscDLHandle)dlhandle;
120:   PetscFunctionReturn(PETSC_SUCCESS);
121: }

123: /*@C
124:   PetscDLClose -  closes a dynamic library

126:   Not Collective, No Fortran Support

128:   Input Parameter:
129: . handle - the handle for the library obtained with `PetscDLOpen()`

131:   Level: developer

133: .seealso: `PetscDLOpen()`, `PetscDLSym()`, `PetscDLAddr()`
134: @*/
135: PetscErrorCode PetscDLClose(PetscDLHandle *handle)
136: {
137:   PetscFunctionBegin;
138:   PetscAssertPointer(handle, 1);

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

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

176:   /*
177:      --- unimplemented ---
178:   */
179: #else
180:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
181: #endif

183:   *handle = NULL;
184:   PetscFunctionReturn(PETSC_SUCCESS);
185: }

187: // clang-format off
188: /*@C
189:   PetscDLSym - finds a symbol in a dynamic library

191:   Not Collective, No Fortran Support

193:   Input Parameters:
194: + handle - obtained with `PetscDLOpen()` or `NULL`
195: - symbol - name of symbol

197:   Output Parameter:
198: . value - returns pointer to the function, `NULL` if not found

200:   Level: developer

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

207: .seealso: `PetscDLClose()`, `PetscDLOpen()`, `PetscDLAddr()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
208:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`, `PetscDLHandle`
209: @*/
210: PetscErrorCode PetscDLSym(PetscDLHandle handle, const char symbol[], void **value)
211: {
212:   dlhandle_t dlhandle;
213:   dlsymbol_t dlsymbol;

215:   PetscFunctionBegin;
216:   PetscAssertPointer(symbol, 2);
217:   PetscAssertPointer(value, 3);

219:   dlhandle = (dlhandle_t)0;
220:   dlsymbol = (dlsymbol_t)0;
221:   *value   = NULL;

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

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

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

293: #if defined(PETSC_SERIALIZE_FUNCTIONS)
294:   if (*value) PetscCall(PetscFPTAdd(*value, symbol));
295: #endif /* PETSC_SERIALIZE_FUNCTIONS */
296:   PetscFunctionReturn(PETSC_SUCCESS);
297: }

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

302:   Not Collective, No Fortran Support

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

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

310:   Level: developer

312:   Notes:
313:   The caller must free the returned name.

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

318: .seealso: `PetscDLClose()`, `PetscDLSym()`, `PetscDLOpen()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`,
319:           `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()`
320: @*/
321: PetscErrorCode PetscDLAddr(PetscVoidFn *func, char *name[])
322: {
323:   PetscFunctionBegin;
324:   PetscAssertPointer(name, 2);
325:   *name = NULL;
326: #if defined(PETSC_HAVE_DLADDR) && !(defined(__cray__) && defined(__clang__))
327:   dlerror(); /* clear any previous error */
328:   {
329:     Dl_info info;

331:     PetscCheck(dladdr(*(void **)&func, &info), PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror());
332:     PetscCall(PetscDemangleSymbol(info.dli_sname, name));
333:   }
334: #endif
335:   PetscFunctionReturn(PETSC_SUCCESS);
336: }