/*++ 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); }