Linux内核调试工具

原文地址:http://blog.csdn.net/ariesjzj/article/details/8244333

一些Linux Kernel的分析调试工作,主要包换qemu,kprobes和trace等,以作备忘。

 

Qemu源码级调试Kernel

1. Qemu编译与安装

先安装libsdl的开发库

$ ./configure

$ make

# make install

Qemu-1.2.1试过能work,早先的版本编译启动时可能有问题。怕麻烦的可以直接apt-get install qemu。。。但这样装起来的qemu有可能断点不work。

 

2. Linux kernel编译

如果要在64位机上编译32位内核,要加上ARCH=xxx选项。如

# make ARCH=i386 defconfig

# make ARCH=i386 menuconfig

然后选上:

   kernel hacking –> compile the kernel with debug info

   kernel hacking –> compile the kernel with frame pointers

另外选上      

    File system -> The extended 4 (ext4) filesystem

否则对有些img可能会在启动时挂载root失败.

# make ARCH=i386 bzImage

结束后生成Arch/x86/boot/bzImage和vmlinux,再在qemu的官网上下linux-0.2.img.bz2并解压得到linux-0.2.img。运行

$ qemu -kernel bzImage -hda linux-0.2.img -append root=/dev/sda rw -s -S

由于加了-S起来后停住在1234端口上等待debugger连接,于是起gdb client:

$ gdb vmlinux

(gdb) target remote localhost:1234

然后就可以像调app一样调kernel了。如图:

 

注意Root文件系统镜像除了用qemu提供的test image外,还可以自己用busybox做。嫌麻烦的可以用Buildroot,它会自动下载和编译Linux内核和rootfs等等。

