KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / ke / catch.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/catch.c
5 * PURPOSE: Exception handling
6 *
7 * PROGRAMMERS: Anich Gregor
8 * David Welch (welch@mcmail.com)
9 * Casper S. Hornstrup (chorns@users.sourceforge.net)
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* FUNCTIONS ****************************************************************/
19
20 ULONG
21 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
22 IN PCONTEXT Context);
23
24 /*
25 * @unimplemented
26 */
27 VOID
28 STDCALL
29 KiCoprocessorError(VOID)
30 {
31 UNIMPLEMENTED;
32 }
33
34 /*
35 * @unimplemented
36 */
37 VOID
38 STDCALL
39 KiUnexpectedInterrupt(VOID)
40 {
41 UNIMPLEMENTED;
42 }
43
44 VOID
45 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
46 PCONTEXT Context,
47 PKTRAP_FRAME Tf,
48 KPROCESSOR_MODE PreviousMode,
49 BOOLEAN SearchFrames)
50 {
51 EXCEPTION_DISPOSITION Value;
52 CONTEXT TContext;
53 KD_CONTINUE_TYPE Action = kdHandleException;
54
55 DPRINT("KiDispatchException() called\n");
56
57 /* Increase number of Exception Dispatches */
58 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
59
60 if (!Context)
61 {
62 /* Assume Full context */
63 TContext.ContextFlags = CONTEXT_FULL;
64
65 /* Check the mode */
66 if (PreviousMode == UserMode)
67 {
68 /* Add Debugger Registers if this is User Mode */
69 TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
70 }
71
72 /* Convert the Trapframe into a Context */
73 KeTrapFrameToContext(Tf, &TContext);
74
75 /* Use local stack context */
76 Context = &TContext;
77 }
78
79 /* Break into Debugger */
80 Action = KdpEnterDebuggerException(ExceptionRecord,
81 PreviousMode,
82 Context,
83 Tf,
84 TRUE,
85 TRUE);
86
87 /* If the debugger said continue, then continue */
88 if (Action == kdContinue) return;
89
90 /* If the Debugger couldn't handle it... */
91 if (Action != kdDoNotHandleException)
92 {
93 /* See what kind of Exception this is */
94 if (PreviousMode == UserMode)
95 {
96 /* User mode exception, search the frames if we have to */
97 if (SearchFrames)
98 {
99 PULONG Stack;
100 ULONG CDest;
101 char temp_space[12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)]; /* FIXME: HACKHACK */
102 PULONG pNewUserStack = (PULONG)(Tf->Esp - (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)));
103 NTSTATUS StatusOfCopy;
104
105 /* Enter Debugger if available */
106 Action = KdpEnterDebuggerException(ExceptionRecord,
107 PreviousMode,
108 Context,
109 Tf,
110 TRUE,
111 FALSE);
112
113 /* Exit if we're continuing */
114 if (Action == kdContinue) return;
115
116 /* FIXME: Forward exception to user mode debugger */
117
118 /* FIXME: Check user mode stack for enough space */
119
120 /* Let usermode try and handle the exception. Setup Stack */
121 Stack = (PULONG)temp_space;
122 CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
123 /* Return Address */
124 Stack[0] = 0;
125 /* Pointer to EXCEPTION_RECORD structure */
126 Stack[1] = (ULONG)&pNewUserStack[3];
127 /* Pointer to CONTEXT structure */
128 Stack[2] = (ULONG)&pNewUserStack[CDest];
129 memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
130 memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
131
132 /* Copy Stack */
133 StatusOfCopy = MmCopyToCaller(pNewUserStack,
134 temp_space,
135 (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)));
136
137 /* Check for success */
138 if (NT_SUCCESS(StatusOfCopy))
139 {
140 /* Set new Stack Pointer */
141 Tf->Esp = (ULONG)pNewUserStack;
142 }
143 else
144 {
145 /*
146 * Now it really hit the ventilation device. Sorry,
147 * can do nothing but kill the sucker.
148 */
149 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
150 DPRINT1("User-mode stack was invalid. Terminating target thread\n");
151 }
152 /* Set EIP to the User-mode Dispathcer */
153 Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
154 return;
155 }
156
157 /* FIXME: Forward the exception to the debugger */
158
159 /* FIXME: Forward the exception to the process exception port */
160
161 /* Enter KDB if available */
162 Action = KdpEnterDebuggerException(ExceptionRecord,
163 PreviousMode,
164 Context,
165 Tf,
166 FALSE,
167 FALSE);
168
169 /* Exit if we're continuing */
170 if (Action == kdContinue) return;
171
172 /* Terminate the offending thread */
173 DPRINT1("Unhandled UserMode exception, terminating thread\n");
174 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
175 }
176 else
177 {
178 /* This is Kernel Mode */
179
180 /* Enter KDB if available */
181 Action = KdpEnterDebuggerException(ExceptionRecord,
182 PreviousMode,
183 Context,
184 Tf,
185 TRUE,
186 FALSE);
187
188 /* Exit if we're continuing */
189 if (Action == kdContinue) return;
190
191 /* Dispatch the Exception */
192 Value = RtlpDispatchException (ExceptionRecord, Context);
193 DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
194
195 /* If RtlpDispatchException() did not handle the exception then bugcheck */
196 if (Value != ExceptionContinueExecution ||
197 0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE))
198 {
199 DPRINT("ExceptionRecord->ExceptionAddress = 0x%x\n", ExceptionRecord->ExceptionAddress);
200
201 /* Enter KDB if available */
202 Action = KdpEnterDebuggerException(ExceptionRecord,
203 PreviousMode,
204 Context,
205 Tf,
206 FALSE,
207 FALSE);
208
209 /* Exit if we're continuing */
210 if (Action == kdContinue) return;
211
212 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
213 ExceptionRecord->ExceptionCode,
214 (ULONG)ExceptionRecord->ExceptionAddress,
215 ExceptionRecord->ExceptionInformation[0],
216 ExceptionRecord->ExceptionInformation[1],
217 Tf);
218 }
219 }
220 }
221 }
222
223 /* EOF */