reactos/ntoskrnl/ke/bug.c

1463 lines
42 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/bug.c
* PURPOSE: Bugcheck Support
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#ifdef KDBG
#include <kdbg/kdb.h>
#endif
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
LIST_ENTRY KeBugcheckCallbackListHead;
LIST_ENTRY KeBugcheckReasonCallbackListHead;
KSPIN_LOCK BugCheckCallbackLock;
ULONG KeBugCheckActive, KeBugCheckOwner;
LONG KeBugCheckOwnerRecursionCount;
PMESSAGE_RESOURCE_DATA KiBugCodeMessages;
ULONG KeBugCheckCount = 1;
ULONG KiHardwareTrigger;
PUNICODE_STRING KiBugCheckDriver;
ULONG_PTR KiBugCheckData[5];
PKNMI_HANDLER_CALLBACK KiNmiCallbackListHead = NULL;
KSPIN_LOCK KiNmiCallbackListLock;
2023-04-04 21:41:48 +00:00
/* Jira Reporting */
UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion;
UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
/* PRIVATE FUNCTIONS *********************************************************/
PVOID
NTAPI
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
KiPcToFileHeader(IN PVOID Pc,
OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
IN BOOLEAN DriversOnly,
OUT PBOOLEAN InKernel)
{
ULONG i = 0;
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
PVOID ImageBase, PcBase = NULL;
PLDR_DATA_TABLE_ENTRY Entry;
PLIST_ENTRY ListHead, NextEntry;
/* Check which list we should use */
ListHead = (KeLoaderBlock) ? &KeLoaderBlock->LoadOrderListHead :
&PsLoadedModuleList;
/* Assume no */
*InKernel = FALSE;
/* Set list pointers and make sure it's valid */
NextEntry = ListHead->Flink;
if (NextEntry)
{
/* Start loop */
while (NextEntry != ListHead)
{
/* Increase entry */
i++;
/* Check if this is a kernel entry and we only want drivers */
if ((i <= 2) && (DriversOnly != FALSE))
{
/* Skip it */
NextEntry = NextEntry->Flink;
continue;
}
/* Get the loader entry */
Entry = CONTAINING_RECORD(NextEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
/* Move to the next entry */
NextEntry = NextEntry->Flink;
ImageBase = Entry->DllBase;
/* Check if this is the right one */
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
if (((ULONG_PTR)Pc >= (ULONG_PTR)Entry->DllBase) &&
((ULONG_PTR)Pc < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
{
/* Return this entry */
*LdrEntry = Entry;
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
PcBase = ImageBase;
/* Check if this was a kernel or HAL entry */
if (i <= 2) *InKernel = TRUE;
break;
}
}
}
/* Return the base address */
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
return PcBase;
}
PVOID
NTAPI
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
KiRosPcToUserFileHeader(IN PVOID Pc,
OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
{
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
PVOID ImageBase, PcBase = NULL;
PLDR_DATA_TABLE_ENTRY Entry;
PLIST_ENTRY ListHead, NextEntry;
/*
* We know this is valid because we should only be called after a
* succesfull address from RtlWalkFrameChain for UserMode, which
* validates everything for us.
*/
ListHead = &KeGetCurrentThread()->
Teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList;
/* Set list pointers and make sure it's valid */
NextEntry = ListHead->Flink;
if (NextEntry)
{
/* Start loop */
while (NextEntry != ListHead)
{
/* Get the loader entry */
Entry = CONTAINING_RECORD(NextEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
/* Move to the next entry */
NextEntry = NextEntry->Flink;
ImageBase = Entry->DllBase;
/* Check if this is the right one */
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
if (((ULONG_PTR)Pc >= (ULONG_PTR)Entry->DllBase) &&
((ULONG_PTR)Pc < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
{
/* Return this entry */
*LdrEntry = Entry;
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
PcBase = ImageBase;
break;
}
}
}
/* Return the base address */
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
return PcBase;
}
USHORT
NTAPI
KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip,
IN ULONG FramesToCapture,
OUT PVOID *BackTrace,
OUT PULONG BackTraceHash OPTIONAL)
{
PVOID Frames[2 * 64];
ULONG FrameCount;
ULONG Hash = 0, i;
/* Skip a frame for the caller */
FramesToSkip++;
/* Don't go past the limit */
if ((FramesToCapture + FramesToSkip) >= 128) return 0;
/* Do the back trace */
FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 1);
/* Make sure we're not skipping all of them */
if (FrameCount <= FramesToSkip) return 0;
/* Loop all the frames */
for (i = 0; i < FramesToCapture; i++)
{
/* Don't go past the limit */
if ((FramesToSkip + i) >= FrameCount) break;
/* Save this entry and hash it */
BackTrace[i] = Frames[FramesToSkip + i];
Hash += PtrToUlong(BackTrace[i]);
}
/* Write the hash */
if (BackTraceHash) *BackTraceHash = Hash;
/* Clear the other entries and return count */
RtlFillMemoryUlong(Frames, 128, 0);
return (USHORT)i;
}
VOID
FASTCALL
KeRosDumpStackFrameArray(IN PULONG_PTR Frames,
IN ULONG FrameCount)
{
ULONG i;
ULONG_PTR Addr;
BOOLEAN InSystem;
PVOID p;
/* GCC complaints that it may be used uninitialized */
PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
/* Loop them */
for (i = 0; i < FrameCount; i++)
{
/* Get the EIP */
Addr = Frames[i];
if (!Addr)
{
break;
}
/* Get the base for this file */
if (Addr > (ULONG_PTR)MmHighestUserAddress)
{
/* We are in kernel */
p = KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem);
}
else
{
/* We are in user land */
p = KiRosPcToUserFileHeader((PVOID)Addr, &LdrEntry);
}
if (p)
{
#ifdef KDBG
if (!KdbSymPrintAddress((PVOID)Addr, NULL))
#endif
{
CHAR AnsiName[64];
/* Convert module name to ANSI and print it */
KeBugCheckUnicodeToAnsi(&LdrEntry->BaseDllName,
AnsiName,
sizeof(AnsiName));
Addr -= (ULONG_PTR)LdrEntry->DllBase;
DbgPrint("<%s: %p>", AnsiName, (PVOID)Addr);
}
}
else
{
/* Print only the address */
DbgPrint("<%p>", (PVOID)Addr);
}
/* Go to the next frame */
DbgPrint("\n");
}
}
VOID
NTAPI
KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL,
IN ULONG FrameCount OPTIONAL)
{
ULONG_PTR Frames[32];
ULONG RealFrameCount;
/* If the caller didn't ask, assume 32 frames */
if (!FrameCount || FrameCount > 32) FrameCount = 32;
if (Frame)
{
/* Dump them */
KeRosDumpStackFrameArray(Frame, FrameCount);
}
else
{
/* Get the current frames (skip the two. One for the dumper, one for the caller) */
RealFrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
DPRINT1("RealFrameCount =%lu\n", RealFrameCount);
/* Dump them */
KeRosDumpStackFrameArray(Frames, RealFrameCount);
/* Count left for user mode? */
if (FrameCount - RealFrameCount > 0)
{
/* Get the current frames */
RealFrameCount = KeRosCaptureUserStackBackTrace(-1, FrameCount - RealFrameCount, (PVOID*)Frames, NULL);
/* Dump them */
KeRosDumpStackFrameArray(Frames, RealFrameCount);
}
}
}
CODE_SEG("INIT")
VOID
NTAPI
KiInitializeBugCheck(VOID)
{
PMESSAGE_RESOURCE_DATA BugCheckData;
LDR_RESOURCE_INFO ResourceInfo;
PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
NTSTATUS Status;
PLDR_DATA_TABLE_ENTRY LdrEntry;
/* Get the kernel entry */
LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
/* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
ResourceInfo.Type = 11;
ResourceInfo.Name = 1;
ResourceInfo.Language = 9;
/* Do the lookup. */
Status = LdrFindResource_U(LdrEntry->DllBase,
&ResourceInfo,
RESOURCE_DATA_LEVEL,
&ResourceDataEntry);
/* Make sure it worked */
if (NT_SUCCESS(Status))
{
/* Now actually get a pointer to it */
Status = LdrAccessResource(LdrEntry->DllBase,
ResourceDataEntry,
(PVOID*)&BugCheckData,
NULL);
if (NT_SUCCESS(Status)) KiBugCodeMessages = BugCheckData;
}
}
BOOLEAN
NTAPI
KeGetBugMessageText(IN ULONG BugCheckCode,
OUT PANSI_STRING OutputString OPTIONAL)
{
ULONG i;
ULONG IdOffset;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
PCHAR BugCode;
USHORT Length;
BOOLEAN Result = FALSE;
/* Make sure we're not bugchecking too early */
if (!KiBugCodeMessages) return Result;
/*
* Globally protect in SEH as we are trying to access data in
* dire situations, and potentially going to patch it (see below).
*/
_SEH2_TRY
{
/*
* Make the kernel resource section writable, as we are going to manually
* trim the trailing newlines in the bugcheck resource message in place,
* when OutputString is NULL and before displaying it on screen.
*/
MmMakeKernelResourceSectionWritable();
/* Find the message. This code is based on RtlFindMesssage */
for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++)
{
/* Check if the ID matches */
if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) &&
(BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId))
{
/* Get offset to entry */
MessageEntry = (PMESSAGE_RESOURCE_ENTRY)
((ULONG_PTR)KiBugCodeMessages + KiBugCodeMessages->Blocks[i].OffsetToEntries);
IdOffset = BugCheckCode - KiBugCodeMessages->Blocks[i].LowId;
/* Advance in the entries until finding it */
while (IdOffset--)
{
MessageEntry = (PMESSAGE_RESOURCE_ENTRY)
((ULONG_PTR)MessageEntry + MessageEntry->Length);
}
/* Make sure it's not Unicode */
ASSERT(!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE));
/* Get the final code */
BugCode = (PCHAR)MessageEntry->Text;
Length = (USHORT)strlen(BugCode);
/* Handle trailing newlines */
while ((Length > 0) && ((BugCode[Length - 1] == '\n') ||
(BugCode[Length - 1] == '\r') ||
(BugCode[Length - 1] == ANSI_NULL)))
{
/* Directly trim the newline in place if we don't return the string */
if (!OutputString) BugCode[Length - 1] = ANSI_NULL;
/* Skip the trailing newline */
Length--;
}
/* Check if caller wants an output string */
if (OutputString)
{
/* Return it in the OutputString */
OutputString->Buffer = BugCode;
OutputString->Length = Length;
OutputString->MaximumLength = Length;
}
else
{
/* Direct output to screen */
InbvDisplayString(BugCode);
InbvDisplayString("\r");
}
/* We're done */
Result = TRUE;
break;
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
}
_SEH2_END;
/* Return the result */
return Result;
}
VOID
NTAPI
KiDoBugCheckCallbacks(VOID)
{
PKBUGCHECK_CALLBACK_RECORD CurrentRecord;
PLIST_ENTRY ListHead, NextEntry, LastEntry;
ULONG_PTR Checksum;
/* First make sure that the list is initialized... it might not be */
ListHead = &KeBugcheckCallbackListHead;
if ((!ListHead->Flink) || (!ListHead->Blink))
return;
/* Loop the list */
LastEntry = ListHead;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Get the reord */
CurrentRecord = CONTAINING_RECORD(NextEntry,
KBUGCHECK_CALLBACK_RECORD,
Entry);
/* Validate it */
// TODO/FIXME: Check whether the memory CurrentRecord points to
// is still accessible and valid!
if (CurrentRecord->Entry.Blink != LastEntry) return;
Checksum = (ULONG_PTR)CurrentRecord->CallbackRoutine;
Checksum += (ULONG_PTR)CurrentRecord->Buffer;
Checksum += (ULONG_PTR)CurrentRecord->Length;
Checksum += (ULONG_PTR)CurrentRecord->Component;
/* Make sure it's inserted and validated */
if ((CurrentRecord->State == BufferInserted) &&
(CurrentRecord->Checksum == Checksum))
{
/* Call the routine */
CurrentRecord->State = BufferStarted;
_SEH2_TRY
{
(CurrentRecord->CallbackRoutine)(CurrentRecord->Buffer,
CurrentRecord->Length);
CurrentRecord->State = BufferFinished;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
CurrentRecord->State = BufferIncomplete;
}
_SEH2_END;
}
/* Go to the next entry */
LastEntry = NextEntry;
NextEntry = NextEntry->Flink;
}
}
VOID
NTAPI
KiBugCheckDebugBreak(IN ULONG StatusCode)
{
- Stub out DbgKdWriteVirtualMemoryApi, DbgKdReadPhysicalMemoryApi, DbgKdWritePhysicalMemoryApi, DbgKdWriteBreakPointExApi, DbgKdRestoreBreakPointExApi, DbgKdSearchMemoryApi and DbgKdFillMemoryApi cases more properly. - Fail on physical memory write like we do for read too. - Don't handle OldVlm1/2 as they appear to be deprecated and unhandled in Windows. - Implement HalHaltSystem to halt execution in a portable way. Default to xHalHaltSystem, a simple infinite loop, if we get called before HAL has initialized. Use this in KiBugCheckDebugBreak and the system shutdown handler instead of x86/AMD64/ARM intrinsics. - Don't try to halt the CPU if KeBugCheck has been called 3 times or more -- if this happens, something has gone very wrong, and we shouldn't try to do anything special. Just loop infinitely. - Fix KiBugCheckDebugBreak -- it shouldn't halt execution when called for the first chance as bugcheck callbacks have not been invoked at this point (nor has the BSOD been displayed). Use SEH to protect against a crash instead of checking KdDebuggerNotPresent as the debugger, if it is present, *could* disconnect while the trap is being handled. Also, don't halt execution if the debugger handled the breakpoint, just break again. - Don't call MmMapIoSpace from HalpReboot! The reboot might take place at elevated IRQL (as high as HIGH_LEVEL if called from KeBugCheck), and thus can't use any Mm support routines. Use a PTE from the reserved HAL region and map it ourselves instead as done in the BIOS call code. - Acquire the display ownership in HalReturnToFirmware in case the caller hasn't done so (as done in the KD reboot routine, for example). - Just include ntndk.h in hal.h instead of including 6 NDK headers (which turns into more than half of the NDK anyway since those headers include other NDK headers). - Crashing and rebooting from KD now works properly. svn path=/trunk/; revision=43380
2009-10-11 20:16:45 +00:00
/*
* Wrap this in SEH so we don't crash if
* there is no debugger or if it disconnected
*/
DoBreak:
_SEH2_TRY
{
/* Breakpoint */
DbgBreakPointWithStatus(StatusCode);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* No debugger, halt the CPU */
HalHaltSystem();
}
_SEH2_END;
/* Break again if this wasn't first try */
if (StatusCode != DBG_STATUS_BUGCHECK_FIRST) goto DoBreak;
}
PCHAR
NTAPI
KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode,
OUT PCHAR Ansi,
IN ULONG Length)
{
PCHAR p;
PWCHAR pw;
ULONG i;
/* Set length and normalize it */
i = Unicode->Length / sizeof(WCHAR);
i = min(i, Length - 1);
/* Set source and destination, and copy */
pw = Unicode->Buffer;
p = Ansi;
while (i--) *p++ = (CHAR)*pw++;
/* Null terminate and return */
*p = ANSI_NULL;
return Ansi;
}
VOID
NTAPI
KiDumpParameterImages(IN PCHAR Message,
IN PULONG_PTR Parameters,
IN ULONG ParameterCount,
IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine)
{
ULONG i;
BOOLEAN InSystem;
PLDR_DATA_TABLE_ENTRY LdrEntry;
PVOID ImageBase;
PUNICODE_STRING DriverName;
CHAR AnsiName[32];
PIMAGE_NT_HEADERS NtHeader;
ULONG TimeStamp;
BOOLEAN FirstRun = TRUE;
/* Loop parameters */
for (i = 0; i < ParameterCount; i++)
{
/* Get the base for this parameter */
ImageBase = KiPcToFileHeader((PVOID)Parameters[i],
&LdrEntry,
FALSE,
&InSystem);
if (!ImageBase)
{
/* FIXME: Add code to check for unloaded drivers */
DPRINT1("Potentially unloaded driver!\n");
continue;
}
else
{
/* Get the NT Headers and Timestamp */
NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
TimeStamp = NtHeader->FileHeader.TimeDateStamp;
/* Convert the driver name */
DriverName = &LdrEntry->BaseDllName;
ConversionRoutine(&LdrEntry->BaseDllName,
AnsiName,
sizeof(AnsiName));
}
/* Format driver name */
sprintf(Message,
"%s** %12s - Address %p base at %p, DateStamp %08lx\r\n",
FirstRun ? "\r\n*":"*",
AnsiName,
(PVOID)Parameters[i],
ImageBase,
TimeStamp);
/* Check if we only had one parameter */
if (ParameterCount <= 1)
{
/* Then just save the name */
KiBugCheckDriver = DriverName;
}
else
{
/* Otherwise, display the message */
InbvDisplayString(Message);
}
/* Loop again */
FirstRun = FALSE;
}
}
VOID
NTAPI
KiDisplayBlueScreen(IN ULONG MessageId,
IN BOOLEAN IsHardError,
IN PCHAR HardErrCaption OPTIONAL,
IN PCHAR HardErrMessage OPTIONAL,
IN PCHAR Message)
{
CHAR AnsiName[107];
/* Check if bootvid is installed */
if (InbvIsBootDriverInstalled())
{
/* Acquire ownership and reset the display */
InbvAcquireDisplayOwnership();
InbvResetDisplay();
/* Display blue screen */
InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLUE);
InbvSetTextColor(BV_COLOR_WHITE);
InbvInstallDisplayStringFilter(NULL);
InbvEnableDisplayString(TRUE);
InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
}
/* Check if this is a hard error */
if (IsHardError)
{
/* Display caption and message */
if (HardErrCaption) InbvDisplayString(HardErrCaption);
if (HardErrMessage) InbvDisplayString(HardErrMessage);
}
/* Begin the display */
InbvDisplayString("\r\n");
/* Print out initial message */
KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
InbvDisplayString("\r\n\r\n");
/* Check if we have a driver */
if (KiBugCheckDriver)
{
/* Print out into to driver name */
KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
/* Convert and print out driver name */
KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
InbvDisplayString(" ");
InbvDisplayString(AnsiName);
InbvDisplayString("\r\n\r\n");
}
/* Check if this is the generic message */
if (MessageId == BUGCODE_PSS_MESSAGE)
{
/* It is, so get the bug code string as well */
KeGetBugMessageText((ULONG)KiBugCheckData[0], NULL);
InbvDisplayString("\r\n\r\n");
}
/* Print second introduction message */
KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
InbvDisplayString("\r\n\r\n");
/* Get the bug code string */
KeGetBugMessageText(MessageId, NULL);
InbvDisplayString("\r\n\r\n");
/* Print message for technical information */
KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
/* Show the technical Data */
RtlStringCbPrintfA(AnsiName,
sizeof(AnsiName),
"\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
(ULONG)KiBugCheckData[0],
(PVOID)KiBugCheckData[1],
(PVOID)KiBugCheckData[2],
(PVOID)KiBugCheckData[3],
(PVOID)KiBugCheckData[4]);
InbvDisplayString(AnsiName);
/* Check if we have a driver*/
if (KiBugCheckDriver)
{
/* Display technical driver data */
InbvDisplayString(Message);
}
else
{
/* Dump parameter information */
KiDumpParameterImages(Message,
(PVOID)&KiBugCheckData[1],
4,
KeBugCheckUnicodeToAnsi);
}
}
DECLSPEC_NORETURN
VOID
NTAPI
KeBugCheckWithTf(IN ULONG BugCheckCode,
IN ULONG_PTR BugCheckParameter1,
IN ULONG_PTR BugCheckParameter2,
IN ULONG_PTR BugCheckParameter3,
IN ULONG_PTR BugCheckParameter4,
IN PKTRAP_FRAME TrapFrame)
{
PKPRCB Prcb = KeGetCurrentPrcb();
CONTEXT Context;
ULONG MessageId;
CHAR AnsiName[128];
BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
PVOID Pc = NULL, Memory;
PVOID DriverBase;
PLDR_DATA_TABLE_ENTRY LdrEntry;
PULONG_PTR HardErrorParameters;
KIRQL OldIrql;
/* Set active bugcheck */
KeBugCheckActive = TRUE;
KiBugCheckDriver = NULL;
/* Check if this is power failure simulation */
if (BugCheckCode == POWER_FAILURE_SIMULATE)
{
/* Call the Callbacks and reboot */
KiDoBugCheckCallbacks();
HalReturnToFirmware(HalRebootRoutine);
}
/* Save the IRQL and set hardware trigger */
Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
InterlockedIncrement((PLONG)&KiHardwareTrigger);
/* Capture the CPU Context */
RtlCaptureContext(&Prcb->ProcessorState.ContextFrame);
KiSaveProcessorControlState(&Prcb->ProcessorState);
Context = Prcb->ProcessorState.ContextFrame;
/* FIXME: Call the Watchdog if it's registered */
/* Check which bugcode this is */
switch (BugCheckCode)
{
/* These bug checks already have detailed messages, keep them */
case UNEXPECTED_KERNEL_MODE_TRAP:
case DRIVER_CORRUPTED_EXPOOL:
case ACPI_BIOS_ERROR:
case ACPI_BIOS_FATAL_ERROR:
case THREAD_STUCK_IN_DEVICE_DRIVER:
case DATA_BUS_ERROR:
case FAT_FILE_SYSTEM:
case NO_MORE_SYSTEM_PTES:
case INACCESSIBLE_BOOT_DEVICE:
/* Keep the same code */
MessageId = BugCheckCode;
break;
/* Check if this is a kernel-mode exception */
case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
case KMODE_EXCEPTION_NOT_HANDLED:
/* Use the generic text message */
MessageId = KMODE_EXCEPTION_NOT_HANDLED;
break;
/* File-system errors */
case NTFS_FILE_SYSTEM:
/* Use the generic message for FAT */
MessageId = FAT_FILE_SYSTEM;
break;
/* Check if this is a coruption of the Mm's Pool */
case DRIVER_CORRUPTED_MMPOOL:
/* Use generic corruption message */
MessageId = DRIVER_CORRUPTED_EXPOOL;
break;
/* Check if this is a signature check failure */
case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
/* Use the generic corruption message */
MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
break;
/* All other codes */
default:
/* Use the default bugcheck message */
MessageId = BUGCODE_PSS_MESSAGE;
break;
}
/* Save bugcheck data */
KiBugCheckData[0] = BugCheckCode;
KiBugCheckData[1] = BugCheckParameter1;
KiBugCheckData[2] = BugCheckParameter2;
KiBugCheckData[3] = BugCheckParameter3;
KiBugCheckData[4] = BugCheckParameter4;
/* Now check what bugcheck this is */
switch (BugCheckCode)
{
/* Invalid access to R/O memory or Unhandled KM Exception */
case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY:
{
/* Check if we have a trap frame */
if (!TrapFrame)
{
/* Use parameter 3 as a trap frame, if it exists */
if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
}
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
/* Check if we got one now and if we need to get the Program Counter */
if ((TrapFrame) &&
(BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
{
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
/* Get the Program Counter */
Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
}
break;
}
/* Wrong IRQL */
case IRQL_NOT_LESS_OR_EQUAL:
{
/*
* The NT kernel has 3 special sections:
* MISYSPTE, POOLMI and POOLCODE. The bug check code can
* determine in which of these sections this bugcode happened
* and provide a more detailed analysis. For now, we don't.
*/
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
/* Program Counter is in parameter 4 */
Pc = (PVOID)BugCheckParameter4;
/* Get the driver base */
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
DriverBase = KiPcToFileHeader(Pc,
&LdrEntry,
FALSE,
&IsSystem);
if (IsSystem)
{
/*
* The error happened inside the kernel or HAL.
* Get the memory address that was being referenced.
*/
Memory = (PVOID)BugCheckParameter1;
/* Find to which driver it belongs */
DriverBase = KiPcToFileHeader(Memory,
&LdrEntry,
TRUE,
&IsSystem);
if (DriverBase)
{
/* Get the driver name and update the bug code */
KiBugCheckDriver = &LdrEntry->BaseDllName;
KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
}
else
{
/* Find the driver that unloaded at this address */
KiBugCheckDriver = NULL; // FIXME: ROS can't locate
/* Check if the cause was an unloaded driver */
if (KiBugCheckDriver)
{
/* Update bug check code */
KiBugCheckData[0] =
SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
}
}
}
else
{
/* Update the bug check code */
KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
}
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
/* Clear Pc so we don't look it up later */
Pc = NULL;
break;
}
/* Hard error */
case FATAL_UNHANDLED_HARD_ERROR:
{
/* Copy bug check data from hard error */
HardErrorParameters = (PULONG_PTR)BugCheckParameter2;
KiBugCheckData[0] = BugCheckParameter1;
KiBugCheckData[1] = HardErrorParameters[0];
KiBugCheckData[2] = HardErrorParameters[1];
KiBugCheckData[3] = HardErrorParameters[2];
KiBugCheckData[4] = HardErrorParameters[3];
/* Remember that this is hard error and set the caption/message */
IsHardError = TRUE;
HardErrCaption = (PCHAR)BugCheckParameter3;
HardErrMessage = (PCHAR)BugCheckParameter4;
break;
}
/* Page fault */
case PAGE_FAULT_IN_NONPAGED_AREA:
{
/* Assume no driver */
DriverBase = NULL;
/* Check if we have a trap frame */
if (!TrapFrame)
{
/* We don't, use parameter 3 if possible */
if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
}
/* Check if we have a frame now */
if (TrapFrame)
{
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
/* Get the Program Counter */
Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
KiBugCheckData[3] = (ULONG_PTR)Pc;
/* Find out if was in the kernel or drivers */
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
DriverBase = KiPcToFileHeader(Pc,
&LdrEntry,
FALSE,
&IsSystem);
}
else
{
/* Can't blame a driver, assume system */
IsSystem = TRUE;
}
/* FIXME: Check for session pool in addition to special pool */
/* Special pool has its own bug check codes */
if (MmIsSpecialPoolAddress((PVOID)BugCheckParameter1))
{
if (MmIsSpecialPoolAddressFree((PVOID)BugCheckParameter1))
{
KiBugCheckData[0] = IsSystem
? PAGE_FAULT_IN_FREED_SPECIAL_POOL
: DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL;
}
else
{
KiBugCheckData[0] = IsSystem
? PAGE_FAULT_BEYOND_END_OF_ALLOCATION
: DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION;
}
}
else if (!DriverBase)
{
/* Find the driver that unloaded at this address */
KiBugCheckDriver = NULL; // FIXME: ROS can't locate
/* Check if the cause was an unloaded driver */
if (KiBugCheckDriver)
{
KiBugCheckData[0] =
DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
}
}
break;
}
/* Check if the driver forgot to unlock pages */
case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
/* Program Counter is in parameter 1 */
Pc = (PVOID)BugCheckParameter1;
break;
/* Check if the driver consumed too many PTEs */
case DRIVER_USED_EXCESSIVE_PTES:
/* Loader entry is in parameter 1 */
LdrEntry = (PVOID)BugCheckParameter1;
KiBugCheckDriver = &LdrEntry->BaseDllName;
break;
/* Check if the driver has a stuck thread */
case THREAD_STUCK_IN_DEVICE_DRIVER:
/* The name is in Parameter 3 */
KiBugCheckDriver = (PVOID)BugCheckParameter3;
break;
/* Anything else */
default:
break;
}
/* Do we have a driver name? */
if (KiBugCheckDriver)
{
/* Convert it to ANSI */
KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
}
else
{
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
/* Do we have a Program Counter? */
if (Pc)
{
/* Dump image name */
KiDumpParameterImages(AnsiName,
Mega KD64 revival patch: KD64 - Fix some 64-bit issues and some x86 specificness. - Sub out some KdpTrap cases more properly. - Implement support for .crash and .reboot. Does not seem to work currently because of weird issues. - Implement KdpDprintf to send strings directly to the debugger from inside of KD64. Use it in KdEnterDebugger instead of DbgPrint so we won't try to enter the debugger recursively. - Implement KdUpdateDataBlock to set the KeUserCallbackDispatcher pointer in the debugger block after its address is retrieved from ntdll. - Don't assume breakpoints are 1 byte long in portable code -- use KD_BREAKPOINT_SIZE and define it per architecture. - KdpStub: KdEnableDebugger returns NTSTATUS, not TRUE/FALSE. Other - wdbgexts.h: Properly define CURRENT_KD_SECONDARY_VERSION for AMD64. - Make PsNtosImageBase pointer-sized as it should be. - Change the definition of KDSTATUS so it is guaranteed to be 32-bit. - Fix a critical bug in KiRestoreProcessorControlState: it didn't clear the busy flag in the TSS before reloading the task register, resulting in a GPF if we tried to reload the same register. - Add macros for getting and setting special purpose registers (the Program Counter and the "return register") in portable code instead of using #ifdef every time. Do likewise for setting IMAGE_FILE_MACHINE_XXX, using a new IMAGE_FILE_MACHINE_ARCHITECTURE macro. - Don't refer to the Program Counter as "Eip" in portable code. - Define DBG_STATUS_CONTROL_C for assembly code and use it in KeUpdateSystemTime. svn path=/trunk/; revision=43283
2009-10-04 16:53:15 +00:00
(PULONG_PTR)&Pc,
1,
KeBugCheckUnicodeToAnsi);
}
}
/* Check if we need to save the context for KD */
if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG_PTR)&Context;
/* Check if a debugger is connected */
if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
{
/* Crash on the debugger console */
DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
" (0x%p,0x%p,0x%p,0x%p)\n\n",
KiBugCheckData[0],
KiBugCheckData[1],
KiBugCheckData[2],
KiBugCheckData[3],
KiBugCheckData[4]);
/* Check if the debugger isn't currently connected */
if (!KdDebuggerNotPresent)
{
/* Check if we have a driver to blame */
if (KiBugCheckDriver)
{
/* Dump it */
DbgPrint("Driver at fault: %s.\n", AnsiName);
}
/* Check if this was a hard error */
if (IsHardError)
{
/* Print caption and message */
if (HardErrCaption) DbgPrint(HardErrCaption);
if (HardErrMessage) DbgPrint(HardErrMessage);
}
/* Break in the debugger */
KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
}
}
/* Raise IRQL to HIGH_LEVEL */
_disable();
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
/* Avoid recursion */
if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
{
#ifdef CONFIG_SMP
/* Set CPU that is bug checking now */
KeBugCheckOwner = Prcb->Number;
/* Freeze the other CPUs */
for (ULONG i = 0; i < KeNumberProcessors; i++)
{
if (i != Prcb->Number)
{
/* Send the IPI */
KiIpiSend(AFFINITY_MASK(i), IPI_FREEZE);
}
}
/* Give the other CPUs one second to catch up */
KeStallExecutionProcessor(1000000);
#endif
/* Display the BSOD */
KiDisplayBlueScreen(MessageId,
IsHardError,
HardErrCaption,
HardErrMessage,
AnsiName);
// TODO/FIXME: Run the registered reason-callbacks from
// the KeBugcheckReasonCallbackListHead list with the
// KbCallbackReserved1 reason.
/* Check if the debugger is disabled but we can enable it */
if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
{
/* Enable it */
KdEnableDebuggerWithLock(FALSE);
}
else
{
/* Otherwise, print the last line */
InbvDisplayString("\r\n");
}
/* Save the context */
Prcb->ProcessorState.ContextFrame = Context;
/* FIXME: Support Triage Dump */
/* FIXME: Write the crash dump */
}
else
{
/* Increase recursion count */
KeBugCheckOwnerRecursionCount++;
if (KeBugCheckOwnerRecursionCount == 2)
{
/* Break in the debugger */
KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
}
else if (KeBugCheckOwnerRecursionCount > 2)
{
- Stub out DbgKdWriteVirtualMemoryApi, DbgKdReadPhysicalMemoryApi, DbgKdWritePhysicalMemoryApi, DbgKdWriteBreakPointExApi, DbgKdRestoreBreakPointExApi, DbgKdSearchMemoryApi and DbgKdFillMemoryApi cases more properly. - Fail on physical memory write like we do for read too. - Don't handle OldVlm1/2 as they appear to be deprecated and unhandled in Windows. - Implement HalHaltSystem to halt execution in a portable way. Default to xHalHaltSystem, a simple infinite loop, if we get called before HAL has initialized. Use this in KiBugCheckDebugBreak and the system shutdown handler instead of x86/AMD64/ARM intrinsics. - Don't try to halt the CPU if KeBugCheck has been called 3 times or more -- if this happens, something has gone very wrong, and we shouldn't try to do anything special. Just loop infinitely. - Fix KiBugCheckDebugBreak -- it shouldn't halt execution when called for the first chance as bugcheck callbacks have not been invoked at this point (nor has the BSOD been displayed). Use SEH to protect against a crash instead of checking KdDebuggerNotPresent as the debugger, if it is present, *could* disconnect while the trap is being handled. Also, don't halt execution if the debugger handled the breakpoint, just break again. - Don't call MmMapIoSpace from HalpReboot! The reboot might take place at elevated IRQL (as high as HIGH_LEVEL if called from KeBugCheck), and thus can't use any Mm support routines. Use a PTE from the reserved HAL region and map it ourselves instead as done in the BIOS call code. - Acquire the display ownership in HalReturnToFirmware in case the caller hasn't done so (as done in the KD reboot routine, for example). - Just include ntndk.h in hal.h instead of including 6 NDK headers (which turns into more than half of the NDK anyway since those headers include other NDK headers). - Crashing and rebooting from KD now works properly. svn path=/trunk/; revision=43380
2009-10-11 20:16:45 +00:00
/* Halt execution */
while (TRUE);
}
}
/* Call the Callbacks */
KiDoBugCheckCallbacks();
/* FIXME: Call Watchdog if enabled */
/* Check if we have to reboot */
if (Reboot)
{
/* Unload symbols */
- DBGKD_WAIT_STATE_CHANGE64 is used in KD protocol 5, not number 6 that we use. Protocol 6 uses the DBGKD_ANY_WAIT_STATE_CHANGE structure which is sized according to the largest control-report structure (AMD64_DBGKD_CONTROL_REPORT currently), and is larger than DBGKD_WAIT_STATE_CHANGE64 on x86. This worked because our DBGKD_WAIT_STATE_CHANGE32/64 structures contained incorrect DBGKD_CONTROL_REPORT (used) and CONTEXT (unused) members that sized up the wait-state structure to pass WinDbg's length verification! It actually becomes larger than DBGKD_ANY_WAIT_STATE_CHANGE, but WinDbg only seems bail out only if the structure is too small. Remove the incorrect members from the protocol 5 structures and change to DBGKD_ANY_WAIT_STATE_CHANGE everywhere. - Correct the value of SIZE_OF_FX_REGISTERS -- it was 4 times too low which resulted in KeContextToTrapFrame not properly clearing out the XMM register area. Correct the define and move it out from ke.h to x86's ketypes.h and use it in the FXSAVE format structure. Also remove the IOPM definitions from ke.h as they have been in the NDK for a while. - KD uses STRINGs, not ANSI_STRINGs -- they are the same thing, but let's be consistent. - ExceptionRecord32To64 should be available for both 32 and 64 bit builds (and it shouldn't be a forceinline). Get rid of CopyExceptionRecord and determine if we need to convert or can just copy it directly instead. - Use _WIN64 instead of _M_AMD64 when determining if we need to set the DBGKD_VERS_FLAG_PTR64 flag. - Don't check Nt/DbgQueryDebugFilterState for zero or nonzero -- it actually returns TRUE, FALSE or STATUS_INVALID_PARAMETER_1! Check for != TRUE in preparation for proper implementation of NtSet/QueryDebugFilterState. - Fix Format parameter of DbgPrintReturnControlC -- it is const like the other DbgPrint* routines. - Be consistent with the types used in debug.c and don't set local variables to zero if we are going to return to caller -- this doesn't seem to be required anymore. - Fix DebugService and DebugService2: DebugService should take a ULONG followed by 4 pointers and DebugService2 doesn't return anything. - Use ZwCurrentProcess() instead of -1 or 0xFFFFFFFF (which is incorrect for 64-bit) for the ProcessId parameter of DbgLoad/UnloadImageSymbols to clarify what is being passed. Don't use ZwCurrentProcess() in KeBugCheckWithTf for the pointer parameter of DbgUnLoadImageSymbols either. Use MAXULONG_PTR casted to PVOID instead. - Use better named and sized variables in KdpTrap for setting the "return register" in the caller's CONTEXT. - Correct and clarify the comment documenting under what conditions we pass user mode exceptions to the kernel debugger. svn path=/trunk/; revision=43741
2009-10-25 15:56:38 +00:00
DbgUnLoadImageSymbols(NULL, (PVOID)MAXULONG_PTR, 0);
HalReturnToFirmware(HalRebootRoutine);
}
/* Attempt to break in the debugger (otherwise halt CPU) */
KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
- Stub out DbgKdWriteVirtualMemoryApi, DbgKdReadPhysicalMemoryApi, DbgKdWritePhysicalMemoryApi, DbgKdWriteBreakPointExApi, DbgKdRestoreBreakPointExApi, DbgKdSearchMemoryApi and DbgKdFillMemoryApi cases more properly. - Fail on physical memory write like we do for read too. - Don't handle OldVlm1/2 as they appear to be deprecated and unhandled in Windows. - Implement HalHaltSystem to halt execution in a portable way. Default to xHalHaltSystem, a simple infinite loop, if we get called before HAL has initialized. Use this in KiBugCheckDebugBreak and the system shutdown handler instead of x86/AMD64/ARM intrinsics. - Don't try to halt the CPU if KeBugCheck has been called 3 times or more -- if this happens, something has gone very wrong, and we shouldn't try to do anything special. Just loop infinitely. - Fix KiBugCheckDebugBreak -- it shouldn't halt execution when called for the first chance as bugcheck callbacks have not been invoked at this point (nor has the BSOD been displayed). Use SEH to protect against a crash instead of checking KdDebuggerNotPresent as the debugger, if it is present, *could* disconnect while the trap is being handled. Also, don't halt execution if the debugger handled the breakpoint, just break again. - Don't call MmMapIoSpace from HalpReboot! The reboot might take place at elevated IRQL (as high as HIGH_LEVEL if called from KeBugCheck), and thus can't use any Mm support routines. Use a PTE from the reserved HAL region and map it ourselves instead as done in the BIOS call code. - Acquire the display ownership in HalReturnToFirmware in case the caller hasn't done so (as done in the KD reboot routine, for example). - Just include ntndk.h in hal.h instead of including 6 NDK headers (which turns into more than half of the NDK anyway since those headers include other NDK headers). - Crashing and rebooting from KD now works properly. svn path=/trunk/; revision=43380
2009-10-11 20:16:45 +00:00
/* Shouldn't get here */
ASSERT(FALSE);
- Stub out DbgKdWriteVirtualMemoryApi, DbgKdReadPhysicalMemoryApi, DbgKdWritePhysicalMemoryApi, DbgKdWriteBreakPointExApi, DbgKdRestoreBreakPointExApi, DbgKdSearchMemoryApi and DbgKdFillMemoryApi cases more properly. - Fail on physical memory write like we do for read too. - Don't handle OldVlm1/2 as they appear to be deprecated and unhandled in Windows. - Implement HalHaltSystem to halt execution in a portable way. Default to xHalHaltSystem, a simple infinite loop, if we get called before HAL has initialized. Use this in KiBugCheckDebugBreak and the system shutdown handler instead of x86/AMD64/ARM intrinsics. - Don't try to halt the CPU if KeBugCheck has been called 3 times or more -- if this happens, something has gone very wrong, and we shouldn't try to do anything special. Just loop infinitely. - Fix KiBugCheckDebugBreak -- it shouldn't halt execution when called for the first chance as bugcheck callbacks have not been invoked at this point (nor has the BSOD been displayed). Use SEH to protect against a crash instead of checking KdDebuggerNotPresent as the debugger, if it is present, *could* disconnect while the trap is being handled. Also, don't halt execution if the debugger handled the breakpoint, just break again. - Don't call MmMapIoSpace from HalpReboot! The reboot might take place at elevated IRQL (as high as HIGH_LEVEL if called from KeBugCheck), and thus can't use any Mm support routines. Use a PTE from the reserved HAL region and map it ourselves instead as done in the BIOS call code. - Acquire the display ownership in HalReturnToFirmware in case the caller hasn't done so (as done in the KD reboot routine, for example). - Just include ntndk.h in hal.h instead of including 6 NDK headers (which turns into more than half of the NDK anyway since those headers include other NDK headers). - Crashing and rebooting from KD now works properly. svn path=/trunk/; revision=43380
2009-10-11 20:16:45 +00:00
while (TRUE);
}
BOOLEAN
NTAPI
KiHandleNmi(VOID)
{
BOOLEAN Handled = FALSE;
PKNMI_HANDLER_CALLBACK NmiData;
/* Parse the list of callbacks */
NmiData = KiNmiCallbackListHead;
while (NmiData)
{
/* Save if this callback has handled it -- all it takes is one */
Handled |= NmiData->Callback(NmiData->Context, Handled);
NmiData = NmiData->Next;
}
/* Has anyone handled this? */
return Handled;
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @unimplemented
*/
NTSTATUS
NTAPI
KeInitializeCrashDumpHeader(IN ULONG Type,
IN ULONG Flags,
OUT PVOID Buffer,
IN ULONG BufferSize,
OUT ULONG BufferNeeded OPTIONAL)
{
UNIMPLEMENTED;
return STATUS_UNSUCCESSFUL;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
{
KIRQL OldIrql;
BOOLEAN Status = FALSE;
/* Raise IRQL to High */
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
/* Check the Current State */
if (CallbackRecord->State == BufferInserted)
{
/* Reset state and remove from list */
CallbackRecord->State = BufferEmpty;
RemoveEntryList(&CallbackRecord->Entry);
Status = TRUE;
}
/* Lower IRQL and return */
KeLowerIrql(OldIrql);
return Status;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
KeDeregisterBugCheckReasonCallback(
IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
{
KIRQL OldIrql;
BOOLEAN Status = FALSE;
/* Raise IRQL to High */
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
/* Check the Current State */
if (CallbackRecord->State == BufferInserted)
{
/* Reset state and remove from list */
CallbackRecord->State = BufferEmpty;
RemoveEntryList(&CallbackRecord->Entry);
Status = TRUE;
}
/* Lower IRQL and return */
KeLowerIrql(OldIrql);
return Status;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
IN PVOID Buffer,
IN ULONG Length,
IN PUCHAR Component)
{
KIRQL OldIrql;
BOOLEAN Status = FALSE;
/* Raise IRQL to High */
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
/* Check the Current State first so we don't double-register */
if (CallbackRecord->State == BufferEmpty)
{
/* Set the Callback Settings and insert into the list */
CallbackRecord->Length = Length;
CallbackRecord->Buffer = Buffer;
CallbackRecord->Component = Component;
CallbackRecord->CallbackRoutine = CallbackRoutine;
CallbackRecord->State = BufferInserted;
InsertTailList(&KeBugcheckCallbackListHead, &CallbackRecord->Entry);
Status = TRUE;
}
/* Lower IRQL and return */
KeLowerIrql(OldIrql);
return Status;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
KeRegisterBugCheckReasonCallback(
IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
IN KBUGCHECK_CALLBACK_REASON Reason,
IN PUCHAR Component)
{
KIRQL OldIrql;
BOOLEAN Status = FALSE;
/* Raise IRQL to High */
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
/* Check the Current State first so we don't double-register */
if (CallbackRecord->State == BufferEmpty)
{
/* Set the Callback Settings and insert into the list */
CallbackRecord->Component = Component;
CallbackRecord->CallbackRoutine = CallbackRoutine;
CallbackRecord->State = BufferInserted;
CallbackRecord->Reason = Reason;
InsertTailList(&KeBugcheckReasonCallbackListHead,
&CallbackRecord->Entry);
Status = TRUE;
}
/* Lower IRQL and return */
KeLowerIrql(OldIrql);
return Status;
}
/*
* @implemented
*/
PVOID
NTAPI
KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,
IN PVOID Context)
{
KIRQL OldIrql;
PKNMI_HANDLER_CALLBACK NmiData, Next;
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Allocate NMI callback data */
NmiData = ExAllocatePoolWithTag(NonPagedPool, sizeof(*NmiData), TAG_KNMI);
if (!NmiData) return NULL;
/* Fill in the information */
NmiData->Callback = CallbackRoutine;
NmiData->Context = Context;
NmiData->Handle = NmiData;
/* Insert it into NMI callback list */
KiAcquireNmiListLock(&OldIrql);
NmiData->Next = KiNmiCallbackListHead;
Next = InterlockedCompareExchangePointer((PVOID*)&KiNmiCallbackListHead,
NmiData,
NmiData->Next);
ASSERT(Next == NmiData->Next);
KiReleaseNmiListLock(OldIrql);
/* Return the opaque "handle" */
return NmiData->Handle;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
KeDeregisterNmiCallback(IN PVOID Handle)
{
KIRQL OldIrql;
PKNMI_HANDLER_CALLBACK NmiData;
PKNMI_HANDLER_CALLBACK* Previous;
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Find in the list the NMI callback corresponding to the handle */
KiAcquireNmiListLock(&OldIrql);
Previous = &KiNmiCallbackListHead;
NmiData = *Previous;
while (NmiData)
{
if (NmiData->Handle == Handle)
{
/* The handle is the pointer to the callback itself */
ASSERT(Handle == NmiData);
/* Found it, remove from the list */
*Previous = NmiData->Next;
break;
}
/* Not found; try again */
Previous = &NmiData->Next;
NmiData = *Previous;
}
KiReleaseNmiListLock(OldIrql);
/* If we have found the entry, free it */
if (NmiData)
{
ExFreePoolWithTag(NmiData, TAG_KNMI);
return STATUS_SUCCESS;
}
return STATUS_INVALID_HANDLE;
}
/*
* @implemented
*/
DECLSPEC_NORETURN
VOID
NTAPI
KeBugCheckEx(IN ULONG BugCheckCode,
IN ULONG_PTR BugCheckParameter1,
IN ULONG_PTR BugCheckParameter2,
IN ULONG_PTR BugCheckParameter3,
IN ULONG_PTR BugCheckParameter4)
{
/* Call the internal API */
KeBugCheckWithTf(BugCheckCode,
BugCheckParameter1,
BugCheckParameter2,
BugCheckParameter3,
BugCheckParameter4,
NULL);
}
/*
* @implemented
*/
DECLSPEC_NORETURN
VOID
NTAPI
KeBugCheck(ULONG BugCheckCode)
{
/* Call the internal API */
KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
}
/*
* @implemented
*/
VOID
NTAPI
KeEnterKernelDebugger(VOID)
{
/* Disable interrupts */
KiHardwareTrigger = 1;
_disable();
/* Check the bugcheck count */
if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
{
/* There was only one, is the debugger disabled? */
if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
{
/* Enable the debugger */
KdInitSystem(0, NULL);
}
}
- Stub out DbgKdWriteVirtualMemoryApi, DbgKdReadPhysicalMemoryApi, DbgKdWritePhysicalMemoryApi, DbgKdWriteBreakPointExApi, DbgKdRestoreBreakPointExApi, DbgKdSearchMemoryApi and DbgKdFillMemoryApi cases more properly. - Fail on physical memory write like we do for read too. - Don't handle OldVlm1/2 as they appear to be deprecated and unhandled in Windows. - Implement HalHaltSystem to halt execution in a portable way. Default to xHalHaltSystem, a simple infinite loop, if we get called before HAL has initialized. Use this in KiBugCheckDebugBreak and the system shutdown handler instead of x86/AMD64/ARM intrinsics. - Don't try to halt the CPU if KeBugCheck has been called 3 times or more -- if this happens, something has gone very wrong, and we shouldn't try to do anything special. Just loop infinitely. - Fix KiBugCheckDebugBreak -- it shouldn't halt execution when called for the first chance as bugcheck callbacks have not been invoked at this point (nor has the BSOD been displayed). Use SEH to protect against a crash instead of checking KdDebuggerNotPresent as the debugger, if it is present, *could* disconnect while the trap is being handled. Also, don't halt execution if the debugger handled the breakpoint, just break again. - Don't call MmMapIoSpace from HalpReboot! The reboot might take place at elevated IRQL (as high as HIGH_LEVEL if called from KeBugCheck), and thus can't use any Mm support routines. Use a PTE from the reserved HAL region and map it ourselves instead as done in the BIOS call code. - Acquire the display ownership in HalReturnToFirmware in case the caller hasn't done so (as done in the KD reboot routine, for example). - Just include ntndk.h in hal.h instead of including 6 NDK headers (which turns into more than half of the NDK anyway since those headers include other NDK headers). - Crashing and rebooting from KD now works properly. svn path=/trunk/; revision=43380
2009-10-11 20:16:45 +00:00
/* Break in the debugger */
KiBugCheckDebugBreak(DBG_STATUS_FATAL);
}
/* EOF */