QEMU+gdb调试Linux内核全过程

1、编译源码(Linux kernel 4.6.2)

make menuconfig

执行make menuconfig时报错缺少库文件

需要安装依赖库

sudo apt-get install aptitude
sudo aptitude install libncurses5-dev
sudo apt-get install libssl-dev

首先编译内核,编译内核时注意要选两个选项。(注意:除此之外kernel hacking选项下其他的选项都不要选,否则会出现断点无法拦截的情况。这个说法有待验证)

kernel hacking –> kernel debugging –> compile the kernel with debug info

kernel hacking –> compile the kernel with frame pointers

make bzImage -j4

在编译过程中会出现如下的warning,最好解决掉
QEMU+gdb调试Linux内核全过程_第1张图片
解决方法:
进入make menuconfig的图形界面,选择kernel hacking,将frame size由1024改成2048即可。
QEMU+gdb调试Linux内核全过程_第2张图片
QEMU+gdb调试Linux内核全过程_第3张图片
QEMU+gdb调试Linux内核全过程_第4张图片
这样就生成了bzImagevmlinux

bzImage 位于Linux-4.6.2/arch/x86/boot/bzImage

vmlinux 位于linux-4.6.2/vmlinux

2、编译QEMU(使用最新版2.12)

2.1 下载源码

https://download.qemu.org/

下载2.12.0版本;

2.2 编译前的工作

编译之前需要安装一些库文件,否则会卡在下面的页面不动;
这里写图片描述

因此需要安装SDL图形库:(注意是2.0版本的SDL)

sudo apt-get install  libsdl2-2.0
sudo apt-get install  libsdl2-dev

运行下列代码:

./configure --enable-debug  --target-list=x86_64-softmmu

运行上述命令,会出现不存在pixman错误;
这里写图片描述

运行如下命令解决:

sudo apt-get install libpixman-1-dev

紧接着,执行:

sudo make &&  make install

又会遇到如下问题:
缺少flex和bison
QEMU+gdb调试Linux内核全过程_第5张图片
运行如下命令:

sudo apt-get install flex bison

再运行sudo make install即可。

3、编译gdb(更换新的gdb)

  • 下载7.8版本
    http://ftp.gnu.org/gnu/gdb/

  • 修改源码
    参考这篇博客

  • 开始编译:

    ./configure --prefix=~/gdb
    make 
    make install

    运行gdb需要进入~/gdb/bin目录下,执行./gdb;

4、busybox建立最小文件系统

4.1 动态编译的方法(不推荐)

动态编译

4.2 另一种静态库编译方法(推荐):

静态编译

具体的流程如下:

