From b4966f91396b337dc0ce1c1b9f7a95a62a64c84e Mon Sep 17 00:00:00 2001
From: Corinna Vinschen <corinna@vinschen.de>
Date: Fri, 13 May 2011 06:50:20 +0000
Subject: [PATCH] 	* fhandler_process.cc (struct heap_info::heap):
 Convert base to 	uintptr_t.  Add heap_id, end, flags members. 
 (heap_info::heap_vm_chunks): Rename from heaps. 
 (heap_info::heap_info): Rearrange using RtlQueryProcessDebugInformation 
 to get information of heap virtual memory blocks.  Store heap id and 	flags,
 as well as end address of each block. 	(heap_info::fill_if_match): Check
 incoming base address against full 	address range of heap chunks.  Convert
 flag values in extra heap 	information. 	(format_process_maps): Change
 order so that heap check is done before 	MEM_MAPPED check since there
 are shareable heaps. 	* ntdll.h (PDI_HEAP_BLOCKS): Define. 
 (HEAP_FLAG_NOSERIALIZE): Define. 	(HEAP_FLAG_GROWABLE): Define. 
 (HEAP_FLAG_EXCEPTIONS): Define. 	(HEAP_FLAG_NONDEFAULT): Define. 
 (HEAP_FLAG_SHAREABLE): Define. 	(HEAP_FLAG_EXECUTABLE): Define. 
 (HEAP_FLAG_DEBUGGED): Define. 	(struct _DEBUG_HEAP_ARRAY): Define. 
 (struct _DEBUG_HEAP_BLOCK): Define.

---
 winsup/cygwin/ChangeLog           | 24 +++++++++
 winsup/cygwin/fhandler_process.cc | 86 ++++++++++++++++++++++---------
 winsup/cygwin/ntdll.h             | 24 +++++++++
 3 files changed, 109 insertions(+), 25 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index b3122ab28..0733a86a7 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,27 @@
+2011-05-13  Corinna Vinschen  <corinna@vinschen.de>
+
+	* fhandler_process.cc (struct heap_info::heap): Convert base to
+	uintptr_t.  Add heap_id, end, flags members.
+	(heap_info::heap_vm_chunks): Rename from heaps.
+	(heap_info::heap_info): Rearrange using RtlQueryProcessDebugInformation
+	to get information of heap virtual memory blocks.  Store heap id and
+	flags, as well as end address of each block.
+	(heap_info::fill_if_match): Check incoming base address against full
+	address range of heap chunks.  Convert flag values in extra heap
+	information.
+	(format_process_maps): Change order so that heap check is done before
+	MEM_MAPPED check since there are shareable heaps.
+	* ntdll.h (PDI_HEAP_BLOCKS): Define.
+	(HEAP_FLAG_NOSERIALIZE): Define.
+	(HEAP_FLAG_GROWABLE): Define.
+	(HEAP_FLAG_EXCEPTIONS): Define.
+	(HEAP_FLAG_NONDEFAULT): Define.
+	(HEAP_FLAG_SHAREABLE): Define.
+	(HEAP_FLAG_EXECUTABLE): Define.
+	(HEAP_FLAG_DEBUGGED): Define.
+	(struct _DEBUG_HEAP_ARRAY): Define.
+	(struct _DEBUG_HEAP_BLOCK): Define.
+
 2011-05-12  Corinna Vinschen  <corinna@vinschen.de>
 
 	Based on newlib patch to strptime by Peter Rosin <peda@lysator.liu.se>:
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
index 3d353096c..1038537ce 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -614,34 +614,68 @@ struct heap_info
   struct heap
   {
     heap *next;
-    void *base;
+    unsigned heap_id;
+    uintptr_t base;
+    uintptr_t end;
+    unsigned long flags;
   };
-  heap *heaps;
+  heap *heap_vm_chunks;
 
   heap_info (DWORD pid)
-    : heaps (0)
+    : heap_vm_chunks (0)
   {
-    HANDLE hHeapSnap = CreateToolhelp32Snapshot (TH32CS_SNAPHEAPLIST, pid);
-    HEAPLIST32 hl;
-    hl.dwSize = sizeof(hl);
+    PDEBUG_BUFFER buf;
+    NTSTATUS status;
+    PDEBUG_HEAP_ARRAY harray;
 
-    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);
+    buf = RtlCreateQueryDebugBuffer (0, FALSE);
+    if (!buf)
+      return;
+    status = RtlQueryProcessDebugInformation (pid, PDI_HEAPS | PDI_HEAP_BLOCKS,
+					      buf);
+    if (NT_SUCCESS (status)
+	&& (harray = (PDEBUG_HEAP_ARRAY) buf->HeapInformation) != NULL)
+      for (ULONG hcnt = 0; hcnt < harray->Count; ++hcnt)
+      	{
+	  PDEBUG_HEAP_BLOCK barray = (PDEBUG_HEAP_BLOCK)
+				     harray->Heaps[hcnt].Blocks;
+	  if (!barray)
+	    continue;
+	  for (ULONG bcnt = 0; bcnt < harray->Heaps[hcnt].BlockCount; ++bcnt)
+	    if (barray[bcnt].Flags & 2)
+	      {
+		heap *h = (heap *) cmalloc (HEAP_FHANDLER, sizeof (heap));
+		*h = (heap) { heap_vm_chunks,
+			      hcnt, barray[bcnt].Address,
+			      barray[bcnt].Address + barray[bcnt].Size,
+			      harray->Heaps[hcnt].Flags };
+		heap_vm_chunks = h;
+	      }
+	}
+    RtlDestroyQueryDebugBuffer (buf);
   }
   
