From 82207f964a416e3f200d89114fba5e55fbda2c4e Mon Sep 17 00:00:00 2001 From: Recolic Keghart <root@recolic.net> Date: Sun, 15 Dec 2019 03:31:56 +0800 Subject: [PATCH] > Manual commit: Finished watchpoints. U201614531 recolic Linux RECOLICPC 5.4.2-arch1-1 #1 SMP PREEMPT Thu, 05 Dec 2019 12:29:40 +0000 x86_64 GNU/Linux 03:31:56 up 3 days, 10:50, 1 user, load average: 1.28, 1.79, 1.68 a81d98bac18313b314650ef918308dafb0838b90 --- nemu/include/common.h | 10 +++++ nemu/include/monitor/expr.h | 2 +- nemu/include/monitor/watchpoint.h | 31 ++++++++++++--- nemu/src/monitor/cpu-exec.cc | 19 ++++++++- nemu/src/monitor/debug/expr.cc | 19 ++------- nemu/src/monitor/debug/ui.cc | 58 ++++++++++++++++++++++------ nemu/src/monitor/debug/watchpoint.cc | 37 +++++++++++------- 7 files changed, 129 insertions(+), 47 deletions(-) diff --git a/nemu/include/common.h b/nemu/include/common.h index 44d6c1a..b6e40c4 100644 --- a/nemu/include/common.h +++ b/nemu/include/common.h @@ -16,6 +16,7 @@ #include <stdint.h> #include <assert.h> #include <string.h> +#include <string> typedef uint32_t rtlreg_t; @@ -27,4 +28,13 @@ typedef uint16_t ioaddr_t; #include "debug.h" #include "macro.h" +#include <iomanip> +#include <sstream> +inline std::string num2hex(uint32_t n) { + static std::stringstream ss; + ss.str(""); + ss << "0x" << std::setfill('0') << std::setw(8) << std::hex << n << std::dec; + return ss.str(); +} + #endif diff --git a/nemu/include/monitor/expr.h b/nemu/include/monitor/expr.h index c240505..b5d5e6e 100644 --- a/nemu/include/monitor/expr.h +++ b/nemu/include/monitor/expr.h @@ -3,6 +3,6 @@ #include "common.h" -uint32_t expr(char *, bool *); +uint32_t evaluate_expr(std::string e); #endif diff --git a/nemu/include/monitor/watchpoint.h b/nemu/include/monitor/watchpoint.h index f0a250f..7d4c0e5 100644 --- a/nemu/include/monitor/watchpoint.h +++ b/nemu/include/monitor/watchpoint.h @@ -3,13 +3,34 @@ #include "common.h" -typedef struct watchpoint { - int NO; - struct watchpoint *next; +#include <string> +#include <list> +#include <iostream> - /* TODO: Add more members if necessary */ +#include "monitor/expr.h" +struct WP { + std::string expr; + uint32_t curr_value; + int id; + + bool evalulate() { + auto new_value = evaluate_expr(expr); + std::swap(new_value, curr_value); + return new_value != curr_value; + } + WP(std::string e, int id) : expr(e), id(id) { + evalulate(); // initial expr value. + } +}; + +extern std::list<WP> watchpoints; +// WARNING: Not thread-safe +extern int max_watchpoint_id; + +inline std::ostream & operator<< (std::ostream &os, const WP &watchpoint) { + return os << "watchpoint " << watchpoint.id << "{expr=" << watchpoint.expr << ", value=" << num2hex(watchpoint.curr_value) << "}"; +} -} WP; #endif diff --git a/nemu/src/monitor/cpu-exec.cc b/nemu/src/monitor/cpu-exec.cc index 5c46817..3234777 100644 --- a/nemu/src/monitor/cpu-exec.cc +++ b/nemu/src/monitor/cpu-exec.cc @@ -1,5 +1,10 @@ #include "nemu.h" #include "monitor/monitor.h" +#include "monitor/watchpoint.h" + +#include <rlib/stdio.hpp> +#include <rlib/3rdparty/prettyprint.hpp> +using namespace rlib::_3rdparty::std; /* The assembly code of instructions executed is only output to the screen * when the number of instructions executed is less than this value. @@ -40,7 +45,19 @@ void cpu_exec(uint64_t n) { #ifdef DEBUG /* TODO: check watchpoints here. */ - + decltype(watchpoints) updated_watchpoints; + for(auto &watchpoint : watchpoints) { + if(watchpoint.evalulate()) { + // Value changed. + updated_watchpoints.push_back(watchpoint); + } + } + if(! updated_watchpoints.empty()) { + nemu_state = NEMU_STOP; + rlib::println("Watchpoint(s) triggered:"); + rlib::println(updated_watchpoints); + return; + } #endif #ifdef HAS_IOE diff --git a/nemu/src/monitor/debug/expr.cc b/nemu/src/monitor/debug/expr.cc index 9d42827..68fc01c 100644 --- a/nemu/src/monitor/debug/expr.cc +++ b/nemu/src/monitor/debug/expr.cc @@ -99,20 +99,7 @@ static bool make_token(char *e) { return true; } -uint32_t expr(char *e, bool *success) { - if (!make_token(e)) { - *success = false; - return 0; - } - - try { - auto res = parse_one(std::string(e)); - *success = true; - return res; - } - catch(std::exception &e) { - rlib::println("Exception caught:", e.what()); - *success = false; - return 0; - } +uint32_t evaluate_expr(std::string e) { + auto res = parse_one(e); + return res; } diff --git a/nemu/src/monitor/debug/ui.cc b/nemu/src/monitor/debug/ui.cc index 75bc742..253554a 100644 --- a/nemu/src/monitor/debug/ui.cc +++ b/nemu/src/monitor/debug/ui.cc @@ -17,6 +17,9 @@ using rlib::string; #include <sstream> #include <iomanip> +#include <rlib/3rdparty/prettyprint.hpp> +using namespace rlib::_3rdparty::std; + void cpu_exec(uint64_t); /* We use the `readline' library to provide more flexibility to read from stdin. */ @@ -49,6 +52,8 @@ static int cmd_n(char *args) { static int cmd_info(char *args); static int cmd_x(char *args); +static int cmd_w(char *args); +static int cmd_d(char *args); static int cmd_q(char *args) { return -1; @@ -64,8 +69,10 @@ static struct { { "help", "Display informations about all supported commands", cmd_help }, { "c", "Continue the execution of the program", cmd_c }, { "n", "= GDB `n`", cmd_n }, - { "info", "= GDB `info`, only supporting `info r`", cmd_info }, - { "x", "x <bytes> <start address>", cmd_x }, + { "info", "= GDB `info`, supporting `info r` / `info w`", cmd_info }, + { "x", "x <bytes> <start address>, dump memory content.", cmd_x }, + { "w", "w <expr>, add watchpoint for $expr", cmd_w }, + { "d", "d <watchpoint id>, delete watchpoint by id", cmd_d }, { "q", "Exit NEMU", cmd_q }, /* TODO: Add more commands */ @@ -140,7 +147,8 @@ void ui_mainloop(int is_batch_mode) { } } -auto dumpReg(uint32_t val) { +// 3rdparty prettyprint will print rlib::string as array. Let's convert it to normal string. +std::string dumpReg(uint32_t val) { return string("{}{}[32b=0x{}{}, {}L16b=0x{}]").format(std::setfill('0'), std::setw(8), std::hex, val, std::setw(4), (uint16_t)val); } auto dumpMem(uint32_t begin_addr, uint64_t size) { @@ -157,13 +165,19 @@ auto dumpMem(uint32_t begin_addr, uint64_t size) { } static int cmd_info(char *_args) { - if(_args == NULL || "r"_rs != string(_args).strip()) - throw std::runtime_error("Error: only 'info r' is supported."); - println("Registers:"); - printfln("%eax={}, %ebx={}, %ecx={}, %edx={}", dumpReg(cpu.eax), dumpReg(cpu.ebx), dumpReg(cpu.ecx), dumpReg(cpu.edx)); - printfln("%esp={}, %ebp={}, %esi={}, %edi={}", dumpReg(cpu.esp), dumpReg(cpu.ebp), dumpReg(cpu.esi), dumpReg(cpu.edi)); - printfln("%eip={}", dumpReg(cpu.eip)); - return 0; + if(_args == NULL) + throw std::runtime_error("Usage: info <what>"); + if(string(_args).strip() == "r") { + println("Registers:"); + printfln("%eax={}, %ebx={}, %ecx={}, %edx={}", dumpReg(cpu.eax), dumpReg(cpu.ebx), dumpReg(cpu.ecx), dumpReg(cpu.edx)); + printfln("%esp={}, %ebp={}, %esi={}, %edi={}", dumpReg(cpu.esp), dumpReg(cpu.ebp), dumpReg(cpu.esi), dumpReg(cpu.edi)); + printfln("%eip={}", dumpReg(cpu.eip)); + } + else if(string(_args).strip() == "w") { + println("Watchpoints:"); + println(watchpoints); + } + return 0; } static int cmd_x(char *_args) { @@ -176,4 +190,26 @@ static int cmd_x(char *_args) { printfln("Dumping {}{} bytes from {}{}{}:{}", std::dec, args[0], std::hex, args[1], std::dec, dumpMem(std::stoull(args[1], 0, 16), args[0].as<uint64_t>())); return 0; -} \ No newline at end of file +} + +static int cmd_w(char *_args) { + if(_args == NULL) + throw std::invalid_argument("w <expr>"); + + watchpoints.emplace_front(std::string(_args), ++max_watchpoint_id); + auto iter = watchpoints.begin(); // not thread-safe. + rlib::println("Add watchpoint:", *iter); + return 0; +} + +static int cmd_d(char *_args) { + if(_args == NULL) + throw std::invalid_argument("d <wp id>"); + + auto to_remove = rlib::string(_args).as<int>(); + + watchpoints.remove_if([&](auto &wp){ + return wp.id == to_remove; + }); + return 0; +} diff --git a/nemu/src/monitor/debug/watchpoint.cc b/nemu/src/monitor/debug/watchpoint.cc index 2402f38..aae24d9 100644 --- a/nemu/src/monitor/debug/watchpoint.cc +++ b/nemu/src/monitor/debug/watchpoint.cc @@ -1,23 +1,34 @@ #include "monitor/watchpoint.h" #include "monitor/expr.h" -#define NR_WP 32 -static WP wp_pool[NR_WP]; -static WP *head, *free_; +/* +For DOCUMENT WRITER: +DO NOT USE THE TERM "POOL" IF YOU DON't WANT AN real OBJECT POOL!!! -void init_wp_pool() { - int i; - for (i = 0; i < NR_WP; i ++) { - wp_pool[i].NO = i; - wp_pool[i].next = &wp_pool[i + 1]; - } - wp_pool[NR_WP - 1].next = NULL; +#include <rlib/pool.hpp> - head = NULL; - free_ = wp_pool; +rlib::fixed_object_pool<WP> wp_pool(NR_WP); + +void init_wp_pool() {} + +// thread-safe +WP *new_wp() { + auto tmp = wp_pool.try_borrow_one(); + assert(tmp != nullptr); + return tmp; +} + +// thread-safe +void free_wp(WP *pobj) { + wp_pool.release_one(pobj); } +*/ + +std::list<WP> watchpoints; +int max_watchpoint_id = 0; +void init_wp_pool() {} + -/* TODO: Implement the functionality of watchpoint */ -- GitLab