QEMU模拟器源码编译与使用


本文属于 《RISC-V指令集差分测试(DiffTest)系列教程》之一,欢迎查看其它文章。

1 编译MySBI+BenOS

参考《NEMU模拟器源码编译与使用》中,第2节内容。

由于《RISC-V体系结构编程与实践》示例代码有问题(这个作者也知道,原因是:PMP未开启导致无法进入benos),因此,我们需要进行一些修改,才能在高版本的QEMU上运行(我这里用的qemu-7.1.0)。
此BUG的修复介绍,也可参考博客《VSCODE+QEMU+WSL调试RISCV代码(SBI、kernel)》

修改好的代码chapter_2,可从此处获取:

https://gitee.com/bailiyang/cdemo/tree/master/riscv_programming_practice/chapter_2/benos

编译步骤:

cd benos
vim Makefile
GNU ?= riscv64-unknown-linux-gnu          # 将Makefile文件第一行,修改为本行内容
export board=qemu
make

生成了,如下文件:

  • benos.bin,BenOS可执行文件
  • benos.elf,BenOS带调试信息的ELF文件
  • mysbi.bin,MySBI固件的可执行文件
  • mysbi.elf,MySBI带调试信息的ELF文件
  • benos_payload.bin,把benos.bin和mysbi.bin整合到一个可执行二进制文件中。

需要在QEMU中运行的文件有:mysbi.bin、benos.bin、benos.elf。

2 编译QEMU

参考《在QEMU上运行OpenSBI+Linux+Rootfs》中,第1节内容。

3 QEMU运行MySBI+BenOS

将mysbi.bin、benos.bin、benos.elf,拷贝到qemu-7.1.0/build/目录下。
在QEMU中,运行MySBI+BenOS

./qemu-system-riscv64 -nographic -machine virt -m 128M -bios mysbi.bin -device loader,file=benos.bin,addr=0x80200000 -kernel benos.elf

命令参数妙用:

  • -d in_asm,cpu:in_asm表示打印指令在翻译前的反汇编,即原始机器码的反汇编。cpu表示打印CPU寄存器。
  • -D ./qemu.log:表示输出日志到qemu.log文件中。

运行效果,如下所示:

在这里插入图片描述

我们的BenOS,通过串口打印出了信息:Welcome RISC-V!

BenOS代码kernel.c,实现代码,如下所示:

#include "uart.h"

void kernel_main(void)
{
	uart_init();
	uart_send_string("Welcome RISC-V!\r\n");

	while (1) {
		;
	}
}

此时,无法退出QEMU。可以通过以下命令,来退出QEMU:

kill $(ps aux | grep qemu | grep -v grep | awk '{print $2}')

4 使用gdb调试QEMU代码

上述步骤,编译的QEMU,直接就可以gdb调试,只是有一些还是有所优化,如果要完全无优化,可能还需要自己配置再重新编译。

直接在上述命令前,加gdb --args

gdb --args ./qemu-system-riscv64 -nographic -machine virt -m 128M -bios mysbi.bin -device loader,file=benos.bin,addr=0x80200000 -kernel benos.elf

启动调试,如下所示:
在这里插入图片描述

在/target/riscv/translate.c:1052行,打断点:b translate.c:1052,然后
r运行,即可在该断点处停住。

gdb调试QEMU代码成功。

5 通过QEMU调试指令

我们使用QEMU内置的RISCV调试器,来调试BenOS固件代码benos.bin。

benos.bin是RISC-V代码,因此就不能使用X86的gdb来调试了,需要使用RISC-V版的gdb,即riscv64-unknown-elf-gdb。

5.1 安装riscv64-unknown-elf-gdb

  1. 首先安装一些依赖项,其中 libncurses5-dev 提供了 TUI 库(–enable-tui 需要它)
sudo apt-get install libncurses5-dev texinfo libreadline-dev python python-dev 

这里的 python 和 python-dev 并不必须是 python2,我本地的默认 python 就是 3,可以编译成功并且正常使用

  1. 检查本地 python 路径
which python

或者 ll $(which python) 查看链接到那个 python,我的是/usr/bin/python3 -> /usr/bin/python3.6

  1. 下载GDB 源码
wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gdb/gdb-14.2.tar.xz

清华镜像地址: https://mirrors.tuna.tsinghua.edu.cn/gnu/gdb/?C=M&O=D

  1. 解压
tar -xf gdb-14.2.tar.xz
  1. 进入这个目录,并在里面创建另一个目录,用来存放编译结果和二进制文件
cd gdb-14.2
mkdir build-riscv64

适当阅读一下 gdb-14.2/gdb/README,这可是 GDB 的官方安装说明

  1. 进入 gdb-14.2/build-riscv64 目录,准备编译
cd build-riscv64
../configure --prefix=/home/test/tools/gdb-14.2_install --with-python=/usr/bin/python3 --target=riscv64-unknown-elf --enable-tui=yes

--prefix:表示安装路径,编译后的可执行程序等,会拷贝到这个目录下
--with-python:表示python可执行程序文件路径

  1. 编译并生成二进制文件
make -j$(nproc)
make install
  1. 编译好的 GDB 存放在 /home/test/tools/gdb-14.2_install/bin/ 目录下,你可以只保留这个目录,然后添加这个目录到环境变量。

确认 GDB 可以运行

./riscv64-unknown-elf-gdb --version

~/.bashrc 文件末尾,添加以下一行:

export PATH=/home/test/tools/gdb-14.2_install/bin:$PATH

然后执行source ~/.bashrc,使其立即生效。

  1. 安装 gdb-dashboard(可选,似乎下载失败):仅仅是下载一个 python 文件到 ~/.gdbinit 来做 gdb 的启动拓展
wget -P ~ https://github.com/cyrus-and/gdb-dashboard/raw/master/.gdbinit

在这里插入图片描述
到这里gdb就装好了,接下来我们去调试RISC-V代码。

5.2 调试RISC-V代码

我们在,上述QEMU启动命令中,加入-S -s,以启动gdb server:

./qemu-system-riscv64 -S -s -nographic -machine virt -m 128M -bios mysbi.bin -device loader,file=benos.bin,addr=0x80200000 -kernel benos.elf
  • -s参数,也可以用-gdb tcp:1234代替,含义一样;此参数相当于,启动了一个端口1234的TCP服务器。
  • 需要注意,对于-gdb tcp:1234参数,有些QEMU版本可能不支持,跑不起来。

在另外一个终端中,输入如下命令启动gdb:

riscv64-unknown-elf-gdb benos.elf

benos.elf为调试符号文件,若要调试mysbi.bin,那这里就要使用mysbi.elf。

在gdb命令行中,输入以下命令:

target remote localhost:1234		# 连接gdb server
b _start							# 在_start处打断点
c									# 运行

运行效果,如下:

在这里插入图片描述

可以看到在src/boot.S文件中,第6行_start处停住了。

在这里插入图片描述

同时按Ctrl+X+A,可以呼出源码界面,也可以输入n单步执行。

QEMU调试BenOS固件代码成功。

6 小结

QEMU通过-S -s启动了gdb server,通讯方式是TCP,端口1234。

那么,如果我们知道与gdb server的数据包协议,是不是就可以编写一个程序,去控制QEMU的单步执行,以及获取CPU寄存器、内存等,是的,这是可行的。

这个设想,正是后续文章中,介绍的NEMU与QEMU通过socket方式,做DiffTest的底层原理。


参考文档:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值