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