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


rtt
Author(s): RTT Developers
autogenerated on Fri Oct 25 2019 03:59:33