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 15 /* XXX Should be done better !!!*/ 16 #if !defined(PETSC_HAVE_DYNAMIC_LIBRARIES) 17 #undef PETSC_HAVE_WINDOWS_H 18 #undef PETSC_HAVE_DLFCN_H 19 #endif 20 21 #if defined(PETSC_HAVE_WINDOWS_H) 22 #include <windows.h> 23 #endif 24 #if defined(PETSC_HAVE_DLFCN_H) 25 #include <dlfcn.h> 26 #endif 27 28 #if defined(PETSC_HAVE_WINDOWS_H) 29 typedef HMODULE dlhandle_t; 30 typedef FARPROC dlsymbol_t; 31 #elif defined(PETSC_HAVE_DLFCN_H) 32 typedef void* dlhandle_t; 33 typedef void* dlsymbol_t; 34 #else 35 typedef void* dlhandle_t; 36 typedef void* dlsymbol_t; 37 #endif 38 39 /*@C 40 PetscDLOpen - opens dynamic library 41 42 Not Collective 43 44 Input Parameters: 45 + name - name of library 46 - mode - options on how to open library 47 48 Output Parameter: 49 . handle - opaque pointer to be used with PetscDLSym() 50 51 Level: developer 52 53 .seealso: PetscDLClose(), PetscDLSym(), PetscDLAddr() 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 --- unimplemented --- 127 */ 128 #else 129 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 130 #endif 131 132 *handle = (PetscDLHandle) dlhandle; 133 PetscFunctionReturn(0); 134 } 135 136 /*@C 137 PetscDLClose - closes a dynamic library 138 139 Not Collective 140 141 Input Parameter: 142 . handle - the handle for the library obtained with PetscDLOpen() 143 144 Level: developer 145 146 .seealso: PetscDLOpen(), PetscDLSym(), PetscDLAddr() 147 @*/ 148 PetscErrorCode PetscDLClose(PetscDLHandle *handle) 149 { 150 151 PetscFunctionBegin; 152 PetscValidPointer(handle,1); 153 154 /* 155 --- FreeLibrary --- 156 */ 157 #if defined(PETSC_HAVE_WINDOWS_H) 158 #if defined(PETSC_HAVE_FREELIBRARY) 159 if (FreeLibrary((dlhandle_t)*handle) == 0) { 160 #if defined(PETSC_HAVE_GETLASTERROR) 161 char *buff = NULL; 162 DWORD erc = GetLastError(); 163 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL); 164 PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n",buff); 165 LocalFree(buff); 166 #else 167 PetscErrorPrintf("Error closing dynamic library:\n Error message from FreeLibrary() %s\n","unavailable"); 168 #endif 169 } 170 #endif /* !PETSC_HAVE_FREELIBRARY */ 171 172 /* 173 --- dclose --- 174 */ 175 #elif defined(PETSC_HAVE_DLFCN_H) 176 #if defined(PETSC_HAVE_DLCLOSE) 177 #if defined(PETSC_HAVE_DLERROR) 178 dlerror(); /* clear any previous error */ 179 #endif 180 if (dlclose((dlhandle_t)*handle) < 0) { 181 #if defined(PETSC_HAVE_DLERROR) 182 const char *errmsg = dlerror(); 183 #else 184 const char *errmsg = "unavailable"; 185 #endif 186 PetscErrorPrintf("Error closing dynamic library:\n Error message from dlclose() %s\n", errmsg); 187 } 188 #endif /* !PETSC_HAVE_DLCLOSE */ 189 190 /* 191 --- unimplemented --- 192 */ 193 #else 194 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 195 #endif 196 197 *handle = NULL; 198 PetscFunctionReturn(0); 199 } 200 201 /*@C 202 PetscDLSym - finds a symbol in a dynamic library 203 204 Not Collective 205 206 Input Parameters: 207 + handle - obtained with PetscDLOpen() or NULL 208 - symbol - name of symbol 209 210 Output Parameter: 211 . value - pointer to the function, NULL if not found 212 213 Level: developer 214 215 Notes: 216 If handle is NULL, the symbol is looked for in the main executable's dynamic symbol table. 217 In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like 218 systems this requires platform-specific linker flags. 219 220 .seealso: PetscDLClose(), PetscDLOpen(), PetscDLAddr() 221 @*/ 222 PetscErrorCode PetscDLSym(PetscDLHandle handle,const char symbol[],void **value) 223 { 224 PETSC_UNUSED dlhandle_t dlhandle; 225 dlsymbol_t dlsymbol; 226 227 PetscValidCharPointer(symbol,2); 228 PetscValidPointer(value,3); 229 230 dlhandle = (dlhandle_t) 0; 231 dlsymbol = (dlsymbol_t) 0; 232 *value = (void*) 0; 233 234 /* 235 --- GetProcAddress --- 236 */ 237 #if defined(PETSC_HAVE_WINDOWS_H) 238 #if defined(PETSC_HAVE_GETPROCADDRESS) 239 if (handle) dlhandle = (dlhandle_t) handle; 240 else dlhandle = (dlhandle_t) GetCurrentProcess(); 241 dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol); 242 #if defined(PETSC_HAVE_SETLASTERROR) 243 SetLastError((DWORD)0); /* clear any previous error */ 244 #endif 245 #endif /* !PETSC_HAVE_GETPROCADDRESS */ 246 247 /* 248 --- dlsym --- 249 */ 250 #elif defined(PETSC_HAVE_DLFCN_H) 251 #if defined(PETSC_HAVE_DLSYM) 252 if (handle) dlhandle = (dlhandle_t) handle; 253 else { 254 255 #if defined(PETSC_HAVE_DLOPEN) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES) 256 /* Attempt to retrieve the main executable's dlhandle. */ 257 { int dlflags1 = 0, dlflags2 = 0; 258 #if defined(PETSC_HAVE_RTLD_LAZY) 259 dlflags1 = RTLD_LAZY; 260 #endif 261 if (!dlflags1) { 262 #if defined(PETSC_HAVE_RTLD_NOW) 263 dlflags1 = RTLD_NOW; 264 #endif 265 } 266 #if defined(PETSC_HAVE_RTLD_LOCAL) 267 dlflags2 = RTLD_LOCAL; 268 #endif 269 if (!dlflags2) { 270 #if defined(PETSC_HAVE_RTLD_GLOBAL) 271 dlflags2 = RTLD_GLOBAL; 272 #endif 273 } 274 #if defined(PETSC_HAVE_DLERROR) 275 if (!(PETSC_RUNNING_ON_VALGRIND)) { 276 dlerror(); /* clear any previous error; valgrind does not like this */ 277 } 278 #endif 279 /* Attempt to open the main executable as a dynamic library. */ 280 #if defined(PETSC_HAVE_RTDL_DEFAULT) 281 dlhandle = RTLD_DEFAULT; 282 #else 283 dlhandle = dlopen(NULL, dlflags1|dlflags2); 284 #if defined(PETSC_HAVE_DLERROR) 285 { const char *e = (const char*) dlerror(); 286 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); 287 } 288 #endif 289 #endif 290 } 291 #endif 292 #endif /* PETSC_HAVE_DLOPEN && PETSC_HAVE_DYNAMIC_LIBRARIES */ 293 } 294 #if defined(PETSC_HAVE_DLERROR) 295 dlerror(); /* clear any previous error */ 296 #endif 297 dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol); 298 /* 299 --- unimplemented --- 300 */ 301 #else 302 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 303 #endif 304 305 *value = *((void**)&dlsymbol); 306 307 #if defined(PETSC_SERIALIZE_FUNCTIONS) 308 if (*value) { 309 PetscErrorCode ierr; 310 ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr); 311 } 312 #endif 313 return(0); 314 } 315 316 /*@C 317 PetscDLAddr - find the name of a symbol in a dynamic library 318 319 Not Collective 320 321 Input Parameters: 322 + handle - obtained with PetscDLOpen() or NULL 323 - func - pointer to the function, NULL if not found 324 325 Output Parameter: 326 . name - name of symbol, or NULL if name lookup is not supported. 327 328 Level: developer 329 330 Notes: 331 The caller must free the returned name. 332 333 In order to be dynamically loadable, the symbol has to be exported as such. On many UNIX-like 334 systems this requires platform-specific linker flags. 335 336 .seealso: PetscDLClose(), PetscDLSym(), PetscDLOpen() 337 @*/ 338 PetscErrorCode PetscDLAddr(void (*func)(void), char **name) 339 { 340 PetscFunctionBegin; 341 PetscValidCharPointer(name,2); 342 *name = NULL; 343 #if defined(PETSC_HAVE_DLADDR) 344 dlerror(); /* clear any previous error */ 345 { 346 Dl_info info; 347 PetscErrorCode ierr; 348 349 ierr = dladdr(*(void **) &func, &info);if (!ierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Failed to lookup symbol: %s", dlerror()); 350 #ifdef PETSC_HAVE_CXX 351 ierr = PetscDemangleSymbol(info.dli_sname, name);CHKERRQ(ierr); 352 #else 353 ierr = PetscStrallocpy(info.dli_sname, name);CHKERRQ(ierr); 354 #endif 355 } 356 #endif 357 PetscFunctionReturn(0); 358 } 359