$search
00001 /* 00002 * dlfcn-win32 00003 * Copyright (c) 2007 Ramiro Polla 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00018 */ 00019 00020 #include "dlfcn.h" 00021 #include <stdio.h> 00022 #include <stdlib.h> 00023 00024 /* Note: 00025 * MSDN says these functions are not thread-safe. We make no efforts to have 00026 * any kind of thread safety. 00027 */ 00028 00029 typedef struct global_object { 00030 HMODULE hModule; 00031 struct global_object *previous; 00032 struct global_object *next; 00033 } global_object; 00034 00035 static global_object first_object; 00036 00037 /* These functions implement a double linked list for the global objects. */ 00038 static global_object *global_search( HMODULE hModule ) 00039 { 00040 global_object *pobject; 00041 00042 if( hModule == NULL ) 00043 return NULL; 00044 00045 for( pobject = &first_object; pobject ; pobject = pobject->next ) 00046 if( pobject->hModule == hModule ) 00047 return pobject; 00048 00049 return NULL; 00050 } 00051 00052 static void global_add( HMODULE hModule ) 00053 { 00054 global_object *pobject; 00055 global_object *nobject; 00056 00057 if( hModule == NULL ) 00058 return; 00059 00060 pobject = global_search( hModule ); 00061 00062 /* Do not add object again if it's already on the list */ 00063 if( pobject ) 00064 return; 00065 00066 for( pobject = &first_object; pobject->next ; pobject = pobject->next ); 00067 00068 nobject = malloc( sizeof(global_object) ); 00069 00070 /* Should this be enough to fail global_add, and therefore also fail 00071 * dlopen? 00072 */ 00073 if( !nobject ) 00074 return; 00075 00076 pobject->next = nobject; 00077 nobject->next = NULL; 00078 nobject->previous = pobject; 00079 nobject->hModule = hModule; 00080 } 00081 00082 static void global_rem( HMODULE hModule ) 00083 { 00084 global_object *pobject; 00085 00086 if( hModule == NULL ) 00087 return; 00088 00089 pobject = global_search( hModule ); 00090 00091 if( !pobject ) 00092 return; 00093 00094 if( pobject->next ) 00095 pobject->next->previous = pobject->previous; 00096 if( pobject->previous ) 00097 pobject->previous->next = pobject->next; 00098 00099 free( pobject ); 00100 } 00101 00102 /* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one 00103 * static buffer. 00104 * MSDN says the buffer cannot be larger than 64K bytes, so we set it to 00105 * the limit. 00106 */ 00107 static char error_buffer[65535]; 00108 static char *current_error; 00109 00110 static int copy_string( char *dest, int dest_size, const char *src ) 00111 { 00112 int i = 0; 00113 00114 /* gcc should optimize this out */ 00115 if( !src && !dest ) 00116 return 0; 00117 00118 for( i = 0 ; i < dest_size-1 ; i++ ) 00119 { 00120 if( !src[i] ) 00121 break; 00122 else 00123 dest[i] = src[i]; 00124 } 00125 dest[i] = '\0'; 00126 00127 return i; 00128 } 00129 00130 static void save_err_str( const char *str ) 00131 { 00132 DWORD dwMessageId; 00133 DWORD pos; 00134 00135 dwMessageId = GetLastError( ); 00136 00137 if( dwMessageId == 0 ) 00138 return; 00139 00140 /* Format error message to: 00141 * "<argument to function that failed>": <Windows localized error message> 00142 */ 00143 pos = copy_string( error_buffer, sizeof(error_buffer), "\"" ); 00144 pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, str ); 00145 pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, "\": " ); 00146 pos += FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId, 00147 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), 00148 error_buffer+pos, sizeof(error_buffer)-pos, NULL ); 00149 00150 if( pos > 1 ) 00151 { 00152 /* POSIX says the string must not have trailing <newline> */ 00153 if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' ) 00154 error_buffer[pos-2] = '\0'; 00155 } 00156 00157 current_error = error_buffer; 00158 } 00159 00160 static void save_err_ptr_str( const void *ptr ) 00161 { 00162 char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */ 00163 00164 sprintf( ptr_buf, "0x%p", ptr ); 00165 00166 save_err_str( ptr_buf ); 00167 } 00168 00169 void *dlopen( const char *file, int mode ) 00170 { 00171 HMODULE hModule; 00172 UINT uMode; 00173 00174 current_error = NULL; 00175 00176 /* Do not let Windows display the critical-error-handler message box */ 00177 uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); 00178 00179 if( file == 0 ) 00180 { 00181 /* POSIX says that if the value of file is 0, a handle on a global 00182 * symbol object must be provided. That object must be able to access 00183 * all symbols from the original program file, and any objects loaded 00184 * with the RTLD_GLOBAL flag. 00185 * The return value from GetModuleHandle( ) allows us to retrieve 00186 * symbols only from the original program file. For objects loaded with 00187 * the RTLD_GLOBAL flag, we create our own list later on. 00188 */ 00189 hModule = GetModuleHandle( NULL ); 00190 00191 if( !hModule ) 00192 save_err_ptr_str( file ); 00193 } 00194 else 00195 { 00196 char lpFileName[MAX_PATH]; 00197 int i; 00198 00199 /* MSDN says backslashes *must* be used instead of forward slashes. */ 00200 for( i = 0 ; i < sizeof(lpFileName)-1 ; i++ ) 00201 { 00202 if( !file[i] ) 00203 break; 00204 else if( file[i] == '/' ) 00205 lpFileName[i] = '\\'; 00206 else 00207 lpFileName[i] = file[i]; 00208 } 00209 lpFileName[i] = '\0'; 00210 00211 /* POSIX says the search path is implementation-defined. 00212 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely 00213 * to UNIX's search paths (start with system folders instead of current 00214 * folder). 00215 */ 00216 hModule = LoadLibraryEx( (LPSTR) lpFileName, NULL, 00217 LOAD_WITH_ALTERED_SEARCH_PATH ); 00218 00219 /* If the object was loaded with RTLD_GLOBAL, add it to list of global 00220 * objects, so that its symbols may be retrieved even if the handle for 00221 * the original program file is passed. POSIX says that if the same 00222 * file is specified in multiple invocations, and any of them are 00223 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the 00224 * symbols will remain global. 00225 */ 00226 if( !hModule ) 00227 save_err_str( lpFileName ); 00228 else if( (mode & RTLD_GLOBAL) ) 00229 global_add( hModule ); 00230 } 00231 00232 /* Return to previous state of the error-mode bit flags. */ 00233 SetErrorMode( uMode ); 00234 00235 return (void *) hModule; 00236 } 00237 00238 int dlclose( void *handle ) 00239 { 00240 HMODULE hModule = (HMODULE) handle; 00241 BOOL ret; 00242 00243 current_error = NULL; 00244 00245 ret = FreeLibrary( hModule ); 00246 00247 /* If the object was loaded with RTLD_GLOBAL, remove it from list of global 00248 * objects. 00249 */ 00250 if( ret ) 00251 global_rem( hModule ); 00252 else 00253 save_err_ptr_str( handle ); 00254 00255 /* dlclose's return value in inverted in relation to FreeLibrary's. */ 00256 ret = !ret; 00257 00258 return (int) ret; 00259 } 00260 00261 void *dlsym( void *handle, const char *name ) 00262 { 00263 FARPROC symbol; 00264 00265 current_error = NULL; 00266 00267 symbol = GetProcAddress( handle, name ); 00268 00269 if( symbol == NULL ) 00270 { 00271 HMODULE hModule; 00272 00273 /* If the handle for the original program file is passed, also search 00274 * in all globally loaded objects. 00275 */ 00276 00277 hModule = GetModuleHandle( NULL ); 00278 00279 if( hModule == handle ) 00280 { 00281 global_object *pobject; 00282 00283 for( pobject = &first_object; pobject ; pobject = pobject->next ) 00284 { 00285 if( pobject->hModule ) 00286 { 00287 symbol = GetProcAddress( pobject->hModule, name ); 00288 if( symbol != NULL ) 00289 break; 00290 } 00291 } 00292 } 00293 /* We don't need to close hModule since GetModuleHandle() 00294 * Does not increment the refcount. 00295 */ 00296 } 00297 00298 if( symbol == NULL ) 00299 save_err_str( name ); 00300 00301 return (void*) symbol; 00302 } 00303 00304 char *dlerror( void ) 00305 { 00306 char *error_pointer = current_error; 00307 00308 /* POSIX says that invoking dlerror( ) a second time, immediately following 00309 * a prior invocation, shall result in NULL being returned. 00310 */ 00311 current_error = NULL; 00312 00313 return error_pointer; 00314 }