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.
 
 
 
 
 
 

647 lines
17 KiB

//----------------------------------------------------------------------------
//
// User-mode exception analysis.
//
// Copyright (C) Microsoft Corporation, 2001.
//
//----------------------------------------------------------------------------
#include "precomp.h"
#pragma hdrstop
#include "nturtl.h"
typedef void (*EX_STATE_ANALYZER)(PEX_STATE ExState,
UserDebugFailureAnalysis* Analysis);
//----------------------------------------------------------------------------
//
// Exception-specific analyzers.
//
//----------------------------------------------------------------------------
#define IMPL_EXS_ANALYZER(Name) \
void \
Exa_##Name(PEX_STATE ExState, \
UserDebugFailureAnalysis* Analysis)
IMPL_EXS_ANALYZER(STATUS_ACCESS_VIOLATION)
{
Analysis->SetUlong64(ExState->Exr.ExceptionInformation[0] ?
DEBUG_FLR_WRITE_ADDRESS : DEBUG_FLR_READ_ADDRESS,
ExState->Exr.ExceptionInformation[1]);
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, "ACCESS_VIOLATION");
}
//----------------------------------------------------------------------------
//
// App verifier-specific analyzers.
//
//----------------------------------------------------------------------------
#define IMPL_AVRF_ANALYZER(Name) \
void \
Avrf_##Name(PAVRF_STOP AvrfStop, \
DebugFailureAnalysis* Analysis)
IMPL_AVRF_ANALYZER(APPLICATION_VERIFIER_INVALID_HANDLE)
{
EXT_GET_HANDLE_TRACE pGetHandleTrace;
if (AvrfStop->Params[1])
{
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_RECORD, AvrfStop->Params[1]);
}
if (AvrfStop->Params[2])
{
Analysis->SetUlong64(DEBUG_FLR_CONTEXT, AvrfStop->Params[2]);
}
if ((g_TargetQualifier == DEBUG_DUMP_SMALL) ||
(g_TargetQualifier == DEBUG_DUMP_DEFAULT) ||
(g_TargetQualifier == DEBUG_DUMP_FULL))
{
return;
}
// Look for most recent handle trace which resulted in
// bad reference
if (g_ExtControl->
GetExtensionFunction(0, "GetHandleTrace",
(FARPROC*)&pGetHandleTrace) == S_OK &&
pGetHandleTrace)
{
ULONG64 Handle = 0;
ULONG64 Stack[10];
#ifndef HANDLE_TRACE_DB_BADREF
#define HANDLE_TRACE_DB_BADREF 3
#endif
if ((*pGetHandleTrace)(g_ExtClient, HANDLE_TRACE_DB_BADREF,
0, &Handle,
Stack, sizeof(Stack)/sizeof(Stack[0])) == S_OK)
{
// Found the bad handle !!
Analysis->SetUlong64(DEBUG_FLR_BAD_HANDLE, Handle);
}
}
return;
}
IMPL_AVRF_ANALYZER(APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL)
{
CHAR DllName[MAX_PATH];
if (AvrfStop->Params[0])
{
Analysis->SetUlong64(DEBUG_FLR_CRITICAL_SECTION, AvrfStop->Params[0]);
}
if (AvrfStop->Params[2])
{
if (ReadMemory(AvrfStop->Params[2],
DllName,
sizeof(DllName),
NULL))
{
DllName[MAX_PATH-1] = DllName[MAX_PATH-2] = 0;
if (DllName[0])
{
wchr2ansi((PWCHAR) DllName, DllName);
Analysis->SetString(DEBUG_FLR_IMAGE_NAME, DllName);
Analysis->SetUlong(DEBUG_FLR_FOLLOWUP_DRIVER_ONLY, 1);
}
}
}
if (AvrfStop->Params[3])
{
Analysis->SetUlong64(DEBUG_FLR_FAULTING_MODULE, AvrfStop->Params[3]);
}
}
IMPL_AVRF_ANALYZER(APPLICATION_VERIFIER_ACCESS_VIOLATION)
{
if (AvrfStop->Params[0])
{
Analysis->SetUlong64(DEBUG_FLR_INVALID_HEAP_ADDRESS, AvrfStop->Params[0]);
}
if (AvrfStop->Params[1])
{
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, AvrfStop->Params[1]);
}
if (AvrfStop->Params[2])
{
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_RECORD, AvrfStop->Params[2]);
}
if (AvrfStop->Params[3])
{
Analysis->SetUlong64(DEBUG_FLR_CONTEXT, AvrfStop->Params[3]);
}
}
IMPL_AVRF_ANALYZER(APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK)
{
if (AvrfStop->Params[1])
{
Analysis->SetUlong64(DEBUG_FLR_INVALID_HEAP_ADDRESS, AvrfStop->Params[1]);
}
}
IMPL_AVRF_ANALYZER(APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP)
{
CHAR DllName[MAX_PATH];
if (AvrfStop->Params[0])
{
Analysis->SetUlong64(DEBUG_FLR_CRITICAL_SECTION, AvrfStop->Params[0]);
}
}
BOOL
CheckAppVerifierEnabled(
void
)
{
ULONG64 PebAddress;
ULONG Flags;
ULONG BytesRead;
ULONG I;
ULONG64 GlobalFlags;
//
// No app verifier on NT 4
//
if (g_TargetBuild < 2195)
{
return FALSE;
}
GetPebAddress(0, &PebAddress);
if (PebAddress)
{
if (!InitTypeRead (PebAddress, ntdll!_PEB))
{
GlobalFlags = ReadField (NtGlobalFlag);
if ((GlobalFlags & FLG_APPLICATION_VERIFIER))
{
return TRUE;
}
}
}
return FALSE;
}
BOOL
GetVerifierDataFromException(
PEX_STATE ExState,
PULONG Code,
PULONG64 Param1,
PULONG64 Param2,
PULONG64 Param3,
PULONG64 Param4
)
{
CHAR Buffer[MAX_PATH];
ULONG64 Disp;
*Code = 0;
if (ExState == NULL)
{
return FALSE;
}
if (ExState->FirstChance &&
ExState->Exr.ExceptionCode == STATUS_INVALID_HANDLE)
{
if (FaIsFunctionAddr(ExState->Exr.ExceptionAddress,
"KiRaiseUserExceptionDispatcher"))
{
// Most likely this is a use of invalid handle, but verifier
// couldn't catch it because app is under debugger
*Code = APPLICATION_VERIFIER_INVALID_HANDLE ; // INVALID_HANDLE;
*Param1 = STATUS_INVALID_HANDLE;
return TRUE;
}
}
return FALSE;
}
BOOL
GetVerifierStopData(
PULONG Code,
PULONG64 Param1,
PULONG64 Param2,
PULONG64 Param3,
PULONG64 Param4
)
{
ULONG64 CurrentStopAddress;
ULONG PointerSize = IsPtr64() ? 8 : 4;
*Code = 0;
CurrentStopAddress = GetExpression("ntdll!AVrfpStopData");
if (CurrentStopAddress == 0)
{
CurrentStopAddress = GetExpression("verifier!AVrfpStopData");
}
if (CurrentStopAddress == 0)
{
dprintf( "Unable to resolve AVrfpStopData symbol.\n");
return FALSE;
}
if (!ReadMemory(CurrentStopAddress, Code, sizeof(*Code), NULL) ||
!ReadPointer(CurrentStopAddress + PointerSize, Param1) ||
!ReadPointer(CurrentStopAddress + 2*PointerSize, Param2) ||
!ReadPointer(CurrentStopAddress + 3*PointerSize, Param3) ||
!ReadPointer(CurrentStopAddress + 4*PointerSize, Param4))
{
dprintf("Cannot read AVrfpStopData values.\n");
return FALSE;
}
if (*Code)
{
return TRUE;
}
return FALSE;
}
HRESULT
DoVerifierAnalysis(
PEX_STATE ExState,
DebugFailureAnalysis* Analysis
)
{
AVRF_STOP AvrfStop = {0};
if (!GetVerifierStopData(&AvrfStop.Code, &AvrfStop.Params[0], &AvrfStop.Params[1],
&AvrfStop.Params[2], &AvrfStop.Params[3]) &&
!GetVerifierDataFromException(ExState, &AvrfStop.Code, &AvrfStop.Params[0],
&AvrfStop.Params[1], &AvrfStop.Params[2],
&AvrfStop.Params[3]))
{
// Doesn't look like a verifier bug
return S_FALSE;
}
CHAR BugCheckStr[40];
sprintf(BugCheckStr, "AVRF_%lx", AvrfStop.Code);
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
#define CALL_AVRF_ANALYZER(Name) \
case Name: \
Avrf_##Name(&AvrfStop, \
Analysis); \
break;
switch (AvrfStop.Code)
{
CALL_AVRF_ANALYZER(APPLICATION_VERIFIER_INVALID_HANDLE);
CALL_AVRF_ANALYZER(APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL);
CALL_AVRF_ANALYZER(APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK);
CALL_AVRF_ANALYZER(APPLICATION_VERIFIER_ACCESS_VIOLATION);
case APPLICATION_VERIFIER_LOCK_DOUBLE_INITIALIZE:
case APPLICATION_VERIFIER_LOCK_OVER_RELEASED:
case APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED:
case APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED:
case APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT:
CALL_AVRF_ANALYZER(APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP);
default:
break;
}
return S_OK;
}
//----------------------------------------------------------------------------
//
// Generic exception analysis handling.
//
//----------------------------------------------------------------------------
struct EX_ANALYZER_ENTRY
{
ULONG Code;
EX_STATE_ANALYZER Analyzer;
};
#define EXS_ANALYZER_ENTRY(Name) \
Name, Exa_##Name
EX_ANALYZER_ENTRY g_ExAnalyzers[] =
{
EXS_ANALYZER_ENTRY(STATUS_ACCESS_VIOLATION),
0, NULL,
};
void
UeFillAnalysis(PEX_STATE ExState,
UserDebugFailureAnalysis* Analysis)
{
HRESULT Status;
//
// Add common analysis entries.
//
Analysis->SetFailureClass(DEBUG_CLASS_USER_WINDOWS);
Analysis->SetFailureType(DEBUG_FLR_USER_CRASH);
Analysis->SetFailureCode(ExState->Exr.ExceptionCode);
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, ExState->Exr.ExceptionAddress);
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_RECORD, -1);
CHAR BugCheckStr[40];
sprintf(BugCheckStr, "%lx", ExState->Exr.ExceptionCode);
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
Analysis->SetString(DEBUG_FLR_DEFAULT_BUCKET_ID, "APPLICATION_FAULT");
CHAR ProcessName[512];
ULONG Size;
PCHAR Name;
Status = g_ExtSystem->GetCurrentProcessExecutableName(ProcessName,
sizeof(ProcessName),
&Size);
if ((Status == S_OK) && (Size > 1))
{
if (Name = strrchr(ProcessName, '\\'))
{
Name++;
}
else
{
Name = ProcessName;
}
Analysis->SetString(DEBUG_FLR_PROCESS_NAME, Name);
if (!_stricmp("iexplore.exe", Name))
{
Analysis->SetFailureType(DEBUG_FLR_IE_CRASH);
}
}
if (g_TargetPlatform == VER_PLATFORM_WIN32_NT)
{
Analysis->CheckModuleSymbols("ntdll", "OS");
if (CheckAppVerifierEnabled())
{
// This proces has app verifier enabled
DoVerifierAnalysis(ExState, Analysis);
}
}
//
// Find an analyzer for the exception and run it.
//
EX_ANALYZER_ENTRY* Entry = g_ExAnalyzers;
while (Entry->Analyzer)
{
if (Entry->Code == ExState->Exr.ExceptionCode)
{
Entry->Analyzer(ExState, Analysis);
break;
}
Entry++;
}
Analysis->ProcessInformation();
}
UserDebugFailureAnalysis*
UeAnalyze(
PEX_STATE ExState,
ULONG Flags
)
{
ULONG EventType;
DEBUG_LAST_EVENT_INFO_EXCEPTION LastEx;
if (g_ExtControl->GetLastEventInformation(&EventType,
&ExState->ProcId,
&ExState->ThreadId,
&LastEx, sizeof(LastEx), NULL,
NULL, 0, NULL) != S_OK)
{
ExtErr("Unable to get last event information\n");
return NULL;
}
if (EventType != DEBUG_EVENT_EXCEPTION)
{
ExtErr("Event is not an exception\n");
return NULL;
}
ExState->Exr = LastEx.ExceptionRecord;
ExState->FirstChance = LastEx.FirstChance;
UserDebugFailureAnalysis* Analysis = new UserDebugFailureAnalysis;
if (Analysis)
{
Analysis->SetProcessingFlags(Flags);
__try
{
UeFillAnalysis(ExState, Analysis);
}
__except(FaExceptionFilter(GetExceptionInformation()))
{
delete Analysis;
Analysis = NULL;
}
}
return Analysis;
}
HRESULT
AnalyzeUserException(
PCSTR args
)
{
ULONG Flags = 0;
if (g_TargetClass != DEBUG_CLASS_USER_WINDOWS)
{
dprintf("!analyzeuexception is for user mode only\n");
return E_FAIL;
}
for (;;)
{
while (*args == ' ' || *args == '\t')
{
args++;
}
if (*args == '-')
{
++args;
switch(*args)
{
case 'v':
Flags |= FAILURE_ANALYSIS_VERBOSE;
break;
case 'f':
break;
default:
dprintf("Unknown option %c\n", *args);
break;
}
++args;
}
else
{
break;
}
}
dprintf("*******************************************************************************\n");
dprintf("* *\n");
dprintf("* Exception Analysis *\n");
dprintf("* *\n");
dprintf("*******************************************************************************\n");
dprintf("\n");
if (!(Flags & FAILURE_ANALYSIS_VERBOSE))
{
dprintf("Use !analyze -v to get detailed debugging information.\n\n");
}
EX_STATE ExState;
UserDebugFailureAnalysis* Analysis = UeAnalyze(&ExState, Flags);
if (!Analysis)
{
dprintf("\n\nFailure could not be analyzed\n\n");
g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, ".lastevent",
DEBUG_EXECUTE_DEFAULT);
return E_FAIL;
}
Analysis->Output();
delete Analysis;
return S_OK;
}
DECLARE_API( analyzeuexception )
{
INIT_API();
HRESULT Hr = AnalyzeUserException(args);
EXIT_API();
return Hr;
}
//----------------------------------------------------------------------------
//
// UserDebugFailureAnalysis.
//
//----------------------------------------------------------------------------
UserDebugFailureAnalysis::UserDebugFailureAnalysis(void)
: m_NtDllModule("ntdll"),
m_Kernel32Module("kernel32"),
m_Advapi32Module("advapi32")
{
}
DEBUG_POOL_REGION
UserDebugFailureAnalysis::GetPoolForAddress(ULONG64 Addr)
{
return DbgPoolRegionUnknown;
}
PCSTR
UserDebugFailureAnalysis::DescribeAddress(ULONG64 Address)
{
// XXX drewb - QueryVirtual to say something about the address?
return NULL;
}
FOLLOW_ADDRESS
UserDebugFailureAnalysis::IsPotentialFollowupAddress(ULONG64 Address)
{
// XXX drewb - Check against maximum user address, but there's
// no guaranteed way to get the maximum user address.
return FollowYes;
}
FOLLOW_ADDRESS
UserDebugFailureAnalysis::IsFollowupContext(ULONG64 Address1, ULONG64 Address2,
ULONG64 Address3)
{
// XXX drewb - Check against maximum user address, but there's
// no guaranteed way to get the maximum user address.
return FollowYes;
}
FlpClasses
UserDebugFailureAnalysis::GetFollowupClass(ULONG64 Address,
PCSTR Module, PCSTR Routine)
{
if (m_NtDllModule.Contains(Address) ||
m_Kernel32Module.Contains(Address) ||
m_Advapi32Module.Contains(Address) ||
(!_strcmpi(Module, "SharedUserData") &&
Routine && !_strcmpi(Routine, "SystemCallStub")))
{
return FlpOSRoutine;
}
else if (!_strcmpi(Module, "shell32") ||
!_strcmpi(Module, "user32") ||
!_strcmpi(Module, "gdi32") ||
!_strcmpi(Module, "mshtml") ||
!_strcmpi(Module, "ole32") ||
!_strcmpi(Module, "verifier") ||
!_strcmpi(Module, "rpcrt4"))
{
return FlpOSFilterDrv;
}
else
{
return FlpUnknownDrv;
}
}
BOOL
UserDebugFailureAnalysis::CheckForCorruptionInHTE(
ULONG64 hTableEntry,
PCHAR Owner,
ULONG OwnerSize
)
{
return FALSE;
}