This is the mail archive of the
cygwin-patches
mailing list for the Cygwin project.
Re: Extending /proc/*/maps
On May 12 13:53, Ryan Johnson wrote:
> On 12/05/2011 12:55 PM, Corinna Vinschen wrote:
> >>> 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(*).
> The code which queries heap_info already deals with allocations that
> take multiple VirtualQuery calls to traverse, and only calls into
> heap_info for the base of any given allocation.
However, at least heap 2 consists of multiple allocated memory areas,
which are separately VirtualAlloc'ed or NtMapViewOfSection'ed. Therefore
the first VirtualQuery returns AllocationBase = BaseAddress = 0x20000
and the next VirtualQuery returns AllocationBase = BaseAddress = 0x30000.
However, all the memory from 0x20000 up to 0x230000 constitutes a single
start block in heap 2!
> CAVEAT: According to MSDN's documentation for HeapWalk, "a heap
> consists of one or more regions of virtual memory, each with a
> unique region index." During heap walking, wFlags is set to
> PROCESS_HEAP_REGION whenever "the heap element is located at the
> beginning of a region of contiguous virtual memory in use by the
> heap." However, "large block regions" (those allocated directly via
> VirtualAlloc) do not set the PROCESS_HEAP_REGION flag. If this
> PROCESS_HEAP_REGION flag corresponds to your (flags & 2), then we
> won't report any large blocks (however, it's documented to have the
> value 0x0001, with 0x0002 being PROCESS_HEAP_UNCOMMITTED_RANGE).
I created a test application with several heaps and I create large
blocks in two of them. They also have the flags&2 value set. The
problem for heap walk is to identify blocks with a valid address. Keep
in mind that all subsequent blocks within an allocated heap area do
*not* have an addres, but only a size, with address == 0. You only get
their address by iterating from the start block to the block you're
looking for and adding up all sizes of the blocks up to there.
Consequentially a start block of another VirtualAlloc'ed area needs a
marker that the address is valid. That marker is the flags value 2.
Which is kind of weird, actually, since the existence of a non-0 address
in the block should have been enough of a hint that this is a start
block...
As for the big blocks, they are apparently identified by the value in
the "Unknown" member of the DEBUG_HEAP_BLOCK structure. Here's what I
figured out so far as far as "Unknown" is concerned:
0x1000 All normal heaps
0x3000 The process default heap (heap 0)
0xc000 A low-frag heap
0x10000 Heap 2, perhaps the meaning is "stack"?
0x32000 Subsequently allocated block of a growable heap
0x1e9000 Large block
I don't claim to understand the values, especially the reason for
setting several bits.
> >>> 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 (**).
> Sorry, I cut too much context out of the diff. That's
> heap_info::heaps, which indeed refers to heap regions which we
> identified by checking flags&2 (that's why it needs the heap_id
> inside it now, where it didn't before) (++)
So you think something like heap_chunks is better?
> >>>+ 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.
> See (++). When I point my essentially-identical version of the code
> at emacs, it reports 8 heaps, each with 2-4 regions. The list
> traversed by fill_on_match has ~20 entries.
Oh, ok. From my POV 20 is not a large number. Ordering might take
more time than scanning. I don't think it's worth the effort.
Corinna
--
Corinna Vinschen Please, send mails regarding Cygwin to
Cygwin Project Co-Leader cygwin AT cygwin DOT com
Red Hat