用Qemu调有个好处是还可以用Qemu的Monitor查看系统信息(http://doc.opensuse.org/products/draft/SLES/SLES-kvm_sd_draft/cha.qemu.monitor.html)  。如查看control register,tlb或者memory mapping,在调试时都是非常有用的。


Kprobes, jprobes,dprobes

Xprobes族工具以module的方式在指定地址或函数位置加hook,然后用户可以调用自定义的handler。kprobes用来截地址(当然更多时候是根据symbol定位地址),jprobes用来截函数,用它查看函数参数比较方便,因为它的handler原型和要截的函数是一样的。Dprobes可以动态执行。

 

大多数时候我们会通过symbol来加hook,kernel的symbol可以通过以下三种方式找到

1. kernel编译生成的System.map文件

2. $ nm vmlinuz

3. /proc/kallsyms

 

查看当前的kprobes:

# cat/sys/kernel/debug/kprobes/list

 

关闭

# echo "0"> /sys/kernel/debug/kprobes/enabled

开启

# echo "1"> /sys/kernel/debug/kprobes/enabled

 

Linux kernel提供了相关文档Documentation/kprobes.txt,并且提供了几个例子,在samples/kprobes下。用以下Makefile单独编译例子:

obj-m +=jprobe_example.o kprobe_example.o

KDIR=/lib/modules/$(shell uname -r)/build

all:

$(MAKE)-C $(KDIR) SUBDIRS=$(PWD) modules

clean:

rm-rf *.o *.ko *.mod.* .c* .t*

 

编译完后:

# insmod./kprobes_example.ko

然后用 dmesg命令就可以看到handler的输出,如:

[ 1251.789211]Planted kprobe at c1058e30

[ 1256.716389]pre_handler: p->addr = 0xc1058e30, ip = c1058e31, flags = 0x246

[ 1256.716394]post_handler: p->addr = 0xc1058e30, flags = 0x246

[ 1262.680009]pre_handler: p->addr = 0xc1058e30, ip = c1058e31, flags = 0x246

[ 1262.680024]post_handler: p->addr = 0xc1058e30, flags = 0x246

...

[ 1468.928704]Planted jprobe at c1058e30, handler addr e08ff000

[ 1471.688212]jprobe: clone_flags = 0x1200011, stack_size = 0x0, regs = 0xcef87fb4

[ 1474.153652]jprobe: clone_flags = 0x1200011, stack_size = 0x0, regs = 0xcef87fb4

 

产生kernel Core dump

Kernel core dump需要内核支持,Linux kernel中的Documentation/kdump.txt对此讲得比较详细。

Ubuntu上可以装linux-crashdump, 其中包含crash,kexec-tools和makedumpfile等工具。装完后重启机子,启动时按shift进grub,按e看到启动选项多了crashkernel=XXX啥的。进入系统后

# service kdump start

开启kdump进程。系统崩溃时就会在/var/crash/下产生dump文件。简便使系统crash的方法是用magic sysrq:

SysrqAlt+SysRq+s // sync

SysrqAlt+SysRq+c // force crash

 

分析core dump和实时查看系统

crash可用于查看core dump或者实时查看运行状态。假设内核core dump在/var/crash/linux-image-2.6.32-38-generic.0.crash。先从crash文件中解压出vmcore文件:

# apport-unpack /var/crash/linux-image-2.6.32-38-generic.0.crash  ./

再用crash查看:

# crash vmlinux  ./VmCore

这里的vmlinux是kernel source编译出来的binary。

 

crash还可以用来实时查看当前运行的系统,直接运行:

# crash vmlinux

其实相当于

# crash vmlinux /proc/kcore,/proc/kcore是系统虚拟出来的core文件。

 

gdb, ddd也可用于相同功能,比如要实时查看系统:

# ddd vmlinux /proc/kcore

就可以对系统进行有限的gdb调试。

 

Kernel Trace

Kernel的trace功能依赖于debugfs,如果还没挂载的话要先挂上。trace的主要文件在/sys/kernel/debug/tracing下。其用法在kernel中的documentation/trace下写得比较详细,同时kernel还提供了相关例子sample/trace_events.c。

 

在/sys/kernel/debug/tracing下几个重要的文件:

trace: tracer的输出

available_tracers: 可用tracer

current_tracer:当前enabled的tracer

tracing_enabled:开关

 

例:

# echo function > current_tracer

# echo 1> tracing_enabled

# cat trace > trace.txt

# echo 0> tracing_enabled

# cat ./trace.txt

得到如:

...

Xorg-896   [000]  212.518803: do_softirq <-irq_exit

Xorg-896   [000]  212.518806: __do_softirq <-do_softirq

Xorg-896   [000]  212.518813: run_timer_softirq <-__do_softirq

Xorg-896   [000]  212.518816: hrtimer_run_pending <-run_timer_softirq

Xorg-896   [000]  212.518818: _raw_spin_lock_irq <-run_timer_softirq

Xorg-896   [000]  212.518821: rcu_bh_qs <-__do_softirq

Xorg-896   [000]  212.518824: __local_bh_enable <-__do_softirq

Xorg-896   [000]  212.518826: rcu_irq_exit <-irq_exit

Xorg-896   [000]  212.518828: rcu_enter_nohz <-rcu_irq_exit

 Xorg-896   [000]  212.518831: idle_cpu <-irq_exit

...

 

:上面的工具依赖于一些kernel的feature,如debugfs和sysrq等,要使用则要在内核编译时加上它们。

debugfs使内核的信息以基于内存的文件系统呈现,从而使用户很方便地与之交互。详见kernel的Documentation/debugfs.txt。挂载通过

# mount-t debugfs nodev /sys/kernel/debug

 

Sysrq提供了一些用于开发调试kernel的热键,详见kernel的Documentation/sysrq.txt, 该feature的开启通过

# echo 1 >/proc/sys/kernel/sysrq

或将/etc/sysctl.conf设置kernel.sysrq = 1。

 

上面介绍的只是kernel调试工具中的沧海一粟,还有好多神器无法列举,如kgdb, kdb远程调试kernel,kmemcheck,faultinjection等等。

你可能感兴趣的:(Linux)