You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
454 lines
10 KiB
454 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
heap.c
|
|
|
|
Abstract:
|
|
|
|
This function contains the default ntsd debugger extensions
|
|
|
|
Author:
|
|
|
|
Bob Day (bobday) 29-Feb-1992 Grabbed standard header
|
|
|
|
Revision History:
|
|
|
|
Neil Sandlin (NeilSa) 15-Jan-1996 Merged with vdmexts
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
|
|
BOOL bWalkOnly = FALSE;
|
|
|
|
ULONG
|
|
GetHeapBase(
|
|
VOID
|
|
)
|
|
{
|
|
WORD selector;
|
|
SELECTORINFO si;
|
|
|
|
if (!ReadMemExpression("ntvdmd!DbgWowhGlobalHeap", &selector, sizeof(selector))) {
|
|
return 0;
|
|
}
|
|
|
|
GetInfoFromSelector(selector, PROT_MODE, &si);
|
|
|
|
return(si.Base + GetIntelBase());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
GetFileNameFromOwner(
|
|
LPSTR filename,
|
|
LPSTR OwnerName
|
|
)
|
|
{
|
|
}
|
|
|
|
|
|
VOID
|
|
GetHeapOwnerInfo(
|
|
HEAPENTRY *he
|
|
)
|
|
{
|
|
BOOL b;
|
|
NEHEADER owner;
|
|
ULONG base;
|
|
UCHAR len;
|
|
int i;
|
|
ULONG offset;
|
|
WORD wTemp;
|
|
|
|
he->SegmentNumber = -1;
|
|
he->OwnerName[0] = 0;
|
|
if (he->gnode.pga_owner == 0) {
|
|
strcpy(he->OwnerName, "free");
|
|
return;
|
|
} else if (he->gnode.pga_owner>=0xFFF8) {
|
|
strcpy(he->OwnerName, "sentinel");
|
|
return;
|
|
}
|
|
|
|
|
|
base = GetInfoFromSelector(he->gnode.pga_owner, PROT_MODE, NULL)
|
|
+ GetIntelBase();
|
|
|
|
b = READMEM((LPVOID)base, &owner, sizeof(owner));
|
|
|
|
if (b) {
|
|
if (owner.ne_magic == 0x454e) {
|
|
|
|
len = ReadByteSafe(base+owner.ne_restab);
|
|
if (len>8) {
|
|
len=8;
|
|
}
|
|
READMEM((LPVOID)(base+owner.ne_restab+1), he->OwnerName, 8);
|
|
|
|
he->OwnerName[len] = 0;
|
|
if (!_stricmp(he->OwnerName, "kernel")) {
|
|
strcpy(he->FileName, "krnl386");
|
|
} else {
|
|
strcpy(he->FileName, he->OwnerName);
|
|
}
|
|
|
|
offset = owner.ne_segtab;
|
|
|
|
for (i=0; i<owner.ne_cseg; i++) {
|
|
wTemp = ReadWordSafe(base+offset+8); //get handle
|
|
if (wTemp == he->gnode.pga_handle) {
|
|
he->SegmentNumber = i;
|
|
break;
|
|
}
|
|
offset += 10;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
BOOL
|
|
CheckGlobalHeap(
|
|
BOOL bVerbose
|
|
)
|
|
{
|
|
PGHI32 pghi;
|
|
DWORD offset, prevoffset;
|
|
DWORD count, heapcount;
|
|
DWORD p;
|
|
GNODE32 gnode;
|
|
PBYTE pFault = NULL;
|
|
BOOL bError = FALSE;
|
|
|
|
pghi = (PGHI32)GetHeapBase();
|
|
prevoffset = offset = (DWORD) ReadWord(&pghi->hi_first);
|
|
heapcount = count = ReadWord(&pghi->hi_count);
|
|
|
|
if (bVerbose) {
|
|
PRINTF("Global Heap is at %08X\n", pghi);
|
|
}
|
|
|
|
|
|
while ((offset != 0) && (count)) {
|
|
|
|
if (offset&0x1f) {
|
|
PRINTF("Error! Kernel heap entry(%08X) contains invalid forward link (%08X)\n", prevoffset, offset);
|
|
return FALSE;
|
|
}
|
|
|
|
p = (DWORD)pghi + offset;
|
|
|
|
if (!ReadGNode32Safe(p, &gnode)) {
|
|
|
|
PRINTF("Error! Kernel heap entry(%08X) contains invalid forward link (%08X)\n", prevoffset, offset);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (count == heapcount) {
|
|
// first entry
|
|
if (offset != gnode.pga_prev) {
|
|
PRINTF("Error! Kernel heap entry (%08X) contains invalid back link (%08X)\n", offset, gnode.pga_prev);
|
|
PRINTF(" expecting (%08X)\n", offset);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
if (prevoffset != gnode.pga_prev) {
|
|
PRINTF("Error! Kernel heap entry (%08X) contains invalid back link (%08X)\n", offset, gnode.pga_prev);
|
|
PRINTF(" expecting (%08X)\n", prevoffset);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
prevoffset = offset;
|
|
|
|
count--;
|
|
if (offset == gnode.pga_next) {
|
|
if (!count) {
|
|
if (bVerbose) {
|
|
PRINTF("%d entries scanned\n", heapcount);
|
|
}
|
|
return TRUE;
|
|
} else {
|
|
PRINTF("Error! Kernel heap count (%d) larger then forward chain (%d)\n", heapcount, heapcount-count);
|
|
}
|
|
}
|
|
offset = gnode.pga_next;
|
|
}
|
|
|
|
PRINTF("Error! Kernel heap count (%d) smaller then forward chain\n", heapcount);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FindHeapEntry(
|
|
HEAPENTRY *he,
|
|
UINT FindMethod,
|
|
BOOL bVerbose
|
|
)
|
|
{
|
|
PGHI32 pghi;
|
|
DWORD offset;
|
|
DWORD MaxEntries, count;
|
|
DWORD p;
|
|
PBYTE pFault = NULL;
|
|
BOOL bError = FALSE;
|
|
|
|
pghi = (PGHI32)GetHeapBase();
|
|
|
|
//
|
|
// Verify that we are looking at a heap
|
|
//
|
|
offset = (DWORD) ReadWordSafe(&pghi->hi_first);
|
|
p = (DWORD)pghi + offset;
|
|
if (!ReadGNode32Safe(p, &he->gnode)) {
|
|
if (bVerbose) {
|
|
PRINTF("Heap not available\n");
|
|
}
|
|
return FALSE;
|
|
}
|
|
if (offset != he->gnode.pga_prev) {
|
|
if (bVerbose) {
|
|
PRINTF("Heap not valid\n");
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// The caller has requested that we return the next heap
|
|
// entry since the last invocation, or the first entry.
|
|
//
|
|
|
|
if (he->CurrentEntry == 0) {
|
|
|
|
// get first entry
|
|
offset = (DWORD) ReadWord(&pghi->hi_first);
|
|
|
|
} else {
|
|
if (he->CurrentEntry == he->NextEntry) {
|
|
return FALSE;
|
|
}
|
|
|
|
// get next entry
|
|
offset = he->NextEntry;
|
|
|
|
}
|
|
|
|
he->CurrentEntry = offset;
|
|
|
|
if ((he->Selector == 0) && (FindMethod != FHE_FIND_MOD_ONLY)) {
|
|
|
|
p = (DWORD)pghi + offset;
|
|
if (!ReadGNode32(p, &he->gnode)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
he->NextEntry = he->gnode.pga_next;
|
|
GetHeapOwnerInfo(he);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// If we get here, the caller wants us to scan the heap
|
|
//
|
|
|
|
MaxEntries = ReadWord(&pghi->hi_count);
|
|
count = 0;
|
|
|
|
while ((offset != 0) && (count <= MaxEntries)) {
|
|
|
|
p = (DWORD)pghi + offset;
|
|
|
|
if (!ReadGNode32(p, &he->gnode)) {
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
if (FindMethod == FHE_FIND_ANY) {
|
|
WORD sel = he->Selector;
|
|
|
|
if (((sel|1)==((WORD)he->gnode.pga_handle|1)) ||
|
|
((sel|1)==((WORD)he->gnode.pga_owner|1)) ||
|
|
(sel==offset))
|
|
|
|
{
|
|
he->NextEntry = he->gnode.pga_next;
|
|
GetHeapOwnerInfo(he);
|
|
return TRUE;
|
|
}
|
|
|
|
} else if (FindMethod == FHE_FIND_MOD_ONLY) {
|
|
|
|
GetHeapOwnerInfo(he);
|
|
if (!_stricmp(he->OwnerName, he->ModuleArg)) {
|
|
he->NextEntry = he->gnode.pga_next;
|
|
return TRUE;
|
|
}
|
|
|
|
} else {
|
|
if ((he->Selector|1)==((WORD)he->gnode.pga_handle|1)) {
|
|
he->NextEntry = he->gnode.pga_next;
|
|
GetHeapOwnerInfo(he);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
count++;
|
|
if (offset == he->gnode.pga_next) {
|
|
break;
|
|
}
|
|
offset = he->gnode.pga_next;
|
|
he->CurrentEntry = offset;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
chkheap(
|
|
CMD_ARGLIST
|
|
)
|
|
{
|
|
CMD_INIT();
|
|
if (CheckGlobalHeap(TRUE)) {
|
|
PRINTF("Heap checks OK\n");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
// dumpgheap xxx
|
|
// where xxx is the 16-bit protect mode selector of the
|
|
// Kernel global heap info.
|
|
//
|
|
//*************************************************************
|
|
|
|
|
|
VOID
|
|
dgh(
|
|
CMD_ARGLIST
|
|
)
|
|
{
|
|
HEAPENTRY he = {0};
|
|
SELECTORINFO si;
|
|
ULONG TotalAllocated = 0;
|
|
ULONG TotalFree = 0;
|
|
ULONG CountPrinted = 0;
|
|
|
|
CMD_INIT();
|
|
|
|
if (GetNextToken()) {
|
|
he.Selector = (WORD) EXPRESSION( lpArgumentString );
|
|
}
|
|
|
|
PRINTF("Arena Base Limit Hnd Own Fl Lk Module Type Resid");
|
|
PRINTF("\n");
|
|
|
|
PRINTF("===== ======== ======== ==== ==== == == ======== ==== =====");
|
|
PRINTF("\n");
|
|
|
|
while (FindHeapEntry(&he, FHE_FIND_ANY, FHE_FIND_VERBOSE)) {
|
|
|
|
PRINTF("%.5x", he.CurrentEntry);
|
|
PRINTF(" %.8x", he.gnode.pga_address);
|
|
PRINTF(" %.8X", he.gnode.pga_size);
|
|
PRINTF(" %.4X", he.gnode.pga_handle);
|
|
PRINTF(" %.4X", he.gnode.pga_owner);
|
|
PRINTF(" %.2X", he.gnode.pga_flags);
|
|
PRINTF(" %.2X", he.gnode.pga_count);
|
|
PRINTF(" %-8.8s", he.OwnerName);
|
|
|
|
GetInfoFromSelector((WORD)(he.gnode.pga_handle | 1), PROT_MODE, &si);
|
|
|
|
PRINTF(" %s", si.bCode ? "Code" : "Data");
|
|
|
|
if (he.SegmentNumber != -1) {
|
|
PRINTF(" %d", he.SegmentNumber+1);
|
|
}
|
|
PRINTF("\n");
|
|
|
|
if (!he.gnode.pga_owner) {
|
|
TotalFree += he.gnode.pga_size;
|
|
} else {
|
|
TotalAllocated += he.gnode.pga_size;
|
|
}
|
|
CountPrinted++;
|
|
}
|
|
|
|
if (CountPrinted > 1) {
|
|
PRINTF("\n Allocated = %dK, Free = %dK\n", TotalAllocated/1024, TotalFree/1024);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UpdateLockCount(
|
|
int count
|
|
)
|
|
{
|
|
HEAPENTRY he = {0};
|
|
BYTE LockCount;
|
|
|
|
if (GetNextToken()) {
|
|
he.Selector = (WORD) EXPRESSION( lpArgumentString );
|
|
} else {
|
|
PRINTF("Please enter a selector or handle\n");
|
|
return;
|
|
}
|
|
|
|
if (FindHeapEntry(&he, FHE_FIND_SEL_ONLY, FHE_FIND_VERBOSE)) {
|
|
|
|
if (READMEM((LPVOID)(GetHeapBase()+he.CurrentEntry+0x14), &LockCount, 1)) {
|
|
|
|
LockCount = (BYTE)((int) LockCount + count);
|
|
WRITEMEM((LPVOID)(GetHeapBase()+he.CurrentEntry+0x14), &LockCount, 1);
|
|
PRINTF("Lock count for %.4X is now %d\n", he.Selector, LockCount);
|
|
|
|
} else {
|
|
|
|
PRINTF("<can't read memory at that location>\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
PRINTF("Can't find selector %4X in WOW heap\n", he.Selector);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
glock(
|
|
CMD_ARGLIST
|
|
)
|
|
{
|
|
CMD_INIT();
|
|
|
|
UpdateLockCount(1);
|
|
}
|
|
|
|
|
|
VOID
|
|
gunlock(
|
|
CMD_ARGLIST
|
|
)
|
|
{
|
|
CMD_INIT();
|
|
|
|
UpdateLockCount(-1);
|
|
}
|