Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

pstrace

A minimal Linux syscall tracer for x86_64 using ptrace(2).

Build

make

Usage

pstrace [OPTION]... COMMAND [ARG]...
pstrace [OPTION]... -p PID
Flag Description
-f Follow forks — trace child processes
-p PID Attach to an existing process
-o FILE Write trace output to FILE (default: stderr)
-h Show help
pstrace /bin/ls /tmp
pstrace -f make
pstrace -p $(pgrep nginx)
pstrace -o trace.out curl example.com

Architecture

pstrace.c    Main tracing engine: fork/attach, ptrace loop,
             register decoding, signal/exit handling,
             argument and return-value formatting.

syscalls.h   Core types: arg_type enum, syscall_info struct.
syscalls.c   Syscall name table (~170 entries, binary search),
             errno-to-name mapping.

flags.h      flag_def struct, table declarations,
             format_flags() signature.
flags.c      Symbolic constant tables (open flags, mmap prot/flags,
             signals, socket domains/types, clone flags, access modes),
             flag-to-string formatting engine.

Each module does one thing. pstrace.c orchestrates; data lives where it belongs — syscall names in syscalls.c, flag constants in flags.c.

Design rules

  • No dependencies. libc only. No libunwind, libcap, libelf.
  • One file, one concern. Syscall names aren't flag tables aren't the tracing loop.
  • Data drives code. Adding a syscall is one line in a table. Adding a flag type is one table + one case in format_arg().
  • Correct over clever. The ptrace state machine handles fork/clone/execve/signal interleaving properly. If it can't be made simple, it isn't made at all.
  • Compiles clean. -std=c11 -Wall -Wextra -Wpedantic -O2.

Limitations (by design)

  • x86_64 only. The register ABI (orig_rax, rdi, rsi, rdx, r10, r8, r9) is baked in.
  • No syscall filtering (-e). Add it when you need it.
  • No timestamp prefix (-t). Pipe output through ts if needed.
  • String arguments read up to 256 bytes via PTRACE_PEEKDATA.
  • -p requires ptrace_scope=0 or root on modern kernels (YAMA LSM).
  • Anti-debugging seccomp filters (e.g., spotify) produce ENOSYS for all syscalls — a process-level issue, not a tracer bug.

How it works

  1. Fork child, PTRACE_TRACEME, exec target.
  2. Parent waits, sets PTRACE_O_TRACESYSGOOD | TRACEFORK | TRACECLONE | TRACEEXEC.
  3. Loop: waitpid → PTRACE_GETREGS → decode syscall → PTRACE_SYSCALL → repeat.
  4. On syscall-enter: print name and decoded arguments (no newline).
  5. On syscall-exit: print ) = return_value\n.
  6. Signals, fork/clone children, and execve are handled with the appropriate PTRACE_EVENT stops and state transitions.

About

Minimal Linux syscall tracer written in C using ptrace(2).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages