summaryrefslogtreecommitdiff
path: root/src/vm/amd64/RedirectedHandledJITCase.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/amd64/RedirectedHandledJITCase.asm')
-rw-r--r--src/vm/amd64/RedirectedHandledJITCase.asm239
1 files changed, 239 insertions, 0 deletions
diff --git a/src/vm/amd64/RedirectedHandledJITCase.asm b/src/vm/amd64/RedirectedHandledJITCase.asm
new file mode 100644
index 0000000000..a6d3496357
--- /dev/null
+++ b/src/vm/amd64/RedirectedHandledJITCase.asm
@@ -0,0 +1,239 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+; See the LICENSE file in the project root for more information.
+
+; ==++==
+;
+
+;
+; ==--==
+
+include AsmMacros.inc
+include asmconstants.inc
+
+Thread__GetAbortContext equ ?GetAbortContext@Thread@@QEAAPEAU_CONTEXT@@XZ
+
+extern FixContextHandler:proc
+extern LinkFrameAndThrow:proc
+extern GetCurrentSavedRedirectContext:proc
+extern Thread__GetAbortContext:proc
+extern HijackHandler:proc
+extern ThrowControlForThread:proc
+extern FixRedirectContextHandler:proc
+
+;
+; WARNING!! These functions immediately ruin thread unwindability. This is
+; WARNING!! OK as long as there is a mechanism for saving the thread context
+; WARNING!! prior to running these functions as well as a mechanism for
+; WARNING!! restoring the context prior to any stackwalk. This means that
+; WARNING!! we need to ensure that no GC can occur while the stack is
+; WARNING!! unwalkable. This further means that we cannot allow any exception
+; WARNING!! to occure when the stack is unwalkable
+;
+
+
+; If you edit this macro, make sure you update GetCONTEXTFromRedirectedStubStackFrame.
+; This function is used by both the personality routine and the debugger to retrieve the original CONTEXT.
+GenerateRedirectedHandledJITCaseStub macro reason
+
+extern ?RedirectedHandledJITCaseFor&reason&@Thread@@CAXXZ:proc
+
+NESTED_ENTRY RedirectedHandledJITCaseFor&reason&_Stub, _TEXT, FixRedirectContextHandler
+
+ ;
+ ; To aid debugging, we'll fake a call to this function. Allocate an
+ ; extra stack slot that is hidden from the unwind info, where we can
+ ; stuff the "return address". If we wanted to preserve full
+ ; unwindability, we would need to copy all preserved registers.
+ ; Ordinarily, rbp is used for the frame pointer, so since we're only
+ ; interested is debugability, we'll just handle that common case.
+ ;
+
+ push rax ; where to stuff the fake return address
+ push_nonvol_reg rbp ; save interrupted rbp for stack walk
+ alloc_stack 28h ; CONTEXT*, callee scratch area
+ set_frame rbp, 0
+
+.errnz REDIRECTSTUB_ESTABLISHER_OFFSET_RBP, REDIRECTSTUB_ESTABLISHER_OFFSET_RBP has changed - update asm stubs
+
+ END_PROLOGUE
+
+ ;
+ ; Align rsp. rsp must misaligned at entry to any C function.
+ ;
+ and rsp, -16
+
+ ;
+ ; Save a copy of the redirect CONTEXT* in case an exception occurs.
+ ; The personality routine will use this to restore unwindability for
+ ; the exception dispatcher.
+ ;
+ call GetCurrentSavedRedirectContext
+
+ mov [rbp+20h], rax
+.errnz REDIRECTSTUB_RBP_OFFSET_CONTEXT - 20h, REDIRECTSTUB_RBP_OFFSET_CONTEXT has changed - update asm stubs
+
+ ;
+ ; Fetch the interrupted rip and save it as our return address.
+ ;
+ mov rax, [rax + OFFSETOF__CONTEXT__Rip]
+ mov [rbp+30h], rax
+
+ ;
+ ; Call target, which will do whatever we needed to do in the context
+ ; of the target thread, and will RtlRestoreContext when it is done.
+ ;
+ call ?RedirectedHandledJITCaseFor&reason&@Thread@@CAXXZ
+
+ int 3 ; target shouldn't return.
+
+; Put a label here to tell the debugger where the end of this function is.
+PATCH_LABEL RedirectedHandledJITCaseFor&reason&_StubEnd
+
+NESTED_END RedirectedHandledJITCaseFor&reason&_Stub, _TEXT
+
+ endm
+
+
+GenerateRedirectedHandledJITCaseStub GCThreadControl
+GenerateRedirectedHandledJITCaseStub DbgThreadControl
+GenerateRedirectedHandledJITCaseStub UserSuspend
+GenerateRedirectedHandledJITCaseStub YieldTask
+
+ifdef _DEBUG
+ifdef HAVE_GCCOVER
+GenerateRedirectedHandledJITCaseStub GCStress
+endif
+endif
+
+
+; scratch area; padding; GSCookie
+OFFSET_OF_FRAME = SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES + 8 + SIZEOF_GSCookie
+
+; force evaluation to avoid "expression is too complex errors"
+SIZEOF__FaultingExceptionFrame = SIZEOF__FaultingExceptionFrame
+
+GenerateRedirectedStubWithFrame macro STUB, FILTER, TARGET
+
+altentry STUB&_RspAligned
+
+NESTED_ENTRY STUB, _TEXT, FILTER
+
+ ;
+ ; IN: rcx: original IP before redirect
+ ;
+
+ mov rdx, rsp
+
+ ; This push of the return address must not be recorded in the unwind
+ ; info. After this push, unwinding will work.
+ push rcx
+
+ test rsp, 0fh
+ jnz STUB&_FixRsp
+
+STUB&_RspAligned:
+
+ ; Any stack operations hereafter must be recorded in the unwind info, but
+ ; only nonvolatile register locations are needed. Anything else is only
+ ; a "sub rsp, 8" to the unwinder.
+
+ ; m_ctx must be 16-byte aligned
+.errnz (OFFSET_OF_FRAME + SIZEOF__FaultingExceptionFrame) MOD 16
+
+ alloc_stack OFFSET_OF_FRAME + SIZEOF__FaultingExceptionFrame
+
+.errnz THROWSTUB_ESTABLISHER_OFFSET_FaultingExceptionFrame - OFFSET_OF_FRAME, THROWSTUB_ESTABLISHER_OFFSET_FaultingExceptionFrame has changed - update asm stubs
+
+ END_PROLOGUE
+
+ lea rcx, [rsp + OFFSET_OF_FRAME]
+
+ mov dword ptr [rcx], 0 ; Initialize vtbl (it is not strictly necessary)
+ mov dword ptr [rcx + OFFSETOF__FaultingExceptionFrame__m_fFilterExecuted], 0 ; Initialize BOOL for personality routine
+
+ call TARGET
+
+ ; Target should not return.
+ int 3
+
+NESTED_END STUB, _TEXT
+
+; This function is used by the stub above to adjust the stack alignment. The
+; stub can't conditionally push something on the stack because the unwind
+; encodings have no way to express that.
+;
+; CONSIDER: we could move the frame pointer above the FaultingExceptionFrame,
+; and detect the misalignment adjustment in
+; GetFrameFromRedirectedStubStackFrame. This is probably less code and more
+; straightforward.
+LEAF_ENTRY STUB&_FixRsp, _TEXT
+
+ call STUB&_RspAligned
+
+ ; Target should not return.
+ int 3
+
+LEAF_END STUB&_FixRsp, _TEXT
+
+ endm
+
+
+REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE = SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES + 8
+
+NESTED_ENTRY RedirectForThrowControl2, _TEXT
+
+ ; On entry
+ ; rcx -> FaultingExceptionFrame
+ ; rdx -> Original RSP
+
+ alloc_stack REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE
+
+ save_reg_postrsp rcx, REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE + 8h ; FaultingExceptionFrame
+ save_reg_postrsp rdx, REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE + 10h ; Original RSP
+
+ END_PROLOGUE
+
+ ; Fetch rip from a CONTEXT, and store it as our return address.
+ CALL_GETTHREAD
+
+ mov rcx, rax
+ call Thread__GetAbortContext
+
+ mov rax, [rax + OFFSETOF__CONTEXT__Rip]
+ mov rdx, [rsp + REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE + 10h] ; Original RSP
+ mov [rdx - 8], rax
+
+ mov rcx, [rsp + REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE + 8h] ; FaultingExceptionFrame
+ call ThrowControlForThread
+
+ ; ThrowControlForThread doesn't return.
+ int 3
+
+NESTED_END RedirectForThrowControl2, _TEXT
+
+GenerateRedirectedStubWithFrame RedirectForThrowControl, HijackHandler, RedirectForThrowControl2
+
+
+NAKED_THROW_HELPER_FRAME_SIZE = SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES + 8
+
+NESTED_ENTRY NakedThrowHelper2, _TEXT
+
+ ; On entry
+ ; rcx -> FaultingExceptionFrame
+
+ alloc_stack NAKED_THROW_HELPER_FRAME_SIZE
+ END_PROLOGUE
+
+ call LinkFrameAndThrow
+
+ ; LinkFrameAndThrow doesn't return.
+ int 3
+
+NESTED_END NakedThrowHelper2, _TEXT
+
+GenerateRedirectedStubWithFrame NakedThrowHelper, FixContextHandler, NakedThrowHelper2
+
+
+ end
+