73e0e5c2102611da400a040c0fa8a26bdd888866
[reactos.git] / reactos / ntoskrnl / ke / catch.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2000 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: catch.c,v 1.44 2004/07/02 01:36:25 royce Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/catch.c
23 * PURPOSE: Exception handling
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * Casper S. Hornstrup (chorns@users.sourceforge.net)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <reactos/bugcodes.h>
32 #include <roscfg.h>
33 #include <internal/ke.h>
34 #include <internal/ldr.h>
35 #include <internal/ps.h>
36 #include <internal/kd.h>
37 #include <internal/safe.h>
38
39 #define NDEBUG
40 #include <internal/debug.h>
41
42 /* FUNCTIONS ****************************************************************/
43
44 ULONG
45 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
46 IN PCONTEXT Context);
47
48 VOID
49 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
50 PCONTEXT Context,
51 PKTRAP_FRAME Tf,
52 KPROCESSOR_MODE PreviousMode,
53 BOOLEAN SearchFrames)
54 {
55 EXCEPTION_DISPOSITION Value;
56 CONTEXT TContext;
57 KD_CONTINUE_TYPE Action = kdContinue;
58
59 DPRINT("KiDispatchException() called\n");
60
61 /* PCR->KeExceptionDispatchCount++; */
62
63 if (Context == NULL)
64 {
65 TContext.ContextFlags = CONTEXT_FULL;
66 if (PreviousMode == UserMode)
67 {
68 TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
69 }
70
71 KeTrapFrameToContext(Tf, &TContext);
72
73 Context = &TContext;
74 }
75
76 #if 0
77 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
78 {
79 Context->Eip--;
80 }
81 #endif
82
83 if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB)
84 {
85 Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf);
86 }
87 #ifdef KDBG
88 else if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_KDB)
89 {
90 Action = KdbEnterDebuggerException (ExceptionRecord, Context, Tf);
91 if (Action == kdContinue)
92 {
93 return;
94 }
95 }
96 #endif /* KDBG */
97 if (Action != kdHandleException)
98 {
99 if (PreviousMode == UserMode)
100 {
101 if (SearchFrames)
102 {
103 PULONG Stack;
104 ULONG CDest;
105 char temp_space[12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)]; // FIXME: HACKHACK
106 PULONG pNewUserStack = (PULONG)(Tf->Esp - (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)));
107 NTSTATUS StatusOfCopy;
108
109 /* FIXME: Forward exception to user mode debugger */
110
111 /* FIXME: Check user mode stack for enough space */
112
113 /*
114 * Let usermode try and handle the exception
115 */
116 Stack = (PULONG)temp_space;
117 CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
118 /* Return address */
119 Stack[0] = 0;
120 /* Pointer to EXCEPTION_RECORD structure */
121 Stack[1] = (ULONG)&pNewUserStack[3];
122 /* Pointer to CONTEXT structure */
123 Stack[2] = (ULONG)&pNewUserStack[CDest];
124 memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
125 memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
126
127 StatusOfCopy = MmCopyToCaller(pNewUserStack,
128 temp_space,
129 (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)));
130 if (NT_SUCCESS(StatusOfCopy))
131 {
132 Tf->Esp = (ULONG)pNewUserStack;
133 }
134 else
135 {
136 // Now it really hit the ventilation device. Sorry,
137 // can do nothing but kill the sucker.
138 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
139 DPRINT1("User-mode stack was invalid. Terminating target thread\nn");
140 }
141 Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
142 return;
143 }
144
145 /* FIXME: Forward the exception to the debugger */
146
147 /* FIXME: Forward the exception to the process exception port */
148
149 /* Terminate the offending thread */
150 DPRINT1("Unhandled UserMode exception, terminating thread\n");
151 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
152
153 /* If that fails then bugcheck */
154 DPRINT1("Could not terminate thread\n");
155 KEBUGCHECK(KMODE_EXCEPTION_NOT_HANDLED);
156 }
157 else
158 {
159 /* PreviousMode == KernelMode */
160 Value = RtlpDispatchException (ExceptionRecord, Context);
161
162 DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
163 /*
164 * If RtlpDispatchException() does not handle the exception then
165 * bugcheck
166 */
167 if (Value != ExceptionContinueExecution ||
168 0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE))
169 {
170 DPRINT("ExceptionRecord->ExceptionAddress = 0x%x\n",
171 ExceptionRecord->ExceptionAddress );
172 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf);
173 }
174 }
175 }
176 else
177 {
178 KeContextToTrapFrame (Context, KeGetCurrentThread()->TrapFrame);
179 }
180 }
181
182 /*
183 * @implemented
184 */
185 VOID STDCALL
186 ExRaiseAccessViolation (VOID)
187 {
188 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
189 }
190
191 /*
192 * @implemented
193 */
194 VOID STDCALL
195 ExRaiseDatatypeMisalignment (VOID)
196 {
197 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
198 }
199
200 /*
201 * @implemented
202 */
203 VOID STDCALL
204 ExRaiseStatus (IN NTSTATUS Status)
205 {
206 EXCEPTION_RECORD ExceptionRecord;
207
208 DPRINT("ExRaiseStatus(%x)\n", Status);
209
210 ExceptionRecord.ExceptionRecord = NULL;
211 ExceptionRecord.NumberParameters = 0;
212 ExceptionRecord.ExceptionCode = Status;
213 ExceptionRecord.ExceptionFlags = 0;
214
215 RtlRaiseException(&ExceptionRecord);
216 }
217
218
219 /*
220 * @unimplemented
221 */
222 VOID
223 STDCALL
224 ExRaiseException (
225 PEXCEPTION_RECORD pExcptRec
226 )
227 {
228 UNIMPLEMENTED;
229 }
230 /*
231 * @unimplemented
232 */
233 VOID
234 STDCALL
235 ExRaiseHardError (
236 IN NTSTATUS ErrorStatus,
237 IN ULONG NumberOfParameters,
238 IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL,
239 IN PVOID *Parameters,
240 IN HARDERROR_RESPONSE_OPTION ResponseOption,
241 OUT PHARDERROR_RESPONSE Response
242 )
243 {
244 UNIMPLEMENTED;
245 }
246
247
248 /*
249 * @unimplemented
250 */
251 BOOLEAN
252 STDCALL
253 ExSystemExceptionFilter()
254 {
255 UNIMPLEMENTED;
256 return FALSE;
257 }
258
259 VOID
260 FASTCALL
261 KeRosTrapReturn ( PKTRAP_FRAME TrapFrame, PKTRAP_FRAME PrevTrapFrame );
262
263 NTSTATUS STDCALL
264 NtRaiseException (IN PEXCEPTION_RECORD ExceptionRecord,
265 IN PCONTEXT Context,
266 IN BOOLEAN SearchFrames)
267 {
268 PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
269 PKTRAP_FRAME PrevTrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
270
271 KeGetCurrentKPCR()->Tib.ExceptionList = TrapFrame->ExceptionList;
272
273 KiDispatchException(ExceptionRecord,
274 Context,
275 PsGetCurrentThread()->Tcb.TrapFrame,
276 (KPROCESSOR_MODE)ExGetPreviousMode(),
277 SearchFrames);
278
279 KeRosTrapReturn ( TrapFrame, PrevTrapFrame );
280 return(STATUS_SUCCESS);
281 }
282
283 /*
284 * @unimplemented
285 */
286 STDCALL
287 BOOLEAN
288 KeDeregisterBugCheckReasonCallback(
289 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
290 )
291 {
292 UNIMPLEMENTED;
293 return FALSE;
294 }
295
296 /*
297 * @unimplemented
298 */
299 STDCALL
300 ULONG
301 KeGetRecommendedSharedDataAlignment(
302 VOID
303 )
304 {
305 UNIMPLEMENTED;
306 return 0;
307 }
308
309 /*
310 * @unimplemented
311 */
312 STDCALL
313 BOOLEAN
314 KeRegisterBugCheckReasonCallback(
315 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
316 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
317 IN KBUGCHECK_CALLBACK_REASON Reason,
318 IN PUCHAR Component
319 )
320 {
321 UNIMPLEMENTED;
322 return FALSE;
323 }
324
325 /*
326 * @implemented
327 */
328 VOID STDCALL
329 RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
330 {
331 ZwRaiseException(ExceptionRecord, NULL, TRUE);
332 }
333
334 /* EOF */