https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2a8c680dbe6392fa8f21c…
commit 2a8c680dbe6392fa8f21cbd44b7641cf4b6b074b
Author:     Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Thu Apr 18 16:41:48 2019 +0200
Commit:     Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Sat Oct 31 14:23:16 2020 +0100
    [NTOS:KE:X64][NTDLL:X64] Implement KiUserExceptionDispatcher and fix
KiDispatchExceptionToUser
---
 dll/ntdll/dispatch/amd64/dispatch.S | 118 +++++++++++++++++++++++++++++++++++-
 ntoskrnl/ke/amd64/except.c          |  47 +++++++-------
 sdk/include/ndk/amd64/ketypes.h     |  12 ++++
 3 files changed, 152 insertions(+), 25 deletions(-)
diff --git a/dll/ntdll/dispatch/amd64/dispatch.S b/dll/ntdll/dispatch/amd64/dispatch.S
index 6d132df7755..86fe423ab2c 100644
--- a/dll/ntdll/dispatch/amd64/dispatch.S
+++ b/dll/ntdll/dispatch/amd64/dispatch.S
@@ -107,11 +107,125 @@ StatusRaise:
 .ENDP
+/*
+    BOOLEAN
+    NTAPI
+    RtlDispatchException(
+        _In_ PEXCEPTION_RECORD ExceptionRecord,
+        _In_ PCONTEXT ContextRecord);
+ */
+EXTERN RtlDispatchException:PROC
+
+/*
+    NTSTATUS
+    NTAPI
+    ZwContinue(
+        _In_ PCONTEXT Context,
+        _In_ BOOLEAN TestAlert);
+ */
+EXTERN ZwContinue:PROC
+
+/*
+    NTSTATUS
+    NTAPI
+    ZwRaiseException(
+        _In_ PEXCEPTION_RECORD ExceptionRecord,
+        _In_ PCONTEXT Context,
+        _In_ BOOLEAN SearchFrames);
+ */
+EXTERN ZwRaiseException:PROC
+
+/*
+    VOID
+    NTAPI
+    RtlRaiseStatus(
+        _In_ PEXCEPTION_RECORD ExceptionRecord);
+ */
+EXTERN RtlRaiseException:PROC
+
+/*
+    VOID
+    KiUserExceptionDispatcher(
+        CONTEXT ContextRecord<rcx>,
+        PEXCEPTION_RECORD ExceptionRecord<rdx>);
+
+    This function is called with the following stack layout:
+        CONTEXT ContextRecord  <- RSP, RCX
+        EXCEPTION_RECORD ExceptionRecord <- RDX
+        ULONG64 Alignment
+        MACHINE_FRAME MachineFrame
+ */
 PUBLIC KiUserExceptionDispatcher
 .PROC KiUserExceptionDispatcher
-    .endprolog
-    int 3
+    ; The stack is set up with a KUSER_EXCEPTION_STACK
+    ; The frame ends with a MACHINE_FRAME.
+    .PUSHFRAME
+
+    ; This is for the alignment, EXCEPTION_RECORD and CONTEXT
+    .ALLOCSTACK 8 + EXCEPTION_RECORD_LENGTH + CONTEXT_FRAME_LENGTH
+    .ENDPROLOG
+
+    /* Clear direction flag */
+    cld
+
+    /* Dispatch the exception */
+    call RtlDispatchException
+
+    /* Check for success */
+    or al, al
+    jz RaiseException
+
+    /* We're fine, continue execution */
+    lea rcx, [rsp] ; ContextRecord
+    mov dl, 0 ; TestAlert
+    call ZwContinue
+
+    /* Exit */
+    jmp Exit
+
+RaiseException:
+
+    /* Raise the exception */
+    lea rcx, [rsp + CONTEXT_FRAME_LENGTH] ; ExceptionRecord
+    lea rdx, [rsp] ; ContextRecord
+    xor r8, r8
+    call ZwRaiseException
+
+Exit:
+    lea rcx, [rsp + CONTEXT_FRAME_LENGTH] ; ExceptionRecord
+    mov rdx, rax
+    call KiUserExceptionDispatcherNested
+    ret
+
+.ENDP
+
+/*
+    VOID
+    KiUserExceptionDispatcherNested(
+        _In_ ExceptionRecord<rcx>,
+        _In_ Status<edx>
+    )
+ */
+.PROC KiUserExceptionDispatcherNested
+    /* Allocate space for the nested exception record */
+    sub rsp, EXCEPTION_RECORD_LENGTH
+    .ALLOCSTACK EXCEPTION_RECORD_LENGTH
+    .ENDPROLOG
+
+    /* Set it up */
+    mov dword ptr [rsp + ErNumberParameters], 0
+    mov dword ptr [rsp + ErExceptionFlags], EXCEPTION_NONCONTINUABLE
+    mov [rsp + ErExceptionRecord], rcx
+    mov [rsp + ErExceptionCode], edx
+
+    /* Raise the exception */
+    mov rcx, rsp
+    call RtlRaiseException
+
+    /* Cleanup stack and return */
+    add rsp, EXCEPTION_RECORD_LENGTH
+    ret
 .ENDP
 END
diff --git a/ntoskrnl/ke/amd64/except.c b/ntoskrnl/ke/amd64/except.c
index ed0757d84fb..23ff7e016a9 100644
--- a/ntoskrnl/ke/amd64/except.c
+++ b/ntoskrnl/ke/amd64/except.c
@@ -100,10 +100,8 @@ KiDispatchExceptionToUser(
     IN PEXCEPTION_RECORD ExceptionRecord)
 {
     EXCEPTION_RECORD LocalExceptRecord;
-    ULONG Size;
     ULONG64 UserRsp;
-    PCONTEXT UserContext;
-    PEXCEPTION_RECORD UserExceptionRecord;
+    PKUSER_EXCEPTION_STACK UserStack;
     /* Make sure we have a valid SS */
     if (TrapFrame->SegSs != (KGDT64_R3_DATA | RPL_MASK))
@@ -115,27 +113,29 @@ KiDispatchExceptionToUser(
         ExceptionRecord = &LocalExceptRecord;
     }
-    /* Calculate the size of the exception record */
-    Size = FIELD_OFFSET(EXCEPTION_RECORD, ExceptionInformation) +
-           ExceptionRecord->NumberParameters * sizeof(ULONG64);
-
     /* Get new stack pointer and align it to 16 bytes */
-    UserRsp = (Context->Rsp - Size - sizeof(CONTEXT)) & ~15;
+    UserRsp = (Context->Rsp - sizeof(KUSER_EXCEPTION_STACK)) & ~15;
-    /* Get pointers to the usermode context and exception record */
-    UserContext = (PVOID)UserRsp;
-    UserExceptionRecord = (PVOID)(UserRsp + sizeof(CONTEXT));
+    /* Get pointer to the usermode context, exception record and machine frame */
+    UserStack = (PKUSER_EXCEPTION_STACK)UserRsp;
     /* Set up the user-stack */
     _SEH2_TRY
     {
-        /* Probe stack and copy Context */
-        ProbeForWrite(UserContext, sizeof(CONTEXT), sizeof(ULONG64));
-        *UserContext = *Context;
-
-        /* Probe stack and copy exception record */
-        ProbeForWrite(UserExceptionRecord, Size, sizeof(ULONG64));
-        *UserExceptionRecord = *ExceptionRecord;
+        /* Probe the user stack frame and zero it out */
+        ProbeForWrite(UserStack, sizeof(*UserStack),
TYPE_ALIGNMENT(KUSER_EXCEPTION_STACK));
+        RtlZeroMemory(UserStack, sizeof(*UserStack));
+
+        /* Copy Context and ExceptionFrame */
+        UserStack->Context = *Context;
+        UserStack->ExceptionRecord = *ExceptionRecord;
+
+        /* Setup the machine frame */
+        UserStack->MachineFrame.Rip = Context->Rip;
+        UserStack->MachineFrame.SegCs = Context->SegCs;
+        UserStack->MachineFrame.EFlags = Context->EFlags;
+        UserStack->MachineFrame.Rsp = Context->Rsp;
+        UserStack->MachineFrame.SegSs = Context->SegSs;
     }
     _SEH2_EXCEPT((LocalExceptRecord =
*_SEH2_GetExceptionInformation()->ExceptionRecord),
                  EXCEPTION_EXECUTE_HANDLER)
@@ -148,8 +148,8 @@ KiDispatchExceptionToUser(
     _SEH2_END;
     /* Now set the two params for the user-mode dispatcher */
-    TrapFrame->Rcx = (ULONG64)UserContext;
-    TrapFrame->Rdx = (ULONG64)UserExceptionRecord;
+    TrapFrame->Rcx = (ULONG64)&UserStack->ExceptionRecord;
+    TrapFrame->Rdx = (ULONG64)&UserStack->Context;
     /* Set new Stack Pointer */
     TrapFrame->Rsp = UserRsp;
@@ -346,9 +346,10 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
             /* Forward exception to user mode debugger */
             if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
-
-            //KiDispatchExceptionToUser()
-            __debugbreak();
+
+            /* Forward exception to user mode (does not return) */
+            KiDispatchExceptionToUser(TrapFrame, &Context, ExceptionRecord);
+            NT_ASSERT(FALSE);
         }
         /* Try second chance */
diff --git a/sdk/include/ndk/amd64/ketypes.h b/sdk/include/ndk/amd64/ketypes.h
index d2c4da16cc8..c989b4be0ca 100644
--- a/sdk/include/ndk/amd64/ketypes.h
+++ b/sdk/include/ndk/amd64/ketypes.h
@@ -998,6 +998,18 @@ typedef struct _UCALLOUT_FRAME
     MACHINE_FRAME MachineFrame;
 } UCALLOUT_FRAME, *PUCALLOUT_FRAME; // size = 0x0058
+//
+// Stack frame layout for KiUserExceptionDispatcher
+// The name is totally made up
+//
+typedef struct _KUSER_EXCEPTION_STACK
+{
+    CONTEXT Context;
+    EXCEPTION_RECORD ExceptionRecord;
+    ULONG64 Alignment;
+    MACHINE_FRAME MachineFrame;
+} KUSER_EXCEPTION_STACK, * PKUSER_EXCEPTION_STACK;
+
 typedef struct _DISPATCHER_CONTEXT
 {
     ULONG64 ControlPc;