- use inlined probing macros for basic types
[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 != KernelMode)
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 != KernelMode)
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 Status = STATUS_SUCCESS;
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 _SEH_TRY
134 {
135 ProbeForWrite(pNewUserStack,
136 12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT),
137 1);
138 RtlCopyMemory(pNewUserStack,
139 temp_space,
140 12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT));
141 }
142 _SEH_HANDLE
143 {
144 Status = _SEH_GetExceptionCode();
145 }
146 _SEH_END;
147
148 /* Check for success */
149 if (NT_SUCCESS(Status))
150 {
151 /* Set new Stack Pointer */
152 Tf->Esp = (ULONG)pNewUserStack;
153 }
154 else
155 {
156 /*
157 * Now it really hit the ventilation device. Sorry,
158 * can do nothing but kill the sucker.
159 */
160 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
161 DPRINT1("User-mode stack was invalid. Terminating target thread\n");
162 }
163 /* Set EIP to the User-mode Dispathcer */
164 Tf->Eip = (ULONG)KeRaiseUserExceptionDispatcher;
165 return;
166 }
167
168 /* FIXME: Forward the exception to the debugger */
169
170 /* FIXME: Forward the exception to the process exception port */
171
172 /* Enter KDB if available */
173 Action = KdpEnterDebuggerException(ExceptionRecord,
174 PreviousMode,
175 Context,
176 Tf,
177 FALSE,
178 FALSE);
179
180 /* Exit if we're continuing */
181 if (Action == kdContinue) return;
182
183 /* Terminate the offending thread */
184 DPRINT1("Unhandled UserMode exception, terminating thread\n");
185 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
186 }
187 else
188 {
189 /* This is Kernel Mode */
190
191 /* Enter KDB if available */
192 Action = KdpEnterDebuggerException(ExceptionRecord,
193 PreviousMode,
194 Context,
195 Tf,
196 TRUE,
197 FALSE);
198
199 /* Exit if we're continuing */
200 if (Action == kdContinue) return;
201
202 /* Dispatch the Exception */
203 Value = RtlpDispatchException (ExceptionRecord, Context);
204 DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
205
206 /* If RtlpDispatchException() did not handle the exception then bugcheck */
207 if (Value != ExceptionContinueExecution ||
208 0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE))
209 {
210 DPRINT("ExceptionRecord->ExceptionAddress = 0x%p\n", ExceptionRecord->ExceptionAddress);
211
212 /* Enter KDB if available */
213 Action = KdpEnterDebuggerException(ExceptionRecord,
214 PreviousMode,
215 Context,
216 Tf,
217 FALSE,
218 FALSE);
219
220 /* Exit if we're continuing */
221 if (Action == kdContinue) return;
222
223 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
224 ExceptionRecord->ExceptionCode,
225 (ULONG)ExceptionRecord->ExceptionAddress,
226 ExceptionRecord->ExceptionInformation[0],
227 ExceptionRecord->ExceptionInformation[1],
228 Tf);
229 }
230 }
231 }
232 }
233
234 /* EOF */