OSDN Git Service

2012-01-06 Chris Sutcliffe <ir0nh34d@users.sf.net>
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / hookapi.cc
index 26aff51..8137b85 100644 (file)
@@ -1,13 +1,23 @@
+/* hookapi.cc
+
+   Copyright 2005, 2006, 2007, 2008, 2011 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
 #include "winsup.h"
+#include <stdlib.h>
+#include <sys/param.h>
+#include "ntdll.h"
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
 #include "fhandler.h"
 #include "dtable.h"
 #include "cygheap.h"
-#include <stdlib.h>
-#include <imagehlp.h>
-#include <alloca.h>
 
 #define rva(coerce, base, addr) (coerce) ((char *) (base) + (addr))
 #define rvacyg(coerce, addr) rva (coerce, cygwin_hmodule, addr)
@@ -38,19 +48,19 @@ PEHeaderFromHModule (HMODULE hModule)
   return pNTHeader;
 }
 
-long
+static long
 rvadelta (PIMAGE_NT_HEADERS pnt, DWORD import_rva)
 {
   PIMAGE_SECTION_HEADER section = (PIMAGE_SECTION_HEADER) (pnt + 1);
   for (int i = 0; i < pnt->FileHeader.NumberOfSections; i++)
     if (section[i].VirtualAddress <= import_rva
-       && (section[i].VirtualAddress + section[i].Misc.VirtualSize) >= import_rva)
-    // if (strncasematch ((char *) section[i].Name, ".idata", IMAGE_SIZEOF_SHORT_NAME))
+       && (section[i].VirtualAddress + section[i].Misc.VirtualSize) > import_rva)
+    // if (ascii_strncasematch ((char *) section[i].Name, ".idata", IMAGE_SIZEOF_SHORT_NAME))
       return section[i].VirtualAddress - section[i].PointerToRawData;
   return -1;
 }
 
-void *
+static void *
 putmem (PIMAGE_THUNK_DATA pi, const void *hookfn)
 {
   DWORD ofl;
@@ -97,7 +107,7 @@ RedirectIAT (function_hook& fh, PIMAGE_IMPORT_DESCRIPTOR pImportDesc,
          hook_chain *hc;
          for (hc = &cygheap->hooks; hc->next; hc = hc->next)
            continue;
-         hc->next = (hook_chain *) cmalloc (HEAP_1_HOOK, sizeof (hook_chain));
+         hc->next = (hook_chain *) cmalloc_abort (HEAP_1_HOOK, sizeof (hook_chain));
          hc->next->loc = (void **) pi;
          hc->next->func = fh.hookfn;
          hc->next->next = NULL;
@@ -108,10 +118,9 @@ RedirectIAT (function_hook& fh, PIMAGE_IMPORT_DESCRIPTOR pImportDesc,
   return true;
 }
 
-void
+static void
 get_export (function_hook& fh)
 {
-  extern HMODULE cygwin_hmodule;
   PIMAGE_DOS_HEADER pdh = (PIMAGE_DOS_HEADER) cygwin_hmodule;
   if (pdh->e_magic != IMAGE_DOS_SIGNATURE)
     return;
@@ -149,9 +158,76 @@ makename (const char *name, char *&buf, int& i, int inc)
   return name;
 }
 
-// Top level routine to find the EXE's imports, and redirect them
+/* Find first missing dll in a given executable.
+   FIXME: This is not foolproof since it doesn't look for dlls in the
+   same directory as the given executable, like Windows.  Instead it
+   searches for dlls in the context of the current executable.  */
+const char *
+find_first_notloaded_dll (path_conv& pc)
+{
+  const char *res = "?";
+  HANDLE hc = NULL;
+  HMODULE hm = NULL;
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
+  HANDLE h;
+  NTSTATUS status;
+
+  status = NtOpenFile (&h, SYNCHRONIZE | GENERIC_READ,
+                      pc.get_object_attr (attr, sec_none_nih),
+                      &io, FILE_SHARE_VALID_FLAGS,
+                      FILE_SYNCHRONOUS_IO_NONALERT
+                      | FILE_OPEN_FOR_BACKUP_INTENT
+                      | FILE_NON_DIRECTORY_FILE);
+  if (!NT_SUCCESS (status))
+    goto out;
+
+  hc = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL);
+  NtClose (h);
+  if (!hc)
+    goto out;
+  hm = (HMODULE) MapViewOfFile(hc, FILE_MAP_READ, 0, 0, 0);
+  CloseHandle (hc);
+
+  PIMAGE_NT_HEADERS pExeNTHdr;
+  pExeNTHdr = PEHeaderFromHModule (hm);
+
+  if (pExeNTHdr)
+    {
+      DWORD importRVA;
+      importRVA = pExeNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+      if (importRVA)
+       {
+         long delta = rvadelta (pExeNTHdr, importRVA);
+
+         // Convert imports RVA to a usable pointer
+         PIMAGE_IMPORT_DESCRIPTOR pdfirst;
+         pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
+
+         // Iterate through each import descriptor, and redirect if appropriate
+         for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
+           {
+             const char *lib = rva (PSTR, hm, pd->Name - delta);
+             if (!LoadLibraryEx (lib, NULL, DONT_RESOLVE_DLL_REFERENCES
+                                            | LOAD_LIBRARY_AS_DATAFILE))
+               {
+                 static char buf[NT_MAX_PATH];
+                 res = strcpy (buf, lib);
+               }
+           }
+       }
+    }
+
+out:
+  if (hm)
+    UnmapViewOfFile (hm);
+
+  return res;
+}
+
+// Top level routine to find the EXE's imports and redirect them
 void *
