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 PetscFunctionBegin; 144 PetscValidPointer(handle,1); 145 146 /* 147 --- FreeLibrary --- 148 */ 149 #if defined(PETSC_HAVE_WINDOWS_H) 150 #if defined(PETSC_HAVE_FREELIBRARY) 151 if (FreeLibrary((dlhandle_t)*handle) == 0) { 152 #if defined(PETSC_HAVE_GETLASTERROR) 153 char *buff = NULL; 154 DWORD erc = GetLastError(); 155 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL); 156 PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n",buff); 157 LocalFree(buff); 158 #else 159 PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n","unavailable"); 160 #endif 161 } 162 #endif /* !PETSC_HAVE_FREELIBRARY */ 163 164 /* 165 --- dclose --- 166 */ 167 #elif defined(PETSC_HAVE_DLFCN_H) 168 #if defined(PETSC_HAVE_DLCLOSE) 169 #if defined(PETSC_HAVE_DLERROR) 170 dlerror(); /* clear any previous error */ 171 #endif 172 if (dlclose((dlhandle_t)*handle) < 0) { 173 #if defined(PETSC_HAVE_DLERROR) 174 const char *errmsg = dlerror(); 175 #else 176 const char *errmsg = "unavailable"; 177 #endif 178 PetscErrorPrintf("Error closing dynamic library:\n Error message from dlclose() %s\n", errmsg); 179 } 180 #endif /* !PETSC_HAVE_DLCLOSE */ 181 182 /* 183 --- unimplemented --- 184 */ 185 #else 186 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 187 #endif 188 189 *handle = NULL; 190 PetscFunctionReturn(0); 191 } 192 193 /*@C 194 PetscDLSym - finds a symbol in a dynamic library 195 196 Not Collective 197 198 Input Parameters: 199 + handle - obtained with PetscDLOpen() or NULL 200 - symbol - name of symbol 201 202 Output Parameter: 203 . value - pointer to the function, NULL if not found 204 205 Level: developer 206 207 Notes: 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. 211 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; 218 219 PetscValidCharPointer(symbol,2); 220 PetscValidPointer(value,3); 221 222 dlhandle = (dlhandle_t) 0; 223 dlsymbol = (dlsymbol_t) 0; 224 *value = (void*) 0; 225 226 /* 227 --- GetProcAddress --- 228 */ 229 #if defined(PETSC_HAVE_WINDOWS_H) 230 #if defined(PETSC_HAVE_GETPROCADDRESS) 231 if (handle) dlhandle = (dlhandle_t) handle; 232 else dlhandle = (dlhandle_t) GetCurrentProcess(); 233 dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol); 234 #if defined(PETSC_HAVE_SETLASTERROR) 235 SetLastError((DWORD)0); /* clear any previous error */ 236 #endif 237 #endif /* !PETSC_HAVE_GETPROCADDRESS */ 238 239 /* 240 --- dlsym --- 241 */ 242 #elif defined(PETSC_HAVE_DLFCN_H) 243 #if defined(PETSC_HAVE_DLSYM) 244 if (handle) dlhandle = (dlhandle_t) handle; 245 else { 246 247 #if defined(PETSC_HAVE_DLOPEN) 248 /* Attempt to retrieve the main executable's dlhandle. */ 249 { int dlflags1 = 0, dlflags2 = 0; 250 #if defined(PETSC_HAVE_RTLD_LAZY) 251 dlflags1 = RTLD_LAZY; 252 #endif 253 if (!dlflags1) { 254 #if defined(PETSC_HAVE_RTLD_NOW) 255 dlflags1 = RTLD_NOW; 256 #endif 257 } 258 #if defined(PETSC_HAVE_RTLD_LOCAL) 259 dlflags2 = RTLD_LOCAL; 260 #endif 261 if (!dlflags2) { 262 #if defined(PETSC_HAVE_RTLD_GLOBAL) 263 dlflags2 = RTLD_GLOBAL; 264 #endif 265 } 266 #if defined(PETSC_HAVE_DLERROR) 267 if (!(PETSC_RUNNING_ON_VALGRIND)) { 268 dlerror(); /* clear any previous error; valgrind does not like this */ 269 } 270 #endif 271 /* Attempt to open the main executable as a dynamic library. */ 272 #if defined(PETSC_HAVE_RTDL_DEFAULT) 273 dlhandle = RTLD_DEFAULT; 274 #else 275 dlhandle = dlopen(NULL, dlflags1|dlflags2); 276 #if defined(PETSC_HAVE_DLERROR) 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 281 #endif 282 } 283 #endif 284 #endif /* PETSC_HAVE_DLOPEN && PETSC_HAVE_DYNAMIC_LIBRARIES */ 285 } 286 #if defined(PETSC_HAVE_DLERROR) 287 dlerror(); /* clear any previous error */ 288 #endif 289 dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol); 290 /* 291 --- unimplemented --- 292 */ 293 #else 294 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 295 #endif 296 297 *value = *((void**)&dlsymbol); 298 299 #if defined(PETSC_SERIALIZE_FUNCTIONS) 300 if (*value) PetscCall(PetscFPTAdd(*value,symbol)); 301 #endif 302 return(0); 303 } 304 305 /*@C 306 PetscDLAddr - find the name of a symbol in a dynamic library 307 308 Not Collective 309 310 Input Parameters: 311 + handle - obtained with PetscDLOpen() or NULL 312 - func - pointer to the function, NULL if not found 313 314 Output Parameter: 315 . name - name of symbol, or NULL if name lookup is not supported. 316 317 Level: developer 318 319 Notes: 320 The caller must free the returned name. 321 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. 324 325 .seealso: PetscDLClose(), PetscDLSym(), PetscDLOpen() 326 @*/ 327 PetscErrorCode PetscDLAddr(void (*func)(void), char **name) 328 { 329 PetscFunctionBegin; 330 PetscValidPointer(name,2); 331 *name = NULL; 332 #if defined(PETSC_HAVE_DLADDR) 333 dlerror(); /* clear any previous error */ 334 { 335 Dl_info info; 336 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(0); 346 } 347