Call the correct user mode dispatch function in KiDispatchException. The bug was...
[reactos.git] / reactos / ntoskrnl / ke / catch.c
index 98b3c5a..c51765c 100644 (file)
 /*
- * COPYRIGHT:            See COPYING in the top level directory
- * PROJECT:              ReactOS kernel
- * FILE:                 ntoskrnl/ke/catch.c
- * PURPOSE:              Exception handling
- * PROGRAMMER:           David Welch (welch@mcmail.com)
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/ke/catch.c
+ * PURPOSE:         Exception handling
+ *
+ * PROGRAMMERS:     Anich Gregor
+ *                  David Welch (welch@mcmail.com)
+ *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <windows.h>
-#include <ddk/ntddk.h>
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <internal/debug.h>
 
 /* FUNCTIONS ****************************************************************/
 
-VOID ExRaiseStatus(NTSTATUS Status)
+ULONG
+RtlpDispatchException(IN PEXCEPTION_RECORD  ExceptionRecord,
+                      IN PCONTEXT  Context);
+
+/*
+ * @unimplemented
+ */
+VOID
+STDCALL
+KiCoprocessorError(VOID)
 {
-   DbgPrint("ExRaiseStatus(%d)\n",Status);
-   for(;;);
+    UNIMPLEMENTED;
 }
 
-
-NTSTATUS
+/*
+ * @unimplemented
+ */
+VOID
 STDCALL
-NtRaiseException(
-       IN PEXCEPTION_RECORD ExceptionRecord,
-       IN PCONTEXT Context,
-       IN BOOL IsDebugger OPTIONAL
-       )
+KiUnexpectedInterrupt(VOID)
 {
+    UNIMPLEMENTED;
 }
 
-NTSTATUS
-STDCALL
-ZwRaiseException(
-       IN PEXCEPTION_RECORD ExceptionRecord,
-       IN PCONTEXT Context,
-       IN BOOL IsDebugger OPTIONAL
-       )
+VOID
+KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
+                    PCONTEXT Context,
+                    PKTRAP_FRAME Tf,
+                    KPROCESSOR_MODE PreviousMode,
+                    BOOLEAN SearchFrames)
 {
+    EXCEPTION_DISPOSITION Value;
+    CONTEXT TContext;
+    KD_CONTINUE_TYPE Action = kdHandleException;
+
+    DPRINT("KiDispatchException() called\n");
+
+    /* Increase number of Exception Dispatches */
+    KeGetCurrentPrcb()->KeExceptionDispatchCount++;
+
+    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;
+        }
+
+        /* 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);
+
+    /* 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 */