pa1.3: watchpoint support

This commit is contained in:
xinyangli 2024-02-08 20:07:03 +08:00
parent 2675a647b0
commit 504d270947
14 changed files with 363 additions and 36 deletions

View file

@ -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());
}

View file

@ -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);
}

View file

@ -1,2 +0,0 @@
addrexp_lex.h
addrexp.h

View file

@ -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; }
%%

View file

@ -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
%%

View file

@ -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;

View file

@ -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

View file

@ -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;
}