diff --git a/debug/breakpoint.go b/debug/breakpoint.go index ea42cd0..985efea 100644 --- a/debug/breakpoint.go +++ b/debug/breakpoint.go @@ -36,7 +36,7 @@ type Condition struct { func (c *Condition) Eval(regs *Regs) bool { actual, ok := regs.RegValue(c.Reg) if !ok { - return true // unknown register — don't block + return true // unknown register, don't block } var expected uint64 switch { @@ -48,7 +48,7 @@ func (c *Condition) Eval(regs *Regs) bool { } expected = v case c.MemAddr != 0: - // Register-memory comparison — requires a Session, not available here. + // Register-memory comparison, requires a Session, not available here. // Fall back to treating as constant (the caller should resolve). expected = c.Value default: @@ -72,8 +72,7 @@ func (c *Condition) Eval(regs *Regs) bool { } } -// Breakpoints manages the set of breakpoints for a Session. -// Breakpoints manages software breakpoints for a debuggee. +// Breakpoints manages the software breakpoints of one Session. type Breakpoints struct { t tracer bps map[uint64]*Breakpoint @@ -200,7 +199,7 @@ func (bm *Breakpoints) HandleTrap(regs *Regs) *Breakpoint { } // Check the condition (if any). if bp.Cond != nil && !bp.Cond.Eval(regs) { - // Condition not met — restore the byte but do NOT rewind RIP. + // Condition not met, restore the byte but do NOT rewind RIP. // The process continues from the next instruction (past the INT3). word, err := bm.t.Peek(trapAddr) if err == nil { diff --git a/debug/debug_test.go b/debug/debug_test.go index 63a7a8a..bb47ed7 100644 --- a/debug/debug_test.go +++ b/debug/debug_test.go @@ -275,8 +275,7 @@ func TestBreakpointInfo(t *testing.T) { } func TestWatchpointSlotTracking(t *testing.T) { - wpSlots = [4]bool{} // reset - s := &Session{} + s := &Session{} // per-session slots start free // All four slots are free initially. for i := range 4 { @@ -289,8 +288,8 @@ func TestWatchpointSlotTracking(t *testing.T) { } // Manually mark slots 0 and 2 as used (simulating successful SetWatchpoint). - wpSlots[0] = true - wpSlots[2] = true + s.wpSlots[0] = true + s.wpSlots[2] = true if !s.IsWatchpointSlotUsed(0) { t.Error("slot 0 should be in use") @@ -318,7 +317,7 @@ func TestWatchpointSlotTracking(t *testing.T) { // Mark all slots used: FindFreeWatchpointSlot returns -1. for i := range 4 { - wpSlots[i] = true + s.wpSlots[i] = true } if got := s.FindFreeWatchpointSlot(); got != -1 { t.Errorf("FindFreeWatchpointSlot() with all slots used = %d, want -1", got) diff --git a/debug/ptrace_linux.go b/debug/ptrace_linux.go index 0d0c13c..bd5ad95 100644 --- a/debug/ptrace_linux.go +++ b/debug/ptrace_linux.go @@ -22,7 +22,8 @@ type Session struct { cmd *exec.Cmd stopped bool exited bool - codeBase uint64 // base address of the JIT code in the debuggee + codeBase uint64 // base address of the JIT code in the debuggee + wpSlots [16]bool // hardware watchpoint slots in use (DR0-DR3, arm64 BADVR0-15) } // Launch starts the debuggee subprocess (gasm debug --target ...) and diff --git a/debug/watchpoint_linux_amd64.go b/debug/watchpoint_linux_amd64.go index 7c0affb..560a98b 100644 --- a/debug/watchpoint_linux_amd64.go +++ b/debug/watchpoint_linux_amd64.go @@ -20,14 +20,11 @@ const ( WatchRead WatchpointType = 3 // trigger on read or write ) -// wpSlots tracks watchpoint slot occupancy (DR0-DR3). -var wpSlots [4]bool - // FindFreeWatchpointSlot returns the index of the first free watchpoint slot // (0-3), or -1 if all four hardware watchpoints are in use. func (s *Session) FindFreeWatchpointSlot() int { for i := range 4 { - if !wpSlots[i] { + if !s.wpSlots[i] { return i } } @@ -39,7 +36,7 @@ func (s *Session) IsWatchpointSlotUsed(slot int) bool { if slot < 0 || slot > 3 { return false } - return wpSlots[slot] + return s.wpSlots[slot] } // SetWatchpoint installs a hardware watchpoint on the given address. @@ -47,7 +44,7 @@ func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size if slot < 0 || slot > 3 { return fmt.Errorf("debug: watchpoint slot must be 0-3") } - if wpSlots[slot] { + if s.wpSlots[slot] { return fmt.Errorf("debug: watchpoint slot %d already in use", slot) } @@ -96,7 +93,7 @@ func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size if err := ptracePokeUser(s.pid, 0x38, dr7); err != nil { return fmt.Errorf("debug: set DR7: %w", err) } - wpSlots[slot] = true + s.wpSlots[slot] = true return nil } @@ -105,7 +102,7 @@ func (s *Session) ClearWatchpoint(slot int) error { if slot < 0 || slot > 3 { return fmt.Errorf("debug: watchpoint slot must be 0-3") } - if !wpSlots[slot] { + if !s.wpSlots[slot] { return fmt.Errorf("debug: watchpoint slot %d is not in use", slot) } dr7, err := ptracePeekUser(s.pid, 0x38) @@ -116,14 +113,14 @@ func (s *Session) ClearWatchpoint(slot int) error { if err := ptracePokeUser(s.pid, 0x38, dr7); err != nil { return err } - wpSlots[slot] = false + s.wpSlots[slot] = false return nil } // ClearAllWatchpoints removes all hardware watchpoints. func (s *Session) ClearAllWatchpoints() error { for slot := range 4 { - if wpSlots[slot] { + if s.wpSlots[slot] { if err := s.ClearWatchpoint(slot); err != nil { return err } diff --git a/debug/watchpoint_linux_arm64.go b/debug/watchpoint_linux_arm64.go index 3003e3d..871ef83 100644 --- a/debug/watchpoint_linux_arm64.go +++ b/debug/watchpoint_linux_arm64.go @@ -22,9 +22,6 @@ const ( WatchRead WatchpointType = 3 ) -// wpSlots tracks watchpoint slot occupancy. -var wpSlots [16]bool // arm64 supports up to 16 watchpoints - const maxWatchpoints = 16 // hwBreakState mirrors the kernel's struct user_hwdebug_state. @@ -45,7 +42,7 @@ const ( func (s *Session) FindFreeWatchpointSlot() int { for i := range maxWatchpoints { - if !wpSlots[i] { + if !s.wpSlots[i] { return i } } @@ -56,7 +53,7 @@ func (s *Session) IsWatchpointSlotUsed(slot int) bool { if slot < 0 || slot >= maxWatchpoints { return false } - return wpSlots[slot] + return s.wpSlots[slot] } // SetWatchpoint installs a hardware watchpoint on the given address. @@ -64,7 +61,7 @@ func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size if slot < 0 || slot >= maxWatchpoints { return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints-1) } - if wpSlots[slot] { + if s.wpSlots[slot] { return fmt.Errorf("debug: watchpoint slot %d already in use", slot) } @@ -105,7 +102,7 @@ func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size return fmt.Errorf("debug: set watchpoint: %w", err) } - wpSlots[slot] = true + s.wpSlots[slot] = true return nil } @@ -113,7 +110,7 @@ func (s *Session) ClearWatchpoint(slot int) error { if slot < 0 || slot >= maxWatchpoints { return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints-1) } - if !wpSlots[slot] { + if !s.wpSlots[slot] { return fmt.Errorf("debug: watchpoint slot %d is not in use", slot) } @@ -126,13 +123,13 @@ func (s *Session) ClearWatchpoint(slot int) error { if err := s.setHWBreakState(state); err != nil { return err } - wpSlots[slot] = false + s.wpSlots[slot] = false return nil } func (s *Session) ClearAllWatchpoints() error { for slot := 0; slot < maxWatchpoints; slot++ { - if wpSlots[slot] { + if s.wpSlots[slot] { if err := s.ClearWatchpoint(slot); err != nil { return err } diff --git a/debug/watchpoint_linux_loong64.go b/debug/watchpoint_linux_loong64.go index ef7f4ad..dd90a85 100644 --- a/debug/watchpoint_linux_loong64.go +++ b/debug/watchpoint_linux_loong64.go @@ -21,14 +21,11 @@ const ( WatchRead WatchpointType = 3 ) -// wpSlots tracks watchpoint slot occupancy. -var wpSlots [4]bool - const maxWatchpoints = 4 func (s *Session) FindFreeWatchpointSlot() int { for i := range maxWatchpoints { - if !wpSlots[i] { + if !s.wpSlots[i] { return i } } @@ -39,7 +36,7 @@ func (s *Session) IsWatchpointSlotUsed(slot int) bool { if slot < 0 || slot >= maxWatchpoints { return false } - return wpSlots[slot] + return s.wpSlots[slot] } // SetWatchpoint installs a hardware watchpoint. @@ -47,7 +44,7 @@ func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size if slot < 0 || slot >= maxWatchpoints { return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints-1) } - if wpSlots[slot] { + if s.wpSlots[slot] { return fmt.Errorf("debug: watchpoint slot %d already in use", slot) } if size != 1 && size != 2 && size != 4 && size != 8 { @@ -85,7 +82,7 @@ func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size return fmt.Errorf("debug: set watchpoint control: %w", err) } - wpSlots[slot] = true + s.wpSlots[slot] = true return nil } @@ -93,20 +90,20 @@ func (s *Session) ClearWatchpoint(slot int) error { if slot < 0 || slot >= maxWatchpoints { return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints-1) } - if !wpSlots[slot] { + if !s.wpSlots[slot] { return fmt.Errorf("debug: watchpoint slot %d is not in use", slot) } if err := ptracePokeUser(s.pid, uintptr(0x1001+slot*8), 0); err != nil { return err } - wpSlots[slot] = false + s.wpSlots[slot] = false return nil } func (s *Session) ClearAllWatchpoints() error { for slot := 0; slot < maxWatchpoints; slot++ { - if wpSlots[slot] { + if s.wpSlots[slot] { if err := s.ClearWatchpoint(slot); err != nil { return err } diff --git a/debug/watchpoint_linux_riscv64.go b/debug/watchpoint_linux_riscv64.go index 00dd802..c7c8a59 100644 --- a/debug/watchpoint_linux_riscv64.go +++ b/debug/watchpoint_linux_riscv64.go @@ -21,14 +21,11 @@ const ( WatchRead WatchpointType = 3 ) -// wpSlots tracks watchpoint slot occupancy. -var wpSlots [4]bool - const maxWatchpoints = 4 func (s *Session) FindFreeWatchpointSlot() int { for i := range maxWatchpoints { - if !wpSlots[i] { + if !s.wpSlots[i] { return i } } @@ -39,7 +36,7 @@ func (s *Session) IsWatchpointSlotUsed(slot int) bool { if slot < 0 || slot >= maxWatchpoints { return false } - return wpSlots[slot] + return s.wpSlots[slot] } // SetWatchpoint installs a hardware watchpoint. @@ -47,7 +44,7 @@ func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size if slot < 0 || slot >= maxWatchpoints { return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints-1) } - if wpSlots[slot] { + if s.wpSlots[slot] { return fmt.Errorf("debug: watchpoint slot %d already in use", slot) } if size != 1 && size != 2 && size != 4 && size != 8 { @@ -87,7 +84,7 @@ func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size return fmt.Errorf("debug: set watchpoint control: %w", err) } - wpSlots[slot] = true + s.wpSlots[slot] = true return nil } @@ -95,7 +92,7 @@ func (s *Session) ClearWatchpoint(slot int) error { if slot < 0 || slot >= maxWatchpoints { return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints-1) } - if !wpSlots[slot] { + if !s.wpSlots[slot] { return fmt.Errorf("debug: watchpoint slot %d is not in use", slot) } @@ -103,13 +100,13 @@ func (s *Session) ClearWatchpoint(slot int) error { if err := ptracePokeUser(s.pid, uintptr(0x1001+slot*8), 0); err != nil { return err } - wpSlots[slot] = false + s.wpSlots[slot] = false return nil } func (s *Session) ClearAllWatchpoints() error { for slot := 0; slot < maxWatchpoints; slot++ { - if wpSlots[slot] { + if s.wpSlots[slot] { if err := s.ClearWatchpoint(slot); err != nil { return err }