- Use _SEH2_YIELD when returning from an exception instead of returning outside the...
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
index 8a33723..6ee3c74 100644 (file)
@@ -46,22 +46,6 @@ UCHAR KiDebugRegisterTrapOffsets[9] =
 
 /* FUNCTIONS *****************************************************************/
 
-_SEH_DEFINE_LOCALS(KiCopyInfo)
-{
-    volatile EXCEPTION_RECORD SehExceptRecord;
-};
-
-_SEH_FILTER(KiCopyInformation)
-{
-    _SEH_ACCESS_LOCALS(KiCopyInfo);
-
-    /* Copy the exception records and return to the handler */
-    RtlCopyMemory((PVOID)&_SEH_VAR(SehExceptRecord),
-                  _SEH_GetExceptionPointers()->ExceptionRecord,
-                  sizeof(EXCEPTION_RECORD));
-    return EXCEPTION_EXECUTE_HANDLER;
-}
-
 VOID
 INIT_FUNCTION
 NTAPI
@@ -72,7 +56,7 @@ KeInitExceptions(VOID)
     extern KIDTENTRY KiIdt[MAXIMUM_IDTVECTOR];
 
     /* Loop the IDT */
-    for (i = 0; i <= MAXIMUM_IDTVECTOR; i ++)
+    for (i = 0; i <= MAXIMUM_IDTVECTOR; i++)
     {
         /* Save the current Selector */
         FlippedSelector = KiIdt[i].Selector;
@@ -90,7 +74,7 @@ KiUpdateDr7(IN ULONG Dr7)
     ULONG DebugMask = KeGetCurrentThread()->DispatcherHeader.DebugActive;
 
     /* Check if debugging is enabled */
-    if (DebugMask & DR_ACTIVE_MASK)
+    if (DebugMask & DR_MASK(DR7_OVERRIDE_V))
     {
         /* Sanity checks */
         ASSERT((DebugMask & DR_REG_MASK) != 0);
@@ -113,7 +97,7 @@ KiRecordDr7(OUT PULONG Dr7Ptr,
     /* Check if the caller gave us a mask */
     if (!DrMask)
     {
-        /* He didn't use the one from the thread */
+        /* He didn't, use the one from the thread */
         Mask = KeGetCurrentThread()->DispatcherHeader.DebugActive;
     }
     else
@@ -133,14 +117,14 @@ KiRecordDr7(OUT PULONG Dr7Ptr,
         Result = FALSE;
 
         /* Check the DR mask */
-        NewMask &= 0x7F;
+        NewMask &= ~(DR_MASK(7));
         if (NewMask & DR_REG_MASK)
         {
             /* Set the active mask */
-            NewMask |= DR_ACTIVE_MASK;
+            NewMask |= DR_MASK(DR7_OVERRIDE_V);
 
             /* Set DR7 override */
-            *DrMask = DR7_OVERRIDE_MASK;
+            *Dr7Ptr |= DR7_OVERRIDE_MASK;
         }
         else
         {
@@ -154,8 +138,8 @@ KiRecordDr7(OUT PULONG Dr7Ptr,
         Result = NewMask ? TRUE: FALSE;
 
         /* Update the mask to disable debugging */
-        NewMask &= ~DR_ACTIVE_MASK;
-        NewMask |= 0x80;
+        NewMask &= ~(DR_MASK(DR7_OVERRIDE_V));
+        NewMask |= DR_MASK(7);
     }
 
     /* Check if caller wants the new mask */
@@ -170,7 +154,8 @@ KiRecordDr7(OUT PULONG Dr7Ptr,
         if (Mask != NewMask)
         {
             /* Update it */
-            KeGetCurrentThread()->DispatcherHeader.DebugActive = NewMask;
+            KeGetCurrentThread()->DispatcherHeader.DebugActive =
+                (BOOLEAN)NewMask;
         }
     }
 
@@ -210,10 +195,19 @@ NTAPI
 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
                  IN ULONG Esp)
 {
-    ULONG Previous = KiEspFromTrapFrame(TrapFrame);
+    KIRQL OldIrql;
+    ULONG Previous;
+
+    /* Raise to APC_LEVEL if needed */
+    OldIrql = KeGetCurrentIrql();
+    if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
+
+    /* Get the old ESP */
+    Previous = KiEspFromTrapFrame(TrapFrame);
 
     /* Check if this is user-mode or V86 */
-    if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
+    if ((TrapFrame->SegCs & MODE_MASK) ||
+        (TrapFrame->EFlags & EFLAGS_V86_MASK))
     {
         /* Write it directly */
         TrapFrame->HardwareEsp = Esp;
@@ -221,7 +215,11 @@ KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
     else
     {
         /* Don't allow ESP to be lowered, this is illegal */
-        if (Esp < Previous) KeBugCheck(SET_OF_INVALID_CONTEXT);
+        if (Esp < Previous) KeBugCheckEx(SET_OF_INVALID_CONTEXT,
+                                         Esp,
+                                         Previous,
+                                         (ULONG_PTR)TrapFrame,
+                                         0);
 
         /* Create an edit frame, check if it was alrady */
         if (!(TrapFrame->SegCs & FRAME_EDITED))
@@ -243,13 +241,16 @@ KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
             }
         }
     }
+
+    /* Restore IRQL */
+    if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
 }
 
 ULONG
 NTAPI
 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
 {
-    /* If this was V86 Mode */
+    /* Check if this was V86 Mode */
     if (TrapFrame->EFlags & EFLAGS_V86_MASK)
     {
         /* Just return it */
@@ -257,7 +258,7 @@ KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
     }
     else if (TrapFrame->SegCs & MODE_MASK)
     {
-        /* Usermode, return the User SS */
+        /* User mode, return the User SS */
         return TrapFrame->HardwareSegSs | RPL_MASK;
     }
     else
@@ -292,9 +293,9 @@ USHORT
 NTAPI
 KiTagWordFnsaveToFxsave(USHORT TagWord)
 {
-    INT FxTagWord = ~TagWord; 
+    INT FxTagWord = ~TagWord;
 
-    /* 
+    /*
      * Empty is now 00, any 2 bits containing 1 mean valid
      * Now convert the rest (11->0 and the rest to 1)
      */
@@ -316,12 +317,13 @@ KeContextToTrapFrame(IN PCONTEXT Context,
     PFX_SAVE_AREA FxSaveArea;
     ULONG i;
     BOOLEAN V86Switch = FALSE;
-    KIRQL OldIrql = APC_LEVEL;
+    KIRQL OldIrql;
     ULONG DrMask = 0;
     PVOID SafeDr;
 
     /* Do this at APC_LEVEL */
-    if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
+    OldIrql = KeGetCurrentIrql();
+    if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
 
     /* Start with the basic Registers */
     if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
@@ -442,7 +444,7 @@ KeContextToTrapFrame(IN PCONTEXT Context,
                           MAXIMUM_SUPPORTED_EXTENSION);
 
             /* Remove reserved bits from MXCSR */
-            FxSaveArea->U.FxArea.MXCsr &= ~0xFFBF;
+            FxSaveArea->U.FxArea.MXCsr &= KiMXCsrMask;
 
             /* Mask out any invalid flags */
             FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
@@ -544,7 +546,7 @@ KeContextToTrapFrame(IN PCONTEXT Context,
         else
         {
             /* FIXME: Handle FPU Emulation */
-            ASSERT(FALSE);
+            //ASSERT(FALSE);
         }
     }
 
@@ -575,13 +577,13 @@ KeContextToTrapFrame(IN PCONTEXT Context,
         /* If we're in user-mode */
         if (PreviousMode != KernelMode)
         {
-            /* FIXME: Save the mask */
-            //KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask;
+            /* Save the mask */
+            KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask;
         }
     }
 
     /* Check if thread has IOPL and force it enabled if so */
-    if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= 0x3000;
+    if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
 
     /* Restore IRQL */
     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
@@ -600,11 +602,12 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
         FLOATING_SAVE_AREA UnalignedArea;
     } FloatSaveBuffer;
     FLOATING_SAVE_AREA *FloatSaveArea;
-    KIRQL OldIrql = APC_LEVEL;
+    KIRQL OldIrql;
     ULONG i;
 
     /* Do this at APC_LEVEL */
-    if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
+    OldIrql = KeGetCurrentIrql();
+    if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
 
     /* Start with the Control flags */
     if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
@@ -763,7 +766,7 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
             Context->Dr6 = TrapFrame->Dr6;
 
             /* Update DR7 */
-            //Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
+            Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
         }
         else
         {
@@ -780,6 +783,45 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
 }
 
+BOOLEAN
+FASTCALL
+KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL)
+{
+    ULONG Eip;
+    PKTRAP_FRAME TrapFrame = TrapInformation;
+    VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
+
+    /* Don't do anything if we didn't get a trap frame */
+    if (!TrapInformation) return FALSE;
+
+    /* Check where we came from */
+    switch (TrapFrame->SegCs)
+    {
+        /* Kernel mode */
+        case KGDT_R0_CODE:
+
+            /* Allow S-LIST Routine to fail */
+            Eip = (ULONG)&ExpInterlockedPopEntrySListFault;
+            break;
+
+        /* User code */
+        case KGDT_R3_CODE | RPL_MASK:
+
+            /* Allow S-LIST Routine to fail */
+            //Eip = (ULONG)KeUserPopEntrySListFault;
+            Eip = 0;
+            break;
+
+        default:
+
+            /* Anything else gets a bugcheck */
+            Eip = 0;
+    }
+
+    /* Return TRUE if we want to keep the system up */
+    return (TrapFrame->Eip == Eip) ? TRUE : FALSE;
+}
+
 VOID
 NTAPI
 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
@@ -789,10 +831,7 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
                     IN BOOLEAN FirstChance)
 {
     CONTEXT Context;
-    ULONG_PTR Stack, NewStack;
-    ULONG Size;
     EXCEPTION_RECORD LocalExceptRecord;
-    _SEH_DECLARE_LOCALS(KiCopyInfo);
 
     /* Increase number of Exception Dispatches */
     KeGetCurrentPrcb()->KeExceptionDispatchCount++;
@@ -800,7 +839,7 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
     /* Set the context flags */
     Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
 
-    /* Check if User Mode or if the debugger isenabled */
+    /* Check if User Mode or if the debugger is enabled */
     if ((PreviousMode == UserMode) || (KdDebuggerEnabled))
     {
         /* Add the FPU Flag */
@@ -817,11 +856,26 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
     /* Get a Context */
     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
 
-    /* Fix up EIP */
-    if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
+    /* Look at our exception code */
+    switch (ExceptionRecord->ExceptionCode)
     {
-        /* Decrement EIP by one */
-        Context.Eip--;
+        /* Breakpoint */
+        case STATUS_BREAKPOINT:
+
+            /* Decrement EIP by one */
+            Context.Eip--;
+            break;
+
+        /* Internal exception */
+        case KI_EXCEPTION_ACCESS_VIOLATION:
+
+            /* Set correct code */
+            ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
+            if (PreviousMode == UserMode)
+            {
+                /* FIXME: Handle no execute */
+            }
+            break;
     }
 
     /* Sanity check */
@@ -846,9 +900,6 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
                 goto Handled;
             }
 
-            /* HACK: GDB Entry */
-            if (KdpCallGdb(TrapFrame, ExceptionRecord, &Context)) goto Handled;
-
             /* If the Debugger couldn't handle it, dispatch the exception */
             if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
         }
@@ -869,41 +920,41 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
                      ExceptionRecord->ExceptionCode,
                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
-                     ExceptionRecord->ExceptionInformation[0],
-                     ExceptionRecord->ExceptionInformation[1]);
+                     (ULONG_PTR)TrapFrame,
+                     0);
     }
     else
     {
         /* User mode exception, was it first-chance? */
         if (FirstChance)
         {
-            /* Enter Debugger if available */
-            if (PsGetCurrentProcess()->DebugPort)
+            /* Make sure a debugger is present, and ignore user-mode if requested */
+            if ((KiDebugRoutine) &&
+                (!(PsGetCurrentProcess()->DebugPort)))
             {
-                /* FIXME : TODO */
-                //KEBUGCHECK(0);
-            }
-            else if (KiDebugRoutine(TrapFrame,
-                                    ExceptionFrame,
-                                    ExceptionRecord,
-                                    &Context,
-                                    PreviousMode,
-                                    FALSE))
-            {
-                /* Exception was handled */
-                goto Handled;
+                /* Call the debugger */
+                if (KiDebugRoutine(TrapFrame,
+                                   ExceptionFrame,
+                                   ExceptionRecord,
+                                   &Context,
+                                   PreviousMode,
+                                   FALSE))
+                {
+                    /* Exception was handled */
+                    goto Handled;
+                }
             }
 
-            /* HACK: GDB Entry */
-            if (KdpCallGdb(TrapFrame, ExceptionRecord, &Context)) goto Handled;
-
             /* Forward exception to user mode debugger */
             if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) goto Exit;
 
             /* Set up the user-stack */
 DispatchToUser:
-            _SEH_TRY
+            _SEH2_TRY
             {
+                ULONG Size;
+                ULONG_PTR Stack, NewStack;
+
                 /* Make sure we have a valid SS and that this isn't V86 mode */
                 if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) ||
                     (TrapFrame->EFlags & EFLAGS_V86_MASK))
