1. Makefile
于arceos的Makefile可以发现它提供了一键debug
1 2 3 4 5 6 7 8 debug: build $(call run_qemu_debug) & sleep 1 $(GDB) $(OUT_ELF) \ -ex 'target remote localhost:1234' \ -ex 'b rust_entry' \ -ex 'continue' \ -ex 'disp /16i $$pc'
于是只需run改debug,就可以直接在终端使用gdb调试
1 make ARCH=riscv64 A=apps/hv HV=y LOG=info debug
然而默认是release编译,不带debug信息。如Makefile头部所写:
1 2 3 4 5 6 7 8 9 ARCH ?= x86_64 SMP ?= 1 MODE ?= release LOG ?= warn
这里的MODE
会影响到/script/make/cargo.mk
中的cargo build参数,并由此决定是否使用cargo rustc --release
,--release
使得编译结果不带有调试信息。此时指定MODE
为debug即可带有调试信息进行编译。
1 make ARCH=riscv64 A=apps/hv HV=y LOG=info MODE=debug debug
Makefile中debug
目标描述的行为其实是先运行qemu,这个qemu使用了-s -S
参数来启动一个gdb server,此时qemu就会等待gdb client连接,等到连接后再继续执行;然后再启动gdb,读取elf文件获得debug信息,使用target remote localhost:1234
来连接gdb server。连接成功后,qemu继续执行,gdb也可以通过此连接沟通qemu来调试qemu上的程序。
2. VSCode
然而如果要一直在终端gdb,随着debug次数增加,想必人可能会癫掉。
如jyy所说,在前期花费一点时间折腾基础设施/工具,能够节约大量时间。
我们完全可以利用更现代一点的ide/editor,来帮助调试。
以vscode为例,我们主要希望借用vscode的gui来调试。如很多其他编辑器一样,vscode也只是“调用”gdb而已,只是它可以将信息更友好地显示出来;我们要做的就是告诉vscode,调用哪个gdb,调试文件在哪,gdb server的地址在哪……
这些内容在.vscode/launch.json
配置,按下F5进行调试的行为就在此配置,若F5时没有发现launch.json
则会提示生成。
下面是我的配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 { "version" : "0.2.0" , "configurations" : [ { "name" : "qemu connect" , "type" : "cppdbg" , "request" : "launch" , "program" : "${workspaceFolder}/apps/hv/hv_qemu-virt-riscv.elf" , "args" : [ ] , "stopAtEntry" : false , "cwd" : "${fileDirname}" , "environment" : [ ] , "externalConsole" : false , "MIMode" : "gdb" , "setupCommands" : [ { "description" : "为 gdb 启用整齐打印" , "text" : "-enable-pretty-printing" , "ignoreFailures" : true } , { "description" : "将反汇编风格设置为 Intel" , "text" : "-gdb-set disassembly-flavor intel" , "ignoreFailures" : true } ] , "miDebuggerPath" : "riscv64-linux-gdb" , "miDebuggerServerAddress" : "localhost:1234" , } ] }
以上内容所描述的行为差不多相当于执行: 1 2 3 $ gdb $ file ${workspaceFolder} /apps/hv/hv_qemu-virt-riscv.elf $ target remote localhost:1234
makefile也应随之修改,把启动gdb的内容删掉:
1 2 debug: build $(call run_qemu_debug)
到了这一步,只需要先make ARCH=riscv64 A=apps/hv HV=y LOG=info debug
启动qemu,如果正常的话qemu会暂停等待连接;然后再于vscode启动调试,待连接完成,qemu会继续执行,我们也可以直接在vscode进行单步/断点等操作了。
3. rust-gdb
参考【笔记】rCore (RISC-V):GDB 使用记录 | 苦瓜小仔 (zjp-cn.github.io)
使用rust-gdb
可以更好地显示 Rust 的类型,不一定必须。
通过环境变量启动(gdb版本可能不同,改成自己要用的就行): 1 $ RUST_GDB=riscv64-linux-gdb rust-gdb
此时能看到启动后的target信息This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-buildroot-linux-musl".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 GNU gdb (GDB) 13.2 Copyright (C) 2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. ** This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-buildroot-linux-musl" . ** Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help , type "help" .
这时候set architecture
应该会提示有riscv的架构了。
到VSCode部分,根据之前的launch.json
进行部分修改,其中使用"environment"
好像没用,于是就自己添加了环境变量RUST_GDB=riscv64-linux-gdb
,把"environment"
注释掉了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 { "version" : "0.2.0" , "configurations" : [ { "name" : "qemu connect" , "type" : "cppdbg" , "request" : "launch" , "program" : "${workspaceFolder}/apps/hv/hv_qemu-virt-riscv.elf" , "args" : [ ] , "stopAtEntry" : false , "cwd" : "${fileDirname}" , "externalConsole" : false , "MIMode" : "gdb" , "setupCommands" : [ { "description" : "为 gdb 启用整齐打印" , "text" : "-enable-pretty-printing" , "ignoreFailures" : true } , { "description" : "将反汇编风格设置为 Intel" , "text" : "-gdb-set disassembly-flavor intel" , "ignoreFailures" : true } , { "description" : "Set architecture to riscv64" , "text" : "-gdb-set architecture riscv:rv64" } ] , "miDebuggerPath" : "rust-gdb" , "miDebuggerServerAddress" : "localhost:1234" , "logging" : { "engineLogging" : true } , } ] }
4. todo
我尝试在launch.json
添加preLaunchTask
来完成一键启动,即让vscode全套执行先启动qemu+后启动gdb的过程,从而达到一键debug。然而我不知道如何操作preLaunchTask
的同步,看上去vscode执行完启动qemu的指令后就立刻启动了gdb,它没有等待qemu进入连接状态后再启动gdb,即使我在指令后添加了sleep 5
也没有效果。我暂时没有找到办法完成这一点。