72 lines
2.3 KiB
Go
72 lines
2.3 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (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
|
|
}
|