久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linux 系統(tǒng)內(nèi)核的調(diào)試

 openlog 2007-09-28






級別: 初級

樹雷 李 ([email protected]), 清華大學計算機系碩士研究生
渝 陳 ([email protected]), 清華大學

2005 年 12 月 18 日

本文將首先介紹 Linux 內(nèi)核上的一些內(nèi)核代碼監(jiān)視和錯誤跟蹤技術(shù),,這些調(diào)試和跟蹤方法因所要求的使用環(huán)境和使用方法而各有不同,,然后重點介紹三種 Linux 內(nèi)核的源代碼級的調(diào)試方法。

調(diào)試是軟件開發(fā)過程中一個必不可少的環(huán)節(jié),,在 Linux 內(nèi)核開發(fā)的過程中也不可避免地會面對如何調(diào)試內(nèi)核的問題。但是,,Linux 系統(tǒng)的開發(fā)者出于保證內(nèi)核代碼正確性的考慮,,不愿意在 Linux 內(nèi)核源代碼樹中加入一個調(diào)試器。他們認為內(nèi)核中的調(diào)試器會誤導開發(fā)者,,從而引入不良的修正[1],。所以對 Linux 內(nèi)核進行調(diào)試一直是個令內(nèi)核程序員感到棘手的問題,調(diào)試工作的艱苦性是內(nèi)核級的開發(fā)區(qū)別于用戶級開發(fā)的一個顯著特點,。

盡管缺乏一種內(nèi)置的調(diào)試內(nèi)核的有效方法,,但是 Linux 系統(tǒng)在內(nèi)核發(fā)展的過程中也逐漸形成了一些監(jiān)視內(nèi)核代碼和錯誤跟蹤的技術(shù)。同時,,許多的補丁程序應(yīng)運而生,,它們?yōu)闃藴蕛?nèi)核附加了內(nèi)核調(diào)試的支持。盡管這些補丁有些并不被 Linux 官方組織認可,,但他們確實功能完善,,十分強大。調(diào)試內(nèi)核問題時,,利用這些工具與方法跟蹤內(nèi)核執(zhí)行情況,,并查看其內(nèi)存和數(shù)據(jù)結(jié)構(gòu)將是非常有用的。

本文將首先介紹 Linux 內(nèi)核上的一些內(nèi)核代碼監(jiān)視和錯誤跟蹤技術(shù),,這些調(diào)試和跟蹤方法因所要求的使用環(huán)境和使用方法而各有不同,,然后重點介紹三種 Linux 內(nèi)核的源代碼級的調(diào)試方法。

1. Linux 系統(tǒng)內(nèi)核級軟件的調(diào)試技術(shù)

printk() 是調(diào)試內(nèi)核代碼時最常用的一種技術(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)核的補丁,它提供了一種在系統(tǒng)能運行時對內(nèi)核內(nèi)存和數(shù)據(jù)結(jié)構(gòu)進行檢查的辦法,。Oops,、KDB在文章掌握 Linux 調(diào)試技術(shù)有詳細介紹,大家可以參考,。 Kprobes 提供了一個強行進入任何內(nèi)核例程,,并從中斷處理器無干擾地收集信息的接口。使用 Kprobes 可以輕松地收集處理器寄存器和全局數(shù)據(jù)結(jié)構(gòu)等調(diào)試信息,,而無需對Linux內(nèi)核頻繁編譯和啟動,,具體使用方法,請參考使用 Kprobes 調(diào)試內(nèi)核,。

以上介紹了進行Linux內(nèi)核調(diào)試和跟蹤時的常用技術(shù)和方法,。當然,內(nèi)核調(diào)試與跟蹤的方法還不止以上提到的這些,。這些調(diào)試技術(shù)的一個共同的特點在于,,他們都不能提供源代碼級的有效的內(nèi)核調(diào)試手段,有些只能稱之為錯誤跟蹤技術(shù),,因此這些方法都只能提供有限的調(diào)試能力,。下面將介紹三種實用的源代碼級的內(nèi)核調(diào)試方法。





回頁首


2. 使用KGDB構(gòu)建Linux內(nèi)核調(diào)試環(huán)境

kgdb提供了一種使用 gdb調(diào)試 Linux 內(nèi)核的機制,。使用KGDB可以象調(diào)試普通的應(yīng)用程序那樣,,在內(nèi)核中進行設(shè)置斷點、檢查變量值,、單步跟蹤程序運行等操作,。使用KGDB調(diào)試時需要兩臺機器,一臺作為開發(fā)機(Development Machine),另一臺作為目標機(Target Machine),,兩臺機器之間通過串口或者以太網(wǎng)口相連,。串口連接線是一根RS-232接口的電纜,在其內(nèi)部兩端的第2腳(TXD)與第3腳(RXD)交叉相連,,第7腳(接地腳)直接相連,。調(diào)試過程中,被調(diào)試的內(nèi)核運行在目標機上,,gdb調(diào)試器運行在開發(fā)機上,。

目前,kgdb發(fā)布支持i386,、x86_64,、32-bit PPC,、SPARC等幾種體系結(jié)構(gòu)的調(diào)試器。有關(guān)kgdb補丁的下載地址見參考資料[4],。

2.1 kgdb的調(diào)試原理

