编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

我们一起学RISC-V——06-GDB+QEMU调试环境搭建

wxchong 2024-08-07 02:00:22 开源技术 69 ℃ 0 评论

本期内容如下:

  1. GDB调试概述
  2. 编译和安装QEMU
  3. 调试演示

在之前的01-05章我们讲解了RISC-V ISA相关的知识,对RISC-V也已经有个基本的了解,为了加深对RISC-V ISA的理解,光做到看还是不够的,我们还需要动手去编写汇编代码。

GDB工具用于调试编译后的代码;QEMU用于仿真RISC-V处理器,这样我们就可以不需要具体硬件就可以调试我们的汇编代码,对于学习十分方便。


如果,有些人需要在具体硬件上进行仿真调试,我今后还会写一篇文章,介绍如何使用JTAG在linux上进行硬件调试的文章,还请关注。

一、GDB调试概述


GNU symbolic debugger,简称「GDB 调试器」,是 Linux 平台下最常用的一款程序调试器。GDB 编译器通常以 gdb 命令的形式在终端(Shell)中使用。作为程序员,编写和调试程序是必备的技能,为此学好gdb是十分有必要的,还请读者自行查阅相关文档,在这里就不对gdb功能进行过多展开了。

在RISC-V的开发过程中,我们用的gdb工具被包含在工具链中,文件名类似于riscv-none-embed-gdb。在这里我们简单了解一下gdb的基本指令。

  1. riscv-none-embed-gdb 执行文件名称 ---------------gdb加载符号文件,用于后续的调试
  2. run ----------------此命令使程序开始运行

更多指令参见图1.

二、编译,安装和使用QEMU


由于不同的linux发行版本,在软件上兼容性可能会存在一些问题,这里仅介绍如何在linux上,进行RISC-V的QEMU编译和安装,并没有提供已经编译好的qemu-riscv32,我这里采用的操作系统为deepin-v20,其他linux系统编译和安装方法类似。

2.1 QEMU编译和安装

具体步骤如下:

sudo apt install libpixman-1-dev
git clone https://github.com/riscv/riscv-qemu.git
cd riscv-qemu/
git checkout riscv-qemu-3.0
./configure
make -j4
sudo make install 

编译时也许会遇到如下问题

qemu/linux-user/ioctls.h:225:9: error: ‘SIOCGSTAMP’ undeclared here (not in a function); did you mean ‘SIOCSRARP’?
225 | IOCTL(SIOCGSTAMP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timeval)))
| ^~~~~~~~~~
qemu/linux-user/syscall.c:4855:23: note: in definition of macro ‘IOCTL’
4855 | { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
| ^~~
qemu/linux-user/ioctls.h:226:9: error: ‘SIOCGSTAMPNS’ undeclared here (not in a function); did you mean ‘SIOCGSTAMP_OLD’?
226 | IOCTL(SIOCGSTAMPNS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timespec)))
| ^~~~~~~~~~~~
qemu/linux-user/syscall.c:4855:23: note: in definition of macro ‘IOCTL’
4855 | { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },

请按参照如下修即可解决编译错误。

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b187c1281d..f13e260b02 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -37,6 +37,7 @@
#include <sched.h>
#include <sys/timex.h>
#include <sys/socket.h>
+#include <linux/sockios.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <poll.h>

当一切都安装完成后,我们执行qemu-riscv32 --version应当能够看到如图2所示的内容。

2.2 qemu-riscv32的使用

  • qemu-riscv32指令常用格式如下:

qemu-riscv32 程序名称 -nographic

如我们已经有一个已经编译好的riscv32 程序hello,为了在qemu中运行程序,只需要执行如下指令即可。

qemu-riscv32 hello -nographic

  • 如果我们希望联合riscv-none-embed-gdb,并通过qemu实现调试,我们可以使用如下指令让qemu支持gdb单步调试功能。

qemu-riscv32 -singlestep -g 端口号 程序名 -nographic

如需要对上边的hello程序进行调试,我们选的通讯端口为112233,此时指令如下:

qemu-riscv32 -singlestep -g 112233 hello -nographic

三、调试演示


