efa873ec7f62c9473beedf7b4fd3c90eb2a39f4f
[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.38 2003/12/14 19:43:09 navaraf 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 }
92 #endif /* KDBG */
93 if (Action != kdHandleException)
94 {
95 if (PreviousMode == UserMode)
96 {
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 /* FIXME: Forward exception to user mode debugger */
106
107 /* FIXME: Check user mode stack for enough space */
108
109 /*
110 * Let usermode try and handle the exception
111 */
112 Stack = (PULONG)temp_space;
113 CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
114 /* Return address */
115 Stack[0] = 0;
116 /* Pointer to EXCEPTION_RECORD structure */
117 Stack[1] = (ULONG)&pNewUserStack[3];
118 /* Pointer to CONTEXT structure */
119 Stack[2] = (ULONG)&pNewUserStack[CDest];
120 memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
121 memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
122
123 StatusOfCopy = MmCopyToCaller(pNewUserStack,
124 temp_space,
125 (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)));
126 if (NT_SUCCESS(StatusOfCopy))
127 {
128 Tf->Esp = (ULONG)pNewUserStack;
129 }
130 else
131 {
132 // Now it really hit the ventilation device. Sorry,
133 // can do nothing but kill the sucker.
134 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
135 DPRINT1("User-mode stack was invalid. Terminating target thread\nn");
136 }
137 Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
138 return;
139 }
140
141 /* FIXME: Forward the exception to the debugger */
142
143 /* FIXME: Forward the exception to the process exception port */
144
145 /* Terminate the offending thread */
146 DPRINT1("Unhandled UserMode exception, terminating thread\n");
147 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
148
149 /* If that fails then bugcheck */
150 DPRINT1("Could not terminate thread\n");
151 KEBUGCHECK(KMODE_EXCEPTION_NOT_HANDLED);
152 }
153 else
154 {
155 /* PreviousMode == KernelMode */
156 Value = RtlpDispatchException (ExceptionRecord, Context);
157
158 DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
159 /*
160 * If RtlpDispatchException() does not handle the exception then
161 * bugcheck
162 */
163 if (Value != ExceptionContinueExecution ||
164 0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE))
165 {
166 DbgPrint("ExceptionRecord->ExceptionAddress = 0x%x\n",
167 ExceptionRecord->ExceptionAddress );
168 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf);
169 }
170 }
171 }
172 else
173 {
174 KeContextToTrapFrame (Context, KeGetCurrentThread()->TrapFrame);
175 }
176 }
177
178 /*
179 * @implemented
180 */
181 VOID STDCALL
182 ExRaiseAccessViolation (VOID)
183 {
184 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
185 }
186
187 /*
188 * @implemented
189 */
190 VOID STDCALL
191 ExRaiseDatatypeMisalignment (VOID)
192 {
193 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
194 }
195
196 /*
197 * @implemented
198 */
199 VOID STDCALL
200 ExRaiseStatus (IN NTSTATUS Status)
201 {
202 EXCEPTION_RECORD ExceptionRecord;
203
204 DPRINT("ExRaiseStatus(%x)\n", Status);
205
206 ExceptionRecord.ExceptionRecord = NULL;
207 ExceptionRecord.NumberParameters = 0;
208 ExceptionRecord.ExceptionCode = Status;
209 ExceptionRecord.ExceptionFlags = 0;
210
211 RtlRaiseException(&ExceptionRecord);
212 }
213
214
215 NTSTATUS STDCALL
216 NtRaiseException (IN PEXCEPTION_RECORD ExceptionRecord,
217 IN PCONTEXT Context,
218 IN BOOLEAN SearchFrames)
219 {
220 KiDispatchException(ExceptionRecord,
221 Context,
222 PsGetCurrentThread()->Tcb.TrapFrame,
223 ExGetPreviousMode(),
224 SearchFrames);
225 return(STATUS_SUCCESS);
226 }
227
228
229 /*
230 * @implemented
231 */
232 VOID STDCALL
233 RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
234 {
235 ZwRaiseException(ExceptionRecord, NULL, TRUE);
236 }
237
238 /* EOF */