当前位置: 首页 > news >正文

在Ubuntu上使用QEMU学习RISC-V程序(2)gdb调试

文章目录

      • 一、准备工作
      • 二、基本调试流程
        • 1. 设置断点
        • 2. 执行程序
        • 3. 查看源代码/汇编
      • 三、查看寄存器
        • 1. 查看通用寄存器
        • 2. 查看特殊寄存器
      • 四、查看内存
        • 1. 内存查看命令
        • 2. 内存修改命令
      • 五、调试实战示例
      • 六、高级调试技巧
        • 1. 条件断点
        • 2. 自动显示
        • 3. 内存断点(观察点)
        • 4. 回溯调用栈
      • 七、退出调试
    • 八、退出QEMU
      • 总结

在嵌入式开发中,GDB是调试RISC-V程序的核心工具。以下是使用 gdb-multiarch调试 add.elf程序的详细步骤,包括断点设置、寄存器查看、内存分析等关键操作:

一、准备工作

  1. 给elf文件增加调试信息
# 编译汇编代码(添加-g选项)
riscv64-unknown-elf-as -g -march=rv64g -mabi=lp64 add.s -o add.o# 链接(保持-g选项)
riscv64-unknown-elf-ld -g -T link.ld add.o -o add.elf# 检查文件是否包含调试信息
riscv64-unknown-elf-readelf -S add.elf | grep debug# 输出示例(应包含多个debug_*节)
.debug_info     PROGBITS        0000000000000000  000002e0
.debug_abbrev   PROGBITS        0000000000000000  000006e8
.debug_line     PROGBITS        0000000000000000  000007e0
  1. 启动QEMU并暂停执行
qemu-system-riscv64 \-machine virt \-cpu rv64 \-m 128M \-nographic \-bios none \-kernel add.elf \-s -S  # -s开启GDB服务器,-S暂停执行直到GDB连接
  1. 启动GDB并连接到QEMU
    如果没有安装gdb-multiarch,先用sudo apt install gdb-multiarch进行安装。
gdb-multiarch add.elf  # 加载带有调试信息的ELF文件# 在GDB交互式界面中执行以下命令
(gdb) set architecture riscv:rv64  # 指定目标架构
(gdb) target remote :1234         # 连接到QEMU的GDB服务器

二、基本调试流程

1. 设置断点
(gdb) break _start        # 在_start标签处设置断点
(gdb) break add.s:20      # 在add.s文件第20行设置断点
(gdb) break print_string  # 在print_string函数入口设置断点
(gdb) info breakpoints    # 查看已设置的断点
2. 执行程序
(gdb) continue            # 继续执行到下一个断点
(gdb) next                # 单步执行(不进入函数)
(gdb) step                # 单步执行(进入函数)
(gdb) finish              # 执行完当前函数并返回
(gdb) until 25            # 执行到当前文件第25行
3. 查看源代码/汇编
(gdb) list                # 显示当前位置附近的源代码
(gdb) list 10,20          # 显示第10-20行代码
(gdb) disassemble         # 反汇编当前函数
(gdb) x/i $pc             # 显示当前执行的指令
(gdb) layout asm          # 切换到汇编视图
(gdb) layout regs         # 显示寄存器窗口

三、查看寄存器

1. 查看通用寄存器
(gdb) info registers      # 显示所有寄存器
(gdb) print $a0           # 查看a0寄存器的值
(gdb) p/x $sp             # 以十六进制形式查看sp寄存器
(gdb) p/a $ra             # 以地址形式查看ra寄存器
(gdb) display $t0         # 每次停止时自动显示t0寄存器
2. 查看特殊寄存器
(gdb) p $mstatus          # 查看机器状态寄存器
(gdb) p $mcause           # 查看异常原因寄存器
(gdb) p $mtvec            # 查看异常向量表基址
(gdb) set $pc = 0x80000010  # 修改程序计数器

四、查看内存

1. 内存查看命令
(gdb) x/10xw 0x80000000   # 从0x80000000开始,以16进制显示10个32位字
(gdb) x/20b $sp            # 从sp开始,以字节形式显示20个值
(gdb) x/10i 0x80000000    # 从0x80000000开始,显示10条指令
(gdb) examine/i $pc        # 查看当前执行的指令
2. 内存修改命令
(gdb) set {int}0x80000010 = 42  # 将0x80000010处的32位整数设置为42
(gdb) set *0x80000014 = 0x1234  # 将0x80000014处的16位值设置为0x1234

