pa1.3: watchpoint support
This commit is contained in:
parent
2675a647b0
commit
504d270947
14 changed files with 363 additions and 36 deletions
|
@ -31,6 +31,7 @@ static uint64_t g_timer = 0; // unit: us
|
|||
static bool g_print_step = false;
|
||||
|
||||
void device_update();
|
||||
bool wp_eval_all();
|
||||
|
||||
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
|
||||
#ifdef CONFIG_ITRACE_COND
|
||||
|
@ -77,6 +78,10 @@ static void execute(uint64_t n) {
|
|||
exec_once(&s, cpu.pc);
|
||||
g_nr_guest_inst ++;
|
||||
trace_and_difftest(&s, cpu.pc);
|
||||
if (wp_eval_all()) {
|
||||
puts(s.logbuf);
|
||||
break;
|
||||
}
|
||||
if (nemu_state.state != NEMU_RUNNING) break;
|
||||
IFDEF(CONFIG_DEVICE, device_update());
|
||||
}
|
||||
|
|
|
@ -36,5 +36,16 @@ void isa_reg_display() {
|
|||
}
|
||||
|
||||
word_t isa_reg_str2val(const char *s, bool *success) {
|
||||
return 0;
|
||||
assert(s);
|
||||
int i;
|
||||
for (i = 0; i < 32 && strcmp(s, regs[i]) != 0; i++)
|
||||
;
|
||||
|
||||
if (i == 32) {
|
||||
*success = false;
|
||||
return 0;
|
||||
}
|
||||
*success = true;
|
||||
|
||||
return gpr(i);
|
||||
}
|
||||
|
|
2
nemu/src/monitor/sdb/.gitignore
vendored
2
nemu/src/monitor/sdb/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
addrexp_lex.h
|
||||
addrexp.h
|
|
@ -1,5 +1,8 @@
|
|||
%{
|
||||
#include <isa.h>
|
||||
#include <addrexp.h>
|
||||
static bool success = false;
|
||||
void yyerror(word_t *result, const char *err);
|
||||
%}
|
||||
%option noyywrap
|
||||
|
||||
|
@ -7,7 +10,15 @@
|
|||
|
||||
0[xX][0-9a-fA-F]+ { yylval = strtoul(yytext, NULL, 16); return HEX_NUMBER; }
|
||||
[0-9]+ { yylval = strtoul(yytext, NULL, 10); return NUMBER; }
|
||||
[+\-*/()] { return *yytext; }
|
||||
$[asgprt$][0-9pa][0-9]? {
|
||||
yylval = isa_reg_str2val(yytext + 1, &success);
|
||||
if(!success) {
|
||||
yyerror(NULL, "Failed to convert reg to value");
|
||||
return YYerror;
|
||||
}
|
||||
return REGISTER;
|
||||
}
|
||||
[+\-*/<=()] { return *yytext; }
|
||||
[ \t] { }
|
||||
. { printf("Unexpected character: %s\n", yytext); }
|
||||
. { printf("Unexpected character: %s\n", yytext); return YYerror; }
|
||||
%%
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
%code requires {
|
||||
#include <common.h>
|
||||
#include <memory/vaddr.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
extern int yylex(void);
|
||||
}
|
||||
%{
|
||||
#include <common.h>
|
||||
#include <isa.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
void yyerror(word_t *result, const char *err) {
|
||||
fprintf(stderr, "Error: %s\n", err);
|
||||
Error("%s", err);
|
||||
}
|
||||
%}
|
||||
|
||||
%token NUMBER HEX_NUMBER
|
||||
%token REGISTER
|
||||
%locations
|
||||
%start input
|
||||
%define api.value.type { word_t }
|
||||
%parse-param { uint32_t *result }
|
||||
|
@ -27,6 +31,12 @@ input
|
|||
|
||||
expression
|
||||
: number { $$ = $1; }
|
||||
| expression '>' '=' expression { $$ = ($1 >= $4); }
|
||||
| expression '<' '=' expression { $$ = ($1 <= $4); }
|
||||
| expression '=' '=' expression { $$ = ($1 == $4); }
|
||||
| expression '!' '=' expression { $$ = ($1 == $4); }
|
||||
| expression '>' expression { $$ = ($1 > $3); }
|
||||
| expression '<' expression { $$ = ($1 < $3); }
|
||||
| expression '+' expression { $$ = $1 + $3; }
|
||||
| expression '-' expression { $$ = $1 - $3; }
|
||||
| expression '*' expression { $$ = $1 * $3; }
|
||||
|
@ -38,10 +48,12 @@ expression
|
|||
$$ = $1 / $3;
|
||||
}
|
||||
| '-' number { $$ = -$2; }
|
||||
| '*' expression { $$ = vaddr_read($2, WORD_BYTES); }
|
||||
| '(' expression ')' { $$ = $2; }
|
||||
|
||||
number
|
||||
: NUMBER
|
||||
: REGISTER
|
||||
| NUMBER
|
||||
| HEX_NUMBER
|
||||
|
||||
%%
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include "sdb.h"
|
||||
#include "common.h"
|
||||
#include "sys/types.h"
|
||||
#include <addrexp.h>
|
||||
#include <addrexp_lex.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <errno.h>
|
||||
#include <isa.h>
|
||||
|
@ -23,15 +25,15 @@
|
|||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#include <stdint.h>
|
||||
#include <addrexp.h>
|
||||
#include <addrexp_lex.h>
|
||||
|
||||
static int is_batch_mode = false;
|
||||
|
||||
// command handlers
|
||||
static int cmd_help(char *args);
|
||||
static int cmd_c(char *args);
|
||||
static int cmd_p(char *args);
|
||||
static int cmd_q(char *args);
|
||||
static int cmd_w(char *args);
|
||||
static int cmd_x(char *args);
|
||||
static int cmd_si(char *args);
|
||||
static int cmd_info(char *args);
|
||||
|
@ -53,8 +55,10 @@ static struct CommandTable {
|
|||
{"help", "Display information about all supported commands", cmd_help,
|
||||
NULL, 0},
|
||||
{"c", "Continue the execution of the program", cmd_c, NULL, 0},
|
||||
{"p", "Print expression result", cmd_p, NULL, 0},
|
||||
{"q", "Exit NEMU", cmd_q, NULL, 0},
|
||||
{"x", "Examine content of physical memory address", cmd_x, NULL, 0},
|
||||
{"w", "Break when expression is changed", cmd_w, NULL, 0},
|
||||
{"si", "Execute next [n] program line", cmd_si, NULL, 0},
|
||||
{"info", "Print information of registers or watchpoints", cmd_info,
|
||||
cmd_info_table, ARRLEN(cmd_info_table)},
|
||||
|
@ -125,17 +129,17 @@ static word_t parse_uint(const char *arg, bool *success) {
|
|||
}
|
||||
}
|
||||
|
||||
static vaddr_t parse_expr(const char *arg, bool *success) {
|
||||
word_t parse_expr(const char *arg, bool *success) {
|
||||
if (arg == NULL) {
|
||||
puts("Invalid expr argument.");
|
||||
*success = false;
|
||||
return 0;
|
||||
} else {
|
||||
vaddr_t addr;
|
||||
word_t res;
|
||||
yy_scan_string(arg);
|
||||
*success = !yyparse(&addr);
|
||||
*success = !yyparse(&res);
|
||||
yylex_destroy();
|
||||
return addr;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,6 +148,22 @@ static int cmd_c(char *args) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_p(char *args) {
|
||||
char *arg = strtok(NULL, "");
|
||||
bool res = false;
|
||||
|
||||
word_t result = parse_expr(arg, &res);
|
||||
if (!res)
|
||||
goto wrong_usage;
|
||||
printf("%s: %u\n", arg, result);
|
||||
return 0;
|
||||
|
||||
wrong_usage:
|
||||
printf("Invalid argument for command p: %s\n", arg);
|
||||
printf("Usage: p [EXPR: <expr>]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_q(char *args) {
|
||||
nemu_state.state = NEMU_QUIT;
|
||||
return -1;
|
||||
|
@ -181,6 +201,12 @@ static int cmd_info_w(char *args) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_w(char *args) {
|
||||
char *expr = strtok(NULL, "");
|
||||
wp_add(expr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_x(char *args) {
|
||||
char *arg = strtok(NULL, " ");
|
||||
bool res = false;
|
||||
|
|
|
@ -18,4 +18,8 @@
|
|||
|
||||
#include <common.h>
|
||||
|
||||
word_t parse_expr(const char *arg, bool *success);
|
||||
int wp_add(char * expr);
|
||||
int wp_remove_by_number(int number);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,36 +1,38 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan
|
||||
*PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||
*KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
*NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include "sdb.h"
|
||||
#include <common.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define NR_WP 32
|
||||
|
||||
typedef struct watchpoint {
|
||||
int NO;
|
||||
struct watchpoint *next;
|
||||
|
||||
/* TODO: Add more members if necessary */
|
||||
|
||||
word_t val;
|
||||
char *expr;
|
||||
} WP;
|
||||
|
||||
static WP wp_pool[NR_WP] = {};
|
||||
static WP *head = NULL, *free_ = NULL;
|
||||
static WP *head = NULL, *tail = NULL, *free_ = NULL;
|
||||
static int wp_count = 0;
|
||||
|
||||
void init_wp_pool() {
|
||||
int i;
|
||||
for (i = 0; i < NR_WP; i ++) {
|
||||
for (i = 0; i < NR_WP; i++) {
|
||||
wp_pool[i].NO = i;
|
||||
wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]);
|
||||
}
|
||||
|
@ -39,5 +41,110 @@ void init_wp_pool() {
|
|||
free_ = wp_pool;
|
||||
}
|
||||
|
||||
/* TODO: Implement the functionality of watchpoint */
|
||||
static WP *wp_new() {
|
||||
if (free_ == NULL) {
|
||||
Error("wp_pool: Watchpoint pool not initialized or is full.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WP *ret = free_;
|
||||
free_ = free_->next;
|
||||
|
||||
ret->NO = 0;
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wp_delete(WP *wp) {
|
||||
Assert(wp, "Failed to delete watchpoint from pool.");
|
||||
wp->next = free_;
|
||||
free_ = wp;
|
||||
}
|
||||
|
||||
int wp_add(char * expr) {
|
||||
WP *wp = wp_new();
|
||||
if (wp == NULL) {
|
||||
Error("watchpoint: Failed to add watchpoint, pool is full.");
|
||||
goto failed_create;
|
||||
}
|
||||
|
||||
wp->NO = wp_count++;
|
||||
if (tail == NULL) {
|
||||
head = wp;
|
||||
tail = wp;
|
||||
} else {
|
||||
tail->next = wp;
|
||||
tail = wp;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
wp->val = parse_expr(expr, &success);
|
||||
if (!success) {
|
||||
Error("Failed to parse given expression `%s`", expr);
|
||||
goto failed_create;
|
||||
}
|
||||
|
||||
int len = strlen(expr);
|
||||
wp->expr = malloc((len + 1) * sizeof(char));
|
||||
if (wp->expr == NULL) {
|
||||
Error("Failed to allocate memory for expression");
|
||||
goto failed_create;
|
||||
}
|
||||
strncpy(wp->expr, expr, len + 1);
|
||||
wp->expr[len] = '\0';
|
||||
return 0;
|
||||
|
||||
failed_create:
|
||||
wp_delete(wp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int wp_remove_by_number(int number) {
|
||||
WP *target_prev;
|
||||
// Find previous node of target number
|
||||
for (target_prev = head; target_prev != NULL && target_prev->next->NO != number; target_prev = target_prev->next) ;
|
||||
if (target_prev == NULL) {
|
||||
Error("Watchpoint not found, you can check current watchpoints with `info w`");
|
||||
return 1;
|
||||
}
|
||||
WP *target = target_prev->next;
|
||||
target_prev->next = target->next;
|
||||
if (target == head) {
|
||||
head = target->next;
|
||||
} else if (target == tail) {
|
||||
tail = target_prev;
|
||||
}
|
||||
wp_delete(target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool wp_check_change(WP* wp) {
|
||||
bool success = false;
|
||||
word_t result;
|
||||
|
||||
result = parse_expr(wp->expr, &success);
|
||||
if (!success) {
|
||||
panic("Failed to evaluate expression `%s`", wp->expr);
|
||||
}
|
||||
if (result != wp->val) {
|
||||
wp->val = result;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if watchpoint value changed after execution
|
||||
*/
|
||||
bool wp_eval_all() {
|
||||
WP *wp;
|
||||
bool value_change = false;
|
||||
for (wp = head; wp != NULL; wp = wp->next) {
|
||||
int prev_val = wp->val;
|
||||
if (wp_check_change(wp)) {
|
||||
printf("Watchpoint %d: %s\n %u -> %u\n", wp->NO, wp->expr, prev_val, wp->val);
|
||||
value_change = true;
|
||||
}
|
||||
}
|
||||
return value_change;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue