zoukankan      html  css  js  c++  java
  • GDB+QEMU调试内核模块(实践篇)

    调试内核模块的方法有很多。最常用的,可能也是上手难度最低的就是使用prinfk打印出相关的调试信息,但是总给人的感觉不够geeek,所以这里描述一种能够使用gdb+qemu来调试内核的方法。

    启动虚拟机

    /data/bin/qemu-system-x86_64 -m 6144 -M accel=kvm -cpu host -smp 4 -nographic 
    -kernel /root/code/linux-4.18.2/arch/x86/boot/bzImage 
    -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x6,drive=drive-virtio-disk1,id=virtio-disk0,disable-modern=off,disable-legacy=on 
    -drive format=raw,if=none,id=drive-virtio-disk1,cache=directsync,file=/data/rootfs.img,aio=native 
    -netdev tap,id=tap0,ifname=virbr0-nic,vhost=no,script=no 
    -device virtio-net-pci,netdev=tap0 
    -append "root=/dev/vda rw console=ttyS0 nokaslr" -enable-kvm -S -gdb tcp::8889
    

    当进入到虚拟机之后,启动相关的网卡,可以方便的向虚拟机中拷贝相关需要的文件,方便调试。

    内核模块实例

    使用以下链接 中内核模块,作为调试示例。
    如果调试的目标虚拟机是Ubuntu16.04,使用如下分支:

    git clone -b build-for-ubuntu16046 https://github.com/caisan/simplefs
    

    如果是centos7 作为调试的目标虚拟机主机,使用如下分支:

    git clone -b build-for-centos7 https://github.com/caisan/simplefs
    

    为了能在Guest中编译simplefs文件系统,需要在Guest中编译下Linux-kernel 4.18.2,但是不是完全编译,只需要编译所需要的kernel headers,module依赖。
    进入到Guest中:

    cd linux-4.18.2
    make menuconfig
    make modules - j4
    make modules_install -j4
    

    上述编译结束后,到Guest 的路径下:/lib/modules/4.18.2下确认下,不出意外用ls -al可以看到buildsource都链接到/root/linux-4.18.2,如下:

    然后再进入到simplefs, 执行编译此simplefs模块:

    make
    

    随后加载该simplefs.ko模块。注意如果是在centos7上加载此模块,需要先加载jbd2,即就是:modprobe jbd2
    调试的虚拟机我选的Ubuntu 16.04.6,内核版本是
    如下:

     insmod ./simplefs.ko
    
    cat /sys/module/simplefs/sections/.text
    0xffffffffc098f000
    
    cat /sys/module/simplefs/sections/.data
    0xffffffffc0992000
    
    cat /sys/module/simplefs/sections/.bss
    0xffffffffc0992580
    

    以上通过.text, .data, .bss定位到了模块的加载地址,可以使用这三个信息开始我们的调试。

    在Host上调试内核。

    以上将基于QEMU+kvm中的Guest安装好了,现在在Host上进行调试工作。这里说在Host上其实不太准确,调试的目标是Guest kernel上的模块,Host上执行相当于是GDB远程调试,whatever,意会这个意思就可以了。但是请务必将Host上调试的kernel代码和Guest上的版本保持一致。
    以我为例,我Host上kernel代码路径是在/root/code/linux-4.18.2
    因此可以在~/.gdbinit 中添加如下内容:

    add-auto-load-safe-path /root/code/linux-4.18.2/scripts/gdb/vmlinux-gdb.py
    target remote:8889
    

    (这里要强调的是,Host上的kernel同样是经过编译过后的)
    进入到已经编译好的kernel源码目录:

    gdb ./vmlinux
    

    此时进入到了gdb中,由于我们调试的simplefs.ko模块,因此还要在gdb中加载这个模块,注意:这里的加载和使用insmod加载有区别,两者都要做。
    将Guest中网络设置好之后,可以将在Guest中编译好的simplefs.ko模块拷贝出来,下面.text``.data``.bss相关的地址和在Guest中保持一致。

    (gdb) add-symbol-file ./simplefs.ko 0xffffffffc098f000 -s .data 0xffffffffc0992000 -s .bss 0xffffffffc0992580
    

    加载好之后就可以调试了。

    触发调试。

    这里以调试mount的操作为例,在Guest中执行常规的挂载mount 操作,如下:

    dd bs=4096 count=100 if=/dev/zero of=image
    ./mkfs-simplefs image
    mount -o loop -t simplefs image /root/simplefs/mount/
    

    或者采用以下方式设置挂载:

    fallocate -l 1G disk.img
    losetup -f /root/disk.img
    

    取消挂载:
    losetup -D

    然后在Host的gdb中设置断点:

    (gdb) b simplefs_fill_super
    (gdb) c
    

    等待触发到breakpoint。调试命令和gdb使用相同。

  • 相关阅读:
    作用域和内存问题
    Javascript事件
    JavaScript学习总结(三)
    Javascript学习总结(二)
    JavaScript学习总结(一)
    vue开发搭建 1、 npm安装+vue脚手架安装 2、cnpm安装
    20181008
    RabbitMQ在.NetCore中的基础应用
    微软CRM 基于 ADFS自定义多重身份验证
    如何在ASP.NET Core中上传超大文件
  • 原文地址:https://www.cnblogs.com/powerrailgun/p/12161295.html
Copyright © 2011-2022 走看看