f399743dd14967784367e60db822ab8c853c3f43
[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   KD_CONTINUE_TYPE Action = kdContinue;
61
62   DPRINT("KiDispatchException() called\n");
63
64   /* PCR->KeExceptionDispatchCount++; */
65
66 #ifndef LIBCAPTIVE
67   if (Context == NULL)
68     {
69       TContext.ContextFlags = CONTEXT_FULL;
70       if (PreviousMode == UserMode)
71         {
72           TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
73         }
74   
75       KeTrapFrameToContext(Tf, &TContext);
76
77       Context = &TContext;
78     }
79 #endif /* LIBCAPTIVE */
80
81 #if 0
82   if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) 
83     {
84       Context->Eip--;
85     }
86 #endif
87       
88 #ifndef LIBCAPTIVE
89   if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB)
90     {
91       Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf);
92     }
93 #ifdef KDBG
94   else if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_KDB)
95     {
96       Action = KdbEnterDebuggerException (ExceptionRecord, Context, Tf);
97     }
98 #endif /* KDBG */
99 #endif /* LIBCAPTIVE */
100   if (Action != kdHandleException)
101     {
102       if (PreviousMode == UserMode)
103         {
104 #ifdef LIBCAPTIVE
105           KeBugCheck (0);             
106 #else /* !LIBCAPTIVE */
107           if (SearchFrames)
108             {
109               PULONG Stack;
110               ULONG CDest;
111
112               /* FIXME: Forward exception to user mode debugger */
113
114               /* FIXME: Check user mode stack for enough space */
115           
116               /*
117                * Let usermode try and handle the exception
118                */
119               Tf->Esp = Tf->Esp - 
120                 (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT));
121               Stack = (PULONG)Tf->Esp;
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)&Stack[3];   
127               /* Pointer to CONTEXT structure */
128               Stack[2] = (ULONG)&Stack[CDest];     
129               memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
130               memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
131
132               Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
133               return;
134             }
135       
136           /* FIXME: Forward the exception to the debugger */
137
138           /* FIXME: Forward the exception to the process exception port */
139
140           /* Terminate the offending thread */
141           DPRINT1("Unhandled UserMode exception, terminating thread\n");
142           ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
143
144           /* If that fails then bugcheck */
145           DPRINT1("Could not terminate thread\n");
146           KEBUGCHECK(KMODE_EXCEPTION_NOT_HANDLED);
147 #endif /* LIBCAPTIVE */
148         }
149       else
150         {
151           /* PreviousMode == KernelMode */
152           Value = RtlpDispatchException (ExceptionRecord, Context);
153           
154           DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
155           /* 
156            * If RtlpDispatchException() does not handle the exception then 
157            * bugcheck 
158            */
159           if (Value != ExceptionContinueExecution ||
160               0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE))
161             {
162                   DbgPrint("ExceptionRecord->ExceptionAddress = 0x%x\n",
163                           ExceptionRecord->ExceptionAddress );
164 #ifndef LIBCAPTIVE
165               KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf);          
166 #else /* !LIBCAPTIVE */
167               KEBUGCHECK (0);         
168 #endif /* LIBCAPTIVE */
169             }
170         }
171     }
172   else
173     {
174 #ifndef LIBCAPTIVE
175       KeContextToTrapFrame (Context, KeGetCurrentThread()->TrapFrame);
176 #else /* !LIBCAPTIVE */
177       KeBugCheck(0);
178 #endif /* LIBCAPTIVE */
179     }
180 }
181
182 #ifndef LIBCAPTIVE
183
184 /*
185  * @implemented
186  */
187 VOID STDCALL
188 ExRaiseAccessViolation (VOID)
189 {
190   ExRaiseStatus (STATUS_ACCESS_VIOLATION);
191 }
192
193 /*
194  * @implemented
195  */
196 VOID STDCALL
197 ExRaiseDatatypeMisalignment (VOID)
198 {
199   ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
200 }
201
202 #endif /* LIBCAPTIVE */
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 NTSTATUS STDCALL
223 NtRaiseException (IN PEXCEPTION_RECORD ExceptionRecord,
224                   IN PCONTEXT Context,
225                   IN BOOLEAN SearchFrames)
226 {
227   KiDispatchException(ExceptionRecord,
228                       Context,
229                       PsGetCurrentThread()->Tcb.TrapFrame,
230 #ifndef LIBCAPTIVE
231                       ExGetPreviousMode(),
232 #else /* !LIBCAPTIVE */
233                       KernelMode,
234 #endif /* LIBCAPTIVE */
235                       SearchFrames);
236   return(STATUS_SUCCESS);
237 }
238
239
240 /*
241  * @implemented
242  */
243 VOID STDCALL
244 RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
245 {
246 #ifndef LIBCAPTIVE
247   ZwRaiseException(ExceptionRecord, NULL, TRUE);
248 #else /* !LIBCAPTIVE */
249 CONTEXT *LocalContext;
250
251   /* Do not use local variable to benefit from ElectricFence boundary checks */
252   LocalContext=ExAllocatePool(PagedPool,sizeof(LocalContext->ContextFlags));
253   LocalContext->ContextFlags=0;
254
255   NtRaiseException(ExceptionRecord, LocalContext, TRUE);
256
257   ExFreePool(LocalContext);
258 #endif /* LIBCAPTIVE */
259 }
260
261 /* EOF */