跳转至

GDB+QEMU 调试 64 RISC-V LINUX

798 个字 29 行代码 预计阅读时间 3 分钟

Abstract

计算机系统 Ⅱ lab3 实验报告(2022.10.27 ~ 2022.11.10)

Warning

仅供学习参考,请勿抄袭

实验内容

  • 搭建实验环境
    • 安装 risc-v 工具链和 qemu 模拟器
  • 获取 Linux 源码和已经编译好的文件系统
    • kernel.org 下载最新的 Linux 源码
    • 从课程仓库克隆文件系统镜像
  • 编译 Linux 内核
  • 使用 QEMU 运行内核
  • 使用 GDB 对内核进行调试
  • 思考题
    • 使用 riscv64-linux-gnu-gcc 编译单个 .c 文件
    • 使用 riscv64-linux-gnu-objdump 反汇编前面得到的编译产物
    • 调试 Linux 时:
      1. GDB 中查看汇编代码
      2. 0x80000000 处下断点
      3. 查看所有已下的断点
      4. 0x80200000 处下断点
      5. 清除 0x80000000 处的断点
      6. 继续运行直到触发 0x80200000 处的断点
      7. 单步调试一次
      8. 退出 QEMU
    • 学习 Makefile 的基本使用
      1. 观察可用的 target,应该使用 make ? 来清除 Linux 的构建产物?
      2. 默认情况下,内核编译显示的是简略信息(例如:CC init/main.o,应该使用 make ? 来显示 Linux 详细的编译过程呢?

环境搭建

安装 risc-v 工具链和 qemu 模拟器

命令行运行:

sudo apt install qemu-system-misc gcc-riscv64-linux-gnu gdb-multiarch
检查版本:

安装其它后续需要的软件包

Ubuntu 不自带 makegcc 等工具,需要手动安装:

sudo apt install build-essential

在后面编译内核的过程中会出现 /bin/sh: 1: flex: not found 以及 bison: not found 的错误,需要安装 flex bison

sudo apt install flex bison

获取、编译源码

获取 Linux 源码

kernel.org 上查找源码,选择 6.0.5 版本下载(6.1 版本中含有 rust,不选)并解压:

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.0.5.tar.xz
tar -xf linux-6.0.5.tar.xz

克隆课程仓库:

git clone https://git.zju.edu.cn/zju-sys/sys2lab-22fall-stu.git

编译 Linux 内核

进入解压后的 Linux 源码文件夹,进行编译:

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j4
十分钟后完成编译,并可以 ls 查看到编译产物:

运行、调试内核

使用 QEMU 运行内核

进入 sys2lab-22fall-stu/src/lab3 目录中,运行:

qemu-system-riscv64 -nographic -machine virt \
    -kernel ~/Desktop/linux-6.0.5/arch/riscv/boot/Image \
    -device virtio-blk-device,drive=hd0 \
    -append "root=/dev/vda ro console=ttyS0" \
    -bios fw_jump.bin -drive file=rootfs.img,format=raw,id=hd0
使用 QEMU 模拟器来运行内核。这里要注意,kernel 是 arch/riscv/boot/Image 而不是 vmlinux,而且不能加 -S -s,否则会等待 gdb 连接再操作运行。运行起来之后就可以进入到 shell 中运行指令了:

然后 exit 退出 shell,Ctrl+A、X 退出 QEMU

使用 GDB 调试内核

在一个终端运行下面命令启用一个内核并等待调试:

qemu-system-riscv64 -nographic -machine virt \
    -kernel ~/Desktop/linux-6.0.5/arch/riscv/boot/Image \
    -device virtio-blk-device,drive=hd0 \
    -append "root=/dev/vda ro console=ttyS0" \
    -bios fw_jump.bin -drive file=rootfs.img,format=raw,id=hd0 \
    -S -s
在另一个终端启动 gdb:
gdb-multiarch vmlinux
连接、下断点、查看断点,继续运行:

查看汇编、查看寄存器值、单指令运行:

查看帧栈信息:

layout asm(使用 Ctrl+XA 退出

思考题

编译 c 语言文件并反汇编

和系统一中的实验一样,使用 riscv64-linux-gnu-gcc 编译、-objdump 反汇编即可。源文件:

#include <stdio.h>

int main() {
    int a = 1, b = 2;
    printf("%d\n", a + b);
    return 0;
}
先静态编译(方便运行),然后动态编译并使用 objdump 反汇编:

调试 Linux

查看汇编、在 0x80000000 下断点、查看断点、在 0x80200000 下断点、取消 0x80000000 处的断点、继续运行:

单步运行、退出:

Makefile 相关

  1. 观察可用的 target,应该使用 make ? 来清除 Linux 的构建产物?

应该使用 make clean 来清除构建产物

  1. 默认情况下,内核编译显示的是简略信息(例如:CC init/main.o,应该使用 make ? 来显示 Linux 详细的编译过程呢?

make help 可以看到:

  make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build
  make V=2   [targets] 2 => give reason for rebuild of target
所以应该使用 make V=1
最后更新: 2022年11月29日 15:52:39
创建日期: 2022年11月29日 15:52:39
回到页面顶部