gwatch/src/main.cpp

93 lines
2.7 KiB
C++

#include "symbol.hpp"
#include "tracer.hpp"
#include <cxxopts.hpp>
#include <fcntl.h>
#include <filesystem>
#include <iostream>
#include <libdwarf.h>
#include <string>
#include <unistd.h>
#include <vector>
int main(int argc, char **argv) {
cxxopts::Options options("gwatch",
"Watch global variable reads/writes in a binary");
options.add_options()("exec", "Executable to watch",
cxxopts::value<std::filesystem::path>())(
"var", "Variable name to watch", cxxopts::value<std::string>())(
"h,help", "Print usage");
options.allow_unrecognised_options();
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << "Usage: gwatch --var <symbol> --exec <path> [-- arg1 .. argN]" << std::endl;
std::cout << options.help() << std::endl;
return 0;
}
if (!result.count("exec") || !result.count("var")) {
std::cerr << "Error: Both --exec and --var are required" << std::endl;
std::cerr << "Usage: gwatch --var <symbol> --exec <path> [-- arg1 .. argN]" << std::endl;
return 1;
}
auto exec_path = result["exec"].as<std::filesystem::path>();
auto var_name = result["var"].as<std::string>();
// Collect program arguments (after --)
std::vector<std::string> prog_args;
auto unmatched = result.unmatched();
for (const auto& arg : unmatched) {
prog_args.push_back(arg);
}
// Open the binary file
int fd = open(exec_path.c_str(), O_RDONLY);
if (fd < 0) {
std::cerr << "Error: Cannot open file " << exec_path << std::endl;
return 1;
}
// Initialize libdwarf
Dwarf_Debug dbg = nullptr;
Dwarf_Error err;
int res = dwarf_init_b(fd, DW_GROUPNUMBER_ANY, nullptr, nullptr, &dbg, &err);
if (res != DW_DLV_OK) {
std::cerr << "Error: Failed to initialize DWARF debug info for "
<< exec_path << std::endl;
std::cerr << "Make sure the binary was compiled with debug symbols (-g)"
<< std::endl;
close(fd);
return 1;
}
// Find the variable in debug info
Symbol symbol;
auto var_info = symbol.find_global_var(dbg, var_name);
if (!var_info) {
std::cerr << "Error: Variable '" << var_name << "' not found" << std::endl;
dwarf_finish(dbg);
close(fd);
return 1;
}
std::cout << "Watching variable: " << var_info->name << std::endl;
std::cout << "Address: 0x" << std::hex << var_info->address << std::dec << std::endl;
std::cout << "Size: " << var_info->size << " bytes" << std::endl;
std::cout << std::string(50, '-') << std::endl;
// Close DWARF resources before forking
dwarf_finish(dbg);
close(fd);
// Start watching the variable
Tracer tracer;
tracer.watch_variable(exec_path.string(), var_info->address, var_info->size, prog_args);
return 0;
}