diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/debug/ee/amd64/dbghelpers.S | 12 | ||||
-rw-r--r-- | src/debug/ee/amd64/dbghelpers.asm | 12 | ||||
-rw-r--r-- | src/debug/ee/debugger.cpp | 12 |
3 files changed, 35 insertions, 1 deletions
diff --git a/src/debug/ee/amd64/dbghelpers.S b/src/debug/ee/amd64/dbghelpers.S index 405c6a5271..85ec80c701 100644 --- a/src/debug/ee/amd64/dbghelpers.S +++ b/src/debug/ee/amd64/dbghelpers.S @@ -45,6 +45,13 @@ NESTED_ENTRY ExceptionHijack, _TEXT, UnhandledExceptionHandlerUnix // 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 0x20 END_PROLOGUE @@ -53,6 +60,11 @@ NESTED_ENTRY ExceptionHijack, _TEXT, UnhandledExceptionHandlerUnix // 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] diff --git a/src/debug/ee/amd64/dbghelpers.asm b/src/debug/ee/amd64/dbghelpers.asm index 9393552b7a..5836257f46 100644 --- a/src/debug/ee/amd64/dbghelpers.asm +++ b/src/debug/ee/amd64/dbghelpers.asm @@ -48,6 +48,13 @@ NESTED_ENTRY ExceptionHijack, _TEXT, ExceptionHijackPersonalityRoutine ; 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 @@ -56,6 +63,11 @@ NESTED_ENTRY ExceptionHijack, _TEXT, ExceptionHijackPersonalityRoutine ; 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] diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp index 12f87e381c..eb5e65c415 100644 --- a/src/debug/ee/debugger.cpp +++ b/src/debug/ee/debugger.cpp @@ -13502,7 +13502,17 @@ ExceptionHijackPersonalityRoutine(IN PEXCEPTION_RECORD pExceptionRecord CONTEXT * pHijackContext = NULL; // Get the 1st parameter (the Context) from hijack worker. - pHijackContext = *reinterpret_cast<CONTEXT **>(pDispatcherContext->EstablisherFrame); + // EstablisherFrame points to the stack slot 8 bytes above the + // return address to the ExceptionHijack. This would contain the + // parameters passed to ExceptionHijackWorker, which is marked + // STDCALL, but the x64 calling convention lets the + // ExceptionHijackWorker use that stack space, resulting in the + // context being overwritten. Instead, we get the context from the + // previous stack frame, which contains the arguments to + // ExceptionHijack, placed there by the debugger in + // DacDbiInterfaceImpl::Hijack. This works because ExceptionHijack + // allocates exactly 4 stack slots. + pHijackContext = *reinterpret_cast<CONTEXT **>(pDispatcherContext->EstablisherFrame + 0x20); // This copies pHijackContext into pDispatcherContext, which the OS can then // use to walk the stack. |