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 /* TODO: Seem to need fixing, why not just return with an error with SETERRQ() */ 69 #if defined(PETSC_HAVE_GETLASTERROR) 70 PetscErrorCode ierr; 71 DWORD erc; 72 char *buff = NULL; 73 erc = GetLastError(); 74 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, 75 NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL); 76 ierr = PetscError(PETSC_COMM_SELF,__LINE__,PETSC_FUNCTION_NAME,__FILE__,PETSC_ERR_FILE_OPEN,PETSC_ERROR_REPEAT, 77 "Unable to open dynamic library:\n %s\n Error message from LoadLibrary() %s\n",name,buff); 78 LocalFree(buff); 79 PetscFunctionReturn(ierr); 80 #else 81 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n %s\n Error message from LoadLibrary() %s",name,"unavailable"); 82 #endif 83 } 84 85 /* 86 --- dlopen --- 87 */ 88 #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN) 89 /* 90 Mode indicates symbols required by symbol loaded with dlsym() 91 are only loaded when required (not all together) also indicates 92 symbols required can be contained in other libraries also opened 93 with dlopen() 94 */ 95 #if defined(PETSC_HAVE_RTLD_LAZY) 96 dlflags1 = RTLD_LAZY; 97 #endif 98 #if defined(PETSC_HAVE_RTLD_NOW) 99 if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW; 100 #endif 101 #if defined(PETSC_HAVE_RTLD_GLOBAL) 102 dlflags2 = RTLD_GLOBAL; 103 #endif 104 #if defined(PETSC_HAVE_RTLD_LOCAL) 105 if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL; 106 #endif 107 #if defined(PETSC_HAVE_DLERROR) 108 dlerror(); /* clear any previous error */ 109 #endif 110 dlhandle = dlopen(name,dlflags1|dlflags2); 111 if (!dlhandle) { 112 #if defined(PETSC_HAVE_DLERROR) 113 const char *errmsg = dlerror(); 114 #else 115 const char *errmsg = "unavailable"; 116 #endif 117 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n %s\n Error message from dlopen() %s",name,errmsg); 118 } 119 /* 120 --- unimplemented --- 121 */ 122 #else 123 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 124 #endif 125 126 *handle = (PetscDLHandle) dlhandle; 127 PetscFunctionReturn(0); 128 } 129 130 /*@C 131 PetscDLClose - closes a dynamic library 132 133 Not Collective 134 135 Input Parameter: 136 . handle - the handle for the library obtained with PetscDLOpen() 137 138 Level: developer 139 140 .seealso: PetscDLOpen(), PetscDLSym(), PetscDLAddr() 141 @*/ 142 PetscErrorCode PetscDLClose(PetscDLHandle *handle) 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 PetscCheck(!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) PetscCall(PetscFPTAdd(*value,symbol)); 302 #endif 303 return(0); 304 } 305 306 /*@C 307 PetscDLAddr - find the name of a symbol in a dynamic library 308 309 Not Collective 310 311 Input Parameters: 312 + handle - obtained with PetscDLOpen() or NULL 313 - func - pointer to the function, NULL if not found 314 315 Output Parameter: 316 . name - name of symbol, or NULL if name lookup is not supported. 317 318 Level: developer 319 320 Notes: 321 The caller must free the returned name. 322 323 In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like 324 systems this requires platform-specific linker flags. 325 326 .seealso: PetscDLClose(), PetscDLSym(), PetscDLOpen() 327 @*/ 328 PetscErrorCode PetscDLAddr(void (*func)(void), char **name) 329 { 330 PetscFunctionBegin; 331 PetscValidPointer(name,2); 332 *name = NULL; 333 #if defined(PETSC_HAVE_DLADDR) 334 dlerror(); /* clear any previous error */ 335 { 336 Dl_info info; 337 338 PetscCheck(dladdr(*(void **) &func, &info),PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror()); 339 #ifdef PETSC_HAVE_CXX 340 PetscCall(PetscDemangleSymbol(info.dli_sname, name)); 341 #else 342 PetscCall(PetscStrallocpy(info.dli_sname, name)); 343 #endif 344 } 345 #endif 346 PetscFunctionReturn(0); 347 } 348