使用GDB+QEMU调试Linux内核环境搭建


        一直想搭建一个debug kernel的环境,这样的话就可以对kernel启动的各个部分,运行过程中的特定部分进行定位,跟踪,调试,尤其是启动阶段。如果没有debug kernel的环境,那么我们只有使用其他方式来进行调试,例如printk。当然还有kgdb,不过此次不讨论此方式。
        下面我们来进行详细的环境搭建。

1 busybox软件

1.1 busybox下载

        可以从busybox官网地址下载最新版本,或者直接使用wget下载我使用的版本
        [root@localhost ~]# wget https://www.busybox.net/downloads/busybox-1.29.0.tar.bz2
        命令执行效果如下:
在这里插入图片描述

1.2 busybox编译安装

        在编译busybox之前,我们需要对其进行设置,如下所示
首先对压缩包进行解压,之后执行make menuconfig,如下

[root@localhost temp]# tar jxvf busybox-1.29.0.tar.bz2
............
[root@localhost busybox-1.29.0]# make menuconfig

在这里插入图片描述

在这里插入图片描述
        之后选择Exit退出,到这里我们就可以编译busybox了,执行下面的命令

[root@localhost busybox-1.29.0]# make -j 4
..............
[root@localhost busybox-1.29.0]# make install
  ./_install//bin/arch -> busybox
  ./_install//bin/ash -> busybox
  ./_install//bin/base64 -> busybox

  ....................
  ....................

  ./_install//usr/sbin/ubirsvol -> ../../bin/busybox
  ./_install//usr/sbin/ubiupdatevol -> ../../bin/busybox
  ./_install//usr/sbin/udhcpd -> ../../bin/busybox


--------------------------------------------------
You will probably need to make your busybox binary
setuid root to ensure all configured applets will
work properly.

--------------------------------------------------

[root@localhost busybox-1.29.0]# ls -l _install/
total 8
drwxr-xr-x 2 root root 4096 Jan 26 20:02 bin
lrwxrwxrwx 1 root root   11 Jan 26 20:02 linuxrc -> bin/busybox
drwxr-xr-x 2 root root 4096 Jan 26 20:02 sbin
drwxr-xr-x 4 root root   27 Jan 26 20:02 usr

 

2 构建initramfs根文件系统

        创建initramfs,其中包含BusyBox可执行程序、必要的设备文件、启动脚本init。这里没有内核模块,如果需要调试内核模块,可将需要的内核模块包含进来。init脚本只挂载了虚拟文件系统procfs和sysfs,没有挂载磁盘根文件系统,所有调试操作都在内存中进行,不会落磁盘。

[root@localhost temp]# ls
busybox-1.29.0  busybox-1.29.0.tar.bz2
[root@localhost temp]# mkdir initramfs
[root@localhost temp]# cd initramfs
[root@localhost initramfs]# cp ../busybox-1.29.0/_install/* -rf ./
[root@localhost initramfs]# mkdir dev proc sys
[root@localhost initramfs]# sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/
[root@localhost initramfs]# rm -f linuxrc
[root@localhost initramfs]# vim init
[root@localhost initramfs]# chmod a+x init
[root@localhost initramfs]# ls
bin  dev  init  proc  sbin  sys  usr

        其中init的内容如下

#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys

exec /sbin/init

        打包initramfs:

[root@localhost initramfs]# find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
.
./bin
./bin/busybox
./bin/arch
............
............
./dev/tty3
./dev/tty4
./proc
./sys
./init
5285 blocks

[root@localhost initramfs]# ls ../
busybox-1.29.0  busybox-1.29.0.tar.bz2  initramfs  initramfs.cpio.gz

 

3 kernel代码下载及编译

3.1 kernel代码下载

        可以从kernel官网下载需要的kernel版本,我这里使用的是linux-4.14.95版本。执行下面的命令下载即可

[root@localhost temp]# wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.14.95.tar.gz

--2021-01-26 20:21:12--  https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.14.95.tar.gz
Resolving mirrors.edge.kernel.org (mirrors.edge.kernel.org)... 147.75.95.133, 2604:1380:3000:1500::1
Connecting to mirrors.edge.kernel.org (mirrors.edge.kernel.org)|147.75.95.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 156176622 (149M) [application/x-gzip]
Saving to: ‘linux-4.14.95.tar.gz’

100%[====================================================================================================================>] 156,176,622 12.2MB/s   in 16s

2021-01-26 20:21:29 (9.30 MB/s) - ‘linux-4.14.95.tar.gz’ saved [156176622/156176622]

3.2 kernel生成需要的.config文件

        之后就是tar包的解压,完成后进入目录执行make menuconfig,如下

