調(diào)試是軟件開(kāi)發(fā)過(guò)程中一個(gè)必不可少的環(huán)節(jié),在 Linux 內(nèi)核開(kāi)發(fā)的過(guò)程中也不可避免地會(huì)面對(duì)如何調(diào)試內(nèi)核的問(wèn)題。但是,Linux 系統(tǒng)的開(kāi)發(fā)者出于保證內(nèi)核代碼正確性的考慮,不愿意在 Linux 內(nèi)核源代碼樹(shù)中加入一個(gè)調(diào)試器。他們認(rèn)為內(nèi)核中的調(diào)試器會(huì)誤導(dǎo)開(kāi)發(fā)者,從而引入不良的修正[1].所以對(duì) Linux 內(nèi)核進(jìn)行調(diào)試一直是個(gè)令內(nèi)核程序員感到棘手的問(wèn)題,調(diào)試工作的艱苦性是內(nèi)核級(jí)的開(kāi)發(fā)區(qū)別于用戶級(jí)開(kāi)發(fā)的一個(gè)顯著特點(diǎn)。 盡管缺乏一種內(nèi)置的調(diào)試內(nèi)核的有效方法,但是 Linux 系統(tǒng)在內(nèi)核發(fā)展的過(guò)程中也逐漸形成了一些監(jiān)視內(nèi)核代碼和錯(cuò)誤跟蹤的技術(shù)。同時(shí),許多的補(bǔ)丁程序應(yīng)運(yùn)而生,它們?yōu)闃?biāo)準(zhǔn)內(nèi)核附加了內(nèi)核調(diào)試的支持。盡管這些補(bǔ) 丁有些并不被 Linux 官方組織認(rèn)可,但他們確實(shí)功能完善,十分強(qiáng)大。調(diào)試內(nèi)核問(wèn)題時(shí),利用這些工具與方法跟蹤內(nèi)核執(zhí)行情況,并查看其內(nèi)存和數(shù)據(jù)結(jié)構(gòu)將是非常有用的。
本文將首先介紹 Linux 內(nèi)核上的一些內(nèi)核代碼監(jiān)視和錯(cuò)誤跟蹤技術(shù),這些調(diào)試和跟蹤方法因所要求的使用環(huán)境和使用方法而各有不同,然后重點(diǎn)介紹三種 Linux 內(nèi)核的源代碼級(jí)的調(diào)試方法。
1. Linux 系統(tǒng)內(nèi)核級(jí)軟件的調(diào)試技術(shù)
printk() 是調(diào)試內(nèi)核代碼時(shí)最常用的一種技術(shù)。在內(nèi)核代碼中的特定位置加入printk() 調(diào)試調(diào)用,可以直接把所關(guān)心的信息打打印到屏幕上,從而可以觀察程序的執(zhí)行路徑和所關(guān)心的變量、指針等信息。 Linux 內(nèi)核調(diào)試器(Linux kernel debugger,kdb)是 Linux 內(nèi)核的補(bǔ)丁,它提供了一種在系統(tǒng)能運(yùn)行時(shí)對(duì)內(nèi)核內(nèi)存和數(shù)據(jù)結(jié)構(gòu)進(jìn)行檢查的辦法。Oops、KDB在文章掌握 Linux 調(diào)試技術(shù)有詳細(xì)介紹,大家可以參考。 Kprobes 提供了一個(gè)強(qiáng)行進(jìn)入任何內(nèi)核例程,并從中斷處理器無(wú)干擾地收集信息的接口。使用 Kprobes 可以輕松地收集處理器寄存器和全局?jǐn)?shù)據(jù)結(jié)構(gòu)等調(diào)試信息,而無(wú)需對(duì)Linux內(nèi)核頻繁編譯和啟動(dòng),具體使用方法,請(qǐng)參考使用 Kprobes 調(diào)試內(nèi)核。
以上介紹了進(jìn)行Linux內(nèi)核調(diào)試和跟蹤時(shí)的常用技術(shù)和方法。當(dāng)然,內(nèi)核調(diào)試與跟蹤的方法還不止以上提到的這些。這些調(diào)試技術(shù)的一個(gè)共同的特點(diǎn)在于,他們 都不能提供源代碼級(jí)的有效的內(nèi)核調(diào)試手段,有些只能稱之為錯(cuò)誤跟蹤技術(shù),因此這些方法都只能提供有限的調(diào)試能力。下面將介紹三種實(shí)用的源代碼級(jí)的內(nèi)核調(diào)試 方法。
2. 使用KGDB構(gòu)建Linux內(nèi)核調(diào)試環(huán)境
kgdb提供了一種使用 gdb調(diào)試 Linux 內(nèi)核的機(jī)制。使用KGDB可以象調(diào)試普通的應(yīng)用程序那樣,在內(nèi)核中進(jìn)行設(shè)置斷點(diǎn)、檢查變量值、單步跟蹤程序運(yùn)行等操作。使用KGDB調(diào)試時(shí)需要兩臺(tái)機(jī)器, 一臺(tái)作為開(kāi)發(fā)機(jī)(Development Machine),另一臺(tái)作為目標(biāo)機(jī)(Target Machine),兩臺(tái)機(jī)器之間通過(guò)串口或者以太網(wǎng)口相連。串口連接線是一根RS-232接口的電纜,在其內(nèi)部?jī)啥说牡?腳(TXD)與第3腳(RXD) 交叉相連,第7腳(接地腳)直接相連。調(diào)試過(guò)程中,被調(diào)試的內(nèi)核運(yùn)行在目標(biāo)機(jī)上,gdb調(diào)試器運(yùn)行在開(kāi)發(fā)機(jī)上。
目前,kgdb發(fā)布支持i386、x86_64、32-bit PPC、SPARC等幾種體系結(jié)構(gòu)的調(diào)試器。有關(guān)kgdb補(bǔ)丁的下載地址見(jiàn)參考資料[4].
2.1 kgdb的調(diào)試原理
安裝kgdb調(diào)試環(huán)境需要為L(zhǎng)inux內(nèi)核應(yīng)用kgdb補(bǔ)丁,補(bǔ)丁實(shí)現(xiàn)的gdb遠(yuǎn)程調(diào)試所需要的功能包括命令處理、陷阱處理及串口通訊3個(gè)主要的部分。 kgdb補(bǔ)丁的主要作用是在Linux內(nèi)核中添加了一個(gè)調(diào)試Stub.調(diào)試Stub是Linux內(nèi)核中的一小段代碼,提供了運(yùn)行g(shù)db的開(kāi)發(fā)機(jī)和所調(diào)試內(nèi) 核之間的一個(gè)媒介。gdb和調(diào)試stub之間通過(guò)gdb串行協(xié)議進(jìn)行通訊。gdb串行協(xié)議是一種基于消息的ASCII碼協(xié)議, 包含了各種調(diào)試命令。當(dāng)設(shè)置斷點(diǎn)時(shí),kgdb負(fù)責(zé)在設(shè)置斷點(diǎn)的指令前增加一條trap指令,當(dāng)執(zhí)行到斷點(diǎn)時(shí)控制權(quán)就轉(zhuǎn)移到調(diào)試stub中去。此時(shí),調(diào)試 stub的任務(wù)就是使用遠(yuǎn)程串行通信協(xié)議將當(dāng)前環(huán)境傳送給gdb,然后從gdb處接受命令。gdb命令告訴stub下一步該做什么,當(dāng)stub收到繼續(xù)執(zhí) 行的命令時(shí),將恢復(fù)程序的運(yùn)行環(huán)境,把對(duì)CPU的控制權(quán)重新交還給內(nèi)核。
![]()
2.2 Kgdb的安裝與設(shè)置
下面我們將以Linux 2.6.7內(nèi)核為例詳細(xì)介紹kgdb調(diào)試環(huán)境的建立過(guò)程。
2.2.1軟硬件準(zhǔn)備
以下軟硬件配置取自筆者進(jìn)行試驗(yàn)的系統(tǒng)配置情況:
![]()
kgdb補(bǔ)丁的版本遵循如下命名模式:Linux-A-kgdb-B,其中A表示Linux的內(nèi)核版本號(hào),B為kgdb的版本號(hào)。以試驗(yàn)使用的kgdb補(bǔ)丁為例,linux內(nèi)核的版本為linux-2.6.7,補(bǔ)丁版本為kgdb-2.2。
物理連接好串口線后,使用以下命令來(lái)測(cè)試兩臺(tái)機(jī)器之間串口連接情況,stty命令可以對(duì)串口參數(shù)進(jìn)行設(shè)置:
在development機(jī)上執(zhí)行:
stty ispeed 115200 ospeed 115200 -F /dev/ttyS0 |
在target機(jī)上執(zhí)行:
stty ispeed 115200 ospeed 115200 -F /dev/ttyS0 |
在developement機(jī)上執(zhí)行:
在target機(jī)上執(zhí)行:
如果串口連接沒(méi)問(wèn)題的話在將在target機(jī)的屏幕上顯示"hello"。
2.2.2 安裝與配置
下面我們需要應(yīng)用kgdb補(bǔ)丁到Linux內(nèi)核,設(shè)置內(nèi)核選項(xiàng)并編譯內(nèi)核。這方面的資料相對(duì)較少,筆者這里給出詳細(xì)的介紹。下面的工作在開(kāi)發(fā)機(jī)(developement)上進(jìn)行,以上面介紹的試驗(yàn)環(huán)境為例,某些具體步驟在實(shí)際的環(huán)境中可能要做適當(dāng)?shù)母膭?dòng):
I、內(nèi)核的配置與編譯
[root@lisl tmp]# tar -jxvf linux-2.6.7.tar.bz2
[root@lisl tmp]#tar -jxvf linux-2.6.7-kgdb-2.2.tar.tar
[root@lisl tmp]#cd inux-2.6.7 |
請(qǐng)參照目錄補(bǔ)丁包中文件README給出的說(shuō)明,執(zhí)行對(duì)應(yīng)體系結(jié)構(gòu)的補(bǔ)丁程序。由于試驗(yàn)在i386體系結(jié)構(gòu)上完成,所以只需要安裝一下補(bǔ)丁: core-lite.patch、i386-lite.patch、8250.patch、eth.patch、core.patch、 i386.patch。應(yīng)用補(bǔ)丁文件時(shí),請(qǐng)遵循kgdb軟件包內(nèi)series文件所指定的順序,否則可能會(huì)帶來(lái)預(yù)想不到的問(wèn)題。eth.patch文件是 選擇以太網(wǎng)口作為調(diào)試的連接端口時(shí)需要運(yùn)用的補(bǔ)丁
。
應(yīng)用補(bǔ)丁的命令如下所示:
[root@lisl tmp]#patch -p1 <../linux-2.6.7-kgdb-2.2/core-lite.patch |
如果內(nèi)核正確,那么應(yīng)用補(bǔ)丁時(shí)應(yīng)該不會(huì)出現(xiàn)任何問(wèn)題(不會(huì)產(chǎn)生*.rej文件)。為L(zhǎng)inux內(nèi)核添加了補(bǔ)丁之后,需要進(jìn)行內(nèi)核的配置。內(nèi)核的配置可以按照你的習(xí)慣選擇配置Linux內(nèi)核的任意一種方式。
[root@lisl tmp]#make menuconfig |
在內(nèi)核配置菜單的Kernel hacking選項(xiàng)中選擇kgdb調(diào)試項(xiàng),例如:
KGDB: kernel debugging with remote gdb
Method for KGDB communication (KGDB: On generic serial port (8250)) ---> KGDB: Thread analysis KGDB: Console messages through gdb
[root@lisl tmp]#make |
編譯內(nèi)核之前請(qǐng)注意Linux目錄下Makefile中的優(yōu)化選項(xiàng),默認(rèn)的Linux內(nèi)核的編譯都以-O2的優(yōu)化級(jí)別進(jìn)行。在這個(gè)優(yōu)化級(jí)別之下,編 譯器要對(duì)內(nèi)核中的某些代碼的執(zhí)行順序進(jìn)行改動(dòng),所以在調(diào)試時(shí)會(huì)出現(xiàn)程序運(yùn)行與代碼順序不一致的情況?梢园袽akefile中的-O2選項(xiàng)改為-O,但不 可去掉-O,否則編譯會(huì)出問(wèn)題。為了使編譯后的內(nèi)核帶有調(diào)試信息,注意在編譯內(nèi)核的時(shí)候需要加上-g選項(xiàng)。
不過(guò),當(dāng)選擇"Kernel debugging->Compile the kernel with debug info"選項(xiàng)后配置系統(tǒng)將自動(dòng)打開(kāi)調(diào)試選項(xiàng)。另外,選擇"kernel debugging with remote gdb"后,配置系統(tǒng)將自動(dòng)打開(kāi)"Compile the kernel with debug info"選項(xiàng)。
內(nèi)核編譯完成后,使用scp命令進(jìn)行將相關(guān)文件拷貝到target機(jī)上(當(dāng)然也可以使用其它的網(wǎng)絡(luò)工具,如rcp)。
如果系統(tǒng)啟動(dòng)使所需要的某些設(shè)備驅(qū)動(dòng)沒(méi)有編譯進(jìn)內(nèi)核的情況下,那么還需要執(zhí)行如下操作:
[root@lisl tmp]#mkinitrd /boot/initrd-2.6.7-kgdb 2.6.7
[root@lisl tmp]#scp initrd-2.6.7-kgdb root@192.168.6.13:/boot/ initrd-2.6.7-kgdb |
II、kgdb的啟動(dòng)
在將編譯出的內(nèi)核拷貝的到target機(jī)器之后,需要配置系統(tǒng)引導(dǎo)程序,加入內(nèi)核的啟動(dòng)選項(xiàng)。以下是kgdb內(nèi)核引導(dǎo)參數(shù)的說(shuō)明:
![]()
如表中所述,在kgdb 2.0版本之后內(nèi)核的引導(dǎo)參數(shù)已經(jīng)與以前的版本有所不同。使用grub引導(dǎo)程序時(shí),直接將kgdb參數(shù)作為內(nèi)核vmlinuz的引導(dǎo)參數(shù)。下面給出引導(dǎo)器的配置示例。
title 2.6.7 kgdb
root (hd0,0)
kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait kgdb8250=1,115200 |
在使用lilo作為引導(dǎo)程序時(shí),需要把kgdb參放在由append修飾的語(yǔ)句中。下面給出使用lilo作為引導(dǎo)器時(shí)的配置示例。
image=/boot/vmlinuz-2.6.7-kgdb
label=kgdb
read-only
root=/dev/hda3
append="gdb gdbttyS=1 gdbbaud=115200" |
保存好以上配置后重新啟動(dòng)計(jì)算機(jī),選擇啟動(dòng)帶調(diào)試信息的內(nèi)核,內(nèi)核將在短暫的運(yùn)行后在創(chuàng)建init內(nèi)核線程之前停下來(lái),打印出以下信息,并等待開(kāi)發(fā)機(jī)的連接。
Waiting for connection from remote gdb...
在開(kāi)發(fā)機(jī)上執(zhí)行:
gdb
file vmlinux
set remotebaud 115200
target remote /dev/ttyS0 |
其中vmlinux是指向源代碼目錄下編譯出來(lái)的Linux內(nèi)核文件的鏈接,它是沒(méi)有經(jīng)過(guò)壓縮的內(nèi)核文件,gdb程序從該文件中得到各種符號(hào)地址信息。
這樣,就與目標(biāo)機(jī)上的kgdb調(diào)試接口建立了聯(lián)系。一旦建立聯(lián)接之后,對(duì)Linux內(nèi)的調(diào)試工作與對(duì)普通的運(yùn)用程序的調(diào)試就沒(méi)有什么區(qū)別了。任何時(shí)候都可以通過(guò)鍵入ctrl+c打斷目標(biāo)機(jī)的執(zhí)行,進(jìn)行具體的調(diào)試工作。
在kgdb 2.0之前的版本中,編譯內(nèi)核后在arch/i386/kernel目錄下還會(huì)生成可執(zhí)行文件gdbstart。將該文件拷貝到target機(jī)器的/boot目錄下,此時(shí)無(wú)需更改內(nèi)核的啟動(dòng)配置文件,直接使用命令:
[root@lisl boot]#gdbstart -s 115200 -t /dev/ttyS0 |
可以在KGDB內(nèi)核引導(dǎo)啟動(dòng)完成后建立開(kāi)發(fā)機(jī)與目標(biāo)機(jī)之間的調(diào)試聯(lián)系。
2.2.3 通過(guò)網(wǎng)絡(luò)接口進(jìn)行調(diào)試
kgdb也支持使用以太網(wǎng)接口作為調(diào)試器的連接端口。在對(duì)Linux內(nèi)核應(yīng)用補(bǔ)丁包時(shí),需應(yīng)用eth.patch補(bǔ)丁文件。配置內(nèi)核時(shí)在Kernel hacking中選擇kgdb調(diào)試項(xiàng),配置kgdb調(diào)試端口為以太網(wǎng)接口,例如:
KGDB: kernel debugging with remote gdb
Method for KGDB communication (KGDB: On ethernet) --->
( ) KGDB: On generic serial port (8250)
(X) KGDB: On ethernet |
另外使用eth0網(wǎng)口作為調(diào)試端口時(shí),grub.list的配置如下:
title 2.6.7 kgdb
root (hd0,0)
kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait kgdboe=@192.168.
5.13/,@192.168. 6.13/ |
其他的過(guò)程與使用串口作為連接端口時(shí)的設(shè)置過(guò)程相同。
注意:盡管可以使用以太網(wǎng)口作為kgdb的調(diào)試端口,使用串口作為連接端口更加簡(jiǎn)單易行,kgdb項(xiàng)目組推薦使用串口作為調(diào)試端口。
2.2.4 模塊的調(diào)試方法
內(nèi)核可加載模塊的調(diào)試具有其特殊性。由于內(nèi)核模塊中各段的地址是在模塊加載進(jìn)內(nèi)核的時(shí)候才最終確定的,所以develop機(jī)的gdb無(wú)法得到各種符號(hào)地址 信息。所以,使用kgdb調(diào)試模塊所需要解決的一個(gè)問(wèn)題是,需要通過(guò)某種方法獲得可加載模塊的最終加載地址信息,并把這些信息加入到gdb環(huán)境中。
I、在Linux 2.4內(nèi)核中的內(nèi)核模塊調(diào)試方法
在Linux2.4.x內(nèi)核中,可以使用insmod -m命令輸出模塊的加載信息,例如:
[root@lisl tmp]# insmod -m hello.ko >modaddr |
查看模塊加載信息文件modaddr如下:
.this 00000060 c88d8000 2**2
.text 00000035 c88d8060 2**2
.rodata 00000069 c88d80a0 2**5
……
.data 00000000 c88d833c 2**2
.bss 00000000 c88d833c 2**2
…… |
在這些信息中,我們關(guān)心的只有4個(gè)段的地址:.text、.rodata、.data、.bss。在development機(jī)上將以上地址信息加入到gdb中,這樣就可以進(jìn)行模塊功能的測(cè)試了。
(gdb) Add-symbol-file hello.o 0xc88d8060 -s .data 0xc88d80a0 -s
.rodata 0xc88d80a0 -s .bss 0x c88d833c |
這種方法也存在一定的不足,它不能調(diào)試模塊初始化的代碼,因?yàn)榇藭r(shí)模塊初始化代碼已經(jīng)執(zhí)行過(guò)了。而如果不執(zhí)行模塊的加載又無(wú)法獲得模塊插入地址,更不可能在模塊初始化之前設(shè)置斷點(diǎn)了。對(duì)于這種調(diào)試要求可以采用以下替代方法。
在target機(jī)上用上述方法得到模塊加載的地址信息,然后再用rmmod卸載模塊。在development機(jī)上將得到的模塊地址信息導(dǎo)入到gdb環(huán)境 中,在內(nèi)核代碼的調(diào)用初始化代碼之前設(shè)置斷點(diǎn)。這樣,在target機(jī)上再次插入模塊時(shí),代碼將在執(zhí)行模塊初始化之前停下來(lái),這樣就可以使用gdb命令調(diào) 試模塊初始化代碼了。
另外一種調(diào)試模塊初始化函數(shù)的方法是:當(dāng)插入內(nèi)核模塊時(shí),內(nèi)核模塊機(jī)制將調(diào)用函數(shù)sys_init_module(kernel/modle.c)執(zhí)行對(duì)內(nèi)核模塊的初始化,該函數(shù)將調(diào)用所插入模塊的初始化函數(shù)。程序代碼片斷如下:
…… ……
if (mod->init != NULL)
ret = mod->init();
…… ……
在該語(yǔ)句上設(shè)置斷點(diǎn),也能在執(zhí)行模塊初始化之前停下來(lái)。 II、在Linux 2.6.x內(nèi)核中的內(nèi)核模塊調(diào)試方法
Linux 2.6之后的內(nèi)核中,由于module-init-tools工具的更改,insmod命令不再支持-m參數(shù),只有采取其他的方法來(lái)獲取模塊加載到內(nèi)核的地址。通過(guò)分析ELF文件格式,我們知道程序中各段的意義如下:
。text(代碼段):用來(lái)存放可執(zhí)行文件的操作指令,也就是說(shuō)是它是可執(zhí)行程序在內(nèi)存種的鏡像。
。data(數(shù)據(jù)段):數(shù)據(jù)段用來(lái)存放可執(zhí)行文件中已初始化全局變量,也就是存放程序靜態(tài)分配的變量和全局變量。
。bss(BSS段):BSS段包含了程序中未初始化全局變量,在內(nèi)存中 bss段全部置零。
。rodata(只讀段):該段保存著只讀數(shù)據(jù),在進(jìn)程映象中構(gòu)造不可寫(xiě)的段。
通過(guò)在模塊初始化函數(shù)中放置一下代碼,我們可以很容易地獲得模塊加載到內(nèi)存中的地址。
……
int bss_var;
static int hello_init(void)
{
printk(KERN_ALERT "Text location .text(Code Segment):%p\n",hello_init);
static int data_var=0;
printk(KERN_ALERT "Data Location .data(Data Segment):%p\n",&data_var);
printk(KERN_ALERT "BSS Location: .bss(BSS Segment):%p\n",&bss_var);
……
}
Module_init(hello_init); |
這里,通過(guò)在模塊的初始化函數(shù)中添加一段簡(jiǎn)單的程序,使模塊在加載時(shí)打印出在內(nèi)核中的加載地址。。rodata段的地址可以通過(guò)執(zhí)行命令readelf -e hello.ko,取得。rodata在文件中的偏移量并加上段的align值得出。
為了使讀者能夠更好地進(jìn)行模塊的調(diào)試,kgdb項(xiàng)目還發(fā)布了一些腳本程序能夠自動(dòng)探測(cè)模塊的插入并自動(dòng)更新gdb中模塊的符號(hào)信息。這些腳本程序的工作原理與前面解釋的工作過(guò)程相似,更多的信息請(qǐng)閱讀參考資料[4].
2.2.5 硬件斷點(diǎn)
kgdb提供對(duì)硬件調(diào)試寄存器的支持。在kgdb中可以設(shè)置三種硬件斷點(diǎn):執(zhí)行斷點(diǎn)(Execution Breakpoint)、寫(xiě)斷點(diǎn)(Write Breakpoint)、訪問(wèn)斷點(diǎn)(Access Breakpoint)但不支持I/O訪問(wèn)的斷點(diǎn)。目前,kgdb對(duì)硬件斷點(diǎn)的支持是通過(guò)宏來(lái)實(shí)現(xiàn)的,最多可以設(shè)置4個(gè)硬件斷點(diǎn),這些宏的用法如下:
![]()
在有些情況下,硬件斷點(diǎn)的使用對(duì)于內(nèi)核的調(diào)試是非常方便的。有關(guān)硬件斷點(diǎn)的定義和具體的使用說(shuō)明見(jiàn)參考資料[4]
。
2.3.在VMware中搭建調(diào)試環(huán)境
kgdb調(diào)試環(huán)境需要使用兩臺(tái)微機(jī)分別充當(dāng)development機(jī)和target機(jī),使用VMware后我們只使用一臺(tái)計(jì)算機(jī)就可以順利完成kgdb調(diào)試環(huán)境的搭建。以windows下的環(huán)境為例,創(chuàng)建兩臺(tái)虛擬機(jī),一臺(tái)作為開(kāi)發(fā)機(jī),一臺(tái)作為目標(biāo)機(jī)。
2.3.1虛擬機(jī)之間的串口連接
虛擬機(jī)中的串口連接可以采用兩種方法。一種是指定虛擬機(jī)的串口連接到實(shí)際的COM上,例如開(kāi)發(fā)機(jī)連接到COM1,目標(biāo)機(jī)連接到COM2,然后把兩個(gè)串口通 過(guò)串口線相連接。另一種更為簡(jiǎn)便的方法是:在較高一些版本的VMware中都支持把串口映射到命名管道,把兩個(gè)虛擬機(jī)的串口映射到同一個(gè)命名管道。例如, 在兩個(gè)虛擬機(jī)中都選定同一個(gè)命名管道 [url=]\\.\pipe\com_1[/url], 指定target機(jī)的COM口為server端,并選擇"The other end is a virtual machine"屬性;指定development機(jī)的COM口端為client端,同樣指定COM口的"The other end is a virtual machine"屬性。對(duì)于IO mode屬性,在target上選中"Yield CPU on poll"復(fù)選擇框,development機(jī)不選。這樣,可以無(wú)需附加任何硬件,利用虛擬機(jī)就可以搭建kgdb調(diào)試環(huán)境。即降低了使用kgdb進(jìn)行調(diào)試 的硬件要求,也簡(jiǎn)化了建立調(diào)試環(huán)境的過(guò)程。
![]()
2.3.2 VMware的使用技巧
VMware虛擬機(jī)是比較占用資源的,尤其是象上面那樣在Windows中 使用兩臺(tái)虛擬機(jī)。因此,最好為系統(tǒng)配備512M以上的內(nèi)存,每臺(tái)虛擬機(jī)至少分配128M的內(nèi)存。這樣的硬件要求,對(duì)目前主流配置的PC而言并不是過(guò)高的要 求。出于系統(tǒng)性能的考慮,在VMware中盡量使用字符界面進(jìn)行調(diào)試工作。同時(shí),Linux系統(tǒng)默認(rèn)情況下開(kāi)啟了sshd服務(wù),建議使用 SecureCRT登陸到Linux進(jìn)行操作,這樣可以有較好的用戶使用界面。
2.3.3 在Linux下的虛擬機(jī)中使用kgdb
對(duì)于在Linux下面使用VMware虛擬機(jī)的情況,筆者沒(méi)有做過(guò)實(shí)際的探索。從原理上而言,只需要在Linux下只要?jiǎng)?chuàng)建一臺(tái)虛擬機(jī)作為target 機(jī),開(kāi)發(fā)機(jī)的工作可以在實(shí)際的Linux環(huán)境中進(jìn)行,搭建調(diào)試環(huán)境的過(guò)程與上面所述的過(guò)程類似。由于只需要?jiǎng)?chuàng)建一臺(tái)虛擬機(jī),所以使用Linux下的虛擬機(jī) 搭建kgdb調(diào)試環(huán)境對(duì)系統(tǒng)性能的要求較低。(vmware已經(jīng)推出了Linux下的版本)還可以在development機(jī)上配合使用一些其他的調(diào)試工 具,例如功能更強(qiáng)大的cgdb、圖形界面的DDD調(diào)試器等,以方便內(nèi)核的調(diào)試工作。
![]()
2.4 kgdb的一些特點(diǎn)和不足
使用kgdb作為內(nèi)核調(diào)試環(huán)境最大的不足在于對(duì)kgdb硬件環(huán)境的要求較高,必須使用兩臺(tái)計(jì)算機(jī)分別作為target和development機(jī)。盡管使 用虛擬機(jī)的方法可以只用一臺(tái)PC即能搭建調(diào)試環(huán)境,但是對(duì)系統(tǒng)其他方面的性能也提出了一定的要求,同時(shí)也增加了搭建調(diào)試環(huán)境時(shí)復(fù)雜程度。另外,kgdb內(nèi) 核的編譯、配置也比較復(fù)雜,需要一定的技巧,筆者當(dāng)時(shí)做的時(shí)候也是費(fèi)了很多周折。當(dāng)調(diào)試過(guò)程結(jié)束后時(shí),還需要重新制作所要發(fā)布的內(nèi)核。使用kgdb并不能 進(jìn)行全程調(diào)試,也就是說(shuō)kgdb并不能用于調(diào)試系統(tǒng)一開(kāi)始的初始化引導(dǎo)過(guò)程。
不過(guò),kgdb是一個(gè)不錯(cuò)的內(nèi)核調(diào)試工具,使用它可以進(jìn)行對(duì)內(nèi)核的全面調(diào)試,甚至可以調(diào)試內(nèi)核的中斷處理程序。如果在一些圖形化的開(kāi)發(fā)工具的幫助下,對(duì)內(nèi)核的調(diào)試將更方便。