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)
31 #define SIZE_OF_FX_REGISTERS 32
36 IN PKTRAP_FRAME TrapFrame
42 IN FLOATING_SAVE_AREA
*SaveArea
45 extern KIDTENTRY KiIdt
[];
47 /* GLOBALS *****************************************************************/
49 #define FLAG_IF (1<<9)
52 #define STR(x) _STR(x)
55 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
58 extern ULONG init_stack
;
59 extern ULONG init_stack_top
;
61 extern BOOLEAN Ke386NoExecute
;
63 static char *ExceptionTypeStrings
[] =
70 "BOUND range exceeded",
72 "No Math Coprocessor",
76 "Segment Not Present",
77 "Stack Segment Fault",
87 NTSTATUS ExceptionToNtStatus
[] =
89 STATUS_INTEGER_DIVIDE_BY_ZERO
,
91 STATUS_ACCESS_VIOLATION
,
93 STATUS_INTEGER_OVERFLOW
,
94 STATUS_ARRAY_BOUNDS_EXCEEDED
,
95 STATUS_ILLEGAL_INSTRUCTION
,
96 STATUS_FLOAT_INVALID_OPERATION
,
97 STATUS_ACCESS_VIOLATION
,
98 STATUS_ACCESS_VIOLATION
,
99 STATUS_ACCESS_VIOLATION
,
100 STATUS_ACCESS_VIOLATION
,
101 STATUS_STACK_OVERFLOW
,
102 STATUS_ACCESS_VIOLATION
,
103 STATUS_ACCESS_VIOLATION
,
104 STATUS_ACCESS_VIOLATION
, /* RESERVED */
105 STATUS_FLOAT_INVALID_OPERATION
, /* Should not be used, the FPU can give more specific info */
106 STATUS_DATATYPE_MISALIGNMENT
,
107 STATUS_ACCESS_VIOLATION
,
108 STATUS_FLOAT_MULTIPLE_TRAPS
,
111 /* FUNCTIONS ****************************************************************/
114 KiRosPrintAddress(PVOID address
)
116 PLIST_ENTRY current_entry
;
117 PLDR_DATA_TABLE_ENTRY current
;
118 extern LIST_ENTRY ModuleListHead
;
119 ULONG_PTR RelativeAddress
;
124 current_entry
= ModuleListHead
.Flink
;
126 while (current_entry
!= &ModuleListHead
)
129 CONTAINING_RECORD(current_entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
131 if (address
>= (PVOID
)current
->DllBase
&&
132 address
< (PVOID
)((ULONG_PTR
)current
->DllBase
+ current
->SizeOfImage
))
134 RelativeAddress
= (ULONG_PTR
) address
- (ULONG_PTR
) current
->DllBase
;
135 DbgPrint("<%wZ: %x>", ¤t
->FullDllName
, RelativeAddress
);
138 current_entry
= current_entry
->Flink
;
141 address
= (PVOID
)((ULONG_PTR
)address
& ~(ULONG_PTR
)MmSystemRangeStart
);
148 KiKernelTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
152 Er
.ExceptionFlags
= 0;
153 Er
.ExceptionRecord
= NULL
;
154 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
156 if (ExceptionNr
== 14)
158 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
159 Er
.NumberParameters
= 2;
160 Er
.ExceptionInformation
[0] = Tf
->ErrCode
& 0x1;
161 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
165 if (ExceptionNr
< ARRAY_SIZE(ExceptionToNtStatus
))
167 Er
.ExceptionCode
= ExceptionToNtStatus
[ExceptionNr
];
171 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
173 Er
.NumberParameters
= 0;
176 /* FIXME: Which exceptions are noncontinuable? */
177 Er
.ExceptionFlags
= 0;
179 KiDispatchException(&Er
, NULL
, Tf
, KernelMode
, TRUE
);
185 KiDoubleFaultHandler(VOID
)
192 ULONG ExceptionNr
= 8;
198 static PVOID StackTrace
[MM_STACK_SIZE
/ sizeof(PVOID
)];
199 static ULONG StackRepeatCount
[MM_STACK_SIZE
/ sizeof(PVOID
)];
200 static ULONG StackRepeatLength
[MM_STACK_SIZE
/ sizeof(PVOID
)];
205 OldTss
= KeGetCurrentKPCR()->TSS
;
210 if (PsGetCurrentThread() != NULL
&&
211 PsGetCurrentThread()->ThreadsProcess
!= NULL
)
214 PsGetCurrentThread()->ThreadsProcess
->Pcb
.DirectoryTableBase
.QuadPart
;
222 * Check for stack underflow
224 if (PsGetCurrentThread() != NULL
&&
225 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
227 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
228 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
233 * Print out the CPU registers
235 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
237 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
242 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
244 DbgPrint("CS:EIP %x:%x ", OldTss
->Cs
, OldTss
->Eip
);
245 KeRosPrintAddress((PVOID
)OldTss
->Eip
);
247 DbgPrint("cr2 %x cr3 %x ", cr2
, OldCr3
);
248 DbgPrint("Proc: %x ",PsGetCurrentProcess());
249 if (PsGetCurrentProcess() != NULL
)
251 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
252 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
254 if (PsGetCurrentThread() != NULL
)
256 DbgPrint("Thrd: %x Tid: %x",
257 PsGetCurrentThread(),
258 PsGetCurrentThread()->Cid
.UniqueThread
);
261 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss
->Ds
, OldTss
->Es
,
262 OldTss
->Fs
, OldTss
->Gs
);
263 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss
->Eax
, OldTss
->Ebx
,
265 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss
->Edx
,
266 OldTss
->Ebp
, OldTss
->Esi
, Esp0
);
267 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss
->Edi
, OldTss
->Eflags
);
268 if (OldTss
->Cs
== KGDT_R0_CODE
)
270 DbgPrint("kESP %.8x ", Esp0
);
271 if (PsGetCurrentThread() != NULL
)
273 DbgPrint("kernel stack base %x\n",
274 PsGetCurrentThread()->Tcb
.StackLimit
);
280 DbgPrint("User ESP %.8x\n", OldTss
->Esp
);
282 if ((OldTss
->Cs
& 0xffff) == KGDT_R0_CODE
)
284 if (PsGetCurrentThread() != NULL
)
286 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
287 StackBase
= (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
;
291 StackLimit
= (ULONG
)init_stack_top
;
292 StackBase
= (ULONG
)init_stack
;
296 Change to an #if 0 to reduce the amount of information printed on
297 a recursive stack trace.
300 DbgPrint("Frames: ");
301 Frame
= (PULONG
)OldTss
->Ebp
;
302 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
304 KeRosPrintAddress((PVOID
)Frame
[1]);
305 Frame
= (PULONG
)Frame
[0];
309 DbgPrint("Frames: ");
311 Frame
= (PULONG
)OldTss
->Ebp
;
312 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
314 StackTrace
[i
] = (PVOID
)Frame
[1];
315 Frame
= (PULONG
)Frame
[0];
321 while (i
< TraceLength
)
323 StackRepeatCount
[i
] = 0;
326 while ((j
- i
) <= (TraceLength
- j
) && FoundRepeat
== FALSE
)
328 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
329 (j
- i
) * sizeof(PVOID
)) == 0)
331 StackRepeatCount
[i
] = 2;
332 StackRepeatLength
[i
] = j
- i
;
340 if (FoundRepeat
== FALSE
)
345 j
= j
+ StackRepeatLength
[i
];
346 while ((TraceLength
- j
) >= StackRepeatLength
[i
] &&
349 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
350 StackRepeatLength
[i
] * sizeof(PVOID
)) == 0)
352 StackRepeatCount
[i
]++;
353 j
= j
+ StackRepeatLength
[i
];
364 while (i
< TraceLength
)
366 if (StackRepeatCount
[i
] == 0)
368 KeRosPrintAddress(StackTrace
[i
]);
374 if (StackRepeatLength
[i
] == 0)
378 for (j
= 0; j
< StackRepeatLength
[i
]; j
++)
380 KeRosPrintAddress(StackTrace
[i
+ j
]);
382 DbgPrint("}*%d", StackRepeatCount
[i
]);
383 i
= i
+ StackRepeatLength
[i
] * StackRepeatCount
[i
];
395 KiDumpTrapFrame(PKTRAP_FRAME Tf
, ULONG Parameter1
, ULONG Parameter2
)
400 ULONG ExceptionNr
= (ULONG
)Tf
->DbgArgMark
;
401 ULONG cr2
= (ULONG
)Tf
->DbgArgPointer
;
406 * Print out the CPU registers
408 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
410 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
411 ExceptionNr
, Tf
->ErrCode
&0xffff);
415 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrCode
&0xffff);
417 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
418 Tf
->SegCs
&0xffff, Tf
->Eip
);
419 KeRosPrintAddress((PVOID
)Tf
->Eip
);
421 Ke386GetPageTableDirectory(cr3_
);
422 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3_
);
423 DbgPrint("Proc: %x ",PsGetCurrentProcess());
424 if (PsGetCurrentProcess() != NULL
)
426 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
427 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
429 if (PsGetCurrentThread() != NULL
)
431 DbgPrint("Thrd: %x Tid: %x",
432 PsGetCurrentThread(),
433 PsGetCurrentThread()->Cid
.UniqueThread
);
436 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->SegDs
&0xffff, Tf
->SegEs
&0xffff,
437 Tf
->SegFs
&0xffff, Tf
->SegGs
&0xfff);
438 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
439 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf
->Edx
,
440 Tf
->Ebp
, Tf
->Esi
, Esp0
);
441 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->EFlags
);
442 if ((Tf
->SegCs
&0xffff) == KGDT_R0_CODE
)
444 DbgPrint("kESP %.8x ", Esp0
);
445 if (PsGetCurrentThread() != NULL
)
447 DbgPrint("kernel stack base %x\n",
448 PsGetCurrentThread()->Tcb
.StackLimit
);
453 if (PsGetCurrentThread() != NULL
)
455 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
459 StackLimit
= (ULONG
)init_stack_top
;
463 * Dump the stack frames
465 KeDumpStackFrames((PULONG
)Tf
->Ebp
);
469 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
471 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
472 * message and halt the computer
474 * Complete CPU context
480 ASSERT(ExceptionNr
!= 14);
481 ASSERT((ExceptionNr
!= 7 && ExceptionNr
!= 16 && ExceptionNr
!= 19));
483 /* Use the address of the trap frame as approximation to the ring0 esp */
484 Esp0
= (ULONG
)&Tf
->Eip
;
488 Tf
->DbgArgPointer
= cr2
;
491 * If this was a V86 mode exception then handle it specially
493 if (Tf
->EFlags
& (1 << 17))
495 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf
->EFlags
, Tf
->Eip
, ExceptionNr
);
496 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
500 * Check for stack underflow, this may be obsolete
502 DPRINT1("Exception: %x\n", ExceptionNr
);
503 if (PsGetCurrentThread() != NULL
&&
504 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
506 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
507 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
, Tf
->Eip
);
511 if (ExceptionNr
== 15)
515 * This exception should never occur. The P6 has a bug, which does sometimes deliver
516 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
517 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
518 * sources. Linux does ignore this exception.
521 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
526 * Check for a breakpoint that was only for the attention of the debugger.
528 if (ExceptionNr
== 3 && Tf
->Eip
== ((ULONG
)DbgBreakPointNoBugCheck
) + 1)
531 EIP is already adjusted by the processor to point to the instruction
532 after the breakpoint.
538 * Handle user exceptions differently
540 if ((Tf
->SegCs
& 0xFFFF) == (KGDT_R3_CODE
| RPL_MASK
))
542 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
546 return(KiKernelTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
552 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
554 /* Check if this is user-mode or V86 */
555 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
556 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
558 /* Return it directly */
559 return TrapFrame
->HardwareEsp
;
564 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
566 /* Return edited value */
567 return TrapFrame
->TempEsp
;
571 /* Virgin frame, calculate */
572 return (ULONG
)&TrapFrame
->HardwareEsp
;
579 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
582 ULONG Previous
= KiEspFromTrapFrame(TrapFrame
);
584 /* Check if this is user-mode or V86 */
585 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
587 /* Write it directly */
588 TrapFrame
->HardwareEsp
= Esp
;
592 /* Don't allow ESP to be lowered, this is illegal */
593 if (Esp
< Previous
) KeBugCheck(SET_OF_INVALID_CONTEXT
);
595 /* Create an edit frame, check if it was alrady */
596 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
598 /* Update the value */
599 TrapFrame
->TempEsp
= Esp
;
603 /* Check if ESP changed */
607 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
608 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
611 TrapFrame
->TempEsp
= Esp
;
619 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
621 /* If this was V86 Mode */
622 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
625 return TrapFrame
->HardwareSegSs
;
627 else if (TrapFrame
->SegCs
& MODE_MASK
)
629 /* Usermode, return the User SS */
630 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
641 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
644 /* Remove the high-bits */
647 /* If this was V86 Mode */
648 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
651 TrapFrame
->HardwareSegSs
= Ss
;
653 else if (TrapFrame
->SegCs
& MODE_MASK
)
655 /* Usermode, save the User SS */
656 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
662 KiTagWordFnsaveToFxsave(USHORT TagWord
)
664 INT FxTagWord
= ~TagWord
;
667 * Empty is now 00, any 2 bits containing 1 mean valid
668 * Now convert the rest (11->0 and the rest to 1)
670 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
671 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
672 FxTagWord
= (FxTagWord
| (FxTagWord
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
673 FxTagWord
= (FxTagWord
| (FxTagWord
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
679 KeContextToTrapFrame(IN PCONTEXT Context
,
680 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
681 IN OUT PKTRAP_FRAME TrapFrame
,
682 IN ULONG ContextFlags
,
683 IN KPROCESSOR_MODE PreviousMode
)
685 PFX_SAVE_AREA FxSaveArea
;
687 BOOLEAN V86Switch
= FALSE
;
688 KIRQL OldIrql
= APC_LEVEL
;
690 /* Do this at APC_LEVEL */
691 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
693 /* Start with the basic Registers */
694 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
696 /* Check if we went through a V86 switch */
697 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
698 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
700 /* We did, remember this for later */
704 /* Copy EFLAGS. FIXME: Needs to be sanitized */
705 TrapFrame
->EFlags
= Context
->EFlags
;
707 /* Copy EBP and EIP */
708 TrapFrame
->Ebp
= Context
->Ebp
;
709 TrapFrame
->Eip
= Context
->Eip
;
711 /* Check if we were in V86 Mode */
712 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
714 /* Simply copy the CS value */
715 TrapFrame
->SegCs
= Context
->SegCs
;
719 /* We weren't in V86, so sanitize the CS (FIXME!) */
720 TrapFrame
->SegCs
= Context
->SegCs
;
722 /* Don't let it under 8, that's invalid */
723 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
725 /* Force it to User CS */
726 TrapFrame
->SegCs
= (KGDT_R3_CODE
| RPL_MASK
);
730 /* Handle SS Specially for validation */
731 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
733 /* Write ESP back; take into account Edited Trap Frames */
734 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
736 /* Handle our V86 Bias if we went through a switch */
737 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
740 /* Process the Integer Registers */
741 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
743 /* Copy them manually */
744 TrapFrame
->Eax
= Context
->Eax
;
745 TrapFrame
->Ebx
= Context
->Ebx
;
746 TrapFrame
->Ecx
= Context
->Ecx
;
747 TrapFrame
->Edx
= Context
->Edx
;
748 TrapFrame
->Esi
= Context
->Esi
;
749 TrapFrame
->Edi
= Context
->Edi
;
752 /* Process the Context Segments */
753 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
755 /* Check if we were in V86 Mode */
756 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
758 /* Copy the V86 Segments directlry */
759 TrapFrame
->V86Ds
= Context
->SegDs
;
760 TrapFrame
->V86Es
= Context
->SegEs
;
761 TrapFrame
->V86Fs
= Context
->SegFs
;
762 TrapFrame
->V86Gs
= Context
->SegGs
;
764 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
766 /* For kernel mode, write the standard values */
767 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
768 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
769 TrapFrame
->SegFs
= Context
->SegFs
;
770 TrapFrame
->SegGs
= 0;
774 /* For user mode, return the values directlry */
775 TrapFrame
->SegDs
= Context
->SegDs
;
776 TrapFrame
->SegEs
= Context
->SegEs
;
777 TrapFrame
->SegFs
= Context
->SegFs
;
779 /* Handle GS specially */
780 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
782 /* Don't use it, if user */
783 TrapFrame
->SegGs
= 0;
787 /* Copy it if kernel */
788 TrapFrame
->SegGs
= Context
->SegGs
;
793 /* Handle the extended registers */
794 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
795 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
797 /* Get the FX Area */
798 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
800 /* Check if NPX is present */
801 if (KeI386NpxPresent
)
803 /* Flush the NPX State */
804 KiFlushNPXState(NULL
);
806 /* Copy the FX State */
807 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
808 &Context
->ExtendedRegisters
[0],
809 MAXIMUM_SUPPORTED_EXTENSION
);
811 /* Remove reserved bits from MXCSR */
812 FxSaveArea
->U
.FxArea
.MXCsr
&= ~0xFFBF;
814 /* Mask out any invalid flags */
815 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
817 /* FIXME: Check if this is a VDM app */
821 /* Handle the floating point state */
822 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
823 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
825 /* Get the FX Area */
826 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
828 /* Check if NPX is present */
829 if (KeI386NpxPresent
)
831 /* Flush the NPX State */
832 KiFlushNPXState(NULL
);
834 /* Check if we have Fxsr support */
835 if (KeI386FxsrPresent
)
837 /* Convert the Fn Floating Point state to Fx */
838 FxSaveArea
->U
.FxArea
.ControlWord
=
839 (USHORT
)Context
->FloatSave
.ControlWord
;
840 FxSaveArea
->U
.FxArea
.StatusWord
=
841 (USHORT
)Context
->FloatSave
.StatusWord
;
842 FxSaveArea
->U
.FxArea
.TagWord
=
843 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
844 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
845 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
846 FxSaveArea
->U
.FxArea
.ErrorOffset
=
847 Context
->FloatSave
.ErrorOffset
;
848 FxSaveArea
->U
.FxArea
.ErrorSelector
=
849 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
850 FxSaveArea
->U
.FxArea
.DataOffset
=
851 Context
->FloatSave
.DataOffset
;
852 FxSaveArea
->U
.FxArea
.DataSelector
=
853 Context
->FloatSave
.DataSelector
;
855 /* Clear out the Register Area */
856 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
857 SIZE_OF_FX_REGISTERS
);
859 /* Loop the 8 floating point registers */
860 for (i
= 0; i
< 8; i
++)
862 /* Copy from Fn to Fx */
863 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
864 Context
->FloatSave
.RegisterArea
+ (i
* 10),
870 /* Just dump the Fn state in */
871 RtlCopyMemory(&FxSaveArea
->U
.FnArea
,
873 sizeof(FNSAVE_FORMAT
));
876 /* Mask out any invalid flags */
877 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
879 /* FIXME: Check if this is a VDM app */
883 /* FIXME: Handle FPU Emulation */
888 /* Handle the Debug Registers */
889 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
891 /* FIXME: All these should be sanitized */
892 TrapFrame
->Dr0
= Context
->Dr0
;
893 TrapFrame
->Dr1
= Context
->Dr1
;
894 TrapFrame
->Dr2
= Context
->Dr2
;
895 TrapFrame
->Dr3
= Context
->Dr3
;
896 TrapFrame
->Dr6
= Context
->Dr6
;
897 TrapFrame
->Dr7
= Context
->Dr7
;
899 /* Check if usermode */
900 if (PreviousMode
!= KernelMode
)
902 /* Set the Debug Flag */
903 KeGetCurrentThread()->DispatcherHeader
.DebugActive
=
904 (Context
->Dr7
& DR7_ACTIVE
);
909 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
914 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
915 IN PKEXCEPTION_FRAME ExceptionFrame
,
916 IN OUT PCONTEXT Context
)
918 PFX_SAVE_AREA FxSaveArea
;
922 FLOATING_SAVE_AREA UnalignedArea
;
924 FLOATING_SAVE_AREA
*FloatSaveArea
;
925 KIRQL OldIrql
= APC_LEVEL
;
927 /* Do this at APC_LEVEL */
928 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
930 /* Start with the Control flags */
931 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
933 /* EBP, EIP and EFLAGS */
934 Context
->Ebp
= TrapFrame
->Ebp
;
935 Context
->Eip
= TrapFrame
->Eip
;
936 Context
->EFlags
= TrapFrame
->EFlags
;
938 /* Return the correct CS */
939 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
940 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
942 /* Get it from the Temp location */
943 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
947 /* Return it directly */
948 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
951 /* Get the Ss and ESP */
952 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
953 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
956 /* Handle the Segments */
957 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
959 /* Do V86 Mode first */
960 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
962 /* Return from the V86 location */
963 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
964 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
965 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
966 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
970 /* Check if this was a Kernel Trap */
971 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
973 /* Set valid selectors */
974 TrapFrame
->SegGs
= 0;
975 TrapFrame
->SegFs
= KGDT_R0_PCR
;
976 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
977 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
980 /* Return the segments */
981 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
982 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
983 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
984 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
988 /* Handle the simple registers */
989 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
991 /* Return them directly */
992 Context
->Eax
= TrapFrame
->Eax
;
993 Context
->Ebx
= TrapFrame
->Ebx
;
994 Context
->Ecx
= TrapFrame
->Ecx
;
995 Context
->Edx
= TrapFrame
->Edx
;
996 Context
->Esi
= TrapFrame
->Esi
;
997 Context
->Edi
= TrapFrame
->Edi
;
1000 /* Handle extended registers */
1001 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
1002 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
1004 /* Get the FX Save Area */
1005 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
1007 /* Make sure NPX is present */
1008 if (KeI386NpxPresent
)
1010 /* Flush the NPX State */
1011 KiFlushNPXState(NULL
);
1013 /* Copy the registers */
1014 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
1015 &FxSaveArea
->U
.FxArea
,
1016 MAXIMUM_SUPPORTED_EXTENSION
);
1020 /* Handle Floating Point */
1021 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
1022 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
1024 /* Get the FX Save Area */
1025 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
1027 /* Make sure we have an NPX */
1028 if (KeI386NpxPresent
)
1030 /* Check if we have Fxsr support */
1031 if (KeI386FxsrPresent
)
1033 /* Align the floating area to 16-bytes */
1034 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
1035 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
1038 KiFlushNPXState(FloatSaveArea
);
1042 /* We don't, use the FN area and flush the NPX State */
1043 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
1044 KiFlushNPXState(NULL
);
1047 /* Copy into the Context */
1048 RtlCopyMemory(&Context
->FloatSave
,
1050 sizeof(FNSAVE_FORMAT
));
1054 /* FIXME: Handle Emulation */
1059 /* Handle debug registers */
1060 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
1061 CONTEXT_DEBUG_REGISTERS
)
1063 /* Copy the debug registers */
1064 Context
->Dr0
= TrapFrame
->Dr0
;
1065 Context
->Dr1
= TrapFrame
->Dr1
;
1066 Context
->Dr2
= TrapFrame
->Dr2
;
1067 Context
->Dr3
= TrapFrame
->Dr3
;
1068 Context
->Dr6
= TrapFrame
->Dr6
;
1070 /* For user-mode, only set DR7 if a debugger is active */
1071 if (((TrapFrame
->SegCs
& MODE_MASK
) ||
1072 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)) &&
1073 (KeGetCurrentThread()->DispatcherHeader
.DebugActive
))
1076 Context
->Dr7
= TrapFrame
->Dr7
;
1086 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
1091 KeDumpStackFrames(PULONG Frame
)
1093 PULONG StackBase
, StackEnd
;
1094 MEMORY_BASIC_INFORMATION mbi
;
1095 ULONG ResultLength
= sizeof(mbi
);
1098 DbgPrint("Frames:\n");
1101 Status
= MiQueryVirtualMemory (
1104 MemoryBasicInformation
,
1108 if ( !NT_SUCCESS(Status
) )
1110 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1115 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1117 while ( Frame
>= StackBase
&& Frame
< StackEnd
)
1119 ULONG Addr
= Frame
[1];
1120 if (!KeRosPrintAddress((PVOID
)Addr
))
1121 DbgPrint("<%X>", Addr
);
1122 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
1125 Frame
= (PULONG
)Frame
[0];
1137 KeRosDumpStackFrames ( PULONG Frame
, ULONG FrameCount
)
1140 PULONG StackBase
, StackEnd
;
1141 MEMORY_BASIC_INFORMATION mbi
;
1142 ULONG ResultLength
= sizeof(mbi
);
1145 DbgPrint("Frames: ");
1150 #if defined __GNUC__
1151 __asm__("mov %%ebp, %0" : "=r" (Frame
) : );
1152 #elif defined(_MSC_VER)
1153 __asm mov
[Frame
], ebp
1155 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
1158 Status
= MiQueryVirtualMemory (
1161 MemoryBasicInformation
,
1165 if ( !NT_SUCCESS(Status
) )
1167 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1172 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1174 while ( Frame
>= StackBase
&& Frame
< StackEnd
&& i
++ < FrameCount
)
1176 ULONG Addr
= Frame
[1];
1177 if (!KeRosPrintAddress((PVOID
)Addr
))
1178 DbgPrint("<%X>", Addr
);
1179 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
1182 Frame
= (PULONG
)Frame
[0];
1194 KeRosGetStackFrames ( PULONG Frames
, ULONG FrameCount
)
1197 PULONG StackBase
, StackEnd
, Frame
;
1198 MEMORY_BASIC_INFORMATION mbi
;
1199 ULONG ResultLength
= sizeof(mbi
);
1204 #if defined __GNUC__
1205 __asm__("mov %%ebp, %0" : "=r" (Frame
) : );
1206 #elif defined(_MSC_VER)
1207 __asm mov
[Frame
], ebp
1210 Status
= MiQueryVirtualMemory (
1213 MemoryBasicInformation
,
1217 if ( !NT_SUCCESS(Status
) )
1219 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1224 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1226 while ( Count
< FrameCount
&& Frame
>= StackBase
&& Frame
< StackEnd
)
1228 Frames
[Count
++] = Frame
[1];
1230 Frame
= (PULONG
)Frame
[0];
1243 KeInitExceptions(VOID
)
1246 USHORT FlippedSelector
;
1249 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
1251 /* Save the current Selector */
1252 FlippedSelector
= KiIdt
[i
].Selector
;
1254 /* Flip Selector and Extended Offset */
1255 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
1256 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
1262 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord
,
1263 PKEXCEPTION_FRAME ExceptionFrame
,
1264 PKTRAP_FRAME TrapFrame
,
1265 KPROCESSOR_MODE PreviousMode
,
1266 BOOLEAN FirstChance
)
1269 KD_CONTINUE_TYPE Action
;
1270 ULONG_PTR Stack
, NewStack
;
1272 BOOLEAN UserDispatch
= FALSE
;
1273 DPRINT("KiDispatchException() called\n");
1275 /* Increase number of Exception Dispatches */
1276 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
1278 /* Set the context flags */
1279 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
1281 /* Check if User Mode */
1282 if (PreviousMode
== UserMode
)
1284 /* Add the FPU Flag */
1285 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
1286 if (KeI386FxsrPresent
) Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
1290 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
1292 /* Handle kernel-mode first, it's simpler */
1293 if (PreviousMode
== KernelMode
)
1295 /* Check if this is a first-chance exception */
1296 if (FirstChance
== TRUE
)
1298 /* Break into the debugger for the first time */
1299 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1306 /* If the debugger said continue, then continue */
1307 if (Action
== kdContinue
) goto Handled
;
1309 /* If the Debugger couldn't handle it, dispatch the exception */
1310 if (RtlDispatchException(ExceptionRecord
, &Context
))
1312 /* It was handled by an exception handler, continue */
1317 /* This is a second-chance exception, only for the debugger */
1318 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1325 /* If the debugger said continue, then continue */
1326 if (Action
== kdContinue
) goto Handled
;
1328 /* Third strike; you're out */
1329 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1330 ExceptionRecord
->ExceptionCode
,
1331 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1332 ExceptionRecord
->ExceptionInformation
[0],
1333 ExceptionRecord
->ExceptionInformation
[1],
1338 /* User mode exception, was it first-chance? */
1341 /* Enter Debugger if available */
1342 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1349 /* Exit if we're continuing */
1350 if (Action
== kdContinue
) goto Handled
;
1352 /* FIXME: Forward exception to user mode debugger */
1354 /* Set up the user-stack */
1357 /* Align context size and get stack pointer */
1358 Size
= (sizeof(CONTEXT
) + 3) & ~3;
1359 Stack
= (Context
.Esp
& ~3) - Size
;
1360 DPRINT("Stack: %lx\n", Stack
);
1362 /* Probe stack and copy Context */
1363 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
1364 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
1366 /* Align exception record size and get stack pointer */
1367 Size
= (sizeof(EXCEPTION_RECORD
) -
1368 (EXCEPTION_MAXIMUM_PARAMETERS
- ExceptionRecord
->NumberParameters
) *
1369 sizeof(ULONG
) + 3) & ~3;
1370 NewStack
= Stack
- Size
;
1371 DPRINT("NewStack: %lx\n", NewStack
);
1373 /* Probe stack and copy exception record. Don't forget to add the two params */
1374 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
1375 Size
+ 2 * sizeof(ULONG_PTR
),
1377 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
1379 /* Now write the two params for the user-mode dispatcher */
1380 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
1381 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
1383 /* Set new Stack Pointer */
1384 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
1386 /* Set EIP to the User-mode Dispathcer */
1387 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1388 UserDispatch
= TRUE
;
1393 /* Do second-chance */
1398 /* If we dispatch to user, return now */
1399 if (UserDispatch
) return;
1401 /* FIXME: Forward the exception to the debugger for 2nd chance */
1403 /* 3rd strike, kill the thread */
1404 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1405 ZwTerminateThread(NtCurrentThread(), ExceptionRecord
->ExceptionCode
);
1406 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1407 ExceptionRecord
->ExceptionCode
,
1408 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1409 ExceptionRecord
->ExceptionInformation
[0],
1410 ExceptionRecord
->ExceptionInformation
[1],
1415 /* Convert the context back into Trap/Exception Frames */
1416 KeContextToTrapFrame(&Context
,
1419 Context
.ContextFlags
,
1429 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1432 PKTHREAD Thread
= KeGetCurrentThread();
1434 /* Make sure we can access the TEB */
1437 Thread
->Teb
->ExceptionCode
= ExceptionCode
;
1441 return(ExceptionCode
);
1445 /* Get the old EIP */
1446 OldEip
= Thread
->TrapFrame
->Eip
;
1448 /* Change it to the user-mode dispatcher */
1449 Thread
->TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1451 /* Return the old EIP */
1452 return((NTSTATUS
)OldEip
);