nju pa1.1
Created Feb 21, 2025 - Last updated: Mar 6, 2025
Growing 🌿
CSAPP
lldb
debug
运行第一个客户程序
问题1 错误信息
进入nemu文件夹,运行make run
得到
+ CC src/nemu-main.c
+ CC src/engine/interpreter/init.c
+ CC src/engine/interpreter/hostcall.c
+ CC src/device/io/map.c
+ CC src/device/io/mmio.c
+ CC src/device/io/port-io.c
+ CC src/isa/riscv32/reg.c
+ CC src/isa/riscv32/inst.c
+ CC src/isa/riscv32/init.c
+ CC src/isa/riscv32/system/mmu.c
+ CC src/isa/riscv32/system/intr.c
+ CC src/isa/riscv32/logo.c
+ CC src/isa/riscv32/difftest/dut.c
+ CC src/cpu/cpu-exec.c
+ CC src/cpu/difftest/ref.c
+ CC src/cpu/difftest/dut.c
+ CC src/monitor/sdb/expr.c
+ CC src/monitor/sdb/watchpoint.c
+ CC src/monitor/sdb/sdb.c
+ CC src/monitor/monitor.c
+ CC src/utils/log.c
+ CC src/utils/disasm.c
+ CC src/utils/state.c
+ CC src/utils/timer.c
+ CC src/memory/paddr.c
+ CC src/memory/vaddr.c
+ LD /home/haoyue/ics2024/nemu/build/riscv32-nemu-interpreter
# -@git add /home/haoyue/ics2024/nemu/.. -A --ignore-errors
# -@while (test -e .git/index.lock); do sleep 0.1; done
# -@(echo "> "compile NEMU"" && echo 23241121 Haoyuehx && uname -a && uptime) | git commit -F - -q --author='tracer-ics2024 <[email protected]>' --no-verify --allow-empty
# -@sync
# -@git add /home/haoyue/ics2024/nemu/.. -A --ignore-errors
# -@while (test -e .git/index.lock); do sleep 0.1; done
# -@(echo "> "run NEMU"" && echo 23241121 Haoyuehx && uname -a && uptime) | git commit -F - -q --author='tracer-ics2024 <[email protected]>' --no-verify --allow-empty
# -@sync
/home/haoyue/ics2024/nemu/build/riscv32-nemu-interpreter --log=/home/haoyue/ics2024/nemu/build/nemu-log.txt
[src/utils/log.c:30 init_log] Log is written to /home/haoyue/ics2024/nemu/build/nemu-log.txt
[src/memory/paddr.c:50 init_mem] physical memory area [0x80000000, 0x87ffffff]
[src/monitor/monitor.c:51 load_img] No image is given. Use the default build-in image.
[src/monitor/monitor.c:28 welcome] Trace: ON
[src/monitor/monitor.c:31 welcome] If trace is enabled, a log file will be generated to record the trace. This may lead to a large log file. If it is not necessary, you can disable it in menuconfig
[src/monitor/monitor.c:32 welcome] Build time: 16:32:13, Feb 21 2025
Welcome to riscv32-NEMU!
For help, type "help"
[src/monitor/monitor.c:35 welcome] Exercise: Please remove me in the source code and compile NEMU again.
riscv32-nemu-interpreter: src/monitor/monitor.c:36: void welcome(): Assertion `0' failed.
make: *** [/home/haoyue/ics2024/nemu/scripts/native.mk:38: run] Aborted (core dumped)
注意到shell里面的这句话’Please remove me in the source code and compile NEMU again. riscv32-nemu-interpreter: src/monitor/monitor.c:36: void welcome(): Assertion `0’ failed.'
首先找到src/monitor/monitor.c
将
static void welcome() {
Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN), ANSI_FMT("OFF", ANSI_FG_RED)));
IFDEF(CONFIG_TRACE, Log("If trace is enabled, a log file will be generated "
"to record the trace. This may lead to a large log file. "
"If it is not necessary, you can disable it in menuconfig"));
Log("Build time: %s, %s", __TIME__, __DATE__);
printf("Welcome to %s-NEMU!\n", ANSI_FMT(str(__GUEST_ISA__), ANSI_FG_YELLOW ANSI_BG_RED));
printf("For help, type \"help\"\n");
# Log("Exercise: Please remove me in the source code and compile NEMU again.");
# assert(0);
}
后两行注释掉,nemu就可以正确运行。
问题2 在运行NEMU之后直接键入q退出, 你会发现终端输出了一些错误信息.
(nemu) q
make: *** [/home/haoyue/ics2024/nemu/scripts/native.mk:38: run] Error 1
使用lldb debug
haoyue@haoyue:~/ics2024/nemu$ lldb ./build/riscv32-nemu-interpreter
(lldb) target create "./build/riscv32-nemu-interpreter"
Current executable set to '/home/haoyue/ics2024/nemu/build/riscv32-nemu-interpreter' (x86_64).
首先找到键入q后调用的函数
static int cmd_q(char *args) {
return -1;
}
添加断点
(lldb) b cmd_q
Breakpoint 1: where = riscv32-nemu-interpreter`cmd_q at sdb.c:53:3, address = 0x00000000000039f0
运行,输入q,单步调试
(lldb) run
Process 119418 launched: '/home/haoyue/ics2024/nemu/build/riscv32-nemu-interpreter' (x86_64)
[src/utils/log.c:30 init_log] Log is written to stdout
[src/utils/log.c:30 init_log] Log is written to stdout
[src/memory/paddr.c:50 init_mem] physical memory area [0x80000000, 0x87ffffff]
[src/memory/paddr.c:50 init_mem] physical memory area [0x80000000, 0x87ffffff]
[src/monitor/monitor.c:51 load_img] No image is given. Use the default build-in image.
[src/monitor/monitor.c:51 load_img] No image is given. Use the default build-in image.
[src/monitor/monitor.c:28 welcome] Trace: ON
[src/monitor/monitor.c:28 welcome] Trace: ON
[src/monitor/monitor.c:31 welcome] If trace is enabled, a log file will be generated to record the trace. This may lead to a large log file. If it is not necessary, you can disable it in menuconfig
[src/monitor/monitor.c:31 welcome] If trace is enabled, a log file will be generated to record the trace. This may lead to a large log file. If it is not necessary, you can disable it in menuconfig
[src/monitor/monitor.c:32 welcome] Build time: 16:37:26, Feb 21 2025
[src/monitor/monitor.c:32 welcome] Build time: 16:37:26, Feb 21 2025
Welcome to riscv32-NEMU!
For help, type "help"
(nemu) q
Process 119418 stopped
* thread #1, name = 'riscv32-nemu-in', stop reason = breakpoint 1.1
frame #0: 0x00005555555579f0 riscv32-nemu-interpreter`cmd_q(args=<unavailable>) at sdb.c:53:3
50
51 static int cmd_q(char *args) {
52 // nemu_state.state = NEMU_QUIT;
-> 53 return -1;
54 }
55
56 static int cmd_help(char *args);
发现返回is_exit_status_bad()
(lldb) s
Process 119418 stopped
* thread #1, name = 'riscv32-nemu-in', stop reason = step in
frame #0: 0x000055555555635d riscv32-nemu-interpreter`main(argc=<unavailable>, argv=<unavailable>) at nemu-main.c:34:10
31 /* Start engine. */
32 engine_start();
33
-> 34 return is_exit_status_bad();
35 }
发现good值是1
(lldb) s
Process 119418 stopped
* thread #1, name = 'riscv32-nemu-in', stop reason = step in
frame #0: 0x000055555555821f riscv32-nemu-interpreter`is_exit_status_bad at state.c:23:3
20 int is_exit_status_bad() {
21 int good = (nemu_state.state == NEMU_END && nemu_state.halt_ret == 0) ||
22 (nemu_state.state == NEMU_QUIT);
-> 23 return !good;
24 }
(lldb) print good
(int) 1
应该修改cmd_q
static int cmd_q(char *args) {
nemu_state.state = NEMU_QUIT;
return -1;
}
补全代码
单步执行
命令 | 格式 | 使用举例 | 说明 |
---|---|---|---|
单步执行 | si [N] |
si 10 |
让程序单步执行N条指令后暂停执行,当N没有给出时, 缺省为1 |
cmd_table
添加命令
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", "Step into n instructions", cmd_is },
/* TODO: Add more commands */
};
实现方法
static int cmd_is(char* args)
{
int n_inst = 1;
char extra;
if (args == NULL) {
cpu_exec(n_inst);
return 0;
}
if (sscanf(args, "%d%c", &n_inst, &extra) != 1) {
printf("error: invalid thread index '%s'.\n", args);
return 0;
}
if (n_inst == 0) {
printf("error: Thread index 0 is out of range (valid values are 0 - 1).\n");
return 0;
}
cpu_exec(n_inst);
return 0;
}
打印寄存器
命令 | 格式 | 使用举例 | 说明 |
---|---|---|---|
打印程序状态 | info SUBCMD |
info r |
打印寄存器状态 |
cmd_table
添加命令
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", "Step into n instructions", cmd_is },
{ "info", "Print program status", cmd_info },
/* TODO: Add more commands */
};
实现方法,调用isa_reg_display()
static int cmd_info(char* args)
{
if (args == NULL) {
printf("info: missing argument.\n");
return 0;
}
else if (strcmp(args, "r") == 0) {
isa_reg_display();
return 0;
}
// else if (strcmp(args, "w") == 0) {
// return 0;
// }
else {
printf("Undefined info command: \"%s\".\n", args);
return 0;
}
return 0;
}
isa_reg_display()
实现方法
void isa_reg_display()
{
for (int i = 0; i < REG_NUM; i++) {
word_t val = cpu.gpr[i];
printf("%-4s 0x%-16x %d\n", regs[i], val, val);
}
}
word_t isa_reg_str2val(const char *s, bool *success) {
for (int i = 0; i < REG_NUM; i++) {
if (strcmp(s, regs[i]) == 0) {
*success = true;
return cpu.gpr[i];
}
}
*success = false;
return 0;
}
扫描内存
命令 | 格式 | 使用举例 | 说明 |
---|---|---|---|
扫描内存 | x N EXPR |
x 10 $esp |
求出表达式EXPR的值, 将结果作为起始内存 |
地址, 以十六进制形式输出连续的N个4字节 |
cmd_table
添加命令
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", "Step into n instructions", cmd_is },
{ "info", "Print program status", cmd_info },
{ "x", "Examine memory", cmd_x },
/* TODO: Add more commands */
};
实现方法,调用vaddr_read(vaddr_t addr, int len)
在sdb.h
文件添加一行
word_t vaddr_read(vaddr_t addr, int len);
cmd_x(char* args)
实现
static int cmd_x(char* args)
{
char* n_word = strtok(args, " ");
char* arg_expr = strtok(NULL, " ");
if (!n_word || !arg_expr) {
printf("Invalid arguments!\n");
return 0;
}
int len;
if (sscanf(n_word, "%d", &len) != 1) {
printf("error: first argument should be an integer, but got %s\n", n_word);
return 0;
}
word_t start_addr = 0;
if (sscanf(arg_expr, "%x", &start_addr) != 1) {
printf("error: require a hex expression, but got %s\n", arg_expr);
return 0;
}
if (start_addr < 0x80000000 || start_addr > 0x87ffffff) {
printf("Address 0x%x is out of bounds!\n", start_addr);
return 0;
}
for (int i = 0; i < len; i++) {
word_t current_addr = start_addr + i * 4;
word_t val = vaddr_read(current_addr, 4);
if (i == 0) {
printf("0x%x:", current_addr);
} else if (i % 4 == 0 && i != 0) {
printf("\n0x%x:", current_addr);
}
printf("\t0x%08x", val);
}
printf("\n");
return 0;
}