// Copyright (c) 2026 Petr BalvĂ­n (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