Leaked source code of windows server 2003
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.
 
 
 
 
 
 

888 lines
23 KiB

/******************************Module*Header*******************************\
* Module Name: dumpers.cxx
*
* Copyright (c) 2000 Microsoft Corporation
*
\**************************************************************************/
#include "precomp.hxx"
// A resonable count limit for scans and walls
#define COUNT_LIMIT 0x07ffffff
/**************************************************************************\
*
* class ScanDumper
*
\**************************************************************************/
const FIELD_INFO ScanFieldsInit[SCAN_FIELDS_LENGTH] = {
{ DbgStr("cWalls"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL },
{ DbgStr("yTop"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL },
{ DbgStr("yBottom"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL },
{ DbgStr("ai_x[0]"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL },
};
const SYM_DUMP_PARAM ScanSymInit = {
sizeof (SYM_DUMP_PARAM), DbgStr(GDIType(SCAN)), DBG_DUMP_NO_PRINT, 0,
NULL, NULL, NULL, SCAN_FIELDS_LENGTH, NULL
};
const FIELD_INFO WallFieldsInit[1] = {
{ DbgStr("x"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, LeftWallCallback },
};
const SYM_DUMP_PARAM WallSymInit = {
sizeof (SYM_DUMP_PARAM), DbgStr(GDIType(_INDEX_LONG)), DBG_DUMP_NO_PRINT | DBG_DUMP_ARRAY, 0,
NULL, NULL, NULL, 1, NULL
};
const SYM_DUMP_PARAM cWalls2SymInit = {
sizeof (SYM_DUMP_PARAM), DbgStr("ULONG"), DBG_DUMP_NO_PRINT | DBG_DUMP_ADDRESS_AT_END | DBG_DUMP_COPY_TYPE_DATA, 0,
NULL, NULL, NULL, 0, NULL
};
/**************************************************************************\
*
* ScanDumper::ScanDumper
*
\**************************************************************************/
ScanDumper::ScanDumper(
ULONG64 HeadScanAddr,
ULONG64 TailScanAddr,
ULONG ScanCount,
ULONG64 AllocationBase,
ULONG64 AllocationLimit,
ULONG Flags
)
{
block = 0;
Top = POS_INFINITY;
Bottom = NEG_INFINITY;
FirstScanAddr = HeadScanAddr;
LastScanAddr = TailScanAddr;
ScanLimit = ScanCount ? ScanCount : COUNT_LIMIT;
AddressBase = AllocationBase;
AddressLimit = AllocationLimit;
PrintBlocks = (Flags & SCAN_DUMPER_NO_PRINT) == 0;
ForceDump = (Flags & SCAN_DUMPER_FORCE) != 0;
Reverse = (Flags & SCAN_DUMPER_FROM_TAIL) != 0;
// Enable to print a . after each right wall is
// processed when block printing is disabled.
PrintProgress = FALSE;
ProgressCount = 0;
RtlCopyMemory(ScanFields, ScanFieldsInit, sizeof(ScanFields));
RtlCopyMemory(&ScanSym, &ScanSymInit, sizeof(ScanSym));
ScanSym.Fields = ScanFields;
ListWallSize.fOptions = 0;
ListWallSize.fieldCallBack = WallArrayEntryCallback;
RtlCopyMemory(WallFields, WallFieldsInit, sizeof(WallFields));
RtlCopyMemory(&WallSym, &WallSymInit, sizeof(WallSym));
WallSym.listLink = &ListWallSize;
WallSym.Fields = WallFields;
RtlCopyMemory(&cWalls2Sym, &cWalls2SymInit, sizeof(cWalls2Sym));
Valid = TRUE;
// Get basic scan structure information
ScanSize = GetTypeSize(GDIType(SCAN));
if (1)
{
cWallsSize = GetTypeSize("ULONG");
IXSize = GetTypeSize(GDIType(_INDEX_LONG));
}
else
{
ULONG error;
error = Ioctl(IG_DUMP_SYMBOL_INFO, &ScanSym, ScanSym.size);
if (error)
{
dprintf(" SCAN type info Ioctl returned %s\n", pszWinDbgError(error));
}
cWallsSize = ScanFields[SCAN_CWALLS].size;
IXSize = ScanFields[SCAN_AI_X_ADDR].size;
}
if (Reverse && cWallsSize != GetTypeSize("ULONG"))
{
dprintf(" * Error: sizeof(SCAN::cWalls) != sizeof(ULONG)\n"
" => From tail scan dumping won't work.\n");
Reverse = FALSE;
}
if (Reverse)
{
scan = ScanCount;
NegativeScanCount = (ScanCount == 0);
ScanAddr = TailScanAddr;
}
else
{
scan = -1;
NegativeScanCount = FALSE;
ScanAddr = HeadScanAddr;
}
// Will DumpScans work?
CanDump = (ScanSize != 0) && (cWallsSize != 0) && (IXSize != 0);
}
/**************************************************************************\
*
* ScanDumper::DumpScans
*
\**************************************************************************/
BOOL
ScanDumper::DumpScans(
ULONG Count
)
{
ULONG64 NextScanAddr;
ULONG cWalls1, cWalls2;
ULONG error;
if (!CanDump)
{
dprintf(" An error occured in this extension preventing DumpScans from working.\n");
return FALSE;
}
if (! Count && PrintBlocks)
{
dprintf("\tNo scans to dump.\n");
}
if (Count > 100)
{
PrintProgress = TRUE;
ProgressCount = 0;
}
while (Count-- && !CheckControlC())
{
cWalls1 = cWalls2 = 0;
if (Reverse)
{
if (!NT_SUCCESS(ValidateAddress(ScanAddr, "End of ScanAddr", SCAN_VALID_AT_END)))
{
if (!ForceDump) break;
}
cWalls2Sym.addr = ScanAddr;
cWalls2Sym.Context = &cWalls2;
error = Ioctl(IG_DUMP_SYMBOL_INFO, &cWalls2Sym, cWalls2Sym.size);
if (error)
{
dprintf(" Ioctl returned %s\n", pszWinDbgError(error));
break;
}
ScanAddr -= cWalls2 * IXSize + ScanSize;
}
if (gbVerbose)
{
dprintf(" Examining scan %d @ %#p\n", scan+(Reverse?-1:+1), ScanAddr);
}
if (!NT_SUCCESS(ValidateAddress(ScanAddr, "ScanAddr", SCAN_VALID_AT_START)))
{
if (!ForceDump) break;
}
ScanSym.addr = ScanAddr;
error = Ioctl(IG_DUMP_SYMBOL_INFO, &ScanSym, ScanSym.size);
if (error)
{
dprintf(" Ioctl returned %s\n", pszWinDbgError(error));
break;
}
cWalls1 = (ULONG)ScanFields[SCAN_CWALLS].address;
// Update Top and Bottom information
if (!ScanAdvance((LONG)ScanFields[SCAN_YTOP].address, (LONG)ScanFields[SCAN_YBOTTOM].address, Reverse ? cWalls2 : cWalls1))
{
if (!ForceDump) break;
}
// Read cWalls2 if we don't know it.
if (!Reverse)
{
NextScanAddr = ScanAddr + ScanSize + cWalls1 * IXSize;
if (!NT_SUCCESS(ValidateAddress(NextScanAddr, "End of Wall array", SCAN_VALID_AT_END | SCAN_VALID_NO_ERROR_PRINT)))
{
dprintf(" * End of Wall array @ %#p, length %u, at scan %d lies outside valid scan range\n", NextScanAddr, cWalls1, scan);
if (!ForceDump) break;
}
cWalls2Sym.addr = NextScanAddr;
cWalls2Sym.Context = &cWalls2;
error = Ioctl(IG_DUMP_SYMBOL_INFO, &cWalls2Sym, cWalls2Sym.size);
if (error)
{
dprintf(" Ioctl returned %s\n", pszWinDbgError(error));
break;
}
}
// Check cWalls against cWalls2
if (cWalls1 != cWalls2)
{
dprintf(" * cWalls (%u) != cWalls2 (%u) at scan %d\n", cWalls1, cWalls2, scan);
Valid = FALSE;
if (!ForceDump) break;
}
// cWalls is set by ScanAdvance
if (cWalls != 0)
{
WallSym.Context = (PVOID)this;
WallSym.addr = ScanFields[SCAN_AI_X_ADDR].address;
ListWallSize.size = cWalls;
WallFields[0].fieldCallBack = LeftWallCallback;
error = Ioctl(IG_DUMP_SYMBOL_INFO, &WallSym, WallSym.size);
if (error)
{
dprintf(" Ioctl returned %s\n", pszWinDbgError(error));
break;
}
if (!Valid && !ForceDump) break;
}
if (!Reverse)
{
if (!NT_SUCCESS(ValidateAddress(NextScanAddr, "Next ScanAddr", SCAN_VALID_AT_END)))
{
if (!ForceDump) break;
}
ScanAddr = NextScanAddr;
}
}
return Valid;
}
/**************************************************************************\
*
* ScanDumper::NextScan
*
\**************************************************************************/
BOOL
ScanDumper::NextScan(
LONG NextTop,
LONG NextBottom,
ULONG NumWalls
)
{
LONG PrevBottom = Bottom;
BOOL bRet = TRUE;
scan++;
if (scan < 0 || (ULONG)scan >= ScanLimit)
{
dprintf(" * Scan count %d is not in range 1 to %u\n", scan+1, ScanLimit);
Valid = FALSE;
bRet = FALSE;
}
wall = 0;
PrevRight = NEG_INFINITY;
cWalls = NumWalls;
Top = NextTop;
Bottom = NextBottom;
if ((bRet || ForceDump) && Top < PrevBottom)
{
dprintf(" * Scan %d top (%d) < prev bottom (%d)\n",
scan, Top, PrevBottom);
Valid = FALSE;
bRet = FALSE;
}
if (gbVerbose)
{
dprintf(" * Scan %d covers from %d to %d and has %u walls.\n", scan, Top, Bottom, cWalls);
}
if ((bRet || ForceDump) && Bottom < Top)
{
dprintf(" * Scan %d bottom (%d) < top (%d)\n",
scan, Bottom, Top);
Valid = FALSE;
bRet = FALSE;
}
if ((bRet || ForceDump) && cWalls > COUNT_LIMIT)
{
dprintf(" * cWalls (%u) is suspiciously long at scan %d\n", cWalls, scan);
Valid = FALSE;
bRet = FALSE;
}
if ((bRet || ForceDump) && cWalls == 0 && PrintBlocks)
{
dprintf("\tNULL Scans from %d to %d.\n", Top, Bottom);
}
return bRet;
}
/**************************************************************************\
*
* ScanDumper::PrevScan
*
\**************************************************************************/
BOOL
ScanDumper::PrevScan(
LONG PrevTop,
LONG PrevBottom,
ULONG NumWalls
)
{
LONG NextTop = Top;
BOOL bRet = TRUE;
scan--;
if (NegativeScanCount)
{
if (-scan < 1 || (ULONG)-scan > ScanLimit)
{
dprintf(" * Scan count %u is not in range 1 to %u\n", -scan, ScanLimit);
Valid = FALSE;
bRet = FALSE;
}
}
else
{
if (scan < 0 || (ULONG)scan >= ScanLimit)
{
dprintf(" * Scan count %u is not in range 1 to %u\n", scan+1, ScanLimit);
Valid = FALSE;
bRet = FALSE;
}
}
wall = 0;
PrevRight = NEG_INFINITY;
cWalls = NumWalls;
Top = PrevTop;
Bottom = PrevBottom;
if ((bRet || ForceDump) && Bottom > NextTop)
{
dprintf(" * Scan %d bottom (%d) > next top (%d)\n",
scan, Bottom, NextTop);
Valid = FALSE;
bRet = FALSE;
}
if (gbVerbose)
{
dprintf(" * Scan %d covers from %d to %d and has %u walls.\n", scan, Top, Bottom, cWalls);
}
if ((bRet || ForceDump) && Bottom < Top)
{
dprintf(" * Scan %d bottom (%d) < top (%d)\n",
scan, Bottom, Top);
Valid = FALSE;
bRet = FALSE;
}
if ((bRet || ForceDump) && cWalls > COUNT_LIMIT)
{
dprintf(" * cWalls (%u) is suspiciously long at scan %d\n", cWalls, scan);
Valid = FALSE;
bRet = FALSE;
}
if ((bRet || ForceDump) && cWalls == 0 && PrintBlocks)
{
dprintf("\tNULL Scans from %d to %d.\n", Top, Bottom);
}
return bRet;
}
/**************************************************************************\
*
* ScanDumper::NextLeftWall
*
\**************************************************************************/
ULONG
ScanDumper::NextLeftWall(
LONG NextLeft
)
{
ULONG Status = STATUS_SUCCESS;
if (wall > cWalls)
{
dprintf(" * More walls (%u) than expected (%u).\n", wall, cWalls);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
Left = NextLeft;
if (Left <= PrevRight)
{
dprintf(" * Left wall %d (%d) <= previous right (%d) @ scan %d\n",
wall, Left, PrevRight, scan);
Valid = FALSE;
Status = STATUS_UNSUCCESSFUL;
}
wall++;
return Status;
}
/**************************************************************************\
*
* ScanDumper::NextRightWall
*
\**************************************************************************/
ULONG ScanDumper::NextRightWall(
LONG Right
)
{
ULONG Status = STATUS_SUCCESS;
if (wall > cWalls)
{
dprintf(" * More walls (%u) than expected (%u).\n", wall, cWalls);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
if (Right <= Left)
{
dprintf(" * Right wall %d (%d) <= left (%d) @ scan %d\n",
wall, Right, Left, scan);
Valid = FALSE;
Status = STATUS_UNSUCCESSFUL;
}
if (PrintBlocks)
{
dprintf("\tRectangle #%d (%d,%d) - (%d,%d)\n",
block, Left, Top, Right, Bottom);
}
else if (PrintProgress)
{
dprintf(".");
if ((ProgressCount++ % 60) == 0)
{
dprintf("\n");
}
}
wall++;
block++;
PrevRight = Right;
return Status;
}
/**************************************************************************\
*
* ScanDumper::ValidateAddress
*
\**************************************************************************/
ULONG ScanDumper::ValidateAddress(
ULONG64 Address,
const char *pszAddrName,
ULONG Flags
)
{
if (pszAddrName == NULL)
{
pszAddrName = "address";
}
if (gbVerbose)
{
dprintf(" Validating %s %#p\n", pszAddrName, Address);
}
// Check allocation limits
if (Address < AddressBase)
{
if ((Flags & SCAN_VALID_NO_ERROR_PRINT) == 0)
dprintf(" * %s %#p is before address base %#p\n", pszAddrName, Address, AddressBase);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
if (Address > AddressLimit)
{
if ((Flags & SCAN_VALID_NO_ERROR_PRINT) == 0)
dprintf(" * %s %#p is beyond address limit %#p\n", pszAddrName, Address, AddressLimit);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
// Check head and tail limits
if (Address < FirstScanAddr)
{
if ((Flags & SCAN_VALID_NO_ERROR_PRINT) == 0)
dprintf(" * %s %#p is before head address %#p\n", pszAddrName, Address, FirstScanAddr);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
if (Address > LastScanAddr)
{
if ((Flags & SCAN_VALID_NO_ERROR_PRINT) == 0)
dprintf(" * %s %#p beyond tail address %#p\n", pszAddrName, Address, LastScanAddr);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
// Check end edge limits
if (! (Flags & SCAN_VALID_AT_END))
{
if (Address == AddressLimit)
{
if ((Flags & SCAN_VALID_NO_ERROR_PRINT) == 0)
dprintf(" * %s %#p is at address limit %#p\n", pszAddrName, Address, AddressLimit);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
if (Address == LastScanAddr)
{
if ((Flags & SCAN_VALID_NO_ERROR_PRINT) == 0)
dprintf(" * %s %#p is at tail address %#p\n", pszAddrName, Address, LastScanAddr);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
}
// Check start edge limits
if (! (Flags & SCAN_VALID_AT_START))
{
if (Address == AddressBase)
{
if ((Flags & SCAN_VALID_NO_ERROR_PRINT) == 0)
dprintf(" * %s %#p is at address base %#p\n", pszAddrName, Address, AddressBase);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
if (Address == FirstScanAddr)
{
if ((Flags & SCAN_VALID_NO_ERROR_PRINT) == 0)
dprintf(" * %s %#p is at head address %#p\n", pszAddrName, Address, FirstScanAddr);
Valid = FALSE;
return STATUS_UNSUCCESSFUL;
}
}
return STATUS_SUCCESS;
}
/**************************************************************************\
*
* ScanDumper callback interfaces
*
\**************************************************************************/
ULONG
WallArrayEntryCallback(
PFIELD_INFO pField,
ScanDumper *pScanDumper
)
{
if (pScanDumper == NULL || pField == NULL)
{
return STATUS_UNSUCCESSFUL;
}
return pScanDumper->ValidateAddress(pField->address, "Wall @", SCAN_VALID_EXCLUSIVE);
}
ULONG
LeftWallCallback(
PFIELD_INFO pField,
ScanDumper *pScanDumper
)
{
if (pField == NULL)
{
dprintf(" * Error: LeftWallCallback was given NULL pField.\n");
return STATUS_UNSUCCESSFUL;
}
pField->fieldCallBack = RightWallCallback;
if (pScanDumper == NULL)
{
dprintf(" * Error: LeftWallCallback was given NULL pScanDumper.\n");
return STATUS_UNSUCCESSFUL;
}
return pScanDumper->NextLeftWall((LONG)pField->address);
}
ULONG
RightWallCallback(
PFIELD_INFO pField,
ScanDumper *pScanDumper
)
{
if (pField == NULL)
{
dprintf(" * Error: RightWallCallback was given NULL pField.\n");
return STATUS_UNSUCCESSFUL;
}
pField->fieldCallBack = LeftWallCallback;
if (pScanDumper == NULL)
{
dprintf(" * Error: RightWallCallback was given NULL pScanDumper.\n");
return STATUS_UNSUCCESSFUL;
}
return pScanDumper->NextRightWall((LONG)pField->address);
}
template <class T, int Spec>
PrintfTypeFormat<T,Spec>::PrintfTypeFormat() : PrintfFormat()
{
ComposeFormat();
}
template <class T, int Spec>
void PrintfTypeFormat<T,Spec>::ComposeFormat()
{
int pos = 0;
Format[pos++] = '%';
if (Width != -1)
{
int stored = _snprintf(&Format[pos], sizeof(Format)-5-pos, "%d", Width);
if (stored > 0)
{
pos += stored;
}
}
if (Spec & (PRINT_FORMAT_CHARACTER | PRINT_FORMAT_STRING))
{
if (Spec & PRINT_FORMAT_1BYTE)
{
Format[pos++] = 'h';
}
else if (Spec & PRINT_FORMAT_2BYTES)
{
Format[pos++] = 'l';
}
else
{
ExtWarn("Warning: Unknown character print size specification.\n");
}
if (Spec & PRINT_FORMAT_CHARACTER)
{
Format[pos++] = 'c';
}
else
{
Format[pos++] = 's';
}
}
else if (Spec & PRINT_FORMAT_POINTER)
{
Format[pos++] = 'p';
}
else
{
if (Spec & PRINT_FORMAT_1BYTE)
{
}
else if (Spec & PRINT_FORMAT_2BYTES)
{
Format[pos++] = 'h';
}
else if (Spec & PRINT_FORMAT_4BYTES)
{
Format[pos++] = 'l';
}
else if (Spec & PRINT_FORMAT_8BYTES)
{
Format[pos++] = 'I';
Format[pos++] = '6';
Format[pos++] = '4';
}
else
{
ExtWarn("Warning: Unknown print format size specification.\n");
}
if (Spec & PRINT_FORMAT_HEX)
{
Format[pos++] = 'x';
}
else if (Spec & PRINT_FORMAT_SIGNED)
{
Format[pos++] = 'd';
}
else if (Spec & PRINT_FORMAT_UNSIGNED)
{
Format[pos++] = 'u';
}
else
{
ExtErr("Error: Unknown print format specification.\n");
Format[0] = 0;
return;
}
}
Format[pos] = 0;
IsDirty = FALSE;
}
template <class T, int PrintSpec>
BOOL
ArrayDumper<T, PrintSpec>::ReadArray(
const char * SymbolName
)
{
DEBUG_VALUE Addr;
ULONG error;
ULONG ArraySize;
ULONG ArrayLength;
ULONG EntrySize;
DbgPrint("ReadArray called for %s\n", SymbolName);
Length = 0;
if (!GetArrayDimensions(Client, SymbolName, NULL, &ArraySize, &ArrayLength, &EntrySize) ||
!(ArraySize > 0 && ArrayLength > 0 && EntrySize > 0)
)
{
ExtErr("GetArrayDimensions failed or returned a zero value dimension for\n\t%s.\n", SymbolName);
ExtVerb("ArraySize: %u ArrayLength: %u EntrySize: %u.\n",
ArraySize, ArrayLength, EntrySize);
return FALSE;
}
if (EntrySize != sizeof(T))
{
ExtErr("Error: %s has entries of size %u not %u as expected.\n",
SymbolName, EntrySize, sizeof(T));
return FALSE;
}
if (S_OK == g_pExtControl->Evaluate(SymbolName, DEBUG_VALUE_INT64, &Addr, NULL))
{
if (Addr.I64 != 0)
{
HANDLE hHeap = GetProcessHeap();
if (ArrayBuffer == NULL || ArrayLength > HeapSize(hHeap, 0, ArrayBuffer))
{
T *NewBuffer;
NewBuffer = (T *) ((ArrayBuffer == NULL) ?
HeapAlloc(hHeap, 0, ArraySize):
HeapReAlloc(hHeap, 0, ArrayBuffer, ArraySize));
if (NewBuffer == NULL)
{
ExtErr("Buffer alloc failed.\n");
return FALSE;
}
ArrayBuffer = NewBuffer;
}
if (S_OK == g_pExtData->ReadVirtual(Addr.I64, ArrayBuffer, ArraySize, NULL))
{
Length = ArrayLength;
return TRUE;
}
ExtErr("ReadMemory at %p for %u bytes failed.\n", Addr.I64, ArrayLength);
}
else
{
ExtWarn("Symbol %s evaluated to zero.\n", SymbolName);
}
}
else
{
ExtErr("Couldn't evalutate: %s\n", SymbolName);
}
return FALSE;
}
template class PrintfTypeFormat<FormatTemplate(BYTE)>;
template class PrintfTypeFormat<FormatTemplate(WORD)>;
template class PrintfTypeFormat<FormatTemplate(DWORD)>;
template class PrintfTypeFormat<FormatTemplate(DWORD64)>;
template class PrintfTypeFormat<FormatTemplate(CHAR)>;
template class PrintfTypeFormat<FormatTemplate(WCHAR)>;
template class PrintfTypeFormat<FormatTemplate(SHORT)>;
template class PrintfTypeFormat<FormatTemplate(LONG)>;
template class PrintfTypeFormat<FormatTemplate(LONG64)>;
template class PrintfTypeFormat<FormatTemplate(USHORT)>;
template class PrintfTypeFormat<FormatTemplate(ULONG)>;
template class PrintfTypeFormat<FormatTemplate(ULONG64)>;
template class PrintfTypeFormat<ULONG64, PRINT_FORMAT_POINTER>;
template class PrintfTypeFormat<char [], PRINT_FORMAT_STRING>;
template class PrintfTypeFormat<char [], PRINT_FORMAT_WSTRING>;
template class ArrayDumper<FormatTemplate(ULONG)>;