2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/i386/exp.c
5 * PURPOSE: Handling exceptions
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Skywing (skywing@valhallalegends.com)
11 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
21 * - Add more exception frame support for non-i386 compatibility.
22 * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
23 * - Implement official stack trace functions (exported) and remove stuff here.
24 * - Forward exceptions to user-mode debugger.
25 * - Wrap Ki NTDLL callbacks in SEH.
28 /* GLOBALS *****************************************************************/
30 #define FLAG_IF (1<<9)
33 #define STR(x) _STR(x)
36 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
39 extern void KiSystemService(void);
40 extern void KiDebugService(void);
42 extern VOID
KiTrap0(VOID
);
43 extern VOID
KiTrap1(VOID
);
44 extern VOID
KiTrap2(VOID
);
45 extern VOID
KiTrap3(VOID
);
46 extern VOID
KiTrap4(VOID
);
47 extern VOID
KiTrap5(VOID
);
48 extern VOID
KiTrap6(VOID
);
49 extern VOID
KiTrap7(VOID
);
50 extern VOID
KiTrap8(VOID
);
51 extern VOID
KiTrap9(VOID
);
52 extern VOID
KiTrap10(VOID
);
53 extern VOID
KiTrap11(VOID
);
54 extern VOID
KiTrap12(VOID
);
55 extern VOID
KiTrap13(VOID
);
56 extern VOID
KiTrap14(VOID
);
57 extern VOID
KiTrap15(VOID
);
58 extern VOID
KiTrap16(VOID
);
59 extern VOID
KiTrap17(VOID
);
60 extern VOID
KiTrap18(VOID
);
61 extern VOID
KiTrap19(VOID
);
62 extern VOID
KiTrapUnknown(VOID
);
64 extern ULONG init_stack
;
65 extern ULONG init_stack_top
;
67 extern BOOLEAN Ke386NoExecute
;
69 static char *ExceptionTypeStrings
[] =
76 "BOUND range exceeded",
78 "No Math Coprocessor",
82 "Segment Not Present",
83 "Stack Segment Fault",
93 NTSTATUS ExceptionToNtStatus
[] =
95 STATUS_INTEGER_DIVIDE_BY_ZERO
,
97 STATUS_ACCESS_VIOLATION
,
99 STATUS_INTEGER_OVERFLOW
,
100 STATUS_ARRAY_BOUNDS_EXCEEDED
,
101 STATUS_ILLEGAL_INSTRUCTION
,
102 STATUS_FLOAT_INVALID_OPERATION
,
103 STATUS_ACCESS_VIOLATION
,
104 STATUS_ACCESS_VIOLATION
,
105 STATUS_ACCESS_VIOLATION
,
106 STATUS_ACCESS_VIOLATION
,
107 STATUS_STACK_OVERFLOW
,
108 STATUS_ACCESS_VIOLATION
,
109 STATUS_ACCESS_VIOLATION
,
110 STATUS_ACCESS_VIOLATION
, /* RESERVED */
111 STATUS_FLOAT_INVALID_OPERATION
, /* Should not be used, the FPU can give more specific info */
112 STATUS_DATATYPE_MISALIGNMENT
,
113 STATUS_ACCESS_VIOLATION
,
114 STATUS_FLOAT_MULTIPLE_TRAPS
,
117 /* FUNCTIONS ****************************************************************/
120 KiRosPrintAddress(PVOID address
)
122 PLIST_ENTRY current_entry
;
123 PLDR_DATA_TABLE_ENTRY current
;
124 extern LIST_ENTRY ModuleListHead
;
125 ULONG_PTR RelativeAddress
;
130 current_entry
= ModuleListHead
.Flink
;
132 while (current_entry
!= &ModuleListHead
)
135 CONTAINING_RECORD(current_entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderModuleList
);
137 if (address
>= (PVOID
)current
->DllBase
&&
138 address
< (PVOID
)((ULONG_PTR
)current
->DllBase
+ current
->SizeOfImage
))
140 RelativeAddress
= (ULONG_PTR
) address
- (ULONG_PTR
) current
->DllBase
;
141 DbgPrint("<%wZ: %x>", ¤t
->FullDllName
, RelativeAddress
);
144 current_entry
= current_entry
->Flink
;
147 address
= (PVOID
)((ULONG_PTR
)address
& ~(ULONG_PTR
)MmSystemRangeStart
);
154 KiKernelTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
158 Er
.ExceptionFlags
= 0;
159 Er
.ExceptionRecord
= NULL
;
160 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
162 if (ExceptionNr
== 14)
164 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
165 Er
.NumberParameters
= 2;
166 Er
.ExceptionInformation
[0] = Tf
->ErrorCode
& 0x1;
167 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
171 if (ExceptionNr
< ARRAY_SIZE(ExceptionToNtStatus
))
173 Er
.ExceptionCode
= ExceptionToNtStatus
[ExceptionNr
];
177 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
179 Er
.NumberParameters
= 0;
182 /* FIXME: Which exceptions are noncontinuable? */
183 Er
.ExceptionFlags
= 0;
185 KiDispatchException(&Er
, NULL
, Tf
, KernelMode
, TRUE
);
191 KiDoubleFaultHandler(VOID
)
197 ULONG ExceptionNr
= 8;
203 static PVOID StackTrace
[MM_STACK_SIZE
/ sizeof(PVOID
)];
204 static ULONG StackRepeatCount
[MM_STACK_SIZE
/ sizeof(PVOID
)];
205 static ULONG StackRepeatLength
[MM_STACK_SIZE
/ sizeof(PVOID
)];
210 OldTss
= KeGetCurrentKPCR()->TSS
;
215 if (PsGetCurrentThread() != NULL
&&
216 PsGetCurrentThread()->ThreadsProcess
!= NULL
)
219 PsGetCurrentThread()->ThreadsProcess
->Pcb
.DirectoryTableBase
.QuadPart
;
227 * Check for stack underflow
229 if (PsGetCurrentThread() != NULL
&&
230 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
232 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
233 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
238 * Print out the CPU registers
240 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
242 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
247 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
249 DbgPrint("CS:EIP %x:%x ", OldTss
->Cs
, OldTss
->Eip
);
250 KeRosPrintAddress((PVOID
)OldTss
->Eip
);
252 DbgPrint("cr2 %x cr3 %x ", cr2
, OldCr3
);
253 DbgPrint("Proc: %x ",PsGetCurrentProcess());
254 if (PsGetCurrentProcess() != NULL
)
256 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
257 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
259 if (PsGetCurrentThread() != NULL
)
261 DbgPrint("Thrd: %x Tid: %x",
262 PsGetCurrentThread(),
263 PsGetCurrentThread()->Cid
.UniqueThread
);
266 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss
->Ds
, OldTss
->Es
,
267 OldTss
->Fs
, OldTss
->Gs
);
268 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss
->Eax
, OldTss
->Ebx
,
270 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss
->Edx
,
271 OldTss
->Ebp
, OldTss
->Esi
, Esp0
);
272 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss
->Edi
, OldTss
->Eflags
);
273 if (OldTss
->Cs
== KERNEL_CS
)
275 DbgPrint("kESP %.8x ", Esp0
);
276 if (PsGetCurrentThread() != NULL
)
278 DbgPrint("kernel stack base %x\n",
279 PsGetCurrentThread()->Tcb
.StackLimit
);
285 DbgPrint("User ESP %.8x\n", OldTss
->Esp
);
287 if ((OldTss
->Cs
& 0xffff) == KERNEL_CS
)
289 if (PsGetCurrentThread() != NULL
)
291 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
292 StackBase
= (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
;
296 StackLimit
= (ULONG
)init_stack_top
;
297 StackBase
= (ULONG
)init_stack
;
301 Change to an #if 0 to reduce the amount of information printed on
302 a recursive stack trace.
305 DbgPrint("Frames: ");
306 Frame
= (PULONG
)OldTss
->Ebp
;
307 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
309 KeRosPrintAddress((PVOID
)Frame
[1]);
310 Frame
= (PULONG
)Frame
[0];
314 DbgPrint("Frames: ");
316 Frame
= (PULONG
)OldTss
->Ebp
;
317 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
319 StackTrace
[i
] = (PVOID
)Frame
[1];
320 Frame
= (PULONG
)Frame
[0];
326 while (i
< TraceLength
)
328 StackRepeatCount
[i
] = 0;
331 while ((j
- i
) <= (TraceLength
- j
) && FoundRepeat
== FALSE
)
333 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
334 (j
- i
) * sizeof(PVOID
)) == 0)
336 StackRepeatCount
[i
] = 2;
337 StackRepeatLength
[i
] = j
- i
;
345 if (FoundRepeat
== FALSE
)
350 j
= j
+ StackRepeatLength
[i
];
351 while ((TraceLength
- j
) >= StackRepeatLength
[i
] &&
354 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
355 StackRepeatLength
[i
] * sizeof(PVOID
)) == 0)
357 StackRepeatCount
[i
]++;
358 j
= j
+ StackRepeatLength
[i
];
369 while (i
< TraceLength
)
371 if (StackRepeatCount
[i
] == 0)
373 KeRosPrintAddress(StackTrace
[i
]);
379 if (StackRepeatLength
[i
] == 0)
383 for (j
= 0; j
< StackRepeatLength
[i
]; j
++)
385 KeRosPrintAddress(StackTrace
[i
+ j
]);
387 DbgPrint("}*%d", StackRepeatCount
[i
]);
388 i
= i
+ StackRepeatLength
[i
] * StackRepeatCount
[i
];
399 KiDumpTrapFrame(PKTRAP_FRAME Tf
, ULONG Parameter1
, ULONG Parameter2
)
404 ULONG ExceptionNr
= (ULONG
)Tf
->DebugArgMark
;
405 ULONG cr2
= (ULONG
)Tf
->DebugPointer
;
410 * Print out the CPU registers
412 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
414 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
415 ExceptionNr
, Tf
->ErrorCode
&0xffff);
419 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrorCode
&0xffff);
421 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
422 Tf
->Cs
&0xffff, Tf
->Eip
);
423 KeRosPrintAddress((PVOID
)Tf
->Eip
);
425 Ke386GetPageTableDirectory(cr3_
);
426 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3_
);
427 DbgPrint("Proc: %x ",PsGetCurrentProcess());
428 if (PsGetCurrentProcess() != NULL
)
430 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
431 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
433 if (PsGetCurrentThread() != NULL
)
435 DbgPrint("Thrd: %x Tid: %x",
436 PsGetCurrentThread(),
437 PsGetCurrentThread()->Cid
.UniqueThread
);
440 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->Ds
&0xffff, Tf
->Es
&0xffff,
441 Tf
->Fs
&0xffff, Tf
->Gs
&0xfff);
442 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
443 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf
->Edx
,
444 Tf
->Ebp
, Tf
->Esi
, Esp0
);
445 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->Eflags
);
446 if ((Tf
->Cs
&0xffff) == KERNEL_CS
)
448 DbgPrint("kESP %.8x ", Esp0
);
449 if (PsGetCurrentThread() != NULL
)
451 DbgPrint("kernel stack base %x\n",
452 PsGetCurrentThread()->Tcb
.StackLimit
);
457 if (PsGetCurrentThread() != NULL
)
459 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
463 StackLimit
= (ULONG
)init_stack_top
;
467 * Dump the stack frames
469 KeDumpStackFrames((PULONG
)Tf
->Ebp
);
473 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
475 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
476 * message and halt the computer
478 * Complete CPU context
485 ASSERT(ExceptionNr
!= 14);
487 /* Store the exception number in an unused field in the trap frame. */
488 Tf
->DebugArgMark
= (PVOID
)ExceptionNr
;
490 /* Use the address of the trap frame as approximation to the ring0 esp */
491 Esp0
= (ULONG
)&Tf
->Eip
;
495 Tf
->DebugPointer
= (PVOID
)cr2
;
498 * If this was a V86 mode exception then handle it specially
500 if (Tf
->Eflags
& (1 << 17))
502 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf
->Eflags
, Tf
->Eip
, ExceptionNr
);
503 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
507 * Check for stack underflow, this may be obsolete
509 if (PsGetCurrentThread() != NULL
&&
510 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
512 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
513 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
, Tf
->Eip
);
517 if (ExceptionNr
== 15)
521 * This exception should never occur. The P6 has a bug, which does sometimes deliver
522 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
523 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
524 * sources. Linux does ignore this exception.
528 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
533 * Check for a breakpoint that was only for the attention of the debugger.
535 if (ExceptionNr
== 3 && Tf
->Eip
== ((ULONG
)DbgBreakPointNoBugCheck
) + 1)
538 EIP is already adjusted by the processor to point to the instruction
539 after the breakpoint.
545 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
547 if (ExceptionNr
== 7 || ExceptionNr
== 16 || ExceptionNr
== 19)
549 Status
= KiHandleFpuFault(Tf
, ExceptionNr
);
550 if (NT_SUCCESS(Status
))
557 * Handle user exceptions differently
559 if ((Tf
->Cs
& 0xFFFF) == USER_CS
)
561 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
565 return(KiKernelTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
571 KeContextToTrapFrame(PCONTEXT Context
,
572 PKEXCEPTION_FRAME ExceptionFrame
,
573 PKTRAP_FRAME TrapFrame
)
575 /* Start with the basic Registers */
576 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
578 TrapFrame
->Esp
= Context
->Esp
;
579 TrapFrame
->Ss
= Context
->SegSs
;
580 TrapFrame
->Cs
= Context
->SegCs
;
581 TrapFrame
->Eip
= Context
->Eip
;
582 TrapFrame
->Eflags
= Context
->EFlags
;
583 TrapFrame
->Ebp
= Context
->Ebp
;
586 /* Process the Integer Registers */
587 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
589 TrapFrame
->Eax
= Context
->Eax
;
590 TrapFrame
->Ebx
= Context
->Ebx
;
591 TrapFrame
->Ecx
= Context
->Ecx
;
592 TrapFrame
->Edx
= Context
->Edx
;
593 TrapFrame
->Esi
= Context
->Esi
;
594 TrapFrame
->Edi
= Context
->Edi
;
597 /* Process the Context Segments */
598 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
600 TrapFrame
->Ds
= Context
->SegDs
;
601 TrapFrame
->Es
= Context
->SegEs
;
602 TrapFrame
->Fs
= Context
->SegFs
;
603 TrapFrame
->Gs
= Context
->SegGs
;
606 /* Handle the Debug Registers */
607 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
609 TrapFrame
->Dr0
= Context
->Dr0
;
610 TrapFrame
->Dr1
= Context
->Dr1
;
611 TrapFrame
->Dr2
= Context
->Dr2
;
612 TrapFrame
->Dr3
= Context
->Dr3
;
613 TrapFrame
->Dr6
= Context
->Dr6
;
614 TrapFrame
->Dr7
= Context
->Dr7
;
617 /* Handle FPU and Extended Registers */
618 return KiContextToFxSaveArea((PFX_SAVE_AREA
)(TrapFrame
+ 1), Context
);
622 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame
,
625 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
627 Context
->SegSs
= TrapFrame
->Ss
;
628 Context
->Esp
= TrapFrame
->Esp
;
629 Context
->SegCs
= TrapFrame
->Cs
;
630 Context
->Eip
= TrapFrame
->Eip
;
631 Context
->EFlags
= TrapFrame
->Eflags
;
632 Context
->Ebp
= TrapFrame
->Ebp
;
634 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
636 Context
->Eax
= TrapFrame
->Eax
;
637 Context
->Ebx
= TrapFrame
->Ebx
;
638 Context
->Ecx
= TrapFrame
->Ecx
;
640 * NOTE: In the trap frame which is built on entry to a system
641 * call TrapFrame->Edx will actually hold the address of the
642 * previous TrapFrame. I don't believe leaking this information
643 * has security implications. Also EDX holds the address of the
644 * arguments to the system call in progress so it isn't of much
645 * interest to the debugger.
647 Context
->Edx
= TrapFrame
->Edx
;
648 Context
->Esi
= TrapFrame
->Esi
;
649 Context
->Edi
= TrapFrame
->Edi
;
651 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
653 Context
->SegDs
= TrapFrame
->Ds
;
654 Context
->SegEs
= TrapFrame
->Es
;
655 Context
->SegFs
= TrapFrame
->Fs
;
656 Context
->SegGs
= TrapFrame
->Gs
;
658 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
661 * FIXME: Implement this case
663 Context
->ContextFlags
&= (~CONTEXT_DEBUG_REGISTERS
) | CONTEXT_i386
;
665 if ((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) == CONTEXT_FLOATING_POINT
)
668 * FIXME: Implement this case
670 * I think this should only be filled for FPU exceptions, otherwise I
671 * would not know where to get it from as it can be the current state
672 * of the FPU or already saved in the thread's FPU save area.
675 Context
->ContextFlags
&= (~CONTEXT_FLOATING_POINT
) | CONTEXT_i386
;
678 if ((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) == CONTEXT_EXTENDED_REGISTERS
)
681 * FIXME: Investigate this
683 * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
684 * This should only be filled in case of a SIMD exception I think, so
685 * this is not the right place (like for FPU the state could already be
686 * saved in the thread's FX_SAVE_AREA or still be in the CPU)
689 Context
->ContextFlags
&= ~CONTEXT_EXTENDED_REGISTERS
;
695 KeDumpStackFrames(PULONG Frame
)
697 PULONG StackBase
, StackEnd
;
698 MEMORY_BASIC_INFORMATION mbi
;
699 ULONG ResultLength
= sizeof(mbi
);
702 DbgPrint("Frames:\n");
705 Status
= MiQueryVirtualMemory (
708 MemoryBasicInformation
,
712 if ( !NT_SUCCESS(Status
) )
714 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
719 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
721 while ( Frame
>= StackBase
&& Frame
< StackEnd
)
723 ULONG Addr
= Frame
[1];
724 if (!KeRosPrintAddress((PVOID
)Addr
))
725 DbgPrint("<%X>", Addr
);
726 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
729 Frame
= (PULONG
)Frame
[0];
741 KeRosDumpStackFrames ( PULONG Frame
, ULONG FrameCount
)
744 PULONG StackBase
, StackEnd
;
745 MEMORY_BASIC_INFORMATION mbi
;
746 ULONG ResultLength
= sizeof(mbi
);
749 DbgPrint("Frames: ");
755 __asm__("mov %%ebp, %%ebx" : "=b" (Frame
) : );
756 #elif defined(_MSC_VER)
757 __asm mov
[Frame
], ebp
759 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
762 Status
= MiQueryVirtualMemory (
765 MemoryBasicInformation
,
769 if ( !NT_SUCCESS(Status
) )
771 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
776 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
778 while ( Frame
>= StackBase
&& Frame
< StackEnd
&& i
++ < FrameCount
)
780 ULONG Addr
= Frame
[1];
781 if (!KeRosPrintAddress((PVOID
)Addr
))
782 DbgPrint("<%X>", Addr
);
783 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
786 Frame
= (PULONG
)Frame
[0];
798 KeRosGetStackFrames ( PULONG Frames
, ULONG FrameCount
)
801 PULONG StackBase
, StackEnd
, Frame
;
802 MEMORY_BASIC_INFORMATION mbi
;
803 ULONG ResultLength
= sizeof(mbi
);
809 __asm__("mov %%ebp, %%ebx" : "=b" (Frame
) : );
810 #elif defined(_MSC_VER)
811 __asm mov
[Frame
], ebp
814 Status
= MiQueryVirtualMemory (
817 MemoryBasicInformation
,
821 if ( !NT_SUCCESS(Status
) )
823 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
828 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
830 while ( Count
< FrameCount
&& Frame
>= StackBase
&& Frame
< StackEnd
)
832 Frames
[Count
++] = Frame
[1];
834 Frame
= (PULONG
)Frame
[0];
845 set_system_call_gate(unsigned int sel
, unsigned int func
)
847 DPRINT("sel %x %d\n",sel
,sel
);
848 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
850 KiIdt
[sel
].b
= 0xef00 + (((int)func
)&0xffff0000);
851 DPRINT("idt[sel].b %x\n",KiIdt
[sel
].b
);
854 static void set_interrupt_gate(unsigned int sel
, unsigned int func
)
856 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel
,func
);
857 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
859 KiIdt
[sel
].b
= 0x8e00 + (((int)func
)&0xffff0000);
862 static void set_trap_gate(unsigned int sel
, unsigned int func
, unsigned int dpl
)
864 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel
, func
, dpl
);
866 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
868 KiIdt
[sel
].b
= 0x8f00 + (dpl
<< 13) + (((int)func
)&0xffff0000);
872 set_task_gate(unsigned int sel
, unsigned task_sel
)
874 KiIdt
[sel
].a
= task_sel
<< 16;
875 KiIdt
[sel
].b
= 0x8500;
879 KeInitExceptions(VOID
)
881 * FUNCTION: Initalize CPU exception handling
886 DPRINT("KeInitExceptions()\n");
889 * Set up the other gates
891 set_trap_gate(0, (ULONG
)KiTrap0
, 0);
892 set_trap_gate(1, (ULONG
)KiTrap1
, 0);
893 set_trap_gate(2, (ULONG
)KiTrap2
, 0);
894 set_trap_gate(3, (ULONG
)KiTrap3
, 3);
895 set_trap_gate(4, (ULONG
)KiTrap4
, 0);
896 set_trap_gate(5, (ULONG
)KiTrap5
, 0);
897 set_trap_gate(6, (ULONG
)KiTrap6
, 0);
898 set_trap_gate(7, (ULONG
)KiTrap7
, 0);
899 set_task_gate(8, TRAP_TSS_SELECTOR
);
900 set_trap_gate(9, (ULONG
)KiTrap9
, 0);
901 set_trap_gate(10, (ULONG
)KiTrap10
, 0);
902 set_trap_gate(11, (ULONG
)KiTrap11
, 0);
903 set_trap_gate(12, (ULONG
)KiTrap12
, 0);
904 set_trap_gate(13, (ULONG
)KiTrap13
, 0);
905 set_interrupt_gate(14, (ULONG
)KiTrap14
);
906 set_trap_gate(15, (ULONG
)KiTrap15
, 0);
907 set_trap_gate(16, (ULONG
)KiTrap16
, 0);
908 set_trap_gate(17, (ULONG
)KiTrap17
, 0);
909 set_trap_gate(18, (ULONG
)KiTrap18
, 0);
910 set_trap_gate(19, (ULONG
)KiTrap19
, 0);
912 for (i
= 20; i
< 256; i
++)
914 set_trap_gate(i
,(int)KiTrapUnknown
, 0);
917 set_system_call_gate(0x2d,(int)KiDebugService
);
918 set_system_call_gate(0x2e,(int)KiSystemService
);
923 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord
,
924 PKEXCEPTION_FRAME ExceptionFrame
,
925 PKTRAP_FRAME TrapFrame
,
926 KPROCESSOR_MODE PreviousMode
,
930 KD_CONTINUE_TYPE Action
;
931 ULONG_PTR Stack
, NewStack
;
933 BOOLEAN UserDispatch
= FALSE
;
934 DPRINT1("KiDispatchException() called\n");
936 /* Increase number of Exception Dispatches */
937 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
939 /* Set the context flags */
940 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
942 /* Check if User Mode */
943 if (PreviousMode
== UserMode
)
945 /* Add the FPU Flag */
946 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
950 KeTrapFrameToContext(TrapFrame
, &Context
);
952 /* Handle kernel-mode first, it's simpler */
953 if (PreviousMode
== KernelMode
)
955 /* Check if this is a first-chance exception */
956 if (FirstChance
== TRUE
)
958 /* Break into the debugger for the first time */
959 Action
= KdpEnterDebuggerException(ExceptionRecord
,
966 /* If the debugger said continue, then continue */
967 if (Action
== kdContinue
) goto Handled
;
969 /* If the Debugger couldn't handle it, dispatch the exception */
970 if (RtlDispatchException(ExceptionRecord
, &Context
))
972 /* It was handled by an exception handler, continue */
977 /* This is a second-chance exception, only for the debugger */
978 Action
= KdpEnterDebuggerException(ExceptionRecord
,
985 /* If the debugger said continue, then continue */
986 if (Action
== kdContinue
) goto Handled
;
988 /* Third strike; you're out */
989 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
990 ExceptionRecord
->ExceptionCode
,
991 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
992 ExceptionRecord
->ExceptionInformation
[0],
993 ExceptionRecord
->ExceptionInformation
[1],
998 /* User mode exception, was it first-chance? */
1001 /* Enter Debugger if available */
1002 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1009 /* Exit if we're continuing */
1010 if (Action
== kdContinue
) goto Handled
;
1012 /* FIXME: Forward exception to user mode debugger */
1014 /* Set up the user-stack */
1017 /* Align context size and get stack pointer */
1018 Size
= (sizeof(CONTEXT
) + 3) & ~3;
1019 Stack
= (Context
.Esp
& ~3) - Size
;
1020 DPRINT1("Stack: %lx\n", Stack
);
1022 /* Probe stack and copy Context */
1023 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
1024 RtlMoveMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
1026 /* Align exception record size and get stack pointer */
1027 Size
= (sizeof(EXCEPTION_RECORD
) -
1028 (EXCEPTION_MAXIMUM_PARAMETERS
- ExceptionRecord
->NumberParameters
) *
1029 sizeof(ULONG
) + 3) & ~3;
1030 NewStack
= Stack
- Size
;
1031 DPRINT1("NewStack: %lx\n", NewStack
);
1033 /* Probe stack and copy exception record. Don't forget to add the two params */
1034 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
1035 Size
+ 2 * sizeof(ULONG_PTR
),
1037 RtlMoveMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
1039 /* Now write the two params for the user-mode dispatcher */
1040 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
1041 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
1043 /* Set new Stack Pointer */
1044 TrapFrame
->Esp
= NewStack
- 2 * sizeof(ULONG_PTR
);
1046 /* Set EIP to the User-mode Dispathcer */
1047 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1048 UserDispatch
= TRUE
;
1053 /* Do second-chance */
1058 /* If we dispatch to user, return now */
1059 if (UserDispatch
) return;
1061 /* FIXME: Forward the exception to the debugger for 2nd chance */
1063 /* 3rd strike, kill the thread */
1064 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1065 ZwTerminateThread(NtCurrentThread(), ExceptionRecord
->ExceptionCode
);
1066 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1067 ExceptionRecord
->ExceptionCode
,
1068 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1069 ExceptionRecord
->ExceptionInformation
[0],
1070 ExceptionRecord
->ExceptionInformation
[1],
1075 /* Convert the context back into Trap/Exception Frames */
1076 KeContextToTrapFrame(&Context
, NULL
, TrapFrame
);
1084 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1087 PKTHREAD Thread
= KeGetCurrentThread();
1090 Thread
->Teb
->ExceptionCode
= ExceptionCode
;
1092 return(ExceptionCode
);
1095 OldEip
= Thread
->TrapFrame
->Eip
;
1096 Thread
->TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1097 return((NTSTATUS
)OldEip
);