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: }