- Dispatch all symbol loads to a single function, which determines type of passed...
[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 <internal/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 NTAPI
232 KeRosDumpStackFrames(IN PULONG Frame OPTIONAL,
233 IN ULONG FrameCount OPTIONAL)
234 {
235 ULONG Frames[32];
236 ULONG i, Addr;
237 BOOLEAN InSystem;
238 PLDR_DATA_TABLE_ENTRY LdrEntry;
239
240 /* If the caller didn't ask, assume 32 frames */
241 if (!FrameCount || FrameCount > 32) FrameCount = 32;
242
243 /* Get the current frames */
244 FrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
245
246 /* Now loop them (skip the two. One for the dumper, one for the caller) */
247 for (i = 0; i < FrameCount; i++)
248 {
249 /* Get the EIP */
250 Addr = Frames[i];
251
252 /* If we had a custom frame, make sure we've reached it first */
253 if ((Frame) && (Frame[1] == Addr))
254 {
255 Frame = NULL;
256 }
257 else if (Frame)
258 {
259 /* Skip this entry */
260 continue;
261 }
262
263 /* Get the base for this file */
264 if (KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem))
265 {
266 /* Print out the module name */
267 Addr -= (ULONG_PTR)LdrEntry->DllBase;
268 DbgPrint("<%wZ: %x>", &LdrEntry->FullDllName, Addr);
269 }
270 else if (Addr)
271 {
272 /* Print only the address */
273 DbgPrint("<%x>", Addr);
274 }
275
276 /* Go to the next frame */
277 DbgPrint("\n");
278 }
279
280 /* Get the current frames */
281 FrameCount = KeRosCaptureUserStackBackTrace(-1, 32, (PVOID*)Frames, NULL);
282
283 /* Now loop them */
284 for (i = 0; i < FrameCount; i++)
285 {
286 /* Get the EIP */
287 Addr = Frames[i];
288
289 /* Get the base for this file */
290 if (KiRosPcToUserFileHeader((PVOID)Addr, &LdrEntry))
291 {
292 /* Print out the module name */
293 #ifdef KDBG
294 if (!KdbSymPrintAddress((PVOID)Addr))
295 #endif
296 {
297 /* Fall back to usual printing */
298 Addr -= (ULONG_PTR)LdrEntry->DllBase;
299 DbgPrint("<%wZ: %x>", &LdrEntry->FullDllName, Addr);
300 }
301 }
302 else if (Addr)
303 {
304 /* Print only the address */
305 DbgPrint("<%x>", Addr);
306 }
307
308 /* Go to the next frame */
309 DbgPrint("\n");
310 }
311
312 /* Finish the output */
313 DbgPrint("\n");
314 }
315
316 VOID
317 NTAPI
318 KeRosDumpTriageForBugZillaReport(VOID)
319 {
320 #if 0
321 extern BOOLEAN KiFastSystemCallDisable, KiSMTProcessorsPresent;
322 extern ULONG KeI386MachineType, MxcsrFeatureMask;
323 extern BOOLEAN Ke386Pae, Ke386NoExecute;
324
325 DbgPrint("ReactOS has crashed! Please go to http://www.reactos.org/bugzilla/enter_bug.cgi to file a bug!\n");
326 DbgPrint("\nHardware Information\n");
327 DbgPrint("Processor Architecture: %d\n"
328 "Feature Bits: %d\n"
329 "System Call Disabled: %d\n"
330 "NPX Present: %d\n"
331 "MXCsr Mask: %d\n"
332 "MXCsr Feature Mask: %d\n"
333 "XMMI Present: %d\n"
334 "FXSR Present: %d\n"
335 "Machine Type: %d\n"
336 "PAE: %d\n"
337 "NX: %d\n"
338 "Processors: %d\n"
339 "Active Processors: %d\n"
340 "Pentium LOCK Bug: %d\n"
341 "Hyperthreading: %d\n"
342 "CPU Manufacturer: %s\n"
343 "CPU Name: %wZ\n"
344 "CPUID: %d\n"
345 "CPU Type: %d\n"
346 "CPU Stepping: %d\n"
347 "CPU Speed: %d\n"
348 "CPU L2 Cache: %d\n"
349 "BIOS Date: %wZ\n"
350 "BIOS Version: %wZ\n"
351 "Video BIOS Date: %wZ\n"
352 "Video BIOS Version: %wZ\n"
353 "Memory: %d\n",
354 KeProcessorArchitecture,
355 KeFeatureBits,
356 KiFastSystemCallDisable,
357 KeI386NpxPresent,
358 KiMXCsrMask,
359 MxcsrFeatureMask,
360 KeI386XMMIPresent,
361 KeI386FxsrPresent,
362 KeI386MachineType,
363 Ke386Pae,
364 Ke386NoExecute,
365 KeNumberProcessors,
366 KeActiveProcessors,
367 KiI386PentiumLockErrataPresent,
368 KiSMTProcessorsPresent,
369 KeGetCurrentPrcb()->VendorString,
370 &KeRosProcessorName,
371 KeGetCurrentPrcb()->CpuID,
372 KeGetCurrentPrcb()->CpuType,
373 KeGetCurrentPrcb()->CpuStep,
374 KeGetCurrentPrcb()->MHz,
375 ((PKIPCR)KeGetPcr())->SecondLevelCacheSize,
376 &KeRosBiosDate,
377 &KeRosBiosVersion,
378 &KeRosVideoBiosDate,
379 &KeRosVideoBiosVersion,
380 MmNumberOfPhysicalPages * PAGE_SIZE);
381 #endif
382 }
383
384 VOID
385 INIT_FUNCTION
386 NTAPI
387 KiInitializeBugCheck(VOID)
388 {
389 PRTL_MESSAGE_RESOURCE_DATA BugCheckData;
390 LDR_RESOURCE_INFO ResourceInfo;
391 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
392 NTSTATUS Status;
393 PLDR_DATA_TABLE_ENTRY LdrEntry;
394
395 /* Get the kernel entry */
396 LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink,
397 LDR_DATA_TABLE_ENTRY,
398 InLoadOrderLinks);
399
400 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
401 ResourceInfo.Type = 11;
402 ResourceInfo.Name = 1;
403 ResourceInfo.Language = 9;
404
405 /* Do the lookup. */
406 Status = LdrFindResource_U(LdrEntry->DllBase,
407 &ResourceInfo,
408 RESOURCE_DATA_LEVEL,
409 &ResourceDataEntry);
410
411 /* Make sure it worked */
412 if (NT_SUCCESS(Status))
413 {
414 /* Now actually get a pointer to it */
415 Status = LdrAccessResource(LdrEntry->DllBase,
416 ResourceDataEntry,
417 (PVOID*)&BugCheckData,
418 NULL);
419 if (NT_SUCCESS(Status)) KiBugCodeMessages = BugCheckData;
420 }
421 }
422
423 BOOLEAN
424 NTAPI
425 KeGetBugMessageText(IN ULONG BugCheckCode,
426 OUT PANSI_STRING OutputString OPTIONAL)
427 {
428 ULONG i;
429 ULONG IdOffset;
430 ULONG_PTR MessageEntry;
431 PCHAR BugCode;
432 BOOLEAN Result = FALSE;
433
434 /* Make sure we're not bugchecking too early */
435 if (!KiBugCodeMessages) return Result;
436
437 /* Find the message. This code is based on RtlFindMesssage */
438 for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++)
439 {
440 /* Check if the ID Matches */
441 if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) &&
442 (BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId))
443 {
444 /* Get Offset to Entry */
445 MessageEntry = KiBugCodeMessages->Blocks[i].OffsetToEntries +
446 (ULONG_PTR)KiBugCodeMessages;
447 IdOffset = BugCheckCode - KiBugCodeMessages->Blocks[i].LowId;
448
449 /* Get offset to ID */
450 for (i = 0; i < IdOffset; i++)
451 {
452 /* Advance in the Entries */
453 MessageEntry += ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->
454 Length;
455 }
456
457 /* Get the final Code */
458 BugCode = ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->Text;
459 i = strlen(BugCode);
460
461 /* Handle newlines */
462 while ((i > 0) && ((BugCode[i] == '\n') ||
463 (BugCode[i] == '\r') ||
464 (BugCode[i] == ANSI_NULL)))
465 {
466 /* Check if we have a string to return */
467 if (!OutputString) BugCode[i] = ANSI_NULL;
468 i--;
469 }
470
471 /* Check if caller wants an output string */
472 if (OutputString)
473 {
474 /* Return it in the OutputString */
475 OutputString->Buffer = BugCode;
476 OutputString->Length = (USHORT)i + 1;
477 OutputString->MaximumLength = (USHORT)i + 1;
478 }
479 else
480 {
481 /* Direct Output to Screen */
482 InbvDisplayString(BugCode);
483 InbvDisplayString("\r");
484 }
485
486 /* We're done */
487 Result = TRUE;
488 break;
489 }
490 }
491
492 /* Return the result */
493 return Result;
494 }
495
496 VOID
497 NTAPI
498 KiDoBugCheckCallbacks(VOID)
499 {
500 PKBUGCHECK_CALLBACK_RECORD CurrentRecord;
501 PLIST_ENTRY ListHead, NextEntry, LastEntry;
502 ULONG_PTR Checksum;
503
504 /* First make sure that the list is Initialized... it might not be */
505 ListHead = &KeBugcheckCallbackListHead;
506 if ((ListHead->Flink) && (ListHead->Blink))
507 {
508 /* Loop the list */
509 LastEntry = ListHead;
510 NextEntry = ListHead->Flink;
511 while (NextEntry != ListHead)
512 {
513 /* Get the reord */
514 CurrentRecord = CONTAINING_RECORD(NextEntry,
515 KBUGCHECK_CALLBACK_RECORD,
516 Entry);
517
518 /* Validate it */
519 if (CurrentRecord->Entry.Blink != LastEntry) return;
520 Checksum = (ULONG_PTR)CurrentRecord->CallbackRoutine;
521 Checksum += (ULONG_PTR)CurrentRecord->Buffer;
522 Checksum += (ULONG_PTR)CurrentRecord->Length;
523 Checksum += (ULONG_PTR)CurrentRecord->Component;
524
525 /* Make sure it's inserted and valitdated */
526 if ((CurrentRecord->State == BufferInserted) &&
527 (CurrentRecord->Checksum == Checksum))
528 {
529 /* Call the routine */
530 CurrentRecord->State = BufferStarted;
531 (CurrentRecord->CallbackRoutine)(CurrentRecord->Buffer,
532 CurrentRecord->Length);
533 CurrentRecord->State = BufferFinished;
534 }
535
536 /* Go to the next entry */
537 LastEntry = NextEntry;
538 NextEntry = NextEntry->Flink;
539 }
540 }
541 }
542
543 VOID
544 NTAPI
545 KiBugCheckDebugBreak(IN ULONG StatusCode)
546 {
547 /* If KDBG isn't connected, freeze the CPU, otherwise, break */
548 if (KdDebuggerNotPresent) for (;;) KeArchHaltProcessor();
549 DbgBreakPointWithStatus(StatusCode);
550 }
551
552 PCHAR
553 NTAPI
554 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode,
555 OUT PCHAR Ansi,
556 IN ULONG Length)
557 {
558 PCHAR p;
559 PWCHAR pw;
560 ULONG i;
561
562 /* Set length and normalize it */
563 i = Unicode->Length / sizeof(WCHAR);
564 i = min(i, Length - 1);
565
566 /* Set source and destination, and copy */
567 pw = Unicode->Buffer;
568 p = Ansi;
569 while (i--) *p++ = (CHAR)*pw++;
570
571 /* Null terminate and return */
572 *p = ANSI_NULL;
573 return Ansi;
574 }
575
576 VOID
577 NTAPI
578 KiDumpParameterImages(IN PCHAR Message,
579 IN PULONG_PTR Parameters,
580 IN ULONG ParameterCount,
581 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine)
582 {
583 ULONG i;
584 BOOLEAN InSystem;
585 PLDR_DATA_TABLE_ENTRY LdrEntry;
586 PVOID ImageBase;
587 PUNICODE_STRING DriverName;
588 CHAR AnsiName[32];
589 PIMAGE_NT_HEADERS NtHeader;
590 ULONG TimeStamp;
591 BOOLEAN FirstRun = TRUE;
592
593 /* Loop parameters */
594 for (i = 0; i < ParameterCount; i++)
595 {
596 /* Get the base for this parameter */
597 ImageBase = KiPcToFileHeader((PVOID)Parameters[i],
598 &LdrEntry,
599 FALSE,
600 &InSystem);
601 if (!ImageBase)
602 {
603 /* Driver wasn't found, check for unloaded driver */
604 DriverName = NULL; // FIXME: ROS can't
605 if (!DriverName) continue;
606
607 /* Convert the driver name */
608 ImageBase = (PVOID)Parameters[i];
609 ConversionRoutine(DriverName, AnsiName, sizeof(AnsiName));
610 }
611 else
612 {
613 /* Get the NT Headers and Timestamp */
614 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
615 TimeStamp = NtHeader->FileHeader.TimeDateStamp;
616
617 /* Convert the driver name */
618 DriverName = &LdrEntry->BaseDllName;
619 ConversionRoutine(&LdrEntry->BaseDllName,
620 AnsiName,
621 sizeof(AnsiName));
622 }
623
624 /* Format driver name */
625 sprintf(Message,
626 "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
627 FirstRun ? "\r\n*":"*",
628 AnsiName,
629 (PVOID)Parameters[i],
630 ImageBase,
631 TimeStamp);
632
633 /* Check if we only had one parameter */
634 if (ParameterCount <= 1)
635 {
636 /* Then just save the name */
637 KiBugCheckDriver = DriverName;
638 }
639 else
640 {
641 /* Otherwise, display the message */
642 InbvDisplayString(Message);
643 }
644
645 /* Loop again */
646 FirstRun = FALSE;
647 }
648 }
649
650 VOID
651 NTAPI
652 KiDisplayBlueScreen(IN ULONG MessageId,
653 IN BOOLEAN IsHardError,
654 IN PCHAR HardErrCaption OPTIONAL,
655 IN PCHAR HardErrMessage OPTIONAL,
656 IN PCHAR Message)
657 {
658 CHAR AnsiName[75];
659
660 /* Check if bootvid is installed */
661 if (InbvIsBootDriverInstalled())
662 {
663 /* Acquire ownership and reset the display */
664 InbvAcquireDisplayOwnership();
665 InbvResetDisplay();
666
667 /* Display blue screen */
668 InbvSolidColorFill(0, 0, 639, 479, 4);
669 InbvSetTextColor(15);
670 InbvInstallDisplayStringFilter(NULL);
671 InbvEnableDisplayString(TRUE);
672 InbvSetScrollRegion(0, 0, 639, 479);
673 }
674
675 /* Check if this is a hard error */
676 if (IsHardError)
677 {
678 /* Display caption and message */
679 if (HardErrCaption) InbvDisplayString(HardErrCaption);
680 if (HardErrMessage) InbvDisplayString(HardErrMessage);
681 }
682
683 /* Begin the display */
684 InbvDisplayString("\r\n");
685
686 /* Print out initial message */
687 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
688 InbvDisplayString("\r\n\r\n");
689
690 /* Check if we have a driver */
691 if (KiBugCheckDriver)
692 {
693 /* Print out into to driver name */
694 KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
695
696 /* Convert and print out driver name */
697 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
698 InbvDisplayString(" ");
699 InbvDisplayString(AnsiName);
700 InbvDisplayString("\r\n\r\n");
701 }
702
703 /* Check if this is the generic message */
704 if (MessageId == BUGCODE_PSS_MESSAGE)
705 {
706 /* It is, so get the bug code string as well */
707 KeGetBugMessageText(KiBugCheckData[0], NULL);
708 InbvDisplayString("\r\n\r\n");
709 }
710
711 /* Print second introduction message */
712 KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
713 InbvDisplayString("\r\n\r\n");
714
715 /* Get the bug code string */
716 KeGetBugMessageText(MessageId, NULL);
717 InbvDisplayString("\r\n\r\n");
718
719 /* Print message for technical information */
720 KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
721
722 /* Show the technical Data */
723 sprintf(AnsiName,
724 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
725 KiBugCheckData[0],
726 (PVOID)KiBugCheckData[1],
727 (PVOID)KiBugCheckData[2],
728 (PVOID)KiBugCheckData[3],
729 (PVOID)KiBugCheckData[4]);
730 InbvDisplayString(AnsiName);
731
732 /* Check if we have a driver*/
733 if (KiBugCheckDriver)
734 {
735 /* Display technical driver data */
736 InbvDisplayString(Message);
737 }
738 else
739 {
740 /* Dump parameter information */
741 KiDumpParameterImages(Message,
742 (PVOID)&KiBugCheckData[1],
743 4,
744 KeBugCheckUnicodeToAnsi);
745 }
746 }
747
748 VOID
749 NTAPI
750 KeBugCheckWithTf(IN ULONG BugCheckCode,
751 IN ULONG_PTR BugCheckParameter1,
752 IN ULONG_PTR BugCheckParameter2,
753 IN ULONG_PTR BugCheckParameter3,
754 IN ULONG_PTR BugCheckParameter4,
755 IN PKTRAP_FRAME TrapFrame)
756 {
757 PKPRCB Prcb = KeGetCurrentPrcb();
758 CONTEXT Context;
759 ULONG MessageId;
760 CHAR AnsiName[128];
761 BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
762 PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
763 PVOID Eip = NULL, Memory;
764 PVOID DriverBase;
765 PLDR_DATA_TABLE_ENTRY LdrEntry;
766 PULONG_PTR HardErrorParameters;
767 #ifdef CONFIG_SMP
768 LONG i = 0;
769 #endif
770
771 /* Set active bugcheck */
772 KeBugCheckActive = TRUE;
773 KiBugCheckDriver = NULL;
774
775 /* Check if this is power failure simulation */
776 if (BugCheckCode == POWER_FAILURE_SIMULATE)
777 {
778 /* Call the Callbacks and reboot */;
779 KiDoBugCheckCallbacks();
780 HalReturnToFirmware(HalRebootRoutine);
781 }
782
783 /* Save the IRQL and set hardware trigger */
784 Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
785 InterlockedIncrement((PLONG)&KiHardwareTrigger);
786
787 /* Capture the CPU Context */
788 RtlCaptureContext(&Prcb->ProcessorState.ContextFrame);
789 KiSaveProcessorControlState(&Prcb->ProcessorState);
790 Context = Prcb->ProcessorState.ContextFrame;
791
792 /* FIXME: Call the Watchdog if it's registered */
793
794 /* Check which bugcode this is */
795 switch (BugCheckCode)
796 {
797 /* These bug checks already have detailed messages, keep them */
798 case UNEXPECTED_KERNEL_MODE_TRAP:
799 case DRIVER_CORRUPTED_EXPOOL:
800 case ACPI_BIOS_ERROR:
801 case ACPI_BIOS_FATAL_ERROR:
802 case THREAD_STUCK_IN_DEVICE_DRIVER:
803 case DATA_BUS_ERROR:
804 case FAT_FILE_SYSTEM:
805 case NO_MORE_SYSTEM_PTES:
806 case INACCESSIBLE_BOOT_DEVICE:
807
808 /* Keep the same code */
809 MessageId = BugCheckCode;
810 break;
811
812 /* Check if this is a kernel-mode exception */
813 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
814 //case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
815 case KMODE_EXCEPTION_NOT_HANDLED:
816
817 /* Use the generic text message */
818 MessageId = KMODE_EXCEPTION_NOT_HANDLED;
819 break;
820
821 /* File-system errors */
822 case NTFS_FILE_SYSTEM:
823
824 /* Use the generic message for FAT */
825 MessageId = FAT_FILE_SYSTEM;
826 break;
827
828 /* Check if this is a coruption of the Mm's Pool */
829 case DRIVER_CORRUPTED_MMPOOL:
830
831 /* Use generic corruption message */
832 MessageId = DRIVER_CORRUPTED_EXPOOL;
833 break;
834
835 /* Check if this is a signature check failure */
836 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
837
838 /* Use the generic corruption message */
839 MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
840 break;
841
842 /* All other codes */
843 default:
844
845 /* Use the default bugcheck message */
846 MessageId = BUGCODE_PSS_MESSAGE;
847 break;
848 }
849
850 /* Save bugcheck data */
851 KiBugCheckData[0] = BugCheckCode;
852 KiBugCheckData[1] = BugCheckParameter1;
853 KiBugCheckData[2] = BugCheckParameter2;
854 KiBugCheckData[3] = BugCheckParameter3;
855 KiBugCheckData[4] = BugCheckParameter4;
856
857 /* Now check what bugcheck this is */
858 switch (BugCheckCode)
859 {
860 /* Invalid access to R/O memory or Unhandled KM Exception */
861 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
862 case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
863 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY:
864
865 /* Check if we have a trap frame */
866 if (!TrapFrame)
867 {
868 /* Use parameter 3 as a trap frame, if it exists */
869 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
870 }
871
872 /* Check if we got one now and if we need to get EIP */
873 if ((TrapFrame) &&
874 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
875 {
876 #ifdef _M_IX86
877 /* Get EIP */
878 Eip = (PVOID)TrapFrame->Eip;
879 #elif defined(_M_PPC)
880 Eip = (PVOID)TrapFrame->Dr0; /* srr0 */
881 #endif
882 }
883 break;
884
885 /* Wrong IRQL */
886 case IRQL_NOT_LESS_OR_EQUAL:
887
888 /*
889 * The NT kernel has 3 special sections:
890 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
891 * determine in which of these sections this bugcode happened
892 * and provide a more detailed analysis. For now, we don't.
893 */
894
895 /* Eip is in parameter 4 */
896 Eip = (PVOID)BugCheckParameter4;
897
898 /* Get the driver base */
899 DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
900 if (IsSystem)
901 {
902 /*
903 * The error happened inside the kernel or HAL.
904 * Get the memory address that was being referenced.
905 */
906 Memory = (PVOID)BugCheckParameter1;
907
908 /* Find to which driver it belongs */
909 DriverBase = KiPcToFileHeader(Memory,
910 &LdrEntry,
911 TRUE,
912 &IsSystem);
913 if (DriverBase)
914 {
915 /* Get the driver name and update the bug code */
916 KiBugCheckDriver = &LdrEntry->BaseDllName;
917 KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
918 }
919 else
920 {
921 /* Find the driver that unloaded at this address */
922 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
923
924 /* Check if the cause was an unloaded driver */
925 if (KiBugCheckDriver)
926 {
927 /* Update bug check code */
928 KiBugCheckData[0] =
929 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
930 }
931 }
932 }
933 else
934 {
935 /* Update the bug check code */
936 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
937 }
938
939 /* Clear EIP so we don't look it up later */
940 Eip = NULL;
941 break;
942
943 /* Hard error */
944 case FATAL_UNHANDLED_HARD_ERROR:
945
946 /* Copy bug check data from hard error */
947 HardErrorParameters = (PULONG_PTR)BugCheckParameter2;
948 KiBugCheckData[0] = BugCheckParameter1;
949 KiBugCheckData[1] = HardErrorParameters[0];
950 KiBugCheckData[2] = HardErrorParameters[1];
951 KiBugCheckData[3] = HardErrorParameters[2];
952 KiBugCheckData[4] = HardErrorParameters[3];
953
954 /* Remember that this is hard error and set the caption/message */
955 IsHardError = TRUE;
956 HardErrCaption = (PCHAR)BugCheckParameter3;
957 HardErrMessage = (PCHAR)BugCheckParameter4;
958 break;
959
960 /* Page fault */
961 case PAGE_FAULT_IN_NONPAGED_AREA:
962
963 /* Assume no driver */
964 DriverBase = NULL;
965
966 /* Check if we have a trap frame */
967 if (!TrapFrame)
968 {
969 /* We don't, use parameter 3 if possible */
970 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
971 }
972
973 /* Check if we have a frame now */
974 if (TrapFrame)
975 {
976 #ifdef _M_IX86
977 /* Get EIP */
978 Eip = (PVOID)TrapFrame->Eip;
979 KiBugCheckData[3] = (ULONG)Eip;
980 #elif defined(_M_PPC)
981 Eip = (PVOID)TrapFrame->Dr0; /* srr0 */
982 KiBugCheckData[3] = (ULONG)Eip;
983 #endif
984
985 /* Find out if was in the kernel or drivers */
986 DriverBase = KiPcToFileHeader(Eip,
987 &LdrEntry,
988 FALSE,
989 &IsSystem);
990 }
991
992 /*
993 * Now we should check if this happened in:
994 * 1) Special Pool 2) Free Special Pool 3) Session Pool
995 * and update the bugcheck code appropriately.
996 */
997
998 /* Check if we didn't have a driver base */
999 if (!DriverBase)
1000 {
1001 /* Find the driver that unloaded at this address */
1002 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
1003
1004 /* Check if the cause was an unloaded driver */
1005 if (KiBugCheckDriver)
1006 {
1007 KiBugCheckData[0] =
1008 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
1009 }
1010 }
1011 break;
1012
1013 /* Check if the driver forgot to unlock pages */
1014 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
1015
1016 /* EIP is in parameter 1 */
1017 Eip = (PVOID)BugCheckParameter1;
1018 break;
1019
1020 /* Check if the driver consumed too many PTEs */
1021 case DRIVER_USED_EXCESSIVE_PTES:
1022
1023 /* Loader entry is in parameter 1 */
1024 LdrEntry = (PVOID)BugCheckParameter1;
1025 KiBugCheckDriver = &LdrEntry->BaseDllName;
1026 break;
1027
1028 /* Check if the driver has a stuck thread */
1029 case THREAD_STUCK_IN_DEVICE_DRIVER:
1030
1031 /* The name is in Parameter 3 */
1032 KiBugCheckDriver = (PVOID)BugCheckParameter3;
1033 break;
1034
1035 /* Anything else */
1036 default:
1037 break;
1038 }
1039
1040 /* Do we have a driver name? */
1041 if (KiBugCheckDriver)
1042 {
1043 /* Convert it to ANSI */
1044 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
1045 }
1046 else
1047 {
1048 /* Do we have an EIP? */
1049 if (Eip)
1050 {
1051 /* Dump image name */
1052 KiDumpParameterImages(AnsiName,
1053 (PULONG_PTR)&Eip,
1054 1,
1055 KeBugCheckUnicodeToAnsi);
1056 }
1057 }
1058
1059 /* Check if we need to save the context for KD */
1060 #ifdef _WINKD_
1061 if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG)&Context;
1062 #endif
1063
1064 /* Check if a debugger is connected */
1065 if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
1066 {
1067 /* Crash on the debugger console */
1068 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
1069 " (0x%p,0x%p,0x%p,0x%p)\n\n",
1070 KiBugCheckData[0],
1071 KiBugCheckData[1],
1072 KiBugCheckData[2],
1073 KiBugCheckData[3],
1074 KiBugCheckData[4]);
1075
1076 /* Check if the debugger isn't currently connected */
1077 if (!KdDebuggerNotPresent)
1078 {
1079 /* Check if we have a driver to blame */
1080 if (KiBugCheckDriver)
1081 {
1082 /* Dump it */
1083 DbgPrint("Driver at fault: %s.\n", AnsiName);
1084 }
1085
1086 /* Check if this was a hard error */
1087 if (IsHardError)
1088 {
1089 /* Print caption and message */
1090 if (HardErrCaption) DbgPrint(HardErrCaption);
1091 if (HardErrMessage) DbgPrint(HardErrMessage);
1092 }
1093
1094 /* Break in the debugger */
1095 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
1096 }
1097 else
1098 {
1099 /*
1100 * ROS HACK.
1101 * Ok, so debugging is enabled, but KDBG isn't there.
1102 * We'll manually dump the stack for the user.
1103 */
1104 KeRosDumpStackFrames(NULL, 0);
1105
1106 /* ROS HACK 2: Generate something useful for Bugzilla */
1107 KeRosDumpTriageForBugZillaReport();
1108 }
1109 }
1110
1111 /* Raise IRQL to HIGH_LEVEL */
1112 _disable();
1113 KfRaiseIrql(HIGH_LEVEL);
1114
1115 /* Avoid recursion */
1116 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1117 {
1118 #ifdef CONFIG_SMP
1119 /* Set CPU that is bug checking now */
1120 KeBugCheckOwner = Prcb->Number;
1121
1122 /* Freeze the other CPUs */
1123 for (i = 0; i < KeNumberProcessors; i++)
1124 {
1125 if (i != (LONG)KeGetCurrentProcessorNumber())
1126 {
1127 /* Send the IPI and give them one second to catch up */
1128 KiIpiSendRequest(1 << i, IPI_FREEZE);
1129 KeStallExecutionProcessor(1000000);
1130 }
1131 }
1132 #endif
1133
1134 /* Display the BSOD */
1135 KfLowerIrql(APC_LEVEL); // This is a nastier hack than any ever before
1136 KiDisplayBlueScreen(MessageId,
1137 IsHardError,
1138 HardErrCaption,
1139 HardErrMessage,
1140 AnsiName);
1141 KfRaiseIrql(HIGH_LEVEL);
1142
1143 /* Check if the debugger is disabled but we can enable it */
1144 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1145 {
1146 /* Enable it */
1147 #ifdef _WINKD_
1148 KdEnableDebuggerWithLock(FALSE);
1149 #endif
1150 }
1151 else
1152 {
1153 /* Otherwise, print the last line */
1154 InbvDisplayString("\r\n");
1155 }
1156
1157 /* Save the context */
1158 Prcb->ProcessorState.ContextFrame = Context;
1159
1160 /* FIXME: Support Triage Dump */
1161
1162 /* Write the crash dump */
1163 MmDumpToPagingFile(KiBugCheckData[4],
1164 KiBugCheckData[0],
1165 KiBugCheckData[1],
1166 KiBugCheckData[2],
1167 KiBugCheckData[3],
1168 TrapFrame);
1169 }
1170 else
1171 {
1172 /* Increase recursion count */
1173 KeBugCheckOwnerRecursionCount++;
1174 if (KeBugCheckOwnerRecursionCount == 2)
1175 {
1176 /* Break in the debugger */
1177 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1178 }
1179 else if (KeBugCheckOwnerRecursionCount > 2)
1180 {
1181 /* Halt the CPU */
1182 for (;;) KeArchHaltProcessor();
1183 }
1184 }
1185
1186 /* Call the Callbacks */
1187 KiDoBugCheckCallbacks();
1188
1189 /* FIXME: Call Watchdog if enabled */
1190
1191 /* Check if we have to reboot */
1192 if (Reboot)
1193 {
1194 /* Unload symbols */
1195 DbgUnLoadImageSymbols(NULL, NtCurrentProcess(), 0);
1196 HalReturnToFirmware(HalRebootRoutine);
1197 }
1198
1199 /* Attempt to break in the debugger (otherwise halt CPU) */
1200 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1201 }
1202
1203 /* PUBLIC FUNCTIONS **********************************************************/
1204
1205 /*
1206 * @implemented
1207 */
1208 BOOLEAN
1209 NTAPI
1210 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
1211 {
1212 KIRQL OldIrql;
1213 BOOLEAN Status = FALSE;
1214
1215 /* Raise IRQL to High */
1216 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1217
1218 /* Check the Current State */
1219 if (CallbackRecord->State == BufferInserted)
1220 {
1221 /* Reset state and remove from list */
1222 CallbackRecord->State = BufferEmpty;
1223 RemoveEntryList(&CallbackRecord->Entry);
1224 Status = TRUE;
1225 }
1226
1227 /* Lower IRQL and return */
1228 KeLowerIrql(OldIrql);
1229 return Status;
1230 }
1231
1232 /*
1233 * @implemented
1234 */
1235 BOOLEAN
1236 NTAPI
1237 KeDeregisterBugCheckReasonCallback(
1238 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
1239 {
1240 KIRQL OldIrql;
1241 BOOLEAN Status = FALSE;
1242
1243 /* Raise IRQL to High */
1244 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1245
1246 /* Check the Current State */
1247 if (CallbackRecord->State == BufferInserted)
1248 {
1249 /* Reset state and remove from list */
1250 CallbackRecord->State = BufferEmpty;
1251 RemoveEntryList(&CallbackRecord->Entry);
1252 Status = TRUE;
1253 }
1254
1255 /* Lower IRQL and return */
1256 KeLowerIrql(OldIrql);
1257 return Status;
1258 }
1259
1260 /*
1261 * @implemented
1262 */
1263 BOOLEAN
1264 NTAPI
1265 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
1266 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
1267 IN PVOID Buffer,
1268 IN ULONG Length,
1269 IN PUCHAR Component)
1270 {
1271 KIRQL OldIrql;
1272 BOOLEAN Status = FALSE;
1273
1274 /* Raise IRQL to High */
1275 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1276
1277 /* Check the Current State first so we don't double-register */
1278 if (CallbackRecord->State == BufferEmpty)
1279 {
1280 /* Set the Callback Settings and insert into the list */
1281 CallbackRecord->Length = Length;
1282 CallbackRecord->Buffer = Buffer;
1283 CallbackRecord->Component = Component;
1284 CallbackRecord->CallbackRoutine = CallbackRoutine;
1285 CallbackRecord->State = BufferInserted;
1286 InsertTailList(&KeBugcheckCallbackListHead, &CallbackRecord->Entry);
1287 Status = TRUE;
1288 }
1289
1290 /* Lower IRQL and return */
1291 KeLowerIrql(OldIrql);
1292 return Status;
1293 }
1294
1295 /*
1296 * @implemented
1297 */
1298 BOOLEAN
1299 NTAPI
1300 KeRegisterBugCheckReasonCallback(
1301 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
1302 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
1303 IN KBUGCHECK_CALLBACK_REASON Reason,
1304 IN PUCHAR Component)
1305 {
1306 KIRQL OldIrql;
1307 BOOLEAN Status = FALSE;
1308
1309 /* Raise IRQL to High */
1310 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1311
1312 /* Check the Current State first so we don't double-register */
1313 if (CallbackRecord->State == BufferEmpty)
1314 {
1315 /* Set the Callback Settings and insert into the list */
1316 CallbackRecord->Component = Component;
1317 CallbackRecord->CallbackRoutine = CallbackRoutine;
1318 CallbackRecord->State = BufferInserted;
1319 CallbackRecord->Reason = Reason;
1320 InsertTailList(&KeBugcheckReasonCallbackListHead,
1321 &CallbackRecord->Entry);
1322 Status = TRUE;
1323 }
1324
1325 /* Lower IRQL and return */
1326 KeLowerIrql(OldIrql);
1327 return Status;
1328 }
1329
1330 /*
1331 * @implemented
1332 */
1333 VOID
1334 NTAPI
1335 KeBugCheckEx(IN ULONG BugCheckCode,
1336 IN ULONG_PTR BugCheckParameter1,
1337 IN ULONG_PTR BugCheckParameter2,
1338 IN ULONG_PTR BugCheckParameter3,
1339 IN ULONG_PTR BugCheckParameter4)
1340 {
1341 /* Call the internal API */
1342 KeBugCheckWithTf(BugCheckCode,
1343 BugCheckParameter1,
1344 BugCheckParameter2,
1345 BugCheckParameter3,
1346 BugCheckParameter4,
1347 NULL);
1348 }
1349
1350 /*
1351 * @implemented
1352 */
1353 VOID
1354 NTAPI
1355 KeBugCheck(ULONG BugCheckCode)
1356 {
1357 /* Call the internal API */
1358 KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
1359 }
1360
1361 /*
1362 * @implemented
1363 */
1364 VOID
1365 NTAPI
1366 KeEnterKernelDebugger(VOID)
1367 {
1368 /* Disable interrupts */
1369 KiHardwareTrigger = 1;
1370 _disable();
1371
1372 /* Check the bugcheck count */
1373 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1374 {
1375 /* There was only one, is the debugger disabled? */
1376 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1377 {
1378 /* Enable the debugger */
1379 KdInitSystem(0, NULL);
1380 }
1381 }
1382
1383 /* Bugcheck */
1384 KiBugCheckDebugBreak(DBG_STATUS_FATAL);
1385 }
1386
1387 /* EOF */