// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause //go:build linux package debug import ( "syscall" "unsafe" ) // StopReason describes why the debuggee stopped. type StopReason int const ( StopNone StopReason = iota StopBreakpoint // software breakpoint hit StopWatchpoint // hardware watchpoint triggered StopSingleStep // single-step completed StopSignal // stopped by a signal StopExited // process exited ) // siginfo_t layout (Linux): si_signo, si_errno, si_code, then union. // The si_addr field is at offset 16 on all supported architectures. type siginfoT struct { SiSigno int32 SiErrno int32 SiCode int32 _pad [125]byte } const ( trapBRKPT = 1 // software breakpoint trapHWBRKPT = 4 // hardware watchpoint ) // StopInfo returns the reason the debuggee stopped and the faulting address // (for watchpoints, the watched address that was accessed). func (s *Session) StopInfo() (StopReason, uint64) { if s.exited { return StopExited, 0 } var info siginfoT _, _, errno := syscall.Syscall6( syscall.SYS_PTRACE, uintptr(syscall.PTRACE_GETSIGINFO), uintptr(s.pid), 0, uintptr(unsafe.Pointer(&info)), 0, 0, ) if errno != 0 { return StopNone, 0 } if info.SiSigno != int32(syscall.SIGTRAP) { return StopSignal, uint64(info.SiCode) } switch info.SiCode { case trapBRKPT: return StopBreakpoint, 0 case trapHWBRKPT: addr := *(*uint64)(unsafe.Pointer(uintptr(unsafe.Pointer(&info)) + 16)) return StopWatchpoint, addr default: return StopSingleStep, 0 } }