feat(verify): add Call trampolines for arm64, riscv64, loong64
Assisted-by: MiMo V2.5 Pro
This commit is contained in:
@@ -5,7 +5,14 @@
|
||||
|
||||
package debug
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Hardware watchpoint support via arm64 debug registers (DBGWVR/DBGWCR).
|
||||
// Accessed via PTRACE_SETREGSET with NT_ARM_HW_BREAK.
|
||||
|
||||
// WatchpointType selects what triggers the watchpoint.
|
||||
type WatchpointType int
|
||||
@@ -16,10 +23,28 @@ const (
|
||||
)
|
||||
|
||||
// wpSlots tracks watchpoint slot occupancy.
|
||||
var wpSlots [4]bool
|
||||
var wpSlots [16]bool // arm64 supports up to 16 watchpoints
|
||||
|
||||
const maxWatchpoints = 16
|
||||
|
||||
// hwBreakState mirrors the kernel's struct user_hwdebug_state.
|
||||
type hwBreakState struct {
|
||||
DbgInfo uint32
|
||||
_pad [4]byte
|
||||
DbgRegs [16]hwBreakReg
|
||||
}
|
||||
|
||||
type hwBreakReg struct {
|
||||
Addr uint64
|
||||
Ctrl uint64
|
||||
}
|
||||
|
||||
const (
|
||||
ntArmHWBreak = 0x403 // NT_ARM_HW_BREAK
|
||||
)
|
||||
|
||||
func (s *Session) FindFreeWatchpointSlot() int {
|
||||
for i := 0; i < 4; i++ {
|
||||
for i := 0; i < maxWatchpoints; i++ {
|
||||
if !wpSlots[i] {
|
||||
return i
|
||||
}
|
||||
@@ -28,20 +53,129 @@ func (s *Session) FindFreeWatchpointSlot() int {
|
||||
}
|
||||
|
||||
func (s *Session) IsWatchpointSlotUsed(slot int) bool {
|
||||
if slot < 0 || slot > 3 {
|
||||
if slot < 0 || slot >= maxWatchpoints {
|
||||
return false
|
||||
}
|
||||
return wpSlots[slot]
|
||||
}
|
||||
|
||||
// SetWatchpoint installs a hardware watchpoint on the given address.
|
||||
func (s *Session) SetWatchpoint(slot int, addr uint64, typ WatchpointType, size int) error {
|
||||
return fmt.Errorf("debug: hardware watchpoints not yet implemented for arm64")
|
||||
if slot < 0 || slot >= maxWatchpoints {
|
||||
return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints-1)
|
||||
}
|
||||
if wpSlots[slot] {
|
||||
return fmt.Errorf("debug: watchpoint slot %d already in use", slot)
|
||||
}
|
||||
|
||||
state, err := s.getHWBreakState()
|
||||
if err != nil {
|
||||
return fmt.Errorf("debug: read watchpoint state: %w", err)
|
||||
}
|
||||
|
||||
if uint32(slot) >= state.DbgInfo {
|
||||
return fmt.Errorf("debug: slot %d exceeds available watchpoints (%d)", slot, state.DbgInfo)
|
||||
}
|
||||
|
||||
state.DbgRegs[slot].Addr = addr
|
||||
ctrl := uint64(1) // enable
|
||||
switch typ {
|
||||
case WatchWrite:
|
||||
ctrl |= 1 << 3 // store only
|
||||
case WatchRead:
|
||||
ctrl |= 3 << 3 // load+store
|
||||
}
|
||||
var bas uint64
|
||||
switch size {
|
||||
case 1:
|
||||
bas = 0x01
|
||||
case 2:
|
||||
bas = 0x03
|
||||
case 4:
|
||||
bas = 0x0F
|
||||
case 8:
|
||||
bas = 0xFF
|
||||
default:
|
||||
return fmt.Errorf("debug: watchpoint size must be 1, 2, 4, or 8")
|
||||
}
|
||||
ctrl |= bas << 5
|
||||
state.DbgRegs[slot].Ctrl = ctrl
|
||||
|
||||
if err := s.setHWBreakState(state); err != nil {
|
||||
return fmt.Errorf("debug: set watchpoint: %w", err)
|
||||
}
|
||||
|
||||
wpSlots[slot] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) ClearWatchpoint(slot int) error {
|
||||
return fmt.Errorf("debug: hardware watchpoints not yet implemented for arm64")
|
||||
if slot < 0 || slot >= maxWatchpoints {
|
||||
return fmt.Errorf("debug: watchpoint slot must be 0-%d", maxWatchpoints-1)
|
||||
}
|
||||
if !wpSlots[slot] {
|
||||
return fmt.Errorf("debug: watchpoint slot %d is not in use", slot)
|
||||
}
|
||||
|
||||
state, err := s.getHWBreakState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
state.DbgRegs[slot].Addr = 0
|
||||
state.DbgRegs[slot].Ctrl = 0
|
||||
if err := s.setHWBreakState(state); err != nil {
|
||||
return err
|
||||
}
|
||||
wpSlots[slot] = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) ClearAllWatchpoints() error {
|
||||
for slot := 0; slot < maxWatchpoints; slot++ {
|
||||
if wpSlots[slot] {
|
||||
if err := s.ClearWatchpoint(slot); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) getHWBreakState() (*hwBreakState, error) {
|
||||
var state hwBreakState
|
||||
iovec := syscall.Iovec{
|
||||
Base: (*byte)(unsafe.Pointer(&state)),
|
||||
Len: uint32(unsafe.Sizeof(state)),
|
||||
}
|
||||
_, _, errno := syscall.Syscall6(
|
||||
syscall.SYS_PTRACE,
|
||||
uintptr(syscall.PTRACE_GETREGSET),
|
||||
uintptr(s.pid),
|
||||
uintptr(ntArmHWBreak),
|
||||
uintptr(unsafe.Pointer(&iovec)),
|
||||
0, 0,
|
||||
)
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
return &state, nil
|
||||
}
|
||||
|
||||
func (s *Session) setHWBreakState(state *hwBreakState) error {
|
||||
iovec := syscall.Iovec{
|
||||
Base: (*byte)(unsafe.Pointer(state)),
|
||||
Len: uint32(unsafe.Sizeof(*state)),
|
||||
}
|
||||
_, _, errno := syscall.Syscall6(
|
||||
syscall.SYS_PTRACE,
|
||||
uintptr(syscall.PTRACE_SETREGSET),
|
||||
uintptr(s.pid),
|
||||
uintptr(ntArmHWBreak),
|
||||
uintptr(unsafe.Pointer(&iovec)),
|
||||
0, 0,
|
||||
)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user