[root@localhost temp]# tar -zxf linux-4.14.95.tar.gz
[root@localhost temp]# cd linux-4.14.95/
[root@localhost linux-4.14.95]# ls
arch   certs    CREDITS  Documentation  firmware  include  ipc     Kconfig  lib          Makefile  net     samples  security  tools  virt
block  COPYING  crypto   drivers        fs        init     Kbuild  kernel   MAINTAINERS  mm        README  scripts  sound     usr

[root@localhost linux-4.14.95]# make menuconfig

        我们需要选择开启两个选项:Compile the kernel with debug info 和 Provide GDB scripts for kernel debugging。
        Compile the kernel with debug info设置路径:在这里插入图片描述在这里插入图片描述

在这里插入图片描述

        Provide GDB scripts for kernel debugging设置路径:
在这里插入图片描述

在这里插入图片描述

3.3 编译kernel代码

[root@localhost linux-4.14.95]# make -j4
[root@localhost linux-4.14.95]# make modules
[root@localhost linux-4.14.95]# make modules_install
[root@localhost linux-4.14.95]# make install

4 调试

4.1QEMU程序的命令行

#!/bin/bash
KERNEL_MIRROR=kernel_source/linux-4.14.95/arch/x86_64/boot/bzImage
/usr/local/bin/qemu-system-x86_64  \
    -s \
    -smp 2 \
    -kernel  $KERNEL_MIRROR \
    -initrd initramfs.cpio.gz \
    -nographic \
    -append "console=ttyS0 nokaslr"

  • -s是-gdb tcp::1234缩写,监听1234端口,在GDB中可以通过target remote localhost:1234连接
  • -smp 设置多个CPU
  • -kernel指定编译好的调试版内核;
  • -initrd指定制作的initramfs;
  • -nographic取消图形输出窗口,使QEMU成简单的命令行程序;
  • -append "console=ttyS0"将输出重定向到console,将会显示在标准输出stdio。

4.2 启动gdb

        我们需要使用源码编译出来的vmlinux,此文件在kernel源代码的root目录,我们需要到此目录执行gdb vmlinux命令

[root@localhost kernel_source]# cd linux-4.14.95/
[root@localhost linux-4.14.95]# ls
arch        certs    crypto         firmware   include  Kbuild   lib          mm               Module.symvers  samples   sound       usr      vmlinux-gdb.py
block       COPYING  Documentation  fs         init     Kconfig  MAINTAINERS  modules.builtin  net             scripts   System.map  virt     vmlinux.o
built-in.o  CREDITS  drivers        gdb.debug  ipc      kernel   Makefile     modules.order    README          security  tools       vmlinux

[root@localhost linux-4.14.95]# gdb vmlinux

 
        启动gdb后可以使用下面的命令来连接之前的qemu vm,成功后执行bt,如下