@@ -948,38 +999,37 @@ DispatchToUser:
                 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode);
                 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
                 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
-                TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, PreviousMode);
+                TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB,  PreviousMode);
                 TrapFrame->SegGs = 0;
 
                 /* Set EIP to the User-mode Dispatcher */
                 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
-                _SEH_LEAVE;
+
+                /* Dispatch exception to user-mode */
+                _SEH2_YIELD(return);
             }
-            _SEH_EXCEPT(KiCopyInformation)
+            _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
             {
                 /* Check if we got a stack overflow and raise that instead */
-                if (_SEH_VAR(SehExceptRecord).ExceptionCode ==
+                if ((NTSTATUS)LocalExceptRecord.ExceptionCode ==
                     STATUS_STACK_OVERFLOW)
                 {
                     /* Copy the exception address and record */
-                    _SEH_VAR(SehExceptRecord).ExceptionAddress =
+                    LocalExceptRecord.ExceptionAddress =
                         ExceptionRecord->ExceptionAddress;
                     RtlCopyMemory(ExceptionRecord,
-                                  (PVOID)&_SEH_VAR(SehExceptRecord),
+                                  (PVOID)&LocalExceptRecord,
                                   sizeof(EXCEPTION_RECORD));
 
                     /* Do the exception again */
-                    goto DispatchToUser;
+                    _SEH2_YIELD(goto DispatchToUser);
                 }
             }
-            _SEH_END;
-
-            /* Dispatch exception to user-mode */
-            return;
+            _SEH2_END;
         }
 
         /* Try second chance */
