WindowsXP-SP1/windows/core/ntgdi/kdexts2/verifier.cxx
2020-09-30 16:53:49 +02:00

340 lines
10 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
verifier.cxx
Abstract:
This file contains the verifier related routines
for the kernel debugger extensions dll.
Author:
Jason Hartman (JasonHa)
Environment:
User Mode
--*/
#include "precomp.hxx"
// Pool tracking is always disabled for graphic drivers. (NTBUG:421768)
#define GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED 0
/******************************Public*Routine******************************\
* DECLARE_API( verifier )
*
* Dumps the stack backtraces in the tracked pool. Only for checked Hydra.
*
\**************************************************************************/
CHAR szVSTATE[] = "win32k!VSTATE";
#if GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED
CHAR szVERIFIERTRACKHDR[] = "win32k!VERIFIERTRACKHDR";
#endif
const PSZ gpszVerifierFuncs[] = {
"EngAllocMem ",
"EngFreeMem ",
"EngAllocUserMem ",
"EngFreeUserMem ",
"EngCreateBitmap ",
"EngCreateDeviceSurface",
"EngCreateDeviceBitmap ",
"EngCreatePalette ",
"EngCreateClip ",
"EngCreatePath ",
"EngCreateWnd ",
"EngCreateDriverObj ",
"BRUSHOBJ_pvAllocRbrush",
"CLIPOBJ_ppoGetPath ",
};
#define NUM_VER_FUNCS (sizeof(gpszVerifierFuncs)/sizeof(gpszVerifierFuncs[0]))
DECLARE_API( verifier )
{
ULONG error;
ULONG64 offVState;
#define GetVSTATEField(field,local) \
GetFieldValue(offVState, szVSTATE, field, local)
// VSTATE fields
FLONG fl;
#if GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED
ULONG64 pList;
#endif
#if GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED
BOOL bDump = FALSE;
#endif
BOOL bStats = FALSE;
//
// Parse arguments.
//
PARSE_ARGUMENTS(verifier_help);
if(parse_iFindSwitch(tokens, ntok, 'h')!=-1) { goto verifier_help; }
#if GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED
if(parse_iFindSwitch(tokens, ntok, 'd')!=-1) { bDump = TRUE; }
#endif
if(parse_iFindSwitch(tokens, ntok, 's')!=-1) { bStats = TRUE; }
//
// Get global veriferier address (VSTATE gvs)
//
offVState = GetExpression(GDISymbol(gvs));
if (! offVState)
{
ReloadSymbols(GDIModule());
offVState = GetExpression(GDISymbol(gvs));
if (! offVState)
{
dprintf(" GetExpression(\"%s\") returned 0.\n", GDISymbol(gvs));
dprintf(" Please fix symbols and try again.\n");
EXIT_API(S_OK);
}
}
//
// Always dump the verifier state.
//
dprintf("Global VSTATE (@ %#p)\n", offVState);
if (error = (ULONG)InitTypeRead(offVState, win32k!VSTATE))
{
dprintf(" unable to get contents of verifier state\n");
dprintf(" (InitTypeRead returned %s)\n", pszWinDbgError(error));
EXIT_API(S_OK);
}
fl = (FLONG)ReadField(fl);
dprintf(" fl = 0x%08lx\n", fl);
if (fl = (FLONG)flPrintFlags(afdDVERIFIER, (ULONG64)fl))
{
dprintf(" Unknown flags: 0x%08lx\n", fl);
}
dprintf(" bSystemStable = %s\n" , ReadField(bSystemStable) ? "TRUE" : "FALSE");
dprintf(" ulRandomSeed = 0x%08lx\n", (ULONG)ReadField(ulRandomSeed));
dprintf(" ulFailureMask = 0x%08lx\n", (ULONG)ReadField(ulFailureMask));
dprintf(" ulDebugLevel = %ld\n" , (ULONG)ReadField(ulDebugLevel));
#if GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED
dprintf(" hsemPoolTracker = %#p\n" , ReadField(hsemPoolTracker));
pList = ReadField(lePoolTrackerHead.Flink);
dprintf(" lePoolTrackerHead.Flink = %#p\n" , pList);
dprintf(" lePoolTrackerHead.Blink = %#p\n" , ReadField(lePoolTrackerHead.Blink));
#endif
//
// Optionally dump the statistics for each function hooked by verifier.
//
if (bStats)
{
FIELD_INFO Array = {
DbgStr("avs"), DbgStr(""),
0, DBG_DUMP_FIELD_FULL_NAME,
0, NULL
};
FIELD_INFO Entry = {
DbgStr("avs[0]"), DbgStr(""),
0, DBG_DUMP_FIELD_FULL_NAME,
0, NULL
};
SYM_DUMP_PARAM Sym = {
sizeof (SYM_DUMP_PARAM), DbgStr(szVSTATE),
DBG_DUMP_NO_PRINT, offVState,
NULL, NULL, NULL,
1, &Array
};
// Read size of the statistics array
error = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
if (!error)
{
// Read size of a single statistics entry
Sym.Fields = &Entry;
error = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
}
if (error || (Entry.size == 0))
{
dprintf("\n Unable to get verifier statistics.\n");
if (error)
{
if (error == FIELDS_DID_NOT_MATCH)
{
dprintf(" * " GDIModule() " was not built with VERIFIER_STATISTICS defined.\n");
}
else
{
dprintf(" Last error was %s\n.", pszWinDbgError(error));
}
}
}
else
{
char szBuffer[80]; // Composition buffer for field names
int ArraySize = Array.size/Entry.size; // Number of hooked functions
int i;
ULONG ulAttempts;
ULONG ulFailures;
dprintf("\nVerifier statistics:\n");
dprintf("Function Attempts Failures\n");
dprintf("---------------------- ---------- ----------\n");
// Read and print statistics for each hooked function
for (i = 0; i < ArraySize && !CheckControlC(); i++)
{
sprintf(szBuffer, "avs[%d].ulAttempts", i);
error = GetVSTATEField(szBuffer, ulAttempts);
if (error) break;
sprintf(szBuffer, "avs[%d].ulFailures", i);
error = GetVSTATEField(szBuffer, ulFailures);
if (error) break;
dprintf("%s 0x%08lx 0x%08lx\n",
((i < NUM_VER_FUNCS) ?
gpszVerifierFuncs[i] :
" * Uknown Interface * "),
ulAttempts,
ulFailures);
}
if (i == 0)
{
dprintf(" ** No Statistics Available **\n");
}
else if (i > NUM_VER_FUNCS)
{
dprintf("\n * - .verifier extension needs updated.\n");
}
if (error)
{
dprintf(" Last statistic read returned %s.\n", szBuffer, pszWinDbgError(error));
}
}
}
#if GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED
//
// Optionally dump tracked pool.
//
if (bDump)
{
if (fl & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS)
{
FIELD_INFO SizeInfo = {DbgStr("ulSize"), NULL, 0, 0, 0, NULL};
SYM_DUMP_PARAM Sym = {
sizeof(SYM_DUMP_PARAM), DbgStr(szVERIFIERTRACKHDR),
DBG_DUMP_NO_PRINT, 0, NULL, NULL, NULL,
1, &SizeInfo
};
BYTE Tag[4]; // Allocation tag
ULONG64 Size; // Size of allocation
ULONG SizeSize;
ULONG SizeHdr; // Size of header struct (offset to allocation)
// Read sizeof of ulSize field
error = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
SizeSize = (error) ? sizeof(Size) : SizeInfo.size;
// Read sizeof VERIFIERTRACKHDR structure
Sym.Options |= DBG_DUMP_GET_SIZE_ONLY;
SizeHdr = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
dprintf("\nTracked VerifierEngAllocMem allocations\n");
dprintf("Tag \tSize %s\tAddr \n", (SizeSize == sizeof(ULONG)) ? "" : " ");
dprintf("----\t--------%s\t----------------\n", (SizeSize == sizeof(ULONG)) ? "" : "--------");
// Are there any allocations?
if (pList)
{
ULONG64 pListHead = pList;
// Read until we loop back to the first allocation.
do
{
// Attempt to read allocation info
error = GetFieldValue(pList, szVERIFIERTRACKHDR, "ulTag", Tag);
if (error) break;
error = GetFieldValue(pList, szVERIFIERTRACKHDR, "ulSize", Size);
if (error) break;
// Print Tag
dprintf("%c%c%c%c", Tag[0], Tag[1], Tag[2], Tag[3]);
// Print allocation size
if (SizeSize == sizeof(ULONG))
{
dprintf("\t%08X", (ULONG)Size);
}
else
{
dprintf("\t%I64X", Size);
}
// Print start address of allocation
if (SizeHdr != 0)
{
dprintf("\t%p\n", pList+SizeHdr);
}
else
{
dprintf("\t%p+??\n", pList);
}
// Get next allocation
error = GetFieldValue(pList, GDIType(LIST_ENTRY), "FLink", pList);
} while (pList != pListHead && !error && !CheckControlC());
}
else
{
dprintf(" ** No tracked allocations.\n");
}
}
else
dprintf("\nPool tracking not enabled\n");
}
#endif
EXIT_API(S_OK);
//
// Debugger extension help.
//
verifier_help:
dprintf("Usage: verifier [-?h"
#if GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED
"d"
#endif
"s]\n");
#if GRAPHICS_DRIVER_POOL_TRACKING_SUPPORTED
dprintf(" d - Dump tracked pool (if pool tracking enabled)\n");
#endif
dprintf(" s - Dump allocation statistics\n");
EXIT_API(S_OK);
}