From b50052cc1767e2d5ebd6edc31f459bbace131722 Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Sat, 25 Sep 2021 00:17:46 +0200 Subject: [PATCH] proc/native: support watchpoints on Windows (#2651) --- Documentation/backend_test_health.md | 3 +- pkg/proc/native/hwbreak_amd64.go | 39 ++++++++++++++++++++++++++ pkg/proc/native/hwbreak_other.go | 21 ++++++++++++++ pkg/proc/native/nonative_darwin.go | 13 ++------- pkg/proc/native/threads_darwin.go | 11 ++------ pkg/proc/native/threads_freebsd.go | 11 ++------ pkg/proc/native/threads_linux_386.go | 12 -------- pkg/proc/native/threads_linux_amd64.go | 33 ---------------------- pkg/proc/native/threads_linux_arm64.go | 12 -------- pkg/proc/native/threads_windows.go | 28 ++++++++++++------ pkg/proc/proc_test.go | 3 -- 11 files changed, 88 insertions(+), 98 deletions(-) create mode 100644 pkg/proc/native/hwbreak_amd64.go create mode 100644 pkg/proc/native/hwbreak_other.go diff --git a/Documentation/backend_test_health.md b/Documentation/backend_test_health.md index 31911de0..17958f8c 100644 --- a/Documentation/backend_test_health.md +++ b/Documentation/backend_test_health.md @@ -25,7 +25,6 @@ Tests skipped by each supported backend: * 2 upstream issue - https://github.com/golang/go/issues/29322 * rr skipped = 3 * 3 not implemented -* windows skipped = 5 +* windows skipped = 2 * 1 broken - * 3 not implemented * 1 upstream issue diff --git a/pkg/proc/native/hwbreak_amd64.go b/pkg/proc/native/hwbreak_amd64.go new file mode 100644 index 00000000..e15652a3 --- /dev/null +++ b/pkg/proc/native/hwbreak_amd64.go @@ -0,0 +1,39 @@ +package native + +import ( + "github.com/go-delve/delve/pkg/proc" + "github.com/go-delve/delve/pkg/proc/amd64util" +) + +func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { + return t.withDebugRegisters(func(drs *amd64util.DebugRegisters) error { + return drs.SetBreakpoint(idx, addr, wtype.Read(), wtype.Write(), wtype.Size()) + }) +} + +func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { + return t.withDebugRegisters(func(drs *amd64util.DebugRegisters) error { + drs.ClearBreakpoint(idx) + return nil + }) +} + +func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { + var retbp *proc.Breakpoint + err := t.withDebugRegisters(func(drs *amd64util.DebugRegisters) error { + ok, idx := drs.GetActiveBreakpoint() + if ok { + for _, bp := range t.dbp.Breakpoints().M { + if bp.WatchType != 0 && bp.HWBreakIndex == idx { + retbp = bp + break + } + } + } + return nil + }) + if err != nil { + return nil, err + } + return retbp, nil +} diff --git a/pkg/proc/native/hwbreak_other.go b/pkg/proc/native/hwbreak_other.go new file mode 100644 index 00000000..d841cd9e --- /dev/null +++ b/pkg/proc/native/hwbreak_other.go @@ -0,0 +1,21 @@ +// +build !amd64 + +package native + +import ( + "errors" + + "github.com/go-delve/delve/pkg/proc" +) + +func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { + return nil, errors.New("hardware breakpoints not supported") +} + +func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { + return errors.New("hardware breakpoints not supported") +} + +func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { + return errors.New("hardware breakpoints not supported") +} diff --git a/pkg/proc/native/nonative_darwin.go b/pkg/proc/native/nonative_darwin.go index e5e2a3dd..73308b0d 100644 --- a/pkg/proc/native/nonative_darwin.go +++ b/pkg/proc/native/nonative_darwin.go @@ -9,6 +9,7 @@ import ( "github.com/go-delve/delve/pkg/dwarf/op" "github.com/go-delve/delve/pkg/proc" + "github.com/go-delve/delve/pkg/proc/amd64util" "github.com/go-delve/delve/pkg/proc/internal/ebpf" ) @@ -130,16 +131,8 @@ func (t *nativeThread) restoreRegisters(sr proc.Registers) error { panic(ErrNativeBackendDisabled) } -func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { - panic(ErrNativeBackendDisabled) -} - -func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - panic(ErrNativeBackendDisabled) -} - -func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - panic(ErrNativeBackendDisabled) +func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) error) error { + return proc.ErrHWBreakUnsupported } // Stopped returns whether the thread is stopped at diff --git a/pkg/proc/native/threads_darwin.go b/pkg/proc/native/threads_darwin.go index b30f6398..57feb623 100644 --- a/pkg/proc/native/threads_darwin.go +++ b/pkg/proc/native/threads_darwin.go @@ -13,6 +13,7 @@ import ( sys "golang.org/x/sys/unix" "github.com/go-delve/delve/pkg/proc" + "github.com/go-delve/delve/pkg/proc/amd64util" ) // waitStatus is a synonym for the platform-specific WaitStatus @@ -133,14 +134,6 @@ func (t *nativeThread) restoreRegisters(sr proc.Registers) error { return errors.New("not implemented") } -func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { +func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) error) error { return proc.ErrHWBreakUnsupported } - -func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return proc.ErrHWBreakUnsupported -} - -func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { - return nil, nil -} diff --git a/pkg/proc/native/threads_freebsd.go b/pkg/proc/native/threads_freebsd.go index 4405d952..1d661ad3 100644 --- a/pkg/proc/native/threads_freebsd.go +++ b/pkg/proc/native/threads_freebsd.go @@ -11,6 +11,7 @@ import ( sys "golang.org/x/sys/unix" "github.com/go-delve/delve/pkg/proc" + "github.com/go-delve/delve/pkg/proc/amd64util" ) type waitStatus sys.WaitStatus @@ -121,14 +122,6 @@ func (t *nativeThread) ReadMemory(data []byte, addr uint64) (n int, err error) { return n, err } -func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { +func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) error) error { return proc.ErrHWBreakUnsupported } - -func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return proc.ErrHWBreakUnsupported -} - -func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { - return nil, nil -} diff --git a/pkg/proc/native/threads_linux_386.go b/pkg/proc/native/threads_linux_386.go index 9320c9f2..338a166b 100644 --- a/pkg/proc/native/threads_linux_386.go +++ b/pkg/proc/native/threads_linux_386.go @@ -8,15 +8,3 @@ import ( func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error { return fmt.Errorf("restore regs not supported on i386") } - -func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return proc.ErrHWBreakUnsupported -} - -func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return proc.ErrHWBreakUnsupported -} - -func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { - return nil, nil -} diff --git a/pkg/proc/native/threads_linux_amd64.go b/pkg/proc/native/threads_linux_amd64.go index 35681a4a..c53f6c81 100644 --- a/pkg/proc/native/threads_linux_amd64.go +++ b/pkg/proc/native/threads_linux_amd64.go @@ -86,36 +86,3 @@ func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) erro } return err } - -func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return t.withDebugRegisters(func(drs *amd64util.DebugRegisters) error { - return drs.SetBreakpoint(idx, addr, wtype.Read(), wtype.Write(), wtype.Size()) - }) -} - -func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return t.withDebugRegisters(func(drs *amd64util.DebugRegisters) error { - drs.ClearBreakpoint(idx) - return nil - }) -} - -func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { - var retbp *proc.Breakpoint - err := t.withDebugRegisters(func(drs *amd64util.DebugRegisters) error { - ok, idx := drs.GetActiveBreakpoint() - if ok { - for _, bp := range t.dbp.Breakpoints().M { - if bp.WatchType != 0 && bp.HWBreakIndex == idx { - retbp = bp - break - } - } - } - return nil - }) - if err != nil { - return nil, err - } - return retbp, nil -} diff --git a/pkg/proc/native/threads_linux_arm64.go b/pkg/proc/native/threads_linux_arm64.go index b9835ee2..f2f4d290 100644 --- a/pkg/proc/native/threads_linux_arm64.go +++ b/pkg/proc/native/threads_linux_arm64.go @@ -42,15 +42,3 @@ func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error { } return restoreRegistersErr } - -func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return proc.ErrHWBreakUnsupported -} - -func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return proc.ErrHWBreakUnsupported -} - -func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { - return nil, nil -} diff --git a/pkg/proc/native/threads_windows.go b/pkg/proc/native/threads_windows.go index ff07eea3..cb9a7524 100644 --- a/pkg/proc/native/threads_windows.go +++ b/pkg/proc/native/threads_windows.go @@ -7,6 +7,7 @@ import ( sys "golang.org/x/sys/windows" "github.com/go-delve/delve/pkg/proc" + "github.com/go-delve/delve/pkg/proc/amd64util" "github.com/go-delve/delve/pkg/proc/winutil" ) @@ -157,14 +158,25 @@ func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error { return _SetThreadContext(t.os.hThread, savedRegs.(*winutil.AMD64Registers).Context) } -func (t *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return proc.ErrHWBreakUnsupported -} +func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) error) error { + context := winutil.NewCONTEXT() + context.ContextFlags = _CONTEXT_DEBUG_REGISTERS -func (t *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error { - return proc.ErrHWBreakUnsupported -} + err := _GetThreadContext(t.os.hThread, context) + if err != nil { + return err + } + + drs := amd64util.NewDebugRegisters(&context.Dr0, &context.Dr1, &context.Dr2, &context.Dr3, &context.Dr6, &context.Dr7) + + err = f(drs) + if err != nil { + return err + } + + if drs.Dirty { + return _SetThreadContext(t.os.hThread, context) + } -func (t *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) { - return nil, nil + return nil } diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index 00b224e9..d55e45d5 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -5332,7 +5332,6 @@ func TestVariablesWithExternalLinking(t *testing.T) { } func TestWatchpointsBasic(t *testing.T) { - skipOn(t, "not implemented", "windows") skipOn(t, "not implemented", "freebsd") skipOn(t, "not implemented", "darwin") skipOn(t, "not implemented", "386") @@ -5378,7 +5377,6 @@ func TestWatchpointsBasic(t *testing.T) { } func TestWatchpointCounts(t *testing.T) { - skipOn(t, "not implemented", "windows") skipOn(t, "not implemented", "freebsd") skipOn(t, "not implemented", "darwin") skipOn(t, "not implemented", "386") @@ -5496,7 +5494,6 @@ func TestDwrapStartLocation(t *testing.T) { } func TestWatchpointStack(t *testing.T) { - skipOn(t, "not implemented", "windows") skipOn(t, "not implemented", "freebsd") skipOn(t, "not implemented", "darwin") skipOn(t, "not implemented", "386") -- GitLab