On this page
ptrace and Debugging Interfaces
Coverage: ptrace(PTRACE_ATTACH/PTRACE_SYSCALL/PTRACE_PEEKDATA/PTRACE_GETREGS) → strace/gdb implementation principles → /proc/pid/mem → seccomp user notify Applicable to: Linux user space, x86-64/ARM64
Overview
ptrace is the oldest debugging interface in Unix—it allows a tracer process to fully control a tracee process. gdb (breakpoints, single-stepping, register read/write) and strace (system call tracing) are both built on ptrace. In recent years, more efficient alternatives have emerged (/proc/pid/mem, seccomp user notify), but ptrace remains the most universal.
Core ptrace Operations
// Attach (self or others):
; // tracee declares "can be traced"
// or
; // tracer attaches to tracee
; // attach but do not stop (SEIZE, 3.4+)
// Control:
; // continue execution (optional injected signal)
; // stop at syscall entry + exit
; // single-step one instruction
// Read/Write:
; // read tracee memory (word at a time)
; // write tracee memory
; // read registers
; // write registers
// Detach:
;
strace Principles
// Core logic of strace (simplified):
// 1. Fork child process
pid = ;
if
// 2. Parent process (tracer):
; // wait for first stop (SIGTRAP after execve)
while
Every syscall entry/exit goes through: tracer → PTRACE_SYSCALL → waitpid → GETREGS → PTRACE_SYSCALL → waitpid → GETREGS. This is the root cause of strace's high overhead—each traced system call requires 4 context switches (tracee→tracer→tracee→tracer).
gdb Principles
Breakpoints:
gdb uses PTRACE_PEEKDATA to read the instruction at the breakpoint location → saves it
Uses PTRACE_POKEDATA to replace that location with INT3 (0xCC)
Execution reaches INT3 → SIGTRAP → tracer is notified (waitpid)
Tracer restores original instruction → single-step or continue
Single-stepping:
PTRACE_SINGLESTEP → CPU executes 1 instruction → SIGTRAP → tracer
Register read/write:
PTRACE_GETREGS / PTRACE_SETREGS
Memory read/write:
PTRACE_PEEKDATA / PTRACE_POKEDATA (slow, per-word)
/proc/pid/mem: more efficient (pread/pwrite, arbitrary size)
/proc/pid/mem: An Alternative to ptrace
// No need for ptrace ATTACH → read/write tracee's virtual memory
// But ptrace ATTACH is required to write to non-rw regions (before 5.x)
// 5.x+: process_vm_readv/writev is more efficient (no need to open /proc/pid/mem)
int memfd = ;
; // read tracee address addr
; // write tracee address addr
seccomp user notify: "ptrace for the New Era"
// SECCOMP_RET_USER_NOTIF: seccomp filter notifies the supervisor process of syscalls
// Supervisor can check/modify/approve/reject → no need for ptrace (much lower overhead)
// Problems with ptrace:
// All syscalls stop → tracer → tracee (even for syscalls not of interest)
// seccomp user notify:
// Only intercepts syscalls matching the seccomp filter → others are unaffected
// → ptrace overhead is O(all syscalls), seccomp is O(interested ones)
Debugger Limitations
1. A process can only have 1 tracer (multiple straces are not allowed)
2. Processes after PTRACE_TRACEME cannot setuid (security restriction)
3. Cannot trace init (PID 1)
4. Yama LSM: /proc/sys/kernel/yama/ptrace_scope restricts who can trace
0: Anyone can trace anyone (permissive)
1: Can only trace self or descendants (default)
2: Can only trace descendants (admin override)
3: Completely disable ptrace
References
- man: ptrace(2)
- Source code:
kernel/ptrace.c,kernel/seccomp.c - LWN: "Better ptrace", "Seccomp user-space notification"
Keywords: ptrace, PTRACE_ATTACH, PTRACE_SYSCALL, PTRACE_SINGLESTEP, PTRACE_PEEKDATA, strace, gdb, /proc/pid/mem, seccomp user notify, Yama