qemu+gdb调试内核

我们在内核调试的时候,会有很多方法,比如printk, ftrace, kprobe, ebpf和gdb等。比起其他的方法,gdb可以单步运行代码,实时获取变量信息等优势。但劣势也比较明显,比如效率较低,比较适合代码较少,操作简便,场景单一的情况。

编译内核

本实验采用x86的内核,需要增加打开CONFIG_BLK_DEV_RAM选项,并将CONFIG_BLK_DEV_RAM_SIZE设置为65535,以便于使用qemu启动,方法如下:

make menuconfig

进入Device drivers --> Block devices

选中RAM block device support

构建根文件系统

1)下载busybox

  • wget http://www.busybox.net/downloads/busybox-1.35.0.tar.bz2  --no-check-certificate
  • tar xvjf busybox-1.35.0.tar.bz2

2)编译busybox

  • make menuconfig
  • 在Settings中选中“Build static binary”

  • make

 3)制作rootfs

  • dd if=/dev/zero of=rootfs.img bs=1M count=20
  • mkfs.ext4 rootfs.img
  • mkdir fs
  • sudo mount -t ext4 -o loop rootfs.img ./fs
  • sudo make install CONFIG_PREFIX=./fs
  • cd fs/
  • sudo mkdir proc dev etc home mnt
  • sudo cp -r ../examples/bootfloppy/etc/* etc/
  • sudo mkdir /sys
  • 修改etc/fstab为如下内容:
proc        /proc   proc    defaults    0   0
tmpfs       /tmp    tmpfs   defaults    0   0
sysfs       /sys    sysfs   defaults    0   0
tmpfs       /dev    tmpfs   defaults    0   0
debugfs     /sys/kernel/debug   debugfs defaults    0   0

到此,我们得到了我们新制作的根文件系统rootfs.img

安装gdb工具

我使用的是优麒麟系统,所以键入命令“sudo apt-get install gdb gdb-multiarch”

使用qemu启动内核,我的qemu启动脚本为

#!/bin/bash
qemu-system-x86_64  \
      -cpu kvm64 \
      -smp 2 \
      -m 1024M \
      -kernel ./linux-objtrace-jeff-v15/arch/x86_64/boot/bzImage \
      -qmp unix:/tmp/mem/qemu/qmp,server,nowait \
      -gdb unix:/tmp/mem/qemu/gdb,server,nowait \
      -nographic \
      -append "root=/dev/ram0 rw rootfstype=ext4 console=ttyS0 init=./linuxrc nokaslr" \
      -initrd ./rootfs_x86_64.img

使用gdb调试内核

1)启动gdb

sudo gdb-multiarch --tui vmlinux (其中vmlinux为编译好的内核elf文件)

2) 连接内核

target remote /tmp/mem/qemu/gdb

3) 设置断点

b __kprobe_trace_func

本节我们使用一个比较典型的gdb场景,调试kprobe代码,因为kprobe本身属于ftrace的一部分,所以不能使用ftrace来调试kprobe,gdb比较合适。

4) continue (或直接运行c)

让内核继续运行起来。

5) 在内核中输入如下命令,进入断点

cd /sys/kernel/debug/tracing/
echo 1 > events/kprobes/p_vfs_open_0/enable
cat trace

6) 常用调试命令

单步命令:n

进入调用函数内部:s

查看当前函数参数:i args

查看局部变量:i locals

查看单独变量: p variable

查看结构中每一项的值: p *pointer

查看结构定义:ptype struct (ptype /o code还可以查看结构中每一项地址的offset)

查看指定区域的内存内容x/32 addr(读取addr后32个64bit数据)

本例中函数store_trace_args将字符串”trace”放到了entry中,我们查看了entry后面的内存内容,找到了字符串”trace”的ascii,即“74,72,61,63,65”。

查看调用栈:bt

反汇编函数:disas function_name

查看反汇编指令:x/3i $pc

单步调试汇编:ni

 

查看寄存器:info register rdi (i register rdi)

 

基本就是这些,虽然不像eclipse, visual studio那样可以使用鼠标操作,但熟练之后效率也不会低的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值