安裝kgdb調(diào)試環(huán)境需要為Linux內(nèi)核應(yīng)用kgdb補丁,,補丁實現(xiàn)的gdb遠程調(diào)試所需要的功能包括命令處理、陷阱處理及串口通訊3個主要的部分,。kgdb補丁的主要作用是在Linux內(nèi)核中添加了一個調(diào)試Stub,。調(diào)試Stub是Linux內(nèi)核中的一小段代碼,提供了運行g(shù)db的開發(fā)機和所調(diào)試內(nèi)核之間的一個媒介,。gdb和調(diào)試stub之間通過gdb串行協(xié)議進行通訊,。gdb串行協(xié)議是一種基于消息的ASCII碼協(xié)議,包含了各種調(diào)試命令,。當設(shè)置斷點時,,kgdb負責在設(shè)置斷點的指令前增加一條trap指令,當執(zhí)行到斷點時控制權(quán)就轉(zhuǎn)移到調(diào)試stub中去,。此時,,調(diào)試stub的任務(wù)就是使用遠程串行通信協(xié)議將當前環(huán)境傳送給gdb,然后從gdb處接受命令,。gdb命令告訴stub下一步該做什么,,當stub收到繼續(xù)執(zhí)行的命令時,將恢復(fù)程序的運行環(huán)境,,把對CPU的控制權(quán)重新交還給內(nèi)核。



2.2 Kgdb的安裝與設(shè)置

下面我們將以Linux 2.6.7內(nèi)核為例詳細介紹kgdb調(diào)試環(huán)境的建立過程,。

2.2.1軟硬件準備

以下軟硬件配置取自筆者進行試驗的系統(tǒng)配置情況:



kgdb補丁的版本遵循如下命名模式:Linux-A-kgdb-B,,其中A表示Linux的內(nèi)核版本號,B為kgdb的版本號,。以試驗使用的kgdb補丁為例,,linux內(nèi)核的版本為linux-2.6.7,補丁版本為kgdb-2.2,。

物理連接好串口線后,,使用以下命令來測試兩臺機器之間串口連接情況,stty命令可以對串口參數(shù)進行設(shè)置:

在development機上執(zhí)行:


stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
                                    

在target機上執(zhí)行:


stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
                                    

在developement機上執(zhí)行:


echo hello > /dev/ttyS0
                                    

在target機上執(zhí)行:


cat /dev/ttyS0
                                    

如果串口連接沒問題的話在將在target機的屏幕上顯示"hello",。

2.2.2 安裝與配置

下面我們需要應(yīng)用kgdb補丁到Linux內(nèi)核,,設(shè)置內(nèi)核選項并編譯內(nèi)核。這方面的資料相對較少,,筆者這里給出詳細的介紹,。下面的工作在開發(fā)機(developement)上進行,以上面介紹的試驗環(huán)境為例,,某些具體步驟在實際的環(huán)境中可能要做適當?shù)母膭樱?/p>

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
                                    

請參照目錄補丁包中文件README給出的說明,,執(zhí)行對應(yīng)體系結(jié)構(gòu)的補丁程序。由于試驗在i386體系結(jié)構(gòu)上完成,,所以只需要安裝一下補?。篶ore-lite.patch、i386-lite.patch,、8250.patch,、eth.patch、core.patch,、i386.patch,。應(yīng)用補丁文件時,請遵循kgdb軟件包內(nèi)series文件所指定的順序,,否則可能會帶來預(yù)想不到的問題,。eth.patch文件是選擇以太網(wǎng)口作為調(diào)試的連接端口時需要運用的補丁

應(yīng)用補丁的命令如下所示:


[root@lisl tmp]#patch -p1 <../linux-2.6.7-kgdb-2.2/core-lite.patch
                                    

如果內(nèi)核正確,,那么應(yīng)用補丁時應(yīng)該不會出現(xiàn)任何問題(不會產(chǎn)生*.rej文件),。為Linux內(nèi)核添加了補丁之后,需要進行內(nèi)核的配置,。內(nèi)核的配置可以按照你的習慣選擇配置Linux內(nèi)核的任意一種方式,。


[root@lisl tmp]#make menuconfig
                                    

在內(nèi)核配置菜單的Kernel hacking選項中選擇kgdb調(diào)試項,例如:


  [*] 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)核之前請注意Linux目錄下Makefile中的優(yōu)化選項,,默認的Linux內(nèi)核的編譯都以-O2的優(yōu)化級別進行,。在這個優(yōu)化級別之下,編譯器要對內(nèi)核中的某些代碼的執(zhí)行順序進行改動,,所以在調(diào)試時會出現(xiàn)程序運行與代碼順序不一致的情況,。可以把Makefile中的-O2選項改為-O,但不可去掉-O,,否則編譯會出問題,。為了使編譯后的內(nèi)核帶有調(diào)試信息,注意在編譯內(nèi)核的時候需要加上-g選項,。

不過,,當選擇"Kernel debugging->Compile the kernel with debug info"選項后配置系統(tǒng)將自動打開調(diào)試選項。另外,,選擇"kernel debugging with remote gdb"后,,配置系統(tǒng)將自動打開"Compile the kernel with debug info"選項。

內(nèi)核編譯完成后,,使用scp命令進行將相關(guān)文件拷貝到target機上(當然也可以使用其它的網(wǎng)絡(luò)工具,,如rcp)。


[root@lisl tmp]#scp arch/i386/boot/bzImage [email protected]:/boot/vmlinuz-2.6.7-kgdb
                                    [root@lisl tmp]#scp System.map [email protected]:/boot/System.map-2.6.7-kgdb
                                    

如果系統(tǒng)啟動使所需要的某些設(shè)備驅(qū)動沒有編譯進內(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 [email protected]:/boot/ initrd-2.6.7-kgdb
                                    

II,、kgdb的啟動

在將編譯出的內(nèi)核拷貝的到target機器之后,,需要配置系統(tǒng)引導程序,加入內(nèi)核的啟動選項,。以下是kgdb內(nèi)核引導參數(shù)的說明:



如表中所述,,在kgdb 2.0版本之后內(nèi)核的引導參數(shù)已經(jīng)與以前的版本有所不同。使用grub引導程序時,,直接將kgdb參數(shù)作為內(nèi)核vmlinuz的引導參數(shù),。下面給出引導器的配置示例。


title 2.6.7 kgdb
                                    root (hd0,0)
                                    kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait kgdb8250=1,115200
                                    

在使用lilo作為引導程序時,,需要把kgdb參放在由append修飾的語句中,。下面給出使用lilo作為引導器時的配置示例。


image=/boot/vmlinuz-2.6.7-kgdb
                                    label=kgdb
                                    read-only
                                    root=/dev/hda3
                                    append="gdb gdbttyS=1 gdbbaud=115200"
                                    

保存好以上配置后重新啟動計算機,,選擇啟動帶調(diào)試信息的內(nèi)核,,內(nèi)核將在短暫的運行后在創(chuàng)建init內(nèi)核線程之前停下來,打印出以下信息,,并等待開發(fā)機的連接,。

Waiting for connection from remote gdb...

在開發(fā)機上執(zhí)行:


gdb
                                    file vmlinux
                                    set remotebaud 115200
                                    target remote /dev/ttyS0
                                    

其中vmlinux是指向源代碼目錄下編譯出來的Linux內(nèi)核文件的鏈接,它是沒有經(jīng)過壓縮的內(nèi)核文件,,gdb程序從該文件中得到各種符號地址信息,。

這樣,就與目標機上的kgdb調(diào)試接口建立了聯(lián)系,。一旦建立聯(lián)接之后,,對Linux內(nèi)的調(diào)試工作與對普通的運用程序的調(diào)試就沒有什么區(qū)別了。任何時候都可以通過鍵入ctrl+c打斷目標機的執(zhí)行,,進行具體的調(diào)試工作,。

在kgdb 2.0之前的版本中,編譯內(nèi)核后在arch/i386/kernel目錄下還會生成可執(zhí)行文件gdbstart,。將該文件拷貝到target機器的/boot目錄下,此時無需更改內(nèi)核的啟動配置文件,,直接使用命令:


[root@lisl boot]#gdbstart -s 115200 -t /dev/ttyS0
                                    

可以在KGDB內(nèi)核引導啟動完成后建立開發(fā)機與目標機之間的調(diào)試聯(lián)系,。

2.2.3 通過網(wǎng)絡(luò)接口進行調(diào)試

kgdb也支持使用以太網(wǎng)接口作為調(diào)試器的連接端口。在對Linux內(nèi)核應(yīng)用補丁包時,,需應(yīng)用eth.patch補丁文件,。配置內(nèi)核時在Kernel hacking中選擇kgdb調(diào)試項,配置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)試端口時,,grub.list的配置如下:


title 2.6.7 kgdb
                                    root (hd0,0)
                                    kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait [email protected].
                                    5.13/,@192.168. 6.13/
                                    

其他的過程與使用串口作為連接端口時的設(shè)置過程相同。

注意:盡管可以使用以太網(wǎng)口作為kgdb的調(diào)試端口,使用串口作為連接端口更加簡單易行,,kgdb項目組推薦使用串口作為調(diào)試端口,。

2.2.4 模塊的調(diào)試方法

內(nèi)核可加載模塊的調(diào)試具有其特殊性。由于內(nèi)核模塊中各段的地址是在模塊加載進內(nèi)核的時候才最終確定的,,所以develop機的gdb無法得到各種符號地址信息,。所以,使用kgdb調(diào)試模塊所需要解決的一個問題是,,需要通過某種方法獲得可加載模塊的最終加載地址信息,,并把這些信息加入到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個段的地址:.text,、.rodata、.data,、.bss,。在development機上將以上地址信息加入到gdb中,這樣就可以進行模塊功能的測試了。


(gdb) Add-symbol-file hello.o 0xc88d8060 -s .data 0xc88d80a0 -s
                                    .rodata 0xc88d80a0 -s .bss 0x c88d833c
                                    

這種方法也存在一定的不足,,它不能調(diào)試模塊初始化的代碼,,因為此時模塊初始化代碼已經(jīng)執(zhí)行過了。而如果不執(zhí)行模塊的加載又無法獲得模塊插入地址,,更不可能在模塊初始化之前設(shè)置斷點了,。對于這種調(diào)試要求可以采用以下替代方法。

在target機上用上述方法得到模塊加載的地址信息,,然后再用rmmod卸載模塊,。在development機上將得到的模塊地址信息導入到gdb環(huán)境中,在內(nèi)核代碼的調(diào)用初始化代碼之前設(shè)置斷點,。這樣,,在target機上再次插入模塊時,代碼將在執(zhí)行模塊初始化之前停下來,,這樣就可以使用gdb命令調(diào)試模塊初始化代碼了,。

另外一種調(diào)試模塊初始化函數(shù)的方法是:當插入內(nèi)核模塊時,內(nèi)核模塊機制將調(diào)用函數(shù)sys_init_module(kernel/modle.c)執(zhí)行對內(nèi)核模塊的初始化,,該函數(shù)將調(diào)用所插入模塊的初始化函數(shù),。程序代碼片斷如下:


……	……
                                    if (mod->init != NULL)
                                    ret = mod->init();
                                    ……	……
                                    

在該語句上設(shè)置斷點,也能在執(zhí)行模塊初始化之前停下來,。

II,、在Linux 2.6.x內(nèi)核中的內(nèi)核模塊調(diào)試方法

Linux 2.6之后的內(nèi)核中,,由于module-init-tools工具的更改,insmod命令不再支持-m參數(shù),,只有采取其他的方法來獲取模塊加載到內(nèi)核的地址,。通過分析ELF文件格式,我們知道程序中各段的意義如下:

.text(代碼段):用來存放可執(zhí)行文件的操作指令,,也就是說是它是可執(zhí)行程序在內(nèi)存種的鏡像,。

.data(數(shù)據(jù)段):數(shù)據(jù)段用來存放可執(zhí)行文件中已初始化全局變量,也就是存放程序靜態(tài)分配的變量和全局變量,。

.bss(BSS段):BSS段包含了程序中未初始化全局變量,,在內(nèi)存中 bss段全部置零。

.rodata(只讀段):該段保存著只讀數(shù)據(jù),,在進程映象中構(gòu)造不可寫的段,。

通過在模塊初始化函數(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);
                                    

這里,,通過在模塊的初始化函數(shù)中添加一段簡單的程序,使模塊在加載時打印出在內(nèi)核中的加載地址,。.rodata段的地址可以通過執(zhí)行命令readelf -e hello.ko,,取得.rodata在文件中的偏移量并加上段的align值得出。

為了使讀者能夠更好地進行模塊的調(diào)試,,kgdb項目還發(fā)布了一些腳本程序能夠自動探測模塊的插入并自動更新gdb中模塊的符號信息,。這些腳本程序的工作原理與前面解釋的工作過程相似,更多的信息請閱讀參考資料[4],。

2.2.5 硬件斷點

kgdb提供對硬件調(diào)試寄存器的支持,。在kgdb中可以設(shè)置三種硬件斷點:執(zhí)行斷點(Execution Breakpoint)、寫斷點(Write Breakpoint),、訪問斷點(Access Breakpoint)但不支持I/O訪問的斷點,。目前,kgdb對硬件斷點的支持是通過宏來實現(xiàn)的,,最多可以設(shè)置4個硬件斷點,,這些宏的用法如下:



在有些情況下,硬件斷點的使用對于內(nèi)核的調(diào)試是非常方便的,。有關(guān)硬件斷點的定義和具體的使用說明見參考資料[4]

,。

2.3.在VMware中搭建調(diào)試環(huán)境

kgdb調(diào)試環(huán)境需要使用兩臺微機分別充當development機和target機,使用VMware后我們只使用一臺計算機就可以順利完成kgdb調(diào)試環(huán)境的搭建,。以windows下的環(huán)境為例,創(chuàng)建兩臺虛擬機,,一臺作為開發(fā)機,,一臺作為目標機。

2.3.1虛擬機之間的串口連接

虛擬機中的串口連接可以采用兩種方法。一種是指定虛擬機的串口連接到實際的COM上,,例如開發(fā)機連接到COM1,,目標機連接到COM2,然后把兩個串口通過串口線相連接,。另一種更為簡便的方法是:在較高一些版本的VMware中都支持把串口映射到命名管道,,把兩個虛擬機的串口映射到同一個命名管道。例如,,在兩個虛擬機中都選定同一個命名管道 \\.\pipe\com_1,指定target機的COM口為server端,,并選擇"The other end is a virtual machine"屬性;指定development機的COM口端為client端,,同樣指定COM口的"The other end is a virtual machine"屬性,。對于IO mode屬性,在target上選中"Yield CPU on poll"復(fù)選擇框,,development機不選,。這樣,可以無需附加任何硬件,,利用虛擬機就可以搭建kgdb調(diào)試環(huán)境,。即降低了使用kgdb進行調(diào)試的硬件要求,也簡化了建立調(diào)試環(huán)境的過程,。



2.3.2 VMware的使用技巧

VMware虛擬機是比較占用資源的,,尤其是象上面那樣在Windows中使用兩臺虛擬機。因此,,最好為系統(tǒng)配備512M以上的內(nèi)存,,每臺虛擬機至少分配128M的內(nèi)存。這樣的硬件要求,,對目前主流配置的PC而言并不是過高的要求,。出于系統(tǒng)性能的考慮,在VMware中盡量使用字符界面進行調(diào)試工作,。同時,,Linux系統(tǒng)默認情況下開啟了sshd服務(wù),建議使用SecureCRT登陸到Linux進行操作,,這樣可以有較好的用戶使用界面,。

2.3.3 在Linux下的虛擬機中使用kgdb

對于在Linux下面使用VMware虛擬機的情況,筆者沒有做過實際的探索,。從原理上而言,,只需要在Linux下只要創(chuàng)建一臺虛擬機作為target機,開發(fā)機的工作可以在實際的Linux環(huán)境中進行,,搭建調(diào)試環(huán)境的過程與上面所述的過程類似,。由于只需要創(chuàng)建一臺虛擬機,,所以使用Linux下的虛擬機搭建kgdb調(diào)試環(huán)境對系統(tǒng)性能的要求較低。(vmware已經(jīng)推出了Linux下的版本)還可以在development機上配合使用一些其他的調(diào)試工具,,例如功能更強大的cgdb,、圖形界面的DDD調(diào)試器等,以方便內(nèi)核的調(diào)試工作,。



2.4 kgdb的一些特點和不足

使用kgdb作為內(nèi)核調(diào)試環(huán)境最大的不足在于對kgdb硬件環(huán)境的要求較高,,必須使用兩臺計算機分別作為target和development機。盡管使用虛擬機的方法可以只用一臺PC即能搭建調(diào)試環(huán)境,,但是對系統(tǒng)其他方面的性能也提出了一定的要求,,同時也增加了搭建調(diào)試環(huán)境時復(fù)雜程度。另外,,kgdb內(nèi)核的編譯,、配置也比較復(fù)雜,需要一定的技巧,,筆者當時做的時候也是費了很多周折,。當調(diào)試過程結(jié)束后時,還需要重新制作所要發(fā)布的內(nèi)核,。使用kgdb并不能進行全程調(diào)試,,也就是說kgdb并不能用于調(diào)試系統(tǒng)一開始的初始化引導過程。

不過,,kgdb是一個不錯的內(nèi)核調(diào)試工具,,使用它可以進行對內(nèi)核的全面調(diào)試,甚至可以調(diào)試內(nèi)核的中斷處理程序,。如果在一些圖形化的開發(fā)工具的幫助下,,對內(nèi)核的調(diào)試將更方便。





回頁首


3. 使用SkyEye構(gòu)建Linux內(nèi)核調(diào)試環(huán)境

SkyEye是一個開源軟件項目(OPenSource Software),SkyEye項目的目標是在通用的Linux和Windows平臺上模擬常見的嵌入式計算機系統(tǒng),。SkyEye實現(xiàn)了一個指令級的硬件模擬平臺,,可以模擬多種嵌入式開發(fā)板,支持多種CPU指令集,。SkyEye 的核心是 GNU 的 gdb 項目,,它把gdb和 ARM Simulator很好地結(jié)合在了一起。加入ARMulator 的功能之后,,它就可以來仿真嵌入式開發(fā)板,,在它上面不僅可以調(diào)試硬件驅(qū)動,還可以調(diào)試操作系統(tǒng),。Skyeye項目目前已經(jīng)在嵌入式系統(tǒng)開發(fā)領(lǐng)域得到了很大的推廣,。

3.1 SkyEye的安裝和μcLinux內(nèi)核編譯

3.1.1 SkyEye的安裝

SkyEye的安裝不是本文要介紹的重點,目前已經(jīng)有大量的資料對此進行了介紹,。有關(guān)SkyEye的安裝與使用的內(nèi)容請查閱參考資料[11],。由于skyeye面目主要用于嵌入式系統(tǒng)領(lǐng)域,,所以在skyeye上經(jīng)常使用的是μcLinux系統(tǒng),當然使用Linux作為skyeye上運行的系統(tǒng)也是可以的,。由于介紹μcLinux 2.6在skyeye上編譯的相關(guān)資料并不多,所以下面進行詳細介紹,。

3.1.2 μcLinux 2.6.x的編譯

要在SkyEye中調(diào)試操作系統(tǒng)內(nèi)核,,首先必須使被調(diào)試內(nèi)核能在SkyEye所模擬的開發(fā)板上正確運行。因此,,正確編譯待調(diào)試操作系統(tǒng)內(nèi)核并配置SkyEye是進行內(nèi)核調(diào)試的第一步,。下面我們以SkyEye模擬基于Atmel AT91X40的開發(fā)板,并運行μcLinux 2.6為例介紹SkyEye的具體調(diào)試方法,。

I,、安裝交叉編譯環(huán)境

先安裝交叉編譯器。盡管在一些資料中說明使用工具鏈arm-elf-tools-20040427.sh ,但是由于arm-elf-xxx與arm-linux-xxx對宏及鏈接處理的不同,,經(jīng)驗證明使用arm-elf-xxx工具鏈在鏈接vmlinux的最后階段將會出錯,。所以這里我們使用的交叉編譯工具鏈是:arm-uclinux-tools-base-gcc3.4.0-20040713.sh,關(guān)于該交叉編譯工具鏈的下載地址請參見[6],。注意以下步驟最好用root用戶來執(zhí)行,。


[root@lisl tmp]#chmod +x  arm-uclinux-tools-base-gcc3.4.0-20040713.sh
                                    [root@lisl tmp]#./arm-uclinux-tools-base-gcc3.4.0-20040713.sh
                                    

安裝交叉編譯工具鏈之后,請確保工具鏈安裝路徑存在于系統(tǒng)PATH變量中,。

II,、制作μcLinux內(nèi)核

得到μcLinux發(fā)布包的一個最容易的方法是直接訪問uClinux.org站點[7]。該站點發(fā)布的內(nèi)核版本可能不是最新的,,但你能找到一個最新的μcLinux補丁以及找一個對應(yīng)的Linux內(nèi)核版本來制作一個最新的μcLinux內(nèi)核,。這里,將使用這種方法來制作最新的μcLinux內(nèi)核,。目前(筆者記錄編寫此文章時),,所能得到的發(fā)布包的最新版本是uClinux-dist.20041215.tar.gz。

下載uClinux-dist.20041215.tar.gz,,文件的下載地址請參見[7],。

下載linux-2.6.9-hsc0.patch.gz,文件的下載地址請參見[8],。

下載linux-2.6.9.tar.bz2,,文件的下載地址請參見[9]。

現(xiàn)在我們得到了整個的linux-2.6.9源代碼,,以及所需的內(nèi)核補丁,。請準備一個有2GB空間的目錄里來完成以下制作μcLinux內(nèi)核的過程。


[root@lisl tmp]# tar -jxvf uClinux-dist-20041215.tar.bz2
                                    [root@lisl uClinux-dist]# tar -jxvf  linux-2.6.9.tar.bz2
                                    [root@lisl uClinux-dist]# gzip -dc linux-2.6.9-hsc0.patch.gz | patch -p0
                                    

或者使用:


[root@lisl uClinux-dist]# gunzip linux-2.6.9-hsc0.patch.gz
                                    [root@lisl uClinux-dist]patch -p0 < linux-2.6.9-hsc0.patch
                                    

執(zhí)行以上過程后,,將在linux-2.6.9/arch目錄下生成一個補丁目錄-armnommu,。刪除原來μcLinux目錄里的linux-2.6.x(即那個linux-2.6.9-uc0),,并將我們打好補丁的Linux內(nèi)核目錄更名為linux-2.6.x。


[root@lisl uClinux-dist]# rm -rf linux-2.6.x/
                                    [root@lisl uClinux-dist]# mv linux-2.6.9 linux-2.6.x
                                    

III,、配置和編譯μcLinux內(nèi)核

因為只是出于調(diào)試μcLinux內(nèi)核的目的,,這里沒有生成uClibc庫文件及romfs.img文件。在發(fā)布μcLinux時,,已經(jīng)預(yù)置了某些常用嵌入式開發(fā)板的配置文件,,因此這里直接使用這些配置文件,過程如下:


[root@lisl uClinux-dist]# cd linux-2.6.x
                                    [root@lisl linux-2.6.x]#make ARCH=armnommu CROSS_COMPILE=arm-uclinux- atmel_
                                    deconfig
                                    

atmel_deconfig文件是μcLinux發(fā)布時提供的一個配置文件,,存放于目錄linux-2.6.x /arch/armnommu/configs/中,。


[root@lisl linux-2.6.x]#make ARCH=armnommu CROSS_COMPILE=arm-uclinux-
                                    oldconfig
                                    

下面編譯配置好的內(nèi)核:


[root@lisl linux-2.6.x]# make ARCH=armnommu CROSS_COMPILE=arm-uclinux- v=1
                                    

一般情況下,編譯將順利結(jié)束并在Linux-2.6.x/目錄下生成未經(jīng)壓縮的μcLinux內(nèi)核文件vmlinux,。需要注意的是為了調(diào)試μcLinux內(nèi)核,,需要打開內(nèi)核編譯的調(diào)試選項-g,使編譯后的內(nèi)核帶有調(diào)試信息,。打開編譯選項的方法可以選擇:

"Kernel debugging->Compile the kernel with debug info"后將自動打開調(diào)試選項,。也可以直接修改linux-2.6.x目錄下的Makefile文件,為其打開調(diào)試開關(guān),。方法如下:,。


CFLAGS  += -g
                                    

最容易出現(xiàn)的問題是找不到arm-uclinux-gcc命令的錯誤,主要原因是PATH變量中沒有包含arm-uclinux-gcc命令所在目錄,。在arm-linux-gcc的缺省安裝情況下,,它的安裝目錄是/root/bin/arm-linux-tool/,使用以下命令將路徑加到PATH環(huán)境變量中,。


Export PATH=$PATH:/root/bin/arm-linux-tool/bin
                                    

IV,、根文件系統(tǒng)的制作

Linux內(nèi)核在啟動的時的最后操作之一是加載根文件系統(tǒng)。根文件系統(tǒng)中存放了嵌入式系統(tǒng)使用的所有應(yīng)用程序,、庫文件及其他一些需要用到的服務(wù),。出于文章篇幅的考慮,這里不打算介紹根文件系統(tǒng)的制作方法,,讀者可以查閱一些其他的相關(guān)資料,。值得注意的是,由配置文件skyeye.conf指定了裝載到內(nèi)核中的根文件系統(tǒng),。

3.2 使用SkyEye調(diào)試

編譯完μcLinux內(nèi)核后,,就可以在SkyEye中調(diào)試該ELF執(zhí)行文件格式的內(nèi)核了。前面已經(jīng)說過利用SkyEye調(diào)試內(nèi)核與使用gdb調(diào)試運用程序的方法相同,。

需要提醒讀者的是,,SkyEye的配置文件-skyeye.conf記錄了模擬的硬件配置和模擬執(zhí)行行為。該配置文件是SkyEye系統(tǒng)中一個及其重要的文件,很多錯誤和異常情況的發(fā)生都和該文件有關(guān),。在安裝配置SkyEye出錯時,,請首先檢查該配置文件然后再進行其他的工作。此時,,所有的準備工作已經(jīng)完成,,就可以進行內(nèi)核的調(diào)試工作了。

3.3使用SkyEye調(diào)試內(nèi)核的特點和不足

在SkyEye中可以進行對Linux系統(tǒng)內(nèi)核的全程調(diào)試,。由于SkyEye目前主要支持基于ARM內(nèi)核的CPU,,因此一般而言需要使用交叉編譯工具編譯待調(diào)試的Linux系統(tǒng)內(nèi)核。另外,,制作SkyEye中使用的內(nèi)核編譯、配置過程比較復(fù)雜,、繁瑣,。不過,當調(diào)試過程結(jié)束后無需重新制作所要發(fā)布的內(nèi)核,。

