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 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 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 @*/ 221 PetscErrorCode PetscDLSym(PetscDLHandle handle,const char symbol[],void **value) 222 { 223 PETSC_UNUSED dlhandle_t dlhandle; 224 dlsymbol_t dlsymbol; 225 226 PetscValidCharPointer(symbol,2); 227 PetscValidPointer(value,3); 228 229 dlhandle = (dlhandle_t) 0; 230 dlsymbol = (dlsymbol_t) 0; 231 *value = (void*) 0; 232 233 /* 234 --- GetProcAddress --- 235 */ 236 #if defined(PETSC_HAVE_WINDOWS_H) 237 #if defined(PETSC_HAVE_GETPROCADDRESS) 238 if (handle) dlhandle = (dlhandle_t) handle; 239 else dlhandle = (dlhandle_t) GetCurrentProcess(); 240 dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol); 241 #if defined(PETSC_HAVE_SETLASTERROR) 242 SetLastError((DWORD)0); /* clear any previous error */ 243 #endif 244 #endif /* !PETSC_HAVE_GETPROCADDRESS */ 245 246 /* 247 --- dlsym --- 248 */ 249 #elif defined(PETSC_HAVE_DLFCN_H) 250 #if defined(PETSC_HAVE_DLSYM) 251 if (handle) dlhandle = (dlhandle_t) handle; 252 else { 253 254 #if defined(PETSC_HAVE_DLOPEN) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES) 255 /* Attempt to retrieve the main executable's dlhandle. */ 256 { int dlflags1 = 0, dlflags2 = 0; 257 #if defined(PETSC_HAVE_RTLD_LAZY) 258 dlflags1 = RTLD_LAZY; 259 #endif 260 if (!dlflags1) { 261 #if defined(PETSC_HAVE_RTLD_NOW) 262 dlflags1 = RTLD_NOW; 263 #endif 264 } 265 #if defined(PETSC_HAVE_RTLD_LOCAL) 266 dlflags2 = RTLD_LOCAL; 267 #endif 268 if (!dlflags2) { 269 #if defined(PETSC_HAVE_RTLD_GLOBAL) 270 dlflags2 = RTLD_GLOBAL; 271 #endif 272 } 273 #if defined(PETSC_HAVE_DLERROR) 274 if (!(PETSC_RUNNING_ON_VALGRIND)) { 275 dlerror(); /* clear any previous error; valgrind does not like this */ 276 } 277 #endif 278 /* Attempt to open the main executable as a dynamic library. */ 279 #if defined(PETSC_HAVE_RTDL_DEFAULT) 280 dlhandle = RTLD_DEFAULT; 281 #else 282 dlhandle = dlopen(NULL, dlflags1|dlflags2); 283 #if defined(PETSC_HAVE_DLERROR) 284 { const char *e = (const char*) dlerror(); 285 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); 286 } 287 #endif 288 #endif 289 } 290 #endif 291 #endif /* PETSC_HAVE_DLOPEN && PETSC_HAVE_DYNAMIC_LIBRARIES */ 292 } 293 #if defined(PETSC_HAVE_DLERROR) 294 dlerror(); /* clear any previous error */ 295 #endif 296 dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol); 297 /* 298 --- unimplemented --- 299 */ 300 #else 301 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform"); 302 #endif 303 304 *value = *((void**)&dlsymbol); 305 306 #if defined(PETSC_SERIALIZE_FUNCTIONS) 307 if (*value) { 308 PetscErrorCode ierr; 309 ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr); 310 } 311 #endif 312 return(0); 313 } 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 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), const char **name) 335 { 336 PetscFunctionBegin; 337 PetscValidCharPointer(name,3); 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 *name = info.dli_sname; 347 } 348 #endif 349 PetscFunctionReturn(0); 350 } 351