windows-nt/Source/XPSP1/NT/sdktools/debuggers/exts/extsdll/verifier.c

712 lines
16 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
verifier.c
Abstract:
Application verifier debugger extension for both ntsd and kd.
Author:
Silviu Calinoiu (SilviuC) 4-Mar-2001
Environment:
User Mode.
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
ULONG
VrfGetArguments (
PCHAR ArgsString,
PCHAR Args[],
ULONG NoOfArgs
);
VOID
VrfHelp (
);
BOOLEAN
VrfTraceInitialize (
);
ULONG64
VrfTraceAddress (
ULONG TraceIndex
);
VOID
VrfTraceDump (
ULONG TraceIndex
);
VOID
VrfDumpSettings (
);
VOID
VrfDumpVspaceLog (
ULONG NoOfEntries,
ULONG64 Address
);
VOID
VrfDumpHeapLog (
ULONG NoOfEntries,
ULONG64 Address
);
DECLARE_API( avrf )
/*++
Routine Description:
Application verifier debugger extension.
Arguments:
args -
Return Value:
None
--*/
{
PCHAR Args[16];
ULONG NoOfArgs, I;
INIT_API();
//
// Parse arguments.
//
NoOfArgs = VrfGetArguments ((PCHAR)args,
Args,
16);
#if 0
for (I = 0; I < NoOfArgs; I += 1) {
dprintf ("%02u: %s\n", I, Args[I]);
}
#endif
//
// Check if help needed
//
if (NoOfArgs > 0 && strstr (Args[0], "?") != NULL) {
VrfHelp ();
goto Exit;
}
if (VrfTraceInitialize() == FALSE) {
goto Exit;
}
if (NoOfArgs > 1 && _stricmp (Args[0], "-trace") == 0) {
VrfTraceDump (atoi(Args[1]));
goto Exit;
}
if (NoOfArgs > 1 && _stricmp (Args[0], "-vs") == 0) {
if (NoOfArgs > 2 && _stricmp (Args[1], "-a") == 0) {
ULONG64 Address;
BOOL Result;
PCSTR Remainder;
Result = GetExpressionEx (Args[2], &Address, &Remainder);
if (Result == FALSE) {
dprintf ("\nFailed to convert `%s' to an address.\n", Args[2]);
goto Exit;
}
// sscanf (Args[2], "%I64X", &Address);
dprintf ("Searching in vspace log for address %I64X ...\n\n", Address);
VrfDumpVspaceLog (0, Address);
goto Exit;
}
else {
VrfDumpVspaceLog (atoi(Args[1]), 0);
goto Exit;
}
}
if (NoOfArgs > 1 && _stricmp (Args[0], "-hp") == 0) {
if (NoOfArgs > 2 && _stricmp (Args[1], "-a") == 0) {
ULONG64 Address;
BOOL Result;
PCSTR Remainder;
Result = GetExpressionEx (Args[2], &Address, &Remainder);
if (Result == FALSE) {
dprintf ("\nFailed to convert `%s' to an address.\n", Args[2]);
goto Exit;
}
// sscanf (Args[2], "%I64X", &Address);
dprintf ("Searching in vspace log for address %I64X ...\n\n", Address);
VrfDumpHeapLog (0, Address);
goto Exit;
}
else {
VrfDumpHeapLog (atoi(Args[1]), 0);
goto Exit;
}
}
//
// If no option specified then we just print current settings.
//
VrfDumpSettings ();
Exit:
EXIT_API();
return S_OK;
}
VOID
VrfHelp (
)
{
dprintf ("Application verifier debugger extension \n"
" \n"
"!avrf displays current settings and stop \n"
" data if a verifier stop happened. \n"
"!avrf -vs N dumps last N entries from vspace log. \n"
"!avrf -vs -a ADDR searches ADDR in the vspace log. \n"
"!avrf -hp N dumps last N entries from heap log. \n"
"!avrf -hp -a ADDR searches ADDR in the heap log. \n"
" \n");
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////// Argument parsing routines
/////////////////////////////////////////////////////////////////////
PCHAR
VrfGetArgument (
PCHAR Args,
PCHAR * Next
)
{
PCHAR Start;
if (Args == NULL) {
return NULL;
}
while (*Args == ' ' || *Args == '\t') {
Args += 1;
}
if (*Args == '\0') {
return NULL;
}
Start = Args;
while (*Args != ' ' && *Args != '\t' && *Args != '\0') {
Args += 1;
}
if (*Args == '\0') {
*Next = NULL;
}
else {
*Args = '\0';
*Next = Args + 1;
}
return Start;
}
ULONG
VrfGetArguments (
PCHAR ArgsString,
PCHAR Args[],
ULONG NoOfArgs
)
{
PCHAR Arg = ArgsString;
PCHAR Next;
ULONG Index;
for (Index = 0; Index < NoOfArgs; Index += 1) {
Arg = VrfGetArgument (Arg, &Next);
if (Arg) {
Args[Index] = Arg;
}
else {
break;
}
Arg = Next;
}
return Index;
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////// Dump stack traces
/////////////////////////////////////////////////////////////////////
ULONG64 TraceDbArrayEnd;
ULONG PvoidSize;
BOOLEAN
VrfTraceInitialize (
)
{
ULONG64 TraceDatabaseAddress;
ULONG64 TraceDatabase;
//
// Stack trace database address
//
TraceDatabaseAddress = GetExpression("ntdll!RtlpStackTraceDataBase");
if ( TraceDatabaseAddress == 0 ) {
dprintf( "Unable to resolve ntdll!RtlpStackTraceDataBase symbolic name.\n");
return FALSE;
}
if (ReadPtr (TraceDatabaseAddress, &TraceDatabase ) != S_OK) {
dprintf( "Cannot read pointer at ntdll!RtlpStackTraceDataBase\n" );
return FALSE;
}
if (TraceDatabase == 0) {
dprintf( "Stack traces not enabled (ntdll!RtlpStackTraceDataBase is null).\n" );
return FALSE;
}
//
// Find the array of stack traces
//
if (InitTypeRead(TraceDatabase, ntdll!_STACK_TRACE_DATABASE)) {
dprintf("Unable to read type ntdll!_STACK_TRACE_DATABASE @ %p\n", TraceDatabase);
return FALSE;
}
TraceDbArrayEnd = ReadField (EntryIndexArray);
PvoidSize = GetTypeSize ("ntdll!PVOID");
return TRUE;
}
ULONG64
VrfTraceAddress (
ULONG TraceIndex
)
{
ULONG64 TracePointerAddress;
ULONG64 TracePointer;
TracePointerAddress = TraceDbArrayEnd - TraceIndex * PvoidSize;
if (ReadPtr (TracePointerAddress, &TracePointer) != S_OK) {
dprintf ("Cannot read stack trace address @ %p\n", TracePointerAddress);
return 0;
}
return TracePointer;
}
VOID
VrfTraceDump (
ULONG TraceIndex
)
{
ULONG64 TraceAddress;
ULONG64 TraceArray;
ULONG TraceDepth;
ULONG Offset;
ULONG Index;
ULONG64 ReturnAddress;
CHAR Symbol[ 1024 ];
ULONG64 Displacement;
//
// Get real address of the trace.
//
TraceAddress = VrfTraceAddress (TraceIndex);
if (TraceAddress == 0) {
return;
}
//
// Read the stack trace depth
//
if (InitTypeRead(TraceAddress, ntdll!_RTL_STACK_TRACE_ENTRY)) {
dprintf("Unable to read type ntdll!_RTL_STACK_TRACE_ENTRY @ %p\n", TraceAddress);
return;
}
TraceDepth = (ULONG)ReadField (Depth);
//
// Limit the depth to 20 to protect ourselves from corrupted data
//
TraceDepth = __min (TraceDepth, 16);
//
// Get a pointer to the BackTrace array
//
GetFieldOffset ("ntdll!_RTL_STACK_TRACE_ENTRY", "BackTrace", &Offset);
TraceArray = TraceAddress + Offset;
//
// Dump this stack trace. Skip first two entries.
//
TraceArray += 2 * PvoidSize;
for (Index = 2; Index < TraceDepth; Index += 1) {
if (ReadPtr (TraceArray, &ReturnAddress) != S_OK) {
dprintf ("Cannot read address @ %p\n", TraceArray);
return;
}
GetSymbol (ReturnAddress, Symbol, &Displacement);
dprintf ("\t%p: %s+0x%I64X\n",
ReturnAddress,
Symbol,
Displacement );
TraceArray += PvoidSize;
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////// Dump settings
/////////////////////////////////////////////////////////////////////
VOID
VrfDumpSettings (
)
{
ULONG64 FlagsAddress;
ULONG Flags;
ULONG BytesRead;
ULONG64 StopAddress;
ULONG64 StopData[5];
ULONG I;
ULONG UlongPtrSize;
UlongPtrSize = GetTypeSize ("ntdll!ULONG_PTR");
FlagsAddress = GetExpression("ntdll!AVrfpVerifierFlags");
if (FlagsAddress == 0) {
dprintf( "Unable to resolve ntdll!AVrfpVerifierFlags symbolic name.\n");
return;
}
if (ReadMemory (FlagsAddress, &Flags, sizeof Flags, &BytesRead) == FALSE) {
dprintf ("Cannot read value @ %p (ntdll!AVrfpVerifierFlags) \n", FlagsAddress);
return;
}
dprintf ("Application verifier settings (%08X): \n\n", Flags);
if (Flags & RTL_VRF_FLG_FULL_PAGE_HEAP) {
dprintf (" - full page heap\n");
}
else {
dprintf (" - light page heap\n");
}
if (Flags & RTL_VRF_FLG_LOCK_CHECKS) {
dprintf (" - lock checks (critical section verifier)\n");
}
if (Flags & RTL_VRF_FLG_HANDLE_CHECKS) {
dprintf (" - handle checks\n");
}
if (Flags & RTL_VRF_FLG_STACK_CHECKS) {
dprintf (" - stack checks (disable automatic stack extensions)\n");
}
dprintf ("\n");
//
// Check if a verifier stop has been encountered.
//
StopAddress = GetExpression("ntdll!AVrfpStopData");
if (StopAddress == 0) {
dprintf( "Unable to resolve ntdll!AVrfpStopData symbolic name.\n");
return;
}
for (I = 0; I < 5; I += 1) {
if (ReadPtr (StopAddress + I * UlongPtrSize, &(StopData[I])) != S_OK) {
dprintf ("Cannot read value @ %p \n", StopAddress + I * UlongPtrSize);
}
}
if (StopData[0] != 0) {
dprintf ("Stop %p: %p %p %p %p \n",
StopData[0],
StopData[1],
StopData[2],
StopData[3],
StopData[4]);
// silviuc: dump more text info about the verifier_stop
}
}
/////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////// Dump vspace log
/////////////////////////////////////////////////////////////////////
VOID
VrfDumpVspaceLog (
ULONG NoOfEntries,
ULONG64 Address
)
{
ULONG64 IndexAddress;
ULONG Index;
ULONG64 LogAddress;
ULONG EntrySize;
ULONG MaxIndex = 8192; // silviuc: should not be hard coded
ULONG BytesRead;
ULONG64 EntryAddress;
ULONG TraceIndex;
ULONG I;
PCHAR OpName;
BOOLEAN Found = FALSE;
if (Address) {
NoOfEntries = MaxIndex;
}
else {
if (NoOfEntries == 0) {
NoOfEntries = 8;
}
}
EntrySize = GetTypeSize ("verifier!_VS_CALL");
IndexAddress = GetExpression("verifier!VsCallsIndex");
LogAddress = GetExpression("verifier!VsCalls");
if (IndexAddress == 0 || LogAddress == 0 || EntrySize == 0) {
dprintf( "Incorrect symbols for verifier.dll.\n");
return;
}
if (ReadMemory (IndexAddress, &Index, sizeof Index, &BytesRead) == FALSE) {
dprintf ("Cannot read value @ %p (verifier!VsCallsIndex) \n", IndexAddress);
return;
}
for (I = 0; I < NoOfEntries; I += 1) {
ULONG64 VsAddress;
ULONG64 VsSize;
BOOLEAN PrintTrace;
EntryAddress = LogAddress + EntrySize * ((Index - I) % MaxIndex);
if (InitTypeRead (EntryAddress, verifier!_VS_CALL)) {
dprintf("Unable to read type verifier!_VS_CALL @ %p\n", EntryAddress);
return;
}
switch ((ULONG)ReadField(Type)) {
case 0: OpName = "VirtualAlloc"; break;
case 1: OpName = "VirtualFree"; break;
case 2: OpName = "MapView"; break;
case 3: OpName = "UnmapView"; break;
default:OpName = "Unknown?"; break;
}
VsAddress = ReadField(Address);
VsSize = ReadField (Size);
if (Address) {
if (VsAddress <= Address && Address < VsAddress + VsSize) {
PrintTrace = TRUE;
}
else {
PrintTrace = FALSE;
}
}
else {
PrintTrace = TRUE;
}
if (PrintTrace) {
Found = TRUE;
dprintf ("%s (tid: 0x%X): \n"
"address: %p \n"
"size: %p\n"
"operation: %X\n"
"protection: %X\n",
OpName,
(ULONG)ReadField(Thread),
VsAddress,
VsSize,
(ULONG)ReadField(Operation),
(ULONG)ReadField(Protection));
TraceIndex = (ULONG) ReadField (Trace);
VrfTraceDump (TraceIndex);
dprintf ("\n");
}
}
if (! Found) {
dprintf ("No entries found. \n");
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////// Dump heap log
/////////////////////////////////////////////////////////////////////
VOID
VrfDumpHeapLog (
ULONG NoOfEntries,
ULONG64 Address
)
{
ULONG64 IndexAddress;
ULONG Index;
ULONG64 LogAddress;
ULONG EntrySize;
ULONG MaxIndex = 8192; // silviuc: should not be hard coded
ULONG BytesRead;
ULONG64 EntryAddress;
ULONG TraceIndex;
ULONG I;
PCHAR OpName;
BOOLEAN Found = FALSE;
if (Address) {
NoOfEntries = MaxIndex;
}
else {
if (NoOfEntries == 0) {
NoOfEntries = 8;
}
}
EntrySize = GetTypeSize ("verifier!_HEAP_CALL");
IndexAddress = GetExpression("verifier!HeapCallsIndex");
LogAddress = GetExpression("verifier!HeapCalls");
if (IndexAddress == 0 || LogAddress == 0 || EntrySize == 0) {
dprintf( "Incorrect symbols for verifier.dll.\n");
return;
}
if (ReadMemory (IndexAddress, &Index, sizeof Index, &BytesRead) == FALSE) {
dprintf ("Cannot read value @ %p (verifier!HeapCallsIndex) \n", IndexAddress);
return;
}
for (I = 0; I < NoOfEntries; I += 1) {
ULONG64 VsAddress;
ULONG64 VsSize;
BOOLEAN PrintTrace;
EntryAddress = LogAddress + EntrySize * ((Index - I) % MaxIndex);
if (InitTypeRead (EntryAddress, verifier!_HEAP_CALL)) {
dprintf("Unable to read type verifier!_HEAP_CALL @ %p\n", EntryAddress);
return;
}
VsAddress = ReadField(Address);
VsSize = ReadField (Size);
if (VsSize == 0) {
OpName = "free";
}
else {
OpName = "alloc";
}
if (Address) {
if (VsAddress <= Address && Address <= VsAddress + VsSize) {
PrintTrace = TRUE;
}
else {
PrintTrace = FALSE;
}
}
else {
PrintTrace = TRUE;
}
if (PrintTrace) {
Found = TRUE;
dprintf ("%s (tid: 0x%X): \n"
"address: %p \n"
"size: %p\n",
OpName,
(ULONG)ReadField(Thread),
VsAddress,
VsSize);
TraceIndex = (ULONG) ReadField (Trace);
VrfTraceDump (TraceIndex);
dprintf ("\n");
}
}
if (! Found) {
dprintf ("No entries found. \n");
}
}