-  char *fill_if_match (void *base, char *dest )
+  char *fill_if_match (void *base, ULONG type, char *dest )
   {
-    long count = 0;
-    for (heap *h = heaps; h && ++count; h = h->next)
-      if (base == h->base)
+    for (heap *h = heap_vm_chunks; h; h = h->next)
+      if ((uintptr_t) base >= h->base && (uintptr_t) base < h->end)
 	{
-	  __small_sprintf (dest, "[heap %ld]", count);
+	  char *p;
+	  __small_sprintf (dest, "[heap %ld", h->heap_id);
+	  p = strchr (dest, '\0');
+	  if (!(h->flags & HEAP_FLAG_NONDEFAULT))
+	    p = stpcpy (p, " default");
+	  if ((h->flags & HEAP_FLAG_SHAREABLE) && (type & MEM_MAPPED))
+	    p = stpcpy (p, " share");
+	  if (h->flags & HEAP_FLAG_EXECUTABLE)
+	    p = stpcpy (p, " exec");
+	  if (h->flags & HEAP_FLAG_GROWABLE)
+	    p = stpcpy (p, " grow");
+	  if (h->flags & HEAP_FLAG_NOSERIALIZE)
+	    p = stpcpy (p, " noserial");
+	  if (h->flags == HEAP_FLAG_DEBUGGED)
+	    p = stpcpy (p, " debug");
+	  stpcpy (p, "]");
 	  return dest;
 	}
     return 0;
@@ -650,7 +684,7 @@ struct heap_info
   ~heap_info () 
   {
     heap *n = 0;
-    for (heap *m = heaps; m; m = n)
+    for (heap *m = heap_vm_chunks; m; m = n)
       {
 	n = m->next;
 	cfree (m);
@@ -777,11 +811,13 @@ format_process_maps (void *data, char *&destbuf)
 		    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;
+	      else if (!heaps.fill_if_match (cur.abase, mb.Type, posix_modname))
+		{
+		  if (mb.Type & MEM_MAPPED)
+		    strcpy (posix_modname, "[shareable]");
+		  else
+		    posix_modname[0] = 0;
+		}
 	    }
 	}
     }
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index df0ae29a3..cb4e6d962 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -63,6 +63,7 @@
 
 #define PDI_MODULES 0x01
 #define PDI_HEAPS 0x04
+#define PDI_HEAP_BLOCKS 0x10
 #define LDRP_IMAGE_DLL 0x00000004
 #define WSLE_PAGE_READONLY 0x001
 #define WSLE_PAGE_EXECUTE 0x002
@@ -510,6 +511,15 @@ typedef struct _DEBUG_BUFFER
   PVOID Reserved[9];
 } DEBUG_BUFFER, *PDEBUG_BUFFER;
 
+/* Known debug heap flags */
+#define HEAP_FLAG_NOSERIALIZE	       0x1
+#define HEAP_FLAG_GROWABLE	       0x2
+#define HEAP_FLAG_EXCEPTIONS	       0x4
+#define HEAP_FLAG_NONDEFAULT	    0x1000
+#define HEAP_FLAG_SHAREABLE	    0x8000
+#define HEAP_FLAG_EXECUTABLE	   0x40000
+#define HEAP_FLAG_DEBUGGED	0x40000000
+
 typedef struct _DEBUG_HEAP_INFORMATION
 {
   ULONG Base;
@@ -525,6 +535,20 @@ typedef struct _DEBUG_HEAP_INFORMATION
   PVOID Blocks;
 } DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION;
 
+typedef struct _DEBUG_HEAP_ARRAY
+{
+  ULONG Count;
+  DEBUG_HEAP_INFORMATION Heaps[1];
+} DEBUG_HEAP_ARRAY, *PDEBUG_HEAP_ARRAY;
+
+typedef struct _DEBUG_HEAP_BLOCK
+{
+  ULONG Size;
+  ULONG Flags;
+  ULONG Committed;
+  ULONG Address;
+} DEBUG_HEAP_BLOCK, *PDEBUG_HEAP_BLOCK;
+
 typedef struct _DEBUG_MODULE_INFORMATION
 {
   ULONG Reserved[2];