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 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: #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,
 73:                   NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
 74:     PetscError(PETSC_COMM_SELF,__LINE__,PETSC_FUNCTION_NAME,__FILE__,PETSC_ERR_FILE_OPEN,PETSC_ERROR_REPEAT,
 75:                       "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,buff);
 76:     LocalFree(buff);
 77:     return ierr;
 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:   return 0;
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: {

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:     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n",buff);
155:     LocalFree(buff);
156: #else
157:     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n","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:     PetscErrorPrintf("Error closing dynamic library:\n  Error message from dlclose() %s\n", 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:   return 0;
189: }

191: /*@C
192:    PetscDLSym - finds a symbol in a dynamic library

194:    Not Collective

196:    Input Parameters:
197: +   handle - obtained with PetscDLOpen() or NULL
198: -   symbol - name of symbol

200:    Output Parameter:
201: .   value - pointer to the function, NULL if not found

203:    Level: developer

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

210: .seealso: PetscDLClose(), PetscDLOpen(), PetscDLAddr()
211: @*/
212: PetscErrorCode  PetscDLSym(PetscDLHandle handle,const char symbol[],void **value)
213: {
214:   PETSC_UNUSED dlhandle_t dlhandle;
215:   dlsymbol_t              dlsymbol;


220:   dlhandle = (dlhandle_t) 0;
221:   dlsymbol = (dlsymbol_t) 0;
222:   *value   = (void*) 0;

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

237:   /*
238:      --- dlsym ---
239:   */
240: #elif defined(PETSC_HAVE_DLFCN_H)
241: #if defined(PETSC_HAVE_DLSYM)
242:   if (handle) dlhandle = (dlhandle_t) handle;
243:   else {

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

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

297: #if defined(PETSC_SERIALIZE_FUNCTIONS)
298:   if (*value) PetscFPTAdd(*value,symbol);
299: #endif
300:   return(0);
301: }

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

306:   Not Collective

308:   Input Parameters:
309: + handle - obtained with PetscDLOpen() or NULL
310: - func   - pointer to the function, NULL if not found

312:   Output Parameter:
313: . name   - name of symbol, or NULL if name lookup is not supported.

315:   Level: developer

317:   Notes:
318:   The caller must free the returned name.

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

323: .seealso: PetscDLClose(), PetscDLSym(), PetscDLOpen()
324: @*/
325: PetscErrorCode PetscDLAddr(void (*func)(void), char **name)
326: {
328:   *name = NULL;
329: #if defined(PETSC_HAVE_DLADDR) && defined(__USE_GNU)
330:   dlerror(); /* clear any previous error */
331:   {
332:     Dl_info info;

335: #ifdef PETSC_HAVE_CXX
336:     PetscDemangleSymbol(info.dli_sname, name);
337: #else
338:     PetscStrallocpy(info.dli_sname, name);
339: #endif
340:   }
341: #endif
342:   return 0;
343: }