99 lines
2.4 KiB
Go
99 lines
2.4 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
||
|
|
|
||
|
|
//go:build freebsd && amd64
|
||
|
|
|
||
|
|
package debug
|
||
|
|
|
||
|
|
// Regs holds the full general-purpose register set of a traced process
|
||
|
|
// (the FreeBSD amd64 struct reg layout, sys/x86/include/reg.h). FreeBSD
|
||
|
|
// reports segment selectors (FS/GS/ES/DS), not the bases the Linux ptrace
|
||
|
|
// surface carries, and has no ORIG_RAX slot.
|
||
|
|
type Regs struct {
|
||
|
|
R15 uint64
|
||
|
|
R14 uint64
|
||
|
|
R13 uint64
|
||
|
|
R12 uint64
|
||
|
|
RBP uint64
|
||
|
|
RBX uint64
|
||
|
|
R11 uint64
|
||
|
|
R10 uint64
|
||
|
|
R9 uint64
|
||
|
|
R8 uint64
|
||
|
|
RAX uint64
|
||
|
|
RCX uint64
|
||
|
|
RDX uint64
|
||
|
|
RSI uint64
|
||
|
|
RDI uint64
|
||
|
|
RIP uint64
|
||
|
|
CS uint64
|
||
|
|
RFLAGS uint64
|
||
|
|
RSP uint64
|
||
|
|
SS uint64
|
||
|
|
FS uint64
|
||
|
|
GS uint64
|
||
|
|
DS uint64
|
||
|
|
ES uint64
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetPC returns the program counter.
|
||
|
|
func (r *Regs) GetPC() uint64 { return r.RIP }
|
||
|
|
|
||
|
|
// SetPC sets the program counter.
|
||
|
|
func (r *Regs) SetPC(pc uint64) { r.RIP = pc }
|
||
|
|
|
||
|
|
// GetSP returns the stack pointer.
|
||
|
|
func (r *Regs) GetSP() uint64 { return r.RSP }
|
||
|
|
|
||
|
|
// RegValue returns the value of the named register, or false if unknown.
|
||
|
|
func (r *Regs) RegValue(name string) (uint64, bool) {
|
||
|
|
switch name {
|
||
|
|
case "rax", "eax", "ax", "al":
|
||
|
|
return r.RAX, true
|
||
|
|
case "rbx", "ebx", "bx", "bl":
|
||
|
|
return r.RBX, true
|
||
|
|
case "rcx", "ecx", "cx", "cl":
|
||
|
|
return r.RCX, true
|
||
|
|
case "rdx", "edx", "dx", "dl":
|
||
|
|
return r.RDX, true
|
||
|
|
case "rsi", "esi", "si":
|
||
|
|
return r.RSI, true
|
||
|
|
case "rdi", "edi", "di":
|
||
|
|
return r.RDI, true
|
||
|
|
case "rbp", "ebp", "bp":
|
||
|
|
return r.RBP, true
|
||
|
|
case "rsp", "esp", "sp":
|
||
|
|
return r.RSP, true
|
||
|
|
case "r8":
|
||
|
|
return r.R8, true
|
||
|
|
case "r9":
|
||
|
|
return r.R9, true
|
||
|
|
case "r10":
|
||
|
|
return r.R10, true
|
||
|
|
case "r11":
|
||
|
|
return r.R11, true
|
||
|
|
case "r12":
|
||
|
|
return r.R12, true
|
||
|
|
case "r13":
|
||
|
|
return r.R13, true
|
||
|
|
case "r14":
|
||
|
|
return r.R14, true
|
||
|
|
case "r15":
|
||
|
|
return r.R15, true
|
||
|
|
case "rip", "eip":
|
||
|
|
return r.RIP, true
|
||
|
|
default:
|
||
|
|
return 0, false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// breakpointInsn is the software breakpoint instruction.
|
||
|
|
var breakpointInsn = []byte{0xCC} // INT3
|
||
|
|
|
||
|
|
// breakpointPCAdjust is how far PC is past the breakpoint instruction after
|
||
|
|
// a trap. INT3 leaves the hardware PC on the following instruction (Intel
|
||
|
|
// SDM vol 3, "Debug Exceptions") and the FreeBSD T_BPTFLT path delivers
|
||
|
|
// that frame unmodified (sys/amd64/amd64/trap.c), so the trap address is
|
||
|
|
// PC-1, the same correction the Linux side applies.
|
||
|
|
const breakpointPCAdjust = 1
|