2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/i386/exp.c
5 * PURPOSE: Exception Support Code
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@cwcom.net)
9 * Skywing (skywing@valhallalegends.com)
14 * - Clean up file (remove all stack functions and use RtlWalkFrameChain/RtlCaptureStackBacktrace)
15 * - Sanitize some context fields.
16 * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
17 * - Forward exceptions to user-mode debugger.
20 /* INCLUDES *****************************************************************/
25 #include <internal/debug.h>
27 #if defined (ALLOC_PRAGMA)
28 #pragma alloc_text(INIT, KeInitExceptions)
34 IN PKTRAP_FRAME TrapFrame
37 extern KIDTENTRY KiIdt
[];
39 /* GLOBALS *****************************************************************/
41 #define FLAG_IF (1<<9)
44 #define STR(x) _STR(x)
47 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
50 extern ULONG init_stack
;
51 extern ULONG init_stack_top
;
53 extern BOOLEAN Ke386NoExecute
;
55 static char *ExceptionTypeStrings
[] =
62 "BOUND range exceeded",
64 "No Math Coprocessor",
68 "Segment Not Present",
69 "Stack Segment Fault",
79 NTSTATUS ExceptionToNtStatus
[] =
81 STATUS_INTEGER_DIVIDE_BY_ZERO
,
83 STATUS_ACCESS_VIOLATION
,
85 STATUS_INTEGER_OVERFLOW
,
86 STATUS_ARRAY_BOUNDS_EXCEEDED
,
87 STATUS_ILLEGAL_INSTRUCTION
,
88 STATUS_FLOAT_INVALID_OPERATION
,
89 STATUS_ACCESS_VIOLATION
,
90 STATUS_ACCESS_VIOLATION
,
91 STATUS_ACCESS_VIOLATION
,
92 STATUS_ACCESS_VIOLATION
,
93 STATUS_STACK_OVERFLOW
,
94 STATUS_ACCESS_VIOLATION
,
95 STATUS_ACCESS_VIOLATION
,
96 STATUS_ACCESS_VIOLATION
, /* RESERVED */
97 STATUS_FLOAT_INVALID_OPERATION
, /* Should not be used, the FPU can give more specific info */
98 STATUS_DATATYPE_MISALIGNMENT
,
99 STATUS_ACCESS_VIOLATION
,
100 STATUS_FLOAT_MULTIPLE_TRAPS
,
103 /* FUNCTIONS ****************************************************************/
106 KiRosPrintAddress(PVOID address
)
108 PLIST_ENTRY current_entry
;
109 PLDR_DATA_TABLE_ENTRY current
;
110 extern LIST_ENTRY ModuleListHead
;
111 ULONG_PTR RelativeAddress
;
116 current_entry
= ModuleListHead
.Flink
;
118 while (current_entry
!= &ModuleListHead
)
121 CONTAINING_RECORD(current_entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderModuleList
);
123 if (address
>= (PVOID
)current
->DllBase
&&
124 address
< (PVOID
)((ULONG_PTR
)current
->DllBase
+ current
->SizeOfImage
))
126 RelativeAddress
= (ULONG_PTR
) address
- (ULONG_PTR
) current
->DllBase
;
127 DbgPrint("<%wZ: %x>", ¤t
->FullDllName
, RelativeAddress
);
130 current_entry
= current_entry
->Flink
;
133 address
= (PVOID
)((ULONG_PTR
)address
& ~(ULONG_PTR
)MmSystemRangeStart
);
140 KiKernelTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
144 Er
.ExceptionFlags
= 0;
145 Er
.ExceptionRecord
= NULL
;
146 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
148 if (ExceptionNr
== 14)
150 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
151 Er
.NumberParameters
= 2;
152 Er
.ExceptionInformation
[0] = Tf
->ErrCode
& 0x1;
153 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
157 if (ExceptionNr
< ARRAY_SIZE(ExceptionToNtStatus
))
159 Er
.ExceptionCode
= ExceptionToNtStatus
[ExceptionNr
];
163 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
165 Er
.NumberParameters
= 0;
168 /* FIXME: Which exceptions are noncontinuable? */
169 Er
.ExceptionFlags
= 0;
171 KiDispatchException(&Er
, NULL
, Tf
, KernelMode
, TRUE
);
177 KiDoubleFaultHandler(VOID
)
184 ULONG ExceptionNr
= 8;
190 static PVOID StackTrace
[MM_STACK_SIZE
/ sizeof(PVOID
)];
191 static ULONG StackRepeatCount
[MM_STACK_SIZE
/ sizeof(PVOID
)];
192 static ULONG StackRepeatLength
[MM_STACK_SIZE
/ sizeof(PVOID
)];
197 OldTss
= KeGetCurrentKPCR()->TSS
;
202 if (PsGetCurrentThread() != NULL
&&
203 PsGetCurrentThread()->ThreadsProcess
!= NULL
)
206 PsGetCurrentThread()->ThreadsProcess
->Pcb
.DirectoryTableBase
.QuadPart
;
214 * Check for stack underflow
216 if (PsGetCurrentThread() != NULL
&&
217 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
219 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
220 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
225 * Print out the CPU registers
227 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
229 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
234 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
236 DbgPrint("CS:EIP %x:%x ", OldTss
->Cs
, OldTss
->Eip
);
237 KeRosPrintAddress((PVOID
)OldTss
->Eip
);
239 DbgPrint("cr2 %x cr3 %x ", cr2
, OldCr3
);
240 DbgPrint("Proc: %x ",PsGetCurrentProcess());
241 if (PsGetCurrentProcess() != NULL
)
243 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
244 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
246 if (PsGetCurrentThread() != NULL
)
248 DbgPrint("Thrd: %x Tid: %x",
249 PsGetCurrentThread(),
250 PsGetCurrentThread()->Cid
.UniqueThread
);
253 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss
->Ds
, OldTss
->Es
,
254 OldTss
->Fs
, OldTss
->Gs
);
255 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss
->Eax
, OldTss
->Ebx
,
257 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss
->Edx
,
258 OldTss
->Ebp
, OldTss
->Esi
, Esp0
);
259 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss
->Edi
, OldTss
->Eflags
);
260 if (OldTss
->Cs
== KGDT_R0_CODE
)
262 DbgPrint("kESP %.8x ", Esp0
);
263 if (PsGetCurrentThread() != NULL
)
265 DbgPrint("kernel stack base %x\n",
266 PsGetCurrentThread()->Tcb
.StackLimit
);
272 DbgPrint("User ESP %.8x\n", OldTss
->Esp
);
274 if ((OldTss
->Cs
& 0xffff) == KGDT_R0_CODE
)
276 if (PsGetCurrentThread() != NULL
)
278 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
279 StackBase
= (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
;
283 StackLimit
= (ULONG
)init_stack_top
;
284 StackBase
= (ULONG
)init_stack
;
288 Change to an #if 0 to reduce the amount of information printed on
289 a recursive stack trace.
292 DbgPrint("Frames: ");
293 Frame
= (PULONG
)OldTss
->Ebp
;
294 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
296 KeRosPrintAddress((PVOID
)Frame
[1]);
297 Frame
= (PULONG
)Frame
[0];
301 DbgPrint("Frames: ");
303 Frame
= (PULONG
)OldTss
->Ebp
;
304 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
306 StackTrace
[i
] = (PVOID
)Frame
[1];
307 Frame
= (PULONG
)Frame
[0];
313 while (i
< TraceLength
)
315 StackRepeatCount
[i
] = 0;
318 while ((j
- i
) <= (TraceLength
- j
) && FoundRepeat
== FALSE
)
320 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
321 (j
- i
) * sizeof(PVOID
)) == 0)
323 StackRepeatCount
[i
] = 2;
324 StackRepeatLength
[i
] = j
- i
;
332 if (FoundRepeat
== FALSE
)
337 j
= j
+ StackRepeatLength
[i
];
338 while ((TraceLength
- j
) >= StackRepeatLength
[i
] &&
341 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
342 StackRepeatLength
[i
] * sizeof(PVOID
)) == 0)
344 StackRepeatCount
[i
]++;
345 j
= j
+ StackRepeatLength
[i
];
356 while (i
< TraceLength
)
358 if (StackRepeatCount
[i
] == 0)
360 KeRosPrintAddress(StackTrace
[i
]);
366 if (StackRepeatLength
[i
] == 0)
370 for (j
= 0; j
< StackRepeatLength
[i
]; j
++)
372 KeRosPrintAddress(StackTrace
[i
+ j
]);
374 DbgPrint("}*%d", StackRepeatCount
[i
]);
375 i
= i
+ StackRepeatLength
[i
] * StackRepeatCount
[i
];
387 KiDumpTrapFrame(PKTRAP_FRAME Tf
, ULONG Parameter1
, ULONG Parameter2
)
392 ULONG ExceptionNr
= (ULONG
)Tf
->DbgArgMark
;
393 ULONG cr2
= (ULONG
)Tf
->DbgArgPointer
;
398 * Print out the CPU registers
400 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
402 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
403 ExceptionNr
, Tf
->ErrCode
&0xffff);
407 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrCode
&0xffff);
409 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
410 Tf
->SegCs
&0xffff, Tf
->Eip
);
411 KeRosPrintAddress((PVOID
)Tf
->Eip
);
413 Ke386GetPageTableDirectory(cr3_
);
414 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3_
);
415 DbgPrint("Proc: %x ",PsGetCurrentProcess());
416 if (PsGetCurrentProcess() != NULL
)
418 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
419 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
421 if (PsGetCurrentThread() != NULL
)
423 DbgPrint("Thrd: %x Tid: %x",
424 PsGetCurrentThread(),
425 PsGetCurrentThread()->Cid
.UniqueThread
);
428 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->SegDs
&0xffff, Tf
->SegEs
&0xffff,
429 Tf
->SegFs
&0xffff, Tf
->SegGs
&0xfff);
430 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
431 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf
->Edx
,
432 Tf
->Ebp
, Tf
->Esi
, Esp0
);
433 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->EFlags
);
434 if ((Tf
->SegCs
&0xffff) == KGDT_R0_CODE
)
436 DbgPrint("kESP %.8x ", Esp0
);
437 if (PsGetCurrentThread() != NULL
)
439 DbgPrint("kernel stack base %x\n",
440 PsGetCurrentThread()->Tcb
.StackLimit
);
445 if (PsGetCurrentThread() != NULL
)
447 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
451 StackLimit
= (ULONG
)init_stack_top
;
455 * Dump the stack frames
457 KeDumpStackFrames((PULONG
)Tf
->Ebp
);
461 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
463 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
464 * message and halt the computer
466 * Complete CPU context
473 ASSERT(ExceptionNr
!= 14);
475 /* Use the address of the trap frame as approximation to the ring0 esp */
476 Esp0
= (ULONG
)&Tf
->Eip
;
480 Tf
->DbgArgPointer
= cr2
;
483 * If this was a V86 mode exception then handle it specially
485 if (Tf
->EFlags
& (1 << 17))
487 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf
->EFlags
, Tf
->Eip
, ExceptionNr
);
488 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
492 * Check for stack underflow, this may be obsolete
494 if (PsGetCurrentThread() != NULL
&&
495 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
497 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
498 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
, Tf
->Eip
);
502 if (ExceptionNr
== 15)
506 * This exception should never occur. The P6 has a bug, which does sometimes deliver
507 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
508 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
509 * sources. Linux does ignore this exception.
513 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
518 * Check for a breakpoint that was only for the attention of the debugger.
520 if (ExceptionNr
== 3 && Tf
->Eip
== ((ULONG
)DbgBreakPointNoBugCheck
) + 1)
523 EIP is already adjusted by the processor to point to the instruction
524 after the breakpoint.
530 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
532 if (ExceptionNr
== 7 || ExceptionNr
== 16 || ExceptionNr
== 19)
534 Status
= KiHandleFpuFault(Tf
, ExceptionNr
);
535 if (NT_SUCCESS(Status
))
542 * Handle user exceptions differently
544 if ((Tf
->SegCs
& 0xFFFF) == (KGDT_R3_CODE
| RPL_MASK
))
546 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
550 return(KiKernelTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
556 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
558 /* Check if this is user-mode or V86 */
559 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& X86_EFLAGS_VM
))
561 /* Return it directly */
562 return TrapFrame
->HardwareEsp
;
567 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
569 /* Return edited value */
570 return TrapFrame
->TempEsp
;
574 /* Virgin frame, calculate */
575 return (ULONG
)&TrapFrame
->HardwareEsp
;
582 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
585 ULONG Previous
= KiEspFromTrapFrame(TrapFrame
);
587 /* Check if this is user-mode or V86 */
588 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& X86_EFLAGS_VM
))
590 /* Write it directly */
591 TrapFrame
->HardwareEsp
= Esp
;
595 /* Don't allow ESP to be lowered, this is illegal */
598 KeBugCheck(SET_OF_INVALID_CONTEXT
);
601 /* Create an edit frame, check if it was alrady */
602 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
604 /* Update the value */
605 TrapFrame
->TempEsp
= Esp
;
609 /* Check if ESP changed */
613 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
614 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
617 TrapFrame
->TempEsp
= Esp
;
625 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
627 /* If this was V86 Mode */
628 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
631 return TrapFrame
->HardwareSegSs
;
633 else if (TrapFrame
->SegCs
& MODE_MASK
)
635 /* Usermode, return the User SS */
636 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
647 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
650 /* Remove the high-bits */
653 /* If this was V86 Mode */
654 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
657 TrapFrame
->HardwareSegSs
= Ss
;
659 else if (TrapFrame
->SegCs
& MODE_MASK
)
661 /* Usermode, save the User SS */
662 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
668 KeContextToTrapFrame(IN PCONTEXT Context
,
669 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
670 IN OUT PKTRAP_FRAME TrapFrame
,
671 IN ULONG ContextFlags
,
672 IN KPROCESSOR_MODE PreviousMode
)
674 PFX_SAVE_AREA FxSaveArea
;
675 //ULONG i; Future Use
676 BOOLEAN V86Switch
= FALSE
;
678 /* Start with the basic Registers */
679 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
681 /* Check if we went through a V86 switch */
682 if ((Context
->EFlags
& X86_EFLAGS_VM
) !=
683 (TrapFrame
->EFlags
& X86_EFLAGS_VM
))
685 /* We did, remember this for later */
689 /* Copy EFLAGS. FIXME: Needs to be sanitized */
690 TrapFrame
->EFlags
= Context
->EFlags
;
692 /* Copy EBP and EIP */
693 TrapFrame
->Ebp
= Context
->Ebp
;
694 TrapFrame
->Eip
= Context
->Eip
;
696 /* Check if we were in V86 Mode */
697 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
699 /* Simply copy the CS value */
700 TrapFrame
->SegCs
= Context
->SegCs
;
704 /* We weren't in V86, so sanitize the CS (FIXME!) */
705 TrapFrame
->SegCs
= Context
->SegCs
;
707 /* Don't let it under 8, that's invalid */
708 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
710 /* Force it to User CS */
711 TrapFrame
->SegCs
= (KGDT_R3_CODE
| RPL_MASK
);
715 /* Handle SS Specially for validation */
716 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
718 /* Write ESP back; take into account Edited Trap Frames */
719 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
721 /* Handle our V86 Bias if we went through a switch */
722 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
725 /* Process the Integer Registers */
726 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
728 TrapFrame
->Eax
= Context
->Eax
;
729 TrapFrame
->Ebx
= Context
->Ebx
;
730 TrapFrame
->Ecx
= Context
->Ecx
;
731 TrapFrame
->Edx
= Context
->Edx
;
732 TrapFrame
->Esi
= Context
->Esi
;
733 TrapFrame
->Edi
= Context
->Edi
;
736 /* Process the Context Segments */
737 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
739 /* Check if we were in V86 Mode */
740 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
742 /* Copy the V86 Segments directlry */
743 TrapFrame
->V86Ds
= Context
->SegDs
;
744 TrapFrame
->V86Es
= Context
->SegEs
;
745 TrapFrame
->V86Fs
= Context
->SegFs
;
746 TrapFrame
->V86Gs
= Context
->SegGs
;
748 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
750 /* For kernel mode, write the standard values */
751 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
752 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
753 TrapFrame
->SegFs
= Context
->SegFs
;
754 TrapFrame
->SegGs
= 0;
758 /* For user mode, return the values directlry */
759 TrapFrame
->SegDs
= Context
->SegDs
;
760 TrapFrame
->SegEs
= Context
->SegEs
;
761 TrapFrame
->SegFs
= Context
->SegFs
;
763 /* Handle GS specially */
764 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
766 /* Don't use it, if user */
767 TrapFrame
->SegGs
= 0;
771 /* Copy it if kernel */
772 TrapFrame
->SegGs
= Context
->SegGs
;
777 /* Handle the extended registers */
778 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
779 CONTEXT_EXTENDED_REGISTERS
) &&
780 ((TrapFrame
->SegCs
& MODE_MASK
) == UserMode
))
782 /* Get the FX Area */
783 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
785 /* Check if NPX is present */
786 if (KeI386NpxPresent
)
792 /* Handle the floating point state */
793 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
794 CONTEXT_FLOATING_POINT
) &&
795 ((TrapFrame
->SegCs
& MODE_MASK
) == UserMode
))
797 /* Get the FX Area */
798 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
800 /* Check if NPX is present */
801 if (KeI386NpxPresent
)
811 /* Handle the Debug Registers */
812 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
814 /* FIXME: All these should be sanitized */
815 TrapFrame
->Dr0
= Context
->Dr0
;
816 TrapFrame
->Dr1
= Context
->Dr1
;
817 TrapFrame
->Dr2
= Context
->Dr2
;
818 TrapFrame
->Dr3
= Context
->Dr3
;
819 TrapFrame
->Dr6
= Context
->Dr6
;
820 TrapFrame
->Dr7
= Context
->Dr7
;
822 /* Check if usermode */
823 if (PreviousMode
!= KernelMode
)
825 /* Set the Debug Flag */
826 KeGetCurrentThread()->DispatcherHeader
.DebugActive
=
827 (Context
->Dr7
& DR7_ACTIVE
);
831 /* Handle FPU and Extended Registers */
832 KiContextToFxSaveArea((PFX_SAVE_AREA
)(TrapFrame
+ 1), Context
);
837 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
838 IN PKEXCEPTION_FRAME ExceptionFrame
,
839 IN OUT PCONTEXT Context
)
841 PFX_SAVE_AREA FxSaveArea
= NULL
;
843 /* Start with the Control flags */
844 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
846 /* EBP, EIP and EFLAGS */
847 Context
->Ebp
= TrapFrame
->Ebp
;
848 Context
->Eip
= TrapFrame
->Eip
;
849 Context
->EFlags
= TrapFrame
->EFlags
;
851 /* Return the correct CS */
852 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
853 !(TrapFrame
->EFlags
& X86_EFLAGS_VM
))
855 /* Get it from the Temp location */
856 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
860 /* Return it directly */
861 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
864 /* Get the Ss and ESP */
865 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
866 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
869 /* Handle the Segments */
870 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
872 /* Do V86 Mode first */
873 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
875 /* Return from the V86 location */
876 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
877 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
878 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
879 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
883 /* Check if this was a Kernel Trap */
884 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
886 /* Set valid selectors */
887 TrapFrame
->SegGs
= 0;
888 TrapFrame
->SegFs
= KGDT_R0_PCR
;
889 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
890 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
893 /* Return the segments */
894 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
895 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
896 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
897 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
901 /* Handle the simple registers */
902 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
904 /* Return them directly */
905 Context
->Eax
= TrapFrame
->Eax
;
906 Context
->Ebx
= TrapFrame
->Ebx
;
907 Context
->Ecx
= TrapFrame
->Ecx
;
908 Context
->Edx
= TrapFrame
->Edx
;
909 Context
->Esi
= TrapFrame
->Esi
;
910 Context
->Edi
= TrapFrame
->Edi
;
913 /* Handle extended registers */
914 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
915 CONTEXT_EXTENDED_REGISTERS
) &&
916 ((TrapFrame
->SegCs
& MODE_MASK
) == UserMode
))
918 /* Get the FX Save Area */
919 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
921 /* Make sure NPX is present */
922 if (KeI386NpxPresent
)
928 FxSaveArea
= KiGetFpuState(KeGetCurrentThread());
929 if (FxSaveArea
!= NULL
)
931 memcpy(Context
->ExtendedRegisters
, &FxSaveArea
->U
.FxArea
,
932 min(sizeof (Context
->ExtendedRegisters
), sizeof (FxSaveArea
->U
.FxArea
)) );
936 Context
->ContextFlags
&= (~CONTEXT_EXTENDED_REGISTERS
) | CONTEXT_i386
;
940 /* Handle Floating Point */
941 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
942 CONTEXT_FLOATING_POINT
) &&
943 ((TrapFrame
->SegCs
& MODE_MASK
) == UserMode
))
945 /* Get the FX Save Area */
946 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
948 /* Make sure we have an NPX */
949 if (KeI386NpxPresent
)
959 FxSaveArea
= KiGetFpuState(KeGetCurrentThread());
960 if (FxSaveArea
!= NULL
)
962 KiFxSaveAreaToFloatingSaveArea(&Context
->FloatSave
, FxSaveArea
);
966 Context
->ContextFlags
&= (~CONTEXT_FLOATING_POINT
) | CONTEXT_i386
;
970 /* Handle debug registers */
971 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
972 CONTEXT_DEBUG_REGISTERS
)
974 /* Copy the debug registers */
975 Context
->Dr0
= TrapFrame
->Dr0
;
976 Context
->Dr1
= TrapFrame
->Dr1
;
977 Context
->Dr2
= TrapFrame
->Dr2
;
978 Context
->Dr3
= TrapFrame
->Dr3
;
979 Context
->Dr6
= TrapFrame
->Dr6
;
981 /* For user-mode, only set DR7 if a debugger is active */
982 if (((TrapFrame
->SegCs
& MODE_MASK
) ||
983 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)) &&
984 (KeGetCurrentThread()->DispatcherHeader
.DebugActive
))
987 Context
->Dr7
= TrapFrame
->Dr7
;
999 KeDumpStackFrames(PULONG Frame
)
1001 PULONG StackBase
, StackEnd
;
1002 MEMORY_BASIC_INFORMATION mbi
;
1003 ULONG ResultLength
= sizeof(mbi
);
1006 DbgPrint("Frames:\n");
1009 Status
= MiQueryVirtualMemory (
1012 MemoryBasicInformation
,
1016 if ( !NT_SUCCESS(Status
) )
1018 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1023 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1025 while ( Frame
>= StackBase
&& Frame
< StackEnd
)
1027 ULONG Addr
= Frame
[1];
1028 if (!KeRosPrintAddress((PVOID
)Addr
))
1029 DbgPrint("<%X>", Addr
);
1030 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
1033 Frame
= (PULONG
)Frame
[0];
1045 KeRosDumpStackFrames ( PULONG Frame
, ULONG FrameCount
)
1048 PULONG StackBase
, StackEnd
;
1049 MEMORY_BASIC_INFORMATION mbi
;
1050 ULONG ResultLength
= sizeof(mbi
);
1053 DbgPrint("Frames: ");
1058 #if defined __GNUC__
1059 __asm__("mov %%ebp, %0" : "=r" (Frame
) : );
1060 #elif defined(_MSC_VER)
1061 __asm mov
[Frame
], ebp
1063 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
1066 Status
= MiQueryVirtualMemory (
1069 MemoryBasicInformation
,
1073 if ( !NT_SUCCESS(Status
) )
1075 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1080 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1082 while ( Frame
>= StackBase
&& Frame
< StackEnd
&& i
++ < FrameCount
)
1084 ULONG Addr
= Frame
[1];
1085 if (!KeRosPrintAddress((PVOID
)Addr
))
1086 DbgPrint("<%X>", Addr
);
1087 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
1090 Frame
= (PULONG
)Frame
[0];
1102 KeRosGetStackFrames ( PULONG Frames
, ULONG FrameCount
)
1105 PULONG StackBase
, StackEnd
, Frame
;
1106 MEMORY_BASIC_INFORMATION mbi
;
1107 ULONG ResultLength
= sizeof(mbi
);
1112 #if defined __GNUC__
1113 __asm__("mov %%ebp, %0" : "=r" (Frame
) : );
1114 #elif defined(_MSC_VER)
1115 __asm mov
[Frame
], ebp
1118 Status
= MiQueryVirtualMemory (
1121 MemoryBasicInformation
,
1125 if ( !NT_SUCCESS(Status
) )
1127 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1132 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1134 while ( Count
< FrameCount
&& Frame
>= StackBase
&& Frame
< StackEnd
)
1136 Frames
[Count
++] = Frame
[1];
1138 Frame
= (PULONG
)Frame
[0];
1151 KeInitExceptions(VOID
)
1154 USHORT FlippedSelector
;
1157 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
1159 /* Save the current Selector */
1160 FlippedSelector
= KiIdt
[i
].Selector
;
1162 /* Flip Selector and Extended Offset */
1163 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
1164 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
1170 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord
,
1171 PKEXCEPTION_FRAME ExceptionFrame
,
1172 PKTRAP_FRAME TrapFrame
,
1173 KPROCESSOR_MODE PreviousMode
,
1174 BOOLEAN FirstChance
)
1177 KD_CONTINUE_TYPE Action
;
1178 ULONG_PTR Stack
, NewStack
;
1180 BOOLEAN UserDispatch
= FALSE
;
1181 DPRINT("KiDispatchException() called\n");
1183 /* Increase number of Exception Dispatches */
1184 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
1186 /* Set the context flags */
1187 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
1189 /* Check if User Mode */
1190 if (PreviousMode
== UserMode
)
1192 /* Add the FPU Flag */
1193 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
1194 if (KeI386FxsrPresent
) Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
1198 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
1200 /* Handle kernel-mode first, it's simpler */
1201 if (PreviousMode
== KernelMode
)
1203 /* Check if this is a first-chance exception */
1204 if (FirstChance
== TRUE
)
1206 /* Break into the debugger for the first time */
1207 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1214 /* If the debugger said continue, then continue */
1215 if (Action
== kdContinue
) goto Handled
;
1217 /* If the Debugger couldn't handle it, dispatch the exception */
1218 if (RtlDispatchException(ExceptionRecord
, &Context
))
1220 /* It was handled by an exception handler, continue */
1225 /* This is a second-chance exception, only for the debugger */
1226 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1233 /* If the debugger said continue, then continue */
1234 if (Action
== kdContinue
) goto Handled
;
1236 /* Third strike; you're out */
1237 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1238 ExceptionRecord
->ExceptionCode
,
1239 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1240 ExceptionRecord
->ExceptionInformation
[0],
1241 ExceptionRecord
->ExceptionInformation
[1],
1246 /* User mode exception, was it first-chance? */
1249 /* Enter Debugger if available */
1250 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1257 /* Exit if we're continuing */
1258 if (Action
== kdContinue
) goto Handled
;
1260 /* FIXME: Forward exception to user mode debugger */
1262 /* Set up the user-stack */
1265 /* Align context size and get stack pointer */
1266 Size
= (sizeof(CONTEXT
) + 3) & ~3;
1267 Stack
= (Context
.Esp
& ~3) - Size
;
1268 DPRINT("Stack: %lx\n", Stack
);
1270 /* Probe stack and copy Context */
1271 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
1272 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
1274 /* Align exception record size and get stack pointer */
1275 Size
= (sizeof(EXCEPTION_RECORD
) -
1276 (EXCEPTION_MAXIMUM_PARAMETERS
- ExceptionRecord
->NumberParameters
) *
1277 sizeof(ULONG
) + 3) & ~3;
1278 NewStack
= Stack
- Size
;
1279 DPRINT("NewStack: %lx\n", NewStack
);
1281 /* Probe stack and copy exception record. Don't forget to add the two params */
1282 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
1283 Size
+ 2 * sizeof(ULONG_PTR
),
1285 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
1287 /* Now write the two params for the user-mode dispatcher */
1288 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
1289 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
1291 /* Set new Stack Pointer */
1292 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
1294 /* Set EIP to the User-mode Dispathcer */
1295 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1296 UserDispatch
= TRUE
;
1301 /* Do second-chance */
1306 /* If we dispatch to user, return now */
1307 if (UserDispatch
) return;
1309 /* FIXME: Forward the exception to the debugger for 2nd chance */
1311 /* 3rd strike, kill the thread */
1312 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1313 ZwTerminateThread(NtCurrentThread(), ExceptionRecord
->ExceptionCode
);
1314 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1315 ExceptionRecord
->ExceptionCode
,
1316 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1317 ExceptionRecord
->ExceptionInformation
[0],
1318 ExceptionRecord
->ExceptionInformation
[1],
1323 /* Convert the context back into Trap/Exception Frames */
1324 KeContextToTrapFrame(&Context
,
1327 Context
.ContextFlags
,
1337 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1340 PKTHREAD Thread
= KeGetCurrentThread();
1342 /* Make sure we can access the TEB */
1345 Thread
->Teb
->ExceptionCode
= ExceptionCode
;
1349 return(ExceptionCode
);
1353 /* Get the old EIP */
1354 OldEip
= Thread
->TrapFrame
->Eip
;
1356 /* Change it to the user-mode dispatcher */
1357 Thread
->TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1359 /* Return the old EIP */
1360 return((NTSTATUS
)OldEip
);