| OLD | NEW |
| (Empty) | |
| 1 /* |
| 2 * dlfcn-win32 |
| 3 * Copyright (c) 2007 Ramiro Polla |
| 4 * |
| 5 * This library is free software; you can redistribute it and/or |
| 6 * modify it under the terms of the GNU Lesser General Public |
| 7 * License as published by the Free Software Foundation; either |
| 8 * version 2.1 of the License, or (at your option) any later version. |
| 9 * |
| 10 * This library is distributed in the hope that it will be useful, |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 * Lesser General Public License for more details. |
| 14 * |
| 15 * You should have received a copy of the GNU Lesser General Public |
| 16 * License along with this library; if not, write to the Free Software |
| 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 US
A |
| 18 */ |
| 19 |
| 20 #include <windows.h> |
| 21 #include <stdio.h> |
| 22 |
| 23 #include "dlfcn.h" |
| 24 |
| 25 /* Note: |
| 26 * MSDN says these functions are not thread-safe. We make no efforts to have |
| 27 * any kind of thread safety. |
| 28 */ |
| 29 |
| 30 typedef struct global_object { |
| 31 HMODULE hModule; |
| 32 struct global_object *previous; |
| 33 struct global_object *next; |
| 34 } global_object; |
| 35 |
| 36 static global_object first_object; |
| 37 |
| 38 /* These functions implement a double linked list for the global objects. */ |
| 39 static global_object *global_search( HMODULE hModule ) |
| 40 { |
| 41 global_object *pobject; |
| 42 |
| 43 if( hModule == NULL ) |
| 44 return NULL; |
| 45 |
| 46 for( pobject = &first_object; pobject ; pobject = pobject->next ) |
| 47 if( pobject->hModule == hModule ) |
| 48 return pobject; |
| 49 |
| 50 return NULL; |
| 51 } |
| 52 |
| 53 static void global_add( HMODULE hModule ) |
| 54 { |
| 55 global_object *pobject; |
| 56 global_object *nobject; |
| 57 |
| 58 if( hModule == NULL ) |
| 59 return; |
| 60 |
| 61 pobject = global_search( hModule ); |
| 62 |
| 63 /* Do not add object again if it's already on the list */ |
| 64 if( pobject ) |
| 65 return; |
| 66 |
| 67 for( pobject = &first_object; pobject->next ; pobject = pobject->next ); |
| 68 |
| 69 nobject = malloc( sizeof(global_object) ); |
| 70 |
| 71 /* Should this be enough to fail global_add, and therefore also fail |
| 72 * dlopen? |
| 73 */ |
| 74 if( !nobject ) |
| 75 return; |
| 76 |
| 77 pobject->next = nobject; |
| 78 nobject->next = NULL; |
| 79 nobject->previous = pobject; |
| 80 nobject->hModule = hModule; |
| 81 } |
| 82 |
| 83 static void global_rem( HMODULE hModule ) |
| 84 { |
| 85 global_object *pobject; |
| 86 |
| 87 if( hModule == NULL ) |
| 88 return; |
| 89 |
| 90 pobject = global_search( hModule ); |
| 91 |
| 92 if( !pobject ) |
| 93 return; |
| 94 |
| 95 if( pobject->next ) |
| 96 pobject->next->previous = pobject->previous; |
| 97 if( pobject->previous ) |
| 98 pobject->previous->next = pobject->next; |
| 99 |
| 100 free( pobject ); |
| 101 } |
| 102 |
| 103 /* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one |
| 104 * static buffer. |
| 105 * MSDN says the buffer cannot be larger than 64K bytes, so we set it to |
| 106 * the limit. |
| 107 */ |
| 108 static char error_buffer[65535]; |
| 109 static char *current_error; |
| 110 |
| 111 static int copy_string( char *dest, int dest_size, const char *src ) |
| 112 { |
| 113 int i = 0; |
| 114 |
| 115 /* gcc should optimize this out */ |
| 116 if( !src || !dest ) |
| 117 return 0; |
| 118 |
| 119 for( i = 0 ; i < dest_size-1 ; i++ ) |
| 120 { |
| 121 if( !src[i] ) |
| 122 break; |
| 123 else |
| 124 dest[i] = src[i]; |
| 125 } |
| 126 dest[i] = '\0'; |
| 127 |
| 128 return i; |
| 129 } |
| 130 |
| 131 static void save_err_str( const char *str ) |
| 132 { |
| 133 DWORD dwMessageId; |
| 134 DWORD pos; |
| 135 |
| 136 dwMessageId = GetLastError( ); |
| 137 |
| 138 if( dwMessageId == 0 ) |
| 139 return; |
| 140 |
| 141 /* Format error message to: |
| 142 * "<argument to function that failed>": <Windows localized error message> |
| 143 */ |
| 144 pos = copy_string( error_buffer, sizeof(error_buffer), "\"" ); |
| 145 pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, str ); |
| 146 pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, "\": " ); |
| 147 pos += FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId, |
| 148 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), |
| 149 error_buffer+pos, sizeof(error_buffer)-pos, NULL ); |
| 150 |
| 151 if( pos > 1 ) |
| 152 { |
| 153 /* POSIX says the string must not have trailing <newline> */ |
| 154 if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' ) |
| 155 error_buffer[pos-2] = '\0'; |
| 156 } |
| 157 |
| 158 current_error = error_buffer; |
| 159 } |
| 160 |
| 161 static void save_err_ptr_str( const void *ptr ) |
| 162 { |
| 163 char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */ |
| 164 |
| 165 sprintf( ptr_buf, "0x%p", ptr ); |
| 166 |
| 167 save_err_str( ptr_buf ); |
| 168 } |
| 169 |
| 170 void *dlopen( const char *file, int mode ) |
| 171 { |
| 172 HMODULE hModule; |
| 173 UINT uMode; |
| 174 |
| 175 current_error = NULL; |
| 176 |
| 177 /* Do not let Windows display the critical-error-handler message box */ |
| 178 uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); |
| 179 |
| 180 if( file == 0 ) |
| 181 { |
| 182 /* POSIX says that if the value of file is 0, a handle on a global |
| 183 * symbol object must be provided. That object must be able to access |
| 184 * all symbols from the original program file, and any objects loaded |
| 185 * with the RTLD_GLOBAL flag. |
| 186 * The return value from GetModuleHandle( ) allows us to retrieve |
| 187 * symbols only from the original program file. For objects loaded with |
| 188 * the RTLD_GLOBAL flag, we create our own list later on. |
| 189 */ |
| 190 hModule = GetModuleHandle( NULL ); |
| 191 |
| 192 if( !hModule ) |
| 193 save_err_ptr_str( file ); |
| 194 } |
| 195 else |
| 196 { |
| 197 char lpFileName[MAX_PATH]; |
| 198 int i; |
| 199 |
| 200 /* MSDN says backslashes *must* be used instead of forward slashes. */ |
| 201 for( i = 0 ; i < sizeof(lpFileName)-1 ; i++ ) |
| 202 { |
| 203 if( !file[i] ) |
| 204 break; |
| 205 else if( file[i] == '/' ) |
| 206 lpFileName[i] = '\\'; |
| 207 else |
| 208 lpFileName[i] = file[i]; |
| 209 } |
| 210 lpFileName[i] = '\0'; |
| 211 |
| 212 /* POSIX says the search path is implementation-defined. |
| 213 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely |
| 214 * to UNIX's search paths (start with system folders instead of current |
| 215 * folder). |
| 216 */ |
| 217 hModule = LoadLibraryEx( (LPSTR) lpFileName, NULL, |
| 218 LOAD_WITH_ALTERED_SEARCH_PATH ); |
| 219 |
| 220 /* If the object was loaded with RTLD_GLOBAL, add it to list of global |
| 221 * objects, so that its symbols may be retrieved even if the handle for |
| 222 * the original program file is passed. POSIX says that if the same |
| 223 * file is specified in multiple invocations, and any of them are |
| 224 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the |
| 225 * symbols will remain global. |
| 226 */ |
| 227 if( !hModule ) |
| 228 save_err_str( lpFileName ); |
| 229 else if( (mode & RTLD_GLOBAL) ) |
| 230 global_add( hModule ); |
| 231 } |
| 232 |
| 233 /* Return to previous state of the error-mode bit flags. */ |
| 234 SetErrorMode( uMode ); |
| 235 |
| 236 return (void *) hModule; |
| 237 } |
| 238 |
| 239 int dlclose( void *handle ) |
| 240 { |
| 241 HMODULE hModule = (HMODULE) handle; |
| 242 BOOL ret; |
| 243 |
| 244 current_error = NULL; |
| 245 |
| 246 ret = FreeLibrary( hModule ); |
| 247 |
| 248 /* If the object was loaded with RTLD_GLOBAL, remove it from list of global |
| 249 * objects. |
| 250 */ |
| 251 if( ret ) |
| 252 global_rem( hModule ); |
| 253 else |
| 254 save_err_ptr_str( handle ); |
| 255 |
| 256 /* dlclose's return value in inverted in relation to FreeLibrary's. */ |
| 257 ret = !ret; |
| 258 |
| 259 return (int) ret; |
| 260 } |
| 261 |
| 262 void *dlsym( void *handle, const char *name ) |
| 263 { |
| 264 FARPROC symbol; |
| 265 |
| 266 current_error = NULL; |
| 267 |
| 268 symbol = GetProcAddress( handle, name ); |
| 269 |
| 270 if( symbol == NULL ) |
| 271 { |
| 272 HMODULE hModule; |
| 273 |
| 274 /* If the handle for the original program file is passed, also search |
| 275 * in all globally loaded objects. |
| 276 */ |
| 277 |
| 278 hModule = GetModuleHandle( NULL ); |
| 279 |
| 280 if( hModule == handle ) |
| 281 { |
| 282 global_object *pobject; |
| 283 |
| 284 for( pobject = &first_object; pobject ; pobject = pobject->next ) |
| 285 { |
| 286 if( pobject->hModule ) |
| 287 { |
| 288 symbol = GetProcAddress( pobject->hModule, name ); |
| 289 if( symbol != NULL ) |
| 290 break; |
| 291 } |
| 292 } |
| 293 } |
| 294 } |
| 295 |
| 296 if( symbol == NULL ) |
| 297 save_err_str( name ); |
| 298 |
| 299 return (void*) symbol; |
| 300 } |
| 301 |
| 302 char *dlerror( void ) |
| 303 { |
| 304 char *error_pointer = current_error; |
| 305 |
| 306 /* POSIX says that invoking dlerror( ) a second time, immediately following |
| 307 * a prior invocation, shall result in NULL being returned. |
| 308 */ |
| 309 current_error = NULL; |
| 310 |
| 311 return error_pointer; |
| 312 } |
| OLD | NEW |