Project 25: Debugger (ptrace-based)

Project 25: Debugger (ptrace-based)

Build a tiny debugger: run a child process under control, set breakpoints, single-step, and inspect registers/memory.

Quick Reference

Attribute Value
Difficulty Master
Time Estimate 1 month+
Language C (Alternatives: C++, Rust)
Prerequisites Strong x86-64 understanding, ELF familiarity, signals/process control
Key Topics ptrace, breakpoints (int3), single-step, registers, symbolization
CS:APP Chapters 3, 7, 8

1. Learning Objectives

By completing this project, you will:

  1. Control another process (tracee) and understand stop/resume semantics
  2. Implement software breakpoints by patching instructions and handling SIGTRAP
  3. Read/write registers and memory with precision
  4. Build a minimal command loop (break, run, step, continue, regs, x)

2. Project Specification

Build mydb:

  • mydb ./program [args...]
  • Commands (minimum):
    • break <addr|symbol>
    • run
    • step / continue
    • regs
    • x/<n>x <addr> (memory examine)

3. Architecture

  • Launcher: fork + child ptrace(PTRACE_TRACEME) + execve
  • Event loop: waitpid → interpret stops (SIGTRAP, SIGSEGV, exits)
  • Breakpoint manager: save original byte, patch 0xCC, restore on hit
  • Symbol lookup (optional): read ELF symbols (and later DWARF) for break main

4. Testing Strategy

  • Start with a toy program compiled -O0 -g -fno-omit-frame-pointer.
  • Validate breakpoint semantics: hitting at exact instruction, correct RIP adjustment.
  • Add regression tests for multiple breakpoints and repeated hits.

5. Extensions

  • Source line mapping via DWARF (or shell out to addr2line).
  • Watchpoints (data breakpoints) if your platform supports them.
  • Remote stub protocol (GDB remote) as a stretch goal.

6. Reference Reading

  • CS:APP 3e — machine-level debugging sections + ECF/process control
  • Sy Brand — Building a Debugger (step-by-step series)