]> sourceware.org Git - newlib-cygwin.git/commitdiff
* fhandler_process.cc (format_process_maps): Rework to report
authorCorinna Vinschen <corinna@vinschen.de>
Wed, 11 May 2011 10:31:22 +0000 (10:31 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Wed, 11 May 2011 10:31:22 +0000 (10:31 +0000)
all mapped address space in a process (committed or reserved),
identifying the nature of the mapping (mapped file/image, heap,
shared memory) when possible.
(dos_drive_mappings): New helper classes.
(heap_info): Ditto.
* ntdll.h (struct _MEMORY_SECTION_NAME): Define.

winsup/cygwin/ChangeLog
winsup/cygwin/fhandler_process.cc
winsup/cygwin/ntdll.h

index 017987f7d63831a936feaaf636dd100b4f1eb61c..c4fb8c9397c839ea75972d19db493136cb4ed2ce 100644 (file)
@@ -1,3 +1,13 @@
+2011-05-11  Ryan Johnson  <ryan.johnson@cs.utoronto.ca>
+
+       * fhandler_process.cc (format_process_maps): Rework to report
+       all mapped address space in a process (committed or reserved),
+       identifying the nature of the mapping (mapped file/image, heap,
+       shared memory) when possible.
+       (dos_drive_mappings): New helper classes.
+       (heap_info): Ditto.
+       * ntdll.h (struct _MEMORY_SECTION_NAME): Define.
+
 2011-05-11  Corinna Vinschen  <corinna@vinschen.de>
 
        * autoload.cc (GetProcessMemoryInfo): Remove.
index 599f242b5eebb71354e63ccf1d30e9841d847460..3d353096cec52d46012f9ddb7bc0ad89ee7ca38f 100644 (file)
@@ -29,6 +29,7 @@ details. */
 #include <sys/param.h>
 #include <ctype.h>
 #include <psapi.h>
+#include <tlhelp32.h>
 
 #define _COMPILING_NEWLIB
 #include <dirent.h>
@@ -527,6 +528,136 @@ format_process_winexename (void *data, char *&destbuf)
   return len + 1;
 }
 
+struct dos_drive_mappings
+{
+  struct mapping
+  {
+    mapping *next;
+    int len;
+    wchar_t drive_letter;
+    wchar_t mapping[1];
+  };
+  mapping *mappings;
+  
+  dos_drive_mappings ()
+    : mappings(0)
+  {
+    /* The logical drive strings buffer holds a list of (at most 26)
+       drive names separated by nulls and terminated by a double-null:
+
+       "a:\\\0b:\\\0...z:\\\0"
+
+       The annoying part is, QueryDosDeviceW wants only "x:" rather
+       than the "x:\" we get back from GetLogicalDriveStringsW, so
+       we'll have to strip out the trailing slash for each mapping.
+       
+       The returned mapping a native NT pathname (\Device\...) which
+       we can use to fix up the output of GetMappedFileNameW
+    */
+    static unsigned const DBUFLEN = 26 * 4;
+    wchar_t dbuf[DBUFLEN + 1];
+    wchar_t pbuf[NT_MAX_PATH];
+    wchar_t drive[] = {L'x', L':', 0};
+    unsigned result = GetLogicalDriveStringsW (DBUFLEN * sizeof (wchar_t),
+                                              dbuf);
+    if (!result)
+      debug_printf ("Failed to get logical DOS drive names: %lu",
+                   GetLastError ());
+    else if (result > DBUFLEN)
+      debug_printf ("Too many mapped drive letters: %u", result);
+    else
+      for (wchar_t *cur = dbuf; (*drive = *cur); cur = wcschr (cur, L'\0')+1)
+       if (QueryDosDeviceW (drive, pbuf, NT_MAX_PATH))
+         {
+           size_t plen = wcslen (pbuf);
+           size_t psize = plen * sizeof (wchar_t);
+           debug_printf ("DOS drive %ls maps to %ls", drive, pbuf);
+           mapping *m = (mapping*) cmalloc (HEAP_FHANDLER,
+                                            sizeof (mapping) + psize);
+           m->next = mappings;
+           m->len = plen;
+           m->drive_letter = *drive;
+           memcpy (m->mapping, pbuf, psize + sizeof (wchar_t));
+           mappings = m;
+         }
+       else
+         debug_printf ("Unable to determine the native mapping for %ls "
+                       "(error %lu)", drive, GetLastError ());
+  }
+  
+  wchar_t *fixup_if_match (wchar_t *path)
+  {
+    for (mapping *m = mappings; m; m = m->next)
+      if (!wcsncmp (m->mapping, path, m->len))
+       {
+         path += m->len - 2;
+         path[0] = m->drive_letter;
+         path[1] = L':';
+         break;
+       }
+    return path;
+  }
+  
+  ~dos_drive_mappings ()
+  {
+    mapping *n = 0;
+    for (mapping *m = mappings; m; m = n)
+      {
+       n = m->next;
+       cfree (m);
+      }
+  }
+};
+
+struct heap_info
+{
+  struct heap
+  {
+    heap *next;
+    void *base;
+  };
+  heap *heaps;
+
+  heap_info (DWORD pid)
+    : heaps (0)
+  {
+    HANDLE hHeapSnap = CreateToolhelp32Snapshot (TH32CS_SNAPHEAPLIST, pid);
+    HEAPLIST32 hl;
+    hl.dwSize = sizeof(hl);
+
+    if (hHeapSnap != INVALID_HANDLE_VALUE && Heap32ListFirst (hHeapSnap, &hl))
+      do
+       {
+         heap *h = (heap *) cmalloc (HEAP_FHANDLER, sizeof (heap));
+         *h = (heap) {heaps, (void*) hl.th32HeapID};
+         heaps = h;
+       } while (Heap32ListNext (hHeapSnap, &hl));
+    CloseHandle (hHeapSnap);
+  }
+  
+  char *fill_if_match (void *base, char *dest )
+  {
+    long count = 0;
+    for (heap *h = heaps; h && ++count; h = h->next)
+      if (base == h->base)
+       {
+         __small_sprintf (dest, "[heap %ld]", count);
+         return dest;
+       }
+    return 0;
+  }
+  
+  ~heap_info () 
+  {
+    heap *n = 0;
+    for (heap *m = heaps; m; m = n)
+      {
+       n = m->next;
+       cfree (m);
+      }
+  }
+};
+
 static _off64_t
 format_process_maps (void *data, char *&destbuf)
 {
@@ -538,14 +669,28 @@ format_process_maps (void *data, char *&destbuf)
     return 0;
 
   _off64_t len = 0;
-  HMODULE *modules;
-  DWORD needed, i;
-  DWORD_PTR wset_size;
-  DWORD_PTR *workingset = NULL;
-  MODULEINFO info;
+  
+  union access
+  {
+    char flags[8];
+    _off64_t word;
+  } a;
+
+  struct region {
+    access a;
+    char *abase;
+    char *rbase;
+    char *rend;
+  } cur = {{{'\0'}}, (char *)1, 0, 0};
+  
+  MEMORY_BASIC_INFORMATION mb;
+  dos_drive_mappings drive_maps;
+  heap_info heaps (p->dwProcessId);
+  struct __stat64 st;
+  long last_pass = 0;
 
   tmp_pathbuf tp;
-  PWCHAR modname = tp.w_get ();
+  PMEMORY_SECTION_NAME msi = (PMEMORY_SECTION_NAME) tp.w_get ();
   char *posix_modname = tp.c_get ();
   size_t maxsize = 0;
 
@@ -554,75 +699,92 @@ format_process_maps (void *data, char *&destbuf)
       cfree (destbuf);
       destbuf = NULL;
     }
-  if (!EnumProcessModules (proc, NULL, 0, &needed))
-    {
-      __seterrno ();
-      len = -1;
-      goto out;
-    }
-  modules = (HMODULE*) alloca (needed);
-  if (!EnumProcessModules (proc, modules, needed, &needed))
+  
+  /* Iterate over each VM region in the address space, coalescing
+     memory regions with the same permissions. Once we run out, do one
+     last_pass to trigger output of the last accumulated region. */
+  for (char *i = 0;
+       VirtualQueryEx (proc, i, &mb, sizeof(mb)) || (1 == ++last_pass);
+       i = cur.rend)
     {
-      __seterrno ();
-      len = -1;
-      goto out;
-    }
+      if (mb.State == MEM_FREE)
+       a.word = 0;
+      else
+       {
+         static DWORD const RW = (PAGE_EXECUTE_READWRITE | PAGE_READWRITE
+                                  | PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOPY);
+         DWORD p = mb.Protect;
+         a = (access) {{
+             (p & (RW | PAGE_EXECUTE_READ | PAGE_READONLY))?   'r' : '-',
+             (p & (RW))?                                       'w' : '-',
+             (p & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ
+                   | PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE))?  'x' : '-',
+             (p & (PAGE_GUARD))?                               's' : 'p',
+             '\0', // zero-fill the remaining bytes
+           }};
+       }
 
