1 /* 2 Low-level routines for managing dynamic link libraries (DLLs). 3 */ 4 5 #include <petscconf.h> 6 #if defined(PETSC__GNU_SOURCE) 7 #if !defined(_GNU_SOURCE) 8 #define _GNU_SOURCE 1 9 #endif 10 #endif 11 12 #include <petsc/private/petscimpl.h> 13 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 20 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 31 32 /*@C 33 PetscDLOpen - opens dynamic library 34 35 Not Collective 36 37 Input Parameters: 38 + name - name of library 39 - mode - options on how to open library 40 41 Output Parameter: 42 . handle - opaque pointer to be used with PetscDLSym() 43 44 Level: developer 45 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; 52 53 PetscFunctionBegin; 54 PetscValidCharPointer(name,1); 55 PetscValidPointer(handle,3); 56 57 dlflags1 = 0; 58 dlflags2 = 0; 59 dlhandle = (dlhandle_t) 0; 60 *handle = (PetscDLHandle) 0; 61 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) 69 PetscErrorCode ierr; 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 ierr = 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 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n %s\n Error message from LoadLibrary() %s",name,"unavailable"); 81 #endif 82 } 83 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 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n %s\n Error message from dlopen() %s",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 124 125 *handle = (PetscDLHandle) dlhandle; 126 PetscFunctionReturn(0); 127 } 128 129 /*@C 130 PetscDLClose - closes a dynamic library 131 132 Not Collective 133 134 Input Parameter: 135 . handle - the handle for the library obtained with PetscDLOpen() 136 137 Level: developer 138 139 .seealso: PetscDLOpen(), PetscDLSym(), PetscDLAddr() 140 @*/ 141 PetscErrorCode PetscDLClose(PetscDLHandle *handle) 142 { 143 144 PetscFunctionBegin; 145 PetscValidPointer(handle,1); 146 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 */ 164 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 */ 182 183 /* 184 --- unimplemented --- 185 */ 186 #else 187 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 188 #endif 189 190 *handle = NULL; 191 PetscFunctionReturn(0); 192 } 193 194 /*@C 195 PetscDLSym - finds a symbol in a dynamic library 196 197 Not Collective 198 199 Input Parameters: 200 + handle - obtained with PetscDLOpen() or NULL 201 - symbol - name of symbol 202 203 Output Parameter: 204 . value - pointer to the function, NULL if not found 205 206 Level: developer 207 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. 212 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; 219 220 PetscValidCharPointer(symbol,2); 221 PetscValidPointer(value,3); 222 223 dlhandle = (dlhandle_t) 0; 224 dlsymbol = (dlsymbol_t) 0; 225 *value = (void*) 0; 226 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 */ 239 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 { 247 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 PetscCheckFalse(e,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library:\n Error message from dlopen(): '%s'", 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 297 298 *value = *((void**)&dlsymbol); 299 300 #if defined(PETSC_SERIALIZE_FUNCTIONS) 301 if (*value) { 302 PetscErrorCode ierr; 303 ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr); 304 } 305 #endif 306 return(0); 307 } 308 309 /*@C 310 PetscDLAddr - find the name of a symbol in a dynamic library 311 312 Not Collective 313 314 Input Parameters: 315 + handle - obtained with PetscDLOpen() or NULL 316 - func - pointer to the function, NULL if not found 317 318 Output Parameter: 319 . name - name of symbol, or NULL if name lookup is not supported. 320 321 Level: developer 322 323 Notes: 324 The caller must free the returned name. 325 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. 328 329 .seealso: PetscDLClose(), PetscDLSym(), PetscDLOpen() 330 @*/ 331 PetscErrorCode PetscDLAddr(void (*func)(void), char **name) 332 { 333 PetscFunctionBegin; 334 PetscValidCharPointer(name,2); 335 *name = NULL; 336 #if defined(PETSC_HAVE_DLADDR) 337 dlerror(); /* clear any previous error */ 338 { 339 Dl_info info; 340 PetscErrorCode ierr; 341 342 ierr = dladdr(*(void **) &func, &info);PetscCheckFalse(!ierr,PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror()); 343 #ifdef PETSC_HAVE_CXX 344 ierr = PetscDemangleSymbol(info.dli_sname, name);CHKERRQ(ierr); 345 #else 346 ierr = PetscStrallocpy(info.dli_sname, name);CHKERRQ(ierr); 347 #endif 348 } 349 #endif 350 PetscFunctionReturn(0); 351 } 352