在将 Rust 代码编译为 Risc-V 裸机的二进制文件后,一般调试的时候是使用 QEMU 来模拟 RISC-V 启动,为了方便调试,在 QEMU 的启动命令中会加上 -s-S。作用是:

  • -s 启用 GDB 服务器,默认在 1234 端口
  • -S 在启动时暂停 CPU

然后就可以使用 gdb 来调试。

在上面启动 QEMU 后它是在等待 gdb 调试的,我们需要启动 gdb:

gdb \
	-ex 'file target/riscv64gc-unknown-none-elf/debug/os' \
  -ex 'set arch riscv:rv64' \
  -ex 'target remote localhost:1234'

其中 -ex 'file target/riscv64gc-unknown-none-elf/debug/os' 指定了我们要调试的文件;-ex 'target remote localhost:1234' 链接了等待 gdb 调试的 QEMU。

在成功进入 gdb 后,我们一般会先打一个断点,在 gdb 中键入 break <symbol> 在某个符号打一个断点,比如我指定了我的入口函数:rust_main(根据你的项目而定),就是:break rust_main。然后在 gdb 中键入 c,就会直接执行到下一个断点。

如果我们想查看对应的 Rust 源码,在 gdb 中键入 layout src,gdb 会在上方的一块区域显示当前执行到的源码:

file

其中高亮显示的一行就是下一步要执行的代码。要继续执行下一行代码的话,在 gdb 中键入 next

关于 gdb 更多命令能够在网上找到。

layout src 不能显示源码?

如果说在 gdb 中使用 layout src 不能显示你的 Rust 源码,可能有以下几个原因:

  1. 在键入了 layout src 后没有执行下一步代码。在 layout src 后 gdb 并会出现显示源码的区域,但不会马上出现源码,你需要键入 c 跳到下一个断点或者 next 执行下一行代码,或者类似的行为,才能显示
  2. Rust 编译选项使用了 --release 编译选项。--release 编译选项会去除掉一些内容,比如调试信息等,这会使 gdb 找不到调试信息,而无法显示源码。如果是调试,建议使用默认编译选项
  3. 链接器脚本去除了调试信息。因为我们是将 Rust 编译为 RISC-V 裸机的,其中可能会自己编写链接器脚本,注意查看你有没有自己丢弃了调试信息,比如在链接器脚本中的 /DISCARD/ 中出现了 *(.debug) 等,或者编译器参数中去掉了 debug 信息。