This is the mail archive of the cygwin-patches mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Extending /proc/*/maps


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.  If you fetch the heap
and heap block information using the RtlQueryProcessDebugInformation
function, you get the list of blocks.  The first block in the list of
blocks has a flag value of 2.  Let's call it a "start block".  This
block contains the information about the address and size of the virtual
memory block reserved for this heap using VirtualAlloc.

Subsequent blocks do not contain address values, but only size values.
The start of the block is counted relative to the start of the previous
block.  All these blocks are "in-use", up to the last block which has
a flag value of 0x100.  This is the free block at the end of the heap.

For fixed-size heaps, that's all.  Growable heaps can have multiple
memory slots reserved with VirtualAlloc.  For these, if there are still
more blocks, the next block in the list after the free block is a start
block with a flag value of 2 again.  Here's the algorithm which prints
only the virtual memory blocks of all heaps:

  typedef struct _HEAPS
  {
    ULONG count;
    DEBUG_HEAP_INFORMATION dhi[1];
  } HEAPS, *PHEAPS;

  typedef struct _HEAP_BLOCK
  {
    ULONG size;
    ULONG flags;
    ULONG unknown;
    ULONG addr;
  } HEAP_BLOCK, *PHEAP_BLOCK;

  PDEBUG_BUFFER buf;
  NTSTATUS status;

  buf = RtlCreateQueryDebugBuffer (0, FALSE);
  if (!buf)
    {
      fprintf (stderr, "RtlCreateQueryDebugBuffer returned NULL\n");
      return 1;
    }
  status = RtlQueryProcessDebugInformation (GetCurrentProcessId (),
					    PDI_HEAPS | PDI_HEAP_BLOCKS,
					    buf);
  if (!NT_SUCCESS (status))
    [...]
  PHEAPS heaps = (PHEAPS) buf->HeapInformation;
  if (!heaps)
    [...]
  for (int heap_id = 0; heap_id < heaps->count; ++heap_id)
    {
      PHEAP_BLOCK blocks = (PHEAP_BLOCK) heaps->dhi[heap_id].Blocks;
      if (!blocks)
	[...]
      uintptr_t addr = 0;
      for (int block_num = 0; block_num < heaps->dhi[heap_id].BlockCount;
	   ++block_num)
	if (blocks[block_num].flags & 2)
	  printf ("addr 0x%08lx, size %8lu"
		  blocks[block_num].addr,
		    blocks[block_num].size);
    }
  RtlDestroyQueryDebugBuffer (buf);

As you can imagine, only the blocks I called the start blocks are
of interest for your struct heap_info.


Corinna

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]