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 a 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 /* TODO: Seem to need fixing, why not just return with an error with SETERRQ() */ 69 #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, NULL, erc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL); 74 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)); 75 LocalFree(buff); 76 PetscFunctionReturn(PETSC_SUCCESS); 77 #else 78 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n %s\n Error message from LoadLibrary() %s", name, "unavailable"); 79 #endif 80 } 81 82 /* 83 --- dlopen --- 84 */ 85 #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN) 86 /* 87 Mode indicates symbols required by symbol loaded with dlsym() 88 are only loaded when required (not all together) also indicates 89 symbols required can be contained in other libraries also opened 90 with dlopen() 91 */ 92 #if defined(PETSC_HAVE_RTLD_LAZY) 93 dlflags1 = RTLD_LAZY; 94 #endif 95 #if defined(PETSC_HAVE_RTLD_NOW) 96 if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW; 97 #endif 98 #if defined(PETSC_HAVE_RTLD_GLOBAL) 99 dlflags2 = RTLD_GLOBAL; 100 #endif 101 #if defined(PETSC_HAVE_RTLD_LOCAL) 102 if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL; 103 #endif 104 #if defined(PETSC_HAVE_DLERROR) 105 dlerror(); /* clear any previous error */ 106 #endif 107 dlhandle = dlopen(name, dlflags1 | dlflags2); 108 if (!dlhandle) { 109 #if defined(PETSC_HAVE_DLERROR) 110 const char *errmsg = dlerror(); 111 #else 112 const char *errmsg = "unavailable"; 113 #endif 114 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open dynamic library:\n %s\n Error message from dlopen() %s", name, errmsg); 115 } 116 /* 117 --- unimplemented --- 118 */ 119 #else 120 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 121 #endif 122 123 *handle = (PetscDLHandle)dlhandle; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 /*@C 128 PetscDLClose - closes a dynamic library 129 130 Not Collective 131 132 Input Parameter: 133 . handle - the handle for the library obtained with `PetscDLOpen()` 134 135 Level: developer 136 137 .seealso: `PetscDLOpen()`, `PetscDLSym()`, `PetscDLAddr()` 138 @*/ 139 PetscErrorCode PetscDLClose(PetscDLHandle *handle) 140 { 141 PetscFunctionBegin; 142 PetscValidPointer(handle, 1); 143 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 PetscCall(PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n", buff)); 155 LocalFree(buff); 156 #else 157 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n Error message from FreeLibrary() %s", "unavailable"); 158 #endif 159 } 160 #endif /* !PETSC_HAVE_FREELIBRARY */ 161 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 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing dynamic library:\n Error message from dlclose() %s", errmsg); 177 } 178 #endif /* !PETSC_HAVE_DLCLOSE */ 179 180 /* 181 --- unimplemented --- 182 */ 183 #else 184 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 185 #endif 186 187 *handle = NULL; 188 PetscFunctionReturn(PETSC_SUCCESS); 189 } 190 191 // clang-format off 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 Note: 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 PetscFunctionBegin; 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 /* PETSC_HAVE_SETLASTERROR */ 238 #endif /* !PETSC_HAVE_GETPROCADDRESS */ 239 240 /* 241 --- dlsym --- 242 */ 243 #elif defined(PETSC_HAVE_DLFCN_H) /* PETSC_HAVE_WINDOWS_H */ 244 #if defined(PETSC_HAVE_DLSYM) 245 if (handle) dlhandle = (dlhandle_t)handle; 246 else { 247 #if defined(PETSC_HAVE_DLOPEN) 248 /* Attempt to retrieve the main executable's dlhandle. */ 249 { 250 int dlflags1 = 0, dlflags2 = 0; 251 #if defined(PETSC_HAVE_RTLD_LAZY) 252 dlflags1 = RTLD_LAZY; 253 #endif /* PETSC_HAVE_RTLD_LAZY */ 254 #if defined(PETSC_HAVE_RTLD_NOW) 255 if (!dlflags1) { 256 dlflags1 = RTLD_NOW; 257 } 258 #endif /* PETSC_HAVE_RTLD_NOW */ 259 #if defined(PETSC_HAVE_RTLD_LOCAL) 260 dlflags2 = RTLD_LOCAL; 261 #endif /* PETSC_HAVE_RTLD_LOCAL */ 262 #if defined(PETSC_HAVE_RTLD_GLOBAL) 263 if (!dlflags2) { 264 dlflags2 = RTLD_GLOBAL; 265 } 266 #endif /* PETSC_HAVE_RTLD_GLOBAL */ 267 #if defined(PETSC_HAVE_DLERROR) 268 if (!(PETSC_RUNNING_ON_VALGRIND)) { dlerror(); /* clear any previous error; valgrind does not like this */ } 269 #endif /* PETSC_HAVE_DLERROR */ 270 #if defined(PETSC_HAVE_RTLD_DEFAULT) 271 dlhandle = RTLD_DEFAULT; 272 #else /* PETSC_HAVE_RTLD_DEFAULT */ 273 /* Attempt to open the main executable as a dynamic library. */ 274 dlhandle = dlopen(NULL, dlflags1 | dlflags2); 275 #if defined(PETSC_HAVE_DLERROR) 276 { 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 /* PETSC_HAVE_DLERROR */ 281 #endif /* PETSC_HAVE_RTLD_DEFAULT */ 282 } 283 #endif /* PETSC_HAVE_DLOPEN */ 284 } 285 #if defined(PETSC_HAVE_DLERROR) 286 dlerror(); /* clear any previous error */ 287 #endif /* PETSC_HAVE_DLERROR */ 288 dlsymbol = (dlsymbol_t)dlsym(dlhandle, symbol); 289 #else /* PETSC_HAVE_DLSYM */ 290 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 291 #endif /* PETSC_HAVE_DLSYM */ 292 #else /* PETSC_HAVE_DLFCN_H */ 293 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 294 #endif /* PETSC_HAVE_WINDOWS_H */ 295 // clang-format on 296 297 *value = *((void **)&dlsymbol); 298 299 #if defined(PETSC_SERIALIZE_FUNCTIONS) 300 if (*value) PetscCall(PetscFPTAdd(*value, symbol)); 301 #endif /* PETSC_SERIALIZE_FUNCTIONS */ 302 PetscFunctionReturn(PETSC_SUCCESS); 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) && !(defined(__cray__) && defined(__clang__)) 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(PETSC_SUCCESS); 346 } 347