On May 12 14:10, Corinna Vinschen wrote: > On May 11 21:31, Corinna Vinschen wrote: > > On May 11 13:46, Ryan Johnson wrote: > > > Given that Heap32* has already been reverse-engineered by others, > > > the main challenge would involve sorting the set of heap block > > > addresses and distilling them down to a set of allocation bases. We > > > don't want to do repeated linear searches over 50k+ heap blocks. > > > > While the base address of the heap is available in > > DEBUG_HEAP_INFORMATION, I don't see the size of the heap. Maybe it's in > > the block of 7 ULONGs marked as "Reserved"? It must be somewhere. > > Assuming just that, you could scan the list of blocks once and drop > > those within the orignal heap allocation. The remaining blocks are big > > blocks which have been allocated by additional calls to VirtualAlloc. > > After some debugging, I now have the solution. [...]
Here's a prelimiary patch to fhandler_process.cc which takes everything into account I have learned in the meantime. For instance, there are actually heaps marked as shareable. Please have a look. What's missing is the flag for low-fragmentation heaps, but I'm just hunting for it. Corinna Index: fhandler_process.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_process.cc,v retrieving revision 1.96 diff -u -p -r1.96 fhandler_process.cc --- fhandler_process.cc 11 May 2011 10:31:22 -0000 1.96 +++ fhandler_process.cc 12 May 2011 15:08:03 -0000 @@ -609,39 +609,78 @@ struct dos_drive_mappings } }; +/* Known 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 + struct heap_info { struct heap { heap *next; - void *base; + unsigned heap_id; + uintptr_t base; + uintptr_t end; + unsigned long flags; }; 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); + PDEBUG_BUFFER buf; + NTSTATUS status; + PDEBUG_HEAP_ARRAY harray; + + 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) {heaps, hcnt, barray[bcnt].Address, + barray[bcnt].Address + barray[bcnt].Size, + harray->Heaps[hcnt].Flags}; + heaps = 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 = heaps; 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"); + stpcpy (p, "]"); return dest; } return 0; @@ -777,11 +816,13 @@ format_process_maps (void *data, char *& 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; + } } } } Index: ntdll.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/ntdll.h,v retrieving revision 1.117 diff -u -p -r1.117 ntdll.h --- ntdll.h 11 May 2011 13:25:27 -0000 1.117 +++ ntdll.h 12 May 2011 15:08:03 -0000 @@ -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 @@ -525,6 +526,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 Unknown; + ULONG Address; +} DEBUG_HEAP_BLOCK, *PDEBUG_HEAP_BLOCK; + typedef struct _DEBUG_MODULE_INFORMATION { ULONG Reserved[2]; -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat