From 5228b6117d5dd1732b746e2f5590451dbf8d00e8 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Mon, 22 Jul 2024 16:20:19 +0800 Subject: [PATCH] feat: process custom gdb commands --- flake.lock | 8 ++--- flake.nix | 1 - include/api.hpp | 7 ++-- include/config.hpp | 2 ++ include/difftest.hpp | 27 ++++++++++---- src/cli.cpp | 8 +++-- src/difftest.cpp | 55 ++++++++++++++++++++++------- src/gdbstub.cpp | 84 +++++++++++++++++++++++++++++++++++++++++--- src/main.cpp | 11 +++--- 9 files changed, 164 insertions(+), 39 deletions(-) diff --git a/flake.lock b/flake.lock index b4bf5e4..5e5d23f 100644 --- a/flake.lock +++ b/flake.lock @@ -112,11 +112,11 @@ ] }, "locked": { - "lastModified": 1714033851, - "narHash": "sha256-Mi7m3p9vmtNOdyD1hLse/tzxDuV3bwP0gKrmOBPiQ4c=", + "lastModified": 1721457008, + "narHash": "sha256-ekpve0om5hzC1Ntd3zm1cZ9oS5pnr7a2n/tueyqFOsg=", "ref": "refs/heads/master", - "rev": "809554f41ac44acc4b1ec21473746c2af9993f2f", - "revCount": 149, + "rev": "e7aa3319d52fa987ac2192f63aef3dcb1b057e3a", + "revCount": 151, "type": "git", "url": "https://git.xinyang.life/xin/nur.git" }, diff --git a/flake.nix b/flake.nix index f79213a..a78db2d 100644 --- a/flake.nix +++ b/flake.nix @@ -52,4 +52,3 @@ } ); } - diff --git a/include/api.hpp b/include/api.hpp index ed19fd0..114aee8 100644 --- a/include/api.hpp +++ b/include/api.hpp @@ -53,10 +53,11 @@ class Target { public: DiffTargetApi ops; TargetMeta meta; - arch_info_t arch; - size_t argsize; std::vector args; // used as a buffer to store target specific values + bool *do_difftest; + arch_info_t *isa_arch_info; + size_t *dbg_state_size; gdb_action_t last_res; Target(){}; @@ -68,4 +69,4 @@ public: bool is_on_breakpoint(const gdb_action_t &res) const; }; -#endif \ No newline at end of file +#endif diff --git a/include/config.hpp b/include/config.hpp index bb90278..7574852 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -10,6 +10,8 @@ struct Config { std::vector refs_prefix; std::filesystem::path dut; std::string dut_prefix = ""; + std::string gdbstub_addr = "/tmp/gdbstub-diffu.sock"; + bool use_debugger = false; int cli_parse(int argc, char **argv); }; diff --git a/include/difftest.hpp b/include/difftest.hpp index 4985516..7410e0e 100644 --- a/include/difftest.hpp +++ b/include/difftest.hpp @@ -16,8 +16,19 @@ private: // target used for read_reg, write_reg, read_mem, write_mem Target *current_target = &dut; + bool halt_status = false; + inline void start_run() { + __atomic_store_n(&halt_status, false, __ATOMIC_RELAXED); + }; + inline bool is_halt() { + return __atomic_load_n(&halt_status, __ATOMIC_RELAXED); + }; - bool exec(size_t n, gdb_action_t *ret); + struct ExecRet { + bool at_breakpoint; + bool do_difftest; + }; + ExecRet exec(size_t n, gdb_action_t *ret); public: Difftest(Target &&dut, std::vector &&refs); @@ -35,14 +46,16 @@ public: bool del_bp(size_t addr, bp_type_t type); bool check_all(); + int sync_regs_to_ref(void); - arch_info_t get_arch() const { - std::cout << dut.arch.reg_num << std::endl; - return dut.arch; - } + inline void halt() { + __atomic_store_n(&halt_status, true, __ATOMIC_RELAXED); + }; + + arch_info_t get_arch() const { return *dut.isa_arch_info; } static bool check(Target &dut, Target &ref) { - for (int r = 0; r < dut.arch.reg_num; r++) { + for (int r = 0; r < dut.isa_arch_info->reg_num; r++) { size_t regdut = 0, regref = 0; dut.ops.read_reg(dut.args.data(), r, ®dut); ref.ops.read_reg(ref.args.data(), r, ®ref); @@ -92,4 +105,4 @@ public: Iterator end() { return Iterator(*this, refs.size(), false); } }; -#endif \ No newline at end of file +#endif diff --git a/src/cli.cpp b/src/cli.cpp index a92ecbb..add616d 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -24,8 +24,12 @@ int Config::cli_parse(int argc, char **argv) { app.add_option("--dut-prefix", dut_prefix, "Optional prefix for design under test"); + app.add_option("--listen", gdbstub_addr, "Gdb remote listen address"); + + app.add_flag("-g", use_debugger, "Launch gdb remote stub"); + app.set_config("-c,--config") - ->transform(CLI::FileOnDefaultPath("./difftest.toml")); + ->transform(CLI::FileOnDefaultPath("difftest.toml")); // Default value for refs_prefix app.callback([&]() { @@ -45,4 +49,4 @@ int Config::cli_parse(int argc, char **argv) { CLI11_PARSE(app, argc, argv); return 0; -} \ No newline at end of file +} diff --git a/src/difftest.cpp b/src/difftest.cpp index 3d5d333..8da7c30 100644 --- a/src/difftest.cpp +++ b/src/difftest.cpp @@ -11,8 +11,8 @@ Difftest::Difftest(Target &&dut, std::vector &&refs) { this->refs = std::move(refs); for (const auto &ref : refs) { - if (dut.arch.reg_byte != ref.arch.reg_byte || - dut.arch.reg_num != ref.arch.reg_num) { + if (dut.isa_arch_info->reg_byte != ref.isa_arch_info->reg_byte || + dut.isa_arch_info->reg_num != ref.isa_arch_info->reg_num) { throw std::runtime_error("Ref and dut must have the same architecture"); } } @@ -36,9 +36,9 @@ void Difftest::setup(const std::filesystem::path &memory_file) { for (auto it = this->begin(); it != this->end(); ++it) { auto &target = *it; target.ops.init(target.args.data()); - target.ops.write_mem(target.args.data(), 0x80000000UL, membuf.size(), - membuf.data()); - target.ops.write_reg(target.args.data(), 32, 0x80000000UL); + if (target.ops.write_mem(target.args.data(), 0x80000000UL, membuf.size(), + membuf.data()) != 0) + throw std::runtime_error("write_mem failed"); } } @@ -49,26 +49,29 @@ bool Difftest::check_all() { return true; } -bool Difftest::exec(size_t n, gdb_action_t *ret) { +Difftest::ExecRet Difftest::exec(size_t n, gdb_action_t *ret) { + ExecRet exec_ret = {.at_breakpoint = false, .do_difftest = true}; while (n--) { - bool breakflag = false; Target *pbreak = &(*(this->begin())); + // TODO: For improvement, use ThreadPool here for concurrent execution? for (auto it = this->begin(); it != this->end(); ++it) { auto &target = *it; + *target.do_difftest = true; target.ops.stepi(target.args.data(), &target.last_res); if (target.is_on_breakpoint()) { - breakflag = true; + exec_ret.at_breakpoint = true; pbreak = ⌖ } + exec_ret.do_difftest = *target.do_difftest && exec_ret.do_difftest; } - if (breakflag) { + if (exec_ret.at_breakpoint) { ret->reason = pbreak->last_res.reason; ret->data = pbreak->last_res.data; - return false; + break; } } - return true; + return exec_ret; } gdb_action_t Difftest::stepi() { @@ -80,8 +83,14 @@ gdb_action_t Difftest::stepi() { gdb_action_t Difftest::cont() { gdb_action_t ret = {.reason = gdb_action_t::ACT_NONE}; - while (exec(1, &ret)) { - check_all(); + ExecRet exec_ret; + start_run(); + while (!is_halt()) { + exec_ret = exec(1, &ret); + if (exec_ret.do_difftest) + check_all(); + if (exec_ret.at_breakpoint) + break; }; return ret; } @@ -96,6 +105,26 @@ int Difftest::write_reg(int regno, size_t value) { value); } +int Difftest::sync_regs_to_ref(void) { + std::vector regs; + int ret = 0; + for (int i = 0; i <= get_arch().reg_num; i++) { + size_t r; + ret = dut.ops.read_reg(dut.args.data(), i, &r); + if (ret) + return ret; + regs.push_back(r); + } + for (auto &ref : refs) { + for (int i = 0; i <= get_arch().reg_num; i++) { + ret = ref.ops.write_reg(ref.args.data(), i, regs.at(i)); + if (ret) + return ret; + } + } + return ret; +} + int Difftest::read_mem(size_t addr, size_t len, void *val) { return current_target->ops.read_mem(current_target->args.data(), addr, len, val); diff --git a/src/gdbstub.cpp b/src/gdbstub.cpp index 583c4e3..6d613bb 100644 --- a/src/gdbstub.cpp +++ b/src/gdbstub.cpp @@ -1,4 +1,8 @@ +#include +#include +#include #include +#include extern "C" { #include } @@ -43,7 +47,71 @@ static bool difftest_del_bp(void *args, size_t addr, bp_type_t type) { return diff->del_bp(addr, type); } -int gdbstub_loop(Difftest *diff) { +static void difftest_on_interrupt(void *args) { + Difftest *diff = (Difftest *)args; + puts("interrupt"); + diff->halt(); +} + +std::vector split_into_args(const std::string &command) { + std::istringstream iss(command); + std::vector args; + std::string token; + while (iss >> token) { + args.push_back(token); + } + return args; +} + +static char *gdbstub_monitor(void *args, const char *s) { + Difftest *diff = (Difftest *)args; + CLI::App parser; + std::string ret = ""; + + parser.add_subcommand("help", "Print help message")->callback([&]() { + ret = parser.help(); + }); + auto sync = parser.add_subcommand("sync", "Sync states between targets") + ->callback([&]() { diff->sync_regs_to_ref(); }); + + std::string cmdstr; + int slen = strlen(s); + int ch; + for (int i = 0; i < slen; i += 2) { + sscanf(&s[i], "%02x", &ch); + cmdstr.push_back(ch); + } + + auto arglist = split_into_args(cmdstr); + std::vector argv = {""}; + for (const auto &arg : arglist) { + argv.push_back(static_cast(arg.c_str())); + } + + try { + (parser).parse((argv.size()), (argv.data())); + } catch (const CLI ::ParseError &e) { + std::ostringstream os; + os << "Failed to parse " << cmdstr << std::endl + << parser.help() << std::endl; + ret = os.str(); + } + + if (ret[0] == '\0') { + return NULL; + } else { + std::ostringstream ret_stream; + // Set formatting options for the stream + ret_stream << std::hex << std::setfill('0'); + + for (unsigned char c : ret) { + ret_stream << std::setw(2) << static_cast(c); + } + return strdup(ret_stream.str().c_str()); + } +} + +int gdbstub_loop(Difftest *diff, std::string socket_addr) { target_ops gdbstub_ops = {.cont = difftest_cont, .stepi = difftest_stepi, .read_reg = difftest_read_reg, @@ -52,13 +120,19 @@ int gdbstub_loop(Difftest *diff) { .write_mem = difftest_write_mem, .set_bp = difftest_set_bp, .del_bp = difftest_del_bp, - .on_interrupt = NULL}; + .on_interrupt = difftest_on_interrupt, + .monitor = gdbstub_monitor}; gdbstub_t gdbstub_priv; - char socket_addr[] = "127.0.0.1:1234"; - gdbstub_init(&gdbstub_priv, &gdbstub_ops, diff->get_arch(), socket_addr); std::cout << "Waiting for gdb connection at " << socket_addr << std::endl; + + if (!gdbstub_init(&gdbstub_priv, &gdbstub_ops, diff->get_arch(), + socket_addr.c_str())) { + std::cerr << "Failed to init socket at: " << socket_addr << std::endl; + return false; + } + bool success = gdbstub_run(&gdbstub_priv, diff); gdbstub_close(&gdbstub_priv); return !success; -} \ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index eed1644..7b1110d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,9 +2,8 @@ #include "config.hpp" #include "difftest.hpp" -// extern "C" { -int gdbstub_loop(Difftest *); -// } +int gdbstub_loop(Difftest *, std::string); + int main(int argc, char **argv) { Config config; int ret = 0; @@ -27,7 +26,11 @@ int main(int argc, char **argv) { difftest.setup(config.memory_file); - gdbstub_loop(&difftest); + if (config.use_debugger) { + gdbstub_loop(&difftest, config.gdbstub_addr); + } else { + difftest.cont(); + } return 0; }