通过qemu调试centos7内核

Posted rayylee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过qemu调试centos7内核相关的知识,希望对你有一定的参考价值。

1.安装依赖

sed -e 's|^mirrorlist=|#mirrorlist=|g' \\
        -e 's|^#baseurl=http://mirror.centos.org|baseurl=https://mirrors.tuna.tsinghua.edu.cn|g' \\
        -i.bak \\
        /etc/yum.repos.d/CentOS-*.repo
yum install -y vim wget lrzsz
yum install -y gcc bc gcc-c++ ncurses ncurses-devel cmake elfutils-libelf-devel openssl-devel libgcrypt-devel glibc-static
yum install -y qemu-kvm gdb net-tools texinfo

systemctl stop firewalld
systemctl mask firewalld
setenforce 0
sed ‐i '/^SELINUX/s/=.*/=disabled/' /etc/selinux/config

2.下载内核版本解压并进入解压目录

wget https://vault.centos.org/7.9.2009/os/Source/SPackages/kernel-3.10.0-1160.el7.src.rpm

3.清理内核源目录

make mrproper

4.使用make menuconfig菜单来订制内核功能

make menuconfig
(
  配置ext4、virtio为 Y
  修改Makefile: -O2改为-O1; 删掉-Werror 
)

5.编译内核

make vmlinux -j 4
make bzImage

6. 制作initramfs

下载busybox

wget https://busybox.net/downloads/busybox-1.28.0.tar.bz2
cd busybox-1.28.0

配置编译选项busybox,开启Build static binary (no shared libs)选项

make menuconfig
(
Settings  ---> 
  --- Build Options
  [*] Build static binary (no shared libs)
)

编译busybox

make -j 4
make install // 编译安装文件在_install目录下

制作initramfs

mkdir initramfs
cd initramfs
cp ../_install/* -rf ./

mkdir dev,proc,sys

cp -a /dev/null,console,tty,tty1,tty2,tty3,tty4 dev/

rm linuxrc

vim init 
(
#!/bin/busybox sh
mount –t proc none /proc
mount –t sysfs none /sys
exec /sbin/init
)

chmod a+x init
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz

7. 通过qemu-kvm调试内核

/usr/libexec/qemu-kvm -kernel arch/x86/boot/bzImage -initrd initramfs.cpio.gz -s -S -append nokaslr -vnc :0

-kernel bzImage:指定内核路径
-initrd file:指定initramdisk路径
-s:-gdb tcp::1234的缩写, 开启一个gdbserver, 可以通过TCP端口1234连接
-S: 启动后立即暂停
-append nokaslr: 指定内核参数nokaslr, 禁止内核地址随机化, 否则gdb打断点找不到地址
-vnc :0: 开启vnc监听0端口

PS:
--monitor stdio 开启qmp交互

打开另一个终端

gdb vmlinux 
或者
gdb vmlinux --tui
(gdb) target remote:1234
Remote debugging using :1234
0x0000000000000000 in irq_stack_union ()
(gdb) hb start_kernel      // 设置硬件断点
Hardware assisted breakpoint 1 at 0xffffffff81d9ae44: file init/main.c, line 489.
(gdb) info b
Num     Type           Disp Enb Address            What
1       hw breakpoint  keep y   0xffffffff81d9ae44 in start_kernel at init/main.c:489
  breakpoint already hit 1 time
(gdb) c
Continuing.

Breakpoint 1, start_kernel () at init/main.c:489
489 

小技巧: gdb可以直接添加command
gdb vmlinux -ex="target remote:1234" -ex="hb start_kernel"

8. 遇到的问题

8.1 gdb vmlinux会出现 “Remote ‘g’ packet reply is too long”错误

Remote 'g' packet reply is too long: 0000000000000000d981ffffffff00000004000000000000001006000000000000040000000000000010060000000000903fc081ffffffff883fc081ffffffff0000000000000000130000000000000000000000000000000cc5130300000000ffffffff00000000200000000000000020a1d981ffffffff8e0000000000000044aed981ffffffff8200000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000

解决办法: 修改gdb源码, 重新编译

wget ftp://sourceware.org/pub/gdb/releases/gdb-7.6.tar.gz
tar -xvf gdb-7.6.tar.gz
cd gdb-7.6

注释掉:

if (buf_len > 2 * rsa->sizeof_g_packet)
    error (_(“Remote ‘g’ packet reply is too long: %s”), 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;
    

重新编译

mkdir -p /opt/gdb_7_6
./configure --prefix=/opt/gdb_7_6
make && make install
echo "PATH=\\$PATH:/opt/gdb_7_6/bin" >> /root/.bashrc

参考

以上是关于通过qemu调试centos7内核的主要内容,如果未能解决你的问题,请参考以下文章

使用 GDB + Qemu 调试 Linux 内核

调试Linux内核环境MenuOS系统

使用QEMU调试Linux内核代码

利用QEMU+GDB搭建Linux内核调试环境

开启内核地址随机化KASLR后, qemu 调试 kernel 不能设置断点

qemu+gdb调试内核出现remote ‘g’ packet reply is too long