-        if (DbgkForwardException(ExceptionRecord, TRUE, FALSE))
+        if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))
         {
             /* Handled, get out */
             goto Exit;
@@ -991,12 +1041,17 @@ DispatchToUser:
         }
 
         /* 3rd strike, kill the process */
+        DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx\n",
+                PsGetCurrentProcess()->ImageFileName,
+                ExceptionRecord->ExceptionCode,
+                ExceptionRecord->ExceptionAddress);
+
         ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
                      ExceptionRecord->ExceptionCode,
                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
-                     ExceptionRecord->ExceptionInformation[0],
-                     ExceptionRecord->ExceptionInformation[1]);
+                     (ULONG_PTR)TrapFrame,
+                     0);
     }
 
 Handled:
@@ -1017,24 +1072,22 @@ NTSTATUS
 NTAPI
 KeRaiseUserException(IN NTSTATUS ExceptionCode)
 {
-    NTSTATUS Status = STATUS_SUCCESS;
     ULONG OldEip;
     PTEB Teb = KeGetCurrentThread()->Teb;
     PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
 
     /* Make sure we can access the TEB */
-    _SEH_TRY
+    _SEH2_TRY
     {
         /* Set the exception code */
         Teb->ExceptionCode = ExceptionCode;
     }
-    _SEH_HANDLE
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        /* Save exception code */
-        Status = ExceptionCode;
+        /* Return the exception code */
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
     }
-    _SEH_END;
-    if (!NT_SUCCESS(Status)) return Status;
+    _SEH2_END;
 
     /* Get the old EIP */
     OldEip = TrapFrame->Eip;
@@ -1045,4 +1098,3 @@ KeRaiseUserException(IN NTSTATUS ExceptionCode)
     /* Return the old EIP */
     return (NTSTATUS)OldEip;
 }
-