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(); }
public IDisposable Set(int threadID, IntPtr address, UIntPtr size, DataBreakpointTrigger trigger) { if (address == IntPtr.Zero) { throw new ArgumentNullException(nameof(address)); } if (size == UIntPtr.Zero) { throw new ArgumentException("Region size must be non-zero", paramName: nameof(size)); } var type = trigger switch { DataBreakpointTrigger.OnWrite => HardwareBreakpointType.Write, DataBreakpointTrigger.OnReadOrWrite => HardwareBreakpointType.ReadWrite, _ => throw new ArgumentException("Invalid value", paramName: nameof(trigger)) }; var sizeType = checked ((ulong)size) switch { 1 => HardwareBreakpointSize.Size1, 2 => HardwareBreakpointSize.Size2, 4 => HardwareBreakpointSize.Size4, 8 => HardwareBreakpointSize.Size8, _ => throw new NotSupportedException( "Memory region size must be 1, 2, 4, or 8 bytes"), }; var threadHandle = Win32Thread.OpenThread(ThreadAccess.All, inheritHandle: false, threadID); if (threadHandle.IsInvalid) { throw new Win32Exception(); } var breakpoint = Win32HardwareBreakpoint.TrySet(threadHandle, type, sizeType, address); if (breakpoint == null) { throw new InvalidOperationException("Data breakpoint limit reached"); } return(breakpoint); }