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.
2521 lines
72 KiB
2521 lines
72 KiB
/*++
|
|
|
|
Copyright (c) 1992-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
bugcheck.cpp
|
|
|
|
Abstract:
|
|
|
|
WinDbg Extension Api
|
|
|
|
Environment:
|
|
|
|
User Mode.
|
|
|
|
Revision History:
|
|
|
|
Andre Vachon (andreva)
|
|
|
|
bugcheck analyzer.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
extern BUGDESC_APIREFS g_BugDescApiRefs[];
|
|
extern ULONG g_NumBugDescApiRefs;
|
|
|
|
PSTR g_PoolRegion[DbgPoolRegionMax] = {
|
|
"Unknown", // DbgPoolRegionUnknown,
|
|
"Special pool", // DbgPoolRegionSpecial,
|
|
"Paged pool", // DbgPoolRegionPaged,
|
|
"Nonpaged pool", // DbgPoolRegionNonPaged,
|
|
"Pool code", // DbgPoolRegionCode,
|
|
"Nonpaged pool expansion", // DbgPoolRegionNonPagedExpansion,
|
|
};
|
|
|
|
/*
|
|
Get the description record for a bugcheck code.
|
|
*/
|
|
|
|
BOOL
|
|
GetBugCheckDescription(
|
|
PBUGCHECK_ANALYSIS Bc
|
|
)
|
|
{
|
|
ULONG i;
|
|
for (i=0; i<g_NumBugDescApiRefs; i++) {
|
|
if (g_BugDescApiRefs[i].Code == Bc->Code) {
|
|
(g_BugDescApiRefs[i].pExamineRoutine)(Bc);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
PrintBugDescription(
|
|
PBUGCHECK_ANALYSIS pBugCheck
|
|
)
|
|
{
|
|
LPTSTR Name = pBugCheck->szName;
|
|
LPTSTR Description = pBugCheck->szDescription;
|
|
|
|
if (!Name)
|
|
{
|
|
Name = "Unknown bugcheck code";
|
|
}
|
|
|
|
if (!Description)
|
|
{
|
|
Description = "Unknown bugcheck description\n";
|
|
}
|
|
|
|
dprintf("%s (%lx)\n%s", Name, pBugCheck->Code, Description);
|
|
|
|
dprintf("Arguments:\n");
|
|
for (ULONG i=0; i<4; i++) {
|
|
dprintf("Arg%lx: %p",i+1,pBugCheck->Args[i]);
|
|
if (pBugCheck->szParamsDesc[i]) {
|
|
dprintf(", %s", pBugCheck->szParamsDesc[i]);
|
|
}
|
|
dprintf("\n");
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
SaveImageName(
|
|
DebugFailureAnalysis* Analysis,
|
|
LPSTR DriverName)
|
|
{
|
|
PCHAR BaseName = strrchr(DriverName, '\\');
|
|
|
|
if (BaseName)
|
|
{
|
|
BaseName++;
|
|
}
|
|
else
|
|
{
|
|
BaseName = DriverName;
|
|
}
|
|
|
|
if (*BaseName)
|
|
{
|
|
Analysis->SetString(DEBUG_FLR_IMAGE_NAME, BaseName);
|
|
|
|
//
|
|
// Just create a best guess module name because I don't think
|
|
// the driver name returned by theOs is guaranteed to be in
|
|
// the loaded module list (it could be unlaoded)
|
|
//
|
|
|
|
PCHAR EndName;
|
|
|
|
if (EndName = strrchr(DriverName, '.'))
|
|
{
|
|
*EndName = 0;
|
|
}
|
|
|
|
Analysis->SetString(DEBUG_FLR_MODULE_NAME, BaseName);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ReadUnicodeString(
|
|
ULONG64 Address,
|
|
PWCHAR Buffer,
|
|
ULONG BufferSize,
|
|
PULONG StringSize)
|
|
{
|
|
UNICODE_STRING64 uStr;
|
|
UNICODE_STRING32 uStr32;
|
|
ULONG res;
|
|
|
|
if (!Buffer) {
|
|
return FALSE;
|
|
}
|
|
if (!IsPtr64()) {
|
|
|
|
if (!ReadMemory(Address, &uStr32, sizeof(uStr32), &res)) {
|
|
return FALSE;
|
|
}
|
|
uStr.Length = uStr32.Length;
|
|
uStr.MaximumLength = uStr32.MaximumLength;
|
|
uStr.Buffer = (ULONG64) (LONG64) (LONG) uStr32.Buffer;
|
|
} else {
|
|
if (!ReadMemory(Address, &uStr, sizeof(uStr), &res)) {
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
if (StringSize) {
|
|
*StringSize = uStr.Length;
|
|
}
|
|
uStr.Length = (USHORT) min(BufferSize - 2, uStr.Length);
|
|
|
|
if (!ReadMemory(uStr.Buffer, Buffer, uStr.Length, &res)) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Add driver name to CrashInfo if a KiBugCheckReferences a valid name
|
|
*/
|
|
BOOL
|
|
AddBugcheckDriver(
|
|
DebugFailureAnalysis* Analysis,
|
|
BOOL bUnicodeString,
|
|
BOOL bUnicodeData,
|
|
ULONG64 BugCheckDriver
|
|
)
|
|
{
|
|
CHAR DriverName[MAX_PATH];
|
|
|
|
if (Analysis->Get(DEBUG_FLR_IMAGE_NAME))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!BugCheckDriver)
|
|
{
|
|
//
|
|
// This contains a pointer to the unicode string.
|
|
//
|
|
|
|
BugCheckDriver = GetExpression("NT!KiBugCheckDriver");
|
|
|
|
if (BugCheckDriver)
|
|
{
|
|
ReadPointer(BugCheckDriver, &BugCheckDriver);
|
|
}
|
|
}
|
|
|
|
if (BugCheckDriver)
|
|
{
|
|
ULONG length = 0;
|
|
BOOL success;
|
|
ULONG size;
|
|
ULONG res;
|
|
|
|
ZeroMemory(DriverName, sizeof(DriverName));
|
|
|
|
if (bUnicodeString)
|
|
{
|
|
success = ReadUnicodeString(BugCheckDriver,
|
|
(PWCHAR) &DriverName[0],
|
|
sizeof(DriverName), &length);
|
|
}
|
|
else
|
|
{
|
|
size = bUnicodeData ? 2 : 1;
|
|
|
|
while (ReadMemory(BugCheckDriver + length,
|
|
DriverName + length,
|
|
size,
|
|
&res) &&
|
|
(res == size) &&
|
|
*(DriverName + length))
|
|
{
|
|
length += size;
|
|
}
|
|
success = (length > 0);
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
DriverName[length] = 0;
|
|
|
|
if (bUnicodeData)
|
|
{
|
|
wchr2ansi((PWCHAR) DriverName, DriverName);
|
|
DriverName[length / 2] = 0;
|
|
}
|
|
|
|
return SaveImageName(Analysis, DriverName);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BcGetDriverNameFromIrp(
|
|
DebugFailureAnalysis* Analysis,
|
|
ULONG64 Irp,
|
|
ULONG64 DevObj,
|
|
ULONG64 DrvObj
|
|
)
|
|
{
|
|
if (Irp != 0)
|
|
{
|
|
DEBUG_IRP_INFO IrpInfo;
|
|
PGET_IRP_INFO GetIrpInfo;
|
|
|
|
if (g_ExtControl->GetExtensionFunction(0, "GetIrpInfo", (FARPROC*)&GetIrpInfo) == S_OK)
|
|
{
|
|
IrpInfo.SizeOfStruct = sizeof(IrpInfo);
|
|
if (GetIrpInfo &&
|
|
((*GetIrpInfo)(g_ExtClient,Irp, &IrpInfo) == S_OK))
|
|
{
|
|
DevObj = IrpInfo.CurrentStack.DeviceObject;
|
|
Analysis->SetUlong64(DEBUG_FLR_DEVICE_OBJECT, DevObj);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (DevObj != 0)
|
|
{
|
|
DEBUG_DEVICE_OBJECT_INFO DevObjInfo;
|
|
PGET_DEVICE_OBJECT_INFO GetDevObjInfo;
|
|
|
|
if (g_ExtControl->GetExtensionFunction(0, "GetDevObjInfo", (FARPROC*)&GetDevObjInfo) == S_OK)
|
|
{
|
|
DevObjInfo.SizeOfStruct = sizeof(DEBUG_DEVICE_OBJECT_INFO);
|
|
if (GetDevObjInfo &&
|
|
((*GetDevObjInfo)(g_ExtClient,DevObj, &DevObjInfo) == S_OK))
|
|
{
|
|
DrvObj = DevObjInfo.DriverObject;
|
|
Analysis->SetUlong64(DEBUG_FLR_DRIVER_OBJECT, DrvObj);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DrvObj)
|
|
{
|
|
DEBUG_DRIVER_OBJECT_INFO DrvObjInfo;
|
|
PGET_DRIVER_OBJECT_INFO GetDrvObjInfo;
|
|
|
|
if (g_ExtControl->GetExtensionFunction(0, "GetDrvObjInfo",
|
|
(FARPROC*)&GetDrvObjInfo) == S_OK)
|
|
{
|
|
DrvObjInfo.SizeOfStruct = sizeof(DEBUG_DRIVER_OBJECT_INFO);
|
|
if (GetDrvObjInfo &&
|
|
((*GetDrvObjInfo)(g_ExtClient,DrvObj, &DrvObjInfo) == S_OK))
|
|
{
|
|
if (AddBugcheckDriver(Analysis, FALSE, TRUE,
|
|
DrvObjInfo.DriverName.Buffer))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
CHAR DriverName[MAX_PATH];
|
|
|
|
if (g_ExtSymbols->GetModuleNames(DEBUG_ANY_ID,
|
|
DrvObjInfo.DriverStart,
|
|
DriverName,
|
|
sizeof(DriverName),
|
|
NULL,
|
|
NULL, 0, NULL,
|
|
NULL, 0, NULL) == S_OK)
|
|
{
|
|
return SaveImageName(Analysis, DriverName);
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
ULONG64
|
|
BcTargetKernelAddressStart(
|
|
void
|
|
)
|
|
{
|
|
switch (g_TargetMachine)
|
|
{
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
return 0x80000000;
|
|
case IMAGE_FILE_MACHINE_AMD64:
|
|
// return 0x80000000000UI64;
|
|
case IMAGE_FILE_MACHINE_IA64:
|
|
return 0x2000000000000000UI64;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
BcIsCpuOverClocked(
|
|
void
|
|
)
|
|
{
|
|
struct _IntelCPUSpeeds
|
|
{
|
|
union
|
|
{
|
|
ULONG CpuId;
|
|
struct
|
|
{
|
|
ULONG Stepping:8;
|
|
ULONG Model:8;
|
|
ULONG Family:16;
|
|
} s;
|
|
};
|
|
ULONG Mhz;
|
|
} IntelSpeeds[] = {
|
|
{0x06060d, 350},
|
|
//{0x060702, 450},
|
|
{0x060702, 500},
|
|
//{0x060703, 450},
|
|
//{0x060703, 500},
|
|
//{0x060703, 550},
|
|
//{0x060703, 533},
|
|
{0x060703, 600},
|
|
//{0x060801, 500},
|
|
//{0x060801, 533},
|
|
//{0x060801, 550},
|
|
//{0x060801, 600},
|
|
//{0x060801, 650},
|
|
//{0x060801, 667},
|
|
//{0x060801, 700},
|
|
//{0x060801, 733},
|
|
//{0x060801, 750},
|
|
{0x060801, 800},
|
|
//{0x060803, 500},
|
|
//{0x060803, 533},
|
|
//{0x060803, 550},
|
|
//{0x060803, 600},
|
|
//{0x060803, 650},
|
|
//{0x060803, 667},
|
|
//{0x060803, 700},
|
|
//{0x060803, 733},
|
|
//{0x060803, 750},
|
|
//{0x060803, 800},
|
|
//{0x060803, 850},
|
|
//{0x060803, 866},
|
|
//{0x060803, 933},
|
|
{0x060803, 1000},
|
|
//{0x060806, 600},
|
|
//{0x060806, 650},
|
|
//{0x060806, 667},
|
|
//{0x060806, 700},
|
|
//{0x060806, 733},
|
|
//{0x060806, 750},
|
|
//{0x060806, 800},
|
|
//{0x060806, 850},
|
|
//{0x060806, 866},
|
|
//{0x060806, 900},
|
|
//{0x060806, 933},
|
|
{0x060806, 1000},
|
|
//{0x06080A, 700},
|
|
//{0x06080A, 733},
|
|
//{0x06080A, 750},
|
|
//{0x06080A, 800},
|
|
//{0x06080A, 850},
|
|
//{0x06080A, 866},
|
|
//{0x06080A, 933},
|
|
//{0x06080A, 1100},
|
|
{0x06080A, 1130},
|
|
//{0x060B01, 1000},
|
|
//{0x060B01, 1130},
|
|
//{0x060B01, 1200},
|
|
{0x060B01, 1260},
|
|
{0, 0},
|
|
};
|
|
PROCESSORINFO ProcInfo;
|
|
ULONG Processor;
|
|
ULONG64 Prcb;
|
|
HRESULT Hr;
|
|
ULONG Mhz;
|
|
ULONG Number;
|
|
ULONG CpuType;
|
|
ULONG CpuStep;
|
|
DEBUG_PROCESSOR_IDENTIFICATION_ALL IdAll;
|
|
|
|
if (g_TargetMachine != IMAGE_FILE_MACHINE_I386)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Ioctl(IG_KD_CONTEXT, &ProcInfo, sizeof(ProcInfo)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Processor = ProcInfo.Processor;
|
|
|
|
Hr = g_ExtData->ReadProcessorSystemData(Processor,
|
|
DEBUG_DATA_KPRCB_OFFSET,
|
|
&Prcb,
|
|
sizeof(Prcb),
|
|
NULL);
|
|
if (Hr != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_ExtData->
|
|
ReadProcessorSystemData(Processor,
|
|
DEBUG_DATA_PROCESSOR_IDENTIFICATION,
|
|
&IdAll, sizeof(IdAll), NULL) != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_ExtData->
|
|
ReadProcessorSystemData(Processor,
|
|
DEBUG_DATA_PROCESSOR_SPEED,
|
|
&Mhz, sizeof(Mhz), NULL) != S_OK)
|
|
{
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
{
|
|
ULONG Speed;
|
|
ULONG CpuId;
|
|
|
|
CpuId = (IdAll.X86.Family << 16) + (IdAll.X86.Model << 8) + IdAll.X86.Stepping;
|
|
|
|
if (!strcmp(IdAll.X86.VendorString, "GenuineIntel"))
|
|
{
|
|
for (ULONG i=0; IntelSpeeds[i].CpuId !=0; ++i)
|
|
{
|
|
if (IntelSpeeds[i].CpuId == CpuId)
|
|
{
|
|
//
|
|
// If the part is within 2% of the MHz, it's OK.
|
|
//
|
|
if (Mhz > (IntelSpeeds[i].Mhz * 1.02))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ExtGetPoolData(
|
|
ULONG64 Pool,
|
|
PDEBUG_POOL_DATA pPoolData
|
|
)
|
|
{
|
|
PGET_POOL_DATA pGetPoolData = NULL;
|
|
|
|
if (g_ExtControl->
|
|
GetExtensionFunction(0, "GetPoolData",
|
|
(FARPROC*)&pGetPoolData) == S_OK &&
|
|
pGetPoolData)
|
|
{
|
|
return (*pGetPoolData)(g_ExtClient, Pool, pPoolData);
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
#define DECL_GETINFO(bcname) \
|
|
void \
|
|
GetInfoFor##bcname ( \
|
|
PBUGCHECK_ANALYSIS Bc, \
|
|
KernelDebugFailureAnalysis* Analysis \
|
|
)
|
|
|
|
|
|
//DUPINFOCASE( DRIVER_IRQL_NOT_LESS_OR_EQUAL ); //0xD1
|
|
DECL_GETINFO( IRQL_NOT_LESS_OR_EQUAL ) // (0xA)
|
|
/*
|
|
* Parameters
|
|
*
|
|
* Parameter 1 Memory referenced
|
|
* Parameter 2 IRQL Value
|
|
* Parameter 3 0 - Read 1 - Write
|
|
* Parameter 4 Address that referenced the memory
|
|
*
|
|
*
|
|
* Special Case
|
|
*
|
|
* If Parameter 3 is nonzero and equal to Parameter 1, this means that
|
|
* a worker routine returned at a raised IRQL.
|
|
* In this case:
|
|
*
|
|
* Parameter 1 Address of work routine
|
|
* Parameter 2 IRQL at time of reference
|
|
* Parameter 3 Address of work routine
|
|
* Parameter 4 Work item
|
|
*
|
|
*/
|
|
{
|
|
if ((Bc->Args[0] == Bc->Args[2]) && Bc->Args[2])
|
|
{
|
|
// special case
|
|
Analysis->SetUlong64(DEBUG_FLR_WORKER_ROUTINE, Bc->Args[2]);
|
|
Analysis->SetUlong64(DEBUG_FLR_WORK_ITEM, Bc->Args[3]);
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
return;
|
|
}
|
|
|
|
Analysis->SetUlong64(Bc->Args[2] ?
|
|
DEBUG_FLR_WRITE_ADDRESS : DEBUG_FLR_READ_ADDRESS,
|
|
Bc->Args[0]);
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, Bc->Args[3]);
|
|
|
|
if (Bc->Args[0] == Bc->Args[3] &&
|
|
Bc->Args[2] == 0)
|
|
{
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_SPECIFIER, "_CODE_AV");
|
|
}
|
|
|
|
}
|
|
|
|
DECL_GETINFO( MEMORY_MANAGEMENT ) // 0x1A
|
|
{
|
|
CHAR BugCheckStr[20];
|
|
|
|
sprintf(BugCheckStr, "0x%lx_%lx", Bc->Code, Bc->Args[0]);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
}
|
|
|
|
|
|
DECL_GETINFO( KMODE_EXCEPTION_NOT_HANDLED ) // (1e)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_CODE, Bc->Args[0]);
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_PARAMETER1, Bc->Args[2]);
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_PARAMETER2, Bc->Args[3]);
|
|
if ((ULONG)Bc->Args[0] == STATUS_ACCESS_VIOLATION)
|
|
{
|
|
Analysis->SetUlong64(Bc->Args[2] ?
|
|
DEBUG_FLR_WRITE_ADDRESS : DEBUG_FLR_READ_ADDRESS,
|
|
Bc->Args[3]);
|
|
}
|
|
}
|
|
|
|
|
|
DECL_GETINFO( FAT_FILE_SYSTEM ) // 0x23
|
|
{
|
|
ULONG64 ExR = 0, CxR = 0;
|
|
ULONG64 KernAddrStart;
|
|
|
|
|
|
KernAddrStart = BcTargetKernelAddressStart();
|
|
|
|
if (Bc->Args[1] > KernAddrStart) {
|
|
ExR = Bc->Args[1];
|
|
}
|
|
if (Bc->Args[2] > KernAddrStart) {
|
|
CxR = Bc->Args[2];
|
|
}
|
|
|
|
if (ExR) {
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_RECORD, ExR);
|
|
}
|
|
if (CxR) {
|
|
Analysis->SetUlong64(DEBUG_FLR_CONTEXT, CxR);
|
|
}
|
|
}
|
|
|
|
DECL_GETINFO( PANIC_STACK_SWITCH ) // 0x2b
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_TRAP_FRAME, Bc->Args[0]);
|
|
}
|
|
|
|
DECL_GETINFO( SYSTEM_SERVICE_EXCEPTION ) // 0x3b
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_CONTEXT, Bc->Args[2]);
|
|
}
|
|
|
|
DECL_GETINFO( MULTIPLE_IRP_COMPLETE_REQUESTS ) // 0x44
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_IRP_ADDRESS, Bc->Args[0]);
|
|
}
|
|
|
|
DECL_GETINFO( SESSION3_INITIALIZATION_FAILED ) // 0x6f
|
|
{
|
|
CHAR BugCheckStr[20];
|
|
|
|
sprintf(BugCheckStr, "0x%lX_%lX", Bc->Code, Bc->Args[0]);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
}
|
|
|
|
|
|
DECL_GETINFO( PROCESS_HAS_LOCKED_PAGES ) // 0x76
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_PROCESS_OBJECT, Bc->Args[1]);
|
|
|
|
Analysis->SetString(DEBUG_FLR_DEFAULT_BUCKET_ID, "DRIVER_FAULT_0x76");
|
|
|
|
#if 0
|
|
Analysis->SetString(DEBUG_FLR_INTERNAL_SOLUTION_TEXT,
|
|
"An unknown driver has left locked pages in the kernel"
|
|
".\nUsing the registry editor, set HKLM\\SYSTEM\\"
|
|
"CurrentControlSet\\Control\\Session Manager\\"
|
|
"Memory Management\\TrackLockedPages to a DWORD value"
|
|
" of 1, and then reboot the machine.\n\n"
|
|
"If the problem reproduces, the "
|
|
"guilty driver will now be identifiable.\n");
|
|
#endif
|
|
}
|
|
|
|
|
|
DECL_GETINFO( KERNEL_STACK_INPAGE_ERROR ) // 0x77
|
|
{
|
|
CHAR BugCheckStr[20];
|
|
|
|
sprintf(BugCheckStr, "0x%lx_%lx", Bc->Code, Bc->Args[0]);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
Analysis->SetUlong(DEBUG_FLR_STATUS_CODE, (ULONG)Bc->Args[0]);
|
|
|
|
switch ((ULONG) Bc->Args[0])
|
|
{
|
|
case 0xc000009c: // (STATUS_DEVICE_DATA_ERROR)
|
|
case 0xC000016A: // (STATUS_DISK_OPERATION_FAILED)
|
|
Analysis->SetUlong(DEBUG_FLR_DISK_HARDWARE_ERROR, 1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
DECL_GETINFO( KERNEL_DATA_INPAGE_ERROR ) // 0x7A
|
|
{
|
|
CHAR BugCheckStr[20];
|
|
|
|
sprintf(BugCheckStr, "0x%lx_%lx", Bc->Code, Bc->Args[1]);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
Analysis->SetUlong(DEBUG_FLR_STATUS_CODE, (ULONG) Bc->Args[1]);
|
|
|
|
switch ( (ULONG) Bc->Args[1])
|
|
{
|
|
case 0xC000000E: case 0xC000009C:
|
|
case 0xC000009D: case 0xC0000185:
|
|
Analysis->SetUlong(DEBUG_FLR_DISK_HARDWARE_ERROR, 1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
DECL_GETINFO( SYSTEM_THREAD_EXCEPTION_NOT_HANDLED ) // (7e)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_CODE, Bc->Args[0]);
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_PARAMETER1, Bc->Args[2]);
|
|
Analysis->SetUlong64(DEBUG_FLR_CONTEXT, Bc->Args[3]);
|
|
}
|
|
|
|
DECL_GETINFO( BUGCODE_NDIS_DRIVER ) //0x7c
|
|
{
|
|
ULONG64 DriverAddr, DriverBase;
|
|
|
|
DriverAddr = 0;
|
|
|
|
g_ExtSymbols->Reload("ndis.sys");
|
|
switch (Bc->Args[0])
|
|
{
|
|
case 1: case 2: case 3:
|
|
case 5: case 6: case 7: case 8: case 9:
|
|
// Args[1] - A pointer to Miniport block. !ndiskd.miniport on this pointer for more info.
|
|
GetFieldValue(Bc->Args[1], "ndis!NDIS_MINIPORT_BLOCK", "SavedSendHandler", DriverAddr);
|
|
if (!DriverAddr)
|
|
{
|
|
GetFieldValue(Bc->Args[1], "ndis!NDIS_MINIPORT_BLOCK", "SavedSendPacketsHandler", DriverAddr);
|
|
}
|
|
break;
|
|
case 4:
|
|
// Arg[1] - a pointer to ndis!NDIS_M_DRIVER_BLOCK
|
|
|
|
GetFieldValue(Bc->Args[1], "ndis!NDIS_M_DRIVER_BLOCK", "MiniportCharacteristics.InitializeHandler", DriverAddr);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (DriverAddr &&
|
|
(g_ExtSymbols->GetModuleByOffset(DriverAddr, 0, NULL, &DriverBase) == S_OK))
|
|
{
|
|
if (DriverBase)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_MODULE, DriverBase);
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
DECL_GETINFO( UNEXPECTED_KERNEL_MODE_TRAP ) // (7f)
|
|
// It would be good to have TSS or TRAP address as exception parameter
|
|
{
|
|
DEBUG_STACK_FRAME stk[MAX_STACK_FRAMES];
|
|
ULONG frames, i;
|
|
CHAR BugCheckStr[20];
|
|
|
|
sprintf(BugCheckStr, "0x%lx_%lx", Bc->Code, Bc->Args[0]);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
|
|
if ((g_TargetMachine == IMAGE_FILE_MACHINE_I386) &&
|
|
(g_ExtControl->GetStackTrace(0, 0, 0, stk, MAX_STACK_FRAMES,
|
|
&frames ) == S_OK))
|
|
{
|
|
for (i=0; i<frames; ++i)
|
|
{
|
|
if (stk[i].FuncTableEntry)
|
|
{
|
|
PFPO_DATA FpoData = (PFPO_DATA)stk[i].FuncTableEntry;
|
|
if (FpoData->cbFrame == FRAME_TSS)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_TSS,
|
|
(ULONG)stk[i].Reserved[1]);
|
|
break;
|
|
}
|
|
// KiSystemService always has a trap frame - thats normal
|
|
else if ( (FpoData->cbFrame == FRAME_TRAP) &&
|
|
!FaIsFunctionAddr(stk[i].InstructionOffset,
|
|
"KiSystemService"))
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_TRAP_FRAME,
|
|
(ULONG)stk[i].Reserved[2]);
|
|
break;
|
|
}
|
|
//if (FaIsFunctionAddr(stk[i].InstructionOffset, "KiTrap"))
|
|
//{
|
|
// TrapFrame = stk[i].FrameOffset;
|
|
// break;
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DECL_GETINFO( KERNEL_MODE_EXCEPTION_NOT_HANDLED ) // (8e)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_CODE, Bc->Args[0]);
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_TRAP_FRAME, Bc->Args[2]);
|
|
}
|
|
|
|
DECL_GETINFO( MACHINE_CHECK_EXCEPTION ) // 0x9C
|
|
{
|
|
DEBUG_PROCESSOR_IDENTIFICATION_ALL IdAll;
|
|
CHAR BugCheckStr[4+5+17+3]; // space for vendor string, etc.
|
|
PROCESSORINFO ProcInfo;
|
|
ULONG64 Prcb;
|
|
PCHAR Architecture;
|
|
PCHAR Vendor;
|
|
ULONG Processor;
|
|
HRESULT Hr;
|
|
|
|
if (!Ioctl(IG_KD_CONTEXT, &ProcInfo, sizeof(ProcInfo)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Processor = ProcInfo.Processor;
|
|
|
|
//
|
|
// Make sure we can find the PRCB before we ask for identification
|
|
// information that would've been acquired from the PRCB.
|
|
//
|
|
|
|
Hr = g_ExtData->ReadProcessorSystemData(Processor,
|
|
DEBUG_DATA_KPRCB_OFFSET,
|
|
&Prcb,
|
|
sizeof(Prcb),
|
|
NULL);
|
|
if (Hr != S_OK)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Hr = g_ExtData->ReadProcessorSystemData(Processor,
|
|
DEBUG_DATA_PROCESSOR_IDENTIFICATION,
|
|
&IdAll,
|
|
sizeof(IdAll),
|
|
NULL);
|
|
if (Hr != S_OK)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (g_TargetMachine) {
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
Architecture = "IA32";
|
|
Vendor = IdAll.X86.VendorString;
|
|
break;
|
|
case IMAGE_FILE_MACHINE_IA64:
|
|
Architecture = "IA64";
|
|
Vendor = IdAll.Ia64.VendorString;
|
|
break;
|
|
case IMAGE_FILE_MACHINE_AMD64:
|
|
Architecture = "AMD64";
|
|
Vendor = IdAll.Amd64.VendorString;
|
|
break;
|
|
default:
|
|
// use the standard bugcheck string
|
|
return;
|
|
}
|
|
sprintf(BugCheckStr, "0x%lX_%s_%s", Bc->Code, Architecture, Vendor);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
}
|
|
|
|
DECL_GETINFO( USER_MODE_HEALTH_MONITOR ) // 0x9E
|
|
{
|
|
if (Bc->Args[0])
|
|
{
|
|
ULONG result;
|
|
CHAR ImageName[MAX_PATH];
|
|
|
|
Analysis->SetUlong64(DEBUG_FLR_PROCESS_OBJECT, Bc->Args[0]);
|
|
|
|
//
|
|
// Second parameter (which is actually a string within the EPROCESS)
|
|
// is the name of the image.
|
|
//
|
|
if (ReadMemory(Bc->Args[2], ImageName, sizeof(ImageName), &result) &&
|
|
result)
|
|
{
|
|
ImageName[MAX_PATH-1]=0;
|
|
ImageName[result]=0;
|
|
SaveImageName(Analysis, ImageName);
|
|
}
|
|
}
|
|
}
|
|
|
|
DECL_GETINFO( DRIVER_POWER_STATE_FAILURE ) // 0x9F
|
|
{
|
|
ULONG64 DevObj = Bc->Args[2];
|
|
ULONG64 DrvObj = Bc->Args[3];
|
|
ULONG SubCode = (ULONG) Bc->Args[0];
|
|
|
|
if (SubCode)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_DRVPOWERSTATE_SUBCODE, SubCode);
|
|
}
|
|
|
|
if (DrvObj)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_DRIVER_OBJECT, DrvObj);
|
|
BcGetDriverNameFromIrp(Analysis, 0, 0, DrvObj);
|
|
}
|
|
|
|
if (DevObj)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_DEVICE_OBJECT, DevObj);
|
|
if (!DrvObj)
|
|
{
|
|
BcGetDriverNameFromIrp(Analysis, 0, DevObj, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
DECL_GETINFO( ACPI_BIOS_ERROR ) // 0xa5
|
|
{
|
|
switch (Bc->Args[0])
|
|
{
|
|
case 0x03 :
|
|
Analysis->SetUlong64(DEBUG_FLR_ACPI_OBJECT, Bc->Args[1]);
|
|
break;
|
|
|
|
case 0x04 :
|
|
case 0x05 :
|
|
case 0x06 :
|
|
case 0x07 :
|
|
case 0x08 :
|
|
case 0x09 :
|
|
case 0x0A :
|
|
case 0x0C :
|
|
Analysis->SetUlong64(DEBUG_FLR_ACPI_OBJECT, Bc->Args[2]);
|
|
// fallthrough
|
|
|
|
case 0x01 :
|
|
case 0x02 :
|
|
case 0x0B :
|
|
case 0x0D :
|
|
case 0x10 :
|
|
Analysis->SetUlong64(DEBUG_FLR_ACPI_EXTENSION, Bc->Args[1]);
|
|
break;
|
|
|
|
case 0x11 :
|
|
if (Bc->Args[1] == 6)
|
|
{
|
|
// The machine fail to transition into ACPI mode
|
|
CHAR BugCheckStr[40];
|
|
|
|
sprintf(BugCheckStr, "0x%lx_FAILED_ACPI_TRANSITION", Bc->Code);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
}
|
|
break;
|
|
case 0x10001 :
|
|
case 0x10002 :
|
|
case 0x10003 :
|
|
Analysis->SetUlong64(DEBUG_FLR_DEVICE_OBJECT, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_ACPI_OBJECT, Bc->Args[3]);
|
|
break;
|
|
|
|
case 0x10005 :
|
|
case 0x10006 :
|
|
Analysis->SetUlong64(DEBUG_FLR_ACPI_OBJECT, Bc->Args[1]);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
DECL_GETINFO( SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION ) // (c1)
|
|
{
|
|
Analysis->SetUlong(DEBUG_FLR_ANALYZAABLE_POOL_CORRUPTION, 1);
|
|
Analysis->SetUlong64(DEBUG_FLR_SPECIAL_POOL_CORRUPTION_TYPE, Bc->Args[3]);
|
|
}
|
|
|
|
|
|
DECL_GETINFO( BAD_POOL_CALLER ) // 0xC2
|
|
{
|
|
DEBUG_POOL_DATA PoolData = {0};
|
|
CHAR BugcheckStr[20] = {0};
|
|
|
|
sprintf(BugcheckStr, "0x%lx_%lx", BAD_POOL_CALLER, (ULONG) Bc->Args[0]);
|
|
if (Bc->Args[0] == 7)
|
|
{
|
|
// Double free
|
|
if (!(Bc->Args[3] & 0x7))
|
|
{
|
|
// likely to be a valid address
|
|
|
|
Analysis->SetUlong(DEBUG_FLR_ANALYZAABLE_POOL_CORRUPTION, 1);
|
|
|
|
PoolData.SizeofStruct = sizeof(DEBUG_POOL_DATA);
|
|
|
|
if (ExtGetPoolData(Bc->Args[3], &PoolData) == S_OK)
|
|
{
|
|
if (isprint(PoolData.PoolTag & 0xff) &&
|
|
isprint((PoolData.PoolTag >> 8) & 0xff))
|
|
{
|
|
CHAR PoolTag[8] = {0};
|
|
sprintf(PoolTag,"%c%c%c%c",
|
|
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
|
PP(PoolData.PoolTag),
|
|
PP(PoolData.PoolTag >> 8),
|
|
PP(PoolData.PoolTag >> 16),
|
|
PP((PoolData.PoolTag&~0x80000000) >> 24)
|
|
#undef PP
|
|
);
|
|
// seems like a valid pooltag
|
|
Analysis->SetString(DEBUG_FLR_FREED_POOL_TAG, PoolTag);
|
|
CatString(BugcheckStr, "_", sizeof(BugcheckStr));
|
|
CatString(BugcheckStr, PoolTag, sizeof(BugcheckStr));
|
|
}
|
|
}
|
|
|
|
}
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugcheckStr);
|
|
}
|
|
else if ((Bc->Args[0] >= 0x40) && (Bc->Args[0] < 0x60))
|
|
{
|
|
if (Bc->Args[1] == 0)
|
|
{
|
|
Analysis->SetUlong(DEBUG_FLR_ANALYZAABLE_POOL_CORRUPTION, 1);
|
|
}
|
|
} else
|
|
{
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugcheckStr);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
DECL_GETINFO( DRIVER_VERIFIER_DETECTED_VIOLATION ) // 0xC4
|
|
/*
|
|
* Parameters
|
|
*
|
|
* Parameter 1 subclass of violation
|
|
* Parameter 2, 3, 4 vary depending on parameter 1
|
|
*
|
|
*/
|
|
{
|
|
ULONG64 BadDriverAddr;
|
|
ULONG64 DriverNameAddr;
|
|
ULONG res;
|
|
ULONG ParamCount = 0;
|
|
|
|
CHAR BugCheckStr[20];
|
|
|
|
sprintf(BugCheckStr, "0x%lx_%lx", Bc->Code, Bc->Args[0]);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
|
|
|
|
Analysis->SetUlong(DEBUG_FLR_ANALYZAABLE_POOL_CORRUPTION, 1);
|
|
|
|
if ((BadDriverAddr = GetExpression("nt!ViBadDriver")) &&
|
|
ReadPointer(BadDriverAddr, &DriverNameAddr))
|
|
{
|
|
AddBugcheckDriver(Analysis, TRUE, TRUE, DriverNameAddr);
|
|
}
|
|
|
|
switch (Bc->Args[0])
|
|
{
|
|
case 0x00 : // caller is trying to allocate zero bytes
|
|
case 0x01 : // caller is trying to allocate paged pool at DISPATCH_LEVEL or above
|
|
case 0x02 : // caller is trying to allocate nonpaged pool at an IRQL above DISPATCH_LEVEL
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
// 3 - pool type
|
|
// 4 - number of bytes
|
|
break;
|
|
case 0x03 : // caller is trying to allocate more than one page of mustsucceed pool, but one page is the maximum allowed by this API.
|
|
break;
|
|
|
|
case 0x10 : // caller is freeing a bad pool address
|
|
Analysis->SetUlong64(DEBUG_FLR_POOL_ADDRESS, Bc->Args[1]); // bad pool address
|
|
break;
|
|
|
|
case 0x11 : // caller is trying to free paged pool at DISPATCH_LEVEL or above
|
|
case 0x12 : // caller is trying to free nonpaged pool at an IRQL above DISPATCH_LEVEL
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_POOL_ADDRESS, Bc->Args[3]);
|
|
// 3 - pool type
|
|
break;
|
|
|
|
case 0x13 : // the pool the caller is trying to free is already free.
|
|
case 0x14 : // the pool the caller is trying to free is already free.
|
|
// 2 - line number
|
|
// 3 - pool header
|
|
// 4 - pool header contents
|
|
Analysis->SetUlong64(DEBUG_FLR_POOL_ADDRESS, Bc->Args[3]);
|
|
break;
|
|
|
|
case 0x15 : // the pool the caller is trying to free contains an active timer.
|
|
// 2 - timer entry
|
|
// 3 - pool type
|
|
// 4 - pool address being freed
|
|
Analysis->SetUlong64(DEBUG_FLR_POOL_ADDRESS, Bc->Args[3]);
|
|
break;
|
|
|
|
case 0x16 : // the pool the caller is trying to free is a bad address.
|
|
Analysis->SetUlong64(DEBUG_FLR_POOL_ADDRESS, Bc->Args[2]);
|
|
break;
|
|
// 2 - line number
|
|
|
|
case 0x17 : // the pool the caller is trying to free contains an active ERESOURCE.
|
|
// 2 - resource entry
|
|
// 3 - pool type
|
|
Analysis->SetUlong64(DEBUG_FLR_POOL_ADDRESS, Bc->Args[3]);
|
|
break;
|
|
|
|
case 0x30 : // raising IRQL to an invalid level,
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_REQUESTED_IRQL, Bc->Args[2]);
|
|
break;
|
|
|
|
case 0x31 : // lowering IRQL to an invalid level,
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_REQUESTED_IRQL, Bc->Args[2]);
|
|
// 4 - 0 means the new IRQL is bad, 1 means the IRQL is invalid inside a DPC routine
|
|
break;
|
|
|
|
case 0x32 : // releasing a spinlock when not at DISPATCH_LEVEL.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
// 3 - spinlock address
|
|
break;
|
|
|
|
case 0x33 : // acquiring a fast mutex when not at APC_LEVEL or below.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
break;
|
|
// 3 - fast mutex address
|
|
|
|
case 0x34 : // releasing a fast mutex when not at APC_LEVEL.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
break;
|
|
// 3 - thread APC disable count, 4 == fast mutex address
|
|
|
|
case 0x35 : // kernel is releasing a spinlock when not at DISPATCH_LEVEL.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_PREVIOUS_IRQL, Bc->Args[3]);
|
|
break;
|
|
// 3 - spinlock address, 4 == old irql.
|
|
|
|
case 0x36 : // kernel is releasing a queued spinlock when not at DISPATCH_LEVEL.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_PREVIOUS_IRQL, Bc->Args[3]);
|
|
break;
|
|
// 3 - spinlock number,
|
|
|
|
case 0x37 : // a resource is being acquired but APCs are not disabled.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
break;
|
|
// 3 - thread APC disable count,
|
|
// 4 - resource.
|
|
|
|
case 0x38 : // a resource is being released but APCs are not disabled.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
break;
|
|
// 3 - thread APC disable count,
|
|
// 4 - resource.
|
|
|
|
case 0x39 : // a mutex is being acquired unsafe, but irql is not APC_LEVEL on entry.
|
|
case 0x3A : // a mutex is being released unsafe, but irql is not APC_LEVEL on entry.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
break;
|
|
// 3 - thread APC disable count,
|
|
// 4 - mutex.
|
|
|
|
case 0x3B : // KeWaitXxx routine is being called at DISPATCH_LEVEL or higher.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
break;
|
|
// 3 - object to wait on,
|
|
// 4 - time out parameter.
|
|
|
|
case 0x3E : // KeLeaveCriticalRegion is being called for a thread that never entered a critical region.
|
|
// Current stack analysis will give followup
|
|
break;
|
|
|
|
case 0x40 : // acquiring a spinlock when not at DISPATCH_LEVEL.
|
|
case 0x41 : // releasing a spinlock when not at DISPATCH_LEVEL.
|
|
case 0x42 : // acquiring a spinlock when caller is already above DISPATCH_LEVEL.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
break;
|
|
// 3 - spinlock address
|
|
|
|
case 0x51 : // freeing memory where the caller has written past the end of the allocation overwriting our stored bytecount.
|
|
case 0x52 : // freeing memory where the caller has written past the end of the allocation overwriting our stored virtual address.
|
|
case 0x53 : // freeing memory where the caller has written past the end of the allocation overwriting our stored virtual address.
|
|
case 0x54 : // freeing memory where the caller has written past the end of the allocation overwriting our stored virtual address.
|
|
case 0x59 : // freeing memory where the caller has written past the end of the allocation overwriting our stored virtual address.
|
|
Analysis->SetUlong64(DEBUG_FLR_WRITE_ADDRESS, Bc->Args[1]);
|
|
break;
|
|
|
|
case 0x60 : // A driver has forgotten to free its pool allocations prior to unloading.
|
|
case 0x61 : // A driver is unloading and allocating memory (in another thread) at the same time.
|
|
// In both cases ViBadDriver should be set.
|
|
break;
|
|
|
|
case 0x70 : // MmProbeAndLockPages called when not at DISPATCH_LEVEL or below.
|
|
case 0x71 : // MmProbeAndLockProcessPages called when not at DISPATCH_LEVEL or below.
|
|
case 0x72 : // MmProbeAndLockSelectedPages called when not at DISPATCH_LEVEL or below.
|
|
case 0x73 : // MmMapIoSpace called when not at DISPATCH_LEVEL or below.
|
|
case 0x74 : // MmMapLockedPages called when not at DISPATCH_LEVEL or below.
|
|
case 0x75 : // MmMapLockedPages called when not at APC_LEVEL or below.
|
|
case 0x76 : // MmMapLockedPagesSpecifyCache called when not at DISPATCH_LEVEL or below.
|
|
case 0x77 : // MmMapLockedPagesSpecifyCache called when not at APC_LEVEL or below.
|
|
case 0x78 : // MmUnlockPages called when not at DISPATCH_LEVEL or below.
|
|
case 0x79 : // MmUnmapLockedPages called when not at DISPATCH_LEVEL or below.
|
|
case 0x7A : // MmUnmapLockedPages called when not at APC_LEVEL or below.
|
|
case 0x7B : // MmUnmapIoSpace called when not at APC_LEVEL or below.
|
|
case 0x7C : // MmUnlockPages called with an MDL whose pages were never successfully locked.
|
|
case 0x7D : // MmUnlockPages called with an MDL whose pages are from nonpaged pool - these should never be unlocked.
|
|
case 0x80 : // KeSetEvent called when not at DISPATCH_LEVEL or below.
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
break;
|
|
|
|
case 0x81 : // MmMapLockedPages called without MDL_MAPPING_CAN_FAIL
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
DECL_GETINFO( DRIVER_CAUGHT_MODIFYING_FREED_POOL ) // (c6)
|
|
/*
|
|
An attempt was made to access freed pool memory. The faulty component is
|
|
displayed in the current kernel stack.
|
|
Arguments:
|
|
Arg1: memory referenced
|
|
Arg2: value 0 = read operation, 1 = write operation
|
|
Arg3: previous mode.
|
|
Arg4: 4.
|
|
*/
|
|
{
|
|
DEBUG_POOL_DATA PoolData;
|
|
|
|
Analysis->SetUlong64(Bc->Args[1] ?
|
|
DEBUG_FLR_WRITE_ADDRESS : DEBUG_FLR_READ_ADDRESS,
|
|
Bc->Args[0]);
|
|
Analysis->SetUlong64(DEBUG_FLR_PREVIOUS_MODE, Bc->Args[2]);
|
|
}
|
|
|
|
DECL_GETINFO( TIMER_OR_DPC_INVALID ) // (c7)
|
|
/*
|
|
*
|
|
* This is issued if a kernel timer or DPC is found somewhere in
|
|
* memory where it is not permitted.
|
|
*
|
|
* Bugcheck Parameters
|
|
*
|
|
* Parameter 1 0: Timer object 1: DPC object 2: DPC routine
|
|
* Parameter 2 Address of object
|
|
* Parameter 3 Beginning of memory range checked
|
|
* Parameter 4 End of memory range checked
|
|
*
|
|
* This condition is usually caused by a driver failing to cancel a
|
|
* timer or DPC before freeing the memory where it resides.
|
|
*/
|
|
{
|
|
|
|
ULONG PtrSize = IsPtr64() ? 8 : 4;
|
|
ULONG64 ObjAddress;
|
|
CHAR Buffer[MAX_PATH];
|
|
ULONG64 Disp;
|
|
|
|
ObjAddress = Bc->Args[1];
|
|
|
|
switch (Bc->Args[0]) {
|
|
case 0: //Timer object
|
|
ULONG DpcOffsetInTimer;
|
|
if (GetFieldOffset("nt!_KTIMER", "Dpc", &DpcOffsetInTimer))
|
|
{
|
|
// we don't have types
|
|
DpcOffsetInTimer = 0x10 + PtrSize*4;
|
|
}
|
|
if (!ReadPointer(ObjAddress + DpcOffsetInTimer, &ObjAddress))
|
|
{
|
|
// fail
|
|
break;
|
|
}
|
|
// Fall thru
|
|
case 1:
|
|
ULONG DeferredRoutinOffsetInKDPC;
|
|
if (GetFieldOffset("nt!_KDPC", "DeferredRoutine", &DeferredRoutinOffsetInKDPC))
|
|
{
|
|
DeferredRoutinOffsetInKDPC = 4 + PtrSize*2;
|
|
}
|
|
if (!ReadPointer(ObjAddress + DeferredRoutinOffsetInKDPC, &ObjAddress))
|
|
{
|
|
// fail
|
|
break;
|
|
}
|
|
// Fall thru
|
|
case 2:
|
|
|
|
if (FaGetSymbol(ObjAddress, Buffer, &Disp, sizeof(Buffer)))
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_INVALID_DPC_FOUND, ObjAddress);
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, ObjAddress);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
DECL_GETINFO( DRIVER_VERIFIER_IOMANAGER_VIOLATION ) // (c9)
|
|
{
|
|
ULONG64 DeviceObject = 0;
|
|
|
|
Analysis->SetUlong64(DEBUG_FLR_DRIVER_VERIFIER_IO_VIOLATION_TYPE,
|
|
Bc->Args[0]);
|
|
|
|
switch (Bc->Args[0])
|
|
{
|
|
case 0x1:
|
|
// "Invalid IRP passed to IoFreeIrp";
|
|
case 0x2:
|
|
// "IRP still associated with a thread at IoFreeIrp";
|
|
case 0x3:
|
|
// "Invalid IRP passed to IoCallDriver";
|
|
Analysis->SetUlong64(DEBUG_FLR_IRP_ADDRESS, Bc->Args[1]);
|
|
break;
|
|
|
|
case 0x4:
|
|
// "Invalid Device object passed to IoCallDriver";
|
|
DeviceObject = Bc->Args[1];
|
|
break;
|
|
|
|
case 0x5:
|
|
// "Irql not equal across call to the driver dispatch routine"
|
|
DeviceObject = Bc->Args[1];
|
|
Analysis->SetUlong64(DEBUG_FLR_PREVIOUS_IRQL, Bc->Args[2]);
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[3]);
|
|
break;
|
|
|
|
case 0x6:
|
|
// "IRP passed to IoCompleteRequest contains invalid status"
|
|
// Param 1 = "the status";
|
|
Analysis->SetUlong64(DEBUG_FLR_IRP_ADDRESS, Bc->Args[2]);
|
|
break;
|
|
|
|
case 0x7:
|
|
// "IRP passed to IoCompleteRequest still has cancel routine"
|
|
Analysis->SetUlong64(DEBUG_FLR_IRP_CANCEL_ROUTINE, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_IRP_ADDRESS, Bc->Args[2]);
|
|
break;
|
|
|
|
case 0x8:
|
|
// "Call to IoBuildAsynchronousFsdRequest threw an exce
|
|
DeviceObject = Bc->Args[1];
|
|
Analysis->SetUlong64(DEBUG_FLR_IRP_MAJOR_FN, Bc->Args[2]);
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_CODE, Bc->Args[3]);
|
|
break;
|
|
|
|
case 0x9:
|
|
// "Call to IoBuildDeviceIoControlRequest threw an exce
|
|
DeviceObject = Bc->Args[1];
|
|
Analysis->SetUlong64(DEBUG_FLR_IOCONTROL_CODE, Bc->Args[2]);
|
|
Analysis->SetUlong64(DEBUG_FLR_EXCEPTION_CODE, Bc->Args[3]);
|
|
break;
|
|
|
|
case 0x10:
|
|
// "Reinitialization of Device object timer";
|
|
DeviceObject = Bc->Args[1];
|
|
break;
|
|
|
|
case 0x12:
|
|
// "Invalid IOSB in IRP at APC IopCompleteRequest (appe
|
|
Analysis->SetUlong64(DEBUG_FLR_IOSB_ADDRESS, Bc->Args[1]);
|
|
break;
|
|
|
|
case 0x13:
|
|
// "Invalid UserEvent in IRP at APC IopCompleteRequest
|
|
Analysis->SetUlong64(DEBUG_FLR_INVALID_USEREVENT, Bc->Args[1]);
|
|
break;
|
|
|
|
case 0x14:
|
|
// "Irql > DPC at IoCompleteRequest";
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_IRP_ADDRESS, Bc->Args[2]);
|
|
break;
|
|
|
|
}
|
|
|
|
if (DeviceObject)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_DEVICE_OBJECT, DeviceObject);
|
|
BcGetDriverNameFromIrp(Analysis, 0, DeviceObject, 0);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
DECL_GETINFO( PNP_DETECTED_FATAL_ERROR ) // 0xca
|
|
{
|
|
CHAR BugCheckStr[20];
|
|
ULONG64 DeviceObject;
|
|
|
|
sprintf(BugCheckStr, "0x%lX_%lX", Bc->Code, Bc->Args[0]);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
DeviceObject = Bc->Args[1];
|
|
|
|
if (DeviceObject)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_DEVICE_OBJECT, DeviceObject);
|
|
BcGetDriverNameFromIrp(Analysis, 0, DeviceObject, 0);
|
|
}
|
|
|
|
}
|
|
|
|
DECL_GETINFO( DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS ) // 0xcb
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_MODULE, Bc->Args[0]);
|
|
}
|
|
|
|
DECL_GETINFO( DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS ) //0xce
|
|
{
|
|
Analysis->SetUlong64(Bc->Args[1] ?
|
|
DEBUG_FLR_WRITE_ADDRESS : DEBUG_FLR_READ_ADDRESS,
|
|
Bc->Args[0]);
|
|
if (Bc->Args[2]) {
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, Bc->Args[2]);
|
|
}
|
|
}
|
|
|
|
DECL_GETINFO( DRIVER_CORRUPTED_MMPOOL ) // 0xd0
|
|
{
|
|
Analysis->SetUlong64(Bc->Args[2] ?
|
|
DEBUG_FLR_WRITE_ADDRESS : DEBUG_FLR_READ_ADDRESS,
|
|
Bc->Args[0]);
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Bc->Args[1]);
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, Bc->Args[3]);
|
|
|
|
}
|
|
|
|
|
|
//DUPINFOCASE( PAGE_FAULT_IN_FREED_SPECIAL_POOL ); // 0xCC
|
|
//DUPINFOCASE( PAGE_FAULT_BEYOND_END_OF_ALLOCATION ); // 0xCD
|
|
//DUPINFOCASE( TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE ); // 0xCF
|
|
//DUPINFOCASE( PAGE_FAULT_IN_NONPAGED_AREA ) // 0x50
|
|
//DUPINFOCASE( DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION ) // 0xD6
|
|
DECL_GETINFO( DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL ) // 0xD5
|
|
/*
|
|
* Parameters
|
|
*
|
|
* Parameter 1 Memory referenced
|
|
* Parameter 2 0: Read 1: Write
|
|
* Parameter 3 Address that referenced memory (if known)
|
|
* Parameter 4 Reserved
|
|
*
|
|
*/
|
|
{
|
|
CHAR BugCheckStr[30];
|
|
|
|
Analysis->SetUlong64(Bc->Args[1] ?
|
|
DEBUG_FLR_WRITE_ADDRESS : DEBUG_FLR_READ_ADDRESS,
|
|
Bc->Args[0]);
|
|
if (Bc->Args[2]) {
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, Bc->Args[2]);
|
|
}
|
|
Analysis->SetUlong64(DEBUG_FLR_MM_INTERNAL_CODE, Bc->Args[3]);
|
|
|
|
if (Bc->Args[0] == Bc->Args[2] &&
|
|
Bc->Args[1] == 0)
|
|
{
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_SPECIFIER, "_CODE_AV");
|
|
}
|
|
AddBugcheckDriver(Analysis, TRUE, TRUE, 0);
|
|
}
|
|
|
|
|
|
DECL_GETINFO( MANUALLY_INITIATED_CRASH ) //0xE2, 0xDEADDEAD
|
|
{
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, "MANUALLY_INITIATED_CRASH");
|
|
}
|
|
|
|
DECL_GETINFO( THREAD_STUCK_IN_DEVICE_DRIVER ) // 0xEA
|
|
/*
|
|
* PARAMETERS:
|
|
*
|
|
* 1 - Pointer to a stuck thread object. Do .thread then kb on it to
|
|
* find hung location.
|
|
*
|
|
* 2 - Pointer to a DEFERRED_WATCHDOG object.
|
|
*
|
|
* 3 - Pointer to offending driver name.
|
|
*
|
|
* 4 - Number of times "intercepted" bugcheck 0xEA was hit (see notes).
|
|
*/
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_FOLLOWUP_DRIVER_ONLY, 0);
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_THREAD, Bc->Args[0]);
|
|
|
|
Analysis->SetString(DEBUG_FLR_DEFAULT_BUCKET_ID, "GRAPHICS_DRIVER_FAULT");
|
|
}
|
|
|
|
DECL_GETINFO( CRITICAL_PROCESS_DIED ) // (0xef)
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_PROCESS_OBJECT, Bc->Args[0]);
|
|
}
|
|
|
|
DECL_GETINFO( CRITICAL_OBJECT_TERMINATION ) // (0xf4)
|
|
{
|
|
if (Bc->Args[0] == 3)
|
|
{
|
|
ULONG result;
|
|
CHAR ImageName[MAX_PATH];
|
|
|
|
Analysis->SetUlong64(DEBUG_FLR_PROCESS_OBJECT, Bc->Args[1]);
|
|
|
|
//
|
|
// Second parameter (which is actually a string within the EPROCESS)
|
|
// is the name of the image.
|
|
//
|
|
if (ReadMemory(Bc->Args[2], ImageName, sizeof(ImageName), &result) &&
|
|
result)
|
|
{
|
|
ImageName[MAX_PATH-1]=0;
|
|
ImageName[result]=0;
|
|
SaveImageName(Analysis, ImageName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DECL_GETINFO( WINLOGON_FATAL_ERROR ) //(c000021a)
|
|
{
|
|
CHAR BugCheckStr[20];
|
|
|
|
sprintf(BugCheckStr, "0x%lx_%lx", Bc->Code, Bc->Args[1]);
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
}
|
|
|
|
DECL_GETINFO( STATUS_DRIVER_UNABLE_TO_LOAD ) //0xc0000xxx
|
|
{
|
|
if (Bc->Args[0])
|
|
{
|
|
AddBugcheckDriver(Analysis, FALSE, FALSE, Bc->Args[0]);
|
|
}
|
|
}
|
|
|
|
DECL_GETINFO( ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY ) // (0xFC)
|
|
{
|
|
if (Bc->Args[0])
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_FAULTING_IP, Bc->Args[0]);
|
|
}
|
|
// Add bugcheck driver from KiBugCheckDriver
|
|
AddBugcheckDriver(Analysis, TRUE, TRUE, 0);
|
|
}
|
|
|
|
DECL_GETINFO( UNMOUNTABLE_BOOT_VOLUME ) // 0xED
|
|
{
|
|
CHAR BugCheckStr[20];
|
|
|
|
sprintf(BugCheckStr, "0x%lx_%lx", Bc->Code, (ULONG) Bc->Args[1]);
|
|
Analysis->SetUlong(DEBUG_FLR_STATUS_CODE, (ULONG) Bc->Args[1]);
|
|
switch ((ULONG) Bc->Args[1])
|
|
{
|
|
case 0xC0000006:
|
|
Analysis->SetUlong(DEBUG_FLR_SHOW_ERRORLOG, 1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define GETINFOCASE(bcname) \
|
|
case bcname : \
|
|
GetInfoFor##bcname (Bc, Analysis); \
|
|
break;
|
|
#define DUPINFOCASE(bcname) \
|
|
case bcname:
|
|
|
|
void
|
|
BcFillAnalysis(
|
|
PBUGCHECK_ANALYSIS Bc,
|
|
KernelDebugFailureAnalysis* Analysis
|
|
)
|
|
{
|
|
Analysis->SetFailureClass(DEBUG_CLASS_KERNEL);
|
|
|
|
HRESULT Status = Analysis->CheckModuleSymbols("nt", "Kernel");
|
|
if (Status != S_OK)
|
|
{
|
|
goto SkipBucheckSpecificProcessing;
|
|
}
|
|
|
|
//
|
|
// BBT Breaks the stack trace for builds > 2201
|
|
// Hack the return address for better results
|
|
// A new of routines are at the wrong addresses.
|
|
//
|
|
if ((g_TargetMachine == IMAGE_FILE_MACHINE_I386) &&
|
|
(g_TargetBuild > 2500) && (g_TargetBuild < 2507))
|
|
{
|
|
DEBUG_STACK_FRAME Stk[MAX_STACK_FRAMES];
|
|
ULONG Frames = 0;
|
|
|
|
if (S_OK == g_ExtControl->GetStackTrace(0, 0, 0, Stk, MAX_STACK_FRAMES,
|
|
&Frames) &&
|
|
FaIsFunctionAddr(Stk[0].InstructionOffset, "KeBugCheckEx"))
|
|
{
|
|
ULONG CallIP = (ULONG) Stk[1].InstructionOffset - 5, Res;
|
|
UCHAR Instr;
|
|
|
|
// Move the caller's IP back to the actual KeBugCheckEx
|
|
// call. Only do this if we haven't already backed up
|
|
// to a call instruction.
|
|
if (!ReadMemory(Stk[1].InstructionOffset, &Instr, sizeof(Instr),
|
|
&Res) ||
|
|
Res != sizeof(Instr) ||
|
|
Instr != 0xe8)
|
|
{
|
|
WriteMemory(Stk[0].FrameOffset + 4, &CallIP, sizeof(CallIP),
|
|
&Res);
|
|
g_ExtControl->GetStackTrace(0, 0, 0, Stk, MAX_STACK_FRAMES,
|
|
&Frames);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Special value that is set by the kernel debugger so we can detect when
|
|
// people are messing with physical address via the kernel debugger.
|
|
//
|
|
|
|
ULONG64 MmPoisonedTbAddr;
|
|
MmPoisonedTbAddr = GetExpression("nt!MmPoisonedTb");
|
|
|
|
if (MmPoisonedTbAddr)
|
|
{
|
|
ULONG cb;
|
|
ULONG MmPoisonedTb = 0;
|
|
|
|
if (ReadMemory(MmPoisonedTbAddr, &MmPoisonedTb, sizeof(ULONG), &cb) &&
|
|
(MmPoisonedTb != 0))
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_POISONED_TB, 0);
|
|
}
|
|
}
|
|
|
|
SkipBucheckSpecificProcessing:
|
|
|
|
|
|
Analysis->SetFailureType(DEBUG_FLR_KERNEL);
|
|
|
|
switch (Bc->Code)
|
|
{
|
|
case 0:
|
|
ULONG c_ip;
|
|
//
|
|
// This can be a user mode failurein kd. Try to determine that.
|
|
//
|
|
|
|
if ( (GetExpression("@$ip") < BcTargetKernelAddressStart()) &&
|
|
(GetExpression("@$sp") < BcTargetKernelAddressStart()) )
|
|
{
|
|
Analysis->SetFailureType(DEBUG_FLR_USER_CRASH);
|
|
g_ExtControl->Execute(DEBUG_OUTCTL_IGNORE, ".reload /user",
|
|
DEBUG_EXECUTE_NOT_LOGGED);
|
|
}
|
|
|
|
break;
|
|
|
|
GETINFOCASE( DRIVER_CAUGHT_MODIFYING_FREED_POOL );
|
|
|
|
DUPINFOCASE( PAGE_FAULT_IN_FREED_SPECIAL_POOL );
|
|
DUPINFOCASE( PAGE_FAULT_BEYOND_END_OF_ALLOCATION );
|
|
DUPINFOCASE( TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE );
|
|
DUPINFOCASE( PAGE_FAULT_IN_NONPAGED_AREA );
|
|
DUPINFOCASE( DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION );
|
|
GETINFOCASE( DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL );
|
|
|
|
GETINFOCASE( DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS );
|
|
|
|
GETINFOCASE( DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS );
|
|
|
|
GETINFOCASE( DRIVER_VERIFIER_IOMANAGER_VIOLATION );
|
|
|
|
DUPINFOCASE( DRIVER_IRQL_NOT_LESS_OR_EQUAL );
|
|
GETINFOCASE( IRQL_NOT_LESS_OR_EQUAL );
|
|
|
|
GETINFOCASE( PANIC_STACK_SWITCH );
|
|
|
|
GETINFOCASE( KMODE_EXCEPTION_NOT_HANDLED );
|
|
|
|
GETINFOCASE( SYSTEM_SERVICE_EXCEPTION );
|
|
|
|
GETINFOCASE( ACPI_BIOS_ERROR );
|
|
|
|
GETINFOCASE( USER_MODE_HEALTH_MONITOR );
|
|
|
|
GETINFOCASE( MEMORY_MANAGEMENT );
|
|
|
|
DUPINFOCASE( KERNEL_MODE_EXCEPTION_NOT_HANDLED_M );
|
|
GETINFOCASE( KERNEL_MODE_EXCEPTION_NOT_HANDLED );
|
|
|
|
DUPINFOCASE( SYSTEM_THREAD_EXCEPTION_NOT_HANDLED_M );
|
|
GETINFOCASE( SYSTEM_THREAD_EXCEPTION_NOT_HANDLED );
|
|
|
|
GETINFOCASE( SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION );
|
|
|
|
GETINFOCASE( KERNEL_STACK_INPAGE_ERROR );
|
|
|
|
GETINFOCASE( KERNEL_DATA_INPAGE_ERROR );
|
|
|
|
GETINFOCASE( TIMER_OR_DPC_INVALID );
|
|
|
|
DUPINFOCASE( UNEXPECTED_KERNEL_MODE_TRAP_M );
|
|
GETINFOCASE( UNEXPECTED_KERNEL_MODE_TRAP );
|
|
|
|
GETINFOCASE( MULTIPLE_IRP_COMPLETE_REQUESTS );
|
|
|
|
GETINFOCASE( WINLOGON_FATAL_ERROR );
|
|
|
|
DUPINFOCASE( RDR_FILE_SYSTEM );
|
|
DUPINFOCASE( UDFS_FILE_SYSTEM );
|
|
DUPINFOCASE( CDFS_FILE_SYSTEM );
|
|
DUPINFOCASE( NTFS_FILE_SYSTEM );
|
|
GETINFOCASE( FAT_FILE_SYSTEM );
|
|
|
|
DUPINFOCASE( STATUS_DRIVER_ENTRYPOINT_NOT_FOUND );
|
|
DUPINFOCASE( STATUS_PROCEDURE_NOT_FOUND );
|
|
DUPINFOCASE( STATUS_DRIVER_ORDINAL_NOT_FOUND );
|
|
GETINFOCASE( STATUS_DRIVER_UNABLE_TO_LOAD );
|
|
|
|
GETINFOCASE( PNP_DETECTED_FATAL_ERROR );
|
|
|
|
GETINFOCASE( MACHINE_CHECK_EXCEPTION );
|
|
|
|
GETINFOCASE( DRIVER_POWER_STATE_FAILURE );
|
|
|
|
DUPINFOCASE( THREAD_STUCK_IN_DEVICE_DRIVER_M );
|
|
GETINFOCASE( THREAD_STUCK_IN_DEVICE_DRIVER );
|
|
|
|
GETINFOCASE( SESSION3_INITIALIZATION_FAILED );
|
|
|
|
GETINFOCASE( DRIVER_VERIFIER_DETECTED_VIOLATION );
|
|
|
|
GETINFOCASE( CRITICAL_OBJECT_TERMINATION );
|
|
|
|
GETINFOCASE( CRITICAL_PROCESS_DIED );
|
|
|
|
GETINFOCASE( PROCESS_HAS_LOCKED_PAGES );
|
|
|
|
DUPINFOCASE( MANUALLY_INITIATED_CRASH1 );
|
|
GETINFOCASE( MANUALLY_INITIATED_CRASH );
|
|
|
|
GETINFOCASE( BAD_POOL_CALLER );
|
|
|
|
DUPINFOCASE( DRIVER_CORRUPTED_SYSPTES );
|
|
DUPINFOCASE( SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD )
|
|
DUPINFOCASE( DRIVER_PORTION_MUST_BE_NONPAGED );
|
|
GETINFOCASE( DRIVER_CORRUPTED_MMPOOL );
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
if (!Analysis->GetFailureCode())
|
|
{
|
|
//
|
|
// We ignore the top bit when setting the internal failure code
|
|
// so we can bucket things togeter appropriately.
|
|
// The top bit only represent a dump generation difference, not
|
|
// a root cause difference.
|
|
//
|
|
Analysis->SetFailureCode(Bc->Code & ~0x10000000);
|
|
}
|
|
|
|
if (!Analysis->Get(DEBUG_FLR_DEFAULT_BUCKET_ID))
|
|
{
|
|
if (Analysis->GetFailureType() == DEBUG_FLR_USER_CRASH)
|
|
{
|
|
Analysis->SetString(DEBUG_FLR_DEFAULT_BUCKET_ID, "APPLICATION_FAULT");
|
|
}
|
|
else
|
|
{
|
|
Analysis->SetString(DEBUG_FLR_DEFAULT_BUCKET_ID, "DRIVER_FAULT");
|
|
}
|
|
}
|
|
|
|
if (!Analysis->Get(DEBUG_FLR_BUGCHECK_STR))
|
|
{
|
|
CHAR BugCheckStr[12];
|
|
sprintf(BugCheckStr, "0x%lX", Analysis->GetFailureCode());
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_STR, BugCheckStr);
|
|
|
|
if (Analysis->Get(DEBUG_FLR_WRITE_ADDRESS))
|
|
{
|
|
Analysis->SetString(DEBUG_FLR_BUGCHECK_SPECIFIER, "_W");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save the current IRQL.
|
|
//
|
|
|
|
if (g_TargetBuild > 2600)
|
|
{
|
|
PROCESSORINFO ProcInfo;
|
|
ULONG64 Prcb;
|
|
ULONG64 Irql = 0;
|
|
HRESULT Hr;
|
|
|
|
if (Ioctl(IG_KD_CONTEXT, &ProcInfo, sizeof(ProcInfo)))
|
|
{
|
|
Hr = g_ExtData->ReadProcessorSystemData(ProcInfo.Processor,
|
|
DEBUG_DATA_KPRCB_OFFSET,
|
|
&Prcb,
|
|
sizeof(Prcb),
|
|
NULL);
|
|
if (Hr == S_OK && Prcb)
|
|
{
|
|
if (!GetFieldValue(Prcb, "nt!_KPRCB", "DebuggerSavedIRQL", Irql))
|
|
{
|
|
Analysis->SetUlong64(DEBUG_FLR_CURRENT_IRQL, Irql);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ULONG64 Irp;
|
|
|
|
if (Analysis->GetUlong64(DEBUG_FLR_IRP_ADDRESS, &Irp))
|
|
{
|
|
BcGetDriverNameFromIrp(Analysis, Irp, 0, 0);
|
|
}
|
|
|
|
//
|
|
// Generic processing
|
|
//
|
|
|
|
Analysis->ProcessInformation();
|
|
}
|
|
|
|
void
|
|
ReadWatchDogBugcheck(
|
|
PBUGCHECK_ANALYSIS Bc
|
|
)
|
|
{
|
|
// Check if this could be a watchdog bugcheck
|
|
// Read watchdog!g_WdBugCheckData
|
|
ULONG64 wdBugcheck;
|
|
ULONG res;
|
|
ULONG PtrSize = IsPtr64() ? 8 : 4;
|
|
|
|
wdBugcheck = GetExpression("watchdog!g_WdBugCheckData");
|
|
if (wdBugcheck)
|
|
{
|
|
wdBugcheck = GetExpression("VIDEOPRT!g_WdpBugCheckData");
|
|
}
|
|
if (wdBugcheck)
|
|
{
|
|
ReadMemory(wdBugcheck, &Bc->Code, sizeof(ULONG), &res);
|
|
ReadPointer(wdBugcheck + PtrSize,&Bc->Args[0]);
|
|
ReadPointer(wdBugcheck + 2*PtrSize,&Bc->Args[1]);
|
|
ReadPointer(wdBugcheck + 3*PtrSize,&Bc->Args[2]);
|
|
ReadPointer(wdBugcheck + 4*PtrSize,&Bc->Args[3]);
|
|
}
|
|
|
|
}
|
|
|
|
KernelDebugFailureAnalysis*
|
|
BcAnalyze(
|
|
OUT PBUGCHECK_ANALYSIS Bc,
|
|
ULONG Flags
|
|
)
|
|
{
|
|
if (g_ExtControl->ReadBugCheckData(&Bc->Code, &Bc->Args[0], &Bc->Args[1],
|
|
&Bc->Args[2], &Bc->Args[3]) != S_OK)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (Bc->Code == 0)
|
|
{
|
|
ReadWatchDogBugcheck(Bc);
|
|
}
|
|
|
|
KernelDebugFailureAnalysis* Analysis = new KernelDebugFailureAnalysis;
|
|
if (Analysis)
|
|
{
|
|
Analysis->SetProcessingFlags(Flags);
|
|
|
|
__try
|
|
{
|
|
BcFillAnalysis(Bc, Analysis);
|
|
}
|
|
__except(FaExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
delete Analysis;
|
|
Analysis = NULL;
|
|
}
|
|
}
|
|
|
|
return Analysis;
|
|
}
|
|
|
|
HRESULT
|
|
AnalyzeBugCheck(
|
|
PCSTR args
|
|
)
|
|
{
|
|
KernelDebugFailureAnalysis* Analysis;
|
|
BUGCHECK_ANALYSIS Bc = {0};
|
|
BOOL Dump = TRUE;
|
|
ULONG Flags = 0;
|
|
DEBUG_FLR_PARAM_TYPE Params[10];
|
|
ULONG ParamCount = 0;
|
|
|
|
if (g_TargetClass != DEBUG_CLASS_KERNEL) {
|
|
dprintf("!analyzebugcheck is for kernel mode only\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
while (*args == ' ' || *args == '\t')
|
|
{
|
|
args++;
|
|
}
|
|
|
|
if (*args == '-')
|
|
{
|
|
++args;
|
|
switch(*args)
|
|
{
|
|
case 'D':
|
|
{
|
|
CHAR ParamString[100];
|
|
ULONG ParamLength = 0;
|
|
args+=2;
|
|
while(*args && *args != ' ' && *args != '\t')
|
|
{
|
|
ParamString[ParamLength++] = *args++;
|
|
}
|
|
ParamString[ParamLength] = 0;
|
|
|
|
//
|
|
// Match the string to the actual failure ID.
|
|
//
|
|
|
|
ULONG i=0;
|
|
while(FlrLookupTable[i].Data &&
|
|
strcmp(FlrLookupTable[i].String, ParamString))
|
|
{
|
|
i++;
|
|
}
|
|
|
|
Params[ParamCount++] = FlrLookupTable[i].Data;
|
|
break;
|
|
}
|
|
case 'n':
|
|
if (!strncmp(args, "nodb",4))
|
|
{
|
|
args+=4;
|
|
Flags |= FAILURE_ANALYSIS_NO_DB_LOOKUP;
|
|
}
|
|
break;
|
|
case 's':
|
|
if (!strncmp(args, "show",4))
|
|
{
|
|
ULONG64 Code;
|
|
args+=4;
|
|
GetExpressionEx(args, &Code, &args);
|
|
Bc.Code = (ULONG)Code;
|
|
|
|
for (ULONG i=0; i<4 && *args; i++)
|
|
{
|
|
if (!GetExpressionEx(args, &Bc.Args[i], &args))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
GetBugCheckDescription(&Bc);
|
|
PrintBugDescription(&Bc);
|
|
return S_OK;
|
|
}
|
|
case 'v':
|
|
Flags |= FAILURE_ANALYSIS_VERBOSE;
|
|
break;
|
|
case 'f':
|
|
break;
|
|
default:
|
|
{
|
|
CHAR Option[2];
|
|
Option[0] = *args; Option[1] = 0;
|
|
dprintf("\nUnknown option '-%s'\n", Option );
|
|
break;
|
|
}
|
|
}
|
|
if (*args == 0)
|
|
{
|
|
break;
|
|
}
|
|
++args;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
g_ExtControl->ReadBugCheckData(&Bc.Code, &Bc.Args[0], &Bc.Args[1],
|
|
&Bc.Args[2], &Bc.Args[3]);
|
|
|
|
if (Bc.Code == 0)
|
|
{
|
|
ReadWatchDogBugcheck(&Bc);
|
|
}
|
|
|
|
if (!ParamCount)
|
|
{
|
|
dprintf("*******************************************************************************\n");
|
|
dprintf("* *\n");
|
|
dprintf("* Bugcheck Analysis *\n");
|
|
dprintf("* *\n");
|
|
dprintf("*******************************************************************************\n");
|
|
dprintf("\n");
|
|
|
|
if (Flags & FAILURE_ANALYSIS_VERBOSE)
|
|
{
|
|
GetBugCheckDescription(&Bc);
|
|
PrintBugDescription(&Bc);
|
|
dprintf("\nDebugging Details:\n------------------\n\n");
|
|
}
|
|
else
|
|
{
|
|
dprintf("Use !analyze -v to get detailed debugging information.\n\n");
|
|
|
|
dprintf("BugCheck %lX, {%1p, %1p, %1p, %1p}\n\n",
|
|
Bc.Code,
|
|
Bc.Args[0],Bc.Args[1],Bc.Args[2],Bc.Args[3]);
|
|
}
|
|
}
|
|
|
|
Analysis = BcAnalyze(&Bc, Flags);
|
|
|
|
if (!Analysis)
|
|
{
|
|
dprintf("\n\nFailure could not be analyzed\n\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (ParamCount)
|
|
{
|
|
while(ParamCount--)
|
|
{
|
|
Analysis->OutputEntryParam(Params[ParamCount]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Always call output so we can key information printed out also, such
|
|
// as *** entries.
|
|
//
|
|
|
|
Analysis->Output();
|
|
|
|
delete Analysis;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// KernelDebugFailureAnalysis.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
KernelDebugFailureAnalysis::KernelDebugFailureAnalysis(void)
|
|
: m_KernelModule("nt")
|
|
{
|
|
}
|
|
|
|
DEBUG_POOL_REGION
|
|
KernelDebugFailureAnalysis::GetPoolForAddress(ULONG64 Addr)
|
|
{
|
|
PGET_POOL_REGION GetPoolRegion = NULL;
|
|
|
|
if (g_ExtControl->
|
|
GetExtensionFunction(0, "GetPoolRegion",
|
|
(FARPROC*)&GetPoolRegion) == S_OK &&
|
|
GetPoolRegion)
|
|
{
|
|
DEBUG_POOL_REGION RegionId;
|
|
|
|
(*GetPoolRegion)(g_ExtClient, Addr, &RegionId);
|
|
return RegionId;
|
|
}
|
|
|
|
return DbgPoolRegionUnknown;
|
|
}
|
|
|
|
PCSTR
|
|
KernelDebugFailureAnalysis::DescribeAddress(ULONG64 Addr)
|
|
{
|
|
DEBUG_POOL_REGION RegionId = GetPoolForAddress(Addr);
|
|
|
|
|
|
if ((RegionId != DbgPoolRegionUnknown) &&
|
|
(RegionId < DbgPoolRegionMax))
|
|
{
|
|
return g_PoolRegion[RegionId];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
FOLLOW_ADDRESS
|
|
KernelDebugFailureAnalysis::IsPotentialFollowupAddress(ULONG64 Address)
|
|
{
|
|
CHAR Buffer[MAX_PATH];
|
|
ULONG64 Disp;
|
|
|
|
//
|
|
// Check for special symbols which indicate we are transitioning back
|
|
// to user mode code, so the rest of the stack can not be at fault.
|
|
//
|
|
|
|
if (GetFailureType() == DEBUG_FLR_USER_CRASH)
|
|
{
|
|
return FollowYes;
|
|
}
|
|
|
|
if (FaGetSymbol(Address, Buffer, &Disp, sizeof(Buffer)) &&
|
|
(!_strcmpi(Buffer, "nt!KiCallUserMode") ||
|
|
!_strcmpi(Buffer, "SharedUserData!SystemCallStub")))
|
|
{
|
|
return FollowStop;
|
|
}
|
|
|
|
if (Address > BcTargetKernelAddressStart())
|
|
{
|
|
return FollowYes;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We don't stop on user mode addresses because they could be
|
|
// garbage on the stack we - just skip them
|
|
//
|
|
|
|
return FollowSkip;
|
|
}
|
|
}
|
|
|
|
FOLLOW_ADDRESS
|
|
KernelDebugFailureAnalysis::IsFollowupContext(ULONG64 Address1,
|
|
ULONG64 Address2,
|
|
ULONG64 Address3)
|
|
{
|
|
// If it's a user mode address, and a dump file, it's not a valid
|
|
// context.
|
|
// A user mode address is valid for a kernel mode context because
|
|
// a hardcoded breakpoint from user mode with kd active will show up
|
|
// on the stack.
|
|
|
|
if ( (Address1 < BcTargetKernelAddressStart()) &&
|
|
(Address2 < BcTargetKernelAddressStart()) &&
|
|
(Address3 < BcTargetKernelAddressStart()) )
|
|
{
|
|
if ((g_TargetQualifier == DEBUG_DUMP_SMALL) ||
|
|
(g_TargetQualifier == DEBUG_DUMP_DEFAULT) ||
|
|
(g_TargetQualifier == DEBUG_DUMP_FULL))
|
|
{
|
|
return FollowStop;
|
|
}
|
|
}
|
|
|
|
return FollowYes;
|
|
}
|
|
|
|
FlpClasses
|
|
KernelDebugFailureAnalysis::GetFollowupClass(ULONG64 Address,
|
|
PCSTR Module, PCSTR Routine)
|
|
{
|
|
if (m_KernelModule.Contains(Address) ||
|
|
!_strcmpi(Module, "ntfs") ||
|
|
!_strcmpi(Module, "fastfat"))
|
|
{
|
|
return FlpOSRoutine;
|
|
}
|
|
else if (!_strcmpi(Module, "sr") ||
|
|
!_strcmpi(Module, "ndis") ||
|
|
!_strcmpi(Module, "videoprt") ||
|
|
!_strcmpi(Module, "USBPORT") ||
|
|
!_strcmpi(Module, "USBHUB") ||
|
|
!_strcmpi(Module, "dxg") ||
|
|
!_strcmpi(Module, "win32k") ||
|
|
!_strcmpi(Module, "verifier") ||
|
|
!_strcmpi(Module, "scsiport"))
|
|
{
|
|
return FlpOSFilterDrv;
|
|
}
|
|
else if (!_strcmpi(Module, "SharedUserData") &&
|
|
Routine && !_strcmpi(Routine, "SystemCallStub"))
|
|
{
|
|
// Do not followup on usermode calls
|
|
return FlpIgnore;
|
|
}
|
|
else
|
|
{
|
|
return FlpUnknownDrv;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* This checks for valid object pointers in HANDLE_TABLE_ENTRY. If the pointers are
|
|
* invalid it tries to figure out who corrupted the values.
|
|
*
|
|
* Reutrns TRUE if it succesfully identifies a memory curruption
|
|
*/
|
|
BOOL
|
|
KernelDebugFailureAnalysis::CheckForCorruptionInHTE(
|
|
ULONG64 hTableEntry,
|
|
PCHAR Owner,
|
|
ULONG OwnerSize)
|
|
{
|
|
ULONG64 Object = 0;
|
|
ULONG64 CorruptingPool = 0;
|
|
DEBUG_POOL_REGION Region;
|
|
|
|
// hTableEntry must be in PagedPool, but we have
|
|
// a loose check here since GetPoolForAddress is unreliable on
|
|
// minidumps PagedPool
|
|
if (IsPotentialFollowupAddress(hTableEntry) != FollowYes)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ReadPointer(hTableEntry, &Object))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Region = GetPoolForAddress(Object);
|
|
|
|
if (IsPotentialFollowupAddress(Object) != FollowYes)
|
|
{
|
|
// Object is invalid, it must be in PagedPool or NonPagedPool
|
|
|
|
return AddCorruptingPool(hTableEntry);
|
|
}
|
|
|
|
if (InitTypeRead(Object, nt!_OBJECT_HEADER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
ULONG PointerCount, HandleCount;
|
|
ULONG64 ObjType;
|
|
|
|
PointerCount = (ULONG) ReadField(PointerCount);
|
|
HandleCount = (ULONG) ReadField(HandleCount);
|
|
ObjType = (ULONG) ReadField(Type);
|
|
|
|
// Verify object for inconsistent counts
|
|
// Invalid object type, must be in kernel mode
|
|
|
|
if ((PointerCount > 0x10000) ||
|
|
(HandleCount > 0x10000) ||
|
|
(HandleCount > PointerCount) ||
|
|
(IsPotentialFollowupAddress(ObjType) != FollowYes)
|
|
)
|
|
{
|
|
// Object is corrupted, previous pool is a possible corruptor
|
|
|
|
AddCorruptingPool(Object);
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
KernelDebugFailureAnalysis::AddCorruptingPool(
|
|
ULONG64 CorruptedPool
|
|
)
|
|
{
|
|
DEBUG_POOL_DATA PoolData = {0};
|
|
|
|
PoolData.SizeofStruct = sizeof(DEBUG_POOL_DATA);
|
|
if (ExtGetPoolData(CorruptedPool, &PoolData) != S_OK)
|
|
{
|
|
//
|
|
// Pool block is badly corrupted, loop backwards to find first non-corrupt block
|
|
//
|
|
ULONG PoolHeaderSize = GetTypeSize("nt!_POOL_HEADER");
|
|
ULONG64 PoolAddr;
|
|
for (PoolAddr = CorruptedPool - 2*PoolHeaderSize;
|
|
PoolAddr > (CorruptedPool -0x1000); // Limit to 4KB
|
|
PoolAddr -= 2*PoolHeaderSize)
|
|
{
|
|
if (ExtGetPoolData(PoolAddr, &PoolData) == S_OK)
|
|
{
|
|
goto FoundPool;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
} else if (PoolData.Free && !PoolData.Allocated &&
|
|
PoolData.Size != 0)
|
|
{
|
|
// Pool seem to have been correctly freed
|
|
return FALSE;
|
|
} else if (ExtGetPoolData(PoolData.PoolBlock - PoolData.PreviousSize,
|
|
&PoolData) == S_OK)
|
|
// Now get previous pool as it most likely corruptor
|
|
{
|
|
FoundPool:
|
|
CHAR PoolTag[8] = {0};
|
|
SetUlong64(DEBUG_FLR_CORRUPTING_POOL_ADDRESS, PoolData.PoolBlock);
|
|
|
|
sprintf(PoolTag,"%c%c%c%c",
|
|
#define PP(x) isprint(((x)&0xff))?((x)&0xff):('.')
|
|
PP(PoolData.PoolTag),
|
|
PP(PoolData.PoolTag >> 8),
|
|
PP(PoolData.PoolTag >> 16),
|
|
PP((PoolData.PoolTag&~0x80000000) >> 24)
|
|
#undef PP
|
|
);
|
|
|
|
SetString(DEBUG_FLR_CORRUPTING_POOL_TAG, PoolTag);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
typedef struct _CHECK_STACK {
|
|
PCHAR* BreakinStk;
|
|
BOOL ValidMatch;
|
|
ULONG MachineType;
|
|
} CHECK_STACK;
|
|
|
|
BOOL
|
|
KernelDebugFailureAnalysis::IsManualBreakin(
|
|
PDEBUG_STACK_FRAME Stk,
|
|
ULONG Frames
|
|
)
|
|
//
|
|
// Check stack to see if this is result of manual breakin
|
|
//
|
|
{
|
|
CHAR szBrakFn[100];
|
|
ULONG64 Disp;
|
|
ULONG NumStacks, i, j;
|
|
BOOL NoMatches;
|
|
static PCHAR StkX86CtrlCBreakin1[] = {
|
|
"nt!*Break*",
|
|
"nt!KeUpdateSystemTime",
|
|
"nt!KiIdleLoop",
|
|
NULL,
|
|
};
|
|
static PCHAR StkX86CtrlCBreakin2[] = {
|
|
"nt!*Break*",
|
|
"nt!KeUpdateSystemTime",
|
|
"hal!HalProcessorIdle",
|
|
NULL,
|
|
};
|
|
static PCHAR StkIa64CtrlCBreakin1[] = {
|
|
"nt!KeBreakinBreakpoint",
|
|
"hal!HalpClockInterrupt",
|
|
"nt!KiExternalInterruptHandler",
|
|
"nt!Kil_TopOfIdleLoop",
|
|
NULL,
|
|
};
|
|
static PCHAR StkIa64CtrlCBreakin2[] = {
|
|
"nt!KeBreakinBreakpoint",
|
|
"hal!HalpClockInterrupt",
|
|
"nt!KiExternalInterruptHandler",
|
|
NULL
|
|
};
|
|
CHECK_STACK StksToCheck[] = {
|
|
{StkX86CtrlCBreakin1, TRUE, IMAGE_FILE_MACHINE_I386},
|
|
{StkX86CtrlCBreakin2, TRUE, IMAGE_FILE_MACHINE_I386},
|
|
{StkIa64CtrlCBreakin1, TRUE, IMAGE_FILE_MACHINE_IA64},
|
|
{StkIa64CtrlCBreakin2, TRUE, IMAGE_FILE_MACHINE_IA64},
|
|
};
|
|
|
|
|
|
//
|
|
// We are looking for:
|
|
// 0 nt!*Break*
|
|
//
|
|
|
|
|
|
//
|
|
// Assume 3 to 5 frames for a manual breakin stack
|
|
//
|
|
if (Frames < 3 || Frames > 5 || Stk == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (FaGetSymbol(Stk[0].InstructionOffset, szBrakFn,
|
|
&Disp, sizeof(szBrakFn)))
|
|
{
|
|
if (!strstr(szBrakFn, "Break"))
|
|
{
|
|
return FALSE;
|
|
}
|
|
} else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
NumStacks = sizeof(StksToCheck)/sizeof(CHECK_STACK);
|
|
|
|
for (i = 0; i < NumStacks; ++i)
|
|
{
|
|
if (StksToCheck[i].MachineType != g_TargetMachine)
|
|
{
|
|
StksToCheck[i].ValidMatch = FALSE;
|
|
}
|
|
}
|
|
|
|
for (j=1;j<Frames;++j)
|
|
{
|
|
NoMatches = TRUE;
|
|
if (FaGetSymbol(Stk[j].InstructionOffset, szBrakFn,
|
|
&Disp, sizeof(szBrakFn)))
|
|
{
|
|
for (i = 0; i < NumStacks; ++i)
|
|
{
|
|
if (StksToCheck[i].ValidMatch)
|
|
{
|
|
if (StksToCheck[i].BreakinStk[j] == NULL)
|
|
{
|
|
StksToCheck[i].ValidMatch = FALSE;
|
|
} else if (strcmp(szBrakFn, StksToCheck[i].BreakinStk[j]))
|
|
{
|
|
StksToCheck[i].ValidMatch = FALSE;
|
|
} else
|
|
{
|
|
// Breakin stack i matck with current stack till frame j
|
|
NoMatches = FALSE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (NoMatches)
|
|
{
|
|
// None of the stacks in StksToCheck match
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < NumStacks; ++i)
|
|
{
|
|
if (StksToCheck[i].ValidMatch)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Create a new minidump file of this crash
|
|
//
|
|
#if 0
|
|
ULONG FailTime = 0;
|
|
ULONG UpTime = 0;
|
|
CHAR CurrentTime[20];
|
|
CHAR CurrentDate[20];
|
|
CHAR Buffer[MAX_PATH];
|
|
|
|
g_ExtControl->GetCurrentTimeDate(&FailTime);
|
|
g_ExtControl->GetCurrentSystemUpTime(&UpTime);
|
|
_strtime(CurrentTime);
|
|
_strdate(CurrentDate);
|
|
|
|
if (CurrentTime && UpTime)
|
|
{
|
|
PrintString(Buffer, sizeof(Buffer), "Dump%s-%s-%08lx-%08lx-%s.dmp",
|
|
FailTime, Uptime, Currentdate, CurrentTime);
|
|
Status = g_ExtClient->WriteDumpFile(Buffer ,DEBUG_DUMP_SMALL);
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
CHAR Buffer[MAX_PATH];
|
|
if (Dump && GetTempFileName(".", "DMP", 0, Buffer))
|
|
{
|
|
Status = g_ExtClient->WriteDumpFile(Buffer ,DEBUG_DUMP_SMALL);
|
|
|
|
if (Status == S_OK)
|
|
{
|
|
//
|
|
// We create a file - now lets send it to the database
|
|
//
|
|
|
|
//CopyFile(Buffer, "c:\\xxxx", 0);
|
|
DeleteFile(Buffer);
|
|
}
|
|
dprintf("Done.");
|
|
}
|
|
|
|
dprintf("\n\n");
|
|
#endif
|