2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/bug.c
5 * PURPOSE: Bugcheck Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 #if defined (ALLOC_PRAGMA)
16 #pragma alloc_text(INIT, KiInitializeBugCheck)
19 /* GLOBALS *******************************************************************/
21 LIST_ENTRY KeBugcheckCallbackListHead
;
22 LIST_ENTRY KeBugcheckReasonCallbackListHead
;
23 KSPIN_LOCK BugCheckCallbackLock
;
24 ULONG KeBugCheckActive
, KeBugCheckOwner
;
25 LONG KeBugCheckOwnerRecursionCount
;
26 PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages
;
27 ULONG KeBugCheckCount
= 1;
28 ULONG KiHardwareTrigger
;
29 PUNICODE_STRING KiBugCheckDriver
;
30 ULONG_PTR KiBugCheckData
[5];
32 /* Bugzilla Reporting */
33 UNICODE_STRING KeRosProcessorName
, KeRosBiosDate
, KeRosBiosVersion
;
34 UNICODE_STRING KeRosVideoBiosDate
, KeRosVideoBiosVersion
;
36 /* PRIVATE FUNCTIONS *********************************************************/
40 KiPcToFileHeader(IN PVOID Eip
,
41 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
,
42 IN BOOLEAN DriversOnly
,
43 OUT PBOOLEAN InKernel
)
46 PVOID ImageBase
, EipBase
= NULL
;
47 PLDR_DATA_TABLE_ENTRY Entry
;
48 PLIST_ENTRY ListHead
, NextEntry
;
50 /* Check which list we should use */
51 ListHead
= (KeLoaderBlock
) ? &KeLoaderBlock
->LoadOrderListHead
:
57 /* Set list pointers and make sure it's valid */
58 NextEntry
= ListHead
->Flink
;
62 while (NextEntry
!= ListHead
)
67 /* Check if this is a kernel entry and we only want drivers */
68 if ((i
<= 2) && (DriversOnly
== TRUE
))
71 NextEntry
= NextEntry
->Flink
;
75 /* Get the loader entry */
76 Entry
= CONTAINING_RECORD(NextEntry
,
80 /* Move to the next entry */
81 NextEntry
= NextEntry
->Flink
;
82 ImageBase
= Entry
->DllBase
;
84 /* Check if this is the right one */
85 if (((ULONG_PTR
)Eip
>= (ULONG_PTR
)Entry
->DllBase
) &&
86 ((ULONG_PTR
)Eip
< ((ULONG_PTR
)Entry
->DllBase
+ Entry
->SizeOfImage
)))
88 /* Return this entry */
92 /* Check if this was a kernel or HAL entry */
93 if (i
<= 2) *InKernel
= TRUE
;
99 /* Return the base address */
105 KiRosPrintAddress(PVOID address
)
107 PLIST_ENTRY current_entry
;
108 PLDR_DATA_TABLE_ENTRY current
;
109 extern LIST_ENTRY PsLoadedModuleList
;
110 ULONG_PTR RelativeAddress
;
115 current_entry
= PsLoadedModuleList
.Flink
;
117 while (current_entry
!= &PsLoadedModuleList
)
119 current
= CONTAINING_RECORD(current_entry
,
120 LDR_DATA_TABLE_ENTRY
,
123 if (address
>= (PVOID
)current
->DllBase
&&
124 address
< (PVOID
)((ULONG_PTR
)current
->DllBase
+
125 current
->SizeOfImage
))
127 RelativeAddress
= (ULONG_PTR
)address
-
128 (ULONG_PTR
)current
->DllBase
;
129 DbgPrint("<%wZ: %x>", ¤t
->FullDllName
, RelativeAddress
);
132 current_entry
= current_entry
->Flink
;
141 KiRosPcToUserFileHeader(IN PVOID Eip
,
142 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
144 PVOID ImageBase
, EipBase
= NULL
;
145 PLDR_DATA_TABLE_ENTRY Entry
;
146 PLIST_ENTRY ListHead
, NextEntry
;
149 * We know this is valid because we should only be called after a
150 * succesfull address from RtlWalkFrameChain for UserMode, which
151 * validates everything for us.
153 ListHead
= &KeGetCurrentThread()->
154 Teb
->ProcessEnvironmentBlock
->Ldr
->InLoadOrderModuleList
;
156 /* Set list pointers and make sure it's valid */
157 NextEntry
= ListHead
->Flink
;
161 while (NextEntry
!= ListHead
)
163 /* Get the loader entry */
164 Entry
= CONTAINING_RECORD(NextEntry
,
165 LDR_DATA_TABLE_ENTRY
,
168 /* Move to the next entry */
169 NextEntry
= NextEntry
->Flink
;
170 ImageBase
= Entry
->DllBase
;
172 /* Check if this is the right one */
173 if (((ULONG_PTR
)Eip
>= (ULONG_PTR
)Entry
->DllBase
) &&
174 ((ULONG_PTR
)Eip
< ((ULONG_PTR
)Entry
->DllBase
+ Entry
->SizeOfImage
)))
176 /* Return this entry */
184 /* Return the base address */
190 KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip
,
191 IN ULONG FramesToCapture
,
192 OUT PVOID
*BackTrace
,
193 OUT PULONG BackTraceHash OPTIONAL
)
195 PVOID Frames
[2 * 64];
199 /* Skip a frame for the caller */
202 /* Don't go past the limit */
203 if ((FramesToCapture
+ FramesToSkip
) >= 128) return 0;
205 /* Do the back trace */
206 FrameCount
= RtlWalkFrameChain(Frames
, FramesToCapture
+ FramesToSkip
, 1);
208 /* Make sure we're not skipping all of them */
209 if (FrameCount
<= FramesToSkip
) return 0;
211 /* Loop all the frames */
212 for (i
= 0; i
< FramesToCapture
; i
++)
214 /* Don't go past the limit */
215 if ((FramesToSkip
+ i
) >= FrameCount
) break;
217 /* Save this entry and hash it */
218 BackTrace
[i
] = Frames
[FramesToSkip
+ i
];
219 Hash
+= PtrToUlong(BackTrace
[i
]);
223 if (BackTraceHash
) *BackTraceHash
= Hash
;
225 /* Clear the other entries and return count */
226 RtlFillMemoryUlong(Frames
, 128, 0);
232 KeRosDumpStackFrameArray(IN PULONG_PTR Frames
,
240 /* GCC complaints that it may be used uninitialized */
241 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
244 for (i
= 0; i
< FrameCount
; i
++)
253 /* Get the base for this file */
254 if (Addr
> (ULONG_PTR
)MmHighestUserAddress
)
256 /* We are in kernel */
257 p
= KiPcToFileHeader((PVOID
)Addr
, &LdrEntry
, FALSE
, &InSystem
);
261 /* We are in user land */
262 p
= KiRosPcToUserFileHeader((PVOID
)Addr
, &LdrEntry
);
267 if (!KdbSymPrintAddress((PVOID
)Addr
))
270 /* Print out the module name */
271 Addr
-= (ULONG_PTR
)LdrEntry
->DllBase
;
272 DbgPrint("<%wZ: %p>", &LdrEntry
->FullDllName
, (PVOID
)Addr
);
277 /* Print only the address */
278 DbgPrint("<%p>", (PVOID
)Addr
);
281 /* Go to the next frame */
288 KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL
,
289 IN ULONG FrameCount OPTIONAL
)
291 ULONG_PTR Frames
[32];
292 ULONG RealFrameCount
;
294 /* If the caller didn't ask, assume 32 frames */
295 if (!FrameCount
|| FrameCount
> 32) FrameCount
= 32;
300 KeRosDumpStackFrameArray(Frame
, FrameCount
);
304 /* Get the current frames (skip the two. One for the dumper, one for the caller) */
305 RealFrameCount
= RtlCaptureStackBackTrace(2, FrameCount
, (PVOID
*)Frames
, NULL
);
308 KeRosDumpStackFrameArray(Frames
, RealFrameCount
);
310 /* Count left for user mode? */
311 if (FrameCount
- RealFrameCount
> 0)
313 /* Get the current frames */
314 RealFrameCount
= KeRosCaptureUserStackBackTrace(-1, FrameCount
- RealFrameCount
, (PVOID
*)Frames
, NULL
);
317 KeRosDumpStackFrameArray(Frames
, RealFrameCount
);
325 KeRosDumpTriageForBugZillaReport(VOID
)
328 extern BOOLEAN KiFastSystemCallDisable
, KiSMTProcessorsPresent
;
329 extern ULONG KeI386MachineType
, MxcsrFeatureMask
;
330 extern BOOLEAN Ke386Pae
, Ke386NoExecute
;
332 DbgPrint("ReactOS has crashed! Please go to http://www.reactos.org/bugzilla/enter_bug.cgi to file a bug!\n");
333 DbgPrint("\nHardware Information\n");
334 DbgPrint("Processor Architecture: %d\n"
336 "System Call Disabled: %d\n"
339 "MXCsr Feature Mask: %d\n"
346 "Active Processors: %d\n"
347 "Pentium LOCK Bug: %d\n"
348 "Hyperthreading: %d\n"
349 "CPU Manufacturer: %s\n"
357 "BIOS Version: %wZ\n"
358 "Video BIOS Date: %wZ\n"
359 "Video BIOS Version: %wZ\n"
361 KeProcessorArchitecture
,
363 KiFastSystemCallDisable
,
374 KiI386PentiumLockErrataPresent
,
375 KiSMTProcessorsPresent
,
376 KeGetCurrentPrcb()->VendorString
,
378 KeGetCurrentPrcb()->CpuID
,
379 KeGetCurrentPrcb()->CpuType
,
380 KeGetCurrentPrcb()->CpuStep
,
381 KeGetCurrentPrcb()->MHz
,
382 ((PKIPCR
)KeGetPcr())->SecondLevelCacheSize
,
386 &KeRosVideoBiosVersion
,
387 MmNumberOfPhysicalPages
* PAGE_SIZE
);
394 KiInitializeBugCheck(VOID
)
396 PRTL_MESSAGE_RESOURCE_DATA BugCheckData
;
397 LDR_RESOURCE_INFO ResourceInfo
;
398 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
400 PLDR_DATA_TABLE_ENTRY LdrEntry
;
402 /* Get the kernel entry */
403 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
404 LDR_DATA_TABLE_ENTRY
,
407 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
408 ResourceInfo
.Type
= 11;
409 ResourceInfo
.Name
= 1;
410 ResourceInfo
.Language
= 9;
413 Status
= LdrFindResource_U(LdrEntry
->DllBase
,
418 /* Make sure it worked */
419 if (NT_SUCCESS(Status
))
421 /* Now actually get a pointer to it */
422 Status
= LdrAccessResource(LdrEntry
->DllBase
,
424 (PVOID
*)&BugCheckData
,
426 if (NT_SUCCESS(Status
)) KiBugCodeMessages
= BugCheckData
;
432 KeGetBugMessageText(IN ULONG BugCheckCode
,
433 OUT PANSI_STRING OutputString OPTIONAL
)
437 ULONG_PTR MessageEntry
;
439 BOOLEAN Result
= FALSE
;
441 /* Make sure we're not bugchecking too early */
442 if (!KiBugCodeMessages
) return Result
;
444 /* Find the message. This code is based on RtlFindMesssage */
445 for (i
= 0; i
< KiBugCodeMessages
->NumberOfBlocks
; i
++)
447 /* Check if the ID Matches */
448 if ((BugCheckCode
>= KiBugCodeMessages
->Blocks
[i
].LowId
) &&
449 (BugCheckCode
<= KiBugCodeMessages
->Blocks
[i
].HighId
))
451 /* Get Offset to Entry */
452 MessageEntry
= KiBugCodeMessages
->Blocks
[i
].OffsetToEntries
+
453 (ULONG_PTR
)KiBugCodeMessages
;
454 IdOffset
= BugCheckCode
- KiBugCodeMessages
->Blocks
[i
].LowId
;
456 /* Get offset to ID */
457 for (i
= 0; i
< IdOffset
; i
++)
459 /* Advance in the Entries */
460 MessageEntry
+= ((PRTL_MESSAGE_RESOURCE_ENTRY
)MessageEntry
)->
464 /* Get the final Code */
465 BugCode
= ((PRTL_MESSAGE_RESOURCE_ENTRY
)MessageEntry
)->Text
;
468 /* Handle newlines */
469 while ((i
> 0) && ((BugCode
[i
] == '\n') ||
470 (BugCode
[i
] == '\r') ||
471 (BugCode
[i
] == ANSI_NULL
)))
473 /* Check if we have a string to return */
474 if (!OutputString
) BugCode
[i
] = ANSI_NULL
;
478 /* Check if caller wants an output string */
481 /* Return it in the OutputString */
482 OutputString
->Buffer
= BugCode
;
483 OutputString
->Length
= (USHORT
)i
+ 1;
484 OutputString
->MaximumLength
= (USHORT
)i
+ 1;
488 /* Direct Output to Screen */
489 InbvDisplayString(BugCode
);
490 InbvDisplayString("\r");
499 /* Return the result */
505 KiDoBugCheckCallbacks(VOID
)
507 PKBUGCHECK_CALLBACK_RECORD CurrentRecord
;
508 PLIST_ENTRY ListHead
, NextEntry
, LastEntry
;
511 /* First make sure that the list is Initialized... it might not be */
512 ListHead
= &KeBugcheckCallbackListHead
;
513 if ((ListHead
->Flink
) && (ListHead
->Blink
))
516 LastEntry
= ListHead
;
517 NextEntry
= ListHead
->Flink
;
518 while (NextEntry
!= ListHead
)
521 CurrentRecord
= CONTAINING_RECORD(NextEntry
,
522 KBUGCHECK_CALLBACK_RECORD
,
526 if (CurrentRecord
->Entry
.Blink
!= LastEntry
) return;
527 Checksum
= (ULONG_PTR
)CurrentRecord
->CallbackRoutine
;
528 Checksum
+= (ULONG_PTR
)CurrentRecord
->Buffer
;
529 Checksum
+= (ULONG_PTR
)CurrentRecord
->Length
;
530 Checksum
+= (ULONG_PTR
)CurrentRecord
->Component
;
532 /* Make sure it's inserted and valitdated */
533 if ((CurrentRecord
->State
== BufferInserted
) &&
534 (CurrentRecord
->Checksum
== Checksum
))
536 /* Call the routine */
537 CurrentRecord
->State
= BufferStarted
;
538 (CurrentRecord
->CallbackRoutine
)(CurrentRecord
->Buffer
,
539 CurrentRecord
->Length
);
540 CurrentRecord
->State
= BufferFinished
;
543 /* Go to the next entry */
544 LastEntry
= NextEntry
;
545 NextEntry
= NextEntry
->Flink
;
553 KiBugCheckDebugBreak(IN ULONG StatusCode
)
555 /* If KDBG isn't connected, freeze the CPU, otherwise, break */
556 if (KdDebuggerNotPresent
) for (;;) KeArchHaltProcessor();
557 DbgBreakPointWithStatus(StatusCode
);
563 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode
,
571 /* Set length and normalize it */
572 i
= Unicode
->Length
/ sizeof(WCHAR
);
573 i
= min(i
, Length
- 1);
575 /* Set source and destination, and copy */
576 pw
= Unicode
->Buffer
;
578 while (i
--) *p
++ = (CHAR
)*pw
++;
580 /* Null terminate and return */
587 KiDumpParameterImages(IN PCHAR Message
,
588 IN PULONG_PTR Parameters
,
589 IN ULONG ParameterCount
,
590 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine
)
594 PLDR_DATA_TABLE_ENTRY LdrEntry
;
596 PUNICODE_STRING DriverName
;
598 PIMAGE_NT_HEADERS NtHeader
;
600 BOOLEAN FirstRun
= TRUE
;
602 /* Loop parameters */
603 for (i
= 0; i
< ParameterCount
; i
++)
605 /* Get the base for this parameter */
606 ImageBase
= KiPcToFileHeader((PVOID
)Parameters
[i
],
612 /* FIXME: Add code to check for unloaded drivers */
613 DPRINT1("Potentially unloaded driver!\n");
618 /* Get the NT Headers and Timestamp */
619 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
620 TimeStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
622 /* Convert the driver name */
623 DriverName
= &LdrEntry
->BaseDllName
;
624 ConversionRoutine(&LdrEntry
->BaseDllName
,
629 /* Format driver name */
631 "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
632 FirstRun
? "\r\n*":"*",
634 (PVOID
)Parameters
[i
],
638 /* Check if we only had one parameter */
639 if (ParameterCount
<= 1)
641 /* Then just save the name */
642 KiBugCheckDriver
= DriverName
;
646 /* Otherwise, display the message */
647 InbvDisplayString(Message
);
657 KiDisplayBlueScreen(IN ULONG MessageId
,
658 IN BOOLEAN IsHardError
,
659 IN PCHAR HardErrCaption OPTIONAL
,
660 IN PCHAR HardErrMessage OPTIONAL
,
665 /* Check if bootvid is installed */
666 if (InbvIsBootDriverInstalled())
668 /* Acquire ownership and reset the display */
669 InbvAcquireDisplayOwnership();
672 /* Display blue screen */
673 InbvSolidColorFill(0, 0, 639, 479, 4);
674 InbvSetTextColor(15);
675 InbvInstallDisplayStringFilter(NULL
);
676 InbvEnableDisplayString(TRUE
);
677 InbvSetScrollRegion(0, 0, 639, 479);
680 /* Check if this is a hard error */
683 /* Display caption and message */
684 if (HardErrCaption
) InbvDisplayString(HardErrCaption
);
685 if (HardErrMessage
) InbvDisplayString(HardErrMessage
);
688 /* Begin the display */
689 InbvDisplayString("\r\n");
691 /* Print out initial message */
692 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO
, NULL
);
693 InbvDisplayString("\r\n\r\n");
695 /* Check if we have a driver */
696 if (KiBugCheckDriver
)
698 /* Print out into to driver name */
699 KeGetBugMessageText(BUGCODE_ID_DRIVER
, NULL
);
701 /* Convert and print out driver name */
702 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
703 InbvDisplayString(" ");
704 InbvDisplayString(AnsiName
);
705 InbvDisplayString("\r\n\r\n");
708 /* Check if this is the generic message */
709 if (MessageId
== BUGCODE_PSS_MESSAGE
)
711 /* It is, so get the bug code string as well */
712 KeGetBugMessageText(KiBugCheckData
[0], NULL
);
713 InbvDisplayString("\r\n\r\n");
716 /* Print second introduction message */
717 KeGetBugMessageText(PSS_MESSAGE_INTRO
, NULL
);
718 InbvDisplayString("\r\n\r\n");
720 /* Get the bug code string */
721 KeGetBugMessageText(MessageId
, NULL
);
722 InbvDisplayString("\r\n\r\n");
724 /* Print message for technical information */
725 KeGetBugMessageText(BUGCHECK_TECH_INFO
, NULL
);
727 /* Show the technical Data */
729 "\r\n\r\n*** STOP: 0x%p (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
730 (PVOID
)KiBugCheckData
[0],
731 (PVOID
)KiBugCheckData
[1],
732 (PVOID
)KiBugCheckData
[2],
733 (PVOID
)KiBugCheckData
[3],
734 (PVOID
)KiBugCheckData
[4]);
735 InbvDisplayString(AnsiName
);
737 /* Check if we have a driver*/
738 if (KiBugCheckDriver
)
740 /* Display technical driver data */
741 InbvDisplayString(Message
);
745 /* Dump parameter information */
746 KiDumpParameterImages(Message
,
747 (PVOID
)&KiBugCheckData
[1],
749 KeBugCheckUnicodeToAnsi
);
756 KeBugCheckWithTf(IN ULONG BugCheckCode
,
757 IN ULONG_PTR BugCheckParameter1
,
758 IN ULONG_PTR BugCheckParameter2
,
759 IN ULONG_PTR BugCheckParameter3
,
760 IN ULONG_PTR BugCheckParameter4
,
761 IN PKTRAP_FRAME TrapFrame
)
763 PKPRCB Prcb
= KeGetCurrentPrcb();
767 BOOLEAN IsSystem
, IsHardError
= FALSE
, Reboot
= FALSE
;
768 PCHAR HardErrCaption
= NULL
, HardErrMessage
= NULL
;
769 PVOID Eip
= NULL
, Memory
;
771 PLDR_DATA_TABLE_ENTRY LdrEntry
;
772 PULONG_PTR HardErrorParameters
;
778 /* Set active bugcheck */
779 KeBugCheckActive
= TRUE
;
780 KiBugCheckDriver
= NULL
;
782 /* Check if this is power failure simulation */
783 if (BugCheckCode
== POWER_FAILURE_SIMULATE
)
785 /* Call the Callbacks and reboot */;
786 KiDoBugCheckCallbacks();
787 HalReturnToFirmware(HalRebootRoutine
);
790 /* Save the IRQL and set hardware trigger */
791 Prcb
->DebuggerSavedIRQL
= KeGetCurrentIrql();
792 InterlockedIncrement((PLONG
)&KiHardwareTrigger
);
794 /* Capture the CPU Context */
795 RtlCaptureContext(&Prcb
->ProcessorState
.ContextFrame
);
796 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
797 Context
= Prcb
->ProcessorState
.ContextFrame
;
799 /* FIXME: Call the Watchdog if it's registered */
801 /* Check which bugcode this is */
802 switch (BugCheckCode
)
804 /* These bug checks already have detailed messages, keep them */
805 case UNEXPECTED_KERNEL_MODE_TRAP
:
806 case DRIVER_CORRUPTED_EXPOOL
:
807 case ACPI_BIOS_ERROR
:
808 case ACPI_BIOS_FATAL_ERROR
:
809 case THREAD_STUCK_IN_DEVICE_DRIVER
:
811 case FAT_FILE_SYSTEM
:
812 case NO_MORE_SYSTEM_PTES
:
813 case INACCESSIBLE_BOOT_DEVICE
:
815 /* Keep the same code */
816 MessageId
= BugCheckCode
;
819 /* Check if this is a kernel-mode exception */
820 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
821 //case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
822 case KMODE_EXCEPTION_NOT_HANDLED
:
824 /* Use the generic text message */
825 MessageId
= KMODE_EXCEPTION_NOT_HANDLED
;
828 /* File-system errors */
829 case NTFS_FILE_SYSTEM
:
831 /* Use the generic message for FAT */
832 MessageId
= FAT_FILE_SYSTEM
;
835 /* Check if this is a coruption of the Mm's Pool */
836 case DRIVER_CORRUPTED_MMPOOL
:
838 /* Use generic corruption message */
839 MessageId
= DRIVER_CORRUPTED_EXPOOL
;
842 /* Check if this is a signature check failure */
843 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
:
845 /* Use the generic corruption message */
846 MessageId
= BUGCODE_PSS_MESSAGE_SIGNATURE
;
849 /* All other codes */
852 /* Use the default bugcheck message */
853 MessageId
= BUGCODE_PSS_MESSAGE
;
857 /* Save bugcheck data */
858 KiBugCheckData
[0] = BugCheckCode
;
859 KiBugCheckData
[1] = BugCheckParameter1
;
860 KiBugCheckData
[2] = BugCheckParameter2
;
861 KiBugCheckData
[3] = BugCheckParameter3
;
862 KiBugCheckData
[4] = BugCheckParameter4
;
864 /* Now check what bugcheck this is */
865 switch (BugCheckCode
)
867 /* Invalid access to R/O memory or Unhandled KM Exception */
868 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
869 case ATTEMPTED_WRITE_TO_READONLY_MEMORY
:
870 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY
:
872 /* Check if we have a trap frame */
875 /* Use parameter 3 as a trap frame, if it exists */
876 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
879 /* Check if we got one now and if we need to get EIP */
881 (BugCheckCode
!= KERNEL_MODE_EXCEPTION_NOT_HANDLED
))
885 Eip
= (PVOID
)TrapFrame
->Eip
;
886 #elif defined(_M_PPC)
887 Eip
= (PVOID
)TrapFrame
->Dr0
; /* srr0 */
893 case IRQL_NOT_LESS_OR_EQUAL
:
896 * The NT kernel has 3 special sections:
897 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
898 * determine in which of these sections this bugcode happened
899 * and provide a more detailed analysis. For now, we don't.
902 /* Eip is in parameter 4 */
903 Eip
= (PVOID
)BugCheckParameter4
;
905 /* Get the driver base */
906 DriverBase
= KiPcToFileHeader(Eip
, &LdrEntry
, FALSE
, &IsSystem
);
910 * The error happened inside the kernel or HAL.
911 * Get the memory address that was being referenced.
913 Memory
= (PVOID
)BugCheckParameter1
;
915 /* Find to which driver it belongs */
916 DriverBase
= KiPcToFileHeader(Memory
,
922 /* Get the driver name and update the bug code */
923 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
924 KiBugCheckData
[0] = DRIVER_PORTION_MUST_BE_NONPAGED
;
928 /* Find the driver that unloaded at this address */
929 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
931 /* Check if the cause was an unloaded driver */
932 if (KiBugCheckDriver
)
934 /* Update bug check code */
936 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD
;
942 /* Update the bug check code */
943 KiBugCheckData
[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL
;
946 /* Clear EIP so we don't look it up later */
951 case FATAL_UNHANDLED_HARD_ERROR
:
953 /* Copy bug check data from hard error */
954 HardErrorParameters
= (PULONG_PTR
)BugCheckParameter2
;
955 KiBugCheckData
[0] = BugCheckParameter1
;
956 KiBugCheckData
[1] = HardErrorParameters
[0];
957 KiBugCheckData
[2] = HardErrorParameters
[1];
958 KiBugCheckData
[3] = HardErrorParameters
[2];
959 KiBugCheckData
[4] = HardErrorParameters
[3];
961 /* Remember that this is hard error and set the caption/message */
963 HardErrCaption
= (PCHAR
)BugCheckParameter3
;
964 HardErrMessage
= (PCHAR
)BugCheckParameter4
;
968 case PAGE_FAULT_IN_NONPAGED_AREA
:
970 /* Assume no driver */
973 /* Check if we have a trap frame */
976 /* We don't, use parameter 3 if possible */
977 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
980 /* Check if we have a frame now */
985 Eip
= (PVOID
)TrapFrame
->Eip
;
986 KiBugCheckData
[3] = (ULONG
)Eip
;
987 #elif defined(_M_PPC)
988 Eip
= (PVOID
)TrapFrame
->Dr0
; /* srr0 */
989 KiBugCheckData
[3] = (ULONG
)Eip
;
992 /* Find out if was in the kernel or drivers */
993 DriverBase
= KiPcToFileHeader(Eip
,
1000 * Now we should check if this happened in:
1001 * 1) Special Pool 2) Free Special Pool 3) Session Pool
1002 * and update the bugcheck code appropriately.
1005 /* Check if we didn't have a driver base */
1008 /* Find the driver that unloaded at this address */
1009 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
1011 /* Check if the cause was an unloaded driver */
1012 if (KiBugCheckDriver
)
1015 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS
;
1020 /* Check if the driver forgot to unlock pages */
1021 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS
:
1023 /* EIP is in parameter 1 */
1024 Eip
= (PVOID
)BugCheckParameter1
;
1027 /* Check if the driver consumed too many PTEs */
1028 case DRIVER_USED_EXCESSIVE_PTES
:
1030 /* Loader entry is in parameter 1 */
1031 LdrEntry
= (PVOID
)BugCheckParameter1
;
1032 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
1035 /* Check if the driver has a stuck thread */
1036 case THREAD_STUCK_IN_DEVICE_DRIVER
:
1038 /* The name is in Parameter 3 */
1039 KiBugCheckDriver
= (PVOID
)BugCheckParameter3
;
1047 /* Do we have a driver name? */
1048 if (KiBugCheckDriver
)
1050 /* Convert it to ANSI */
1051 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
1055 /* Do we have an EIP? */
1058 /* Dump image name */
1059 KiDumpParameterImages(AnsiName
,
1062 KeBugCheckUnicodeToAnsi
);
1066 /* Check if we need to save the context for KD */
1068 if (!KdPitchDebugger
) KdDebuggerDataBlock
.SavedContext
= (ULONG_PTR
)&Context
;
1071 /* Check if a debugger is connected */
1072 if ((BugCheckCode
!= MANUALLY_INITIATED_CRASH
) && (KdDebuggerEnabled
))
1074 /* Crash on the debugger console */
1075 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
1076 " (0x%p,0x%p,0x%p,0x%p)\n\n",
1083 /* Check if the debugger isn't currently connected */
1084 if (!KdDebuggerNotPresent
)
1086 /* Check if we have a driver to blame */
1087 if (KiBugCheckDriver
)
1090 DbgPrint("Driver at fault: %s.\n", AnsiName
);
1093 /* Check if this was a hard error */
1096 /* Print caption and message */
1097 if (HardErrCaption
) DbgPrint(HardErrCaption
);
1098 if (HardErrMessage
) DbgPrint(HardErrMessage
);
1101 /* Break in the debugger */
1102 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST
);
1108 * Ok, so debugging is enabled, but KDBG isn't there.
1109 * We'll manually dump the stack for the user.
1111 KeRosDumpStackFrames(NULL
, 0);
1113 /* ROS HACK 2: Generate something useful for Bugzilla */
1114 KeRosDumpTriageForBugZillaReport();
1118 /* Raise IRQL to HIGH_LEVEL */
1120 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1122 /* Avoid recursion */
1123 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1126 /* Set CPU that is bug checking now */
1127 KeBugCheckOwner
= Prcb
->Number
;
1129 /* Freeze the other CPUs */
1130 for (i
= 0; i
< KeNumberProcessors
; i
++)
1132 if (i
!= (LONG
)KeGetCurrentProcessorNumber())
1134 /* Send the IPI and give them one second to catch up */
1135 KiIpiSend(1 << i
, IPI_FREEZE
);
1136 KeStallExecutionProcessor(1000000);
1141 /* Display the BSOD */
1142 KeLowerIrql(APC_LEVEL
); // This is a nastier hack than any ever before
1143 KiDisplayBlueScreen(MessageId
,
1148 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1150 /* Check if the debugger is disabled but we can enable it */
1151 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1155 KdEnableDebuggerWithLock(FALSE
);
1160 /* Otherwise, print the last line */
1161 InbvDisplayString("\r\n");
1164 /* Save the context */
1165 Prcb
->ProcessorState
.ContextFrame
= Context
;
1167 /* FIXME: Support Triage Dump */
1169 /* Write the crash dump */
1170 MmDumpToPagingFile(KiBugCheckData
[4],
1179 /* Increase recursion count */
1180 KeBugCheckOwnerRecursionCount
++;
1181 if (KeBugCheckOwnerRecursionCount
== 2)
1183 /* Break in the debugger */
1184 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
1186 else if (KeBugCheckOwnerRecursionCount
> 2)
1189 for (;;) KeArchHaltProcessor();
1193 /* Call the Callbacks */
1194 KiDoBugCheckCallbacks();
1196 /* FIXME: Call Watchdog if enabled */
1198 /* Check if we have to reboot */
1201 /* Unload symbols */
1202 DbgUnLoadImageSymbols(NULL
, NtCurrentProcess(), 0);
1203 HalReturnToFirmware(HalRebootRoutine
);
1206 /* Attempt to break in the debugger (otherwise halt CPU) */
1207 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
1210 /* PUBLIC FUNCTIONS **********************************************************/
1217 KeInitializeCrashDumpHeader(IN ULONG Type
,
1220 IN ULONG BufferSize
,
1221 OUT ULONG BufferNeeded OPTIONAL
)
1224 return STATUS_UNSUCCESSFUL
;
1232 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
)
1235 BOOLEAN Status
= FALSE
;
1237 /* Raise IRQL to High */
1238 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1240 /* Check the Current State */
1241 if (CallbackRecord
->State
== BufferInserted
)
1243 /* Reset state and remove from list */
1244 CallbackRecord
->State
= BufferEmpty
;
1245 RemoveEntryList(&CallbackRecord
->Entry
);
1249 /* Lower IRQL and return */
1250 KeLowerIrql(OldIrql
);
1259 KeDeregisterBugCheckReasonCallback(
1260 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
)
1263 BOOLEAN Status
= FALSE
;
1265 /* Raise IRQL to High */
1266 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1268 /* Check the Current State */
1269 if (CallbackRecord
->State
== BufferInserted
)
1271 /* Reset state and remove from list */
1272 CallbackRecord
->State
= BufferEmpty
;
1273 RemoveEntryList(&CallbackRecord
->Entry
);
1277 /* Lower IRQL and return */
1278 KeLowerIrql(OldIrql
);
1287 KeDeregisterNmiCallback(PVOID Handle
)
1290 return STATUS_UNSUCCESSFUL
;
1298 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
,
1299 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine
,
1302 IN PUCHAR Component
)
1305 BOOLEAN Status
= FALSE
;
1307 /* Raise IRQL to High */
1308 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1310 /* Check the Current State first so we don't double-register */
1311 if (CallbackRecord
->State
== BufferEmpty
)
1313 /* Set the Callback Settings and insert into the list */
1314 CallbackRecord
->Length
= Length
;
1315 CallbackRecord
->Buffer
= Buffer
;
1316 CallbackRecord
->Component
= Component
;
1317 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1318 CallbackRecord
->State
= BufferInserted
;
1319 InsertTailList(&KeBugcheckCallbackListHead
, &CallbackRecord
->Entry
);
1323 /* Lower IRQL and return */
1324 KeLowerIrql(OldIrql
);
1333 KeRegisterBugCheckReasonCallback(
1334 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
,
1335 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine
,
1336 IN KBUGCHECK_CALLBACK_REASON Reason
,
1337 IN PUCHAR Component
)
1340 BOOLEAN Status
= FALSE
;
1342 /* Raise IRQL to High */
1343 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1345 /* Check the Current State first so we don't double-register */
1346 if (CallbackRecord
->State
== BufferEmpty
)
1348 /* Set the Callback Settings and insert into the list */
1349 CallbackRecord
->Component
= Component
;
1350 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1351 CallbackRecord
->State
= BufferInserted
;
1352 CallbackRecord
->Reason
= Reason
;
1353 InsertTailList(&KeBugcheckReasonCallbackListHead
,
1354 &CallbackRecord
->Entry
);
1358 /* Lower IRQL and return */
1359 KeLowerIrql(OldIrql
);
1368 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine
,
1380 KeBugCheckEx(IN ULONG BugCheckCode
,
1381 IN ULONG_PTR BugCheckParameter1
,
1382 IN ULONG_PTR BugCheckParameter2
,
1383 IN ULONG_PTR BugCheckParameter3
,
1384 IN ULONG_PTR BugCheckParameter4
)
1386 /* Call the internal API */
1387 KeBugCheckWithTf(BugCheckCode
,
1400 KeBugCheck(ULONG BugCheckCode
)
1402 /* Call the internal API */
1403 KeBugCheckWithTf(BugCheckCode
, 0, 0, 0, 0, NULL
);
1411 KeEnterKernelDebugger(VOID
)
1413 /* Disable interrupts */
1414 KiHardwareTrigger
= 1;
1417 /* Check the bugcheck count */
1418 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1420 /* There was only one, is the debugger disabled? */
1421 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1423 /* Enable the debugger */
1424 KdInitSystem(0, NULL
);
1429 KiBugCheckDebugBreak(DBG_STATUS_FATAL
);