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