Skip to content
Snippets Groups Projects
Verified Commit 82207f96 authored by Recolic Keghart's avatar Recolic Keghart
Browse files

> 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
parent 85626f9f
No related branches found
No related tags found
No related merge requests found
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <string>
typedef uint32_t rtlreg_t; typedef uint32_t rtlreg_t;
...@@ -27,4 +28,13 @@ typedef uint16_t ioaddr_t; ...@@ -27,4 +28,13 @@ typedef uint16_t ioaddr_t;
#include "debug.h" #include "debug.h"
#include "macro.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 #endif
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
#include "common.h" #include "common.h"
uint32_t expr(char *, bool *); uint32_t evaluate_expr(std::string e);
#endif #endif
...@@ -3,13 +3,34 @@ ...@@ -3,13 +3,34 @@
#include "common.h" #include "common.h"
typedef struct watchpoint { #include <string>
int NO; #include <list>
struct watchpoint *next; #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 #endif
#include "nemu.h" #include "nemu.h"
#include "monitor/monitor.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 /* The assembly code of instructions executed is only output to the screen
* when the number of instructions executed is less than this value. * when the number of instructions executed is less than this value.
...@@ -40,7 +45,19 @@ void cpu_exec(uint64_t n) { ...@@ -40,7 +45,19 @@ void cpu_exec(uint64_t n) {
#ifdef DEBUG #ifdef DEBUG
/* TODO: check watchpoints here. */ /* 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 #endif
#ifdef HAS_IOE #ifdef HAS_IOE
......
...@@ -99,20 +99,7 @@ static bool make_token(char *e) { ...@@ -99,20 +99,7 @@ static bool make_token(char *e) {
return true; return true;
} }
uint32_t expr(char *e, bool *success) { uint32_t evaluate_expr(std::string e) {
if (!make_token(e)) { auto res = parse_one(e);
*success = false; return res;
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;
}
} }
...@@ -17,6 +17,9 @@ using rlib::string; ...@@ -17,6 +17,9 @@ using rlib::string;
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <rlib/3rdparty/prettyprint.hpp>
using namespace rlib::_3rdparty::std;
void cpu_exec(uint64_t); void cpu_exec(uint64_t);
/* We use the `readline' library to provide more flexibility to read from stdin. */ /* We use the `readline' library to provide more flexibility to read from stdin. */
...@@ -49,6 +52,8 @@ static int cmd_n(char *args) { ...@@ -49,6 +52,8 @@ static int cmd_n(char *args) {
static int cmd_info(char *args); static int cmd_info(char *args);
static int cmd_x(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) { static int cmd_q(char *args) {
return -1; return -1;
...@@ -64,8 +69,10 @@ static struct { ...@@ -64,8 +69,10 @@ static struct {
{ "help", "Display informations about all supported commands", cmd_help }, { "help", "Display informations about all supported commands", cmd_help },
{ "c", "Continue the execution of the program", cmd_c }, { "c", "Continue the execution of the program", cmd_c },
{ "n", "= GDB `n`", cmd_n }, { "n", "= GDB `n`", cmd_n },
{ "info", "= GDB `info`, only supporting `info r`", cmd_info }, { "info", "= GDB `info`, supporting `info r` / `info w`", cmd_info },
{ "x", "x <bytes> <start address>", cmd_x }, { "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 }, { "q", "Exit NEMU", cmd_q },
/* TODO: Add more commands */ /* TODO: Add more commands */
...@@ -140,7 +147,8 @@ void ui_mainloop(int is_batch_mode) { ...@@ -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); 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) { auto dumpMem(uint32_t begin_addr, uint64_t size) {
...@@ -157,13 +165,19 @@ 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) { static int cmd_info(char *_args) {
if(_args == NULL || "r"_rs != string(_args).strip()) if(_args == NULL)
throw std::runtime_error("Error: only 'info r' is supported."); throw std::runtime_error("Usage: info <what>");
println("Registers:"); if(string(_args).strip() == "r") {
printfln("%eax={}, %ebx={}, %ecx={}, %edx={}", dumpReg(cpu.eax), dumpReg(cpu.ebx), dumpReg(cpu.ecx), dumpReg(cpu.edx)); println("Registers:");
printfln("%esp={}, %ebp={}, %esi={}, %edi={}", dumpReg(cpu.esp), dumpReg(cpu.ebp), dumpReg(cpu.esi), dumpReg(cpu.edi)); printfln("%eax={}, %ebx={}, %ecx={}, %edx={}", dumpReg(cpu.eax), dumpReg(cpu.ebx), dumpReg(cpu.ecx), dumpReg(cpu.edx));
printfln("%eip={}", dumpReg(cpu.eip)); printfln("%esp={}, %ebp={}, %esi={}, %edi={}", dumpReg(cpu.esp), dumpReg(cpu.ebp), dumpReg(cpu.esi), dumpReg(cpu.edi));
return 0; printfln("%eip={}", dumpReg(cpu.eip));
}
else if(string(_args).strip() == "w") {
println("Watchpoints:");
println(watchpoints);
}
return 0;
} }
static int cmd_x(char *_args) { static int cmd_x(char *_args) {
...@@ -176,4 +190,26 @@ 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>())); 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; 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;
}
#include "monitor/watchpoint.h" #include "monitor/watchpoint.h"
#include "monitor/expr.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() { #include <rlib/pool.hpp>
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;
head = NULL; rlib::fixed_object_pool<WP> wp_pool(NR_WP);
free_ = wp_pool;
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 */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment