原文地址: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等等。