Linux内核调测之Qemu+Gdb

转载于 https://blog.csdn.net/jasonLee_lijiaqi/article/details/80967912

1、编译源码

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 【make -j4】

在编译过程中会出现如下的warning,最好解决掉

在这里插入图片描述
解决方法:
进入make menuconfig的图形界面,选择kernel hacking,将frame size由1024改成2048即可。
在这里插入图片描述

这样就生成了bzImage和vmlinux:
bzImage 位于Linux-4.6.2/arch/x86/boot/bzImage;
vmlinux 位于linux-4.6.2/vmlinux;

2、编译QEMU

2.1 下载源码
https://download.qemu.org/

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 ,运行如下命令:

sudo apt-get install flex bison

再运行

sudo make install

3、编译gdb

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

3.2 修改源码
https://blog.csdn.net/barry283049/article/details/42970739

修改代码【否则调试内核会出现remote ‘g’ packet reply is too long的问题】

cd gdb-7.8/gdb
vim remote.c

按照如图所示修改代码【针对7.8版本】:
在这里插入图片描述

代码如下:

if (buf_len > 2 * rsa->sizeof_g_packet) {  
      rsa->sizeof_g_packet = buf_len ;  
      for (i = 0; i < gdbarch_num_regs (gdbarch); i++)  
      {  
         if (rsa->regs->pnum == -1)  
         continue;  
  
         if (rsa->regs->offset >= rsa->sizeof_g_packet)  
         rsa->regs->in_g_packet = 0;  
         else  
         rsa->regs->in_g_packet = 1;  
      }  
}

3.3 开始编译:

mkdir _install
./configure --prefix=./_install
make
make install

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

4、busybox建立最小文件系统

4.1 动态编译的方法(不推荐)
动态编译 https://siweixiang.github.io/notes/2016_06_19_build_minimal_linux_hack_env_with_busybox_x86_64.html

4.2 另一种静态库编译方法(推荐):
静态编译 https://github.com/chyyuu/tiny_linux_ChildIsTalent

具体的流程如下:
4.2.1 安装busybox
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

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

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

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

cd ramdisk

ln -s bin/busybox init

4.3.3 设置开机启动程序

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

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.4 测试根文件系统
下面就可以测试根文件系统了。

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

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

My Tiny Linux Start ? …
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

运行上个命令之后,弹出下面这个页面:
在这里插入图片描述
此时,开启另一个terminal,运行如下命令:

gdb /usr/src/linux-4.6.2/vmlinux (修改成自己的vmlinux路径)
target remote:1234 (默认端口是1234,进行远程连接)
b start_kernel (设置断点)
c (continue 运行到断点处)

具体如下图:
在这里插入图片描述
可以看到gdb运行start_kernel断点处停下来了,接下来就可以使用gdb的基本命令进行单步调试了。

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

hb start_kernel //设置硬件断点

如果需要查看启动过程中的信息,则需要将qemu监视器中的内容重定向到terminal中。
使用如下命令 -nographic 配合-append”console=ttyS0”

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值