root/libltdl/loaders/loadlibrary.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_vtable
  2. vl_exit
  3. vm_open
  4. vm_close
  5. vm_sym
  6. loadlibraryerror
  7. wrap_getthreaderrormode
  8. fallback_getthreaderrormode
  9. wrap_setthreaderrormode
  10. fallback_setthreaderrormode

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */