Extending /proc/*/maps

Corinna Vinschen corinna-cygwin@cygwin.com
Thu May 12 16:56:00 GMT 2011

On May 12 12:31, Ryan Johnson wrote:
> On 12/05/2011 11:09 AM, Corinna Vinschen wrote:
> >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.
> I like it. Detailed comments below.
> >+/* Known heap flags */
> >+#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
> Would it make sense to put those in ntdll.h along with the heap
> structs that use them?


> >    struct heap
> >    {
> >      heap *next;
> >-    void *base;
> >+    unsigned heap_id;
> >+    uintptr_t base;
> >+    uintptr_t end;
> >+    unsigned long flags;
> >    };
> We don't actually need the end pointer: we're trying to match an

No, we need it.  The heaps consist of reserved and committed memory
blocks, as well as of shareable and non-shareable blocks.  Thus you
get multiple VirtualQuery calls per heap, thus you have to check for
the address within the entire heap(*).

> >    heap *heaps;
> This is a misnomer now -- it's really a list of heap regions/blocks.

I don't think so.  The loop stores only the blocks which constitute
the original VirtualAlloc'ed memory regions.  They are not the real
heap blocks returned by Heap32First/Heap32Next.  These are filtered
out by checking for 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;
> Given that the number of heap blocks is potentially large, I think

Not really.  See (**).  3 heaps -> 3 blocks, or only slightly more
if a growable heap got expanded.

> Do you actually encounter requests which fall inside a heap region
> rather than at its start?

Yes, see (*).  And have a look into the output of my code in
contrast to what's printed by the currently version from CVS.

>  I have not seen this in my experiments,
> and if you have it is almost certainly a bug in format_process_maps'
> allocation traversal.

No, see (*).

> Also, are there ever shareable-but-not-mem_mapped segments?

Yes, there are.  2 of the 3 default heaps are marked as shareable, but
one of them is only partially shared.  Of course I don't understand the
reason behind this and how this is accomplished, given that the user
code can't even set a flag "shareable" at HeapCreate time.


Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

More information about the Cygwin-patches mailing list