Imported Upstream version 2.4.2
[platform/upstream/libtool.git] / libltdl / loaders / loadlibrary.c
1 /* loader-loadlibrary.c --  dynamic linking for Win32
2
3    Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006,
4                  2007, 2008, 2010 Free Software Foundation, Inc.
5    Written by Thomas Tanner, 1998
6
7    NOTE: The canonical source of this file is maintained with the
8    GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
9
10 GNU Libltdl is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14
15 As a special exception to the GNU Lesser General Public License,
16 if you distribute this file as part of a program or library that
17 is built using GNU Libtool, you may include this file under the
18 same distribution terms that you use for the rest of that program.
19
20 GNU Libltdl is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 GNU Lesser General Public License for more details.
24
25 You should have received a copy of the GNU Lesser General Public
26 License along with GNU Libltdl; see the file COPYING.LIB.  If not, a
27 copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
28 or obtained by writing to the Free Software Foundation, Inc.,
29 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 */
31
32 #include "lt__private.h"
33 #include "lt_dlloader.h"
34
35 #if defined(__CYGWIN__)
36 # include <sys/cygwin.h>
37 #endif
38
39 /* Use the preprocessor to rename non-static symbols to avoid namespace
40    collisions when the loader code is statically linked into libltdl.
41    Use the "<module_name>_LTX_" prefix so that the symbol addresses can
42    be fetched from the preloaded symbol list by lt_dlsym():  */
43 #define get_vtable      loadlibrary_LTX_get_vtable
44
45 LT_BEGIN_C_DECLS
46 LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
47 LT_END_C_DECLS
48
49
50 /* Boilerplate code to set up the vtable for hooking this loader into
51    libltdl's loader list:  */
52 static int       vl_exit  (lt_user_data loader_data);
53 static lt_module vm_open  (lt_user_data loader_data, const char *filename,
54                            lt_dladvise advise);
55 static int       vm_close (lt_user_data loader_data, lt_module module);
56 static void *    vm_sym   (lt_user_data loader_data, lt_module module,
57                           const char *symbolname);
58
59 static lt_dlinterface_id iface_id = 0;
60 static lt_dlvtable *vtable = 0;
61
62 /* Return the vtable for this loader, only the name and sym_prefix
63    attributes (plus the virtual function implementations, obviously)
64    change between loaders.  */
65 lt_dlvtable *
66 get_vtable (lt_user_data loader_data)
67 {
68   if (!vtable)
69     {
70       vtable = (lt_dlvtable *) lt__zalloc (sizeof *vtable);
71       iface_id = lt_dlinterface_register ("ltdl loadlibrary", NULL);
72     }
73
74   if (vtable && !vtable->name)
75     {
76       vtable->name              = "lt_loadlibrary";
77       vtable->module_open       = vm_open;
78       vtable->module_close      = vm_close;
79       vtable->find_sym          = vm_sym;
80       vtable->dlloader_exit     = vl_exit;
81       vtable->dlloader_data     = loader_data;
82       vtable->priority          = LT_DLLOADER_APPEND;
83     }
84
85   if (vtable && (vtable->dlloader_data != loader_data))
86     {
87       LT__SETERROR (INIT_LOADER);
88       return 0;
89     }
90
91   return vtable;
92 }
93
94
95
96 /* --- IMPLEMENTATION --- */
97
98
99 #include <windows.h>
100
101 #define LOCALFREE(mem)                                       LT_STMT_START { \
102         if (mem) { LocalFree ((void *)mem); mem = NULL; }    } LT_STMT_END
103 #define LOADLIB__SETERROR(errmsg) LT__SETERRORSTR (loadlibraryerror (errmsg))
104 #define LOADLIB_SETERROR(errcode) LOADLIB__SETERROR (LT__STRERROR (errcode))
105
106 static const char *loadlibraryerror (const char *default_errmsg);
107 static DWORD WINAPI wrap_getthreaderrormode (void);
108 static DWORD WINAPI fallback_getthreaderrormode (void);
109 static BOOL WINAPI wrap_setthreaderrormode (DWORD mode, DWORD *oldmode);
110 static BOOL WINAPI fallback_setthreaderrormode (DWORD mode, DWORD *oldmode);
111
112 typedef DWORD (WINAPI getthreaderrormode_type) (void);
113 typedef BOOL (WINAPI setthreaderrormode_type) (DWORD, DWORD *);
114
115 static getthreaderrormode_type *getthreaderrormode = wrap_getthreaderrormode;
116 static setthreaderrormode_type *setthreaderrormode = wrap_setthreaderrormode;
117 static char *error_message = 0;
118
119
120 /* A function called through the vtable when this loader is no
121    longer needed by the application.  */
122 static int
123 vl_exit (lt_user_data LT__UNUSED loader_data)
124 {
125   vtable = NULL;
126   LOCALFREE (error_message);
127   return 0;
128 }
129
130 /* A function called through the vtable to open a module with this
131    loader.  Returns an opaque representation of the newly opened
132    module for processing with this loader's other vtable functions.  */
133 static lt_module
134 vm_open (lt_user_data LT__UNUSED loader_data, const char *filename,
135          lt_dladvise LT__UNUSED advise)
136 {
137   lt_module     module     = 0;
138   char          *ext;
139   char          wpath[MAX_PATH];
140   size_t        len;
141
142   if (!filename)
143     {
144       /* Get the name of main module */
145       *wpath = 0;
146       GetModuleFileName (NULL, wpath, sizeof (wpath));
147       filename = wpath;
148     }
149   else
150     {
151       len = LT_STRLEN (filename);
152
153       if (len >= MAX_PATH)
154         {
155           LT__SETERROR (CANNOT_OPEN);
156           return 0;
157         }
158
159 #if HAVE_DECL_CYGWIN_CONV_PATH
160       if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, filename, wpath, MAX_PATH))
161         {
162           LT__SETERROR (CANNOT_OPEN);
163           return 0;
164         }
165       len = 0;
166 #elif defined(__CYGWIN__)
167       cygwin_conv_to_full_win32_path (filename, wpath);
168       len = 0;
169 #else
170       strcpy(wpath, filename);
171 #endif
172
173       ext = strrchr (wpath, '.');
174       if (!ext)
175         {
176           /* Append a `.' to stop Windows from adding an
177              implicit `.dll' extension. */
178           if (!len)
179             len = strlen (wpath);
180
181           if (len + 1 >= MAX_PATH)
182             {
183               LT__SETERROR (CANNOT_OPEN);
184               return 0;
185             }
186
187           wpath[len] = '.';
188           wpath[len+1] = '\0';
189         }
190     }
191
192   {
193     /* Silence dialog from LoadLibrary on some failures. */
194     DWORD errormode = getthreaderrormode ();
195     DWORD last_error;
196
197     setthreaderrormode (errormode | SEM_FAILCRITICALERRORS, NULL);
198
199     module = LoadLibrary (wpath);
200
201     /* Restore the error mode. */
202     last_error = GetLastError ();
203     setthreaderrormode (errormode, NULL);
204     SetLastError (last_error);
205   }
206
207   /* libltdl expects this function to fail if it is unable
208      to physically load the library.  Sadly, LoadLibrary
209      will search the loaded libraries for a match and return
210      one of them if the path search load fails.
211
212      We check whether LoadLibrary is returning a handle to
213      an already loaded module, and simulate failure if we
214      find one. */
215   {
216     lt_dlhandle cur = 0;
217
218     while ((cur = lt_dlhandle_iterate (iface_id, cur)))
219       {
220         if (!cur->module)
221           {
222             cur = 0;
223             break;
224           }
225
226         if (cur->module == module)
227           {
228             break;
229           }
230       }
231
232     if (!module)
233       LOADLIB_SETERROR (CANNOT_OPEN);
234     else if (cur)
235       {
236         LT__SETERROR (CANNOT_OPEN);
237         module = 0;
238       }
239   }
240
241   return module;
242 }
243
244
245 /* A function called through the vtable when a particular module
246    should be unloaded.  */
247 static int
248 vm_close (lt_user_data LT__UNUSED loader_data, lt_module module)
249 {
250   int errors = 0;
251
252   if (FreeLibrary ((HMODULE) module) == 0)
253     {
254       LOADLIB_SETERROR (CANNOT_CLOSE);
255       ++errors;
256     }
257
258   return errors;
259 }
260
261
262 /* A function called through the vtable to get the address of
263    a symbol loaded from a particular module.  */
264 static void *
265 vm_sym (lt_user_data LT__UNUSED loader_data, lt_module module, const char *name)
266 {
267   void *address = (void *) GetProcAddress ((HMODULE) module, name);
268
269   if (!address)
270     {
271       LOADLIB_SETERROR (SYMBOL_NOT_FOUND);
272     }
273
274   return address;
275 }
276
277
278
279 /* --- HELPER FUNCTIONS --- */
280
281
282 /* Return the windows error message, or the passed in error message on
283    failure. */
284 static const char *
285 loadlibraryerror (const char *default_errmsg)
286 {
287   size_t len;
288   LOCALFREE (error_message);
289
290   FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
291                   FORMAT_MESSAGE_FROM_SYSTEM |
292                   FORMAT_MESSAGE_IGNORE_INSERTS,
293                   NULL,
294                   GetLastError (),
295                   0,
296                   (char *) &error_message,
297                   0, NULL);
298
299   /* Remove trailing CRNL */
300   len = LT_STRLEN (error_message);
301   if (len && error_message[len - 1] == '\n')
302     error_message[--len] = LT_EOS_CHAR;
303   if (len && error_message[len - 1] == '\r')
304     error_message[--len] = LT_EOS_CHAR;
305
306   return len ? error_message : default_errmsg;
307 }
308
309 /* A function called through the getthreaderrormode variable which checks
310    if the system supports GetThreadErrorMode (or GetErrorMode) and arranges
311    for it or a fallback implementation to be called directly in the future.
312    The selected version is then called. */
313 static DWORD WINAPI
314 wrap_getthreaderrormode (void)
315 {
316   HMODULE kernel32 = GetModuleHandleA ("kernel32.dll");
317   getthreaderrormode
318     = (getthreaderrormode_type *) GetProcAddress (kernel32,
319                                                   "GetThreadErrorMode");
320   if (!getthreaderrormode)
321     getthreaderrormode
322       = (getthreaderrormode_type *) GetProcAddress (kernel32,
323                                                     "GetErrorMode");
324   if (!getthreaderrormode)
325     getthreaderrormode = fallback_getthreaderrormode;
326   return getthreaderrormode ();
327 }
328
329 /* A function called through the getthreaderrormode variable for cases
330    where the system does not support GetThreadErrorMode or GetErrorMode */
331 static DWORD WINAPI
332 fallback_getthreaderrormode (void)
333 {
334   /* Prior to Windows Vista, the only way to get the current error
335      mode was to set a new one. In our case, we are setting a new
336      error mode right after "getting" it while ignoring the error
337      mode in effect when setting the new error mode, so that's
338      fairly ok. */
339   return (DWORD) SetErrorMode (SEM_FAILCRITICALERRORS);
340 }
341
342 /* A function called through the setthreaderrormode variable which checks
343    if the system supports SetThreadErrorMode and arranges for it or a
344    fallback implementation to be called directly in the future.
345    The selected version is then called. */
346 static BOOL WINAPI
347 wrap_setthreaderrormode (DWORD mode, DWORD *oldmode)
348 {
349   HMODULE kernel32 = GetModuleHandleA ("kernel32.dll");
350   setthreaderrormode
351     = (setthreaderrormode_type *) GetProcAddress (kernel32,
352                                                   "SetThreadErrorMode");
353   if (!setthreaderrormode)
354     setthreaderrormode = fallback_setthreaderrormode;
355   return setthreaderrormode (mode, oldmode);
356 }
357
358 /* A function called through the setthreaderrormode variable for cases
359    where the system does not support SetThreadErrorMode. */
360 static BOOL WINAPI
361 fallback_setthreaderrormode (DWORD mode, DWORD *oldmode)
362 {
363   /* Prior to Windows 7, there was no way to set the thread local error
364      mode, so set the process global error mode instead. */
365   DWORD old = (DWORD) SetErrorMode (mode);
366   if (oldmode)
367     *oldmode = old;
368   return TRUE;
369 }