Fix handling of breakpoint exceptions in KDB.
[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.56 2004/12/18 19:22:10 blight 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 <ntoskrnl.h>
31 #define NDEBUG
32 #include <internal/debug.h>
33
34 /* FUNCTIONS ****************************************************************/
35
36 ULONG
37 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
38 IN PCONTEXT Context);
39
40 VOID
41 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
42 PCONTEXT Context,
43 PKTRAP_FRAME Tf,
44 KPROCESSOR_MODE PreviousMode,
45 BOOLEAN SearchFrames)
46 {
47 EXCEPTION_DISPOSITION Value;
48 CONTEXT TContext;
49 KD_CONTINUE_TYPE Action = kdHandleException;
50
51 DPRINT("KiDispatchException() called\n");
52
53 /* PCR->KeExceptionDispatchCount++; */
54
55 if (Context == NULL)
56 {
57 TContext.ContextFlags = CONTEXT_FULL;
58 if (PreviousMode == UserMode)
59 {
60 TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
61 }
62
63 KeTrapFrameToContext(Tf, &TContext);
64
65 Context = &TContext;
66 }
67
68 #if 0
69 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
70 {
71 Context->Eip--;
72 }
73 #endif
74
75 if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB)
76 {
77 Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf);
78 }
79
80 if (Action == kdContinue)
81 {
82 return;
83 }
84
85 if (Action != kdDoNotHandleException)
86 {
87 if (PreviousMode == UserMode)
88 {
89 if (SearchFrames)
90 {
91 PULONG Stack;
92 ULONG CDest;
93 char temp_space[12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)]; /* FIXME: HACKHACK */
94 PULONG pNewUserStack = (PULONG)(Tf->Esp - (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)));
95 NTSTATUS StatusOfCopy;
96
97 #ifdef KDBG
98 KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
99 Context, Tf, FALSE);
100 #endif
101
102 /* FIXME: Forward exception to user mode debugger */
103
104 /* FIXME: Check user mode stack for enough space */
105
106 /*
107 * Let usermode try and handle the exception
108 */
109 Stack = (PULONG)temp_space;
110 CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
111 /* Return address */
112 Stack[0] = 0;
113 /* Pointer to EXCEPTION_RECORD structure */
114 Stack[1] = (ULONG)&pNewUserStack[3];
115 /* Pointer to CONTEXT structure */
116 Stack[2] = (ULONG)&pNewUserStack[CDest];
117 memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
118 memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
119
120 StatusOfCopy = MmCopyToCaller(pNewUserStack,
121 temp_space,
122 (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)));
123 if (NT_SUCCESS(StatusOfCopy))
124 {
125 Tf->Esp = (ULONG)pNewUserStack;
126 }
127 else
128 {
129 /* Now it really hit the ventilation device. Sorry,
130 * can do nothing but kill the sucker.
131 */
132 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
133 DPRINT1("User-mode stack was invalid. Terminating target thread\n");
134 }
135 Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
136 return;
137 }
138
139 /* FIXME: Forward the exception to the debugger */
140
141 /* FIXME: Forward the exception to the process exception port */
142
143 #ifdef KDBG
144 KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
145 Context, Tf, TRUE);
146 #endif
147
148 /* Terminate the offending thread */
149 DPRINT1("Unhandled UserMode exception, terminating thread\n");
150 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
151 }
152 else
153 {
154 /* PreviousMode == KernelMode */
155 #ifdef KDBG
156 KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
157 Context, Tf, FALSE);
158 #endif
159
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 #ifdef KDBG
173 Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
174 Context, Tf, TRUE);
175 if (Action == kdContinue)
176 {
177 return;
178 }
179 #endif
180 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf);
181 }
182 }
183 }
184 }
185
186 /*
187 * @implemented
188 */
189 VOID STDCALL
190 ExRaiseAccessViolation (VOID)
191 {
192 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
193 }
194
195 /*
196 * @implemented
197 */
198 VOID STDCALL
199 ExRaiseDatatypeMisalignment (VOID)
200 {
201 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
202 }
203
204 /*
205 * @implemented
206 */
207 VOID STDCALL
208 ExRaiseStatus (IN NTSTATUS Status)
209 {
210 EXCEPTION_RECORD ExceptionRecord;
211
212 DPRINT("ExRaiseStatus(%x)\n", Status);
213
214 ExceptionRecord.ExceptionRecord = NULL;
215 ExceptionRecord.NumberParameters = 0;
216 ExceptionRecord.ExceptionCode = Status;
217 ExceptionRecord.ExceptionFlags = 0;
218
219 RtlRaiseException(&ExceptionRecord);
220 }
221
222
223
224 /*
225 * @implemented
226 */
227 VOID
228 STDCALL
229 ExRaiseException (
230 PEXCEPTION_RECORD ExceptionRecord
231 )
232 {
233 RtlRaiseException(ExceptionRecord);
234 }
235
236 /*
237 * @implemented
238 */
239 BOOLEAN
240 STDCALL
241 ExSystemExceptionFilter(VOID)
242 {
243 return KeGetPreviousMode() != KernelMode ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
244 }
245
246 /*
247 * @unimplemented
248 */
249 VOID
250 STDCALL
251 ExRaiseHardError (
252 IN NTSTATUS ErrorStatus,
253 IN ULONG NumberOfParameters,
254 IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL,
255 IN PVOID *Parameters,
256 IN HARDERROR_RESPONSE_OPTION ResponseOption,
257 OUT PHARDERROR_RESPONSE Response
258 )
259 {
260 UNIMPLEMENTED;
261 }
262
263 /*
264 * @unimplemented
265 */
266 BOOLEAN
267 STDCALL
268 KeDeregisterBugCheckReasonCallback(
269 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
270 )
271 {
272 UNIMPLEMENTED;
273 return FALSE;
274 }
275
276 /*
277 * @unimplemented
278 */
279 ULONG
280 STDCALL
281 KeGetRecommendedSharedDataAlignment(
282 VOID
283 )
284 {
285 UNIMPLEMENTED;
286 return 0;
287 }
288
289 /*
290 * @unimplemented
291 */
292 BOOLEAN
293 STDCALL
294 KeRegisterBugCheckReasonCallback(
295 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
296 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
297 IN KBUGCHECK_CALLBACK_REASON Reason,
298 IN PUCHAR Component
299 )
300 {
301 UNIMPLEMENTED;
302 return FALSE;
303 }
304
305 /* EOF */