WindowsDiagnostics.cpp (2825B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/WindowsDiagnostics.h" 8 9 #include "mozilla/Assertions.h" 10 #include "mozilla/Attributes.h" 11 #include "mozilla/Types.h" 12 13 #include <windows.h> 14 #include <winternl.h> 15 16 #if defined(_M_AMD64) 17 18 namespace mozilla { 19 20 MOZ_RUNINIT static OnSingleStepCallback sOnSingleStepCallback{}; 21 static void* sOnSingleStepCallbackState = nullptr; 22 static bool sIsSingleStepping = false; 23 24 MFBT_API AutoOnSingleStepCallback::AutoOnSingleStepCallback( 25 OnSingleStepCallback aOnSingleStepCallback, void* aState) { 26 MOZ_RELEASE_ASSERT(!sIsSingleStepping && !sOnSingleStepCallback && 27 !sOnSingleStepCallbackState, 28 "Single-stepping is already active"); 29 30 sOnSingleStepCallback = std::move(aOnSingleStepCallback); 31 sOnSingleStepCallbackState = aState; 32 sIsSingleStepping = true; 33 } 34 35 MFBT_API AutoOnSingleStepCallback::~AutoOnSingleStepCallback() { 36 sOnSingleStepCallback = OnSingleStepCallback(); 37 sOnSingleStepCallbackState = nullptr; 38 sIsSingleStepping = false; 39 } 40 41 // Going though this assembly code turns on the trap flag, which will trigger 42 // a first single-step exception. It is then up to the exception handler to 43 // keep the trap flag enabled so that a new single step exception gets 44 // triggered with the following instruction. 45 MFBT_API MOZ_NEVER_INLINE MOZ_NAKED void EnableTrapFlag() { 46 asm volatile( 47 "pushfq;" 48 "orw $0x100,(%rsp);" 49 "popfq;" 50 "retq;"); 51 } 52 53 // This function does not do anything special, but when we reach its address 54 // while single-stepping the exception handler will know that it is now time to 55 // leave the trap flag turned off. 56 MFBT_API MOZ_NEVER_INLINE MOZ_NAKED void DisableTrapFlag() { 57 asm volatile("retq;"); 58 } 59 60 MFBT_API LONG SingleStepExceptionHandler(_EXCEPTION_POINTERS* aExceptionInfo) { 61 if (sIsSingleStepping && sOnSingleStepCallback && 62 aExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) { 63 auto instructionPointer = aExceptionInfo->ContextRecord->Rip; 64 bool keepOnSingleStepping = false; 65 if (instructionPointer != reinterpret_cast<uintptr_t>(&DisableTrapFlag)) { 66 keepOnSingleStepping = sOnSingleStepCallback( 67 sOnSingleStepCallbackState, aExceptionInfo->ContextRecord); 68 } 69 if (keepOnSingleStepping) { 70 aExceptionInfo->ContextRecord->EFlags |= 0x100; 71 } else { 72 sIsSingleStepping = false; 73 } 74 return EXCEPTION_CONTINUE_EXECUTION; 75 } 76 return EXCEPTION_CONTINUE_SEARCH; 77 } 78 79 } // namespace mozilla 80 81 #endif // _M_AMD64