public static Win32HardwareBreakpoint TrySet(SafeObjectHandle threadHandle, HardwareBreakpointType type, HardwareBreakpointSize size, IntPtr address) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || IntPtr.Size != 8) { throw new PlatformNotSupportedException("Only 64 bit Windows is supported"); } var breakpoint = new Win32HardwareBreakpoint { Address = address, Size = size, Type = type, ThreadHandle = threadHandle }; bool self = threadHandle.DangerousGetHandle() == Win32Thread.GetCurrentThread().DangerousGetHandle(); if (self) { int threadID = GetCurrentThreadId(); breakpoint.ThreadHandle = Win32Thread.OpenThread(ThreadAccess.All, inheritHandle: false, threadID: threadID); if (breakpoint.ThreadHandle.IsInvalid) { throw new Win32Exception(); } } breakpoint.CompletionEvent = Win32Event.CreateEvent(IntPtr.Zero, manualReset: false, initialState: false, name: null); breakpoint.Op = Operation.Set; Win32Thread.ThreadProc threadProc = Win32HardwareBreakpoint.th; var th = Marshal.GetFunctionPointerForDelegate(threadProc); var h = GCHandle.Alloc(breakpoint); if (Win32Thread.CreateThread(IntPtr.Zero, UIntPtr.Zero, th, parameter: (IntPtr)h, creationFlags: 0, out int _).IsInvalid) { throw new Win32Exception(); } WaitForSingleObject(breakpoint.CompletionEvent, dwMilliseconds: Constants.INFINITE); breakpoint.CompletionEvent.Dispose(); if (self) { breakpoint.ThreadHandle.Dispose(); } breakpoint.ThreadHandle = threadHandle; if (!breakpoint.SUCC) { h.Free(); return(null); } breakpoint.gcHandle = h; GC.KeepAlive(threadProc); return(breakpoint); }
static void Remove(GCHandle handle) { if (!handle.IsAllocated) { throw new ArgumentNullException(nameof(handle)); } var breakpoint = (Win32HardwareBreakpoint)handle.Target; bool isSelf = false; if (breakpoint.ThreadHandle.DangerousGetHandle() == Win32Thread.GetCurrentThread().DangerousGetHandle()) { int threadID = GetCurrentThreadId(); breakpoint.ThreadHandle = Win32Thread.OpenThread(ThreadAccess.All, inheritHandle: false, threadID); if (breakpoint.ThreadHandle.IsInvalid) { throw new Win32Exception(); } isSelf = true; } breakpoint.CompletionEvent = Win32Event.CreateEvent(IntPtr.Zero, manualReset: false, initialState: false, name: null); breakpoint.Op = Operation.Remove; Win32Thread.ThreadProc threadProc = Win32HardwareBreakpoint.th; var th = Marshal.GetFunctionPointerForDelegate(threadProc); if (Win32Thread.CreateThread(IntPtr.Zero, UIntPtr.Zero, th, (IntPtr)handle, 0, out int _).IsInvalid) { throw new Win32Exception(); } WaitForSingleObject(breakpoint.CompletionEvent, Constants.INFINITE); breakpoint.CompletionEvent.Dispose(); if (isSelf) { breakpoint.ThreadHandle.Dispose(); } handle.Free(); }
static int th(IntPtr lpParameter) { if (lpParameter == IntPtr.Zero) { throw new ArgumentNullException(nameof(lpParameter)); } var breakpoint = (Win32HardwareBreakpoint)GCHandle.FromIntPtr(lpParameter).Target; int threadOpResult = SuspendThread(breakpoint.ThreadHandle); GetLastError().ThrowOnError(); var ct = new Win32ThreadContext { ContextFlags = ContextFlags.DebugRegisters, }; Win32ThreadContext.Get(breakpoint.ThreadHandle, ref ct); GetLastError().ThrowOnError(); int FlagBit = 0; bool Dr0Busy = false; bool Dr1Busy = false; bool Dr2Busy = false; bool Dr3Busy = false; if (((ulong)ct.Dr7 & 1) != 0) { Dr0Busy = true; } if (((ulong)ct.Dr7 & 4) != 0) { Dr1Busy = true; } if (((ulong)ct.Dr7 & 16) != 0) { Dr2Busy = true; } if (((ulong)ct.Dr7 & 64) != 0) { Dr3Busy = true; } if (breakpoint.Op == Operation.Remove) { // Remove if (breakpoint.iReg == 0) { FlagBit = 0; ct.Dr0 = IntPtr.Zero; Dr0Busy = false; } if (breakpoint.iReg == 1) { FlagBit = 2; ct.Dr1 = IntPtr.Zero;; Dr1Busy = false; } if (breakpoint.iReg == 2) { FlagBit = 4; ct.Dr2 = IntPtr.Zero;; Dr2Busy = false; } if (breakpoint.iReg == 3) { FlagBit = 6; ct.Dr3 = IntPtr.Zero;; Dr3Busy = false; } if (IntPtr.Size == 8) { ulong v = (ulong)ct.Dr7; v &= ~(1ul << FlagBit); ct.Dr7 = (IntPtr)v; } } else { if (!Dr0Busy) { breakpoint.iReg = 0; ct.Dr0 = breakpoint.Address; Dr0Busy = true; } else if (!Dr1Busy) { breakpoint.iReg = 1; ct.Dr1 = breakpoint.Address; Dr1Busy = true; } else if (!Dr2Busy) { breakpoint.iReg = 2; ct.Dr2 = breakpoint.Address; Dr2Busy = true; } else if (!Dr3Busy) { breakpoint.iReg = 3; ct.Dr3 = breakpoint.Address; Dr3Busy = true; } else { breakpoint.SUCC = false; threadOpResult = ResumeThread(breakpoint.ThreadHandle); GetLastError().ThrowOnError(); Win32Event.SetEvent(breakpoint.CompletionEvent); return(0); } ct.Dr6 = IntPtr.Zero; int st = 0; if (breakpoint.Type == HardwareBreakpointType.Code) { st = 0; } if (breakpoint.Type == HardwareBreakpointType.ReadWrite) { st = 3; } if (breakpoint.Type == HardwareBreakpointType.Write) { st = 1; } int le = 0; if (breakpoint.Size == HardwareBreakpointSize.Size1) { le = 0; } if (breakpoint.Size == HardwareBreakpointSize.Size2) { le = 1; } if (breakpoint.Size == HardwareBreakpointSize.Size4) { le = 3; } if (breakpoint.Size == HardwareBreakpointSize.Size8) { le = 2; } SetBits(ref ct.Dr7, 16 + breakpoint.iReg * 4, 2, st); SetBits(ref ct.Dr7, 18 + breakpoint.iReg * 4, 2, le); SetBits(ref ct.Dr7, breakpoint.iReg * 2, 1, 1); } ct.ContextFlags = ContextFlags.DebugRegisters; ct.Set(breakpoint.ThreadHandle); ct = new Win32ThreadContext { ContextFlags = ContextFlags.DebugRegisters }; Win32ThreadContext.Get(breakpoint.ThreadHandle, ref ct); threadOpResult = ResumeThread(breakpoint.ThreadHandle); GetLastError().ThrowOnError(); breakpoint.SUCC = true; Win32Event.SetEvent(breakpoint.CompletionEvent); return(0); }