五、调试实战示例

假设我们要调试add.s程序中的加法操作:

  1. 设置断点并开始执行
(gdb) break _start
(gdb) continue
  1. 单步执行到加法操作
(gdb) step  # 执行初始化栈指针
(gdb) step  # 加载a0 = 10
(gdb) step  # 加载a1 = 20
(gdb) step  # 执行add a2, a0, a1
  1. 验证加法结果
(gdb) p/x $a0    # 应该显示0xa (10)
(gdb) p/x $a1    # 应该显示0x14 (20)
(gdb) p/x $a2    # 应该显示0x1e (30)
  1. 查看内存中的变量
(gdb) x/i $pc    # 显示当前指令
(gdb) x/10xw 0x80000000  # 查看.text段内容
(gdb) x/10xw $sp         # 查看栈内容
  1. 调试UART输出
(gdb) break print_string
(gdb) continue
(gdb) step  # 进入print_string函数
(gdb) p $a0  # 查看要打印的字符串地址
(gdb) x/s $a0  # 以字符串形式显示内存内容

六、高级调试技巧

1. 条件断点
(gdb) break add.s:25 if $a0 > 10  # 当a0>10时触发断点
2. 自动显示
(gdb) display/i $pc        # 每次停止时显示当前指令
(gdb) display/x $a0        # 每次停止时显示a0寄存器
3. 内存断点(观察点)
(gdb) watch *0x80000020    # 当地址0x80000020被修改时触发
4. 回溯调用栈
(gdb) backtrace           # 显示调用栈
(gdb) frame 1             # 切换到第1层栈帧

七、退出调试

(gdb) disconnect          # 断开与QEMU的连接
(gdb) quit                # 退出GDB

八、退出QEMU

退出qemu-system-riscv64通常可以使用快捷键或通过监视器界面来操作,具体方法如下:

  • 使用快捷键:按下Ctrl + a,然后松开这两个键,再按下x,即可直接终止QEMU进程,回到shell界面。
  • 通过监视器界面:首先按下Ctrl + a,然后松开,再按下c,这将退出当前操作系统的shell界面,进入QEMU的监视器界面。接着在监视器界面中,输入q并按回车键,即可完全退出QEMU。

总结

通过上述命令,你可以全面掌控程序的执行流程,监控寄存器和内存的变化,从而快速定位问题。GDB的强大功能不仅适用于调试简单程序,也是开发复杂嵌入式系统的必备工具。建议结合具体程序多练习,熟练掌握这些命令将显著提高开发效率。

http://www.xdnf.cn/news/1179955.html

相关文章:

  • Java面试宝典:Spring专题二
  • 回调后门 函数
  • 如何彻底清除服务器上的恶意软件与后门
  • 基于Matlab图像处理的水果分级系统
  • Compose 适配 - 键鼠模式
  • Linux和Windows基于V4L2和TCP的QT监控
  • JavaWeb学习打卡13(JSP原理解析)
  • 【0基础PS】PS(Photoshop)与Ai( Illustrator )等相似软件区别
  • 内网IM:BeeWorks私有化部署的安全通讯解决方案
  • Linux命令基础完结篇
  • Windows 11下纯软件模拟虚拟机的设备模拟与虚拟化(仅终端和网络)
  • 【C++】类和对象(1)
  • go项目实战二
  • ESP32- 项目应用1 智能手表 之更新天气#4
  • Rust与YOLO目标检测实战
  • OpenLayers 综合案例-基础图层控制
  • ddos 放在多个云主机,同时运行
  • vue递归树形结构删除不符合数据 生成一个新数组
  • 点击按钮滚动到底功能vue的v-on:scroll运用
  • 04.建造者模式的终极手册:从快餐定制到航天飞船的组装哲学
  • 期待更好的发展
  • 使用全局变量访问 Qt UI 组件的方法文档
  • 基于markdown封装的前端文档编辑工具,markdown.js的解析与应用
  • 开源Qwen凌晨暴击闭源Claude!刷新AI编程SOTA,支持1M上下文
  • SQL基础⑪ | 约束
  • 基于ABC与BP神经网络分类模型的特征选择方法研究(Python实现)
  • 制造业新突破:AR 培训系统助力复杂操作轻松上手​
  • Linux服务器安全自动化审计实战:一键扫描账户/网络/进程/计划任务风险(附开源脚本)
  • 数据库期中复习
  • 【Guava】1.1.我的报告