Linux Kernel調試環境搭建(正式版)


簡單記錄下可行的kernel調試工具和步驟。
(本文是從本人的github上遷移過來的)
調試使用4.18版本的kernel, 用到的工具是qemu+gdb

1. 調試環境說明

Host主機是centos7.6的環境

2. 編譯需要調試的內核(4.18 version)

首先下載內核tar包:
wget https://mirrors.aliyun.com/linux-kernel/v4.x/linux-4.18.2.tar.gz
可能需要安裝:
yum install flex.x86_64 bison.x86_64 elfutils-libelf-devel -y
可能需要安裝的依賴:

yum groupinstall "Development Tools" -y && yum install ncurses-devel -y && yum install hmaccalc zlib-devel binutils-devel elfutils-libelf-devel -y
yum install openssl-devel -y
yum install bc -y 
yum install glibc-static -y
yum install openssl -y

解壓后開始編譯:

make defconfig
make kvmconfig
make -j4  

參考:https://www.cnblogs.com/powerrailgun/category/1554674.html
以上步驟結束后會產生用於調試的內核bzImage鏡像,位於arch/x86/boot/bzImage
更多可選的:

 config          - Update current config utilising a line-oriented program'
        @echo  '  nconfig         - Update current config utilising a ncurses menu based program'
        @echo  '  menuconfig      - Update current config utilising a menu based program'
        @echo  '  xconfig         - Update current config utilising a Qt based front-end'
        @echo  '  gconfig         - Update current config utilising a GTK+ based front-end'
        @echo  '  oldconfig       - Update current config utilising a provided .config as base'
        @echo  '  localmodconfig  - Update current config disabling modules not loaded'
        @echo  '  localyesconfig  - Update current config converting local mods to core'
        @echo  '  defconfig       - New config with default from ARCH supplied defconfig'
        @echo  '  savedefconfig   - Save current config as ./defconfig (minimal config)'
        @echo  '  allnoconfig     - New config where all options are answered with no'
        @echo  '  allyesconfig    - New config where all options are accepted with yes'
        @echo  '  allmodconfig    - New config selecting modules when possible'
        @echo  '  alldefconfig    - New config with all symbols set to default'
        @echo  '  randconfig      - New config with random answer to all options'
        @echo  '  listnewconfig   - List new options'
        @echo  '  olddefconfig    - Same as oldconfig but sets new symbols to their'
        @echo  '                    default value without prompting'
        @echo  '  kvmconfig       - Enable additional options for kvm guest kernel support'
        @echo  '  xenconfig       - Enable additional options for xen dom0 and guest kernel support'
        @echo  '  tinyconfig      - Configure the tiniest possible kernel'
        @echo  '  testconfig      - Run Kconfig unit tests (requires python3 and pytest)'

3. 編譯較新版本的qemu

下載qemu-4.1.1.tar.gz版本
https://download.qemu.org/
解壓之。
具體需要的依賴包視實際情況而定,參考:

yum install pixman-devel -y

最終安裝后的版本:

pixman-devel-0.34.0-1.el7.x86_64
pixman-0.34.0-1.el7.x86_64

可能還會安裝諸如:bison和flex這樣的工具。
為了不和以后系統安裝的qemu發生沖突,這里將qemu安裝到/data目錄下:

./configure --enable-rbd --enable-debug --enable-trace-backends=simple --enable-debug-stack-usage --enable-kvm --enable-vnc --prefix=/data --target-list=x86_64-softmmu

注意:
如果不加上--target-list=x86_64-softmmu選項,那么會編譯所有平台的模擬器,即就是不限於x86_64
--enable-rbd可能需要安裝librdb庫。--enable-trace-backends=simple該選項可能會影響性能,故生產環境中應關閉該選項,調試環境中推薦開啟。

接着,開始編譯和安裝:

make -j4
make install

4. 編譯較新版本的gdb

download gdb source code:
wget https://mirrors.ustc.edu.cn/gnu/gdb/gdb-8.2.tar.gz
wget https://github.com/libexpat/libexpat/releases/download/R_2_2_8/expat-2.2.8.tar.bz2

4.1 先編譯expat

解壓:expat-2.2.8.tar.bz2
然后開始執行編譯:

./configure --prefix=/data/expat-2.2.8
make -j4 && make install

4.2 開始編譯安裝gdb

and edit gdb/remote.c
remote_target::process_g_packet函數中的一部分內容修改成這個樣子,否則gdb調試的時候可能出錯:

  /* Further sanity checks, with knowledge of the architecture.  */
//  if (buf_len > 2 * rsa->sizeof_g_packet)
 //   error (_("Remote 'g' packet reply is too long (expected %ld bytes, got %d "
