《電子技術應用》
您所在的位置:首頁 > 嵌入式技術 > 設計應用 > kgdb調試Linux內核的剖析與改進
kgdb調試Linux內核的剖析與改進
李紅衛1 李翠萍1 韓紅宇2
1. 常州江蘇技術師范學院(213001) ; 2. 阜新遼寧工程技術大學(123000)
摘要: 在Linux內核中加入kgdb,通過開發機上的gdb對目標機上的內核進行源代碼級的調試技術。
Abstract:
Key words :

摘   要: 在Linux內核中加入kgdb,通過開發機上的gdb對目標機上的內核進行源代碼級的調試技術。
關鍵詞: 遠程調試  kgdb  串口通信協議  異常處理

  操作系統的內核調試器除完成一般的調試功能外,還必須工作在內核中。因此,內核調試器與用戶級的調試器有很大的區別。在Linux系統中,對內核的調試有很多種方法,例如:可在內核中插入printk( )函數,將調試信息輸出,然后針對輸出的信息進行分析;可以使用/proc文件系統對內核進行分析;可以利用strace命令對系統調用進行分析。但這些方法都不能直接對內核源代碼級進行調試。因此,本文介紹一種在內核源代碼中插入kgdb(Kernel GNU Debuger,GNU內核調試器),通過開發機上的gdb調試器對運行于目標機上的內核進行源代碼級調試的技術。
1  kgdb調試內核的實現原理
1.1 通信協議
  kgdb提供了一種使用gdb調試Linux內核的機制。使用kgdb調試內核需要二臺機器,一臺作為開發機,另一臺作為目標機,通過串口將它們連接起來。在將要調試的內核中插入kgdb,重新編譯內核,使其運行在目標機上。而gdb在開發機上運行,gdb通過串口與要調試的內核進行通信,對目標機上的內核進行控制,從而實現遠程調試內核的目的。
  要使gdb有效地控制調試目標機上的內核,必須與目標機上的kgdb約定相互的通信協議。而gdb本身帶有一個遠程串行通信協議,所以在kgdb中包含相同的協議即可實現開發機與目標機之間的通信。
  開發機上的gdb可以向目標機發送一些命令數據包,如果kgdb能夠實現g、G、m、M、c和s等主要命令,則在使用gdb對目標機上的內核進行調試時就像在本機上調試程序一樣。這六個命令的功能描述如下:
  g:查看CPU寄存器的值;
  G:設置CPU寄存器的值;
  maddr,count:從addr位置開始讀count個字節的數據;
  Maddr,count:從addr位置開始寫count個字節的數據;
  c/caddr:在當前位置上繼續執行程序或從地址addr處開始執行;
  s/saddr:單步執行當前的指令,或者執行到指定的addr位置。
1.2 kgdb遠程調試技術分析
  遠程調試常采用插樁(stub)的方法實現。在目標操作系統內和開發機上的調試器內分別加入某些功能模塊(如通信模塊和異常處理模塊等),二者互通信息來完成調試工作,這些功能模塊統稱為插樁。gdb本身帶有這些功能模塊,所以在調試內核時,只需要在內核中加入stub插樁模塊即可實現用gdb遠程調試內核的目的。gdb遠程調試器的結構如圖1所示。


  通過對kgdb源程序進行分析可知,kgdb主要有二大模塊:一個是初始化模塊,完成初始化過程,接管所有異常、設置串口通信等低層實現;另一個是控制模塊,實現通信,對接收到的信息包進行解析并執行,對應答包進行打包發送。
1.2.1 kgdb初始化模塊的實現
  在Linux啟動時要調用start_kernel( )函數。該函數調用一系列初始化函數,完成系統初始化工作。kgdb通過對該函數進行修改,使其在內核初始化工作完成后將控制權交給插樁程序kgdb,由插樁程序完成調試內核的任務。
  (1)設置異常中斷處理程序入口
  kgdb插樁模塊要對目標機上被調試的程序進行控制,必須對目標機上所發生的所有異常進行統一管理。在上述Linux啟動過程中,若要執行start_kernel( )函數,則應在該函數中調用trap_init( )函數設置各種入口地址,如異常事件處理程序入口、系統調用入口等。其中trap0~trap19為各種異常事件錯誤入口,如被0除、溢出、存儲器越界等。為了使gdb能夠捕獲這些發生在目標機上的異常,kgdb要對各個需要捕獲的異常處理函數進行修改。當發生異常時使異常處理事件進入異常處理函數handle_excepton( ),han-
