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
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)>;
|
|
|
|
|