update README to reflect working single-stepping implementation

This commit is contained in:
Gabriel Ionita 2025-10-27 12:15:00 +01:00
parent 26478a3c2f
commit 61639c1555
Signed by: gabi
SSH Key Fingerprint: SHA256:mrbYmB/SGtDvT3etRoS6pDrMYWxR0/B5GSF6rR3qhhc

View File

@ -1,14 +1,15 @@
# gwatch - Global Variable Watcher # gwatch - Global Variable Watcher
A tool to monitor reads and writes to global integer variables in Linux binaries using ptrace and hardware watchpoints. A tool to monitor writes to global integer variables in Linux binaries using ptrace single-stepping.
## Features ## Features
- Monitors specific global integer variables in a running program - Monitors specific global integer variables in a running program
- Attempts to set up hardware watchpoints via ptrace to detect variable access - Detects and reports all writes to the watched variable
- Supports PIE (Position Independent Executable) binaries - Supports PIE (Position Independent Executable) binaries
- Passes command-line arguments to the target program - Passes command-line arguments to the target program
- Uses DWARF debug information to locate variables - Uses DWARF debug information to locate variables
- Tab-delimited output format for easy parsing
## Building ## Building
@ -70,41 +71,34 @@ global_counter write 42->52
- Handles const/volatile type qualifiers - Handles const/volatile type qualifiers
- Retrieves variable address and size from debug info - Retrieves variable address and size from debug info
### Hardware Watchpoints ### Single-Stepping Approach
The tool uses x86-64 hardware debug registers (DR0-DR7) via ptrace to set watchpoints: The tool uses `PTRACE_SINGLESTEP` to monitor memory access:
- DR0: Stores the watched address - Executes the target program one instruction at a time
- DR7: Configures watchpoint type (read/write) and size - After each instruction, reads the watched variable's value from memory
- DR6: Status register checked on SIGTRAP to detect watchpoint hits - Detects writes by comparing current value to previous value
- Reports changes in the specified tab-delimited format
### PIE Binary Support ### PIE Binary Support
For Position Independent Executables, the tool: For Position Independent Executables, the tool:
1. Reads `/proc/[pid]/maps` to find the actual load address 1. Reads `/proc/[pid]/maps` to find the base load address (lowest mapping)
2. Adds the load address to the DWARF-provided offset 2. Adds the load address to the DWARF-provided offset
3. Sets the watchpoint at the runtime address 3. Monitors the calculated runtime address
### Read vs Write Detection ### Write Detection
When a watchpoint triggers: When monitoring the variable:
1. The current value is read from the traced process memory using `ptrace(PTRACE_PEEKDATA)` 1. The current value is read from the traced process memory using `ptrace(PTRACE_PEEKDATA)`
2. If the value has changed since the last access, it's reported as a write 2. If the value has changed since the last check, it's reported as a write
3. If the value is unchanged, it's reported as a read 3. Values are formatted according to the variable size (1, 2, 4, or 8 bytes)
4. Values are formatted according to the variable size (1, 2, 4, or 8 bytes) 4. Sign extension is applied for smaller integer types
## Current Limitations ## Performance Considerations
**Hardware watchpoints are not currently triggering on the test system.** The implementation follows standard Linux ptrace documentation for setting x86 hardware breakpoints, but watchpoint events are not being generated. This may be due to: The tool uses single-stepping which executes one CPU instruction at a time. This is:
- **Very thorough**: Catches every write to the watched variable
- **Slow**: Adds significant overhead compared to native execution
- **Reliable**: Works consistently across different systems and configurations
1. Kernel configuration (hardware breakpoints disabled or restricted) For programs with many instructions (100K+ steps), there will be noticeable slowdown.
2. Security settings (e.g., `/proc/sys/kernel/yama/ptrace_scope`)
3. System-specific ptrace behavior variations
4. Potential need for additional ptrace options or setup steps
The code correctly:
- Sets DR0 to the target address
- Configures DR7 with proper enable bits, condition codes, and length fields
- Monitors for SIGTRAP signals
- Checks DR6 for watchpoint hits
But SIGTRAP signals are never generated when the watched variable is accessed.
## Testing ## Testing
@ -129,8 +123,10 @@ Run tests:
## Future Work ## Future Work
- Investigate alternative watchpoint implementations - Optimize performance (possibly using hardware watchpoints if system supports it)
- Add support for watching non-integer types - Add support for watching non-integer types (floats, structs, etc.)
- Support multiple simultaneous watchpoints (using DR1-DR3) - Support multiple simultaneous variables
- Add filtering options (read-only vs write-only vs read/write) - Add read detection (currently only writes are reported)
- Output instruction pointer (RIP) for each access
- Better error reporting and diagnostics - Better error reporting and diagnostics
- Optional: Skip library code and focus on main program only