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.
 
 
 
 
 
 

3470 lines
99 KiB

//----------------------------------------------------------------------------
//
// Generic failure analysis framework.
//
// Copyright (C) Microsoft Corporation, 2001.
//
//----------------------------------------------------------------------------
#include "precomp.h"
#pragma hdrstop
#include <time.h>
BOOL g_SymbolsReloaded;
HRESULT
ModuleParams::Update(void)
{
HRESULT Status;
ULONG i;
DEBUG_MODULE_PARAMETERS Params;
if (m_Valid)
{
return S_OK;
}
if ((Status = g_ExtSymbols->GetModuleByModuleName(m_Name, 0,
&i, &m_Base)) == S_OK &&
(Status = g_ExtSymbols->GetModuleParameters(1, &m_Base, i,
&Params)) == S_OK)
{
m_Size = Params.Size;
m_Valid = TRUE;
}
return Status;
}
// Read a null terminated string from the address specified.
BOOL ReadAcsiiString(ULONG64 Address, PCHAR DestBuffer, ULONG BufferLen)
{
ULONG OneByteRead;
ULONG BytesRead = 0;
if (Address && DestBuffer)
{
while (BufferLen && ReadMemory(Address, DestBuffer, 1, &OneByteRead))
{
BytesRead++;
if ((*DestBuffer) == 0)
{
return BytesRead;
}
BufferLen--;
DestBuffer++;
Address++;
}
}
return 0;
}
LONG
FaExceptionFilter(
struct _EXCEPTION_POINTERS *ExceptionInfo
)
{
ULONG Code = ExceptionInfo->ExceptionRecord->ExceptionCode;
if (Code == E_OUTOFMEMORY || Code == E_INVALIDARG)
{
// Expected exceptions that the analysis code
// can throw to terminate the analysis. Drop
// into the handler.
return EXCEPTION_EXECUTE_HANDLER;
}
// Otherwise this isn't an exception we expected.
// Let it continue on so that it isn't hidden and
// can be debugged.
return EXCEPTION_CONTINUE_SEARCH;
}
BOOL
FaGetSymbol(
ULONG64 Address,
PCHAR Name,
PULONG64 Disp,
ULONG NameSize
)
{
CHAR Buffer[MAX_PATH] = {0};
*Name = 0;
GetSymbol(Address, Name, Disp);
if (*Name == 0)
{
//
// Get the actual Image name from debugger module list
//
ULONG Index;
CHAR ModBuffer[100];
ULONG64 Base;
if (S_OK == g_ExtSymbols->
GetModuleByOffset(Address, 0, &Index, &Base))
{
if (g_ExtSymbols->
GetModuleNames(Index, Base,
ModBuffer, sizeof(ModBuffer), NULL,
NULL, 0, NULL,
NULL, 0, NULL) == S_OK)
{
PCHAR Break = strrchr(ModBuffer, '\\');
if (Break)
{
CopyString(ModBuffer, Break + 1, sizeof(ModBuffer));
}
CopyString(Name, ModBuffer, NameSize);
if (Break = strchr(Name, '.'))
{
*Break = 0;
}
*Disp = Address - Base;
}
}
}
return (*Name != 0);
}
BOOL
FaIsFunctionAddr(
ULONG64 IP,
PSTR FuncName
)
// Check if IP is in the function FuncName
{
static ULONG64 s_LastIP = 0;
static CHAR s_Buffer[MAX_PATH];
CHAR *Scan, *FnIP;
ULONG64 Disp;
if (s_LastIP != IP)
{
// This would make it faster for multiple IsFunctionAddr for same IP
GetSymbol(IP, s_Buffer, &Disp);
s_LastIP = IP;
}
if (Scan = strchr(s_Buffer, '!'))
{
FnIP = Scan + 1;
while (*FnIP == '_')
{
++FnIP;
}
}
else
{
FnIP = &s_Buffer[0];
}
return !strncmp(FnIP, FuncName, strlen(FuncName));
}
BOOL
FaGetFollowupInfo(
IN OPTIONAL ULONG64 Addr,
PCHAR SymbolName,
PCHAR Owner,
ULONG OwnerSize
)
{
EXT_TRIAGE_FOLLOWUP FollowUp = &_EFN_GetTriageFollowupFromSymbol;
DEBUG_TRIAGE_FOLLOWUP_INFO Info;
CHAR Buffer[MAX_PATH];
if (!*SymbolName)
{
ULONG64 Disp;
FaGetSymbol(Addr, Buffer, &Disp, sizeof(Buffer));
SymbolName = Buffer;
}
if (*SymbolName)
{
Info.SizeOfStruct = sizeof(Info);
Info.OwnerName = Owner;
Info.OwnerNameSize = (USHORT)OwnerSize;
if ((*FollowUp)(g_ExtClient, SymbolName, &Info) > TRIAGE_FOLLOWUP_IGNORE)
{
// This is an interesting routine to followup on
return TRUE;
}
}
if (Owner)
{
*Owner=0;
}
return FALSE;
}
HRESULT
FaGetPoolTagFollowup(
PCHAR szPoolTag,
PSTR Followup,
ULONG FollowupSize
)
{
ULONG PoolTag;
DEBUG_POOLTAG_DESCRIPTION TagDesc = {0};
PGET_POOL_TAG_DESCRIPTION pGetTagDesc = NULL;
TagDesc.SizeOfStruct = sizeof(TagDesc);
if (g_ExtControl->
GetExtensionFunction(0, "GetPoolTagDescription",
(FARPROC*)&pGetTagDesc) == S_OK &&
pGetTagDesc)
{
PoolTag = *((PULONG) szPoolTag);
if ((*pGetTagDesc)(PoolTag, &TagDesc) == S_OK)
{
PCHAR Dot;
if (Dot = strchr(TagDesc.Binary, '.'))
{
*Dot = 0;
}
if (TagDesc.Binary[0])
{
if (FaGetFollowupInfo(0, TagDesc.Binary, Followup, FollowupSize))
{
return S_OK;
}
}
if (TagDesc.Owner[0])
{
CopyString(Followup, TagDesc.Owner, FollowupSize);
return S_OK;
}
}
}
return E_FAIL;
}
ULONG64
FaGetImplicitStackOffset(
void
)
{
// IDebugRegisters::GetStackOffset not used since it
// ignores implicit context
ULONG64 Stk = 0;
switch (g_TargetMachine)
{
case IMAGE_FILE_MACHINE_I386:
Stk = GetExpression("@esp");
break;
case IMAGE_FILE_MACHINE_IA64:
Stk = GetExpression("@sp");
break;
case IMAGE_FILE_MACHINE_AMD64:
Stk = GetExpression("@rsp");
break;
}
return Stk;
}
DECLARE_API( analyze )
{
ULONG EventType, ProcId, ThreadId;
BOOL Force = FALSE;
BOOL ForceUser = FALSE;
INIT_API();
if (g_ExtControl->GetLastEventInformation(&EventType, &ProcId, &ThreadId,
NULL, 0, NULL,
NULL, 0, NULL) != S_OK)
{
ExtErr("Unable to get last event information\n");
goto Exit;
}
//
// Check for -f in both cases
//
PCSTR tmpArgs = args;
while (*args)
{
if (*args == '-')
{
++args;
if (*args == 'f')
{
Force = TRUE;
break;
} else if (!strncmp(args, "show",4))
{
Force = TRUE;
} else if (*args == 'u')
{
// could be use for user stack anlysis in k-mode
// ForceUser = TRUE;
}
}
++args;
}
args = tmpArgs;
//
// Call the correct routine to process the event.
//
if ((EventType == DEBUG_EVENT_EXCEPTION) || (Force == TRUE))
{
ULONG DebugType, DebugQual;
if (g_ExtControl->GetDebuggeeType(&DebugType, &DebugQual) != S_OK)
{
ExtErr("Unable to determine debuggee type\n");
Status = E_FAIL;
}
else
{
if (ForceUser)
{
DebugType = DEBUG_CLASS_USER_WINDOWS;
}
switch(DebugType)
{
case DEBUG_CLASS_KERNEL:
//
// For live debug sessions force the symbols to get reloaded
// the first time as we find many sessions where the
// debugger got reconnected and no module list exists.
// This also happens for user mode breaks in kd where the
// module list is wrong.
//
if ((g_TargetQualifier == DEBUG_KERNEL_CONNECTION) &&
(!g_SymbolsReloaded++))
{
g_ExtSymbols->Reload("");
}
Status = AnalyzeBugCheck(args);
break;
case DEBUG_CLASS_USER_WINDOWS:
Status = AnalyzeUserException(args);
break;
case DEBUG_CLASS_UNINITIALIZED:
ExtErr("No debuggee\n");
Status = E_FAIL;
default:
ExtErr("Unknown debuggee type\n");
Status = E_INVALIDARG;
}
}
}
else if (EventType == 0)
{
dprintf("The debuggee is ready to run\n");
Status = S_OK;
}
else
{
Status = E_NOINTERFACE;
}
if (Status == E_NOINTERFACE)
{
g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, ".lastevent",
DEBUG_EXECUTE_DEFAULT);
}
Exit:
EXIT_API();
return Status;
}
HRESULT
_EFN_GetFailureAnalysis(
IN PDEBUG_CLIENT Client,
IN ULONG Flags,
OUT PDEBUG_FAILURE_ANALYSIS* Analysis
)
{
BOOL Enter = (g_ExtClient != Client);
HRESULT Hr;
if (Enter)
{
INIT_API();
}
ULONG DebugType, DebugQual;
if ((Hr = g_ExtControl->GetDebuggeeType(&DebugType,
&DebugQual)) != S_OK)
{
ExtErr("Unable to determine debuggee type\n");
}
else if (DebugType == DEBUG_CLASS_KERNEL)
{
BUGCHECK_ANALYSIS Bc;
*Analysis = (IDebugFailureAnalysis*)BcAnalyze(&Bc, Flags);
Hr = *Analysis ? S_OK : E_OUTOFMEMORY;
}
else if (DebugType == DEBUG_CLASS_USER_WINDOWS)
{
EX_STATE ExState;
*Analysis = (IDebugFailureAnalysis*)UeAnalyze(&ExState, Flags);
Hr = *Analysis ? S_OK : E_OUTOFMEMORY;
}
else
{
Hr = E_INVALIDARG;
}
if (Enter)
{
EXIT_API();
}
return Hr;
}
DECLARE_API( dumpfa )
{
INIT_API();
ULONG64 Address = GetExpression(args);
if (Address)
{
ULONG64 Data;
ULONG64 DataUsed;
ULONG EntrySize;
EntrySize = GetTypeSize("ext!_FA_ENTRY");
InitTypeRead(Address, ext!DebugFailureAnalysis);
Data = ReadField(m_Data);
DataUsed = ReadField(m_DataUsed);
g_ExtControl->Output(1, "DataUsed %x\n", (ULONG)DataUsed);
while (DataUsed > EntrySize)
{
ULONG FullSize;
InitTypeRead(Data, ext!_FA_ENTRY);
g_ExtControl->Output(1,
"Type = %08lx - Size = %x\n",
(ULONG)ReadField(Tag),
ReadField(DataSize));
FullSize = (ULONG)ReadField(FullSize);
Data += FullSize;
DataUsed -= FullSize;
}
}
EXIT_API();
return S_OK;
}
//----------------------------------------------------------------------------
//
// DebugFailureAnalysisImpl.
//
//----------------------------------------------------------------------------
#define FA_ALIGN(Size) (((Size) + 7) & ~7)
#define FA_GROW_BY 4096
#if DBG
#define SCORCH_ENTRY(Entry) \
memset((Entry) + 1, 0xdb, (Entry)->FullSize - sizeof(*(Entry)))
#else
#define SCORCH_ENTRY(Entry)
#endif
#define RAISE_ERROR(Code) RaiseException(Code, 0, 0, NULL)
DebugFailureAnalysis::DebugFailureAnalysis(void)
{
m_Refs = 1;
m_FailureClass = DEBUG_CLASS_UNINITIALIZED;
m_FailureType = DEBUG_FLR_UNKNOWN;
m_FailureCode = 0;
m_Data = NULL;
m_DataLen = 0;
m_DataUsed = 0;
ZeroMemory(PossibleFollowups, sizeof(PossibleFollowups));
BestClassFollowUp = (FlpClasses)0;
}
DebugFailureAnalysis::~DebugFailureAnalysis(void)
{
free(m_Data);
}
STDMETHODIMP
DebugFailureAnalysis::QueryInterface(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
)
{
HRESULT Status;
*Interface = NULL;
Status = S_OK;
if (IsEqualIID(InterfaceId, IID_IUnknown) ||
IsEqualIID(InterfaceId, __uuidof(IDebugFailureAnalysis)))
{
*Interface = (IDebugFailureAnalysis *)this;
AddRef();
}
else
{
Status = E_NOINTERFACE;
}
return Status;
}
STDMETHODIMP_(ULONG)
DebugFailureAnalysis::AddRef(
THIS
)
{
return InterlockedIncrement((PLONG)&m_Refs);
}
STDMETHODIMP_(ULONG)
DebugFailureAnalysis::Release(
THIS
)
{
LONG Refs = InterlockedDecrement((PLONG)&m_Refs);
if (Refs == 0)
{
delete this;
}
return Refs;
}
STDMETHODIMP_(ULONG)
DebugFailureAnalysis::GetFailureClass(void)
{
return m_FailureClass;
}
STDMETHODIMP_(DEBUG_FAILURE_TYPE)
DebugFailureAnalysis::GetFailureType(void)
{
return m_FailureType;
}
STDMETHODIMP_(ULONG)
DebugFailureAnalysis::GetFailureCode(void)
{
return m_FailureCode;
}
STDMETHODIMP_(FA_ENTRY*)
DebugFailureAnalysis::Get(FA_TAG Tag)
{
FA_ENTRY* Entry = NULL;
while ((Entry = NextEntry(Entry)) != NULL)
{
if (Entry->Tag == Tag)
{
return Entry;
}
}
return NULL;
}
STDMETHODIMP_(FA_ENTRY*)
DebugFailureAnalysis::GetNext(FA_ENTRY* Entry, FA_TAG Tag, FA_TAG TagMask)
{
while ((Entry = NextEntry(Entry)) != NULL)
{
if ((Entry->Tag & TagMask) == Tag)
{
return Entry;
}
}
return NULL;
}
STDMETHODIMP_(FA_ENTRY*)
DebugFailureAnalysis::GetString(FA_TAG Tag, PSTR Str, ULONG MaxSize)
{
FA_ENTRY* Entry = Get(Tag);
if (Entry != NULL)
{
if (Entry->DataSize > MaxSize)
{
return NULL;
}
CopyString(Str, FA_ENTRY_DATA(PSTR, Entry),MaxSize);
}
return Entry;
}
STDMETHODIMP_(FA_ENTRY*)
DebugFailureAnalysis::GetBuffer(FA_TAG Tag, PVOID Buf, ULONG Size)
{
FA_ENTRY* Entry = Get(Tag);
if (Entry != NULL)
{
if (Entry->DataSize != Size)
{
return NULL;
}
memcpy(Buf, FA_ENTRY_DATA(PUCHAR, Entry), Size);
}
return Entry;
}
STDMETHODIMP_(FA_ENTRY*)
DebugFailureAnalysis::GetUlong(FA_TAG Tag, PULONG Value)
{
return GetBuffer(Tag, Value, sizeof(*Value));
}
STDMETHODIMP_(FA_ENTRY*)
DebugFailureAnalysis::GetUlong64(FA_TAG Tag, PULONG64 Value)
{
return GetBuffer(Tag, Value, sizeof(*Value));
}
STDMETHODIMP_(FA_ENTRY*)
DebugFailureAnalysis::NextEntry(FA_ENTRY* Entry)
{
if (Entry == NULL)
{
Entry = (FA_ENTRY*)m_Data;
}
else
{
Entry = (FA_ENTRY*)((PUCHAR)Entry + Entry->FullSize);
}
if (ValidEntry(Entry))
{
return Entry;
}
else
{
return NULL;
}
}
FA_ENTRY*
DebugFailureAnalysis::Set(FA_TAG Tag, ULONG Size)
{
FA_ENTRY* Entry;
ULONG FullSize;
// Compute full rounded size.
FullSize = sizeof(FA_ENTRY) + FA_ALIGN(Size);
// Check and see if there's already an entry.
Entry = Get(Tag);
if (Entry != NULL)
{
// If it's already large enough use it and
// pack in remaining data.
if (Entry->FullSize >= FullSize)
{
ULONG Pack = Entry->FullSize - FullSize;
if (Pack > 0)
{
PackData((PUCHAR)Entry + FullSize, Pack);
Entry->FullSize = (USHORT)FullSize;
}
Entry->DataSize = (USHORT)Size;
SCORCH_ENTRY(Entry);
return Entry;
}
// Entry is too small so remove it.
PackData((PUCHAR)Entry, Entry->FullSize);
}
return Add(Tag, Size);
}
FA_ENTRY*
DebugFailureAnalysis::SetString(FA_TAG Tag, PSTR Str)
{
ULONG Size = strlen(Str) + 1;
FA_ENTRY* Entry = Set(Tag, Size);
if (Entry != NULL)
{
memcpy(FA_ENTRY_DATA(PSTR, Entry), Str, Size);
}
return Entry;
}
FA_ENTRY*
DebugFailureAnalysis::SetStrings(FA_TAG Tag, ULONG Count, PSTR* Strs)
{
ULONG i;
ULONG Size = 0;
for (i = 0; i < Count; i++)
{
Size += strlen(Strs[i]) + 1;
}
// Put a double terminator at the very end.
Size++;
FA_ENTRY* Entry = Set(Tag, Size);
if (Entry != NULL)
{
PSTR Data = FA_ENTRY_DATA(PSTR, Entry);
for (i = 0; i < Count; i++)
{
Size = strlen(Strs[i]) + 1;
memcpy(Data, Strs[i], Size);
Data += Size;
}
*Data = 0;
}
return Entry;
}
FA_ENTRY*
DebugFailureAnalysis::SetBuffer(FA_TAG Tag, PVOID Buf, ULONG Size)
{
FA_ENTRY* Entry = Set(Tag, Size);
if (Entry != NULL)
{
memcpy(FA_ENTRY_DATA(PUCHAR, Entry), Buf, Size);
}
return Entry;
}
FA_ENTRY*
DebugFailureAnalysis::Add(FA_TAG Tag, ULONG Size)
{
// Compute full rounded size.
ULONG FullSize = sizeof(FA_ENTRY) + FA_ALIGN(Size);
FA_ENTRY* Entry = AllocateEntry(FullSize);
if (Entry != NULL)
{
Entry->Tag = Tag;
Entry->FullSize = (USHORT)FullSize;
Entry->DataSize = (USHORT)Size;
SCORCH_ENTRY(Entry);
}
return Entry;
}
ULONG
DebugFailureAnalysis::Delete(FA_TAG Tag, FA_TAG TagMask)
{
ULONG Deleted = 0;
FA_ENTRY* Entry = NextEntry(NULL);
while (Entry != NULL)
{
if ((Entry->Tag & TagMask) == Tag)
{
PackData((PUCHAR)Entry, Entry->FullSize);
Deleted++;
// Check and see if we packed away the last entry.
if (!ValidEntry(Entry))
{
break;
}
}
else
{
Entry = NextEntry(Entry);
}
}
return Deleted;
}
void
DebugFailureAnalysis::Empty(void)
{
// Reset used to just the header.
m_DataUsed = 0;
}
FA_ENTRY*
DebugFailureAnalysis::AllocateEntry(ULONG FullSize)
{
// Sizes must fit in USHORTs. This shouldn't be
// a big problem since analyses shouldn't have
// huge data items in them.
if (FullSize > 0xffff)
{
RAISE_ERROR(E_INVALIDARG);
return NULL;
}
if (m_DataUsed + FullSize > m_DataLen)
{
ULONG NewLen = m_DataLen;
do
{
NewLen += FA_GROW_BY;
}
while (m_DataUsed + FullSize > NewLen);
PUCHAR NewData = (PUCHAR)realloc(m_Data, NewLen);
if (NewData == NULL)
{
RAISE_ERROR(E_OUTOFMEMORY);
return NULL;
}
m_Data = NewData;
m_DataLen = NewLen;
}
FA_ENTRY* Entry = (FA_ENTRY*)(m_Data + m_DataUsed);
m_DataUsed += FullSize;
return Entry;
}
void
DebugFailureAnalysis::DbFindBucketInfo(
void
)
{
SolutionDatabaseHandler *Db;
CHAR Solution[SOLUTION_TEXT_SIZE];
CHAR SolOSVer[OS_VER_SIZE];
ULONG RaidBug;
FA_ENTRY* BucketEntry;
FA_ENTRY* GBucketEntry;
FA_ENTRY* DriverNameEntry = NULL;
FA_ENTRY* TimeStampEntry = NULL;
static CHAR SolvedBucket[MAX_PATH] = {0}, SolvedgBucket[MAX_PATH] = {0};
static CHAR SolutionString[MAX_PATH] = {0};
static ULONG SolutionId = 0, SolutionType, SolutionIdgBucket = 0;
if (GetProcessingFlags() & FAILURE_ANALYSIS_NO_DB_LOOKUP)
{
return;
}
if (!(BucketEntry = Get(DEBUG_FLR_BUCKET_ID)))
{
return;
}
if (!strcmp(SolvedBucket, FA_ENTRY_DATA(PCHAR, BucketEntry)))
{
if (SolutionType != CiSolUnsolved)
{
SetString(DEBUG_FLR_INTERNAL_SOLUTION_TEXT, SolutionString);
}
SetUlong(DEBUG_FLR_SOLUTION_ID, SolutionId);
SetUlong(DEBUG_FLR_SOLUTION_TYPE, SolutionType);
// Generic bucket
if (BucketEntry = Get(DEBUG_FLR_DEFAULT_BUCKET_ID))
{
if (!strcmp(SolvedgBucket, FA_ENTRY_DATA(PCHAR, BucketEntry)))
{
SetUlong(DEBUG_FLR_DEFAULT_SOLUTION_ID, SolutionIdgBucket);
}
}
return;
}
// if (!(DriverNameEntry = Get(DEBUG_FLR_IMAGE_NAME)) ||
// !(TimeStampEntry = Get(DEBUG_FLR_IMAGE_TIMESTAMP)))
// {
// return;
// }
HRESULT Hr;
BOOL SolDbInitialized = g_SolDb != NULL;
if (!SolDbInitialized)
{
if (FAILED(Hr = InitializeDatabaseHandlers(g_ExtControl, 4)))
{
// dprintf("Database initialize failed %lx\n", Hr);
return;
}
SolDbInitialized = TRUE;
}
if (g_SolDb->ConnectToDataBase())
{
if (GBucketEntry = Get(DEBUG_FLR_DEFAULT_BUCKET_ID))
{
CopyString(SolvedgBucket, FA_ENTRY_DATA(PCHAR, GBucketEntry), sizeof(SolvedgBucket));
}
//
// List crashes for the same bucket
//
CopyString(SolvedBucket, FA_ENTRY_DATA(PCHAR, BucketEntry), sizeof(SolvedBucket));
if (SUCCEEDED(Hr = g_SolDb->GetSolutionFromDB(FA_ENTRY_DATA(PCHAR, BucketEntry),
SolvedgBucket, NULL, 0,
// FA_ENTRY_DATA(PCHAR, DriverNameEntry),
// (ULONG)(*FA_ENTRY_DATA(PULONG64, TimeStampEntry)),
0, Solution, SOLUTION_TEXT_SIZE,
&SolutionId, &SolutionType,
&SolutionIdgBucket)))
{
if (SolutionId != 0)
{
SetString(DEBUG_FLR_INTERNAL_SOLUTION_TEXT, Solution);
CopyString(SolutionString, Solution, sizeof(SolutionString));
} else
{
SolutionId = -1; // unsolved
SolutionType = 0;
}
if (SolutionIdgBucket == 0)
{
SolutionIdgBucket = -1; // unsolved
}
SetUlong(DEBUG_FLR_SOLUTION_ID, SolutionId);
SetUlong(DEBUG_FLR_SOLUTION_TYPE, SolutionType);
SetUlong(DEBUG_FLR_DEFAULT_SOLUTION_ID, SolutionIdgBucket);
} else
{
// We did not succesfully look up in DB
SolvedgBucket[0] = '\0';
SolvedBucket[0] = '\0';
}
#if 0
if (SolOSVer[0] != '\0')
{
SetString(DEBUG_FLR_FIXED_IN_OSVERSION, SolOSVer);
}
}
if (Db->FindRaidBug(FA_ENTRY_DATA(PCHAR, Entry),
&RaidBug) == S_OK)
{
SetUlong64(DEBUG_FLR_INTERNAL_RAID_BUG, RaidBug);
}
#endif
}
;
if (SolDbInitialized)
{
UnInitializeDatabaseHandlers(FALSE);
}
return;
}
FLR_LOOKUP_TABLE FlrLookupTable[] = {
DEBUG_FLR_RESERVED , "RESERVED"
,DEBUG_FLR_DRIVER_OBJECT , "DRIVER_OBJECT"
,DEBUG_FLR_DEVICE_OBJECT , "DEVICE_OBJECT"
,DEBUG_FLR_INVALID_PFN , "INVALID_PFN"
,DEBUG_FLR_WORKER_ROUTINE , "WORKER_ROUTINE"
,DEBUG_FLR_WORK_ITEM , "WORK_ITEM"
,DEBUG_FLR_INVALID_DPC_FOUND , "INVALID_DPC_FOUND"
,DEBUG_FLR_PROCESS_OBJECT , "PROCESS_OBJECT"
,DEBUG_FLR_FAILED_INSTRUCTION_ADDRESS , "FAILED_INSTRUCTION_ADDRESS"
,DEBUG_FLR_LAST_CONTROL_TRANSFER , "LAST_CONTROL_TRANSFER"
,DEBUG_FLR_ACPI_EXTENSION , "ACPI_EXTENSION"
,DEBUG_FLR_ACPI_OBJECT , "ACPI_OBJECT"
,DEBUG_FLR_PROCESS_NAME , "PROCESS_NAME"
,DEBUG_FLR_READ_ADDRESS , "READ_ADDRESS"
,DEBUG_FLR_WRITE_ADDRESS , "WRITE_ADDRESS"
,DEBUG_FLR_CRITICAL_SECTION , "CRITICAL_SECTION"
,DEBUG_FLR_BAD_HANDLE , "BAD_HANDLE"
,DEBUG_FLR_INVALID_HEAP_ADDRESS , "INVALID_HEAP_ADDRESS"
,DEBUG_FLR_IRP_ADDRESS , "IRP_ADDRESS"
,DEBUG_FLR_IRP_MAJOR_FN , "IRP_MAJOR_FN"
,DEBUG_FLR_IRP_MINOR_FN , "IRP_MINOR_FN"
,DEBUG_FLR_IRP_CANCEL_ROUTINE , "IRP_CANCEL_ROUTINE"
,DEBUG_FLR_IOSB_ADDRESS , "IOSB_ADDRESS"
,DEBUG_FLR_INVALID_USEREVENT , "INVALID_USEREVENT"
,DEBUG_FLR_PREVIOUS_MODE , "PREVIOUS_MODE"
,DEBUG_FLR_CURRENT_IRQL , "CURRENT_IRQL"
,DEBUG_FLR_PREVIOUS_IRQL , "PREVIOUS_IRQL"
,DEBUG_FLR_REQUESTED_IRQL , "REQUESTED_IRQL"
,DEBUG_FLR_ASSERT_DATA , "ASSERT_DATA"
,DEBUG_FLR_ASSERT_FILE , "ASSERT_FILE_LOCATION"
,DEBUG_FLR_EXCEPTION_PARAMETER1 , "EXCEPTION_PARAMETER1"
,DEBUG_FLR_EXCEPTION_PARAMETER2 , "EXCEPTION_PARAMETER2"
,DEBUG_FLR_EXCEPTION_PARAMETER3 , "EXCEPTION_PARAMETER3"
,DEBUG_FLR_EXCEPTION_PARAMETER4 , "EXCEPTION_PARAMETER4"
,DEBUG_FLR_EXCEPTION_RECORD , "EXCEPTION_RECORD"
,DEBUG_FLR_POOL_ADDRESS , "POOL_ADDRESS"
,DEBUG_FLR_CORRUPTING_POOL_ADDRESS , "CORRUPTING_POOL_ADDRESS"
,DEBUG_FLR_CORRUPTING_POOL_TAG , "CORRUPTING_POOL_TAG"
,DEBUG_FLR_FREED_POOL_TAG , "FREED_POOL_TAG"
,DEBUG_FLR_SPECIAL_POOL_CORRUPTION_TYPE , "SPECIAL_POOL_CORRUPTION_TYPE"
,DEBUG_FLR_FILE_ID , "FILE_ID"
,DEBUG_FLR_FILE_LINE , "FILE_LINE"
,DEBUG_FLR_BUGCHECK_STR , "BUGCHECK_STR"
,DEBUG_FLR_BUGCHECK_SPECIFIER , "BUGCHECK_SPECIFIER"
,DEBUG_FLR_DRIVER_VERIFIER_IO_VIOLATION_TYPE, "DRIVER_VERIFIER_IO_VIOLATION_TYPE"
,DEBUG_FLR_EXCEPTION_CODE , "EXCEPTION_CODE"
,DEBUG_FLR_STATUS_CODE , "STATUS_CODE"
,DEBUG_FLR_IOCONTROL_CODE , "IOCONTROL_CODE"
,DEBUG_FLR_MM_INTERNAL_CODE , "MM_INTERNAL_CODE"
,DEBUG_FLR_DRVPOWERSTATE_SUBCODE , "DRVPOWERSTATE_SUBCODE"
,DEBUG_FLR_CORRUPT_MODULE_LIST , "CORRUPT_MODULE_LIST"
,DEBUG_FLR_BAD_STACK , "BAD_STACK"
,DEBUG_FLR_ZEROED_STACK , "ZEROED_STACK"
,DEBUG_FLR_WRONG_SYMBOLS , "WRONG_SYMBOLS"
,DEBUG_FLR_FOLLOWUP_DRIVER_ONLY , "FOLLOWUP_DRIVER_ONLY"
,DEBUG_FLR_CPU_OVERCLOCKED , "CPU_OVERCLOCKED"
,DEBUG_FLR_MANUAL_BREAKIN , "MANUAL_BREAKIN"
,DEBUG_FLR_POSSIBLE_INVALID_CONTROL_TRANSFER, "POSSIBLE_INVALID_CONTROL_TRANSFER"
,DEBUG_FLR_POISONED_TB , "POISONED_TB"
,DEBUG_FLR_UNKNOWN_MODULE , "UNKNOWN_MODULE"
,DEBUG_FLR_ANALYZAABLE_POOL_CORRUPTION , "ANALYZAABLE_POOL_CORRUPTION"
,DEBUG_FLR_SINGLE_BIT_ERROR , "SINGLE_BIT_ERROR"
,DEBUG_FLR_TWO_BIT_ERROR , "TWO_BIT_ERROR"
,DEBUG_FLR_INVALID_KERNEL_CONTEXT , "INVALID_KERNEL_CONTEXT"
,DEBUG_FLR_DISK_HARDWARE_ERROR , "DISK_HARDWARE_ERROR"
,DEBUG_FLR_POOL_CORRUPTOR , "POOL_CORRUPTOR"
,DEBUG_FLR_MEMORY_CORRUPTOR , "MEMORY_CORRUPTOR"
,DEBUG_FLR_UNALIGNED_STACK_POINTER , "UNALIGNED_STACK_POINTER"
,DEBUG_FLR_OLD_OS_VERSION , "OLD_OS_VERSION"
,DEBUG_FLR_BUGCHECKING_DRIVER , "BUGCHECKING_DRIVER"
,DEBUG_FLR_BUCKET_ID , "BUCKET_ID"
,DEBUG_FLR_IMAGE_NAME , "IMAGE_NAME"
,DEBUG_FLR_SYMBOL_NAME , "SYMBOL_NAME"
,DEBUG_FLR_FOLLOWUP_NAME , "FOLLOWUP_NAME"
,DEBUG_FLR_STACK_COMMAND , "STACK_COMMAND"
,DEBUG_FLR_STACK_TEXT , "STACK_TEXT"
,DEBUG_FLR_INTERNAL_SOLUTION_TEXT , "INTERNAL_SOLUTION_TEXT"
,DEBUG_FLR_MODULE_NAME , "MODULE_NAME"
,DEBUG_FLR_INTERNAL_RAID_BUG , "INTERNAL_RAID_BUG"
,DEBUG_FLR_FIXED_IN_OSVERSION , "FIXED_IN_OSVERSION"
,DEBUG_FLR_DEFAULT_BUCKET_ID , "DEFAULT_BUCKET_ID"
,DEBUG_FLR_FAULTING_IP , "FAULTING_IP"
,DEBUG_FLR_FAULTING_MODULE , "FAULTING_MODULE"
,DEBUG_FLR_IMAGE_TIMESTAMP , "DEBUG_FLR_IMAGE_TIMESTAMP"
,DEBUG_FLR_FOLLOWUP_IP , "FOLLOWUP_IP"
,DEBUG_FLR_FAULTING_THREAD , "FAULTING_THREAD"
,DEBUG_FLR_CONTEXT , "CONTEXT"
,DEBUG_FLR_TRAP_FRAME , "TRAP_FRAME"
,DEBUG_FLR_TSS , "TSS"
,DEBUG_FLR_SHOW_ERRORLOG , "ERROR_LOG"
,DEBUG_FLR_MASK_ALL , "MASK_ALL"
// Zero entry Must be last;
,DEBUG_FLR_INVALID , "INVALID"
};
void
DebugFailureAnalysis::OutputEntryParam(DEBUG_FLR_PARAM_TYPE Type)
{
FA_ENTRY *Entry = Get(Type);
if (Entry)
{
OutputEntry(Entry);
}
}
void
DebugFailureAnalysis::OutputEntry(FA_ENTRY* Entry)
{
CHAR Buffer[MAX_PATH];
CHAR Module[MAX_PATH];
ULONG64 Base;
ULONG64 Address;
ULONG OutCtl;
ULONG i = 0;
OutCtl = DEBUG_OUTCTL_AMBIENT;
switch(Entry->Tag)
{
// These are just tags - don't print out
case DEBUG_FLR_CORRUPT_MODULE_LIST:
case DEBUG_FLR_BAD_STACK:
case DEBUG_FLR_ZEROED_STACK:
case DEBUG_FLR_WRONG_SYMBOLS:
case DEBUG_FLR_FOLLOWUP_DRIVER_ONLY:
case DEBUG_FLR_UNKNOWN_MODULE:
case DEBUG_FLR_ANALYZAABLE_POOL_CORRUPTION:
case DEBUG_FLR_INVALID_KERNEL_CONTEXT:
case DEBUG_FLR_SOLUTION_TYPE:
case DEBUG_FLR_MANUAL_BREAKIN:
// soluion ids from DB
case DEBUG_FLR_SOLUTION_ID:
case DEBUG_FLR_DEFAULT_SOLUTION_ID:
// Field folded into others
case DEBUG_FLR_BUGCHECK_SPECIFIER:
return;
// Marged with other output
return;
}
//
// Find the entry in the description table
//
while(FlrLookupTable[i].Data &&
Entry->Tag != FlrLookupTable[i].Data)
{
i++;
}
dprintf("\n%s: ", FlrLookupTable[i].String);
switch(Entry->Tag)
{
// Notification to user
case DEBUG_FLR_DISK_HARDWARE_ERROR:
// FlrLookupTable value has already been printed
dprintf("There was error with disk hardware\n");
break;
// Strings:
case DEBUG_FLR_ASSERT_DATA:
case DEBUG_FLR_ASSERT_FILE:
case DEBUG_FLR_BUCKET_ID:
case DEBUG_FLR_DEFAULT_BUCKET_ID:
case DEBUG_FLR_STACK_TEXT:
case DEBUG_FLR_STACK_COMMAND:
case DEBUG_FLR_INTERNAL_SOLUTION_TEXT:
case DEBUG_FLR_FIXED_IN_OSVERSION:
case DEBUG_FLR_BUGCHECK_STR:
case DEBUG_FLR_IMAGE_NAME:
case DEBUG_FLR_MODULE_NAME:
case DEBUG_FLR_PROCESS_NAME:
case DEBUG_FLR_FOLLOWUP_NAME:
case DEBUG_FLR_POOL_CORRUPTOR:
case DEBUG_FLR_MEMORY_CORRUPTOR:
case DEBUG_FLR_BUGCHECKING_DRIVER:
case DEBUG_FLR_SYMBOL_NAME:
case DEBUG_FLR_CORRUPTING_POOL_TAG:
case DEBUG_FLR_FREED_POOL_TAG:
dprintf(" %s\n", FA_ENTRY_DATA(PCHAR, Entry));
break;
// DWORDs:
case DEBUG_FLR_PREVIOUS_IRQL:
case DEBUG_FLR_CURRENT_IRQL:
case DEBUG_FLR_MM_INTERNAL_CODE:
case DEBUG_FLR_SPECIAL_POOL_CORRUPTION_TYPE:
case DEBUG_FLR_PREVIOUS_MODE:
case DEBUG_FLR_IMAGE_TIMESTAMP:
case DEBUG_FLR_SINGLE_BIT_ERROR:
case DEBUG_FLR_TWO_BIT_ERROR:
dprintf(" %lx\n", *FA_ENTRY_DATA(PULONG64, Entry));
break;
// DWORDs:
case DEBUG_FLR_INTERNAL_RAID_BUG:
case DEBUG_FLR_OLD_OS_VERSION:
dprintf(" %d\n", *FA_ENTRY_DATA(PULONG64, Entry));
break;
// Pointers
case DEBUG_FLR_PROCESS_OBJECT:
case DEBUG_FLR_DEVICE_OBJECT:
case DEBUG_FLR_DRIVER_OBJECT:
case DEBUG_FLR_ACPI_OBJECT:
case DEBUG_FLR_IRP_ADDRESS:
case DEBUG_FLR_EXCEPTION_PARAMETER1:
case DEBUG_FLR_EXCEPTION_PARAMETER2:
case DEBUG_FLR_FAULTING_THREAD:
case DEBUG_FLR_WORK_ITEM:
dprintf(" %p\n", *FA_ENTRY_DATA(PULONG64, Entry));
break;
// Pointers to code
case DEBUG_FLR_WORKER_ROUTINE:
case DEBUG_FLR_IRP_CANCEL_ROUTINE:
case DEBUG_FLR_FAILED_INSTRUCTION_ADDRESS:
case DEBUG_FLR_FAULTING_IP:
case DEBUG_FLR_FOLLOWUP_IP:
case DEBUG_FLR_FAULTING_MODULE:
FaGetSymbol(*FA_ENTRY_DATA(PULONG64, Entry), Buffer, &Address, sizeof(Buffer));
dprintf("\n%s+%I64lx\n", Buffer, Address);
g_ExtControl->OutputDisassemblyLines(OutCtl, 0, 1,
*FA_ENTRY_DATA(PULONG64, Entry),
0, NULL, NULL, NULL, NULL);
break;
// Address description
case DEBUG_FLR_READ_ADDRESS:
case DEBUG_FLR_WRITE_ADDRESS:
case DEBUG_FLR_POOL_ADDRESS:
case DEBUG_FLR_CORRUPTING_POOL_ADDRESS:
{
PCSTR Desc = DescribeAddress(*FA_ENTRY_DATA(PULONG64, Entry));
if (!Desc)
{
Desc = "";
}
dprintf(" %p %s\n", *FA_ENTRY_DATA(PULONG64, Entry), Desc);
break;
}
case DEBUG_FLR_EXCEPTION_CODE:
case DEBUG_FLR_STATUS_CODE:
{
DEBUG_DECODE_ERROR Err;
Err.Code = (ULONG) *FA_ENTRY_DATA(PULONG, Entry);
Err.TreatAsStatus = (Entry->Tag == DEBUG_FLR_STATUS_CODE);
// dprintf(" %lx", *FA_ENTRY_DATA(PULONG, Entry));
DecodeErrorForMessage( &Err );
if (!Err.TreatAsStatus)
{
dprintf("(%s) %#x (%u) - %s\n",
Err.Source, Err.Code, Err.Code, Err.Message);
}
else
{
dprintf("(%s) %#x - %s\n",
Err.Source, Err.Code, Err.Message);
}
break;
}
case DEBUG_FLR_CPU_OVERCLOCKED:
dprintf(" *** Machine was determined to be overclocked !\n");
break;
case DEBUG_FLR_ACPI_EXTENSION:
dprintf(" %p -- (!acpikd.acpiext %p)\n", *FA_ENTRY_DATA(PULONG64, Entry),
*FA_ENTRY_DATA(PULONG64, Entry));
sprintf(Buffer, "!acpikd.acpiext %I64lx", *FA_ENTRY_DATA(PULONG64, Entry));
g_ExtControl->Execute(OutCtl, Buffer, DEBUG_EXECUTE_DEFAULT);
break;
case DEBUG_FLR_TRAP_FRAME:
dprintf(" %p -- (.trap %I64lx)\n", *FA_ENTRY_DATA(PULONG64, Entry),
*FA_ENTRY_DATA(PULONG64, Entry));
sprintf(Buffer, ".trap %I64lx", *FA_ENTRY_DATA(PULONG64, Entry));
g_ExtControl->Execute(OutCtl, Buffer, DEBUG_EXECUTE_DEFAULT);
g_ExtControl->Execute(OutCtl, ".trap", DEBUG_EXECUTE_DEFAULT);
break;
case DEBUG_FLR_CONTEXT:
dprintf(" %p -- (.cxr %I64lx)\n", *FA_ENTRY_DATA(PULONG64, Entry),
*FA_ENTRY_DATA(PULONG64, Entry));
sprintf(Buffer, ".cxr %I64lx", *FA_ENTRY_DATA(PULONG64, Entry));
g_ExtControl->Execute(OutCtl, Buffer, DEBUG_EXECUTE_DEFAULT);
g_ExtControl->Execute(OutCtl, ".cxr", DEBUG_EXECUTE_DEFAULT);
break;
case DEBUG_FLR_EXCEPTION_RECORD:
dprintf(" %p -- (.exr %I64lx)\n", *FA_ENTRY_DATA(PULONG64, Entry),
*FA_ENTRY_DATA(PULONG64, Entry));
sprintf(Buffer, ".exr %I64lx", *FA_ENTRY_DATA(PULONG64, Entry));
g_ExtControl->Execute(OutCtl, Buffer, DEBUG_EXECUTE_DEFAULT);
break;
case DEBUG_FLR_TSS:
dprintf(" %p -- (.tss %I64lx)\n", *FA_ENTRY_DATA(PULONG64, Entry),
*FA_ENTRY_DATA(PULONG64, Entry));
sprintf(Buffer, ".tss %I64lx", *FA_ENTRY_DATA(PULONG64, Entry));
g_ExtControl->Execute(OutCtl, Buffer, DEBUG_EXECUTE_DEFAULT);
g_ExtControl->Execute(OutCtl, ".trap", DEBUG_EXECUTE_DEFAULT);
break;
case DEBUG_FLR_LAST_CONTROL_TRANSFER:
case DEBUG_FLR_POSSIBLE_INVALID_CONTROL_TRANSFER:
dprintf(" from %p to %p\n",
FA_ENTRY_DATA(PULONG64, Entry)[0],
FA_ENTRY_DATA(PULONG64, Entry)[1]);
break;
case DEBUG_FLR_CRITICAL_SECTION:
dprintf("%p (!cs -s %p)\n",
*FA_ENTRY_DATA(PULONG64, Entry),
*FA_ENTRY_DATA(PULONG64, Entry));
break;
case DEBUG_FLR_BAD_HANDLE:
dprintf("%p (!htrace %p)\n",
*FA_ENTRY_DATA(PULONG64, Entry),
*FA_ENTRY_DATA(PULONG64, Entry));
break;
case DEBUG_FLR_INVALID_HEAP_ADDRESS:
dprintf("%p (!heap -p -a %p)\n",
*FA_ENTRY_DATA(PULONG64, Entry),
*FA_ENTRY_DATA(PULONG64, Entry));
break;
case DEBUG_FLR_SHOW_ERRORLOG:
g_ExtControl->Execute(OutCtl, "!errlog", DEBUG_EXECUTE_DEFAULT);
break;
default:
dprintf(" *** Unknown TAG in analysis list %lx\n\n",
Entry->Tag);
return;
}
return;
}
void
DebugFailureAnalysis::Output()
{
ULONG RetVal;
FA_ENTRY* Entry;
BOOL Verbose = (GetProcessingFlags() & FAILURE_ANALYSIS_VERBOSE);
//
// In verbose mode, show everything that we figured out during analysis
//
if (Verbose)
{
Entry = NULL;
while (Entry = NextEntry(Entry))
{
OutputEntry(Entry);
}
}
if (Get(DEBUG_FLR_POISONED_TB))
{
dprintf("*** WARNING: nt!MmPoisonedTb is non-zero:\n"
"*** The machine has been manipulated using the kernel debugger.\n"
"*** MachineOwner should be contacted first\n\n\n");
}
PCHAR SolInOS = NULL;
if (Entry = Get(DEBUG_FLR_FIXED_IN_OSVERSION))
{
SolInOS = FA_ENTRY_DATA(PCHAR, Entry);
}
PCHAR Solution = NULL;
if (Entry = Get(DEBUG_FLR_INTERNAL_SOLUTION_TEXT))
{
Solution = FA_ENTRY_DATA(PCHAR, Entry);
}
//
// Print the bad driver if we are not in verbose mode - otherwise
// is is printed out using the params
//
if (!Verbose && !Solution)
{
if (Entry = Get(DEBUG_FLR_CORRUPTING_POOL_TAG))
{
dprintf("Probably pool corruption caused by Tag: %s\n",
FA_ENTRY_DATA(PCHAR, Entry));
}
else
{
PCHAR DriverName = NULL;
PCHAR SymName = NULL;
if (Entry = Get(DEBUG_FLR_IMAGE_NAME))
{
DriverName = FA_ENTRY_DATA(PCHAR, Entry);
}
if (Entry = Get(DEBUG_FLR_SYMBOL_NAME))
{
SymName = FA_ENTRY_DATA(PCHAR, Entry);
}
if (DriverName || SymName)
{
dprintf("Probably caused by : ");
if (SymName && DriverName)
{
dprintf("%s ( %s )\n", DriverName, SymName);
}
else if (SymName)
{
dprintf("%s\n", SymName);
}
else
{
dprintf("%s\n", DriverName);
}
}
}
}
if (Verbose || !Solution)
{
PCHAR FollowupAlias = NULL;
//
// Print what the user should do:
// - Followup person
// - Solution text if there is one.
//
if (Entry = Get(DEBUG_FLR_FOLLOWUP_NAME))
{
dprintf("\nFollowup: %s\n", FA_ENTRY_DATA(PCHAR, Entry));
}
else
{
dprintf(" *** Followup info cannot be found !!! Please contact \"Debugger Team\"\n");
}
dprintf("---------\n");
if (Entry = Get(DEBUG_FLR_POSSIBLE_INVALID_CONTROL_TRANSFER))
{
CHAR Buffer[MAX_PATH];
ULONG64 Address;
FaGetSymbol(FA_ENTRY_DATA(PULONG64, Entry)[0], Buffer, &Address, sizeof(Buffer));
dprintf(" *** Possible invalid call from %p ( %s+0x%1p )\n",
FA_ENTRY_DATA(PULONG64, Entry)[0],
Buffer,
Address);
FaGetSymbol(FA_ENTRY_DATA(PULONG64, Entry)[1], Buffer, &Address, sizeof(Buffer));
dprintf(" *** Expected target %p ( %s+0x%1p )\n",
FA_ENTRY_DATA(PULONG64, Entry)[1],
Buffer,
Address);
}
dprintf("\n");
}
if (Entry = Get(DEBUG_FLR_INTERNAL_RAID_BUG))
{
dprintf("Raid bug for this failure: %d\n\n",
*FA_ENTRY_DATA(PULONG64, Entry));
}
if (Solution)
{
dprintf(" This problem has a known fix.\n"
" Please connect to the following URL for details:\n"
" ------------------------------------------------\n"
" %s\n\n",
Solution);
}
if (SolInOS)
{
dprintf(" This has been fixed in : %s\n", SolInOS);
}
}
LPSTR
TimeToStr(
ULONG TimeDateStamp,
BOOL DateOnly
)
{
LPSTR TimeDateStr; // pointer to static cruntime buffer.
static char datebuffer[100];
tm * pTime;
time_t TDStamp = (time_t) (LONG) TimeDateStamp;
// Handle invalid \ page out timestamps, since ctime blows up on
// this number
if ((TimeDateStamp == 0) || (TimeDateStamp == -1))
{
return "unknown_date";
}
else if (DateOnly)
{
pTime = localtime(&TDStamp);
sprintf(datebuffer, "%d_%d_%d",
pTime->tm_mon + 1, pTime->tm_mday, pTime->tm_year + 1900);
return datebuffer;
}
else
{
// TimeDateStamp is always a 32 bit quantity on the target,
// and we need to sign extend for 64 bit host since time_t
// has been extended to 64 bits.
TDStamp = (time_t) (LONG) TimeDateStamp;
TimeDateStr = ctime((time_t *)&TDStamp);
if (TimeDateStr)
{
TimeDateStr[strlen(TimeDateStr) - 1] = 0;
}
else
{
TimeDateStr = "***** Invalid";
}
return TimeDateStr;
}
}
void
DebugFailureAnalysis::GenerateBucketId(void)
{
ULONG LengthUsed = 0;
CHAR BucketId[MAX_PATH] = {0};
PSTR BucketPtr = BucketId;
PSTR Str;
FA_ENTRY* Entry;
FA_ENTRY* NameEntry;
FA_ENTRY* ModuleEntry;
ULONG ModuleTimestamp = 0;
CHAR Command[MAX_PATH] = {0};
CHAR followup[MAX_PATH];
//
// Set the final command string
//
if (Entry = Get(DEBUG_FLR_STACK_COMMAND))
{
CopyString(Command, FA_ENTRY_DATA(PSTR, Entry), sizeof(Command) - 5);
strcat(Command, " ; ");
}
strcat(Command, "kb");
SetString(DEBUG_FLR_STACK_COMMAND, Command);
if (Get(DEBUG_FLR_OLD_OS_VERSION))
{
SetString(DEBUG_FLR_DEFAULT_BUCKET_ID, "OLD_OS");
}
//
// Don't change the bucket ID for these two things as the debugger code
// to detect them is not 100% reliable.
//
//if (Get(DEBUG_FLR_CPU_OVERCLOCKED))
//{
// SetString(DEBUG_FLR_BUCKET_ID, "CPU_OVERCLOCKED");
// return;
//}
//
//
// If the faulting module exists:
// Get the module timestamp of the faulting module.
// Check if it is an old driver.
//
ModuleEntry = Get(DEBUG_FLR_MODULE_NAME);
if (ModuleEntry)
{
ULONG Index;
ULONG64 Base;
DEBUG_MODULE_PARAMETERS Params;
g_ExtSymbols->GetModuleByModuleName(FA_ENTRY_DATA(PCHAR, ModuleEntry),
0, &Index, &Base);
if (Base &&
g_ExtSymbols->GetModuleParameters(1, &Base, Index, &Params) == S_OK)
{
ModuleTimestamp = Params.TimeDateStamp;
}
}
NameEntry = Get(DEBUG_FLR_IMAGE_NAME);
if (NameEntry)
{
if (!strcmp(FA_ENTRY_DATA(PCHAR, NameEntry), "Unknown_Image"))
{
NameEntry = NULL;
}
}
if (ModuleTimestamp && NameEntry)
{
PCHAR String;
ULONG LookupTimestamp;
String = g_pTriager->GetFollowupStr("OldImages",
FA_ENTRY_DATA(PCHAR, NameEntry));
if (String)
{
LookupTimestamp = strtol(String, NULL, 16);
//
// If the driver is known to be bad, just use driver name
//
if (LookupTimestamp > ModuleTimestamp)
{
if (FaGetFollowupInfo(NULL,
FA_ENTRY_DATA(PCHAR, ModuleEntry),
followup,
sizeof(followup)))
{
SetString(DEBUG_FLR_FOLLOWUP_NAME, followup);
}
//sprintf(BucketPtr, "OLD_IMAGE_%s_TS_%lX",
// FA_ENTRY_DATA(PCHAR, NameEntry),
// ModuleTimestamp);
PrintString(BucketPtr, sizeof(BucketId) - LengthUsed, "OLD_IMAGE_%s",
FA_ENTRY_DATA(PCHAR, NameEntry));
SetString(DEBUG_FLR_BUCKET_ID, BucketId);
return;
}
}
}
if (Entry = Get(DEBUG_FLR_POSSIBLE_INVALID_CONTROL_TRANSFER))
{
if (Get(DEBUG_FLR_SINGLE_BIT_ERROR))
{
SetString(DEBUG_FLR_BUCKET_ID, "SINGLE_BIT_CPU_CALL_ERROR");
}
else if (Get(DEBUG_FLR_TWO_BIT_ERROR))
{
SetString(DEBUG_FLR_BUCKET_ID, "TWO_BIT_CPU_CALL_ERROR");
}
else
{
SetString(DEBUG_FLR_BUCKET_ID, "CPU_CALL_ERROR");
}
return;
}
if (Entry = Get(DEBUG_FLR_MANUAL_BREAKIN))
{
SetString(DEBUG_FLR_BUCKET_ID, "MANUAL_BREAKIN");
SetString(DEBUG_FLR_FOLLOWUP_NAME, "MachineOwner");
return;
}
if (!PossibleFollowups[FlpSpecific].Owner[0])
{
BOOL bPoolTag = FALSE;
if (Entry = Get(DEBUG_FLR_BUGCHECKING_DRIVER))
{
PrintString(BucketPtr, sizeof(BucketId) - LengthUsed,
"%s_BUGCHECKING_DRIVER_%s",
FA_ENTRY_DATA(PCHAR, Get(DEBUG_FLR_BUGCHECK_STR)),
FA_ENTRY_DATA(PCHAR, Entry));
}
else if (Entry = Get(DEBUG_FLR_MEMORY_CORRUPTOR))
{
PrintString(BucketPtr, sizeof(BucketId) - LengthUsed,
"MEMORY_CORRUPTION_%s",
FA_ENTRY_DATA(PCHAR, Entry));
}
else if (Entry = Get(DEBUG_FLR_POOL_CORRUPTOR))
{
PrintString(BucketPtr, sizeof(BucketId) - LengthUsed,
"POOL_CORRUPTION_%s",
FA_ENTRY_DATA(PCHAR, Entry));
}
else if (Entry = Get(DEBUG_FLR_CORRUPTING_POOL_TAG))
{
PrintString(BucketPtr, sizeof(BucketId) - LengthUsed,
"CORRUPTING_POOLTAG_%s",
FA_ENTRY_DATA(PCHAR, Entry));
bPoolTag = TRUE;
}
if (Entry)
{
if (bPoolTag &&
(FaGetPoolTagFollowup(FA_ENTRY_DATA(PCHAR, Entry),
followup,
sizeof(followup)) == S_OK))
{
SetString(DEBUG_FLR_FOLLOWUP_NAME, followup);
} else if (FaGetFollowupInfo(NULL,
FA_ENTRY_DATA(PCHAR, Entry),
followup,
sizeof(followup)))
{
SetString(DEBUG_FLR_FOLLOWUP_NAME, followup);
}
SetString(DEBUG_FLR_BUCKET_ID, BucketId);
return;
}
}
//
// Only check this after as we could still have found a bad driver
// with a bad stack (like drivers that cause stack corruption ...)
//
Str = NULL;
Entry = NULL;
while (Entry = NextEntry(Entry))
{
switch(Entry->Tag)
{
case DEBUG_FLR_WRONG_SYMBOLS:
Str = "WRONG_SYMBOLS";
break;
case DEBUG_FLR_BAD_STACK:
Str = "BAD_STACK";
break;
case DEBUG_FLR_ZEROED_STACK:
Str = "ZEROED_STACK";
break;
case DEBUG_FLR_INVALID_KERNEL_CONTEXT:
Str = "INVALID_KERNEL_CONTEXT";
break;
case DEBUG_FLR_CORRUPT_MODULE_LIST:
Str = "CORRUPT_MODULELIST";
break;
break;
}
if (Str)
{
if (FaGetFollowupInfo(NULL,
"ProcessingError",
followup,
sizeof(followup)))
{
SetString(DEBUG_FLR_FOLLOWUP_NAME, followup);
}
SetString(DEBUG_FLR_BUCKET_ID, Str);
return;
}
}
//
// Add failure code.
//
if (Entry = Get(DEBUG_FLR_BUGCHECK_STR))
{
PrintString(BucketPtr, sizeof(BucketId) - LengthUsed, "%s", FA_ENTRY_DATA(PCHAR, Entry));
LengthUsed += strlen(BucketPtr);
BucketPtr = BucketId + LengthUsed;
}
if (Entry = Get(DEBUG_FLR_BUGCHECK_SPECIFIER))
{
PrintString(BucketPtr, sizeof(BucketId) - LengthUsed, "%s", FA_ENTRY_DATA(PCHAR, Entry));
LengthUsed += strlen(BucketPtr);
BucketPtr = BucketId + LengthUsed;
}
//
// If it's driver only, but the failure is not in a driver, then show the
// full name of the failure. If we could not get the name, or we really
// have a driver only, show the name of the image.
//
if ( (Entry = Get(DEBUG_FLR_SYMBOL_NAME)) &&
( !Get(DEBUG_FLR_FOLLOWUP_DRIVER_ONLY) ||
(BestClassFollowUp < FlpUnknownDrv)))
{
//
// If the faulting IP and the read address are the same, this is
// an interesting scenario we want to catch.
//
if (Get(DEBUG_FLR_FAILED_INSTRUCTION_ADDRESS))
{
PrintString(BucketPtr,
sizeof(BucketId) - LengthUsed,
"_BAD_IP");
LengthUsed += strlen(BucketPtr);
BucketPtr = BucketId + LengthUsed;
}
PrintString(BucketPtr,
sizeof(BucketId) - LengthUsed,
"_%s",
FA_ENTRY_DATA(PCHAR, Entry));
LengthUsed += strlen(BucketPtr);
BucketPtr = BucketId + LengthUsed;
}
else if (NameEntry)
{
PrintString(BucketPtr,
sizeof(BucketId) - LengthUsed,
"_IMAGE_%s",
FA_ENTRY_DATA(PCHAR, NameEntry));
LengthUsed += strlen(BucketPtr);
BucketPtr = BucketId + LengthUsed;
// Also add timestamp in this case.
if (ModuleTimestamp)
{
PrintString(BucketPtr,
sizeof(BucketId) - LengthUsed,
"_DATE_%s",
TimeToStr(ModuleTimestamp, TRUE));
LengthUsed += strlen(BucketPtr);
BucketPtr = BucketId + LengthUsed;
}
}
//
// Store the bucket ID in the analysis structure
//
//BucketDone:
for (PCHAR Scan = &BucketId[0]; *Scan; ++Scan)
{
// remove special chars that cause problems for IIS or SQL
if (*Scan == '<' || *Scan == '>' || *Scan == '|' ||
*Scan == '`' || *Scan == '\''|| (!isprint(*Scan)) )
{
*Scan = '_';
}
}
SetString(DEBUG_FLR_BUCKET_ID, BucketId);
}
void
DebugFailureAnalysis::AnalyzeStack(void)
{
PDEBUG_OUTPUT_CALLBACKS PrevCB;
ULONG i;
BOOL BoostToSpecific = FALSE;
ULONG64 TrapFrame = 0;
ULONG64 Thread = 0;
ULONG64 ImageNameAddr = 0;
DEBUG_STACK_FRAME Stk[MAX_STACK_FRAMES];
ULONG Frames = 0;
ULONG Trap0EFrameLimit = 2;
ULONG64 OriginalFaultingAddress = 0;
CHAR Command[50] = {0};
FA_ENTRY* Entry;
BOOL BadContext = FALSE;
ULONG PtrSize = IsPtr64() ? 8 : 4;
BOOL IsVrfBugcheck = FALSE;
//
// If someone provided a best followup already, just return
//
if (PossibleFollowups[MaxFlpClass-1].Owner[0])
{
return;
}
if (g_TargetClass == DEBUG_CLASS_KERNEL)
{
// Check if CPU is overclocked
//if (BcIsCpuOverClocked())
//{
// SetUlong64(DEBUG_FLR_CPU_OVERCLOCKED, -1);
//
// BestClassFollowUp = FlpOSInternalRoutine;
// strcpy(PossibleFollowups[FlpOSInternalRoutine].Owner, "MachineOwner");
// return;
//}
//
// Check if this bugcheck has any specific followup that independant
// of the failure stack
//
if (Entry = Get(DEBUG_FLR_BUGCHECK_STR))
{
PCHAR String;
String = g_pTriager->GetFollowupStr("bugcheck",
FA_ENTRY_DATA(PCHAR, Entry));
if (String)
{
if (!strncmp(String, "maybe_", 6))
{
BestClassFollowUp = FlpOSRoutine;
CopyString(PossibleFollowups[FlpOSRoutine].Owner,
String + 6,
sizeof(PossibleFollowups[FlpOSRoutine].Owner));
}
else if (!strncmp(String, "specific_", 9))
{
BoostToSpecific = TRUE;
}
else
{
BestClassFollowUp = FlpSpecific;
CopyString(PossibleFollowups[FlpSpecific].Owner,
String,
sizeof(PossibleFollowups[FlpSpecific].Owner));
return;
}
}
}
}
//
// Add trap frame, context info from the current stack
//
// Note(kksharma):We only need one of these to get to
// faulting stack (and only one of them should
// be available otherwise somethings wrong)
//
Entry = NULL;
while (Entry = NextEntry(Entry))
{
switch(Entry->Tag)
{
case DEBUG_FLR_CONTEXT:
sprintf(Command, ".cxr %I64lx",
*FA_ENTRY_DATA(PULONG64, Entry));
break;
case DEBUG_FLR_TRAP_FRAME:
sprintf(Command, ".trap %I64lx",
*FA_ENTRY_DATA(PULONG64, Entry));
break;
case DEBUG_FLR_TSS:
sprintf(Command, ".tss %I64lx",
*FA_ENTRY_DATA(PULONG64, Entry));
break;
case DEBUG_FLR_FAULTING_THREAD:
sprintf(Command, ".thread %I64lx",
*FA_ENTRY_DATA(PULONG64, Entry));
break;
case DEBUG_FLR_EXCEPTION_RECORD:
if (*FA_ENTRY_DATA(PULONG64, Entry) == -1)
{
sprintf(Command, ".ecxr");
}
break;
case DEBUG_FLR_FAULTING_IP:
case DEBUG_FLR_FAULTING_MODULE:
//
// We already have some info from the bugcheck
// Use that address to start off with.
// But if we could not use it to set any followup, then continue
// lookinh for the others.
//
if (OriginalFaultingAddress = *FA_ENTRY_DATA(PULONG64, Entry))
{
if (!GetTriageInfoFromStack(0, 1, OriginalFaultingAddress,
PossibleFollowups,
&BestClassFollowUp))
{
OriginalFaultingAddress = 0;
}
}
break;
default:
break;
}
if (Command[0] && OriginalFaultingAddress)
{
break;
}
}
RepeatGetCommand:
if (!Command[0])
{
//
// Get the current stack.
//
if (S_OK != g_ExtControl->GetStackTrace(0, 0, 0, Stk, MAX_STACK_FRAMES,
&Frames))
{
Frames = 0;
}
//
// Make sure this is a valid stack to analyze. Such as for kernel mode
// try to recognize stack after user breakin and send to machineowner
//
if (m_FailureType == DEBUG_FLR_KERNEL &&
m_FailureCode == 0 && Frames >= 3)
{
if (IsManualBreakin(Stk, Frames))
{
// set machine owner as followup
SetUlong(DEBUG_FLR_MANUAL_BREAKIN, TRUE);
strcpy(PossibleFollowups[MaxFlpClass-1].Owner, "MachineOwner");
PossibleFollowups[MaxFlpClass-1].InstructionOffset = Stk[0].InstructionOffset;
return;
}
}
//
// Get the current stack and check if we can get trap
// frame/context from it
//
ULONG64 ExceptionPointers = 0;
for (i = 0; i < Frames; ++i)
{
#if 0
// Stack walker taskes care of these when walking stack
if (GetTrapFromStackFrameFPO(&stk[i], &TrapFrame))
{
break;
}
#endif
//
// First argument of this function is the assert
// Second argument of this function is the file name
// Third argument of this function is the line number
//
if (FaIsFunctionAddr(Stk[i].InstructionOffset, "RtlAssert"))
{
ULONG Len;
CHAR AssertData[MAX_PATH + 1] = {0};
if (Len = ReadAcsiiString(Stk[i].Params[0],
AssertData,
sizeof(AssertData)))
{
SetString(DEBUG_FLR_ASSERT_DATA, AssertData);
}
if (Len = ReadAcsiiString(Stk[i].Params[1],
AssertData,
sizeof(AssertData)))
{
strncat(AssertData, " at Line ", sizeof(AssertData) - Len);
Len = strlen(AssertData);
PrintString(AssertData + Len,
sizeof(AssertData) - Len - 1,
"%I64lx",
Stk[i].Params[2]);
SetString(DEBUG_FLR_ASSERT_FILE, AssertData);
}
}
// If Trap 0E is the second or 3rd frame on the stack, we can just
// switch to that trap frame.
// Otherwise, we want to leave it as is because the failure is
// most likely due to the frames between bugcheck and trap0E
//
// ebp of KiTrap0E is the trap frame
//
if ((i <= Trap0EFrameLimit) &&
FaIsFunctionAddr(Stk[i].InstructionOffset, "KiTrap0E"))
{
TrapFrame = Stk[i].Reserved[2];
break;
}
//
// take first param - spin lock - and it contains the thread that
// owns the spin lock.
// Make sure to zero the bottom bit as it is always set ...
//
if ((i == 0) &&
FaIsFunctionAddr(Stk[i].InstructionOffset,
"SpinLockSpinningForTooLong"))
{
if (ReadPointer(Stk[0].Params[0], &Thread) &&
Thread)
{
Thread &= ~0x1;
}
break;
}
//
// First arg of KiMemoryFault is the trap frame
//
if (FaIsFunctionAddr(Stk[i].InstructionOffset, "KiMemoryFault") ||
FaIsFunctionAddr(Stk[i].InstructionOffset,
"Ki386CheckDivideByZeroTrap"))
{
TrapFrame = Stk[i].Params[0];
break;
}
//
// Third arg of KiMemoryFault is the trap frame
//
if (FaIsFunctionAddr(Stk[i].InstructionOffset,
"KiDispatchException"))
{
TrapFrame = Stk[i].Params[2];
break;
}
//
// First argument of this function is EXCEPTION_POINTERS
//
if (FaIsFunctionAddr(Stk[i].InstructionOffset,
"PspUnhandledExceptionInSystemThread"))
{
ExceptionPointers = Stk[i].Params[0];
break;
}
//
// First argument of this function is a BUGCHECK_DATA structure
// The thread is the second parameter in that data structure
//
if (FaIsFunctionAddr(Stk[i].InstructionOffset,
"WdBugCheckStuckDriver") ||
FaIsFunctionAddr(Stk[i].InstructionOffset,
"WdpBugCheckStuckDriver"))
{
ReadPointer(Stk[i].Params[0] + PtrSize, &Thread);
break;
}
//
// First argument of these functions are EXCEPTION_POINTERS
//
if (FaIsFunctionAddr(Stk[i].InstructionOffset,
"PopExceptionFilter") ||
FaIsFunctionAddr(Stk[i].InstructionOffset,
"RtlUnhandledExceptionFilter2"))
{
ExceptionPointers = Stk[i].Params[0];
break;
}
//
// THIRD argument has the name of Exe
// nt!PspCatchCriticalBreak(char* Msg, void* Object,unsigned char* ImageFileName)
//
if (FaIsFunctionAddr(Stk[i].InstructionOffset,
"PspCatchCriticalBreak"))
{
ImageNameAddr = Stk[i].Params[2];
break;
}
//
// VERIFIER : Look for possible verifier failures
// verifier!VerifierStopMessage means verifier caused the break
//
if (FaIsFunctionAddr(Stk[i].InstructionOffset,
"VerifierStopMessage"))
{
IsVrfBugcheck = TRUE;
break;
}
}
if (ExceptionPointers)
{
ULONG64 Exr = 0, Cxr = 0;
if (!ReadPointer(ExceptionPointers, &Exr) ||
!ReadPointer(ExceptionPointers + PtrSize, &Cxr))
{
// dprintf("Unable to read exception pointers at %p\n",
// ExcepPtr);
}
if (Exr)
{
SetUlong64(DEBUG_FLR_EXCEPTION_RECORD, Exr);
}
if (Cxr)
{
sprintf(Command, ".cxr %I64lx", Cxr);
SetUlong64(DEBUG_FLR_CONTEXT, Cxr);
}
}
if (TrapFrame)
{
sprintf(Command, ".trap %I64lx", TrapFrame);
SetUlong64(DEBUG_FLR_TRAP_FRAME, TrapFrame);
}
if (Thread)
{
sprintf(Command, ".thread %I64lx", Thread);
SetUlong64(DEBUG_FLR_FAULTING_THREAD, Thread);
}
if (ImageNameAddr)
{
CHAR Buffer[50]={0}, *pImgExt;
ULONG cb;
if (ReadMemory(ImageNameAddr, Buffer, sizeof(Buffer) - 1, &cb) &&
Buffer[0])
{
if (pImgExt = strchr(Buffer, '.'))
{
// we do not want imageextension here
*pImgExt = 0;
}
SetString(DEBUG_FLR_MODULE_NAME, Buffer);
}
}
if (IsVrfBugcheck)
{
ULONG64 AvrfCxr = 0;
// We hit this when app verifier breaks into kd and usermode
// analysis isn't called
if (DoVerifierAnalysis(NULL, this) == S_OK)
{
if (GetUlong64(DEBUG_FLR_CONTEXT, &AvrfCxr) != NULL)
{
sprintf(Command, ".cxr %I64lx", AvrfCxr);
}
}
}
}
//
// execute the command and get an updated stack
//
if (Command[0])
{
g_ExtControl->Execute(DEBUG_OUTCTL_IGNORE, Command,
DEBUG_EXECUTE_NOT_LOGGED);
if (g_ExtControl->GetStackTrace(0, 0, 0, Stk, MAX_STACK_FRAMES,
&Frames) != S_OK)
{
Frames = 0;
}
}
//
// Get relevant stack
//
// We can get stack with 1 frame because a .trap can bring us to the
// faulting instruction, and if it's a 3rd party driver with no symbols
// and image, the stack can be 1 frame - although a very valid one.
//
if (Frames)
{
ULONG64 Values[3];
Values[0] = Stk[0].ReturnOffset;
Values[1] = Stk[0].InstructionOffset;
Values[2] = Stk[0].StackOffset;
SetUlong64s(DEBUG_FLR_LAST_CONTROL_TRANSFER, 3, Values);
// If everything on the stack is user mode in the case of a kernel
// mode failure, we got some bad context information.
if (IsFollowupContext(Values[0],Values[1],Values[2]) != FollowYes)
{
SetUlong64(DEBUG_FLR_INVALID_KERNEL_CONTEXT, 0);
BadContext = TRUE;
}
else
{
GetTriageInfoFromStack(&Stk[0], Frames, 0, PossibleFollowups,
&BestClassFollowUp);
}
}
ULONG64 StackBase = FaGetImplicitStackOffset();
//
// If the stack pointer is not aligned, take a note of that.
//
if (StackBase & 0x3)
{
Set(DEBUG_FLR_UNALIGNED_STACK_POINTER, 0);
}
//
// If we have an image name (possibly directly from the bugcheck
// information) try to get the followup from that.
//
if ((BestClassFollowUp < FlpUnknownDrv) &&
(Entry = Get(DEBUG_FLR_MODULE_NAME)))
{
FaGetFollowupInfo(NULL,
FA_ENTRY_DATA(PCHAR, Entry),
PossibleFollowups[FlpUnknownDrv].Owner,
sizeof(PossibleFollowups[FlpUnknownDrv].Owner));
if (PossibleFollowups[FlpUnknownDrv].Owner[0])
{
BestClassFollowUp = FlpUnknownDrv;
}
}
//
// If we could not find anything at this point, look further up the stack
// for a trap frame to catch failures of this kind:
// nt!RtlpBreakWithStatusInstruction
// nt!KiBugCheckDebugBreak+0x19
// nt!KeBugCheck2+0x499
// nt!KeBugCheckEx+0x19
// nt!_KiTrap0E+0x224
//
if (!Command[0] &&
(BestClassFollowUp < FlpOSFilterDrv) &&
(Trap0EFrameLimit != 0xff))
{
Trap0EFrameLimit = 0xff;
goto RepeatGetCommand;
}
//
// Last resort, manually read the stack and look for some symbol
// to followup on.
//
if ((BadContext == FALSE) &&
((BestClassFollowUp == FlpIgnore) ||
((BestClassFollowUp < FlpOSRoutine) && (Frames <= 2))))
{
FindFollowupOnRawStack(StackBase,
PossibleFollowups,
&BestClassFollowUp);
}
//
// Get something !
//
if (BestClassFollowUp < FlpOSRoutine)
{
if (!BestClassFollowUp)
{
PossibleFollowups[FlpOSInternalRoutine].InstructionOffset =
GetExpression("@$ip");
}
if (!PossibleFollowups[FlpOSInternalRoutine].Owner[0] ||
!_stricmp(PossibleFollowups[FlpOSInternalRoutine].Owner, "ignore"))
{
FaGetFollowupInfo(NULL,
"default",
PossibleFollowups[FlpOSInternalRoutine].Owner,
sizeof(PossibleFollowups[FlpOSInternalRoutine].Owner));
BestClassFollowUp = FlpOSRoutine;
}
}
//
// Special handling so a bugcheck EA can always take predence over a pool
// corruption.
//
if (BoostToSpecific)
{
for (i = MaxFlpClass-1; i ; i--)
{
if (PossibleFollowups[i].Owner[0])
{
PossibleFollowups[FlpSpecific] = PossibleFollowups[i];
break;
}
}
}
//
// Get the faulting stack
//
g_OutCapCb.Reset();
g_OutCapCb.Output(0, "\n");
g_ExtClient->GetOutputCallbacks(&PrevCB);
g_ExtClient->SetOutputCallbacks(&g_OutCapCb);
g_ExtControl->OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT |
DEBUG_OUTCTL_NOT_LOGGED, Stk, Frames,
DEBUG_STACK_ARGUMENTS |
DEBUG_STACK_FRAME_ADDRESSES |
DEBUG_STACK_SOURCE_LINE);
g_ExtClient->SetOutputCallbacks(PrevCB);
if (*g_OutCapCb.GetCapturedText())
{
SetString(DEBUG_FLR_STACK_TEXT, g_OutCapCb.GetCapturedText());
}
//
// Reset the current state to normal so !analyze does not have any
// side-effects
//
if (Command[0])
{
SetString(DEBUG_FLR_STACK_COMMAND, Command);
//
// Clear the set context
//
g_ExtControl->Execute(DEBUG_OUTCTL_IGNORE, ".cxr 0; .thread",
DEBUG_EXECUTE_NOT_LOGGED);
}
}
VOID
DebugFailureAnalysis::FindFollowupOnRawStack(
ULONG64 StackBase,
PFOLLOWUP_DESCS PossibleFollowups,
FlpClasses *BestClassFollowUp
)
{
#define NUM_ADDRS 200
ULONG i;
ULONG PtrSize = IsPtr64() ? 8 : 4;
BOOL AddressFound = FALSE;
BOOL ZeroedStack = TRUE;
ULONG64 AddrToLookup;
FlpClasses RawStkBestFollowup;
if (*BestClassFollowUp >= FlpUnknownDrv)
{
// Any better fron raw stack won't be as accurate as what we have
return;
} else if (*BestClassFollowUp == FlpIgnore)
{
// We don't want to followup on os internal routine here
RawStkBestFollowup = FlpOSInternalRoutine;
} else
{
RawStkBestFollowup = *BestClassFollowUp;
}
// Align stack to natural pointer size.
StackBase &= ~((ULONG64)PtrSize - 1);
for (i = 0; i < NUM_ADDRS; i++)
{
if (!ReadPointer(StackBase, &AddrToLookup))
{
break;
}
StackBase+= PtrSize;
if (AddrToLookup)
{
FOLLOW_ADDRESS Follow;
ZeroedStack = FALSE;
Follow = IsPotentialFollowupAddress(AddrToLookup);
if (Follow == FollowStop)
{
break;
}
else if (Follow == FollowSkip)
{
continue;
}
AddressFound = TRUE;
GetTriageInfoFromStack(0, 1, AddrToLookup,
PossibleFollowups,
&RawStkBestFollowup);
if (RawStkBestFollowup == FlpUnknownDrv)
{
break;
}
}
}
if (!AddressFound)
{
if (ZeroedStack)
{
SetUlong64(DEBUG_FLR_ZEROED_STACK, 0);
}
else
{
SetUlong64(DEBUG_FLR_BAD_STACK, 0);
}
}
if (RawStkBestFollowup > FlpOSInternalRoutine)
{
*BestClassFollowUp = RawStkBestFollowup;
}
}
BOOL
DebugFailureAnalysis::GetTriageInfoFromStack(
PDEBUG_STACK_FRAME Stack,
ULONG Frames,
ULONG64 SingleInstruction,
PFOLLOWUP_DESCS PossibleFollowups,
FlpClasses *BestClassFollowUp)
{
ULONG i;
EXT_TRIAGE_FOLLOWUP FollowUp = &_EFN_GetTriageFollowupFromSymbol;
BOOL bStat = FALSE;
BOOL IgnorePoolCorruptionFlp = FALSE;
FOLLOW_ADDRESS Follow;
if (Get(DEBUG_FLR_ANALYZAABLE_POOL_CORRUPTION))
{
IgnorePoolCorruptionFlp = TRUE;
}
for (i = 0; i < Frames; ++i)
{
ULONG64 Disp;
ULONG64 Instruction;
CHAR Module[20] = {0};
CHAR Buffer[MAX_PATH];
CHAR Owner[100];
DWORD dwOwner;
DEBUG_TRIAGE_FOLLOWUP_INFO Info;
FlpClasses ClassFollowUp = FlpIgnore;
FlpClasses StoreClassFollowUp = FlpIgnore;
Instruction = SingleInstruction;
if (!SingleInstruction)
{
Instruction = Stack[i].InstructionOffset;
}
//
// Determine how to process this address.
//
Follow = IsPotentialFollowupAddress(Instruction);
if (Follow == FollowStop)
{
break;
}
else if (Follow == FollowSkip)
{
continue;
}
Buffer[0] = 0;
FaGetSymbol(Instruction, Buffer, &Disp, sizeof(Buffer));
if (Buffer[0] == 0)
{
//
// Either its a bad stack or someone jumped called to bad IP
//
continue;
}
//
// Check if this routine has any special significance for getting
// faulting module
//
PCHAR Routine = strchr(Buffer, '!');
if (Routine)
{
*Routine = 0;
}
CopyString(Module, Buffer, sizeof(Module));
if (Routine)
{
*Routine = '!';
Routine++;
if (Stack && !strcmp(Routine, "IopCompleteRequest"))
{
// First argument is Irp Tail, get the driver from Irp
ULONG TailOffset = 0;
ULONG64 Irp;
GetFieldOffset("nt!_IRP", "Tail", &TailOffset);
if (TailOffset)
{
FA_ENTRY* Entry = NULL;
PCHAR ModuleName = NULL;
Irp = Stack[i].Params[0] - TailOffset;
SetUlong64(DEBUG_FLR_IRP_ADDRESS, Irp);
if (BcGetDriverNameFromIrp(this, Irp, NULL, NULL))
{
if (Entry = Get(DEBUG_FLR_IMAGE_NAME))
{
CopyString(Buffer, FA_ENTRY_DATA(PCHAR, Entry), sizeof(Buffer));
PCHAR Dot;
if (Dot = strchr(Buffer, '.'))
{
*Dot = 0;
CopyString(Module, Buffer, sizeof(Module));
}
}
}
}
}
else if ((i == 0) && Stack &&
!strcmp(Routine, "ObpCloseHandleTableEntry"))
{
//
// Check for possible memory corruption
// 2nd parameter is HANDLE_TABLE_ENTRY
//
if (CheckForCorruptionInHTE(Stack[i].Params[1], Owner, sizeof(Owner)))
{
// We have pool corrupting PoolTag in analysis
// continue with default analysis for now
}
}
}
ClassFollowUp = GetFollowupClass(Instruction, Module, Routine);
if (ClassFollowUp == FlpIgnore)
{
continue;
}
Info.SizeOfStruct = sizeof(Info);
Info.OwnerName = &Owner[0];
Info.OwnerNameSize = sizeof(Owner);
if (dwOwner = (*FollowUp)(g_ExtClient, Buffer, &Info))
{
PCHAR pOwner = Owner;
if (dwOwner == TRIAGE_FOLLOWUP_IGNORE)
{
ClassFollowUp = FlpIgnore;
}
else if (!strncmp(Owner, "maybe_", 6))
{
pOwner = Owner + 6;
ClassFollowUp = (FlpClasses) ((ULONG) ClassFollowUp - 1);
}
else if (!strncmp(Owner, "last_", 5))
{
pOwner = Owner + 5;
ClassFollowUp = FlpOSInternalRoutine;
}
else if (!strncmp(Owner, "specific_", 9))
{
pOwner = Owner + 9;
ClassFollowUp = FlpSpecific;
}
else if (!_stricmp(Owner, "pool_corruption"))
{
if (IgnorePoolCorruptionFlp)
{
continue;
}
//
// If we have non-kernel followups already on the stack
// it could be them no correctly handling this stack.
// If we only have kernel calls, then it must be pool
// corruption.
//
// We later rely on a pool corruption always being marked
// as a FlpUnknownDrv
//
StoreClassFollowUp = FlpUnknownDrv;
ClassFollowUp = FlpOSFilterDrv;
}
if (StoreClassFollowUp == FlpIgnore)
{
StoreClassFollowUp = ClassFollowUp;
}
//
// Save this entry if it's better than anything else we have.
//
if (ClassFollowUp > *BestClassFollowUp)
{
bStat = TRUE;
*BestClassFollowUp = StoreClassFollowUp;
CopyString(PossibleFollowups[StoreClassFollowUp].Owner,
pOwner,
sizeof(PossibleFollowups[StoreClassFollowUp].Owner));
PossibleFollowups[StoreClassFollowUp].InstructionOffset =
Instruction;
if (StoreClassFollowUp == FlpUnknownDrv)
{
// Best match possible
return bStat;
}
}
}
}
return bStat;
}
BOOL
DebugFailureAnalysis::AddCorruptModules(void)
{
//
// Check if we have an old build. Anything smaller than OSBuild
// and not identified specifically by build number in the list is old.
//
PCHAR String;
CHAR BuildString[7];
ULONG BuildNum = 0;
BOOL FoundCorruptor = FALSE;
BOOL PoolCorruption = FALSE;
ULONG Loaded;
ULONG Unloaded;
CHAR Name[MAX_PATH];
CHAR ImageName[MAX_PATH];
CHAR CorruptModule[MAX_PATH];
FA_ENTRY *Entry;
FA_ENTRY *BugCheckEntry;
sprintf(BuildString, "%d", g_TargetBuild);
if (!g_pTriager->GetFollowupStr("OSBuild", BuildString))
{
if (String = g_pTriager->GetFollowupStr("OSBuild", "old"))
{
BuildNum = strtol(String, NULL, 10);
if (BuildNum > g_TargetBuild)
{
SetUlong64(DEBUG_FLR_OLD_OS_VERSION, g_TargetBuild);
}
}
}
//
// If we have a specific solution, return
// if we can't get a module list, return
//
if (PossibleFollowups[FlpSpecific].Owner[0] ||
(g_ExtSymbols->GetNumberModules(&Loaded, &Unloaded) != S_OK))
{
return FALSE;
}
//
// Determine if the failure was likely caused by a pool corruption
//
if ((BestClassFollowUp < FlpUnknownDrv) ||
!_stricmp(PossibleFollowups[FlpUnknownDrv].Owner, "pool_corruption"))
{
PoolCorruption = TRUE;
}
BugCheckEntry = Get(DEBUG_FLR_BUGCHECK_STR);
//
// Loop three types to find the types of corruptors in order.
// the order must match the order in which we generate the bucket name
// for these types so the image name ends up correct.
//
for (ULONG TypeLoop = 0; TypeLoop < 3; TypeLoop++)
{
if ((TypeLoop == 0) && !BugCheckEntry)
{
continue;
}
if ((TypeLoop == 2) && !PoolCorruption)
{
continue;
}
for (ULONG Index = 0; Index < Loaded + Unloaded; Index++)
{
ULONG64 Base;
DEBUG_FLR_PARAM_TYPE Type = (DEBUG_FLR_PARAM_TYPE)0;
PCHAR Scan;
PCHAR DriverName;
DEBUG_MODULE_PARAMETERS Params;
ULONG Start, End = 0;
if (g_ExtSymbols->GetModuleByIndex(Index, &Base) != S_OK)
{
continue;
}
if (g_ExtSymbols->GetModuleNames(Index, Base,
ImageName, MAX_PATH, NULL,
Name, MAX_PATH, NULL,
NULL, 0, NULL) != S_OK)
{
continue;
}
if (g_ExtSymbols->GetModuleParameters(1, &Base, Index,
&Params) != S_OK)
{
continue;
}
//
// Strip the path
//
DriverName = ImageName;
if (Scan = strrchr(DriverName, '\\'))
{
DriverName = Scan+1;
}
//
// Look for the module in both the various bad drivers list.
// poolcorruptor and memorycorruptor lists in triage.ini
//
switch (TypeLoop)
{
case 0:
Type = DEBUG_FLR_BUGCHECKING_DRIVER;
PrintString(CorruptModule, sizeof(CorruptModule), "%s_%s",
FA_ENTRY_DATA(PCHAR, BugCheckEntry), DriverName);
g_pTriager->GetFollowupDate("bugcheckingDriver", CorruptModule,
&Start, &End);
break;
case 1:
Type = DEBUG_FLR_MEMORY_CORRUPTOR;
g_pTriager->GetFollowupDate("memorycorruptors", DriverName,
&Start, &End);
break;
case 2:
//
// Only look at kernel mode pool corruptors if the failure
// is a kernel mode crash (and same for user mode), because
// a kernel pool corruptor will almost never affect an app
// (apps don't see data in pool blocks)
//
if ((BOOL)(GetFailureType() != DEBUG_FLR_KERNEL) ==
(BOOL)((Params.Flags & DEBUG_MODULE_USER_MODE) != 0))
{
Type = DEBUG_FLR_POOL_CORRUPTOR;
g_pTriager->GetFollowupDate("poolcorruptors", DriverName,
&Start, &End);
}
break;
}
//
// Add it to the list if it's really known to be a bad driver.
//
if (End)
{
//
// Check to see if the timestamp is older than a fixed
// driver. If the module is unloaded and no fix is know,
// then also mark it as bad
//
if ( (Params.TimeDateStamp &&
(Params.TimeDateStamp < End) &&
(Params.TimeDateStamp >= Start)) ||
((Params.Flags & DEBUG_MODULE_UNLOADED) &&
(End == 0xffffffff)) )
{
// Don't store the timestamp on memory corrupting
// modules to simplify bucketing annd allow for
// name lookup.
//
//sprintf(CorruptModule, "%s_%08lx",
// DriverName, Params.TimeDateStamp);
//
// Store the first driver we find as the cause,
// bug accumulate the list of known memory corruptors.
//
if (!FoundCorruptor)
{
SetString(DEBUG_FLR_MODULE_NAME, Name);
SetString(DEBUG_FLR_IMAGE_NAME, DriverName);
SetUlong64(DEBUG_FLR_IMAGE_TIMESTAMP,
Params.TimeDateStamp);
FoundCorruptor = TRUE;
}
//
// Remove the dot since we check the followup
// based on that string.
//
if (Scan = strrchr(DriverName, '.'))
{
*Scan = 0;
}
if (strlen(DriverName) < sizeof(CorruptModule))
{
CopyString(CorruptModule, DriverName,
sizeof(CorruptModule));
}
Entry = Add(Type, strlen(CorruptModule) + 1);
if (Entry)
{
CopyString(FA_ENTRY_DATA(PCHAR, Entry),
CorruptModule, Entry->FullSize);
}
}
}
}
}
return FoundCorruptor;
}
void
DebugFailureAnalysis::SetSymbolNameAndModule()
{
ULONG64 Address = 0;
CHAR Buffer[MAX_PATH];
ULONG64 Disp, Base = 0;
ULONG Index;
ULONG i;
//
// Store the best followup name in the analysis results
//
for (i = MaxFlpClass-1; i ; i--)
{
if (PossibleFollowups[i].Owner[0])
{
if (PossibleFollowups[i].InstructionOffset)
{
Address = PossibleFollowups[i].InstructionOffset;
SetUlong64(DEBUG_FLR_FOLLOWUP_IP,
PossibleFollowups[i].InstructionOffset);
}
SetString(DEBUG_FLR_FOLLOWUP_NAME, PossibleFollowups[i].Owner);
break;
}
}
//
// Now that we have the followip, get the module names.
//
// The address may not be set in the case where we just
// had a driver name with no real address for it
//
if (Address)
{
//
// Try to get the full symbol name.
// leave space for Displacement
//
Buffer[0] = 0;
if (FaGetSymbol(Address, Buffer, &Disp, sizeof(Buffer) - 20))
{
sprintf(Buffer + strlen(Buffer), "+%I64lx", Disp);
SetString(DEBUG_FLR_SYMBOL_NAME, Buffer);
}
//
// Now get the Mod name
//
g_ExtSymbols->GetModuleByOffset(Address, 0, &Index, &Base);
if (Base)
{
CHAR ModBuf[100];
CHAR ImageBuf[100];
PCHAR Scan;
PCHAR ImageName;
if (g_ExtSymbols->GetModuleNames(Index, Base,
ImageBuf, sizeof(ImageBuf), NULL,
ModBuf, sizeof(ModBuf), NULL,
NULL, 0, NULL) == S_OK)
{
//
// Check for unknown module.
// If it's not, then we should have something valid.
//
if (!strstr(ModBuf, "Unknown"))
{
//
// Strip the path - keep the extension
//
ImageName = ImageBuf;
if (Scan = strrchr(ImageName, '\\'))
{
ImageName = Scan+1;
}
SetString(DEBUG_FLR_MODULE_NAME, ModBuf);
SetString(DEBUG_FLR_IMAGE_NAME, ImageName);
DEBUG_MODULE_PARAMETERS Params;
ULONG TimeStamp = 0;
if (g_ExtSymbols->GetModuleParameters(1, &Base, Index,
&Params) == S_OK)
{
TimeStamp = Params.TimeDateStamp;
}
SetUlong64(DEBUG_FLR_IMAGE_TIMESTAMP, TimeStamp);
return;
}
}
}
}
//
// If we make it here there was an error getting module name,
// so set things to "unknown".
//
if (!Get(DEBUG_FLR_MODULE_NAME))
{
SetUlong64(DEBUG_FLR_UNKNOWN_MODULE, 1);
SetString(DEBUG_FLR_MODULE_NAME, "Unknown_Module");
SetString(DEBUG_FLR_IMAGE_NAME, "Unknown_Image");
SetUlong64(DEBUG_FLR_IMAGE_TIMESTAMP, 0);
}
}
HRESULT
DebugFailureAnalysis::CheckModuleSymbols(PSTR ModName, PSTR ShowName)
{
ULONG ModIndex;
ULONG64 ModBase;
DEBUG_MODULE_PARAMETERS ModParams;
if (S_OK != g_ExtSymbols->GetModuleByModuleName(ModName, 0, &ModIndex,
&ModBase))
{
ExtErr("***** Debugger could not find %s in module list, "
"dump might be corrupt.\n"
"***** Followup with Debugger team\n\n",
ModName);
SetString(DEBUG_FLR_CORRUPT_MODULE_LIST, ModName);
return E_FAILURE_CORRUPT_MODULE_LIST;
}
else if ((S_OK != g_ExtSymbols->GetModuleParameters(1, &ModBase, 0,
&ModParams)) ||
(ModParams.SymbolType == DEBUG_SYMTYPE_NONE) ||
(ModParams.SymbolType == DEBUG_SYMTYPE_EXPORT))
// (ModParams.Flags & DEBUG_MODULE_SYM_BAD_CHECKSUM))
{
ExtErr("***** %s symbols are WRONG. Please fix symbols to "
"do analysis.\n\n", ShowName);
SetUlong64(DEBUG_FLR_WRONG_SYMBOLS, ModBase);
return E_FAILURE_WRONG_SYMBOLS;
}
return S_OK;
}
void
DebugFailureAnalysis::ProcessInformation(void)
{
//
// Analysis of abstracted information.
//
// Now that raw information has been gathered,
// perform abstract analysis of the gathered
// information to produce even higher-level
// information. The process iterates until no
// new information is produced.
//
AnalyzeStack();
while (ProcessInformationPass())
{
// Iterate.
}
//
// Only add corrupt modules if we did not find a specific solution.
//
// If we do find a memory corruptor, the followup and name will be set
// from the module name as part of bucketing.
if (!AddCorruptModules())
{
SetSymbolNameAndModule();
}
GenerateBucketId();
DbFindBucketInfo();
}
ULONG64
GetControlTransferTargetX86(ULONG64 StackOffset, PULONG64 ReturnOffset)
{
ULONG Done;
UCHAR InstrBuf[8];
ULONG StackReturn;
ULONG64 Target;
ULONG JumpCount;
//
// Check that we just performed a call, which implies
// the first value on the stack is equal to the return address
// computed during stack walk.
//
if (!ReadMemory(StackOffset, &StackReturn, 4, &Done) ||
(Done != 4) ||
StackReturn != (ULONG)*ReturnOffset)
{
return 0;
}
//
// Check for call rel32 instruction.
//
if (!ReadMemory(*ReturnOffset - 5, InstrBuf, 5, &Done) ||
(Done != 5) ||
(InstrBuf[0] != 0xe8))
{
return 0;
}
Target = (LONG64)(LONG)
((ULONG)*ReturnOffset + *(ULONG UNALIGNED *)&InstrBuf[1]);
// Adjust the return offset to point to the start of the instruction.
(*ReturnOffset) -= 5;
//
// We may have called an import thunk or something else which
// immediately jumps somewhere else, so follow jumps.
//
JumpCount = 8;
for (;;)
{
if (!ReadMemory(Target, InstrBuf, 6, &Done) ||
Done < 5)
{
// We expect to be able to read the target memory
// as that's where we think IP is. If this fails
// we need to flag it as a problem.
return Target;
}
if (InstrBuf[0] == 0xe9)
{
Target = (LONG64)(LONG)
((ULONG)Target + 5 + *(ULONG UNALIGNED *)&InstrBuf[1]);
}
else if (InstrBuf[0] == 0xff && InstrBuf[1] == 0x25)
{
ULONG64 Ind;
if (Done < 6)
{
// We see a jump but we don't have all the
// memory. To avoid spurious errors we just
// give up.
return 0;
}
Ind = (LONG64)(LONG)*(ULONG UNALIGNED *)&InstrBuf[2];
if (!ReadMemory(Ind, &Target, 4, &Done) ||
Done != 4)
{
return 0;
}
Target = (LONG64)(LONG)Target;
}
else
{
break;
}
if (JumpCount-- == 0)
{
// We've been tracing jumps too long, just give up.
return 0;
}
}
return Target;
}
BOOL
DebugFailureAnalysis::ProcessInformationPass(void)
{
ULONG Done;
ULONG64 ExceptionCode;
ULONG64 Arg1, Arg2;
ULONG64 Values[2];
ULONG PtrSize = IsPtr64() ? 8 : 4;
FA_ENTRY* Entry;
//
// Determine if the current fault is due to inability
// to execute an instruction. The checks are:
// 1. A read access violation at the current IP indicates
// the current instruction memory is invalid.
// 2. An illegal instruction fault indicates the current
// instruction is invalid.
//
if (!Get(DEBUG_FLR_FAILED_INSTRUCTION_ADDRESS))
{
if (GetUlong64(DEBUG_FLR_EXCEPTION_CODE, &ExceptionCode) &&
(ExceptionCode == STATUS_ILLEGAL_INSTRUCTION) &&
GetUlong64(DEBUG_FLR_FAULTING_IP, &Arg1))
{
// Invalid instruction.
SetUlong64(DEBUG_FLR_FAILED_INSTRUCTION_ADDRESS, Arg1);
return TRUE;
}
if ( // ExceptionCode == STATUS_ACCESS_VIOLATION &&
GetUlong64(DEBUG_FLR_READ_ADDRESS, &Arg1) &&
GetUlong64(DEBUG_FLR_FAULTING_IP, &Arg2) &&
Arg1 == Arg2)
{
// Invalid instruction.
SetUlong64(DEBUG_FLR_FAILED_INSTRUCTION_ADDRESS, Arg1);
return TRUE;
}
}
//
// If we've determined that the current failure is
// due to inability to execute an instruction, check
// and see whether there's a call to the instruction.
// If the instruction prior at the return address can be analyzed,
// check for known instruction sequences to see if perhaps
// the processor incorrectly handled a control transfer.
//
if (!Get(DEBUG_FLR_POSSIBLE_INVALID_CONTROL_TRANSFER) &&
(Entry = Get(DEBUG_FLR_LAST_CONTROL_TRANSFER)))
{
ULONG64 ReturnOffset = FA_ENTRY_DATA(PULONG64, Entry)[0];
Arg2 = FA_ENTRY_DATA(PULONG64, Entry)[1];
ULONG64 StackOffset = FA_ENTRY_DATA(PULONG64, Entry)[2];
ULONG64 Target = 0;
switch(g_TargetMachine)
{
case IMAGE_FILE_MACHINE_I386:
Target = GetControlTransferTargetX86(StackOffset, &ReturnOffset);
break;
}
if (Target && Target != Arg2)
{
char Sym1[MAX_PATH], Sym2[MAX_PATH];
ULONG64 Disp;
//
// If both addresses are within the same function
// we assume that there has been some execution
// in the function and therefore this doesn't
// actually indicate a problem.
// NOTE - DbgBreakPointWithStatus has an internal label
// which messes up symbols, so account for that too by
// checking we are 10 bytes within the function.
//
FaGetSymbol(Target, Sym1, &Disp, sizeof(Sym1));
FaGetSymbol(Arg2, Sym2, &Disp, sizeof(Sym2));
if ((Arg2 - Target > 10) &&
(strcmp(Sym1, Sym2) != 0))
{
PCHAR String;
ULONG64 BitDiff;
ULONG64 BitDiff2;
Values[0] = ReturnOffset;
Values[1] = Target;
SetUlong64s(DEBUG_FLR_POSSIBLE_INVALID_CONTROL_TRANSFER,
2, Values);
//
// If the difference between the two address is a power of 2,
// then it's a single bit error.
// Also, to avoid sign extension issues due to a 1 bit error
// in the top bit, check if the difference betweent the two is
// only the sign extensions, and zero out the top 32 bits if
// it's the case.
//
BitDiff = Arg2 ^ Target;
if ((BitDiff >> 32) == 0xFFFFFFFF)
{
BitDiff &= 0xFFFFFFFF;
}
if (!(BitDiff2 = (BitDiff & (BitDiff - 1))))
{
Set(DEBUG_FLR_SINGLE_BIT_ERROR, 1);
}
if (!(BitDiff2 & (BitDiff2 - 1)))
{
Set(DEBUG_FLR_TWO_BIT_ERROR, 1);
}
if (String = g_pTriager->GetFollowupStr("badcpu", ""))
{
BestClassFollowUp = FlpSpecific;
CopyString(PossibleFollowups[FlpSpecific].Owner,
String,
sizeof(PossibleFollowups[FlpSpecific].Owner));
SetString(DEBUG_FLR_MODULE_NAME, "No_Module");
SetString(DEBUG_FLR_IMAGE_NAME, "No_Image");
SetUlong64(DEBUG_FLR_IMAGE_TIMESTAMP, 0);
}
return TRUE;
}
}
}
//
// If the process is determine to be of importance to this failure,
// also expose the process name.
// This will overwrite the PROCESS_NAME of the default process.
//
if (GetUlong64(DEBUG_FLR_PROCESS_OBJECT, &Arg1) &&
!Get(DEBUG_FLR_PROCESS_NAME))
{
ULONG NameOffset;
CHAR Name[17];
if (!GetFieldOffset("nt!_EPROCESS", "ImageFileName", &NameOffset) &&
NameOffset)
{
if (ReadMemory(Arg1 + NameOffset, Name, sizeof(Name), &Done) &&
(Done == sizeof(Name)))
{
Name[16] = 0;
SetString(DEBUG_FLR_PROCESS_NAME, Name);
return TRUE;
}
}
}
return FALSE;
}