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;


 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: #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,
 74:                   NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
 75:     PetscError(PETSC_COMM_SELF,__LINE__,PETSC_FUNCTION_NAME,__FILE__,PETSC_ERR_FILE_OPEN,PETSC_ERROR_REPEAT,
 76:                       "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,buff);
 77:     LocalFree(buff);
 78:     PetscFunctionReturn(ierr);
 79: #else
 80:     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,"unavailable");
 81: #endif
 82:   }

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

125:   *handle = (PetscDLHandle) dlhandle;
126:   return(0);
127: }

129: /*@C
130:    PetscDLClose -  closes a dynamic library

132:    Not Collective

134:   Input Parameter:
135: .   handle - the handle for the library obtained with PetscDLOpen()

137:   Level: developer

139: .seealso: PetscDLOpen(), PetscDLSym(), PetscDLAddr()
140: @*/
141: PetscErrorCode  PetscDLClose(PetscDLHandle *handle)
142: {


147:   /*
148:      --- FreeLibrary ---
149:   */
150: #if defined(PETSC_HAVE_WINDOWS_H)
151: #if defined(PETSC_HAVE_FREELIBRARY)
152:   if (FreeLibrary((dlhandle_t)*handle) == 0) {
153: #if defined(PETSC_HAVE_GETLASTERROR)
154:     char  *buff = NULL;
155:     DWORD erc   = GetLastError();
156:     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
157:     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n",buff);
158:     LocalFree(buff);
159: #else
160:     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n","unavailable");
161: #endif
162:   }
163: #endif /* !PETSC_HAVE_FREELIBRARY */

165:   /*
166:      --- dclose ---
167:   */
168: #elif defined(PETSC_HAVE_DLFCN_H)
169: #if defined(PETSC_HAVE_DLCLOSE)
170: #if defined(PETSC_HAVE_DLERROR)
171:   dlerror(); /* clear any previous error */
172: #endif
173:   if (dlclose((dlhandle_t)*handle) < 0) {
174: #if defined(PETSC_HAVE_DLERROR)
175:     const char *errmsg = dlerror();
176: #else
177:     const char *errmsg = "unavailable";
178: #endif
179:     PetscErrorPrintf("Error closing dynamic library:\n  Error message from dlclose() %s\n", errmsg);
180:   }
181: #endif /* !PETSC_HAVE_DLCLOSE */

183:   /*
184:      --- unimplemented ---
185:   */
186: #else
187:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
188: #endif

190:   *handle = NULL;
191:   return(0);
192: }

194: /*@C
195:    PetscDLSym - finds a symbol in a dynamic library

197:    Not Collective

199:    Input Parameters:
200: +   handle - obtained with PetscDLOpen() or NULL
201: -   symbol - name of symbol

203:    Output Parameter:
204: .   value - pointer to the function, NULL if not found

206:    Level: developer

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

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


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
238: #endif /* !PETSC_HAVE_GETPROCADDRESS */

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

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

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

300: #if defined(PETSC_SERIALIZE_FUNCTIONS)
301:   if (*value) {
303:     PetscFPTAdd(*value,symbol);
304:   }
305: #endif
306:   return(0);
307: }

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

312:   Not Collective

314:   Input Parameters:
315: + handle - obtained with PetscDLOpen() or NULL
316: - func   - pointer to the function, NULL if not found

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

321:   Level: developer

323:   Notes:
324:   The caller must free the returned name.

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

329: .seealso: PetscDLClose(), PetscDLSym(), PetscDLOpen()
330: @*/
331: PetscErrorCode PetscDLAddr(void (*func)(void), char **name)
332: {
335:   *name = NULL;
336: #if defined(PETSC_HAVE_DLADDR)
337:   dlerror(); /* clear any previous error */
338:   {
339:     Dl_info        info;

342:     dladdr(*(void **) &func, &info);if (!ierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror());
343: #ifdef PETSC_HAVE_CXX
344:     PetscDemangleSymbol(info.dli_sname, name);
345: #else
346:     PetscStrallocpy(info.dli_sname, name);
347: #endif
348:   }
349: #endif
350:   return(0);
351: }