如何調試係統啟動過程中systemd的代碼
之前寫過很多kernel的gdb debug, 其實用戶態也是可以調試的, 隻是在共享庫的動態地址上不是很好處理, 最近同事有調試係統啟動過程中systemd的需求, 簡單研究了一下
其實qemu kvm打斷點並不區別kernel還是用戶態, 都是rip的值等於某個地址或者遇到斷點指令了, 所以開機的時候把斷點打到systemd的main上就可以了
但是其實另外一個問題是, 用戶態的地址是很多進程共享的, 這時候有可能會另一個進程也跑到了這個地址, 所以斷點就需要條件斷點, 用進程的pid是一個好方法,
下麵是簡單得步驟
第一步, 開機暫停
sudo qemu-system-x86_64 -drive file=centos7.vhd,if=virtio -vnc :11 -enable-kvm -serial mon:stdio -smp 8 -m 1024 -redir tcp:1011::22 -append "root=/dev/vda1 console=ttyS0 slub_debug=PFZ ro norandmaps" -kernel /home/shidao.ytt/alikernel/7u/arch/x86/boot/bzImage -s -S
kernel 參數 norandmaps很重要, 不然的話, 共享庫的地址每次都不一樣, 加了這個參數, 每次共享庫的地址都是一樣的, 就不用考慮共享庫動態地址的問題了
第二步, 連接qemu, 打斷點到systemd的main
/usr/bin/gdb vmlinux -ex 'target remote :1234' -ex 'thb start_kernel' -ex c
(gdb) add-symbol-file /usr/lib/debug/usr/lib/systemd/systemd.debug 0x0000555555573b60
這裏說明一下, 因為要調試guest的systemd代碼, 所以要在物理機上安裝guest的systemd的debuginfo, 這個很好處理, 去centos下載debuginfo rpm安裝就可以了
後麵的地址0x0000555555573b60是systemd映射到進程代碼段的加載地址, 這個地址如何獲得, 開機一次, 去查看pid 1進程的vm映射空間就可以了, 簡單一點就是gdb -p 1, info files就可以了
(gdb) thbreak *0x5555555752c0 if $lx_current().pid == 1
Hardware assisted breakpoint 2 at 0x5555555752c0: file src/core/main.c, line 1244.
簡單說明, 因為systemd進程都還沒起來, 所以是沒有這個地址的, 所以一定需要用hardware breakpoint, 後麵是條件判斷, 隻有pid為1的時候生效, 這個就是斷點打到具體進程的利器了
c
接著跑

隻要打斷點的時候加入pid的條件限製, 就可以打到任意的進程了
最後更新:2017-09-05 16:02:32