#include "symbol.hpp" #include "tracer.hpp" #include #include #include #include #include #include #include #include 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())( "var", "Variable name to watch", cxxopts::value())( "h,help", "Print usage"); options.allow_unrecognised_options(); auto result = options.parse(argc, argv); if (result.count("help")) { std::cout << "Usage: gwatch --var --exec [-- 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 --exec [-- arg1 .. argN]" << std::endl; return 1; } auto exec_path = result["exec"].as(); auto var_name = result["var"].as(); // Collect program arguments (after --) std::vector 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; } // Close DWARF resources before forking dwarf_finish(dbg); close(fd); // Start watching the variable Tracer tracer; tracer.watch_variable(var_info->name, exec_path.string(), var_info->address, var_info->size, prog_args); return 0; }