dle_excepton( )就會將目標機上發生的異常以信號“Sxx”的方式通知主機上的gdb,主機上的gdb即可知道目標機上發生的異常。
  (2)串口初始化
  將所有異常入口地址進行修改后,應該對串口進行初始化,并設置linux_debug_traps指針變量的值,使其指向異常處理程序入口地址。此工作結束后,kgdb就接管所有發生在目標機上的異常事件。
1.2.2 kgdb控制模塊的實現
  kgdb控制模塊主要完成對協議的解析和執行,這些功能都在handle_exception( )函數中實現。通過該函數可實現在內核中設置斷點、單步執行代碼和監視變量的值。
  handle_exception( )函數首先判斷CPU是否處于虛擬86模式或用戶態,若是則返回。由此可見,kgdb只對內核態程序進行調試。其次判斷是否發生讀/寫內存異常,若是則為讀/寫內存操作設置一個有效內存地址,返回重試,否則向主機發送信息“Sxx”,其中xx是發生異常的信號量值,即通知開發機上的gdb在目標機上發生了什么樣的異常。接下來handle_exception( )接收來自主機的調試命令,對來自主機的命令進行解析并完成命令的執行,在kgdb中主要完成的調試命令有m、M、g、G、s、c。當這些命令執行完后還需要向開發機發送應答信息,報告完成命令的情況。此函數的流程如圖2所示。


  (1)g讀寄存器命令的實現。當系統發生異常時,系統首先將發生異常的進程的CPU狀態保存在核心堆棧中。用g命令讀寄存器時,實際上就是從核心棧中去取,但gdb所規定的寄存器的排列與Linux內核中對寄存器的排列順序不一致,需要進行寄存器的轉換。通過函數regs_to_gdb_regs(gdb_regs,&regs)實現轉換,轉換結束后將寄存器的值打包送回主機。
  (2)G寫寄存器命令的實現。對接收到的數據包進行解包,把結果放入gdb_regs結構中,再通過gdb_regs_to_regs(gdb_regs,&regs)函數將接收到的寄存器的值進行轉換,并放入核心棧中,通過對核心棧的修改得到修改寄存器的目標。
  (3)讀/寫內存命令的實現。對內存的讀寫有可能再次發生讀寫內存異常。例如對一個非法的地址進行讀寫的kgdb解決方法如下:
  kgdb通過函數int get_char(char?鄢char)讀內存,通過函數void set_char(char?鄢addr,int val)寫內存。kgdb在讀/寫不確定的內存時,通過二個變量來判斷是否讀/寫內存發生異常。一個變量是kgdb_memerr_expected,標志是否讀寫不確定的內存;另一個變量是kgdb_memerr,標志在讀寫內存時是否發生了異常。這樣,對不確定內存的讀/寫過程可分三步。
  第一步:對這二個變量賦值。將kgdb_memerr_expected賦值為1,表示對不確定內存進行讀/寫操作。對kgdb_me-merr賦值為0,表示在讀/寫內存時沒有發生異常。
  第二步:對內存進行讀寫操作。若讀寫地址是非法地址,則進入異常處理程序,轉第三步。若正確,則返回,并清變量kgdb_memerr_expected為0,表示讀寫內存結束。
  第三步:進入異常處理程序中。首先要判斷kgdb_me-merr_expected是否為1。若是1,則說明對內存讀/寫時發生了異常。這時先清kgdb_ memerr_expected為0,置kgdb_memerr為1,標志在讀/寫內存時發生了異常,并為讀/寫內存設置一個有效地址。這個有效地址是一個可讀/寫的內存地址,可以對其進行操作,操作的結果是無效的。
  (4)s單步命令的實現。基于x86 CPU的體系結構支持單步執行,但它只是指令級的單步,而不是源代碼級的單步。這里的s命令是實現指令級的單步,它的處理方法是:將產生異常的進程標志寄存器的陷阱標志位TF置1,異常中斷處理程序結束返回到異常點繼續執行。因TF標志位為1,所以程序執行一條指令后又進入異常處理程序。主機處的gdb利用此命令實現源代碼級的單步跟蹤。
  (5)c繼續運行命令的實現。異常處理程序結束,恢復異常處的CPU狀態,使程序繼續執行。
