1 /* 2 Low-level routines for managing dynamic link libraries (DLLs). 3 */ 4 5 #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for dlopen() */ 6 #include <petsc/private/petscimpl.h> 7 8 #if defined(PETSC_HAVE_WINDOWS_H) 9 #include <windows.h> 10 #endif 11 #if defined(PETSC_HAVE_DLFCN_H) 12 #include <dlfcn.h> 13 #endif 14 15 #if defined(PETSC_HAVE_WINDOWS_H) 16 typedef HMODULE dlhandle_t; 17 typedef FARPROC dlsymbol_t; 18 #elif defined(PETSC_HAVE_DLFCN_H) 19 typedef void *dlhandle_t; 20 typedef void *dlsymbol_t; 21 #else 22 typedef void *dlhandle_t; 23 typedef void *dlsymbol_t; 24 #endif 25 26 /*@C 27 PetscDLOpen - opens a dynamic library 28 29 Not Collective, No Fortran Support 30 31 Input Parameters: 32 + name - name of library 33 - mode - options on how to open library 34 35 Output Parameter: 36 . handle - opaque pointer to be used with `PetscDLSym()` 37 38 Level: developer 39 40 .seealso: `PetscDLClose()`, `PetscDLSym()`, `PetscDLAddr()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`, 41 `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()` 42 @*/ 43 PetscErrorCode PetscDLOpen(const char name[], PetscDLMode mode, PetscDLHandle *handle) 44 { 45 PETSC_UNUSED int dlflags1, dlflags2; /* There are some preprocessor paths where these variables are set, but not used */ 46 dlhandle_t dlhandle; 47 48 PetscFunctionBegin; 49 PetscAssertPointer(name, 1); 50 PetscAssertPointer(handle, 3); 51 52 dlflags1 = 0; 53 dlflags2 = 0; 54 dlhandle = (dlhandle_t)0; 55 *handle = (PetscDLHandle)0; 56 57 /* 58 --- LoadLibrary --- 59 */ 60 #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_LOADLIBRARY) 61 dlhandle = LoadLibrary(name); 62 if (!dlhandle) { 63 /* TODO: Seem to need fixing, why not just return with an error with SETERRQ() */ 64 #if defined(PETSC_HAVE_GETLASTERROR) 65 DWORD erc; 66 char *buff = NULL; 67 erc = GetLastError(); 68 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL); 69 PetscCall(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)); 70 LocalFree(buff); 71 PetscFunctionReturn(PETSC_SUCCESS); 72 #else 73 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n %s\n Error message from LoadLibrary() %s", name, "unavailable"); 74 #endif 75 } 76 77 /* 78 --- dlopen --- 79 */ 80 #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN) 81 /* 82 Mode indicates symbols required by symbol loaded with dlsym() 83 are only loaded when required (not all together) also indicates 84 symbols required can be contained in other libraries also opened 85 with dlopen() 86 */ 87 #if defined(PETSC_HAVE_RTLD_LAZY) 88 dlflags1 = RTLD_LAZY; 89 #endif 90 #if defined(PETSC_HAVE_RTLD_NOW) 91 if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW; 92 #endif 93 #if defined(PETSC_HAVE_RTLD_GLOBAL) 94 dlflags2 = RTLD_GLOBAL; 95 #endif 96 #if defined(PETSC_HAVE_RTLD_LOCAL) 97 if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL; 98 #endif 99 #if defined(PETSC_HAVE_DLERROR) 100 dlerror(); /* clear any previous error */ 101 #endif 102 dlhandle = dlopen(name, dlflags1 | dlflags2); 103 if (!dlhandle) { 104 #if defined(PETSC_HAVE_DLERROR) 105 const char *errmsg = dlerror(); 106 #else 107 const char *errmsg = "unavailable"; 108 #endif 109 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n %s\n Error message from dlopen() %s", name, errmsg); 110 } 111 /* 112 --- unimplemented --- 113 */ 114 #else 115 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 116 #endif 117 118 *handle = (PetscDLHandle)dlhandle; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 /*@C 123 PetscDLClose - closes a dynamic library 124 125 Not Collective, No Fortran Support 126 127 Input Parameter: 128 . handle - the handle for the library obtained with `PetscDLOpen()` 129 130 Level: developer 131 132 .seealso: `PetscDLOpen()`, `PetscDLSym()`, `PetscDLAddr()` 133 @*/ 134 PetscErrorCode PetscDLClose(PetscDLHandle *handle) 135 { 136 PetscFunctionBegin; 137 PetscAssertPointer(handle, 1); 138 139 /* 140 --- FreeLibrary --- 141 */ 142 #if defined(PETSC_HAVE_WINDOWS_H) 143 #if defined(PETSC_HAVE_FREELIBRARY) 144 if (FreeLibrary((dlhandle_t)*handle) == 0) { 145 #if defined(PETSC_HAVE_GETLASTERROR) 146 char *buff = NULL; 147 DWORD erc = GetLastError(); 148 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL); 149 PetscCall(PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n", buff)); 150 LocalFree(buff); 151 #else 152 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n Error message from FreeLibrary() %s", "unavailable"); 153 #endif 154 } 155 #endif /* !PETSC_HAVE_FREELIBRARY */ 156 157 /* 158 --- dclose --- 159 */ 160 #elif defined(PETSC_HAVE_DLFCN_H) 161 #if defined(PETSC_HAVE_DLCLOSE) 162 #if defined(PETSC_HAVE_DLERROR) 163 dlerror(); /* clear any previous error */ 164 #endif 165 if (dlclose((dlhandle_t)*handle) < 0) { 166 #if defined(PETSC_HAVE_DLERROR) 167 const char *errmsg = dlerror(); 168 #else 169 const char *errmsg = "unavailable"; 170 #endif 171 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n Error message from dlclose() %s", errmsg); 172 } 173 #endif /* !PETSC_HAVE_DLCLOSE */ 174 175 /* 176 --- unimplemented --- 177 */ 178 #else 179 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 180 #endif 181 182 *handle = NULL; 183 PetscFunctionReturn(PETSC_SUCCESS); 184 } 185 186 // clang-format off 187 /*@C 188 PetscDLSym - finds a symbol in a dynamic library 189 190 Not Collective, No Fortran Support 191 192 Input Parameters: 193 + handle - obtained with `PetscDLOpen()` or `NULL` 194 - symbol - name of symbol 195 196 Output Parameter: 197 . value - pointer to the function, `NULL` if not found 198 199 Level: developer 200 201 Note: 202 If handle is `NULL`, the symbol is looked for in the main executable's dynamic symbol table. 203 In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like 204 systems this requires platform-specific linker flags. 205 206 .seealso: `PetscDLClose()`, `PetscDLOpen()`, `PetscDLAddr()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`, 207 `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()` 208 @*/ 209 PetscErrorCode PetscDLSym(PetscDLHandle handle, const char symbol[], void **value) 210 { 211 dlhandle_t dlhandle; 212 dlsymbol_t dlsymbol; 213 214 PetscFunctionBegin; 215 PetscAssertPointer(symbol, 2); 216 PetscAssertPointer(value, 3); 217 218 dlhandle = (dlhandle_t)0; 219 dlsymbol = (dlsymbol_t)0; 220 *value = NULL; 221 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 /* PETSC_HAVE_SETLASTERROR */ 233 #endif /* !PETSC_HAVE_GETPROCADDRESS */ 234 235 /* 236 --- dlsym --- 237 */ 238 #elif defined(PETSC_HAVE_DLFCN_H) /* PETSC_HAVE_WINDOWS_H */ 239 #if defined(PETSC_HAVE_DLSYM) 240 if (handle) dlhandle = (dlhandle_t)handle; 241 else { 242 #if defined(PETSC_HAVE_DLOPEN) 243 /* Attempt to retrieve the main executable's dlhandle. */ 244 { 245 #if !defined(PETSC_HAVE_RTLD_DEFAULT) 246 int dlflags1 = 0, dlflags2 = 0; 247 #if defined(PETSC_HAVE_RTLD_LAZY) 248 dlflags1 = RTLD_LAZY; 249 #endif /* PETSC_HAVE_RTLD_LAZY */ 250 #if defined(PETSC_HAVE_RTLD_NOW) 251 if (!dlflags1) dlflags1 = RTLD_NOW; 252 #endif /* PETSC_HAVE_RTLD_NOW */ 253 #if defined(PETSC_HAVE_RTLD_LOCAL) 254 dlflags2 = RTLD_LOCAL; 255 #endif /* PETSC_HAVE_RTLD_LOCAL */ 256 #if defined(PETSC_HAVE_RTLD_GLOBAL) 257 if (!dlflags2) dlflags2 = RTLD_GLOBAL; 258 #endif /* PETSC_HAVE_RTLD_GLOBAL */ 259 #endif /* !PETSC_HAVE_RTLD_DEFAULT */ 260 #if defined(PETSC_HAVE_DLERROR) 261 if (!(PETSC_RUNNING_ON_VALGRIND)) dlerror(); /* clear any previous error, valgrind does not like this */ 262 #endif /* PETSC_HAVE_DLERROR */ 263 #if defined(PETSC_HAVE_RTLD_DEFAULT) 264 dlhandle = RTLD_DEFAULT; 265 #else /* PETSC_HAVE_RTLD_DEFAULT */ 266 /* Attempt to open the main executable as a dynamic library. */ 267 dlhandle = dlopen(NULL, dlflags1 | dlflags2); 268 #if defined(PETSC_HAVE_DLERROR) 269 { 270 const char *e = (const char *)dlerror(); 271 PetscCheck(!e, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library: error message from dlopen(): '%s'", e); 272 } 273 #endif /* PETSC_HAVE_DLERROR */ 274 #endif /* !PETSC_HAVE_RTLD_DEFAULT */ 275 } 276 #endif /* PETSC_HAVE_DLOPEN */ 277 } 278 #if defined(PETSC_HAVE_DLERROR) 279 dlerror(); /* clear any previous error */ 280 #endif /* PETSC_HAVE_DLERROR */ 281 dlsymbol = (dlsymbol_t)dlsym(dlhandle, symbol); 282 #else /* PETSC_HAVE_DLSYM */ 283 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 284 #endif /* PETSC_HAVE_DLSYM */ 285 #else /* PETSC_HAVE_DLFCN_H */ 286 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 287 #endif /* PETSC_HAVE_WINDOWS_H */ 288 // clang-format on 289 290 *value = *((void **)&dlsymbol); 291 292 #if defined(PETSC_SERIALIZE_FUNCTIONS) 293 if (*value) PetscCall(PetscFPTAdd(*value, symbol)); 294 #endif /* PETSC_SERIALIZE_FUNCTIONS */ 295 PetscFunctionReturn(PETSC_SUCCESS); 296 } 297 298 /*@C 299 PetscDLAddr - find the name of a symbol in a dynamic library 300 301 Not Collective, No Fortran Support 302 303 Input Parameters: 304 . func - pointer to the function, `NULL` if not found 305 306 Output Parameter: 307 . name - name of symbol, or `NULL` if name lookup is not supported. 308 309 Level: developer 310 311 Notes: 312 The caller must free the returned name. 313 314 In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like 315 systems this requires platform-specific linker flags. 316 317 .seealso: `PetscDLClose()`, `PetscDLSym()`, `PetscDLOpen()`, `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`, 318 `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`, `PetscDLLibrarySym()` 319 @*/ 320 PetscErrorCode PetscDLAddr(PetscVoidFn *func, char *name[]) 321 { 322 PetscFunctionBegin; 323 PetscAssertPointer(name, 2); 324 *name = NULL; 325 #if defined(PETSC_HAVE_DLADDR) && !(defined(__cray__) && defined(__clang__)) 326 dlerror(); /* clear any previous error */ 327 { 328 Dl_info info; 329 330 PetscCheck(dladdr(*(void **)&func, &info), PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror()); 331 PetscCall(PetscDemangleSymbol(info.dli_sname, name)); 332 } 333 #endif 334 PetscFunctionReturn(PETSC_SUCCESS); 335 } 336