在看此文章之前,請先參考《利用busybox制作一個小巧的Linux系統》http://www.linuxidc.com/Linux/2011-08/40881.htm與《使用busybox做一個小巧的Linux操作系統》 見 http://www.linuxidc.com/Linux/2008-04/12510.htm 制作出一個initrd內存盤。
1. 首先編譯內核,編譯內核時注意要選中
kernel hacking –> kernel debugging –> compile the kernel with debug info
kernel hacking –> compile the kernel with frame pointers
兩個選項。(注意:除此之外kernel hacking 選項下其他的選項都不要選,否則會出現斷點無法攔截的情況。)
2. 假設你的內核目錄位於/home/xxx/linux-2.6.28中,且編譯內核時你指定的大O參數指定的目錄是O=/home/xxx/linux-2.6.28-obj。
用新編譯的帶調試信息的內核,啟動一個虛擬機。
$ qemu –kernel /home/xxx/linux-2.6.28-obj/arch/x86/boot/bzImage –append "root=/dev/ram0 rw"
-initrd /home/initrd.gz –s –S [qemu文檔:http://qemu.weilnetz.de/qemu-doc.html]
-s-->Shorthand for -gdb tcp::1234, i.e. open agdbserver on TCP port 1234
-S-->Donot start CPU at startup (you must type 'c' in the monitor)
這樣啟動虛擬機後,它會在1234端口產生一個gdb stub以供調試時使用。
然後我們打開令一個xterm終端運行gdb命令開始調試:
$ gdb /home/xxx/linux-2.6.28-obj/vmlinux
#######若未使用-s參數,則可按下面啟用調試##########
然後會出現qemu的工作終端,你在上面點擊鼠標可以陷入,ctrl+ alt + 2可以釋放鼠標
(qemu)gdbservertcp::1234 [若使用了-s參數則無需此步]
##################################
然後在gdb的提示符下輸入: target remote localhost:1234 連接gdb stub
然後開始設置斷點,比如: break start_kernel
然後輸入c命令,然後qemu繼續運行後,就會在start_kernel 入口處停了下來。
這時候你就可以輸入各種gdb命令來對linux kernel進行hack了。。
當然,這裡采用gdb的一個前端工具ddd會更好。但還是需要學習一些常用的gdb命令(這樣才能更熟練的進行調試)
常用的gdb調試命令:
1. file <文件名> : 加載被調試的可執行程序文件.
2. run(簡寫r也可以): 運行被調試程序,直到遇到斷點.
3. c : 繼續執行被調試程序,直到下一斷點.
4. b : 設置斷點.
5. d <編號> : 刪除斷點.
6. info breakpoints : 顯示已設置的斷點列表.
7. s : 源碼級的單步進入.
8. n : 源碼級的單步步過.
9. si/ni : 指令級的單步進入和步過.(需要先運行display /i $pc)
10. info all-register: 顯示所有寄存器的值.
11. p /x $eax : 以16進制顯示某一特定寄存器的值.
12. q: 退出gdb調試環境.
13. disassemble <0xXXXXXXXX> : 反匯編指定地址處的指令.(加/r選項,顯示對應匯編代碼的機器碼)
14. set disassembly-flavor <intel | att> : 設定匯編顯示的格式(Intel格式或者AT&T格式)
15. 修改指定地址的內存數據:set {unsigned char} <0xXXXXXXXX>= <new data>
16. 顯示源代碼文件: list
17. info stack: 查看棧追蹤(棧回溯). 或者使用 backtrace 也可以
18. x /nfu <addr> : 查看指定地址處的內存內容.
n: 表示個數. f(format): x,16進制. d,10進制. u(每一項的長度): b,單字節. w,4字節. h,雙字節.
例如: x /1xw 0x804a010