diff --git a/articles/20230428-gdb-and-qemu-gdbstub-debug.md b/articles/20230428-gdb-and-qemu-gdbstub-debug.md index 470a5e343a53a55caac6195d3f13d1e2401dbb7d..696d4ddd0ad4be7280746b436b0263e0087bb5b7 100644 --- a/articles/20230428-gdb-and-qemu-gdbstub-debug.md +++ b/articles/20230428-gdb-and-qemu-gdbstub-debug.md @@ -13,7 +13,7 @@ ## QEMU gdbstub -调试与 QEMU 自带的 gdbstub 相关的问题时,需要熟练掌握 gdb 的远程串行调试协议。协议内容详见 [GDB Remote Serial Protocol][001] +调试与 QEMU 自带的 gdbstub 相关的问题时,需要熟练掌握 gdb 的远程串行调试协议。协议内容详见 [GDB Remote Serial Protocol][001]。 QEMU 里与 gdbstub 相关的代码分布在如下目录: @@ -29,7 +29,7 @@ gdbstub/trace-events 包含了 QEMU 自带的 trace 功能记录下来的 gdbstu $ qemu-system-riscv64 -nographic -M sifive_u,msel=11 -smp 5 -m 8G -bios u-boot-spl.bin -drive file=sdcard.img,if=sd -s -S -D gdbstub.txt -d trace:gdbstub* ``` -按照给定的命令行参数启动模拟的 sifive_u 机器,将所有与 gdbstub 相关的 trace 事件日志都写入当前目录下的 gdbstub.txt 里,查看 gdbstub.txt 可以得到 QEMU 记录的其与 gdb 客户端非常详细的交互信息。下面是日志里的一段信息,可以看到 QEMU 收到了客户端的读取 target.xml 的请求并返回了文件内容。 +按照给定的命令行参数启动模拟的 sifive_u 机器,将所有与 gdbstub 相关的 trace 事件日志(-d trace:gdbstub*)都写入当前目录下的 gdbstub.txt(-D gdbstub.txt) 里,查看 gdbstub.txt 可以得到 QEMU 记录的其与 gdb 客户端非常详细的交互信息。下面是日志里的一段信息,可以看到 QEMU 收到了客户端的读取 target.xml 的请求并返回了文件内容。 ``` gdbstub_io_command Received: qXfer:features:read:target.xml:0,ffb @@ -90,7 +90,7 @@ warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. ``` -注意:`gdb-multiarch` 开始调试前,需要正确设置被调试代码的体系架构,否则在没有指定被调试文件的情况下,gdb 并不会根据被调试文件来 “猜测” 被调试代码的指令集,这样会导致出现一个错误信息 “Truncated register 37 in remote 'g' packet” 从而连不上 QEMU 的 gdbstub。这里我们设置了 `gdb-multiarch` 被调试的目标体系架构为 riscv:rv64。 +注意:在 `gdb-multiarch` 连到 QEMU 侧的 gdbstub 之前,如果命令行或者 gdb shell 下没有指定被调试文件,连接到 QEMU 的 gdbstub 的时候可能会出现一个错误信息 “Truncated register 37 in remote 'g' packet”,这是因为主机端的 `gdb-multiarch` 默认配置的被调试代码的体系架构为 x86_64,而当我们没有指定被调试文件的情况下,gdb 无法根据被调试文件的类型(如 ELF 文件)来正确设置 gdb 被调试代码的体系架构,当 QEMU 这侧模拟的 CPU 体系架构不是 x86_64 就会抛出上述错误信息。在我们的例子中,使用 `set architecture` 的命令来设置 `gdb-multiarch` 被调试的目标体系架构为 riscv:rv64。 这里出现了两条 warning。第二条 warning 是正常的,因为我在启动 gdb 的时候没有给它被调试的文件,所以这条可以忽略。 @@ -123,7 +123,7 @@ $ make -j$(nproc) $ ./gdb --data-directory=./data-directory ``` -果然,新版本的 gdb 不会出现这个问题。那么 QEMU v7.2.0 的这个 [commit][002] 改动其实是要配合新版本的 gdb 来使用的,严格意义上来讲这里是存在一个兼容性的问题,具体是谁的兼容性问题这里我们暂且不表。先看看 gdb 的行为发生了什么改变,这里我们需要一些调试 gdb 程序本身的技巧。 +果然,新版本的 gdb 不会出现这个问题。我们可以分析一下 gdb 的行为发生了什么改变,这里我们需要一些调试 gdb 程序本身的技巧。 ### 深入分析 @@ -306,7 +306,9 @@ gdbarch_find_by_info: New architecture 0x55c97f9defc0 (riscv:rv64) selected } ``` -至此,这个问题的根因找到了。 +### 问题根因和解决办法 + +回顾整个问题,笔者一如既往用 Ubuntu 20.04 自带的 9.2 版本的 gdb-multiarch 来调试 QEMU 7.2.0,发现了 “Architecture rejected target-supplied description” 的告警信息,换用新版本的 gdb 这个问题不再复现。虽然 revert QEMU v7.2.0 的这个 [commit][002] 可以使问题消失,但仔细分析 QEMU 这个 commit 并没有问题。真正的问题在于 gdb 侧做了修改,QEMU v7.2.0 也跟着做了相应的修改,所以这意味着 QEMU v7.2.0 其实是要配合新版本的 gdb 来使用的,严格意义上来讲 gdb 这里存在着一个向后兼容性的问题,但从 [commit][002] 的描述来看,这是对 RISC-V 体系架构早期支持过程中在 gdb/QEMU 中引入的一些 hack 的清理,选择正本清源长期来看对 RISC-V 体系架构支持肯定是具有积极意义的。 ## 总结 @@ -314,6 +316,11 @@ gdbarch_find_by_info: New architecture 0x55c97f9defc0 (riscv:rv64) selected ## 参考资料 +- [GDB Remote Serial Protocol][001] +- [QEMU commit: target/riscv: remove fflags, frm, and fcsr from riscv-*-fpu.xml][002] +- [QEMU commit: target/riscv: remove fixed numbering from GDB xml feature files][003] +- [GDB Debugging Output][004] + [001]: https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html [002]: https://gitlab.com/qemu-project/qemu/-/commit/94452ac4cf263e8996613db8d981e4ea85bd019a [003]: https://gitlab.com/qemu-project/qemu/-/commit/4c0f0b6619126637e802f07c9fe8e9fffbc1c4bb