借助qemu使用gdb去跟踪和学习内核

      这是一篇《使用qemu搭建linux内核开发环境详细教程》的续篇。需要合起来看

      之前总结了一篇使用qemu搭建内核实验环境的文章,既然环境搭建起来了,那么就要用起来。跟踪内核代码,去实时看内核的走向,一直是一个不怎么容易的操作,要么缺乏硬件资源,要么缺乏软件环境,这里给出一种选择,使用qemu+gdb的方式,不依赖硬件,在我们自己的电脑上就可以完成这个过程。这里记录一下这个过程。

       这是一篇纯操作的文章,没有什么知识点,虽然回头看很简单,但是流程上的的东西,一步不对就无法进行下去,不过还好,折腾出来了,借助于前人的分享,我也分享出来,希望帮助到更多和我一样热爱内核的人。

以下所有的操作都是基于《使用qemu搭建linux内核开发环境详细教程》https://blog.csdn.net/weixin_38227420/article/details/88402738中的环境去操作,如果你按照自己的方式搭建了环境,只需要修改编译链和路径即可

我这里使用的linux-3.10.104,高版本的4.4以上内核也可以

  • 1.修改内核配置项,时内核带上debug信息

执行该操作,依次配置配置项
 

make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm menuconfig

    Kernel hacking  --->

                [*] Compile the kernel with debug info

  • 2.编译内核

make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm -j4
  • 3.使用qemu加载内核

qemu-system-arm -M vexpress-a9 -s -kernel ./qemu-image/zImage -m 512M -append "root=/dev/ram rdinit=sbin/init  console=ttyAMA0" -nographic

注意其中的-s。这个-s表示-gdb tcp::1234缩写,监听1234端口。使用了-s参数,待会我们就可以使用gdb去调试内核了

其中./qemu-image/zImage和qemu-image/rootfs.img需要根据你自己的环境中的路径来填写,如果路径不匹配会导致找不到这些镜像导致启动失败

  • 4.使用gdb连接内核

4.1重新开一个终端

4.2使用gdb加载

进入到之前编译的内核代码中vmlinux所在目录执行

arm-linux-gnueabihf-gdb vmlinux

这里有一点一定要注意,你要调试的内核是用什么编译链编的,这里的gdb就要用这个编译链的gdb,因为我要调试的内核是用arm-linux-gnueabihf-xxx编译链编的,所以这里使用arm-linux-gnueabihf-gdb去加载vmlinux。

(小插曲:因为我的电脑是centos,它自带gdb,所以我刚开始直接是gdb vmlinux,但是怎么也无法断点调试,折腾了很久,因为很多前人写的博客也是用的gdb,但我这里就是不行,一点进展也没有,非常郁闷,直接怀疑自己了。直到后面看到一篇文章说,“调试的时候需要选对编译链”才意识到,我用的centos自带的gdb是x-86的gdb和我的版本不一样。。。。)

执行后终端是这样:

可以看到Reading symbols from vmlinux...done.表示已经加载了符号表了

4.3gdb连接内核:

在gdb中输入target remote tcp:localhost:1234,表示gdb去连接1234端口

target remote tcp:localhost:1234

连接成功后有如下显示

  • 5.开始调试:

接下来的调试和在用户态使用gdb调试应用程序是一样的,使用的命令也是一样的,只是换成了调试内核

做两个简单的实验:

1.在kernel的启动过程中打2个断点,对start_kernel和kernel_restart这两个启动和重启必调的函数打断点

(gdb) b start_kernel
Breakpoint 1 at 0x80488790: file init/main.c, line 473.
(gdb) b kernel_restart
Breakpoint 2 at 0x80031d34: file kernel/sys.c, line 397.
(gdb) 

然后执行c:contimue,等待内核操作

然后在另一个跑kernel的终端执行命令reboot,

可以看到,此时内核重启了,但是此时停在了Requesting system reboot,并且内核终端此时无响应,这是因为已经进入gdb的断点了,看下gdb的所在的终端:

可以看到已经停在了kernel_restart这个函数里了,表示在执行关机操作,此时使用gdb的如下命令:l 和bt命令

和在用户态使用gdb一样,使用l和bt命令可以查看此时的代码段和此时的调用栈,非常方便。

这里我们继续让内核往下走,在gdb中敲c命令

此时发现进入了第二个断点start_kernel,表示已经到了重启的操作,进入了c入口,此时使用n命令继续走可以看到

可以看到单步的运行过程

此时在执行c命令。切换到内核的终端,此时跳过了所有的断点,内核完成重启了

  • 总结:

     这种方式的好处是轻量简单,只需一台电脑即可,不涉及反复的烧写和硬件支持,效率高啊,对于感兴趣的内核模块,在看代码的时候可以打个断点跟一下,实践一下。比如可以触发一个中断,跟踪下中断的执行流程,我想这比看再多书也要管用。

   不过也有局限,和真实的板上环境还是有区别,对于一些极度依赖具体硬件的驱动可能无法进行,但是这种方式比较适合学习和硬件不那么紧密的模块,例如内核的纯软件层面,可以用来做为一个学习内核的辅助手段。

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值