//           "bytes): %s"), rsa->sizeof_g_packet, buf_len / 2, rs->buf);
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[i].pnum == -1)
            continue;
        if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
            rsa->regs[i].in_g_packet = 0;
        else
            rsa->regs[i].in_g_packet = 1;
    }
}

進入到gdb-8.2的目錄下,編譯gdb:

./configure --prefix=/opt --with-expat --includedir=/data/expat-2.2.8/include/ --libdir=/data/expat-2.2.8/lib

還需要安裝一個包,否則在make install時會出現錯誤。
yum install texinfo -y
然后執行make:

make 
make install 

這里假設我的expat放置在/data/路徑下。

5. 制作rootfs

在第1步,已經將內核編譯好了,還需要一個rootfs,用於啟動完整的Linux系統。
參考以下腳本制作一個rootfs:
yum install debootstrap.noarch -y

rm -rf /data/ubuntu_1604
rm -rf /data/rootfs.img

/data/bin/qemu-img create /data/rootfs.img 5G
mkfs.ext4 /data/rootfs.img

mkdir /data/ubuntu_1604
mount -o loop /data/rootfs.img /data/ubuntu_1604
debootstrap --arch=amd64 xenial /data/ubuntu_1604 https://mirrors.aliyun.com/ubuntu/

#auto login
mkdir -p /data/ubuntu_1604/etc/systemd/system/serial-getty@ttyS0.service.d
cat << EOF > /data/ubuntu_1604/etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf
[Service]
ExecStart=
ExecStart=-/sbin/agetty --noissue --autologin root %I $TERM
Type=idle
EOF

umount /data/ubuntu_1604

經過以上步驟,制作好了一個rootfs,再結合第1步生成的內核bzImage,就可以在qemu中啟動了。
以上制作的rootfs是Ubuntu的,如果要制作基於CentOS的rootfs,參考鏈接:http://linuxcoming.com/blog/2019/07/04/build_ram_os_of_centos.html

6. 調試實例

參考以下腳本,啟動一個調試實例:

/data/qemu-4.1.0/x86_64-softmmu/qemu-system-x86_64 -kernel linux-4.8/arch/x86/boot/bzImage \
-drive file=./rootfs.img,if=virtio \
-netdev tap,id=tap0,ifname=virbr0-nic,vhost=on,script=no -m 2048 \
-device virtio-net-pci,netdev=tap0 \
-append "root=/dev/vda rw console=ttyS0 nokaslr" \
-nographic \
--enable-kvm -S -gdb tcp::8889

可能會用到的qemu參數:

-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x6,drive=drive-virtio-disk0,id=virtio-disk0 -drive file=fake.img,format=qcow2,if=none,id=drive-virtio-disk0,cache=writeback

### 或者直接使用以下命令行可以調試qemu+Linux kernel

/opt/bin/gdb -nh --args /data/bin/qemu-system-x86_64 -m 1024 -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-disk0,id=virtio-disk0 \
-drive format=raw,if=none,id=drive-virtio-disk0,cache=writeback,file=/data/rootfs.img \
-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" -S --enable-kvm -gdb tcp::8889

注意以上的磁盤那里不要再指定if=virtio,因此我們已經通過id指定了。重復指定會報錯。
另外,添加這樣的參數可以用於測試legacy和modern參數:-device disable-modern=on,disable-legacy=off
gdb加上-nh參數是不讓其使用~/.gdbinit中設置的命令。
參考:https://heiko-sieger.info/tuning-vm-disk-performance/
上面將qemu運行起來后,qemu會在初始階段停住等待gdb的調試命令。
下面,將使用gdb調試內核了。

# Attach gdb
gdb ./linux-4.18.2/vmlinux 
(gdb) target remote :8889

或者將上述初始化命令寫入到~/.gdbinit文件中,如下:

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

注意:在設置breakpoint的時候,對於QEMU模擬的VM,可以使用break,但對於KVM模擬的VM,需要使用hbreak。

7. QEMU trace的使用

假設在第3步啟用了--enable-trace-backends=simple這個選項來編譯qemu,那么可以嘗試使用下qemu的trace功能幫助調試。
以下兩個鏈接有助於使用qemu trace:
https://blog.csdn.net/scaleqiao/article/details/50787340
https://blog.csdn.net/weixin_34144450/article/details/91744086



參考鏈接:
https://www.anmolsarma.in/post/single-step-kernel/
https://www.binss.me/blog/how-to-debug-linux-kernel/


在docker 容器中運行:
創建容器:

docker run --rm -it --name build_upstream_qemu -d --cap-add NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --device=/dev/kvm:/dev/kvm --device=/dev/net/tun:/dev/net/tun -v /root/kernel:/root/kernel docker.io/centos:centos7 bash


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM