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;