// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause //go:build linux && riscv64 package debug import ( "fmt" ) // Hardware watchpoints are not reachable through the riscv64 kernel ptrace // interface. arch/riscv/kernel/ptrace.c forwards every POKEUSER/PEEKUSER to // the generic ptrace_request, and the riscv user_regset view contains only // the GPR, FP and vector regsets: there is no debug-register or trigger // regset, and offsets outside the view fail with EIO. The Sdtrig CSRs // (tselect/tdata1/tdata2) are not exposed to ptrace either. Until the // kernel grows a trigger regset, SetWatchpoint reports the fact instead of // poking a window that does not exist. // WatchpointType selects what triggers the watchpoint. type WatchpointType int const ( WatchWrite WatchpointType = 1 WatchRead WatchpointType = 3 ) // maxWatchpoints reports the number of hardware watchpoint slots the // architecture provides. riscv64 exposes none via ptrace; the bound exists // so the slot bookkeeping stays consistent. func maxWatchpoints() int { return 4 } // archWatchpointAddr resolves the address of the watchpoint that fired. // Unreachable in practice (watchpoints cannot be armed), but si_addr names // the accessed address where the kernel does report one. func archWatchpointAddr(s *Session, siAddr uint64) uint64 { return siAddr } func (s *Session) FindFreeWatchpointSlot() int { for i := range maxWatchpoints() { if !s.wpSlots[i] { return i } } return -1 } func (s *Session) IsWatchpointSlotUsed(slot int) bool { if slot < 0 || slot >= maxWatchpoints() { return false } return s.wpSlots[slot] } // SetWatchpoint always fails: the riscv64 kernel ptrace interface has no // hardware-watchpoint access. func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size int) error { return fmt.Errorf("debug: hardware watchpoints are not supported by the riscv64 kernel ptrace interface") } // ClearWatchpoint always fails: no watchpoint can ever be armed. func (s *Session) ClearWatchpoint(slot int) error { if slot < 0 || slot >= maxWatchpoints() { return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints()-1) } return fmt.Errorf("debug: watchpoint slot %d is not in use", slot) } func (s *Session) ClearAllWatchpoints() error { return nil }