2. 使用OpenOCD连接RISC-V SoC的JTAG调试

任务目标

在本案例中,你将启动QEMU内置的RISC-V virt机器,在其上运行一个简单的RISC-V汇编程序,并通过GDB远程连接进行调试。完成本案例后,你将掌握QEMU作为RISC-V处理器模拟器的基本使用方法,以及GDB远程调试的完整流程。

环境准备

需要安装以下工具(以Ubuntu/Debian为例):

sudo apt-get install qemu-system-misc gdb-multiarch binutils-riscv64-linux-gnu

验证安装:

qemu-system-riscv64 --version
riscv64-linux-gnu-as --version
gdb-multiarch --version

实现步骤

1. 编写RISC-V汇编程序

创建一个文件 hello.s,内容如下:

.section .text
.globl _start
_start:
    li t0, 0x10000000   # UART基地址(virt机器)
    li t1, 0x48         # 'H'
    sb t1, 0(t0)
    li t1, 0x65         # 'e'
    sb t1, 0(t0)
    li t1, 0x6C         # 'l'
    sb t1, 0(t0)
    sb t1, 0(t0)        # 第二个'l'
    li t1, 0x6F         # 'o'
    sb t1, 0(t0)
    li t1, 0x0A         # '\n'
    sb t1, 0(t0)

    # 死循环,便于调试观察
loop:
    j loop

2. 编译链接

riscv64-linux-gnu-as -o hello.o hello.s
riscv64-linux-gnu-ld -o hello.elf -Ttext=0x80000000 hello.o
riscv64-linux-gnu-objcopy -O binary hello.elf hello.bin

说明:virt机器默认加载地址为0x80000000,链接脚本指定代码段起始地址。

3. 启动QEMU并运行程序

qemu-system-riscv64 -machine virt -nographic -bios none -kernel hello.bin

预期输出:终端显示 Hello 后程序进入死循环。按 Ctrl+A 然后按 X 退出QEMU。

4. 连接GDB进行远程调试

首先以调试模式启动QEMU(新终端):

qemu-system-riscv64 -machine virt -nographic -bios none -kernel hello.bin -s -S

参数说明:-s 在端口1234开启GDB服务,-S 启动时暂停CPU等待调试器连接。

然后在另一个终端启动GDB:

gdb-multiarch hello.elf
(gdb) target remote :1234
(gdb) continue

GDB连接后,程序开始执行,QEMU终端输出 Hello。此时可在GDB中按 Ctrl+C 中断程序,使用 info registers 查看寄存器状态,或使用 break *0x80000000 设置断点后重新运行。

验证方法

  • 运行验证:QEMU终端正确输出 Hello,说明程序在模拟的RISC-V处理器上正常执行。
  • 调试验证:GDB成功连接后,执行 continue 能看到程序运行;中断后 info registers 能显示RISC-V寄存器内容(如 pc、t0、t1),且 pc 指向死循环地址。
  • 断点验证:在 0x80000000 设置断点后重启程序,GDB应在第一条指令处暂停,单步执行 stepi 可逐条观察指令执行。

常见问题

  • GDB连接失败:确认QEMU以 -s -S 参数启动,且端口1234未被占用。
  • 程序无输出:检查UART地址是否为 0x10000000(virt机器标准地址),以及链接地址是否正确。
  • 架构不匹配:使用 gdb-multiarch 而非默认 gdb,并确保加载的是ELF文件(hello.elf)而非二进制文件。

本案例通过最小可复现示例,完成了QEMU模拟RISC-V处理器、运行程序及GDB远程调试的完整闭环。后续案例将在此基础上扩展更多调试技巧。