3.1 编写汇编文件hello.S文件,

该文件主要实现两个数相加,加数1放入a1,加数2放入a2,结果a0

  .global _start
_start:
      li a1,23
      li a2,18
      add a0,a1,a2

loop:
      j   loop

3.2 编写Makefile文件

Makefile文件主要是为了方便今后的代码编译,不需要每次都输入很长的编译指令,仅需执行make,即可完成程序的编译。

CC:=riscv-none-embed-gcc
XFLAGS+= -save-temps -nostdlib -nostartfiles -ffreestanding -static 

all:
	$(CC) $(XFLAGS) -g -o hello hello.S

clean:
	rm -rf *.o

riscv-none-embed-gcc为我选用的工具链的编译器名称,如果你的编译器为其他,请做相应的修改,gcc是可以直接编译汇编指令的当然你也可以使用riscv-none-embed-as进行编译。

3.3 编写仿真器启动脚本sim

sim脚本不是必须的,之所以这样写是为了方便今后快速用qemu加载编译后的程序,方便调试exe_name为要执行的程序,这里实行./sim hello就实现了加载hello程序到qemu仿真器的操作。

function help()
{
echo "Please input applicantion !"
echo "==========="
echo "sim  exe_name"
}

function main()
{

if [ "$1" == "" ];then
	help
	return
fi

qemu-riscv32 -singlestep -g 12345 $1 nographic
}

main $1

3.4 完成各文件的编写

所有文件编写完后,我们将看到如图3所示的hello工程目录结构。

3.5 编译hello.S文件

执行make指令,将看到hello文件被创建了

3.6 开启qemu-riscv32仿真器

执行sim hello,qemu-riscv32将会加载hello程序


3.7 开启riscv32的gdb工具

1.执行riscv-none-embed-gdb hello,该指令将会把hello文件加载到gdb中;

2.在gdb控制台中执行target remote localhost:12345 连接qemu-riscv32仿真器;

3.前两步完成后便可以开始调试hello程序了。



3.8 调试hello程序

具体调试的过程参见如下gdb调试log,

Copyright (C) 2019 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-unknown-linux-gnu --target=riscv-none-embed".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://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".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello...        
(gdb) target remote localhost:12345
Remote debugging using localhost:12345
_start () at hello.S:4
4           li  a1,23
(gdb) list
1           .align 4
2           .global  _start
3       _start:
4           li  a1,23
5           li  a2,18
6           add a0,a1,a2   
7
8
9       loop:
10         j    loop
(gdb) break 7
Breakpoint 1 at 0x1006a
(gdb) break 3
Breakpoint 2 at 0x10062: file hello.S, line 5.
(gdb) next

Breakpoint 2, _start () at hello.S:5
5           li  a2,18
(gdb) next
6           add a0,a1,a2   
(gdb) next
loop () at hello.S:10
10         j    loop
(gdb) info registers 
ra             0x0      0x0
sp             0xffffcda0       0xffffcda0
gp             0x0      0x0
tp             0x0      0x0
t0             0x0      0
t1             0x0      0
t2             0x0      0
fp             0x0      0x0
s1             0x0      0
a0             0x29     41
a1             0x17     23
a2             0x12     18
a3             0x0      0
a4             0x0      0
a5             0x0      0
a6             0x0      0
a7             0x0      0
s2             0x0      0
s3             0x0      0
s4             0x0      0
s5             0x0      0
s6             0x0      0
s7             0x0      0
s8             0x0      0
s9             0x0      0
s10            0x0      0
s11            0x0      0
t3             0x0      0
t4             0x0      0
t5             0x0      0
t6             0x0      0
--Type <RET> for more, q to quit, c to continue without paging--c
pc             0x10068  0x10068 <loop>

从gdb调试过程中可以看到a0的值为41,a1为23,a2为18,也就是说a0=a1+a2,和我们的汇编程序一样。


至此,一个可以仿真和调试RISC-V环境就已经搭建完毕了,今后我们便可以在这个环境下学习具体的汇编指令了,通过gdb的info registers指令我们可以实时查看到RISC-V处理器的所有寄存器数据。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表