rptrace is a Ruby wrapper for Linux ptrace(2) focused on building tracers and debugger-like tooling with a Ruby-friendly API.
Overview and Motivation
Linux ptrace(2) is powerful but low-level. This gem wraps process control, register/memory access, and syscall decoding behind a small Ruby API so you can build:
-
strace-like tools - process instrumentation utilities
- debugger-oriented experiments
Features
- Top-level namespace is
Rptrace(noRptrace::Rubynesting) -
TraceeAPI forspawn,attach,cont,syscall,detach, andwait - Register and memory wrappers (
Registers,Memory) -
/proc/<pid>/mapsparser (ProcMaps,Tracee#memory_maps) - Software breakpoints on x86_64 (
Tracee#set_breakpoint,remove_breakpoint) - Syscall lookup (
Rptrace::Syscall) forx86_64/aarch64 - High-level tracing helper
Rptrace.strace(follow_children/yield_seccompsupported) - ptrace event helpers (
Tracee#event_message,Tracee#seccomp_data,Tracee#seccomp_metadata,Tracee#seccomp_filter)
Installation
Add this line to your application's Gemfile:
gem "rptrace"And then execute:
bundle installQuick Start
require "rptrace"
Rptrace.strace("/bin/ls", "-la", "/tmp") do |event|
next unless event.exit?
puts event
endFollow child processes/threads (clone/fork/vfork):
Rptrace.strace("/usr/bin/ruby", "-e", "pid = fork { sleep 0.1 }; Process.wait(pid)", follow_children: true) do |event|
next unless event.enter?
puts "pid=#{event.tracee.pid} #{event.syscall.name}"
endInclude seccomp stop events in trace stream:
Rptrace.strace("/bin/ls", "/tmp", yield_seccomp: true) do |event|
case event
when Rptrace::SyscallEvent
puts event if event.exit?
when Rptrace::SeccompEvent
warn event.to_s
end
endSet and clear a software breakpoint (x86_64):
tracee = Rptrace::Tracee.attach(target_pid)
bp = tracee.set_breakpoint(0x401000)
# ...
bp.restoreInspect seccomp filter metadata and decoded BPF instructions:
tracee = Rptrace::Tracee.attach(target_pid)
tracee.enable_seccomp_events!
supported = tracee.seccomp_supported?
available = tracee.seccomp_filter_available?(index: 0)
meta = tracee.seccomp_metadata(index: 0) # => { filter_off: 0, flags: ... }
flag_names = tracee.seccomp_metadata_flag_names(index: 0) # => [:tsync, :log, ...]
insns = tracee.seccomp_filter(index: 0) # => [{ code:, jt:, jf:, k: }, ...]Permission Guide
ptrace requires privilege on Linux:
- run as
root, or - run with
CAP_SYS_PTRACE, and - ensure Yama policy allows tracing (
/proc/sys/kernel/yama/ptrace_scope)
Integration specs are opt-in and require:
PTRACE_RUN_INTEGRATION=1 bundle exec rspec spec/integrationYou can inspect local ptrace capability setup from Ruby:
diagnostics = Rptrace.ptrace_permissions
puts diagnostics # => { ptrace_privileged:, cap_sys_ptrace:, yama_ptrace_scope:, hints: [...] }Fail fast with an actionable permission error:
Rptrace.ensure_ptrace_privileged!(request: :attach)Examples
examples/simple_strace.rbexamples/syscall_counter.rbexamples/file_access_tracer.rbexamples/memory_reader.rb
API Reference
- Generate docs:
bundle exec yard doc - Open index:
doc/index.html
Development
bundle exec rspecRun specs with coverage threshold check:
COVERAGE=1 COVERAGE_MIN_LINE=95 bundle exec rspec spec/unit spec/rptrace_spec.rbGenerate syscall tables from Linux headers (x86_64 / aarch64):
bundle exec rake syscall:generateYou can override header paths with:
PTRACE_SYSCALL_HEADER_X86_64PTRACE_SYSCALL_HEADER_AARCH64
Optional task controls:
-
ARCH=x86_64(orARCH=x86_64,aarch64) to limit architectures -
STRICT=1to fail if any requested architecture header is missing
Generate YARD documentation:
bundle exec yard docRelease
- CI release workflow:
.github/workflows/release.yml - Trigger by pushing a tag (example:
v0.1.0) or viaworkflow_dispatch - Set repository secret
RUBYGEMS_API_KEYto enablegem push - Local preflight:
bundle exec rake release:preflight - Local credential check:
bundle exec rake release:check_credentials
Limitations
- Linux only
- Ruby 3.1+
- Architecture support:
x86_64andaarch64 - Integration tests require ptrace permission (
rootorCAP_SYS_PTRACE)
License
MIT