update for HEAD-2003050101
[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 #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
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* FUNCTIONS ****************************************************************/
42
43 ULONG
44 RtlpDispatchException(IN PEXCEPTION_RECORD  ExceptionRecord,
45         IN PCONTEXT  Context);
46
47 VOID 
48 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
49                     PCONTEXT Context,
50                     PKTRAP_FRAME Tf,
51                     KPROCESSOR_MODE PreviousMode,
52                     BOOLEAN SearchFrames)
53 {
54   EXCEPTION_DISPOSITION Value;
55   CONTEXT TContext;
56   KD_CONTINUE_TYPE Action = kdContinue;
57
58   DPRINT("KiDispatchException() called\n");
59
60   /* PCR->KeExceptionDispatchCount++; */
61
62   if (Context == NULL)
63     {
64       TContext.ContextFlags = CONTEXT_FULL;
65       if (PreviousMode == UserMode)
66         {
67           TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
68         }
69   
70       KeTrapFrameToContext(Tf, &TContext);
71
72       Context = &TContext;
73     }
74
75 #if 0
76   if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) 
77     {
78       Context->Eip--;
79     }
80 #endif
81       
82   if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB)
83     {
84       Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf);
85     }
86 #ifdef KDBG
87   else if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_KDB)
88     {
89       Action = KdbEnterDebuggerException (ExceptionRecord, Context, Tf);
90     }
91 #endif /* KDBG */
92   if (Action != kdHandleException)
93     {
94       if (PreviousMode == UserMode)
95         {
96           if (SearchFrames)
97             {
98               PULONG Stack;
99               ULONG CDest;
100
101               /* FIXME: Forward exception to user mode debugger */
102
103               /* FIXME: Check user mode stack for enough space */
104           
105               /*
106                * Let usermode try and handle the exception
107                */
108               Tf->Esp = Tf->Esp - 
109                 (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT));
110               Stack = (PULONG)Tf->Esp;
111               CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
112               /* Return address */
113               Stack[0] = 0;    
114               /* Pointer to EXCEPTION_RECORD structure */
115               Stack[1] = (ULONG)&Stack[3];   
116               /* Pointer to CONTEXT structure */
117               Stack[2] = (ULONG)&Stack[CDest];     
118               memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
119               memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
120
121               Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
122               return;
123             }
124       
125           /* FIXME: Forward the exception to the debugger */
126
127           /* FIXME: Forward the exception to the process exception port */
128
129           /* Terminate the offending thread */
130           DPRINT1("Unhandled UserMode exception, terminating thread\n");
131           ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
132
133           /* If that fails then bugcheck */
134           DPRINT1("Could not terminate thread\n");
135           KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
136         }
137       else
138         {
139           /* PreviousMode == KernelMode */
140           Value = RtlpDispatchException (ExceptionRecord, Context);
141           
142           DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
143           /* 
144            * If RtlpDispatchException() does not handle the exception then 
145            * bugcheck 
146            */
147           if (Value != ExceptionContinueExecution ||
148               0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE))
149             {
150               KeBugCheckWithTf(KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf);          
151             }
152         }
153     }
154   else
155     {
156       KeContextToTrapFrame (Context, KeGetCurrentThread()->TrapFrame);
157     }
158 }
159
160 VOID STDCALL
161 ExRaiseAccessViolation (VOID)
162 {
163   ExRaiseStatus (STATUS_ACCESS_VIOLATION);
164 }
165
166 VOID STDCALL
167 ExRaiseDatatypeMisalignment (VOID)
168 {
169   ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
170 }
171
172 VOID STDCALL
173 ExRaiseStatus (IN NTSTATUS Status)
174 {
175   EXCEPTION_RECORD ExceptionRecord;
176
177   DPRINT("ExRaiseStatus(%x)\n", Status);
178
179   ExceptionRecord.ExceptionRecord = NULL;
180   ExceptionRecord.NumberParameters = 0;
181   ExceptionRecord.ExceptionCode = Status;
182   ExceptionRecord.ExceptionFlags = 0;
183
184   RtlRaiseException(&ExceptionRecord);
185 }
186
187
188 NTSTATUS STDCALL
189 NtRaiseException (IN PEXCEPTION_RECORD ExceptionRecord,
190                   IN PCONTEXT Context,
191                   IN BOOLEAN SearchFrames)
192 {
193   KiDispatchException(ExceptionRecord,
194                       Context,
195                       PsGetCurrentThread()->Tcb.TrapFrame,
196                       ExGetPreviousMode(),
197                       SearchFrames);
198   return(STATUS_SUCCESS);
199 }
200
201
202 VOID STDCALL
203 RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
204 {
205   ZwRaiseException(ExceptionRecord, NULL, TRUE);
206 }
207
208 /* EOF */