-  QueryWorkingSet (proc, (void *) &wset_size, sizeof wset_size);
-  if (GetLastError () == ERROR_BAD_LENGTH)
-    {
-      workingset = (DWORD_PTR *) alloca (sizeof (DWORD_PTR) * ++wset_size);
-      if (!QueryWorkingSet (proc, (void *) workingset,
-                           sizeof (DWORD_PTR) * wset_size))
-       workingset = NULL;
-    }
-  for (i = 0; i < needed / sizeof (HMODULE); i++)
-    if (GetModuleInformation (proc, modules[i], &info, sizeof info)
-       && GetModuleFileNameExW (proc, modules[i], modname, NT_MAX_PATH))
-      {
-       char access[5];
-       strcpy (access, "r--p");
-       struct __stat64 st;
-       if (mount_table->conv_to_posix_path (modname, posix_modname, 0))
-         sys_wcstombs (posix_modname, NT_MAX_PATH, modname);
-       if (stat64 (posix_modname, &st))
-         {
-           st.st_dev = 0;
-           st.st_ino = 0;
-         }
-       size_t newlen = strlen (posix_modname) + 62;
-       if (len + newlen >= maxsize)
-         destbuf = (char *) crealloc_abort (destbuf,
-                                          maxsize += roundup2 (newlen, 2048));
-       if (workingset)
-         for (unsigned i = 1; i <= wset_size; ++i)
+      region next = { a,
+                     (char *) mb.AllocationBase,
+                     (char *) mb.BaseAddress,
+                     (char *) mb.BaseAddress+mb.RegionSize
+      };
+      
+      /* Windows permissions are more fine-grained than the unix rwxp,
+        so we reduce clutter by manually coalescing regions sharing
+        the same allocation base and effective permissions. */
+      bool newbase = (next.abase != cur.abase);
+      if (!last_pass && !newbase && next.a.word == cur.a.word)
+         cur.rend = next.rend; // merge with previous
+      else
+       {
+         // output the current region if it's "interesting"
+         if (cur.a.word)
+           {
+             size_t newlen = strlen (posix_modname) + 62;
+             if (len + newlen >= maxsize)
+               destbuf = (char *) crealloc_abort (destbuf,
+                                                  maxsize += roundup2 (newlen,
+                                                                       2048));
+             int written = __small_sprintf (destbuf + len,
+                                            "%08lx-%08lx %s %08lx %04x:%04x %U   ",
+                                            cur.rbase, cur.rend, cur.a.flags,
+                                            cur.rbase - cur.abase,
+                                            st.st_dev >> 16,
+                                            st.st_dev & 0xffff,
+                                            st.st_ino);
+             while (written < 62)
+               destbuf[len + written++] = ' ';
+             len += written;
+             len += __small_sprintf (destbuf + len, "%s\n", posix_modname);
+           }
+         // start of a new region (but possibly still the same allocation)
+         cur = next;
+         // if a new allocation, figure out what kind it is 
+         if (newbase && !last_pass)
            {
-             DWORD_PTR addr = workingset[i] & 0xfffff000UL;
-             if ((char *)addr >= info.lpBaseOfDll
-                 && (char *)addr < (char *)info.lpBaseOfDll + info.SizeOfImage)
+             st.st_dev = 0;
+             st.st_ino = 0;
+             if ((mb.Type & (MEM_MAPPED | MEM_IMAGE))
+                 && NT_SUCCESS (NtQueryVirtualMemory (proc, cur.abase,
+                                                      MemorySectionName,
+                                                      msi, 65536, NULL)))
                {
-                 access[0] = (workingset[i] & 0x5) ? 'r' : '-';
-                 access[1] = (workingset[i] & 0x4) ? 'w' : '-';
-                 access[2] = (workingset[i] & 0x2) ? 'x' : '-';
-                 access[3] = (workingset[i] & 0x100) ? 's' : 'p';
+                 PWCHAR dosname =
+                     drive_maps.fixup_if_match (msi->SectionFileName.Buffer);
+                 if (mount_table->conv_to_posix_path (dosname,
+                                                      posix_modname, 0))
+                   sys_wcstombs (posix_modname, NT_MAX_PATH, dosname);
+                 stat64 (posix_modname, &st);
                }
+             else if (mb.Type & MEM_MAPPED)
+               strcpy (posix_modname, "[shareable]");
+             else if (!(mb.Type & MEM_PRIVATE
+                        && heaps.fill_if_match (cur.abase, posix_modname)))
+               posix_modname[0] = 0;
            }
-       int written = __small_sprintf (destbuf + len,
-                               "%08lx-%08lx %s %08lx %04x:%04x %U   ",
-                               info.lpBaseOfDll,
-                               (unsigned long)info.lpBaseOfDll
-                               + info.SizeOfImage,
-                               access,
-                               info.EntryPoint,
-                               st.st_dev >> 16,
-                               st.st_dev & 0xffff,
-                               st.st_ino);
-       while (written < 62)
-         destbuf[len + written++] = ' ';
-       len += written;
-       len += __small_sprintf (destbuf + len, "%s\n", posix_modname);
-      }
-out:
+       }
+    }
   CloseHandle (proc);
   return len;
 }
index 75ba1a5e89189570ae51e11686278e51f9094e37..090ec648f4b10713df242b36779687e851c5e21f 100644 (file)
@@ -645,6 +645,11 @@ typedef struct _MEMORY_WORKING_SET_LIST
   ULONG WorkingSetList[1];
 } MEMORY_WORKING_SET_LIST, *PMEMORY_WORKING_SET_LIST;
 
+typedef struct _MEMORY_SECTION_NAME
+{
+  UNICODE_STRING SectionFileName;
+} MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;
+
 typedef struct _FILE_BASIC_INFORMATION {
   LARGE_INTEGER CreationTime;
   LARGE_INTEGER LastAccessTime;
This page took 0.042919 seconds and 5 git commands to generate.