Call the correct user mode dispatch function in KiDispatchException. The bug was...
[reactos.git] / reactos / ntoskrnl / ke / catch.c
index 0adfe99..c51765c 100644 (file)
 /*
- *  ReactOS kernel
- *  Copyright (C) 2000  ReactOS Team
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/ke/catch.c
+ * PURPOSE:         Exception handling
  *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id: catch.c,v 1.13 2001/03/18 19:35:12 dwelch Exp $
- *
- * PROJECT:              ReactOS kernel
- * FILE:                 ntoskrnl/ke/catch.c
- * PURPOSE:              Exception handling
- * PROGRAMMER:           David Welch (welch@mcmail.com)
+ * PROGRAMMERS:     Anich Gregor
+ *                  David Welch (welch@mcmail.com)
+ *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/ke.h>
-#include <internal/ldr.h>
-#include <internal/ps.h>
-
+#include <ntoskrnl.h>
+#define NDEBUG
 #include <internal/debug.h>
 
 /* FUNCTIONS ****************************************************************/
 
-VOID 
-KiDispatchException(PEXCEPTION_RECORD Er,
-                   PCONTEXT Context,
-                   PKTRAP_FRAME Tf,
-                   KPROCESSOR_MODE PreviousMode,
-                   BOOLEAN SearchFrames)
-{
-  CONTEXT TContext;
-
-  /* PCR->KeExceptionDispatchCount++; */
+ULONG
+RtlpDispatchException(IN PEXCEPTION_RECORD  ExceptionRecord,
+                      IN PCONTEXT  Context);
 
-  if (Context != NULL)
-    {
-      TContext.ContextFlags = CONTEXT_FULL;
-      if (PreviousMode == UserMode)
-       {
-         TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
-       }
-  
-      KeTrapFrameToContext(Tf, &TContext);
-
-      Context = &TContext;
-    }
-
-  if (Er->ExceptionCode == STATUS_BREAKPOINT) 
-    {
-      Context->Eip--;
-    }
-
-  if (PreviousMode == UserMode)
-    {
-      if (SearchFrames)
-       {
-         PULONG Stack;
-         ULONG CDest;
-
-         /* FIXME: Give the kernel debugger a chance */
-
-         /* FIXME: Forward exception to user mode debugger */
-
-         /* FIXME: Check user mode stack for enough space */
-
-         
-         /*
-          * Let usermode try and handle the exception
-          */
-         Tf->Esp = Tf->Esp - 
-           (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT));
-         Stack = (PULONG)Tf->Esp;
-         CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
-         /* Return address */
-         Stack[0] = 0;    
-         /* Pointer to EXCEPTION_RECORD structure */
-         Stack[1] = (ULONG)&Stack[3];   
-         /* Pointer to CONTEXT structure */
-         Stack[2] = (ULONG)&Stack[CDest];     
-         memcpy(&Stack[3], Er, sizeof(EXCEPTION_RECORD));
-         memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
-
-         Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher();
-         return;
-       }
-      
-      /* FIXME: Forward the exception to the debugger */
-
-      /* FIXME: Forward the exception to the process exception port */
-
-      /* Terminate the offending thread */
-      ZwTerminateThread(NtCurrentThread(), Er->ExceptionCode);
-
-      /* If that fails then bugcheck */
-      KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
-    }
-  else
-    {
-      KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
-    }
-}
-
-VOID STDCALL
-ExRaiseAccessViolation (VOID)
+/*
+ * @unimplemented
+ */
+VOID
+STDCALL
+KiCoprocessorError(VOID)
 {
-  ExRaiseStatus (STATUS_ACCESS_VIOLATION);
+    UNIMPLEMENTED;
 }
 
-VOID STDCALL
-ExRaiseDatatypeMisalignment (VOID)
+/*
+ * @unimplemented
+ */
+VOID
+STDCALL
+KiUnexpectedInterrupt(VOID)
 {
-  ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
+    UNIMPLEMENTED;
 }
 
-VOID STDCALL
-ExRaiseStatus (IN NTSTATUS Status)
+VOID
+KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
+                    PCONTEXT Context,
+                    PKTRAP_FRAME Tf,
+                    KPROCESSOR_MODE PreviousMode,
+                    BOOLEAN SearchFrames)
 {
-  DbgPrint("ExRaiseStatus(%x)\n",Status);
-  for(;;);
-}
+    EXCEPTION_DISPOSITION Value;
+    CONTEXT TContext;
+    KD_CONTINUE_TYPE Action = kdHandleException;
 
+    DPRINT("KiDispatchException() called\n");
 
+    /* Increase number of Exception Dispatches */
+    KeGetCurrentPrcb()->KeExceptionDispatchCount++;
 
-NTSTATUS STDCALL
-NtRaiseException (IN PEXCEPTION_RECORD ExceptionRecord,
-                 IN PCONTEXT Context,
-                 IN BOOLEAN SearchFrames)
-{
-  KiDispatchException(ExceptionRecord,
-                     Context,
-                     PsGetCurrentThread()->Tcb.TrapFrame,
-                     ExGetPreviousMode(),
-                     SearchFrames);
-  return(STATUS_SUCCESS);
-}
+    if (!Context)
+    {
+        /* Assume Full context */
+        TContext.ContextFlags = CONTEXT_FULL;
 
+        /* Check the mode */
+        if (PreviousMode != KernelMode)
+        {
+            /* Add Debugger Registers if this is User Mode */
+            TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER;
+        }
 
-VOID STDCALL
-RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
-{
+        /* Convert the Trapframe into a Context */
+        KeTrapFrameToContext(Tf, &TContext);
 
-}
+        /* Use local stack context */
+        Context = &TContext;
+    }
 
