Loading... > 简要记录一下为了调试 rCore 而配置的 VSCode 调试环境。 Debugging an OS kernel is not as simple as debugging a normal program, especially when it requires cross-platform compiler and QEMU simulator. In order to have a better experience with debugging rCore, an OS written by our university for teaching the OS course, I set up VSCode with related toolchains. In this article, I will briefly note some of tools and show my VSCode configurations. My working environment: macOS Monterey on MacBook Pro with Intel i9 Something about rCore that I used to debug: rust, RISC-V # QEMU Install QEMU by Homebrew. On macOS, there's only a system mode simulator. I leverage Docker to run a normal user program by adding a function into `~/.zshrc`: ```sh docker-rv64-run() { docker run --rm -it -v "$(pwd)":"/workspace" riscv64/alpine:edge "/workspace/$1" } ``` Note that some bugs may occur when the user program has runtime errors. To start the OS by QEMU: ```sh qemu-system-riscv64 -machine virt -nographic -bios $workspaceRoot/bootloader/rustsbi-qemu.bin -device loader,file=$workspaceRoot/os/target/riscv64gc-unknown-none-elf/debug/os.bin,addr=0x80200000 -s -S ``` Meaning of the options: ```sh -s shorthand for -gdb tcp::1234 -S freeze CPU at startup (use 'c' to start execution) ``` Use `Cmd A + X` to terminate QEMU. # RISC-V Tools ## GDB Use cross-platform GDB to debug the kernel running in QEMU: ```sh riscv64-unknown-elf-gdb -ex 'set arch riscv:rv64' -ex 'file target/riscv64gc-unknown-none-elf/debug/os' -ex 'target remote :1234' ``` In GDB, there are some useful commands: ``` x/10i $pc lay asm lay src b *0x80400000 b *&label_name ni si ``` ## Objdump Disassemble all of binary file: ```sh riscv64-unknown-elf-objdump -S -s ../user/target/riscv64gc-unknown-none-elf/debug/test1_write1 ``` Disassemble a specific section: ```sh # -S # --source # Display source code intermixed with disassembly, if # possible. Implies -d. # -s # --full-contents # Display the full contents of any sections requested. By # default all non-empty sections are displayed. # -j name # --section=name # Display information only for section name. riscv64-unknown-elf-objdump -S -s -j .rodata ../user/target/riscv64gc-unknown-none-elf/debug/test1_write ``` # VSCode Download the extension "Native Debug", and then modify `launch.json` and `task.json`. `launch.json` : ```json { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "gdb", "request": "attach", "name": "Attach to gdbserver", "gdbpath": "riscv64-unknown-elf-gdb", "autorun": [ "set arch riscv:rv64", ], "executable": "${workspaceRoot}/os/target/riscv64gc-unknown-none-elf/debug/os", "target": ":1234", "remote": true, "cwd": "${workspaceRoot}/os", "valuesFormatting": "prettyPrinters", "preLaunchTask": "qemuStartKernel", }, { "type": "gdb", "request": "launch", "name": "Launch Program", "gdbpath": "riscv64-unknown-elf-gdb", "autorun": [ "set arch riscv:rv64", "target remote localhost:1234", "file ${workspaceRoot}/os/target/riscv64gc-unknown-none-elf/debug/os", ], "target": "${workspaceRoot}/os/target/riscv64gc-unknown-none-elf/debug/os", "cwd": "${workspaceRoot}/os", "valuesFormatting": "prettyPrinters", "preLaunchTask": "qemuStartKernel", }, { "type": "cppdbg", "request": "launch", "name": "Debug by Cpp", "miDebuggerPath": "riscv64-unknown-elf-gdb", // "miDebuggerArgs": "-ex 'set arch riscv:rv64'", "program": "${workspaceRoot}/os/target/riscv64gc-unknown-none-elf/debug/os", "miDebuggerServerAddress": "localhost:1234", "cwd": "${workspaceRoot}/os", "preLaunchTask": "qemuStartKernel", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ], }, ] } ``` As you can see, there are three configurations, but actually they do the same thing. There are some key points about this configuation: - The first two configuations are made for the `Native Debug` extension. The last one is for an extension related to cpp. (I don't know which one it is exactly.) - I think it is the `type` entry that determines which extension will be used when debugging. - The keys in each configuation need to be matched with design of the corresponding extension. The extension will read some specified keys according to its implementaion. Those it doesn't know will have no effect. - One annoying thing is that some extensions have little examples or documents to tell us which keys it will read. For example, using `target` or `executable` is confusing, and the extension even uses them in different ways in different "types". One trick we can use is that, the auto-completed keys not proposed by copilot or tabnine or their counterparts in the VSCode editor are the legal keys to use in the editing configuration. Since it requires to launch QEMU as a "backend" before debugging with GDB (VSCode is also based on GDB), we need to add a `tasks.json` in the `.vscode` directory. We implement the "preLaunchTask" "qemuStartKernel" used in `launch.json`. ```json { // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "label": "qemuStartKernel", "type": "shell", // "command": "tmux new-session -d 'qemu-system-riscv64 -machine virt -nographic -bios ${workspaceRoot}/bootloader/rustsbi-qemu.bin -device loader,file=${workspaceRoot}/os/target/riscv64gc-unknown-none-elf/debug/os.bin,addr=0x80200000 -s -S' && tmux -2 at -d", "command": "qemu-system-riscv64 -machine virt -nographic -bios ${workspaceRoot}/bootloader/rustsbi-qemu.bin -device loader,file=${workspaceRoot}/os/target/riscv64gc-unknown-none-elf/debug/os.bin,addr=0x80200000 -s -S", "isBackground": true } ] } ``` Note that I don't add making and building commands in this "preLaunchTask", since it takes more than 5 seconds to complete even everything is unchanged after the last building. So I build the OS manually after changing it. Just click OK and remember our choice when something pops up after launching the debugging process. Using configurations for the `Native Debug` extension, we can execuate GDB commands in VSCode in the debug console. It seems that currently it is not able to jump into assembly files direcly in the VSCode, so we still need to use raw GDB commands sometimes. Last modification:March 7, 2022 © Allow specification reprint Support Appreciate the author Like 0 如果觉得我的文章对你有用,请随意赞赏