implement formatted output for reads and writes
This commit is contained in:
parent
56ad622018
commit
3953ba9fb0
@ -86,7 +86,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// Start watching the variable
|
// Start watching the variable
|
||||||
Tracer tracer;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[7]), dr7);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tracer::handle_watchpoint_hit(pid_t pid, uint64_t address) {
|
int64_t Tracer::read_memory_value(pid_t pid, uint64_t address, size_t size) {
|
||||||
struct user_regs_struct regs;
|
int64_t value = 0;
|
||||||
ptrace(PTRACE_GETREGS, pid, 0, ®s);
|
|
||||||
|
|
||||||
std::cout << std::format("Variable accessed at RIP: 0x{:x}", regs.rip)
|
if (size == 1) {
|
||||||
<< std::endl;
|
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) {
|
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;
|
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<std::string> &args) {
|
const std::vector<std::string> &args) {
|
||||||
|
var_name_ = var_name;
|
||||||
|
prev_value_.reset();
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
if (pid == 0) {
|
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);
|
offsetof(struct user, u_debugreg[6]), 0);
|
||||||
|
|
||||||
if (dr6 & 0x1) { // DR0 triggered
|
if (dr6 & 0x1) { // DR0 triggered
|
||||||
handle_watchpoint_hit(pid, runtime_addr);
|
handle_watchpoint_hit(pid, runtime_addr, size);
|
||||||
|
|
||||||
// Clear DR6
|
// Clear DR6
|
||||||
ptrace(PTRACE_POKEUSER, pid,
|
ptrace(PTRACE_POKEUSER, pid,
|
||||||
|
|||||||
@ -2,18 +2,24 @@
|
|||||||
#define GWATCH_TRACER_HPP
|
#define GWATCH_TRACER_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class Tracer {
|
class Tracer {
|
||||||
public:
|
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<std::string> &args = {});
|
const std::vector<std::string> &args = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setup_hardware_watchpoint(pid_t pid, uint64_t address, size_t size);
|
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);
|
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<int64_t> prev_value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user