diff options
Diffstat (limited to 'src/debug/ee/amd64/dbghelpers.asm')
-rw-r--r-- | src/debug/ee/amd64/dbghelpers.asm | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/debug/ee/amd64/dbghelpers.asm b/src/debug/ee/amd64/dbghelpers.asm new file mode 100644 index 0000000000..5836257f46 --- /dev/null +++ b/src/debug/ee/amd64/dbghelpers.asm @@ -0,0 +1,164 @@ +; 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 + +extern FuncEvalHijackWorker:proc +extern FuncEvalHijackPersonalityRoutine:proc + +; @dbgtodo- once we port Funceval, use the ExceptionHijack stub instead of this func-eval stub. +NESTED_ENTRY FuncEvalHijack, _TEXT, FuncEvalHijackPersonalityRoutine + ; the stack should be aligned at this point, since we do not call this + ; function explicitly + alloc_stack 20h + END_PROLOGUE + + mov [rsp], rcx + call FuncEvalHijackWorker + + ; + ; The following nop is crucial. It is important that the OS *not* recognize + ; the instruction immediately following the call above as an epilog, if it + ; does recognize it as an epilogue, it unwinds this function itself rather + ; than calling our personality routine to do the unwind, and then stack + ; tracing is hosed. + ; + nop + + ; + ; epilogue + ; + add rsp, 20h + TAILJMP_RAX +NESTED_END FuncEvalHijack, _TEXT + + + +extern ExceptionHijackWorker:proc +extern ExceptionHijackPersonalityRoutine:proc + +; This is the general purpose hijacking stub. The DacDbi Hijack primitive will +; set up the stack and then set the IP here, and so this just makes the call. +NESTED_ENTRY ExceptionHijack, _TEXT, ExceptionHijackPersonalityRoutine + ; the stack should be aligned at this point, since we do not call this + ; function explicitly + ; + ; There is a problem here. The Orcas assembler doesn't like a 0-sized stack frame. + ; So we allocate 4 stack slots as the outgoing argument home and just copy the + ; arguments set up by DacDbi into these stack slots. We will take a perf hit, + ; but this is not a perf critical code path anyway. + + ; There is an additional dependency on this alloc_stack: the + ; ExceptionHijackPersonalityRoutine assumes that it can find + ; the first argument to HijackWorker in the stack frame of + ; ExceptionHijack, at an offset of exactly 0x20 bytes from + ; ExceptionHijackWorker's stack frame. Therefore it is + ; important that we move the stack pointer by the same amount. + alloc_stack 20h + END_PROLOGUE + + ; We used to do an "alloc_stack 0h" because the stack has been allocated for us + ; by the OOP hijacking routine. Our arguments have also been pushed onto the + ; stack for us. However, the Orcas compilers don't like a 0-sized frame, so + ; we need to allocate something here and then just copy the stack arguments to + ; their new argument homes. + + ; In x86, ExceptionHijackWorker is marked STDCALL, so it finds + ; its arguments on the stack. In x64, it gets its arguments in + ; registers (set up for us by DacDbiInterfaceImpl::Hijack), + ; and this stack space may be reused. + mov rax, [rsp + 20h] + mov [rsp], rax + mov rax, [rsp + 28h] + mov [rsp + 8h], rax + mov rax, [rsp + 30h] + mov [rsp + 10h], rax + mov rax, [rsp + 38h] + mov [rsp + 18h], rax + + ; DD Hijack primitive already set the stack. So just make the call now. + call ExceptionHijackWorker + + ; + ; The following nop is crucial. It is important that the OS *not* recognize + ; the instruction immediately following the call above as an epilog, if it + ; does recognize it as an epilogue, it unwinds this function itself rather + ; than calling our personality routine to do the unwind, and then stack + ; tracing is hosed. + ; + nop + + ; *** Should never get here *** + ; Hijack should have restored itself first. + int 3 + + ; + ; epilogue + ; + add rsp, 20h + TAILJMP_RAX + +; Put a label here to tell the debugger where the end of this function is. +PATCH_LABEL ExceptionHijackEnd + +NESTED_END ExceptionHijack, _TEXT + +; +; Flares for interop debugging. +; Flares are exceptions (breakpoints) at well known addresses which the RS +; listens for when interop debugging. +; + +; This exception is from managed code. +LEAF_ENTRY SignalHijackStartedFlare, _TEXT + int 3 + ; make sure that the basic block is unique + test rax,1 + ret +LEAF_END SignalHijackStartedFlare, _TEXT + +; Start the handoff +LEAF_ENTRY ExceptionForRuntimeHandoffStartFlare, _TEXT + int 3 + ; make sure that the basic block is unique + test rax,2 + ret +LEAF_END ExceptionForRuntimeHandoffStartFlare, _TEXT + +; Finish the handoff. +LEAF_ENTRY ExceptionForRuntimeHandoffCompleteFlare, _TEXT + int 3 + ; make sure that the basic block is unique + test rax,3 + ret +LEAF_END ExceptionForRuntimeHandoffCompleteFlare, _TEXT + +; Signal execution return to unhijacked state +LEAF_ENTRY SignalHijackCompleteFlare, _TEXT + int 3 + ; make sure that the basic block is unique + test rax,4 + ret +LEAF_END SignalHijackCompleteFlare, _TEXT + +; This exception is from unmanaged code. +LEAF_ENTRY ExceptionNotForRuntimeFlare, _TEXT + int 3 + ; make sure that the basic block is unique + test rax,5 + ret +LEAF_END ExceptionNotForRuntimeFlare, _TEXT + +; The Runtime is synchronized. +LEAF_ENTRY NotifyRightSideOfSyncCompleteFlare, _TEXT + int 3 + ; make sure that the basic block is unique + test rax,6 + ret +LEAF_END NotifyRightSideOfSyncCompleteFlare, _TEXT + + + +; This goes at the end of the assembly file + end |