729 lines
17 KiB
C
729 lines
17 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
stubs.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements bug check and system shutdown code.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Mark Lucovsky (markl) 30-Aug-1990
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ki.h"
|
|||
|
|
|||
|
//
|
|||
|
// Define forward referenced prototypes.
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
KiScanBugCheckCallbackList (
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Define bug count recursion counter and a context buffer.
|
|||
|
//
|
|||
|
|
|||
|
ULONG KeBugCheckCount = 1;
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KeBugCheck (
|
|||
|
IN ULONG BugCheckCode
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function crashes the system in a controlled manner.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BugCheckCode - Supplies the reason for the bug check.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KeBugCheckEx(BugCheckCode,0,0,0,0);
|
|||
|
}
|
|||
|
|
|||
|
ULONG KiBugCheckData[5];
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
KeGetBugMessageText(
|
|||
|
IN ULONG MessageId,
|
|||
|
IN PANSI_STRING ReturnedString OPTIONAL
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
PUCHAR s;
|
|||
|
PMESSAGE_RESOURCE_BLOCK MessageBlock;
|
|||
|
PUCHAR Buffer;
|
|||
|
BOOLEAN Result;
|
|||
|
|
|||
|
Result = FALSE;
|
|||
|
try {
|
|||
|
if (KiBugCodeMessages != NULL) {
|
|||
|
MessageBlock = &KiBugCodeMessages->Blocks[0];
|
|||
|
for (i = KiBugCodeMessages->NumberOfBlocks; i; i--) {
|
|||
|
if (MessageId >= MessageBlock->LowId &&
|
|||
|
MessageId <= MessageBlock->HighId) {
|
|||
|
|
|||
|
s = (PCHAR)KiBugCodeMessages + MessageBlock->OffsetToEntries;
|
|||
|
for (i = MessageId - MessageBlock->LowId; i; i--) {
|
|||
|
s += ((PMESSAGE_RESOURCE_ENTRY)s)->Length;
|
|||
|
}
|
|||
|
|
|||
|
Buffer = ((PMESSAGE_RESOURCE_ENTRY)s)->Text;
|
|||
|
|
|||
|
i = strlen(Buffer) - 1;
|
|||
|
while (i > 0 && (Buffer[i] == '\n' ||
|
|||
|
Buffer[i] == '\r' ||
|
|||
|
Buffer[i] == 0
|
|||
|
)
|
|||
|
) {
|
|||
|
if (!ARGUMENT_PRESENT( ReturnedString )) {
|
|||
|
Buffer[i] = 0;
|
|||
|
}
|
|||
|
i -= 1;
|
|||
|
}
|
|||
|
|
|||
|
if (!ARGUMENT_PRESENT( ReturnedString )) {
|
|||
|
HalDisplayString(Buffer);
|
|||
|
}
|
|||
|
else {
|
|||
|
ReturnedString->Buffer = Buffer;
|
|||
|
ReturnedString->Length = (USHORT)(i+1);
|
|||
|
ReturnedString->MaximumLength = (USHORT)(i+1);
|
|||
|
}
|
|||
|
Result = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
MessageBlock++;
|
|||
|
}
|
|||
|
}
|
|||
|
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|||
|
;
|
|||
|
}
|
|||
|
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PCHAR
|
|||
|
KeBugCheckUnicodeToAnsi(
|
|||
|
IN PUNICODE_STRING UnicodeString,
|
|||
|
OUT PCHAR AnsiBuffer,
|
|||
|
IN ULONG MaxAnsiLength
|
|||
|
)
|
|||
|
{
|
|||
|
PCHAR Dst;
|
|||
|
PWSTR Src;
|
|||
|
ULONG Length;
|
|||
|
|
|||
|
Length = UnicodeString->Length / sizeof( WCHAR );
|
|||
|
if (Length >= MaxAnsiLength) {
|
|||
|
Length = MaxAnsiLength - 1;
|
|||
|
}
|
|||
|
Src = UnicodeString->Buffer;
|
|||
|
Dst = AnsiBuffer;
|
|||
|
while (Length--) {
|
|||
|
*Dst++ = (UCHAR)*Src++;
|
|||
|
}
|
|||
|
*Dst = '\0';
|
|||
|
return AnsiBuffer;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KeBugCheckEx (
|
|||
|
IN ULONG BugCheckCode,
|
|||
|
IN ULONG BugCheckParameter1,
|
|||
|
IN ULONG BugCheckParameter2,
|
|||
|
IN ULONG BugCheckParameter3,
|
|||
|
IN ULONG BugCheckParameter4
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function crashes the system in a controlled manner.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BugCheckCode - Supplies the reason for the bug check.
|
|||
|
|
|||
|
BugCheckParameter1-4 - Supplies additional bug check information
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR Buffer[100];
|
|||
|
ULONG BugCheckParameters[4];
|
|||
|
CONTEXT ContextSave;
|
|||
|
#if !defined(i386)
|
|||
|
KIRQL OldIrql;
|
|||
|
#endif
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
ULONG TargetSet;
|
|||
|
|
|||
|
#endif
|
|||
|
BOOLEAN hardErrorCalled;
|
|||
|
|
|||
|
//
|
|||
|
// Capture the callers context as closely as possible into the debugger's
|
|||
|
// processor state area of the Prcb
|
|||
|
//
|
|||
|
// N.B. There may be some prologue code that shuffles registers such that
|
|||
|
// they get destroyed.
|
|||
|
//
|
|||
|
|
|||
|
#if defined(i386)
|
|||
|
KiSetHardwareTrigger();
|
|||
|
#else
|
|||
|
KiHardwareTrigger = 1;
|
|||
|
#endif
|
|||
|
|
|||
|
RtlCaptureContext(&KeGetCurrentPrcb()->ProcessorState.ContextFrame);
|
|||
|
KiSaveProcessorControlState(&KeGetCurrentPrcb()->ProcessorState);
|
|||
|
|
|||
|
//
|
|||
|
// this is necessary on machines where the
|
|||
|
// virtual unwind that happens during KeDumpMachineState()
|
|||
|
// destroys the context record
|
|||
|
//
|
|||
|
|
|||
|
ContextSave = KeGetCurrentPrcb()->ProcessorState.ContextFrame;
|
|||
|
|
|||
|
//
|
|||
|
// if we are called by hard error then we don't want to dump the
|
|||
|
// processor state on the machine.
|
|||
|
//
|
|||
|
// We know that we are called by hard error because the bug check
|
|||
|
// code will be FATAL_UNHANDLED_HARD_ERROR. If this is so then the
|
|||
|
// error status passed to harderr is the second parameter, and a pointer
|
|||
|
// to the parameter array from hard error is passed as the third
|
|||
|
// argument.
|
|||
|
//
|
|||
|
|
|||
|
if (BugCheckCode == FATAL_UNHANDLED_HARD_ERROR) {
|
|||
|
|
|||
|
PULONG parameterArray;
|
|||
|
|
|||
|
hardErrorCalled = TRUE;
|
|||
|
|
|||
|
parameterArray = (PULONG)BugCheckParameter2;
|
|||
|
BugCheckCode = BugCheckParameter1;
|
|||
|
BugCheckParameter1 = parameterArray[0];
|
|||
|
BugCheckParameter2 = parameterArray[1];
|
|||
|
BugCheckParameter3 = parameterArray[2];
|
|||
|
BugCheckParameter4 = parameterArray[3];
|
|||
|
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
hardErrorCalled = FALSE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
KiBugCheckData[0] = BugCheckCode;
|
|||
|
KiBugCheckData[1] = BugCheckParameter1;
|
|||
|
KiBugCheckData[2] = BugCheckParameter2;
|
|||
|
KiBugCheckData[3] = BugCheckParameter3;
|
|||
|
KiBugCheckData[4] = BugCheckParameter4;
|
|||
|
|
|||
|
BugCheckParameters[0] = BugCheckParameter1;
|
|||
|
BugCheckParameters[1] = BugCheckParameter2;
|
|||
|
BugCheckParameters[2] = BugCheckParameter3;
|
|||
|
BugCheckParameters[3] = BugCheckParameter4;
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
//
|
|||
|
// Don't clear screen if debugger is available.
|
|||
|
//
|
|||
|
|
|||
|
if (KdDebuggerEnabled != FALSE) {
|
|||
|
try {
|
|||
|
DbgPrint("\n*** Fatal System Error: 0x%08lX (0x%08lX,0x%08lX,0x%08lX,0x%08lX)\n\n",
|
|||
|
BugCheckCode,
|
|||
|
BugCheckParameter1,
|
|||
|
BugCheckParameter2,
|
|||
|
BugCheckParameter3,
|
|||
|
BugCheckParameter4
|
|||
|
);
|
|||
|
DbgBreakPointWithStatus(DBG_STATUS_BUGCHECK_FIRST);
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
for (;;) {
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endif //DBG
|
|||
|
|
|||
|
//
|
|||
|
// Freeze execution of the system by disabling interrupts and looping
|
|||
|
//
|
|||
|
|
|||
|
KiDisableInterrupts();
|
|||
|
|
|||
|
#if !defined(i386)
|
|||
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Don't attempt to display message more than once.
|
|||
|
//
|
|||
|
|
|||
|
if (InterlockedDecrement (&KeBugCheckCount) == 0) {
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to get the other processors frozen now, but don't wait
|
|||
|
// for them to freeze (in case someone is stuck)
|
|||
|
//
|
|||
|
|
|||
|
TargetSet = KeActiveProcessors & ~KeGetCurrentPrcb()->SetMember;
|
|||
|
if (TargetSet != 0) {
|
|||
|
KiIpiSend((KAFFINITY) TargetSet, IPI_FREEZE);
|
|||
|
|
|||
|
//
|
|||
|
// Give the other processors one second to flush their data caches.
|
|||
|
//
|
|||
|
// N.B. This cannot be synchronized since the reason for the bug
|
|||
|
// may be one of the other processors failed.
|
|||
|
//
|
|||
|
|
|||
|
KeStallExecutionProcessor(1000 * 1000);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
if (!hardErrorCalled) {
|
|||
|
sprintf((char *)Buffer,
|
|||
|
"\n*** STOP: 0x%08lX (0x%08lX,0x%08lX,0x%08lX,0x%08lX)\n",
|
|||
|
BugCheckCode,
|
|||
|
BugCheckParameter1,
|
|||
|
BugCheckParameter2,
|
|||
|
BugCheckParameter3,
|
|||
|
BugCheckParameter4
|
|||
|
);
|
|||
|
|
|||
|
HalDisplayString((char *)Buffer);
|
|||
|
KeGetBugMessageText(BugCheckCode, NULL);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Process the bug check callback list.
|
|||
|
//
|
|||
|
|
|||
|
KiScanBugCheckCallbackList();
|
|||
|
|
|||
|
//
|
|||
|
// If the debugger is not enabled, then dump the machine state and
|
|||
|
// attempt to enable the debbugger.
|
|||
|
//
|
|||
|
|
|||
|
if (!hardErrorCalled) {
|
|||
|
|
|||
|
KeDumpMachineState(
|
|||
|
&KeGetCurrentPrcb()->ProcessorState,
|
|||
|
(char *)Buffer,
|
|||
|
BugCheckParameters,
|
|||
|
4,
|
|||
|
KeBugCheckUnicodeToAnsi);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (KdDebuggerEnabled == FALSE && KdPitchDebugger == FALSE ) {
|
|||
|
KdInitSystem(NULL, FALSE);
|
|||
|
|
|||
|
} else {
|
|||
|
HalDisplayString("\n");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Write a crash dump and optionally reboot if the system has been
|
|||
|
// so configured.
|
|||
|
//
|
|||
|
|
|||
|
KeGetCurrentPrcb()->ProcessorState.ContextFrame = ContextSave;
|
|||
|
if (!IoWriteCrashDump(BugCheckCode,
|
|||
|
BugCheckParameter1,
|
|||
|
BugCheckParameter2,
|
|||
|
BugCheckParameter3,
|
|||
|
BugCheckParameter4,
|
|||
|
&ContextSave
|
|||
|
)) {
|
|||
|
//
|
|||
|
// If no crashdump take, display the PSS message
|
|||
|
//
|
|||
|
|
|||
|
KeGetBugMessageText(BUGCODE_PSS_MESSAGE, NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to enter the kernel debugger.
|
|||
|
//
|
|||
|
|
|||
|
while(TRUE) {
|
|||
|
try {
|
|||
|
DbgBreakPointWithStatus(DBG_STATUS_BUGCHECK_SECOND);
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
for (;;) {
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KeEnterKernelDebugger (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function crashes the system in a controlled manner attempting
|
|||
|
to invoke the kernel debugger.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
#if !defined(i386)
|
|||
|
KIRQL OldIrql;
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Freeze execution of the system by disabling interrupts and looping
|
|||
|
//
|
|||
|
|
|||
|
KiHardwareTrigger = 1;
|
|||
|
KiDisableInterrupts();
|
|||
|
#if !defined(i386)
|
|||
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|||
|
#endif
|
|||
|
if (InterlockedDecrement (&KeBugCheckCount) == 0) {
|
|||
|
if (KdDebuggerEnabled == FALSE) {
|
|||
|
if ( KdPitchDebugger == FALSE ) {
|
|||
|
KdInitSystem(NULL, FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
while(TRUE) {
|
|||
|
try {
|
|||
|
DbgBreakPointWithStatus(DBG_STATUS_FATAL);
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
for (;;) {
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
NTKERNELAPI
|
|||
|
BOOLEAN
|
|||
|
KeDeregisterBugCheckCallback (
|
|||
|
IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function deregisters a bug check callback record.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CallbackRecord - Supplies a pointer to a bug check callback record.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the specified bug check callback record is successfully deregistered,
|
|||
|
then a value of TRUE is returned. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
BOOLEAN Deregister;
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to HIGH_LEVEL and acquire the bug check callback list
|
|||
|
// spinlock.
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|||
|
KiAcquireSpinLock(&KeBugCheckCallbackLock);
|
|||
|
|
|||
|
//
|
|||
|
// If the specified callback record is currently registered, then
|
|||
|
// deregister the callback record.
|
|||
|
//
|
|||
|
|
|||
|
Deregister = FALSE;
|
|||
|
if (CallbackRecord->State == BufferInserted) {
|
|||
|
CallbackRecord->State = BufferEmpty;
|
|||
|
RemoveEntryList(&CallbackRecord->Entry);
|
|||
|
Deregister = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release the bug check callback spinlock, lower IRQL to its previous
|
|||
|
// value, and return whether the callback record was successfully
|
|||
|
// deregistered.
|
|||
|
//
|
|||
|
|
|||
|
KiReleaseSpinLock(&KeBugCheckCallbackLock);
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
return Deregister;
|
|||
|
}
|
|||
|
|
|||
|
NTKERNELAPI
|
|||
|
BOOLEAN
|
|||
|
KeRegisterBugCheckCallback (
|
|||
|
IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
|
|||
|
IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
|
|||
|
IN PVOID Buffer,
|
|||
|
IN ULONG Length,
|
|||
|
IN PUCHAR Component
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function registers a bug check callback record. If the system
|
|||
|
crashes, then the specified function will be called during bug check
|
|||
|
processing so it may dump additional state in the specified bug check
|
|||
|
buffer.
|
|||
|
|
|||
|
N.B. Bug check callback routines are called in reverse order of
|
|||
|
registration, i.e., in LIFO order.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CallbackRecord - Supplies a pointer to a callback record.
|
|||
|
|
|||
|
CallbackRoutine - Supplies a pointer to the callback routine.
|
|||
|
|
|||
|
Buffer - Supplies a pointer to the bug check buffer.
|
|||
|
|
|||
|
Length - Supplies the length of the bug check buffer in bytes.
|
|||
|
|
|||
|
Component - Supplies a pointer to a zero terminated component
|
|||
|
identifier.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the specified bug check callback record is successfully registered,
|
|||
|
then a value of TRUE is returned. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
BOOLEAN Inserted;
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to HIGH_LEVEL and acquire the bug check callback list
|
|||
|
// spinlock.
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|||
|
KiAcquireSpinLock(&KeBugCheckCallbackLock);
|
|||
|
|
|||
|
//
|
|||
|
// If the specified callback record is currently not registered, then
|
|||
|
// register the callback record.
|
|||
|
//
|
|||
|
|
|||
|
Inserted = FALSE;
|
|||
|
if (CallbackRecord->State == BufferEmpty) {
|
|||
|
CallbackRecord->CallbackRoutine = CallbackRoutine;
|
|||
|
CallbackRecord->Buffer = Buffer;
|
|||
|
CallbackRecord->Length = Length;
|
|||
|
CallbackRecord->Component = Component;
|
|||
|
CallbackRecord->Checksum =
|
|||
|
(ULONG)CallbackRoutine + (ULONG)Buffer + Length + (ULONG)Component;
|
|||
|
|
|||
|
CallbackRecord->State = BufferInserted;
|
|||
|
InsertHeadList(&KeBugCheckCallbackListHead, &CallbackRecord->Entry);
|
|||
|
Inserted = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release the bug check callback spinlock, lower IRQL to its previous
|
|||
|
// value, and return whether the callback record was successfully
|
|||
|
// registered.
|
|||
|
//
|
|||
|
|
|||
|
KiReleaseSpinLock(&KeBugCheckCallbackLock);
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
return Inserted;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KiScanBugCheckCallbackList (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function scans the bug check callback list and calls each bug
|
|||
|
check callback routine so it can dump component specific information
|
|||
|
that may identify the cause of the bug check.
|
|||
|
|
|||
|
N.B. The scan of the bug check callback list is performed VERY
|
|||
|
carefully. Bug check callback routines are called at HIGH_LEVEL
|
|||
|
and may not acquire ANY resources.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PKBUGCHECK_CALLBACK_RECORD CallbackRecord;
|
|||
|
ULONG Checksum;
|
|||
|
ULONG Index;
|
|||
|
PLIST_ENTRY LastEntry;
|
|||
|
PLIST_ENTRY ListHead;
|
|||
|
PLIST_ENTRY NextEntry;
|
|||
|
PUCHAR Source;
|
|||
|
|
|||
|
//
|
|||
|
// If the bug check callback listhead is not initialized, then the
|
|||
|
// bug check has occured before the system has gotten far enough
|
|||
|
// in the initialization code to enable anyone to register a callback.
|
|||
|
//
|
|||
|
|
|||
|
ListHead = &KeBugCheckCallbackListHead;
|
|||
|
if ((ListHead->Flink != NULL) && (ListHead->Blink != NULL)) {
|
|||
|
|
|||
|
//
|
|||
|
// Scan the bug check callback list.
|
|||
|
//
|
|||
|
|
|||
|
LastEntry = ListHead;
|
|||
|
NextEntry = ListHead->Flink;
|
|||
|
while (NextEntry != ListHead) {
|
|||
|
|
|||
|
//
|
|||
|
// The next entry address must be aligned properly, the
|
|||
|
// callback record must be readable, and the callback record
|
|||
|
// must have back link to the last entry.
|
|||
|
//
|
|||
|
|
|||
|
if (((ULONG)NextEntry & (sizeof(ULONG) - 1)) != 0) {
|
|||
|
return;
|
|||
|
|
|||
|
} else {
|
|||
|
CallbackRecord = CONTAINING_RECORD(NextEntry,
|
|||
|
KBUGCHECK_CALLBACK_RECORD,
|
|||
|
Entry);
|
|||
|
|
|||
|
Source = (PUCHAR)CallbackRecord;
|
|||
|
for (Index = 0; Index < sizeof(KBUGCHECK_CALLBACK_RECORD); Index += 1) {
|
|||
|
if (MmDbgReadCheck((PVOID)Source) == NULL) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Source += 1;
|
|||
|
}
|
|||
|
|
|||
|
if (CallbackRecord->Entry.Blink != LastEntry) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the callback record has a state of inserted and the
|
|||
|
// computed checksum matches the callback record checksum,
|
|||
|
// then call the specified bug check callback routine.
|
|||
|
//
|
|||
|
|
|||
|
Checksum = (ULONG)CallbackRecord->CallbackRoutine;
|
|||
|
Checksum += (ULONG)CallbackRecord->Buffer;
|
|||
|
Checksum += CallbackRecord->Length;
|
|||
|
Checksum += (ULONG)CallbackRecord->Component;
|
|||
|
if ((CallbackRecord->State == BufferInserted) &&
|
|||
|
(CallbackRecord->Checksum == Checksum)) {
|
|||
|
|
|||
|
//
|
|||
|
// Call the specified bug check callback routine and
|
|||
|
// handle any exceptions that occur.
|
|||
|
//
|
|||
|
|
|||
|
CallbackRecord->State = BufferStarted;
|
|||
|
try {
|
|||
|
(CallbackRecord->CallbackRoutine)(CallbackRecord->Buffer,
|
|||
|
CallbackRecord->Length);
|
|||
|
|
|||
|
CallbackRecord->State = BufferFinished;
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
CallbackRecord->State = BufferIncomplete;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LastEntry = NextEntry;
|
|||
|
NextEntry = NextEntry->Flink;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|