/*++ 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; iCode) { (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; icbFrame == 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;jGetCurrentTimeDate(&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