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