(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0xffffffff81734122 in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:57
57              asm volatile("sti; hlt": : :"memory");
(gdb) bt
#0  0xffffffff81734122 in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:57
#1  0xffffffff81733df8 in arch_safe_halt () at ./arch/x86/include/asm/paravirt.h:94
#2  default_idle () at arch/x86/kernel/process.c:564
#3  0xffffffff810ce286 in cpuidle_idle_call () at kernel/sched/idle.c:156
#4  do_idle () at kernel/sched/idle.c:246
#5  0xffffffff810ce4ef in cpu_startup_entry (state=CPUHP_ONLINE) at kernel/sched/idle.c:351
#6  0xffffffff81726d56 in rest_init () at init/main.c:435
#7  0xffffffff8252711b in start_kernel () at init/main.c:710
#8  0xffffffff810000d5 in secondary_startup_64 () at arch/x86/kernel/head_64.S:240
#9  0x0000000000000000 in ?? ()
(gdb) b do_IRQ
Breakpoint 1 at 0xffffffff81802620: file arch/x86/kernel/irq.c, line 217.
(gdb) c
Continuing.

Breakpoint 1, do_IRQ (regs=0xffffffff82003de8 <init_thread_union+15848>) at arch/x86/kernel/irq.c:217
217     {
(gdb) bt
#0  do_IRQ (regs=0xffffffff82003de8 <init_thread_union+15848>) at arch/x86/kernel/irq.c:217
#1  0xffffffff81800947 in common_interrupt () at arch/x86/entry/entry_64.S:571
#2  0xffffffff82003de8 in init_thread_union ()
#3  0x0000000000000000 in ?? ()

        至此环境搭建完毕。

参考文档

1 使用QEMU和GDB调试Linux内核
2 Linux内核调试 之 qemu+gdb
3 2020-02-27-Linux内核0-使用QEMU和GDB调试Linux内核

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: gdb是一个强大的调试工具,可以用于调试Linux内核使用gdb调试Linux内核需要以下步骤: 1. 编译内核时添加调试信息 在编译内核时需要添加调试信息,可以通过在Makefile中添加以下选项来实现: CONFIG_DEBUG_INFO=y CONFIG_DEBUG_KERNEL=y 2. 启动内核调试 在启动内核时需要添加调试选项,可以通过在grub或者lilo中添加以下选项来实现: debug debug earlyprintk=serial,ttyS0,115200 3. 连接gdb 使用gdb连接内核需要使用kgdb插件,可以通过以下命令加载kgdb插件: modprobe kgdb 然后使用以下命令连接gdbgdb vmlinux (gdb) target remote /dev/ttyS0 4. 使用gdb调试 连接成功后,可以使用gdb进行调试,例如: (gdb) b start_kernel (gdb) c 这将在内核启动时设置断点,并继续执行内核。当内核执行到断点时,gdb将停止执行并等待命令。 以上是使用gdb调试Linux内核的基本步骤,具体调试方法和命令可以参考gdb文档和Linux内核调试文档。 ### 回答2: gdb是一款功能强大的调试器,在日常的编程开发中得到了广泛应用。然而,gdb调试Linux内核时与调试用户态应用程序时有所不同。调试内核需要使用gdb的特殊功能来处理调试内核的问题。在下面的几个方面中,我将解释如何使用gdb调试Linux内核。 1. 准备gdb环境 首先需要将gdb环境设置为可以使用内核符号。在编译内核时,需要在Makefile中添加CONFIG_DEBUG_INFO和CONFIG_DEBUG_KERNEL选项,以支持调试信息。此外,还需要安装所需的内核符号,然后通过"sudo sysctl -w kernel.yama.ptrace_scope=0"以解决防止调试器附加的安全机制问题。 2. 加载内核映像 通过gdb来加载内核映像。使用gdb命令"file vmlinux"来加载内核映像,其中vmlinux是含有调试符号的内核镜像文件。 3. 内核断点调试 可以使用gdb设置内核断点,以调试内核时确定内核程序执行过程中的问题。使用gdb命令"b <function>"设置函数断点,而使用"b * <address>"设置指定地址的断点。 4. 调试内核panic 当内核执行时发生错误时,系统会进入panic状态。如果需要调试内核panic,可以使用gdb命令"handle SIGTRAP noprint pass"来设置中断处理。使用"monitor halt"或直接ctrl+c可以停止内核,查看是什么出问题了,并且使用"cont"命令让内核继续运行。 5. 查看内核堆栈 可以使用gdb命令"bt"来查看内核的堆栈,以确定调试内核时的问题。在通过gdb调试内核处理内核问题时,内核堆栈非常有用。 总的来说,使用gdb调试Linux内核需要更多的操作方式和技巧,但是如果熟练掌握gdb的某些功能和命令,并且了解内核基本结构和运行机制,就可以高效地调试内核出现的问题。 ### 回答3: GDB(GNU调试器)是一个强大的调试工具,也可以用来调试Linux内核。但是,与调试应用程序或用户空间程序相比,内核调试可能会更加复杂。下面是关于如何使用GDB调试Linux内核的一些指南和步骤。 1.编译内核 为了调试内核,首先需要编译内核并安装它。在编译内核时,需要启用符号表。使用如下命令: $ make menuconfig 在Kernel hacking中设置Debug kernel,这将启用符号表的编译。然后使用命令“make”编译内核并安装它。 2.配置调试环境内核启动时,启用调试合适的调试器非常重要。例如,可以使用串线调试器而不是控制台输出,因为调试信息可能无法立即打印到控制台。可以通过UART控制台或JTAG调试器进行调试,这通常比控制台输出更可靠。 3.使用GDB连接到内核 使用GDB的第一步是启动GDB,同时指定内核映像文件作为第一个参数。例如,如果内核映像文件为”vmlinuz”,可以使用如下命令连接GDB内核: $ gdb vmlinuz 然后,需要设置GDB的默认连接地址: add-symbol-file /path/to/kernel/vmlinux 0xADDRESS 这里的ADDRESS 应该是编译内核时已知的地址。可以在内核映像文件的/System.map文件中找到地址信息。 4.使用GDB调试 在连接GDB内核后,可以使用GDB来单步执行内核代码或设置断点。可以使用GDB的“step”命令来进入下一个函数调用,并使用“next”命令来执行下一行代码。还可以使用“break”命令设置断点,以捕获特定的行动或事件。 也可以在调试内核使用一些GDB调试命令,例如:“watch”命令用于设置监视点,以监视变量的值,而不必停止调试器。可以使用“info” 命令,以获取关于调试目标状态的信息。 总之,调试Linux内核需要仔细的计划和准备。在内核源代码中随时插入代码并编译并不是一个高效的方法。使用GDB可以更轻松地捕获和解决内核的问题。通过使用GDB,可以提高软件开发的效率,并确保Linux内核的稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值