2  kgdb插樁技術的不足與改進
  現有的kgdb不具有使目標程序進行調試模式和正常運行模式的切換功能。目前的處理方法是:當程序調試好后,將kgdb卸下,重新編譯程序。當發生錯誤時再將kgdb插入目標程序中,編譯后再在目標機上調試。由此可見操作十分不便。本文提出一種新的設計思路,使目標機上運行的程序可隨時進行調試模式與正常運行模式的切換,這樣更便于調試。下面討論其實現方法。
   (1)在目標機方:通過對kgdb源代碼分析可知,在進入各異常函數中,首先判斷指向gdb_debug_hook類型的函數指針變量linux_debug_hook是否為空。若不為空則執行異常處理函數handle_exception( ),否則,執行原異常處理程序。這樣通過修改這個變量的值,即可實現調試模式與正常運行模式的轉換。當設置linux_debug_hook為(gdb_debug_hook?鄢)NULL時,目標機程序運行在正常運行狀態;當設置linux_debug_hook為指向異常函數handle_exception( )時,則目標機程序運行在調試狀態。
   (2)在主機方:調試狀態到正常運行狀態的轉換:在kgdb中設置一個變量int stop_gdb。當主機對該變量進行賦值時,目標機上的kgdb獲取信息后,使指向函數的指針變量linux_debug_hook指向(gdb_debug_hook?鄢)NULL,然后,kgdb構造c命令并執行,使目標機上的程序脫離調試運行模式進入正常運行模式。
  主機端發送命令:set stop_gdb=1
  這條命令經過主機端的gdb解析,實際上是執行協議命令M,即寫內存命令。這樣就需要在kgdb中對M命令進行修改。
  目標端kgdb 執行M命令的算法描述如下:
  (1)向主機返回應答信息“OK”;
  (2)如果所寫地址與變量stop_gdb的地址相同,則轉(4);
  (3)執行原M命令,轉(8);
  (4)設置變量initialized為0;
  (5)設置指針變量linux_debug_hook為(gdb_debug_hook*)NULL;
  (6)構造命令c;
   (7)執行命令c,目標機上被調試的程序轉為正常運行模式;
  (8)結束。
  正常運行狀態到調試狀態的轉換:目標程序從正常運行狀態切換到調試狀態,就不像從調試狀態到正常運行狀態切換那樣對一個變量進行設置而觸發狀態的切換。因為目標機已不在主機端gdb的控制下運行,主機端的gdb與目標機端的kgdb已失去了聯系。所以要激活目標機進入調試狀態,只能使用中斷技術,利用串口中斷來激活對目標機由正常運行狀態切換到調試狀態。
  在gdb與目標機建立連接時,gdb首先要向目標機發送一個數據包$Hc-1#09,它會觸發目標機上串口中斷處理程序的執行,并判斷接收的數據包是否為“Hc-1”。若是則設置linux_debug_hook指向異常中斷處理程序handle_exception( ),并執行breakpoint( )函數,使目標機進入調試狀態。
  通過上述方法即可實現目標機上程序運行狀態的切換,使程序調試更加靈活。
3  結束語
  通過對kgdb調試技術的分析與改進,增加了調試的方法和思路。此調試技術可以應用于嵌入式系統的設計和開發中,為嵌入式開發工具增加了一種廉價而強有力的調試工具。
參考文獻
1   李善平,劉文峰.Linux內核2.4版源代碼分析大全.北京: 機械工業出版社,2002
2   李紅衛,李翠萍.嵌入式軟件的調試技術.計算機時代,2002;(8)
 

此內容為AET網站原創,未經授權禁止轉載。
主站蜘蛛池模板: 国产精品视频第一区二区三区 | 亚洲国产精品乱码一区二区三区 | 无遮挡一级毛片视频 | 国产一级黄色 | 农村偷人一级超爽毛片 | 国产精品青草久久福利不卡 | 丁香午夜 | 久草手机在线视频 | 性一级录像 | 亚洲va老文色欧美黄大片人人 | 超级在线碰 | 天堂色视频| 国产欧美日韩视频怡春院 | 午夜视频高清在线aaa | 亚洲高清免费视频 | 男女很黄很色床视频网站免 | 特黄色一级毛片 | 欧美日韩国产动漫 | 五月婷婷色综合 | 国产精品123 | 18女人免费毛片a级 18女人毛片水真多免费 | 欧美嫩freexxxhddvd | 日日操夜夜操天天操 | 国产自产视频在线观看香蕉 | 日韩在线视精品在亚洲 | 日韩精品特黄毛片免费看 | 天天干影院 | 免费看h片的网站 | 天天好比 | 九九精品免费 | 黄色a级片在线观看 | 国产亚洲精品仙踪林在线播放 | 亚洲国产成人久久笫一页 | 在线视频精品免费 | 国产成人综合网亚洲欧美在线 | 青青操国产 | 亚洲视频在线观看不卡 | 一道本高清香蕉网 | 涩涩网页 | 日韩在线视频线视频免费网站 | 欧美xxxxbbbb在线播放 |