通過UML可以方便的在本機調試Linux內核,UML是一種特殊的虛擬機,另外一種更為靈活的虛擬機是Qemu,Qemu是一種完全仿真虛擬機, 可以在i386平台仿真任意其他處理器構架,而且支持GDB調試,這裡嘗試一下使用Qemu調試Linux內核,Qemu參數-kernel可以直接指定 內核啟動,這與UML有相似之處。
首先需要編譯安裝Qemu,這裡並沒有什麼疑惑之處,直接從官方網站下載源碼,使用Linux最常用的編譯命令即可:
# 默認選項會編譯所有處理器構架虛擬機
# 可以 ./configure --help 查看編譯特定平台的配置
cpp@dark:~/qemu-0.12.4$ ./configure --target-list=i386-softmmu
cpp@dark:~/qemu-0.12.4$ make
cpp@dark:~/qemu-0.12.4$ make install
接下來以默認選項編譯內核,不過巨崩潰的是內核默認沒有DEBUG_INFO選項,所以雖然能在導出符號部分斷下來,但是沒有源碼,所以需要選則Compile the kernel with debug info選項。
# 默認選項
cpp@dark:~/linux-2.6.34$ make defconfig
# 配置菜單,選擇調試信息
cpp@dark:~/linux-2.6.34$ make menuconfig
# 編譯內核
cpp@dark:~/linux-2.6.34$ make
然後使用Qemu加載內核啟動
cpp@dark:~/linux-2.6.34$ qemu -s -S -kernel arch/x86/boot/bzImage -hda rootfs.img -append "root=/dev/sda"
# 其中一些選項的解釋如下
# -s 監聽tcp:1234端口以等待GDB連接
# -S 虛擬機啟動後停止,以便GDB連接後調試啟動過程
# -kernel 壓縮內核
# -hda 硬盤
# -appand 啟動參數
這裡系統很容易啟動不了,如果系統由於VFS加載錯誤無法啟動,首先嘗試啟動參數root=/dev/sda為root=/dev /hda,hda是IDE硬盤標識,sda為SCSI硬盤,這要看內核識別成哪種,如果仍然不行,那要檢測rootfs.img根文件系統的格式跟內核所 支持的格式是否匹配,2.6.34支持ext3格式,如果格式錯誤,可以利用 Linux 內核調試1 裡的方法,自己手工創建一個ext3格式的文件,然後mount到臨時文件,把其他根文件系統全部拷貝進去即可。
這 樣啟動Qemu之後,發現系統一片黑屏,這裡因為Qemu啟動參數被設置為禁止,Qemu本身具有顯示窗口和控制窗口,利用 Ctrl+Alt+2 進入控制台,c命令繼續虛擬機,Ctrl+Alt+1 返回顯示窗口,Qemu的控制台可以控制很多選項,從這點來看要比VMware等要靈活一些,UML本身也支持運行時控制。
接下來使用GDB啟動虛擬機,當系統停止在啟動之後時,用GDB加載:
# 啟動GDB,GDB加載未壓縮內核
cpp@dark:~/linux-2.6.34$ gdb vmlinux
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-slackware-linux"...
(gdb)
# 設置斷點
(gdb) br start_kernel
Breakpoint 1 at 0xc172f5d4: file init/main.c, line 533.
# 連接Qemu監聽端口1234
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
[New Thread 1]
0x0000fff0 in ?? ()
# 繼續Qemu虛擬機執行
(gdb) c
Continuing.
# 內核解壓之後很快便到達斷點
Breakpoint 1, start_kernel () at init/main.c:533
533 smp_setup_processor_id();
(gdb)
# 接下來便可任意調試內核
(gdb) list
528 asmlinkage void __init start_kernel(void)
529 {
530 char * command_line;
531 extern struct kernel_param __start___param[], __stop___param[];
532
533 smp_setup_processor_id();
534
535 /*
536 * Need to run as early as possible, to initialize the
537 * lockdep hash:
(gdb)
Qemu由於是完全仿真實現,所以可以在任意平台調試其他構架內核,理論上甚至可以在Windows平台交叉編譯Linux內核,再去由Qemu加載調試(交叉編譯比較麻煩,需要先編譯目標構架的binutil,而後鏈接內核)。
相關系列文章:
Linux 內核調試1-UML http://www.linuxidc.com/Linux/2012-07/66410.htm
Linux 內核調試2-UML調試內核 http://www.linuxidc.com/Linux/2012-07/66411.htm
Linux 內核調試3-UML網絡配置 http://www.linuxidc.com/Linux/2012-07/66412.htm
Linux 內核調試4-Qemu調試Linux內核 http://www.linuxidc.com/Linux/2012-07/66413.htm
Linux 內核調試5-UML和Qemu調試模塊 http://www.linuxidc.com/Linux/2012-07/66414.htm
Linux 內核調試6-使用KGDB雙機調試 http://www.linuxidc.com/Linux/2012-07/66415.htm