+    /* Break into Debugger */
+    Action = KdpEnterDebuggerException(ExceptionRecord,
+                                       PreviousMode,
+                                       Context,
+                                       Tf,
+                                       TRUE,
+                                       TRUE);
 
-VOID STDCALL
-RtlUnwind(ULONG Unknown1,
-         ULONG Unknown2,
-         ULONG Unknown3,
-         ULONG Unknown4)
-{
+    /* If the debugger said continue, then continue */
+    if (Action == kdContinue) return;
 
+    /* If the Debugger couldn't handle it... */
+    if (Action != kdDoNotHandleException)
+    {
+        /* See what kind of Exception this is */
+        if (PreviousMode != KernelMode)
+        {
+            /* User mode exception, search the frames if we have to */
+            if (SearchFrames)
+            {
+                PULONG Stack;
+                ULONG CDest;
+                char temp_space[12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)]; /* FIXME: HACKHACK */
+                PULONG pNewUserStack = (PULONG)(Tf->Esp - (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)));
+                NTSTATUS Status = STATUS_SUCCESS;
+
+                /* Enter Debugger if available */
+                Action = KdpEnterDebuggerException(ExceptionRecord,
+                                                   PreviousMode,
+                                                   Context,
+                                                   Tf,
+                                                   TRUE,
+                                                   FALSE);
+
+                /* Exit if we're continuing */
+                if (Action == kdContinue) return;
+
+                /* FIXME: Forward exception to user mode debugger */
+
+                /* FIXME: Check user mode stack for enough space */
+
+                /* Let usermode try and handle the exception. Setup Stack */
+                Stack = (PULONG)temp_space;
+                CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4);
+                /* Return Address */
+                Stack[0] = 0;
+                /* Pointer to EXCEPTION_RECORD structure */
+                Stack[1] = (ULONG)&pNewUserStack[3];
+                /* Pointer to CONTEXT structure */
+                Stack[2] = (ULONG)&pNewUserStack[CDest];
+                memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD));
+                memcpy(&Stack[CDest], Context, sizeof(CONTEXT));
+
+                /* Copy Stack */
+                _SEH_TRY
+                {
+                    ProbeForWrite(pNewUserStack,
+                                  12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT),
+                                  1);
+                    RtlCopyMemory(pNewUserStack,
+                                  temp_space,
+                                  12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT));
+                }
+                _SEH_HANDLE
+                {
+                    Status = _SEH_GetExceptionCode();
+                }
+                _SEH_END;
+
+                /* Check for success */
+                if (NT_SUCCESS(Status))
+                {
+                    /* Set new Stack Pointer */
+                    Tf->Esp = (ULONG)pNewUserStack;
+                }
+                else
+                {
+                    /*
+                     * Now it really hit the ventilation device. Sorry,
+                     * can do nothing but kill the sucker.
+                     */
+                    ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
+                    DPRINT1("User-mode stack was invalid. Terminating target thread\n");
+                }
+                /* Set EIP to the User-mode Dispathcer */
+                Tf->Eip = (ULONG)KeUserExceptionDispatcher;
+                return;
+            }
+
+            /* FIXME: Forward the exception to the debugger */
+
+            /* FIXME: Forward the exception to the process exception port */
+
+            /* Enter KDB if available */
+            Action = KdpEnterDebuggerException(ExceptionRecord,
+                                                PreviousMode,
+                                                Context,
+                                                Tf,
+                                                FALSE,
+                                                FALSE);
+
+            /* Exit if we're continuing */
+            if (Action == kdContinue) return;
+
+            /* Terminate the offending thread */
+            DPRINT1("Unhandled UserMode exception, terminating thread\n");
+            ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
+        }
+        else
+        {
+            /* This is Kernel Mode */
+
+            /* Enter KDB if available */
+            Action = KdpEnterDebuggerException(ExceptionRecord,
+                                                PreviousMode,
+                                                Context,
+                                                Tf,
+                                                TRUE,
+                                                FALSE);
+
+            /* Exit if we're continuing */
+            if (Action == kdContinue) return;
+
+            /* Dispatch the Exception */
+            Value = RtlpDispatchException (ExceptionRecord, Context);
+            DPRINT("RtlpDispatchException() returned with 0x%X\n", Value);
+
+            /* If RtlpDispatchException() did not handle the exception then bugcheck */
+            if (Value != ExceptionContinueExecution ||
+                0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE))
+            {
+                DPRINT("ExceptionRecord->ExceptionAddress = 0x%p\n", ExceptionRecord->ExceptionAddress);
+
+                /* Enter KDB if available */
+                Action = KdpEnterDebuggerException(ExceptionRecord,
+                                                   PreviousMode,
+                                                   Context,
+                                                   Tf,
+                                                   FALSE,
+                                                   FALSE);
+
+                /* Exit if we're continuing */
+                if (Action == kdContinue) return;
+
+                KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
+                                 ExceptionRecord->ExceptionCode,
+                                 (ULONG)ExceptionRecord->ExceptionAddress,
+                                 ExceptionRecord->ExceptionInformation[0],
+                                 ExceptionRecord->ExceptionInformation[1],
+                                 Tf);
+            }
+        }
+    }
 }
 
 /* EOF */