-hook_or_detect_cygwin (const char *name, const void *fn)
+hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys, HANDLE h)
 {
   HMODULE hm = fn ? GetModuleHandle (NULL) : (HMODULE) name;
   PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
@@ -159,30 +235,58 @@ hook_or_detect_cygwin (const char *name, const void *fn)
   if (!pExeNTHdr)
     return false;
 
+  subsys =  pExeNTHdr->OptionalHeader.Subsystem;
+
   DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
                      [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+  DWORD importRVASize = pExeNTHdr->OptionalHeader.DataDirectory
+                       [IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
   if (!importRVA)
     return false;
 
   long delta = fn ? 0 : rvadelta (pExeNTHdr, importRVA);
   if (delta < 0)
     return false;
+  importRVA -= delta;
 
   // Convert imports RVA to a usable pointer
-  PIMAGE_IMPORT_DESCRIPTOR pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
+  PIMAGE_IMPORT_DESCRIPTOR pdfirst;
+  char *map = NULL;
+  DWORD offset = 0;
+  if (h && importRVA + importRVASize > wincap.allocation_granularity ())
+    {
+      /* If h is not NULL, the calling function only mapped at most the first
+        64K of the image.  The IAT is usually at the end of the image, so
+        what we do here is to map the IAT into our address space if it doesn't
+        reside in the first 64K anyway.  The offset must be a multiple of the
+        allocation granularity, though, so we have to map a bit more. */
+      offset = rounddown (importRVA, wincap.allocation_granularity ());
+      DWORD size = importRVA - offset + importRVASize;
+      map = (char *) MapViewOfFile (h, FILE_MAP_READ, 0, offset, size);
+      if (!map)
+       return false;
+      pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, map, importRVA - offset);
+    }
+  else
+    pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA);
 
   function_hook fh;
   fh.origfn = NULL;
   fh.hookfn = fn;
   char *buf = (char *) alloca (strlen (name) + sizeof ("_64"));
-  int i;
+  int i = 0;
   // Iterate through each import descriptor, and redirect if appropriate
   for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
     {
-      if (!strcasematch (rva (PSTR, hm, pd->Name - delta), "cygwin1.dll"))
+      if (!ascii_strcasematch (rva (PSTR, map ?: (char *) hm,
+                                   pd->Name - delta - offset), "cygwin1.dll"))
        continue;
       if (!fn)
-       return (void *) "found it";     // just checking if executable used cygwin1.dll
+       {
+         if (map)
+           UnmapViewOfFile (map);
+         return (void *) "found it";   // just checking if executable used cygwin1.dll
+       }
       i = -1;
       while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
        RedirectIAT (fh, pd, hm);
@@ -190,6 +294,9 @@ hook_or_detect_cygwin (const char *name, const void *fn)
        break;
     }
 
+  if (map)
+    UnmapViewOfFile (map);
+
   while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))
     get_export (fh);
 
@@ -208,7 +315,8 @@ ld_preload ()
   for (p = strtok_r (s, ":\t\n", &here); p; p = strtok_r (NULL, ":\t\n", &here))
     {
       path_conv lib (p);
-      if (!LoadLibrary (lib))
+      WCHAR libname[lib.get_wide_win32_path_len () + 1];
+      if (!LoadLibraryW (lib.get_wide_win32_path (libname)))
        {
          __seterrno ();
          api_fatal ("error while loading shared libraries: %s: "