From 3953ba9fb0a218c1d04a3fb2f60a22ed903c9032 Mon Sep 17 00:00:00 2001 From: Gabriel Ionita Date: Mon, 27 Oct 2025 08:30:00 +0100 Subject: [PATCH] implement formatted output for reads and writes --- src/main.cpp | 3 ++- src/tracer.cpp | 44 +++++++++++++++++++++++++++++++++++++------- src/tracer.hpp | 10 ++++++++-- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2f804aa..5d202fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -86,7 +86,8 @@ int main(int argc, char **argv) { // Start watching the variable Tracer tracer; - tracer.watch_variable(exec_path.string(), var_info->address, var_info->size, prog_args); + tracer.watch_variable(var_info->name, exec_path.string(), var_info->address, + var_info->size, prog_args); return 0; } diff --git a/src/tracer.cpp b/src/tracer.cpp index 7a8938f..d5ff565 100644 --- a/src/tracer.cpp +++ b/src/tracer.cpp @@ -50,12 +50,38 @@ void Tracer::setup_hardware_watchpoint(pid_t pid, uint64_t address, size_t size) ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[7]), dr7); } -void Tracer::handle_watchpoint_hit(pid_t pid, uint64_t address) { - struct user_regs_struct regs; - ptrace(PTRACE_GETREGS, pid, 0, ®s); +int64_t Tracer::read_memory_value(pid_t pid, uint64_t address, size_t size) { + int64_t value = 0; - std::cout << std::format("Variable accessed at RIP: 0x{:x}", regs.rip) - << std::endl; + if (size == 1) { + value = ptrace(PTRACE_PEEKDATA, pid, address, 0) & 0xFF; + } else if (size == 2) { + value = ptrace(PTRACE_PEEKDATA, pid, address, 0) & 0xFFFF; + } else if (size == 4) { + value = ptrace(PTRACE_PEEKDATA, pid, address, 0) & 0xFFFFFFFF; + } else if (size == 8) { + value = ptrace(PTRACE_PEEKDATA, pid, address, 0); + } + + return value; +} + +void Tracer::handle_watchpoint_hit(pid_t pid, uint64_t address, size_t size) { + int64_t current_value = read_memory_value(pid, address, size); + + if (!prev_value_.has_value()) { + // First access - initialize prev_value + prev_value_ = current_value; + std::cout << var_name_ << "\tread\t" << current_value << std::endl; + } else if (prev_value_.value() != current_value) { + // Value changed - this was a write + std::cout << var_name_ << "\twrite\t" << prev_value_.value() + << "->" << current_value << std::endl; + prev_value_ = current_value; + } else { + // Value unchanged - this was a read + std::cout << var_name_ << "\tread\t" << current_value << std::endl; + } } uint64_t Tracer::get_load_address(pid_t pid, const std::string &exec_path) { @@ -91,8 +117,12 @@ uint64_t Tracer::get_load_address(pid_t pid, const std::string &exec_path) { return 0; } -void Tracer::watch_variable(const std::string &exec_path, uint64_t address, size_t size, +void Tracer::watch_variable(const std::string &var_name, const std::string &exec_path, + uint64_t address, size_t size, const std::vector &args) { + var_name_ = var_name; + prev_value_.reset(); + pid_t pid = fork(); if (pid == 0) { @@ -152,7 +182,7 @@ void Tracer::watch_variable(const std::string &exec_path, uint64_t address, size offsetof(struct user, u_debugreg[6]), 0); if (dr6 & 0x1) { // DR0 triggered - handle_watchpoint_hit(pid, runtime_addr); + handle_watchpoint_hit(pid, runtime_addr, size); // Clear DR6 ptrace(PTRACE_POKEUSER, pid, diff --git a/src/tracer.hpp b/src/tracer.hpp index 25313e2..8bd7b6a 100644 --- a/src/tracer.hpp +++ b/src/tracer.hpp @@ -2,18 +2,24 @@ #define GWATCH_TRACER_HPP #include +#include #include #include class Tracer { public: - void watch_variable(const std::string &exec_path, uint64_t address, size_t size, + void watch_variable(const std::string &var_name, const std::string &exec_path, + uint64_t address, size_t size, const std::vector &args = {}); private: void setup_hardware_watchpoint(pid_t pid, uint64_t address, size_t size); - void handle_watchpoint_hit(pid_t pid, uint64_t address); + void handle_watchpoint_hit(pid_t pid, uint64_t address, size_t size); uint64_t get_load_address(pid_t pid, const std::string &exec_path); + int64_t read_memory_value(pid_t pid, uint64_t address, size_t size); + + std::string var_name_; + std::optional prev_value_; }; #endif