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