PA
目录PA1
RTFSC
优美地退出
make run
启动nemu后直接输入q
退出,得到如下最后一行的错误
Welcome to riscv32-NEMU!
For help, type "help"
(nemu) log
Unknown command 'log'
(nemu) q
make: *** [/home/ubuntu/ics2022/nemu/scripts/native.mk:38: run] Error 1
是由于is_exit_status_bad
函数返回了-1,main函数直接返回了此函数返回的结果,make检测到该可执行文件返回了-1,因此报错。通过分析该函数得到解决方案:在输入q
中途退出nemu后,将nemu_state.state
设成NEMU_QUIT
即可
// nemu/src/monitor/sdb/sdb.c
void sdb_mainloop() {
...
int i;
for (i = 0; i < NR_CMD; i ++) {
if (strcmp(cmd, cmd_table[i].name) == 0) {
if (cmd_table[i].handler(args) < 0) {
if (strcmp(cmd, "q") == 0) {
nemu_state.state = NEMU_QUIT; // set "QUIT" state when q
}
return;
}
break;
}
}
if (i == NR_CMD) { printf("Unknown command '%s'\n", cmd); }
}
}
此时再通过make run
运行后中途键入q
命令退出模拟器将不会再报该错误
简易调试器
单步执行 si [N]
第一步,在cmd_table注册一条命令si
// nemu/src/monitor/sdb/sdb.c
static struct {
const char *name;
const char *description;
int (*handler) (char *);
} cmd_table [] = {
{ "help", "Display information about all supported commands", cmd_help },
{ "c", "Continue the execution of the program", cmd_c },
{ "q", "Exit NEMU", cmd_q },
{ "si", "Continue the execution in N steps, default 1", cmd_si },
/* TODO: Add more commands */
};
第二步,编写cmd_si
,即si
具体要执行的东西
static int cmd_si(char *args) {
/* extract the first argument */
char *arg = strtok(NULL, " ");
int n;
if (arg == NULL) {
n = 1;
} else {
n = strtol(arg, NULL, 10);
}
cpu_exec(n);
return 0;
}
打印寄存器 info r
第一步,注册命令
{ "info", "Display the info of registers & watchpoints", cmd_info },
第二步,编写cmd_info
,其中调用的isa_reg_display
函数就是PA文档里介绍的,简易调试器为了屏蔽ISA的差异. 框架代码已经为大家准备了的API之一
static int cmd_info(char *args) {
/* extract the first argument */
char *arg = strtok(NULL, " ");
if (arg == NULL) {
printf("Usage: info r (registers) or info w (watchpoints)\n");
} else {
if (strcmp(arg, "r") == 0) {
isa_reg_display();
} else if (strcmp(arg, "w") == 0) {
// todo
} else {
printf("Usage: info r (registers) or info w (watchpoints)\n");
}
}
return 0;
}
第三步,实现提前设计好的isa_reg_display
// nemu/src/isa/$ISA/reg.c
void isa_reg_display() {
int reg_num = ARRLEN(regs);
int i;
for (i = 0; i < reg_num; i++) {
printf("%-8s%-#20x%-20d\n", regs[i], cpu.gpr[i], cpu.gpr[i]);
}
}
扫描内存 x N EXPR
第一步,注册命令
{ "x", "Usage: x N EXPR. Scan the memory from EXPR by N bytes", cmd_x },
第二步,编写cmd_x
,注意这里有两个参数N和EXPR,因此需要分别检查参数是否存在,并转换类型。然后就是利用vaddr_read
每次读取4个字节并打印。打印格式参照了一下gdb的x命令,每行打印4个4字节
static int cmd_x(char *args) {
char *arg1 = strtok(NULL, " ");
if (arg1 == NULL) {
printf("Usage: x N EXPR\n");
return 0;
}
char *arg2 = strtok(NULL, " ");
if (arg1 == NULL) {
printf("Usage: x N EXPR\n");
return 0;
}
int n = strtol(arg1, NULL, 10);
vaddr_t expr = strtol(arg2, NULL, 16);
int i, j;
for (i = 0; i < n;) {
printf(ANSI_FMT("%#010x: ", ANSI_FG_CYAN), expr);
for (j = 0; i < n && j < 4; i++, j++) {
word_t w = vaddr_read(expr, 4);
printf("%#010x ", w);
expr += 4;
}
puts("");
}
return 0;
}
表达式求值 p EXPR
第一步,注册命令
{"p", "Usage: p EXPR. Calculate the expression, e.g. p $eax + 1", cmd_p}
第二步,编写cmd_p
TODO()
标签:info,int,EXPR,cmd,char,pa,nju,NULL
From: https://www.cnblogs.com/nosae/p/17045249.html