SkyEye只是對系統(tǒng)硬件進行了一定程度上的模擬,,所以在SkyEye與真實硬件環(huán)境相比較而言還是有一定的差距,這對一些與硬件緊密相關(guān)的調(diào)試可能會有一定的影響,,例如驅(qū)動程序的調(diào)試,。不過對于大部分軟件的調(diào)試,SkyEye已經(jīng)提供了精度足夠的模擬了,。

SkyEye的下一個目標是和eclipse結(jié)合,,有了圖形界面,能為調(diào)試和查看源碼提供一些方便,。





回頁首


4. 使用UML調(diào)試Linux內(nèi)核

User-mode Linux(UML)簡單說來就是在Linux內(nèi)運行的Linux,。該項目是使Linux內(nèi)核成為一個運行在 Linux 系統(tǒng)之上單獨的、用戶空間的進程,。UML并不是運行在某種新的硬件體系結(jié)構(gòu)之上,,而是運行在基于 Linux 系統(tǒng)調(diào)用接口所實現(xiàn)的虛擬機。正是由于UML是一個將Linux作為用戶空間進程運行的特性,,可以使用UML來進行操作系統(tǒng)內(nèi)核的調(diào)試,。有關(guān)UML的介紹請查閱參考資料[10]、[12],。

4.1 UML的安裝與調(diào)試

UML的安裝需要一臺運行Linux 2.2.15以上,,或者2.3.22以上的I386機器。對于2.6.8及其以前版本的UML,,采用兩種形式發(fā)布:一種是以RPM包的形式發(fā)布,,一種是以源代碼的形式提供UML的安裝。按照UML的說明,,以RPM形式提供的安裝包比較陳舊且會有許多問題,。以二進制形式發(fā)布的UML包并不包含所需要的調(diào)試信息,,這些代碼在發(fā)布時已經(jīng)做了程度不同的優(yōu)化。所以,,要想利用UML調(diào)試Linux系統(tǒng)內(nèi)核,,需要使用最新的UML patch代碼和對應(yīng)版本的Linux內(nèi)核編譯、安裝UML,。完成UML的補丁之后,,會在arch目錄下產(chǎn)生一個um目錄,主要的UML代碼都放在該目錄下,。

從2.6.9版本之后(包含2.6.9版本的Linux),,User-Mode Linux已經(jīng)隨Linux內(nèi)核源代碼樹一起發(fā)布,它存放于arch/um目錄下,。

編譯好UML的內(nèi)核之后,,直接使用gdb運行已經(jīng)編譯好的內(nèi)核即可進行調(diào)試。

4.2使用UML調(diào)試系統(tǒng)內(nèi)核的特點和不足

目前,,用戶模式 Linux 虛擬機也存在一定的局限性,。由于UML虛擬機是基于Linux系統(tǒng)調(diào)用接口的方式實現(xiàn)的虛擬機,所以用戶模式內(nèi)核不能訪問主機系統(tǒng)上的硬件設(shè)備,。因此,,UML并不適合于調(diào)試那些處理實際硬件的驅(qū)動程序。不過,,如果所編寫的內(nèi)核程序不是硬件驅(qū)動,,例如Linux文件系統(tǒng)、協(xié)議棧等情況,,使用UML作為調(diào)試工具還是一個不錯的選擇,。





回頁首


5. 內(nèi)核調(diào)試配置選項

為了方便調(diào)試和測試代碼,內(nèi)核提供了許多與內(nèi)核調(diào)試相關(guān)的配置選項,。這些選項大部分都在內(nèi)核配置編輯器的內(nèi)核開發(fā)(kernel hacking)菜單項中,。在內(nèi)核配置目錄樹菜單的其他地方也還有一些可配置的調(diào)試選項,下面將對他們作一定的介紹,。

Page alloc debugging :CONFIG_DEBUG_PAGEALLOC:

不使用該選項時,,釋放的內(nèi)存頁將從內(nèi)核地址空間中移出。使用該選項后,,內(nèi)核推遲移出內(nèi)存頁的過程,,因此能夠發(fā)現(xiàn)內(nèi)存泄漏的錯誤。

Debug memory allocations :CONFIG_DEBUG_SLAB:

該打開該選項時,,在內(nèi)核執(zhí)行內(nèi)存分配之前將執(zhí)行多種類型檢查,,通過這些類型檢查可以發(fā)現(xiàn)諸如內(nèi)核過量分配或者未初始化等錯誤。內(nèi)核將會在每次分配內(nèi)存前后時設(shè)置一些警戒值,如果這些值發(fā)生了變化那么內(nèi)核就會知道內(nèi)存已經(jīng)被操作過并給出明確的提示,,從而使各種隱晦的錯誤變得容易被跟蹤,。

Spinlock debugging :CONFIG_DEBUG_SPINLOCK:

打開此選項時,內(nèi)核將能夠發(fā)現(xiàn)spinlock未初始化及各種其他的錯誤,能用于排除一些死鎖引起的錯誤,。

Sleep-inside-spinlock checking:CONFIG_DEBUG_SPINLOCK_SLEEP:

打開該選項時,,當spinlock的持有者要睡眠時會執(zhí)行相應(yīng)的檢查。實際上即使調(diào)用者目前沒有睡眠,,而只是存在睡眠的可能性時也會給出提示,。

Compile the kernel with debug info :CONFIG_DEBUG_INFO:

打開該選項時,編譯出的內(nèi)核將會包含全部的調(diào)試信息,,使用gdb時需要這些調(diào)試信息,。

