Course: System Programming 2025
Project: The DEET Debugger
Reference: CS 110L: Safety in Systems Programming - Project 1
(Assignment Spec | Starter Code)
Note: This project is designed for Linux only, as it relies on Linux-specific system calls like
ptrace.
DEET (Debugs Executables Extremely Terribly) is a lightweight, GDB-like debugger implemented in Rust. It allows users to inspect and control the execution of a target program using standard debugging features like breakpoints, stepping, and variable inspection.
This project demonstrates core system programming concepts including:
- Process Control: Using
fork,exec, andwaitpidto manage inferior processes. - Ptrace API: Leveraging
ptraceto intercept signals, read/write memory, and control execution flow. - DWARF Debugging Information: Parsing DWARF data to map machine code addresses to source code lines, functions, and variables.
- Signal Handling: Managing signals like
SIGTRAPandSIGINTto coordinate between the debugger and the debuggee.
-
Process Management:
- Start a new process (
run) - Continue execution (
continue) - Kill the running process (
quit)
- Start a new process (
-
Execution Control:
- Breakpoints: Set breakpoints by function name, line number, or raw address (
break). - Stepping: Step through the code line-by-line (
stepornext). - Prologue Skipping: Automatically detects function prologues and stops at the first line of user code, ensuring stack frames are set up correctly (similar to GDB).
- Breakpoints: Set breakpoints by function name, line number, or raw address (
-
Inspection:
- Backtrace: Print the current call stack (
backtrace). - Variable Inspection: Print the value of variables in the current scope (
print). Supports global variables and local variables (via stack frame offsets). - Source Listing: Displays the current source line when stopped.
- Backtrace: Print the current call stack (
To build the debugger:
cargo buildTo build the sample programs for debugging:
makeTo run DEET on a target executable (e.g., samples/segfault):
cargo run -- samples/segfaultOnce inside the DEET prompt (deet), you can use the following commands:
| Command | Alias | Description |
|---|---|---|
run [args] |
r |
Start (or restart) the target program with optional arguments. |
continue |
c, cont |
Continue execution until the next breakpoint or signal. |
step [n] |
s |
Execute the next line of source code. Optional n steps multiple lines. |
breakpoint <loc> |
b, break |
Set a breakpoint. <loc> can be a function name (main), line number (10), or address (*0x4005b6). |
print <var> |
p |
Print the value of a variable. |
backtrace |
bt, back |
Show the current call stack. |
quit |
q |
Exit the debugger. |
cargo run -- samples/segfault
(deet) b func1
Setting breakpoint 0 at 0x4011a9
(deet) r
Child stopped (signal SIGTRAP)
Stopped at func1 (/path/to/deet/samples/segfault.c:9)
9 void func1(int a) {
(deet) s
Child stopped (signal SIGTRAP)
Stopped at func1 (/path/to/deet/samples/segfault.c:10)
10 printf("Calling func2\n");
(deet) p a
Found variable a (int 4, located at FramePointerOffset(-20), declared at line 9) in function func1
a = 42
(deet) c
Calling func2
About to segfault... a=2
Child stopped (signal SIGSEGV)
Stopped at func2 (/path/to/deet/samples/segfault.c:5)
5 *(int*)0 = a;
(deet) bt
func2 (/path/to/deet/samples/segfault.c:5)
func1 (/path/to/deet/samples/segfault.c:11)
main (/path/to/deet/samples/segfault.c:15)
(deet) p a
Found variable a (int 4, located at FramePointerOffset(-20), declared at line 3) in function func2
a = 2
(deet) s
Child terminated with signal SIGSEGV
(deet) q
- Inferior Management: The
Inferiorstruct wraps the child process, handlingptracecalls and status updates. - Breakpoint Handling: Breakpoints are implemented by writing the
0xcc(INT 3) instruction to memory. When hit, the original instruction is restored, the instruction pointer is decremented, and execution resumes. - DWARF Parsing: Uses the
gimlicrate to parse debug info. Custom logic was added toDwarfDatato correctly resolve function entry points and skip prologues, ensuring variables are accessible when execution stops. - Variable Printing: Resolves variable locations (stack offsets or absolute addresses) using DWARF data and reads memory via
ptrace.
This project is based on the CS 110L course at Stanford University.