Sync to trunk head(r38096)
[reactos.git] / reactos / ntoskrnl / ke / bug.c
1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #if defined (ALLOC_PRAGMA)
16 #pragma alloc_text(INIT, KiInitializeBugCheck)
17 #endif
18
19 /* GLOBALS *******************************************************************/
20
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];
31
32 /* Bugzilla Reporting */
33 UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion;
34 UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
35
36 /* PRIVATE FUNCTIONS *********************************************************/
37
38 PVOID
39 NTAPI
40 KiPcToFileHeader(IN PVOID Eip,
41 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
42 IN BOOLEAN DriversOnly,
43 OUT PBOOLEAN InKernel)
44 {
45 ULONG i = 0;
46 PVOID ImageBase, EipBase = NULL;
47 PLDR_DATA_TABLE_ENTRY Entry;
48 PLIST_ENTRY ListHead, NextEntry;
49
50 /* Check which list we should use */
51 ListHead = (KeLoaderBlock) ? &KeLoaderBlock->LoadOrderListHead :
52 &PsLoadedModuleList;
53
54 /* Assume no */
55 *InKernel = FALSE;
56
57 /* Set list pointers and make sure it's valid */
58 NextEntry = ListHead->Flink;
59 if (NextEntry)
60 {
61 /* Start loop */
62 while (NextEntry != ListHead)
63 {
64 /* Increase entry */
65 i++;
66
67 /* Check if this is a kernel entry and we only want drivers */
68 if ((i <= 2) && (DriversOnly == TRUE))
69 {
70 /* Skip it */
71 NextEntry = NextEntry->Flink;
72 continue;
73 }
74
75 /* Get the loader entry */
76 Entry = CONTAINING_RECORD(NextEntry,
77 LDR_DATA_TABLE_ENTRY,
78 InLoadOrderLinks);
79
80 /* Move to the next entry */
81 NextEntry = NextEntry->Flink;
82 ImageBase = Entry->DllBase;
83
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)))
87 {
88 /* Return this entry */
89 *LdrEntry = Entry;
90 EipBase = ImageBase;
91
92 /* Check if this was a kernel or HAL entry */
93 if (i <= 2) *InKernel = TRUE;
94 break;
95 }
96 }
97 }
98
99 /* Return the base address */
100 return EipBase;
101 }
102
103 BOOLEAN
104 NTAPI
105 KiRosPrintAddress(PVOID address)
106 {
107 PLIST_ENTRY current_entry;
108 PLDR_DATA_TABLE_ENTRY current;
109 extern LIST_ENTRY PsLoadedModuleList;
110 ULONG_PTR RelativeAddress;
111 ULONG i = 0;
112
113 do
114 {
115 current_entry = PsLoadedModuleList.Flink;
116
117 while (current_entry != &PsLoadedModuleList)
118 {
119 current = CONTAINING_RECORD(current_entry,
120 LDR_DATA_TABLE_ENTRY,
121 InLoadOrderLinks);
122
123 if (address >= (PVOID)current->DllBase &&
124 address < (PVOID)((ULONG_PTR)current->DllBase +
125 current->SizeOfImage))
126 {
127 RelativeAddress = (ULONG_PTR)address -
128 (ULONG_PTR)current->DllBase;
129 DbgPrint("<%wZ: %x>", &current->FullDllName, RelativeAddress);
130 return(TRUE);
131 }
132 current_entry = current_entry->Flink;
133 }
134 } while(++i <= 1);
135
136 return(FALSE);
137 }
138
139 PVOID
140 NTAPI
141 KiRosPcToUserFileHeader(IN PVOID Eip,
142 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
143 {
144 PVOID ImageBase, EipBase = NULL;
145 PLDR_DATA_TABLE_ENTRY Entry;
146 PLIST_ENTRY ListHead, NextEntry;
147
148 /*
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.
152 */
153 ListHead = &KeGetCurrentThread()->
154 Teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList;
155
156 /* Set list pointers and make sure it's valid */
157 NextEntry = ListHead->Flink;
158 if (NextEntry)
159 {
160 /* Start loop */
161 while (NextEntry != ListHead)
162 {
163 /* Get the loader entry */
164 Entry = CONTAINING_RECORD(NextEntry,
165 LDR_DATA_TABLE_ENTRY,
166 InLoadOrderLinks);
167
168 /* Move to the next entry */
169 NextEntry = NextEntry->Flink;
170 ImageBase = Entry->DllBase;
171
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)))
175 {
176 /* Return this entry */
177 *LdrEntry = Entry;
178 EipBase = ImageBase;
179 break;
180 }
181 }
182 }
183
184 /* Return the base address */
185 return EipBase;
186 }
187
188 USHORT
189 NTAPI
190 KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip,
191 IN ULONG FramesToCapture,
192 OUT PVOID *BackTrace,
193 OUT PULONG BackTraceHash OPTIONAL)
194 {
195 PVOID Frames[2 * 64];
196 ULONG FrameCount;
197 ULONG Hash = 0, i;
198
199 /* Skip a frame for the caller */
200 FramesToSkip++;
201
202 /* Don't go past the limit */
203 if ((FramesToCapture + FramesToSkip) >= 128) return 0;
204
205 /* Do the back trace */
206 FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 1);
207
208 /* Make sure we're not skipping all of them */
209 if (FrameCount <= FramesToSkip) return 0;
210
211 /* Loop all the frames */
212 for (i = 0; i < FramesToCapture; i++)
213 {
214 /* Don't go past the limit */
215 if ((FramesToSkip + i) >= FrameCount) break;
216
217 /* Save this entry and hash it */
218 BackTrace[i] = Frames[FramesToSkip + i];
219 Hash += PtrToUlong(BackTrace[i]);
220 }
221
222 /* Write the hash */
223 if (BackTraceHash) *BackTraceHash = Hash;
224
225 /* Clear the other entries and return count */
226 RtlFillMemoryUlong(Frames, 128, 0);
227 return (USHORT)i;
228 }
229
230 VOID
231 FASTCALL
232 KeRosDumpStackFrameArray(IN PULONG_PTR Frames,
233 IN ULONG FrameCount)
234 {
235 ULONG i;
236 ULONG_PTR Addr;
237 BOOLEAN InSystem;
238 PVOID p;
239
240 /* GCC complaints that it may be used uninitialized */
241 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
242
243 /* Loop them */
244 for (i = 0; i < FrameCount; i++)
245 {
246 /* Get the EIP */
247 Addr = Frames[i];
248 if (!Addr)
249 {
250 break;
251 }
252
253 /* Get the base for this file */
254 if (Addr > (ULONG_PTR)MmHighestUserAddress)
255 {
256 /* We are in kernel */
257 p = KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem);
258 }
259 else
260 {
261 /* We are in user land */
262 p = KiRosPcToUserFileHeader((PVOID)Addr, &LdrEntry);
263 }
264 if (p)
265 {
266 #ifdef KDBG
267 if (!KdbSymPrintAddress((PVOID)Addr))
268 #endif
269 {
270 /* Print out the module name */
271 Addr -= (ULONG_PTR)LdrEntry->DllBase;
272 DbgPrint("<%wZ: %p>", &LdrEntry->FullDllName, (PVOID)Addr);
273 }
274 }
275 else
276 {
277 /* Print only the address */
278 DbgPrint("<%p>", (PVOID)Addr);
279 }
280
281 /* Go to the next frame */
282 DbgPrint("\n");
283 }
284 }
285
286 VOID
287 NTAPI
288 KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL,
289 IN ULONG FrameCount OPTIONAL)
290 {
291 ULONG_PTR Frames[32];
292 ULONG RealFrameCount;
293
294 /* If the caller didn't ask, assume 32 frames */
295 if (!FrameCount || FrameCount > 32) FrameCount = 32;
296
297 if (Frame)
298 {
299 /* Dump them */
300 KeRosDumpStackFrameArray(Frame, FrameCount);
301 }
302 else
303 {
304 /* Get the current frames (skip the two. One for the dumper, one for the caller) */
305 RealFrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
306
307 /* Dump them */
308 KeRosDumpStackFrameArray(Frames, RealFrameCount);
309
310 /* Count left for user mode? */
311 if (FrameCount - RealFrameCount > 0)
312 {
313 /* Get the current frames */
314 RealFrameCount = KeRosCaptureUserStackBackTrace(-1, FrameCount - RealFrameCount, (PVOID*)Frames, NULL);
315
316 /* Dump them */
317 KeRosDumpStackFrameArray(Frames, RealFrameCount);
318 }
319 }
320 }
321
322
323 VOID
324 NTAPI
325 KeRosDumpTriageForBugZillaReport(VOID)
326 {
327 #if 0
328 extern BOOLEAN KiFastSystemCallDisable, KiSMTProcessorsPresent;
329 extern ULONG KeI386MachineType, MxcsrFeatureMask;
330 extern BOOLEAN Ke386Pae, Ke386NoExecute;
331
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"
335 "Feature Bits: %d\n"
336 "System Call Disabled: %d\n"
337 "NPX Present: %d\n"
338 "MXCsr Mask: %d\n"
339 "MXCsr Feature Mask: %d\n"
340 "XMMI Present: %d\n"
341 "FXSR Present: %d\n"
342 "Machine Type: %d\n"
343 "PAE: %d\n"
344 "NX: %d\n"
345 "Processors: %d\n"
346 "Active Processors: %d\n"
347 "Pentium LOCK Bug: %d\n"
348 "Hyperthreading: %d\n"
349 "CPU Manufacturer: %s\n"
350 "CPU Name: %wZ\n"
351 "CPUID: %d\n"
352 "CPU Type: %d\n"
353 "CPU Stepping: %d\n"
354 "CPU Speed: %d\n"
355 "CPU L2 Cache: %d\n"
356 "BIOS Date: %wZ\n"
357 "BIOS Version: %wZ\n"
358 "Video BIOS Date: %wZ\n"
359 "Video BIOS Version: %wZ\n"
360 "Memory: %d\n",
361 KeProcessorArchitecture,
362 KeFeatureBits,
363 KiFastSystemCallDisable,
364 KeI386NpxPresent,
365 KiMXCsrMask,
366 MxcsrFeatureMask,
367 KeI386XMMIPresent,
368 KeI386FxsrPresent,
369 KeI386MachineType,
370 Ke386Pae,
371 Ke386NoExecute,
372 KeNumberProcessors,
373 KeActiveProcessors,
374 KiI386PentiumLockErrataPresent,
375 KiSMTProcessorsPresent,
376 KeGetCurrentPrcb()->VendorString,
377 &KeRosProcessorName,
378 KeGetCurrentPrcb()->CpuID,
379 KeGetCurrentPrcb()->CpuType,
380 KeGetCurrentPrcb()->CpuStep,
381 KeGetCurrentPrcb()->MHz,
382 ((PKIPCR)KeGetPcr())->SecondLevelCacheSize,
383 &KeRosBiosDate,
384 &KeRosBiosVersion,
385 &KeRosVideoBiosDate,
386 &KeRosVideoBiosVersion,
387 MmNumberOfPhysicalPages * PAGE_SIZE);
388 #endif
389 }
390
391 VOID
392 INIT_FUNCTION
393 NTAPI
394 KiInitializeBugCheck(VOID)
395 {
396 PRTL_MESSAGE_RESOURCE_DATA BugCheckData;
397 LDR_RESOURCE_INFO ResourceInfo;
398 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
399 NTSTATUS Status;
400 PLDR_DATA_TABLE_ENTRY LdrEntry;
401
402 /* Get the kernel entry */
403 LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink,
404 LDR_DATA_TABLE_ENTRY,
405 InLoadOrderLinks);
406
407 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
408 ResourceInfo.Type = 11;
409 ResourceInfo.Name = 1;
410 ResourceInfo.Language = 9;
411
412 /* Do the lookup. */
413 Status = LdrFindResource_U(LdrEntry->DllBase,
414 &ResourceInfo,
415 RESOURCE_DATA_LEVEL,
416 &ResourceDataEntry);
417
418 /* Make sure it worked */
419 if (NT_SUCCESS(Status))
420 {
421 /* Now actually get a pointer to it */
422 Status = LdrAccessResource(LdrEntry->DllBase,
423 ResourceDataEntry,
424 (PVOID*)&BugCheckData,
425 NULL);
426 if (NT_SUCCESS(Status)) KiBugCodeMessages = BugCheckData;
427 }
428 }
429
430 BOOLEAN
431 NTAPI
432 KeGetBugMessageText(IN ULONG BugCheckCode,
433 OUT PANSI_STRING OutputString OPTIONAL)
434 {
435 ULONG i;
436 ULONG IdOffset;
437 ULONG_PTR MessageEntry;
438 PCHAR BugCode;
439 BOOLEAN Result = FALSE;
440
441 /* Make sure we're not bugchecking too early */
442 if (!KiBugCodeMessages) return Result;
443
444 /* Find the message. This code is based on RtlFindMesssage */
445 for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++)
446 {
447 /* Check if the ID Matches */
448 if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) &&
449 (BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId))
450 {
451 /* Get Offset to Entry */
452 MessageEntry = KiBugCodeMessages->Blocks[i].OffsetToEntries +
453 (ULONG_PTR)KiBugCodeMessages;
454 IdOffset = BugCheckCode - KiBugCodeMessages->Blocks[i].LowId;
455
456 /* Get offset to ID */
457 for (i = 0; i < IdOffset; i++)
458 {
459 /* Advance in the Entries */
460 MessageEntry += ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->
461 Length;
462 }
463
464 /* Get the final Code */
465 BugCode = ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->Text;
466 i = strlen(BugCode);
467
468 /* Handle newlines */
469 while ((i > 0) && ((BugCode[i] == '\n') ||
470 (BugCode[i] == '\r') ||
471 (BugCode[i] == ANSI_NULL)))
472 {
473 /* Check if we have a string to return */
474 if (!OutputString) BugCode[i] = ANSI_NULL;
475 i--;
476 }
477
478 /* Check if caller wants an output string */
479 if (OutputString)
480 {
481 /* Return it in the OutputString */
482 OutputString->Buffer = BugCode;
483 OutputString->Length = (USHORT)i + 1;
484 OutputString->MaximumLength = (USHORT)i + 1;
485 }
486 else
487 {
488 /* Direct Output to Screen */
489 InbvDisplayString(BugCode);
490 InbvDisplayString("\r");
491 }
492
493 /* We're done */
494 Result = TRUE;
495 break;
496 }
497 }
498
499 /* Return the result */
500 return Result;
501 }
502
503 VOID
504 NTAPI
505 KiDoBugCheckCallbacks(VOID)
506 {
507 PKBUGCHECK_CALLBACK_RECORD CurrentRecord;
508 PLIST_ENTRY ListHead, NextEntry, LastEntry;
509 ULONG_PTR Checksum;
510
511 /* First make sure that the list is Initialized... it might not be */
512 ListHead = &KeBugcheckCallbackListHead;
513 if ((ListHead->Flink) && (ListHead->Blink))
514 {
515 /* Loop the list */
516 LastEntry = ListHead;
517 NextEntry = ListHead->Flink;
518 while (NextEntry != ListHead)
519 {
520 /* Get the reord */
521 CurrentRecord = CONTAINING_RECORD(NextEntry,
522 KBUGCHECK_CALLBACK_RECORD,
523 Entry);
524
525 /* Validate it */
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;
531
532 /* Make sure it's inserted and valitdated */
533 if ((CurrentRecord->State == BufferInserted) &&
534 (CurrentRecord->Checksum == Checksum))
535 {
536 /* Call the routine */
537 CurrentRecord->State = BufferStarted;
538 (CurrentRecord->CallbackRoutine)(CurrentRecord->Buffer,
539 CurrentRecord->Length);
540 CurrentRecord->State = BufferFinished;
541 }
542
543 /* Go to the next entry */
544 LastEntry = NextEntry;
545 NextEntry = NextEntry->Flink;
546 }
547 }
548 }
549
550 VOID
551 NTAPI
552 __declspec(noreturn)
553 KiBugCheckDebugBreak(IN ULONG StatusCode)
554 {
555 /* If KDBG isn't connected, freeze the CPU, otherwise, break */
556 if (KdDebuggerNotPresent) for (;;) KeArchHaltProcessor();
557 DbgBreakPointWithStatus(StatusCode);
558 while (TRUE);
559 }
560
561 PCHAR
562 NTAPI
563 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode,
564 OUT PCHAR Ansi,
565 IN ULONG Length)
566 {
567 PCHAR p;
568 PWCHAR pw;
569 ULONG i;
570
571 /* Set length and normalize it */
572 i = Unicode->Length / sizeof(WCHAR);
573 i = min(i, Length - 1);
574
575 /* Set source and destination, and copy */
576 pw = Unicode->Buffer;
577 p = Ansi;
578 while (i--) *p++ = (CHAR)*pw++;
579
580 /* Null terminate and return */
581 *p = ANSI_NULL;
582 return Ansi;
583 }
584
585 VOID
586 NTAPI
587 KiDumpParameterImages(IN PCHAR Message,
588 IN PULONG_PTR Parameters,
589 IN ULONG ParameterCount,
590 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine)
591 {
592 ULONG i;
593 BOOLEAN InSystem;
594 PLDR_DATA_TABLE_ENTRY LdrEntry;
595 PVOID ImageBase;
596 PUNICODE_STRING DriverName;
597 CHAR AnsiName[32];
598 PIMAGE_NT_HEADERS NtHeader;
599 ULONG TimeStamp;
600 BOOLEAN FirstRun = TRUE;
601
602 /* Loop parameters */
603 for (i = 0; i < ParameterCount; i++)
604 {
605 /* Get the base for this parameter */
606 ImageBase = KiPcToFileHeader((PVOID)Parameters[i],
607 &LdrEntry,
608 FALSE,
609 &InSystem);
610 if (!ImageBase)
611 {
612 /* FIXME: Add code to check for unloaded drivers */
613 DPRINT1("Potentially unloaded driver!\n");
614 continue;
615 }
616 else
617 {
618 /* Get the NT Headers and Timestamp */
619 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
620 TimeStamp = NtHeader->FileHeader.TimeDateStamp;
621
622 /* Convert the driver name */
623 DriverName = &LdrEntry->BaseDllName;
624 ConversionRoutine(&LdrEntry->BaseDllName,
625 AnsiName,
626 sizeof(AnsiName));
627 }
628
629 /* Format driver name */
630 sprintf(Message,
631 "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
632 FirstRun ? "\r\n*":"*",
633 AnsiName,
634 (PVOID)Parameters[i],
635 ImageBase,
636 TimeStamp);
637
638 /* Check if we only had one parameter */
639 if (ParameterCount <= 1)
640 {
641 /* Then just save the name */
642 KiBugCheckDriver = DriverName;
643 }
644 else
645 {
646 /* Otherwise, display the message */
647 InbvDisplayString(Message);
648 }
649
650 /* Loop again */
651 FirstRun = FALSE;
652 }
653 }
654
655 VOID
656 NTAPI
657 KiDisplayBlueScreen(IN ULONG MessageId,
658 IN BOOLEAN IsHardError,
659 IN PCHAR HardErrCaption OPTIONAL,
660 IN PCHAR HardErrMessage OPTIONAL,
661 IN PCHAR Message)
662 {
663 CHAR AnsiName[75];
664
665 /* Check if bootvid is installed */
666 if (InbvIsBootDriverInstalled())
667 {
668 /* Acquire ownership and reset the display */
669 InbvAcquireDisplayOwnership();
670 InbvResetDisplay();
671
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);
678 }
679
680 /* Check if this is a hard error */
681 if (IsHardError)
682 {
683 /* Display caption and message */
684 if (HardErrCaption) InbvDisplayString(HardErrCaption);
685 if (HardErrMessage) InbvDisplayString(HardErrMessage);
686 }
687
688 /* Begin the display */
689 InbvDisplayString("\r\n");
690
691 /* Print out initial message */
692 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
693 InbvDisplayString("\r\n\r\n");
694
695 /* Check if we have a driver */
696 if (KiBugCheckDriver)
697 {
698 /* Print out into to driver name */
699 KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
700
701 /* Convert and print out driver name */
702 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
703 InbvDisplayString(" ");
704 InbvDisplayString(AnsiName);
705 InbvDisplayString("\r\n\r\n");
706 }
707
708 /* Check if this is the generic message */
709 if (MessageId == BUGCODE_PSS_MESSAGE)
710 {
711 /* It is, so get the bug code string as well */
712 KeGetBugMessageText(KiBugCheckData[0], NULL);
713 InbvDisplayString("\r\n\r\n");
714 }
715
716 /* Print second introduction message */
717 KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
718 InbvDisplayString("\r\n\r\n");
719
720 /* Get the bug code string */
721 KeGetBugMessageText(MessageId, NULL);
722 InbvDisplayString("\r\n\r\n");
723
724 /* Print message for technical information */
725 KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
726
727 /* Show the technical Data */
728 sprintf(AnsiName,
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);
736
737 /* Check if we have a driver*/
738 if (KiBugCheckDriver)
739 {
740 /* Display technical driver data */
741 InbvDisplayString(Message);
742 }
743 else
744 {
745 /* Dump parameter information */
746 KiDumpParameterImages(Message,
747 (PVOID)&KiBugCheckData[1],
748 4,
749 KeBugCheckUnicodeToAnsi);
750 }
751 }
752
753 VOID
754 NTAPI
755 __declspec(noreturn)
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)
762 {
763 PKPRCB Prcb = KeGetCurrentPrcb();
764 CONTEXT Context;
765 ULONG MessageId;
766 CHAR AnsiName[128];
767 BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
768 PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
769 PVOID Eip = NULL, Memory;
770 PVOID DriverBase;
771 PLDR_DATA_TABLE_ENTRY LdrEntry;
772 PULONG_PTR HardErrorParameters;
773 KIRQL OldIrql;
774 #ifdef CONFIG_SMP
775 LONG i = 0;
776 #endif
777
778 /* Set active bugcheck */
779 KeBugCheckActive = TRUE;
780 KiBugCheckDriver = NULL;
781
782 /* Check if this is power failure simulation */
783 if (BugCheckCode == POWER_FAILURE_SIMULATE)
784 {
785 /* Call the Callbacks and reboot */;
786 KiDoBugCheckCallbacks();
787 HalReturnToFirmware(HalRebootRoutine);
788 }
789
790 /* Save the IRQL and set hardware trigger */
791 Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
792 InterlockedIncrement((PLONG)&KiHardwareTrigger);
793
794 /* Capture the CPU Context */
795 RtlCaptureContext(&Prcb->ProcessorState.ContextFrame);
796 KiSaveProcessorControlState(&Prcb->ProcessorState);
797 Context = Prcb->ProcessorState.ContextFrame;
798
799 /* FIXME: Call the Watchdog if it's registered */
800
801 /* Check which bugcode this is */
802 switch (BugCheckCode)
803 {
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:
810 case DATA_BUS_ERROR:
811 case FAT_FILE_SYSTEM:
812 case NO_MORE_SYSTEM_PTES:
813 case INACCESSIBLE_BOOT_DEVICE:
814
815 /* Keep the same code */
816 MessageId = BugCheckCode;
817 break;
818
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:
823
824 /* Use the generic text message */
825 MessageId = KMODE_EXCEPTION_NOT_HANDLED;
826 break;
827
828 /* File-system errors */
829 case NTFS_FILE_SYSTEM:
830
831 /* Use the generic message for FAT */
832 MessageId = FAT_FILE_SYSTEM;
833 break;
834
835 /* Check if this is a coruption of the Mm's Pool */
836 case DRIVER_CORRUPTED_MMPOOL:
837
838 /* Use generic corruption message */
839 MessageId = DRIVER_CORRUPTED_EXPOOL;
840 break;
841
842 /* Check if this is a signature check failure */
843 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
844
845 /* Use the generic corruption message */
846 MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
847 break;
848
849 /* All other codes */
850 default:
851
852 /* Use the default bugcheck message */
853 MessageId = BUGCODE_PSS_MESSAGE;
854 break;
855 }
856
857 /* Save bugcheck data */
858 KiBugCheckData[0] = BugCheckCode;
859 KiBugCheckData[1] = BugCheckParameter1;
860 KiBugCheckData[2] = BugCheckParameter2;
861 KiBugCheckData[3] = BugCheckParameter3;
862 KiBugCheckData[4] = BugCheckParameter4;
863
864 /* Now check what bugcheck this is */
865 switch (BugCheckCode)
866 {
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:
871
872 /* Check if we have a trap frame */
873 if (!TrapFrame)
874 {
875 /* Use parameter 3 as a trap frame, if it exists */
876 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
877 }
878
879 /* Check if we got one now and if we need to get EIP */
880 if ((TrapFrame) &&
881 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
882 {
883 #ifdef _M_IX86
884 /* Get EIP */
885 Eip = (PVOID)TrapFrame->Eip;
886 #elif defined(_M_PPC)
887 Eip = (PVOID)TrapFrame->Dr0; /* srr0 */
888 #endif
889 }
890 break;
891
892 /* Wrong IRQL */
893 case IRQL_NOT_LESS_OR_EQUAL:
894
895 /*
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.
900 */
901
902 /* Eip is in parameter 4 */
903 Eip = (PVOID)BugCheckParameter4;
904
905 /* Get the driver base */
906 DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
907 if (IsSystem)
908 {
909 /*
910 * The error happened inside the kernel or HAL.
911 * Get the memory address that was being referenced.
912 */
913 Memory = (PVOID)BugCheckParameter1;
914
915 /* Find to which driver it belongs */
916 DriverBase = KiPcToFileHeader(Memory,
917 &LdrEntry,
918 TRUE,
919 &IsSystem);
920 if (DriverBase)
921 {
922 /* Get the driver name and update the bug code */
923 KiBugCheckDriver = &LdrEntry->BaseDllName;
924 KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
925 }
926 else
927 {
928 /* Find the driver that unloaded at this address */
929 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
930
931 /* Check if the cause was an unloaded driver */
932 if (KiBugCheckDriver)
933 {
934 /* Update bug check code */
935 KiBugCheckData[0] =
936 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
937 }
938 }
939 }
940 else
941 {
942 /* Update the bug check code */
943 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
944 }
945
946 /* Clear EIP so we don't look it up later */
947 Eip = NULL;
948 break;
949
950 /* Hard error */
951 case FATAL_UNHANDLED_HARD_ERROR:
952
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];
960
961 /* Remember that this is hard error and set the caption/message */
962 IsHardError = TRUE;
963 HardErrCaption = (PCHAR)BugCheckParameter3;
964 HardErrMessage = (PCHAR)BugCheckParameter4;
965 break;
966
967 /* Page fault */
968 case PAGE_FAULT_IN_NONPAGED_AREA:
969
970 /* Assume no driver */
971 DriverBase = NULL;
972
973 /* Check if we have a trap frame */
974 if (!TrapFrame)
975 {
976 /* We don't, use parameter 3 if possible */
977 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
978 }
979
980 /* Check if we have a frame now */
981 if (TrapFrame)
982 {
983 #ifdef _M_IX86
984 /* Get EIP */
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;
990 #endif
991
992 /* Find out if was in the kernel or drivers */
993 DriverBase = KiPcToFileHeader(Eip,
994 &LdrEntry,
995 FALSE,
996 &IsSystem);
997 }
998
999 /*
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.
1003 */
1004
1005 /* Check if we didn't have a driver base */
1006 if (!DriverBase)
1007 {
1008 /* Find the driver that unloaded at this address */
1009 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
1010
1011 /* Check if the cause was an unloaded driver */
1012 if (KiBugCheckDriver)
1013 {
1014 KiBugCheckData[0] =
1015 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
1016 }
1017 }
1018 break;
1019
1020 /* Check if the driver forgot to unlock pages */
1021 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
1022
1023 /* EIP is in parameter 1 */
1024 Eip = (PVOID)BugCheckParameter1;
1025 break;
1026
1027 /* Check if the driver consumed too many PTEs */
1028 case DRIVER_USED_EXCESSIVE_PTES:
1029
1030 /* Loader entry is in parameter 1 */
1031 LdrEntry = (PVOID)BugCheckParameter1;
1032 KiBugCheckDriver = &LdrEntry->BaseDllName;
1033 break;
1034
1035 /* Check if the driver has a stuck thread */
1036 case THREAD_STUCK_IN_DEVICE_DRIVER:
1037
1038 /* The name is in Parameter 3 */
1039 KiBugCheckDriver = (PVOID)BugCheckParameter3;
1040 break;
1041
1042 /* Anything else */
1043 default:
1044 break;
1045 }
1046
1047 /* Do we have a driver name? */
1048 if (KiBugCheckDriver)
1049 {
1050 /* Convert it to ANSI */
1051 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
1052 }
1053 else
1054 {
1055 /* Do we have an EIP? */
1056 if (Eip)
1057 {
1058 /* Dump image name */
1059 KiDumpParameterImages(AnsiName,
1060 (PULONG_PTR)&Eip,
1061 1,
1062 KeBugCheckUnicodeToAnsi);
1063 }
1064 }
1065
1066 /* Check if we need to save the context for KD */
1067 #ifdef _WINKD_
1068 if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG_PTR)&Context;
1069 #endif
1070
1071 /* Check if a debugger is connected */
1072 if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
1073 {
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",
1077 KiBugCheckData[0],
1078 KiBugCheckData[1],
1079 KiBugCheckData[2],
1080 KiBugCheckData[3],
1081 KiBugCheckData[4]);
1082
1083 /* Check if the debugger isn't currently connected */
1084 if (!KdDebuggerNotPresent)
1085 {
1086 /* Check if we have a driver to blame */
1087 if (KiBugCheckDriver)
1088 {
1089 /* Dump it */
1090 DbgPrint("Driver at fault: %s.\n", AnsiName);
1091 }
1092
1093 /* Check if this was a hard error */
1094 if (IsHardError)
1095 {
1096 /* Print caption and message */
1097 if (HardErrCaption) DbgPrint(HardErrCaption);
1098 if (HardErrMessage) DbgPrint(HardErrMessage);
1099 }
1100
1101 /* Break in the debugger */
1102 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
1103 }
1104 else
1105 {
1106 /*
1107 * ROS HACK.
1108 * Ok, so debugging is enabled, but KDBG isn't there.
1109 * We'll manually dump the stack for the user.
1110 */
1111 KeRosDumpStackFrames(NULL, 0);
1112
1113 /* ROS HACK 2: Generate something useful for Bugzilla */
1114 KeRosDumpTriageForBugZillaReport();
1115 }
1116 }
1117
1118 /* Raise IRQL to HIGH_LEVEL */
1119 _disable();
1120 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1121
1122 /* Avoid recursion */
1123 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1124 {
1125 #ifdef CONFIG_SMP
1126 /* Set CPU that is bug checking now */
1127 KeBugCheckOwner = Prcb->Number;
1128
1129 /* Freeze the other CPUs */
1130 for (i = 0; i < KeNumberProcessors; i++)
1131 {
1132 if (i != (LONG)KeGetCurrentProcessorNumber())
1133 {
1134 /* Send the IPI and give them one second to catch up */
1135 KiIpiSend(1 << i, IPI_FREEZE);
1136 KeStallExecutionProcessor(1000000);
1137 }
1138 }
1139 #endif
1140
1141 /* Display the BSOD */
1142 KeLowerIrql(APC_LEVEL); // This is a nastier hack than any ever before
1143 KiDisplayBlueScreen(MessageId,
1144 IsHardError,
1145 HardErrCaption,
1146 HardErrMessage,
1147 AnsiName);
1148 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1149
1150 /* Check if the debugger is disabled but we can enable it */
1151 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1152 {
1153 /* Enable it */
1154 #ifdef _WINKD_
1155 KdEnableDebuggerWithLock(FALSE);
1156 #endif
1157 }
1158 else
1159 {
1160 /* Otherwise, print the last line */
1161 InbvDisplayString("\r\n");
1162 }
1163
1164 /* Save the context */
1165 Prcb->ProcessorState.ContextFrame = Context;
1166
1167 /* FIXME: Support Triage Dump */
1168
1169 /* Write the crash dump */
1170 MmDumpToPagingFile(KiBugCheckData[4],
1171 KiBugCheckData[0],
1172 KiBugCheckData[1],
1173 KiBugCheckData[2],
1174 KiBugCheckData[3],
1175 TrapFrame);
1176 }
1177 else
1178 {
1179 /* Increase recursion count */
1180 KeBugCheckOwnerRecursionCount++;
1181 if (KeBugCheckOwnerRecursionCount == 2)
1182 {
1183 /* Break in the debugger */
1184 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1185 }
1186 else if (KeBugCheckOwnerRecursionCount > 2)
1187 {
1188 /* Halt the CPU */
1189 for (;;) KeArchHaltProcessor();
1190 }
1191 }
1192
1193 /* Call the Callbacks */
1194 KiDoBugCheckCallbacks();
1195
1196 /* FIXME: Call Watchdog if enabled */
1197
1198 /* Check if we have to reboot */
1199 if (Reboot)
1200 {
1201 /* Unload symbols */
1202 DbgUnLoadImageSymbols(NULL, NtCurrentProcess(), 0);
1203 HalReturnToFirmware(HalRebootRoutine);
1204 }
1205
1206 /* Attempt to break in the debugger (otherwise halt CPU) */
1207 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1208 }
1209
1210 /* PUBLIC FUNCTIONS **********************************************************/
1211
1212 /*
1213 * @unimplemented
1214 */
1215 NTSTATUS
1216 NTAPI
1217 KeInitializeCrashDumpHeader(IN ULONG Type,
1218 IN ULONG Flags,
1219 OUT PVOID Buffer,
1220 IN ULONG BufferSize,
1221 OUT ULONG BufferNeeded OPTIONAL)
1222 {
1223 UNIMPLEMENTED;
1224 return STATUS_UNSUCCESSFUL;
1225 }
1226
1227 /*
1228 * @implemented
1229 */
1230 BOOLEAN
1231 NTAPI
1232 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
1233 {
1234 KIRQL OldIrql;
1235 BOOLEAN Status = FALSE;
1236
1237 /* Raise IRQL to High */
1238 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1239
1240 /* Check the Current State */
1241 if (CallbackRecord->State == BufferInserted)
1242 {
1243 /* Reset state and remove from list */
1244 CallbackRecord->State = BufferEmpty;
1245 RemoveEntryList(&CallbackRecord->Entry);
1246 Status = TRUE;
1247 }
1248
1249 /* Lower IRQL and return */
1250 KeLowerIrql(OldIrql);
1251 return Status;
1252 }
1253
1254 /*
1255 * @implemented
1256 */
1257 BOOLEAN
1258 NTAPI
1259 KeDeregisterBugCheckReasonCallback(
1260 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
1261 {
1262 KIRQL OldIrql;
1263 BOOLEAN Status = FALSE;
1264
1265 /* Raise IRQL to High */
1266 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1267
1268 /* Check the Current State */
1269 if (CallbackRecord->State == BufferInserted)
1270 {
1271 /* Reset state and remove from list */
1272 CallbackRecord->State = BufferEmpty;
1273 RemoveEntryList(&CallbackRecord->Entry);
1274 Status = TRUE;
1275 }
1276
1277 /* Lower IRQL and return */
1278 KeLowerIrql(OldIrql);
1279 return Status;
1280 }
1281
1282 /*
1283 * @unimplemented
1284 */
1285 NTSTATUS
1286 NTAPI
1287 KeDeregisterNmiCallback(PVOID Handle)
1288 {
1289 UNIMPLEMENTED;
1290 return STATUS_UNSUCCESSFUL;
1291 }
1292
1293 /*
1294 * @implemented
1295 */
1296 BOOLEAN
1297 NTAPI
1298 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
1299 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
1300 IN PVOID Buffer,
1301 IN ULONG Length,
1302 IN PUCHAR Component)
1303 {
1304 KIRQL OldIrql;
1305 BOOLEAN Status = FALSE;
1306
1307 /* Raise IRQL to High */
1308 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1309
1310 /* Check the Current State first so we don't double-register */
1311 if (CallbackRecord->State == BufferEmpty)
1312 {
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);
1320 Status = TRUE;
1321 }
1322
1323 /* Lower IRQL and return */
1324 KeLowerIrql(OldIrql);
1325 return Status;
1326 }
1327
1328 /*
1329 * @implemented
1330 */
1331 BOOLEAN
1332 NTAPI
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)
1338 {
1339 KIRQL OldIrql;
1340 BOOLEAN Status = FALSE;
1341
1342 /* Raise IRQL to High */
1343 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1344
1345 /* Check the Current State first so we don't double-register */
1346 if (CallbackRecord->State == BufferEmpty)
1347 {
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);
1355 Status = TRUE;
1356 }
1357
1358 /* Lower IRQL and return */
1359 KeLowerIrql(OldIrql);
1360 return Status;
1361 }
1362
1363 /*
1364 * @unimplemented
1365 */
1366 PVOID
1367 NTAPI
1368 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,
1369 IN PVOID Context)
1370 {
1371 UNIMPLEMENTED;
1372 return NULL;
1373 }
1374
1375 /*
1376 * @implemented
1377 */
1378 VOID
1379 NTAPI
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)
1385 {
1386 /* Call the internal API */
1387 KeBugCheckWithTf(BugCheckCode,
1388 BugCheckParameter1,
1389 BugCheckParameter2,
1390 BugCheckParameter3,
1391 BugCheckParameter4,
1392 NULL);
1393 }
1394
1395 /*
1396 * @implemented
1397 */
1398 VOID
1399 NTAPI
1400 KeBugCheck(ULONG BugCheckCode)
1401 {
1402 /* Call the internal API */
1403 KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
1404 }
1405
1406 /*
1407 * @implemented
1408 */
1409 VOID
1410 NTAPI
1411 KeEnterKernelDebugger(VOID)
1412 {
1413 /* Disable interrupts */
1414 KiHardwareTrigger = 1;
1415 _disable();
1416
1417 /* Check the bugcheck count */
1418 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1419 {
1420 /* There was only one, is the debugger disabled? */
1421 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1422 {
1423 /* Enable the debugger */
1424 KdInitSystem(0, NULL);
1425 }
1426 }
1427
1428 /* Bugcheck */
1429 KiBugCheckDebugBreak(DBG_STATUS_FATAL);
1430 }
1431
1432 /* EOF */