ExRaiseStatus() is now fatal back again as SEH is not needed for valid ops
[reactos.git] / 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$
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 #ifndef LIBCAPTIVE
32 #include <reactos/bugcodes.h>
33 #endif /* LIBCAPTIVE */
34 #include <roscfg.h>
35 #include <internal/ke.h>
36 #include <internal/ldr.h>
37 #include <internal/ps.h>
38 #include <internal/kd.h>
39
40 #define NDEBUG
41 #include <internal/debug.h>
42
43 /* FUNCTIONS ****************************************************************/
44
45 ULONG
46 RtlpDispatchException(IN PEXCEPTION_RECORD  ExceptionRecord,
47         IN PCONTEXT  Context);
48
49 VOID 
50 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
51                     PCONTEXT Context,
52                     PKTRAP_FRAME Tf,
53                     KPROCESSOR_MODE PreviousMode,
54                     BOOLEAN SearchFrames)
55 {
56   EXCEPTION_DISPOSITION Value;
57 #ifndef LIBCAPTIVE
58   CONTEXT TContext;
59 #endif /* LIBCAPTIVE */
60
61   DPRINT("KiDispatchException() called\n");
62
63   /* PCR->KeExceptionDispatchCount++; */
64
65 #ifndef LIBCAPTIVE
66   if (Context == NULL)
67     {
68       TContext.ContextFlags = CONTEXT_FULL;
69       if (PreviousMode == UserMode)
70         {
71           TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
72         }
73   
74       KeTrapFrameToContext(Tf, &TContext);
75
76       Context = &TContext;
77     }
78 #endif /* LIBCAPTIVE */
79
80 #if 0
81   if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) 
82     {
83       Context->Eip--;
84     }
85 #endif
86   if (PreviousMode == UserMode)
87     {
88 #ifdef LIBCAPTIVE
89       KeBugCheck(0);
90 #else /* !LIBCAPTIVE */
91       if (SearchFrames)
92         {
93           PULONG Stack;
94           ULONG CDest;
95
96           /* FIXME: Give the kernel debugger a chance */
97
98           /* FIXME: Forward exception to user mode debugger */
99
100           /* FIXME: Check user mode stack for enough space */
101
102           
103           /*
104            * Let usermode try and handle the exception
105            */
106           Tf->Esp = Tf->Esp - 
107             (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT));
108           Stack = (PULONG)Tf->Esp;
109           CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
110           /* Return address */
111           Stack[0] = 0;    
112           /* Pointer to EXCEPTION_RECORD structure */
113           Stack[1] = (ULONG)&Stack[3];   
114           /* Pointer to CONTEXT structure */
115           Stack[2] = (ULONG)&Stack[CDest];     
116           memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
117           memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
118
119           Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
120           return;
121         }
122       
123       /* FIXME: Forward the exception to the debugger */
124
125       /* FIXME: Forward the exception to the process exception port */
126
127       /* Terminate the offending thread */
128       ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
129
130       /* If that fails then bugcheck */
131       DbgPrint("Could not terminate thread\n");
132       KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
133 #endif /* LIBCAPTIVE */
134     }
135   else
136     {
137       KD_CONTINUE_TYPE Action = kdContinue;
138
139       /* PreviousMode == KernelMode */
140       
141 #ifndef LIBCAPTIVE
142       if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB)
143         {
144           Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf);
145         }
146 #ifdef KDBG
147       else if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_KDB)
148         {
149           Action = KdbEnterDebuggerException (ExceptionRecord, Context, Tf);
150         }
151 #endif /* KDBG */
152 #endif /* LIBCAPTIVE */
153       if (Action != kdHandleException)
154         {
155           Value = RtlpDispatchException (ExceptionRecord, Context);
156           
157           DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
158           /* 
159            * If RtlpDispatchException() does not handle the exception then 
160            * bugcheck 
161            */
162           if (Value != ExceptionContinueExecution)
163             {
164 #ifndef LIBCAPTIVE
165               KeBugCheck (KMODE_EXCEPTION_NOT_HANDLED);       
166 #else /* !LIBCAPTIVE */
167               KeBugCheck (0);         
168 #endif /* LIBCAPTIVE */
169             }
170         }
171       else
172         {
173 #ifndef LIBCAPTIVE
174           KeContextToTrapFrame (Context, KeGetCurrentThread()->TrapFrame);
175 #else /* !LIBCAPTIVE */
176           KeBugCheck(0);
177 #endif /* LIBCAPTIVE */
178         }
179     }
180 }
181
182 #ifndef LIBCAPTIVE
183
184 VOID STDCALL
185 ExRaiseAccessViolation (VOID)
186 {
187   ExRaiseStatus (STATUS_ACCESS_VIOLATION);
188 }
189
190 VOID STDCALL
191 ExRaiseDatatypeMisalignment (VOID)
192 {
193   ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
194 }
195
196 VOID STDCALL
197 ExRaiseStatus (IN NTSTATUS Status)
198 {
199   EXCEPTION_RECORD ExceptionRecord;
200
201   DPRINT("ExRaiseStatus(%x)\n", Status);
202
203   ExceptionRecord.ExceptionRecord = NULL;
204   ExceptionRecord.NumberParameters = 0;
205   ExceptionRecord.ExceptionCode = Status;
206   ExceptionRecord.ExceptionFlags = 0;
207
208   RtlRaiseException(&ExceptionRecord);
209 }
210
211 #endif /* LIBCAPTIVE */
212
213 NTSTATUS STDCALL
214 NtRaiseException (IN PEXCEPTION_RECORD ExceptionRecord,
215                   IN PCONTEXT Context,
216                   IN BOOLEAN SearchFrames)
217 {
218   KiDispatchException(ExceptionRecord,
219                       Context,
220                       PsGetCurrentThread()->Tcb.TrapFrame,
221 #ifndef LIBCAPTIVE
222                       ExGetPreviousMode(),
223 #else /* !LIBCAPTIVE */
224                       KernelMode,
225 #endif /* LIBCAPTIVE */
226                       SearchFrames);
227   return(STATUS_SUCCESS);
228 }
229
230
231 VOID STDCALL
232 RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
233 {
234 #ifndef LIBCAPTIVE
235   ZwRaiseException(ExceptionRecord, NULL, TRUE);
236 #else /* !LIBCAPTIVE */
237 CONTEXT *LocalContext;
238
239   /* Do not use local variable to benefit from ElectricFence boundary checks */
240   LocalContext=ExAllocatePool(PagedPool,sizeof(LocalContext->ContextFlags));
241   LocalContext->ContextFlags=0;
242
243   NtRaiseException(ExceptionRecord, LocalContext, TRUE);
244
245   ExFreePool(LocalContext);
246 #endif /* LIBCAPTIVE */
247 }
248
249 /* EOF */