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