Stack utilization instrumentation :CONFIG_DEBUG_STACK_USAGE:

該選項用于跟蹤內(nèi)核棧的溢出錯誤,一個內(nèi)核棧溢出錯誤的明顯的現(xiàn)象是產(chǎn)生oops錯誤卻沒有列出系統(tǒng)的調(diào)用棧信息,。該選項將使內(nèi)核進行棧溢出檢查,,并使內(nèi)核進行棧使用的統(tǒng)計。

Driver Core verbose debug messages:CONFIG_DEBUG_DRIVER:

該選項位于"Device drivers-> Generic Driver Options"下,,打開該選項使得內(nèi)核驅(qū)動核心產(chǎn)生大量的調(diào)試信息,并將他們記錄到系統(tǒng)日志中,。

Verbose SCSI error reporting (kernel size +=12K) :CONFIG_SCSI_CONSTANTS:

該選項位于"Device drivers/SCSI device support"下,。當SCSI設(shè)備出錯時內(nèi)核將給出詳細的出錯信息。

Event debugging:CONFIG_INPUT_EVBUG:

打開該選項時,,會將輸入子系統(tǒng)的錯誤及所有事件都輸出到系統(tǒng)日志中,。該選項在產(chǎn)生了詳細的輸入報告的同時,也會導致一定的安全問題,。

以上內(nèi)核編譯選項需要讀者根據(jù)自己所進行的內(nèi)核編程的實際情況,,靈活選取。在使用以上介紹的三種源代碼級的內(nèi)核調(diào)試工具時,,一般需要選取CONFIG_DEBUG_INFO選項,,以使編譯的內(nèi)核包含調(diào)試信息。





回頁首


6. 總結(jié)

上面介紹了一些調(diào)試Linux內(nèi)核的方法,,特別是詳細介紹了三種源代碼級的內(nèi)核調(diào)試工具,,以及搭建這些內(nèi)核調(diào)試環(huán)境的方法,讀者可以根據(jù)自己的情況從中作出選擇,。

調(diào)試工具(例如gdb)的運行都需要操作系統(tǒng)的支持,,而此時內(nèi)核由于一些錯誤的代碼而不能正確執(zhí)行對系統(tǒng)的管理功能,所以對內(nèi)核的調(diào)試必須采取一些特殊的方法進行,。以上介紹的三種源代碼級的調(diào)試方法,,可以歸納為以下兩種策略:

I、為內(nèi)核增加調(diào)試Stub,利用調(diào)試Stub進行遠程調(diào)試,,這種調(diào)試策略需要target及development機器才能完成調(diào)試任務(wù),。

II、將虛擬機技術(shù)與調(diào)試工具相結(jié)合,,使Linux內(nèi)核在虛擬機中運行從而利用調(diào)試器對內(nèi)核進行調(diào)試,。這種策略需要制作適合在虛擬機中運行的系統(tǒng)內(nèi)核。

由不同的調(diào)試策略決定了進行調(diào)試時不同的工作原理,,同時也形成了各種調(diào)試方法不同的軟硬件需求和各自的特點,。

另外,需要說明的是內(nèi)核調(diào)試能力的掌握很大程度上取決于經(jīng)驗和對整個操作系統(tǒng)的深入理解,。對系統(tǒng)內(nèi)核的全面深入的理解,,將能在很大程度上加快對Linux系統(tǒng)內(nèi)核的開發(fā)和調(diào)試。

對系統(tǒng)內(nèi)核的調(diào)試技術(shù)和方法絕不止上面介紹所涉及的內(nèi)容,,這里只是介紹了一些經(jīng)??吹胶吐牭椒椒āT贚inux內(nèi)核向前發(fā)展的同時,,內(nèi)核的調(diào)試技術(shù)也在不斷的進步,。希望以上介紹的一些方法能對讀者開發(fā)和學習Linux有所幫助。





回頁首


參考資料

[1] http://oss./projects/kdb/

[2] http://www.ibm.com/developerworks/cn/linux/sdk/l-debug/index.html

[3] http://www.ibm.com/developerworks/cn/linux/l-kdbug/

[4] http://www.ibm.com/developerworks/cn/linux/l-kprobes.html

[5] http://kgdb./downloads.htm

[6] ftp://166.111.68.183

[8] http://www./pub/uClinux/dist/

[9] http://opensrc.sec.samsung.com/download/linux-2.6.9-hsc0.patch.gz

[10] http:// www.

[11] http://user-mode-linux./

[12] http://www.ibm.com/developerworks/cn/linux/l-skyeye/part1/

[13] http://www.ibm.com/developerworks/cn/views/linux/tutorials.jsp?cv_doc_id=84978





回頁首


參考文獻

[1]Robert Love Linux kernel development機械工業(yè)出版社

[2]陳渝 源代碼開發(fā)的嵌入式系統(tǒng)軟件分析與實踐 北京航空航天大學出版社

[3]Alessandro Rubini Linux device driver 2se Edition O'Reilly

[4]Jonathan Corbet Linux device driver 3rd Edition O'Reilly

[5]李善平 Linux內(nèi)核源代碼分析大全 機械工業(yè)出版社



作者簡介

 

李樹雷,,清華大學計算機系碩士研究生,,主要從事操作系統(tǒng)與中間件的研究。通過[email protected] 可以跟他聯(lián)系


 

陳渝, 清華大學,,通過 [email protected] 可以和他聯(lián)系,。






    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多