4.2.1 安装busybox(1.25.0版本)

  • https://busybox.net/ 下载并解压源码

  • 编译busybox源码

    cd busybox-1.25.0
    
    make defconfig
    
    make menuconfig

    在menuconfig中修改配置,使用静态编译busybox,否则在程序运行期间需要对相应的库进行动态加载,那么在根文件系统中则需要提供其所需的共享库。

    进入menuconfig图形界面,选择

           -> Busybox Settings 
    
          -> Build Options  
    
            [*] Build BusyBox as a static binary (no shared libs)         
    
    make -j4

    make 期间会遇到许多的warning,不用管它,对安装影响不大。

    sudo make install

    此时可以在busybox-1.25.0/中看到生成的_install目录。通过下面的命令可以验证busybox是否安装正确:

    ./busybox ls
  • 生成initrd

    首先将上一步生成的_install文件夹复制到其他位置

     cd ..
    
     mkdir ramdisk
    
     cd ramdisk
    
     cp -r ../busy-1.25.0/_install/*  .

    设置初始化进程init(建立一个软链接,一定不能直接复制过去)

    cd ramdisk
    
    ln -s bin/busybox init

    设置开机启动程序

    首先,我们需要先设定一些程序运行所需要的文件夹

    mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin},dev}

    init程序首先会访问etc/inittab文件,因此,我们需要编写inittab,指定开机需要启动的所有程序

    cd etc
    vim inittab

    inittab文件的内容如下所示:

    ::sysinit:/etc/init.d/rcS   
    ::askfirst:-/bin/sh    
    ::restart:/sbin/init
    ::ctrlaltdel:/sbin/reboot
    ::shutdown:/bin/umount -a -r
    ::shutdown:/sbin/swapoff -a

    赋予可执行权限

    chmod +x inittab

    编写系统初始化命令
    从inittab文件中可以看出,首先执行的是/etc/init.d/rcS脚本,因此,我们生成初始化脚本

    mkdir init.d
    cd init.d
    vim rcS

    rcS文件的内容如下所示:

    
    #!/bin/sh
    
    mount proc
    mount -o remount,rw /
    mount -a    
    clear                               
    echo "My Tiny Linux Start :D ......"

    赋予可执行权限

    chmod +x rcS

    在rcS脚本中,mount -a 是自动挂载 /etc/fstab 里面的东西,可以理解为挂在文件系统,因此我们还需要编写 fstab文件来设置我们的文件系统。

    cd ramdisk/etc/
    
    vim fstab

    fstab文件内容如下:

    
    # /etc/fstab
    
    
    proc            /proc        proc    defaults          0       0
    
    sysfs           /sys         sysfs   defaults          0       0
    
    devtmpfs        /dev         devtmpfs  defaults          0       0

    至此,我们已经完成了RAM Disk中相关文件的配置,可以压缩生成文件镜像了。

    cd ramdisk
    
    find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.img

    最后生成的initramfs.img就是我们的根文件系统。

4.2.2 测试根文件系统

下面就可以测试根文件系统了。

 qemu-system-x86_64 -kernel /usr/src/Linux-4.6.2/arch/x86/boot/bzImage -initrd ../initramfs.img

这时qemu上会显示出内核打印的各种信息,最终显示:

My Tiny Linux Start :D ......
Please press Enter to activate this console.

按Enter键后,就可以进入到文件系统中,运行命令

ls /dev

如果能够成功显示目录下所有文件,则文件系统挂载成功。

5. QEMU+GDB调试内核

在之前的四个步骤中,已经准备好了全部的工具,下面就可以使用QEMU+GDB进行内核调试了。
运行如下命令:

qemu-system-x86_64 -kernel /usr/src/linux-4.6.2/arch/x86/boot/bzImage -initrd ../initramfs.img -smp 2  -S -s

先使用命令启动qemu。
  qemu-system-x86_64的参数比较多,这里简单说下:
  -kernel 是指定一个大内核文件,当仁不让的是bzImage。
  -initrd 是指定一个 initrd.img文件,这个文件就是我们使用busybox生成的initramfs.img。
  -smp 可以从名字猜想,它是给qemu指定几个处理器,或者是几个线程<嗯,大概意思就thread吧>。
  -gdb则是启动qemu的内嵌gdbserver,监听的是本地tcp端口1234—如果这样写: -gdb tcp:192.168.1.100:1234 ,似乎也是没问题的。
  -S 就是挂起gdbserver,让gdb remote connect it。
  -s 默认使用1234端口进行远程调试,和-gdb tcp::1234类似。
  -m 2048 指定内存大小为2048M

具体图片如下:
这里写图片描述
运行上个命令之后,弹出下面这个页面:
QEMU+gdb调试Linux内核全过程_第6张图片

此时,开启另一个terminal,运行如下命令:

gdb /usr/src/linux-4.6.2/vmlinux (修改成自己的vmlinux路径)

target remote:1234 (默认端口是1234,进行远程连接)

b start_kernel (设置断点)

c (continue 运行到断点处)

具体如下图:
QEMU+gdb调试Linux内核全过程_第7张图片

可以看到gdb运行start_kernel断点处停下来了,接下来就可以使用gdb的基本命令进行单步调试了。

如果遇到b start_kernel停不下来,可以使用下面的命令:
(普通的break断点无法使得gdb在断点处运行,这是可能是一个gdb的bug())

hb start_kernel  //设置硬件断点

如果需要查看启动过程中的信息,则需要将qemu监视器中的内容重定向到terminal中。

使用如下命令 -nographic 配合-append”console=ttyS0”

这里写图片描述

最后总结

安装QEMU+GDB可以说是坎坷不断,耗费了好几天才最后弄完。
期间遇到过许多错误,这在其他教程中是没有出现的,所以只能自己一点一点的解决。

安装过程中遇到的各种warning和error都不能放过,也许就是因为这些错误导致安装失败。即使看起来安装成功,这些错误未解决仍然可能造成许多错误。

比如,编译内核源码时,遇到需要的warning,当时我没有留意,结果在运行QEMU时就失败了。所以我只能一个一个解决每一个warning,直到完全成功。
另一方面,如果内核编译时总是有错误,可以选择更高版本的内核。有些低版本内核年久失修,而且需要使用特定版本的gcc编译。而你的机器gcc版本过高会造成许多的warning或者error。


另一篇比较全面的教程:
qemu搭建内核开发环境

你可能感兴趣的:(linux内核,内存分配研究)