《電子技術應用》
您所在的位置:首頁 > 嵌入式技術 > 業(yè)界動態(tài) > GDBstub的剖析與改進

GDBstub的剖析與改進

2008-05-27
作者:黃紅燕,史 烈

  摘 要: 討論了GDB遠程調試" title="遠程調試">遠程調試技術在調試內核、嵌入式系統(tǒng)" title="嵌入式系統(tǒng)">嵌入式系統(tǒng)中的實現(xiàn),簡要闡述GDB宿主機和GDB遠程串行協(xié)議,詳細分析GDB調試代理在內核層、應用層的各種實現(xiàn)方法,并提出了一種在不修改操作系統(tǒng)內核前提下調試應用程序" title="應用程序">應用程序的方法。這種方法可移植性強,而且消除了修改系統(tǒng)內核可能帶來的隱患,減少了因修改內核而帶來的工作量,在調試微內核操作系統(tǒng)服務的應用中非常有效。
  關鍵詞: 遠程調試 stub GDBserver KGDB 嵌入式系統(tǒng)調試


  調試是開發(fā)過程中必不可少的環(huán)節(jié),然而內核、嵌入式系統(tǒng)的調試不同于傳統(tǒng)的調試系統(tǒng)。通常嵌入式系統(tǒng)不具備使用本地調試器" title="調試器">調試器的能力,原因如下:
  (1)系統(tǒng)自身的資源有限,內存小,輸入輸出設備不能用于調試。
  (2)傳統(tǒng)的調試系統(tǒng)需要文件系統(tǒng),而嵌入式系統(tǒng)通常無文件系統(tǒng),內核調試時還不支持文件系統(tǒng)。
  (3)調試器的運行本身需要操作系統(tǒng)的支持,因此無法實現(xiàn)操作系統(tǒng)內核的調試。
  最有效的解決方法是采用遠程調試技術。遠程調試是指調試器運行的環(huán)境(主機)與被調試的系統(tǒng)(目標機)在物理上是分離的、通過串口或者網(wǎng)絡進行連接的調試技術。
  GNU免費提供的GDB擁有強大的遠程調試功能,它能夠使開發(fā)人員以遠程調試的方式單步執(zhí)行目標平臺上的程序代碼、設置斷點、查看內存,并與目標平臺交換信息。GDB遠程調試的實時、動態(tài)、方便、免費等優(yōu)點,使它逐漸成為嵌入式開發(fā)首選的調試方案。
  遠程調試系統(tǒng)由三部分組成:主機上的本地調試器、目標機上的調試代理、遠程調試協(xié)議,如圖1所示。對應GDB遠程調試系統(tǒng)的三部分為:GDB、GDBstub、GDB遠程串行協(xié)議。下面就這三部分進行分析。


1 RSP協(xié)議
  GDB RSP(Remote Serial Protocol)定義了GDB宿主機與被調試目標機進行通信時數(shù)據(jù)包的格式。信息的格式是:$數(shù)據(jù)#校驗碼。多數(shù)信息使用ASCII碼,數(shù)據(jù)由一系列的ASCII碼組成,校驗碼是由兩個16進制數(shù)組成的單字節(jié)校驗碼。接收方接收數(shù)據(jù)并校驗,若正確則回應“+”,否則回應“-”。通信的內容包括讀寫數(shù)據(jù)、控制程序運行、報告程序狀態(tài)等命令。RSP的基本命令從通信對話角度可以分為兩種:
  (1)請求
  ?:讀當前系統(tǒng)狀態(tài)
  g:讀所有寄存器
  G〈register_data〉:寫所有寄存器
  m〈address〉,〈length〉:讀內存
  M〈address〉,〈length〉:〈memory_data〉:寫內存
  c:繼續(xù)執(zhí)行
  s:單步執(zhí)行
  k:終止進程
  (2)答復
  “”:告訴GDB上次請求命令不支持。
  E:告訴GDB出錯
  OK:上次請求正確
  W〈exit_status〉:系統(tǒng)在“exit_status”狀態(tài)下退出。
  X〈signal〉:系統(tǒng)在signal信號下終止。
  S〈signal〉:系統(tǒng)在signal信號下停止。
  O:告訴GDB控制臺輸出,這也是惟一向GDB發(fā)出的命令。
2 GDB遠程調試功能
  調試內核時通常還沒有文件系統(tǒng),而且多數(shù)嵌入式系統(tǒng)由于自身資源的限制不具備文件系統(tǒng),因此將與文件系統(tǒng)有關的源文件、目標文件及符號表都存放在主機上,由主機上的調試器處理。同樣,調試用的輸入輸出設備也是由主機提供。主機上的調試器接收用戶輸入的調試命令并進行預處理,對于某些命令(如breakpoint)的處理在主機GDB上實現(xiàn),不需要與目標機通信。當然,更多的指令需要在目標機調試代理上實現(xiàn)。主機根據(jù)RSP對預處理之后的命令進行封裝,發(fā)送給目標機上的調試代理,調試代理接收命令后作相應的處理,并返回信息給主機上的調試器。
3 目標機上stub的實現(xiàn)
  目標機上stub的基本功能是與主機GDB通信,實現(xiàn)讀寫內存、寄存器,stop、continue指令。主機GDB與目標機上stub通信的通用模型如圖2。


  目標機與主機通過硬件連接,被調試部分插入stub,GDB與被調試部分通過RSP通信。根據(jù)stub所處層的不同實現(xiàn)不同層的調試,包括內核層、應用層的調試。
3.1 內核層調試模型
  內核層調試模型如圖3,將stub插入到內核可以實現(xiàn)內核的調試。Linux內核調試機制KGDB就是使用這種模式。KGDB可以分為初始化模塊和控制模塊。


3.1.1 初始化模塊
  修改異常處理" title="異常處理">異常處理函數(shù),使得異常發(fā)生時進入函數(shù)handle_exception( ),GDB就能夠捕獲這些異常。初始化后使用breakpoint( )函數(shù)將系統(tǒng)控制權直接交給GDB。KGDB對異常處理函數(shù)的修改基本上可以分為二種,這兩種方式均需先定義宏CHK_REMOTE_DEBUG:
  #define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \
  { if(linux_debug_hook!=(gdb_debug_hook*) NULL && \
    !user_mode(regs)) \
    { (*linux_debug_hook)(trapnr,signr,error_code,regs);\
      after;\
    }\
  }
  (1)改變程序的流程,以int3的處理函數(shù)為例。
  #define DO_VM86_ERROR(trapnr,signr,str,name) \
  asmlinkage void do_##name(struct pt_regs*regs,long \
  error_code) \
  { \
  CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,goto skip_trap)\
  do_trap(trapnr,signr,str,1,regs,error_code,NULL);\
  skip_trap:\
  return;\
  }
  展開DO_VM86_ERROR(3,SIGTRAP,″int3″,int3)
  asmlinkage void do_int3(struct pt_regs*regs,long
  error_code)
  { if(linux_debug_hook!=(gdb_debug_hook*)NULL&&!
  user_mode(regs))
  { (*linux_debug_hook)(3,SIGTRAP,errorcode,regs);
    goto skip_trap;
  }
  do_trap(3,SIGTRAP,″int3″,1,regs,error_code,NULL);
  skip_trap:
  return;
  }
  由以上代碼可見,進入內核調試狀態(tài)后,異常處理函數(shù)就是handle_exception( ),程序流程跳過了非調試狀態(tài)時的處理函數(shù)do_trap( )。
  (2)不改變程序的流程,以異常divide_error 的處理函數(shù)為例。
  #define DO_VM86_ERROR_INFO(trapnr,signr,str,name,sicode,siaddr) \
  asmlinkage void do_##name(struct pt_regs*regs,long error_code) \
  { ……\
  do_trap(trapnr,signr,str,1,regs,error_code,&info); \
  }
  展開DO_VM86_ERROR_INFO( 0,SIGFPE,″divide error″,
  divide_error,F(xiàn)PE_INTDIV,regs-〉eip)
  asmlinkage void do_divide_error(struct pt_regs*regs,long
  error_code)
  { if(linux_debug_hook!=(gdb_debug_hook*)NULL&&! user_mode(regs))
  { (*linux_debug_hook)(3,SIGTRAP,errorcode,regs);
  }
  do_trap(0,SIGTRAP,″divide erro″,1,regs,error_code,&info);
  }
  從以上代碼看不出調試狀態(tài)與非調試狀態(tài)的區(qū)別,可以看一下do_trap函數(shù)可能會調用的函數(shù)die( )。
  void die(const char*str,struct pt_regs*regs,long err)
  { ……
  CHK_REMOTE_DEBUG(1,SIGTRAP,err,regs,)
  ……
  do_exit(SIGSEGV);
  }
  由此可見,調試狀態(tài)下的異常處理函數(shù)還是進入了handle_exception函數(shù)。不過與上面一種異常不同之處在于:異常處理函數(shù)在調試與非調試狀態(tài)下的程序流程是相同的,handle_exception只獲取系統(tǒng)當時的狀態(tài),繼續(xù)運行的結果還是do_exit。
  雖然不是所有異常函數(shù)都是按上述兩種方法定義,但本質上都一樣。絕大多數(shù)處理函數(shù)的修改屬于第二種,因為第一種異常是為調試準備的。因此在目標機具有調試輸出設備的情況下,完全可以不修改第二種異常處理函數(shù)。因為Linux內核在非調試狀態(tài)下的異常處理函數(shù)已經(jīng)輸出必要的狀態(tài)信息、出錯信息。
3.1.2 控制模塊
  控制模塊與主機GDB通信的具體流程如圖4。KGDB只調試內核態(tài)程序。handle_exception函數(shù)首先判斷CPU是否處于VM86模式或用戶態(tài),若是則返回;然后接收GDB發(fā)來的信息,根據(jù)接收的信息作出相應的操作和回復。流程圖內的虛線框是所有GDBstub中handle_exception函數(shù)的通用流程。


3.2 應用程序調試模型
  在嵌入式Linux開發(fā)領域中調試應用程序常用調試代理工具GDBserver。其工作原理不是在被調試應用程序內編譯stub,而是把被調試程序作為GDBserver的子進程,這樣GDBserver可以利用內核提供的代碼跟蹤機制(ptrace)監(jiān)控被調試進程的運行,從而完成調試任務。此工作原理與GDB本地調試相似。其調試模型如圖5。GDBserver的工作流程是:GDBserver創(chuàng)建子進程-〉綁定跟蹤ptrace(ptrace_traceme,,)-〉從主機傳來的各種調試命令通過GDBserver轉化為各種操作需求的ptrace。如果用GDBserver進行遠程調試,需要內核操作系統(tǒng)的支持,包括子進程、代碼跟蹤機制,這樣其他嵌入式系統(tǒng)內核工作量會較大。而且ptrace也有其局限性,例如只能跟蹤子進程,在調試進程與被調試進程之間傳送一個長字的數(shù)據(jù)。使用通用的調試模式工作量會更小。如圖6,在應用程序中編譯stub,并在應用程序入口處插入斷點,程序開始將控制權交給GDB,之后的流程與內核層調試類似。


4 不修改內核前提下調試應用程序
  GDB設置斷點的方式是使用內存的讀寫,即將原指令用一個trap指令代替,使程序執(zhí)行到該指令時產(chǎn)生單步調試中斷,然后進入異常處理函數(shù),針對調試器的各種操作處理函數(shù)作出相應的操作。不同的系統(tǒng)提供不同的調試異常指令,如int3、trap2等。為了使用硬件平臺提供的斷點指令實現(xiàn)GDBstub調試功能,需要改寫這些指令異常處理函數(shù)。因此一般的調試系統(tǒng)器或調試代理都要涉及單步調試指令的處理函數(shù),需要系統(tǒng)內核的支持。上面提到的KGDB修改了異常處理函數(shù),GDBserver需要系統(tǒng)內核提供ptrace函數(shù)。這種方法存在一些不足:修改內核工作量大,移植性差。針對這些情況可以采用另一種斷點實現(xiàn)方案:在stub中定義一個設置斷點函數(shù)。
  斷點函數(shù)模擬調試異常指令,保護現(xiàn)場、調用異常處理函數(shù)、恢復現(xiàn)場并將控制權交給被調試程序。斷點函數(shù)的基本流程如下。
  #define BREAKPOINT _asm_ _volatile_(″bl ent_exception\n″)
  void debug_trap( )
  { _asm_ _volatile_(″ent_exception: \n″
    保存現(xiàn)場
  ″bl handle_exception \n″
  ″out_exception: \n″
  恢復現(xiàn)場
  );
  }
  handle_exception( )流程類似圖4中的虛線框部分,實現(xiàn)的關鍵是斷點指令的替換。斷點設置時,從GDB傳來硬件平臺提供的斷點異常指令的二進制碼,必須將此二進制碼替換成stub中新定義的BREAKPOINT二進制碼,才能進入調試異常處理函數(shù)。因此在handle_exception( )中,如果收到的請求是“M”,則需要處理數(shù)據(jù),流程如圖7。
  這種方法理論上在內核調試和應用程序調試中都可以使用,但在應用程序的調試中優(yōu)點更明顯。在寫stub時不涉及內核,在調試應用程序時不需切換到內核模式下,直接在用戶模式中即可完成。此方法也存在不足之處。為了實現(xiàn)現(xiàn)場保護,要求用戶了解系統(tǒng)內的寄存器。隨著stub本身復雜度的增加,其正確性需要更多的檢驗。
  加stub的遠程調試方法方便而有效,而且可以降低項目成本,在實際工作中得到廣泛的應用。在不修改內核前提下調試應用程序的方法已成功應用于筆者開發(fā)的微內核結構的操作系統(tǒng),為系統(tǒng)的開發(fā)應用提供了良好的調試手段。當然加stub的遠程調試方法也存在一些不足。由于stub的應用是在串口通信的基礎上,因此串口處理函數(shù)以及stub自身處理函數(shù)的正確性是確保stub安全調試的前提。
參考文獻
1 李紅衛(wèi),李翠萍.kgdb調試Linux內核的剖析與改進.微型機與應用,2004;23(10)
2 郭勝超.GDB遠程調試及其在嵌入式Linux系統(tǒng)中的應用.計算機工程與應用,2004;26(10)
3 彭進展.GRDBS:一種針對嵌入式系統(tǒng)的通用遠程調試系統(tǒng).計算機工程,2003;29(2)
4 Gatliff,Bill.Embedding with GNU:the gdb Remote Serial Protocol.Embedded Systems Programming,1999;(9):109
5 Gilmore J,Shebs S.GDB Internals:A Guild to the Internals of the GNU Debugger.Free Software Foundation Inc,1999

本站內容除特別聲明的原創(chuàng)文章之外,轉載內容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點。轉載的所有的文章、圖片、音/視頻文件等資料的版權歸版權所有權人所有。本站采用的非本站原創(chuàng)文章及圖片等內容無法一一聯(lián)系確認版權者。如涉及作品內容、版權和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當措施,避免給雙方造成不必要的經(jīng)濟損失。聯(lián)系電話:010-82306118;郵箱:aet@chinaaet.com。
主站蜘蛛池模板: 午夜亚洲国产成人不卡在线| 欧美黑人又大又粗XXXXX| 国产欧美另类久久久精品免费 | 下载一个黄色录像| 日韩在线不卡视频| 亚洲va在线va天堂成人| 欧美极度另类精品| 亚洲综合在线一区二区三区| 看全色黄大色黄大片大学生| 四虎影院黄色片| 萌白酱在线17分钟喷水视频| 国产成人久久综合热| 男女下面无遮挡一进一出| 国产肝交视频在线观看| 99久久综合精品国产| 暖暖免费观看日本版| 亚洲欧洲日本天天堂在线观看| 特级深夜a级毛片免费观看| 免费精品久久久久久中文字幕| 99爱在线精品免费观看| 疯狂的欧美乱大交| 国产乱色精品成人免费视频| 麻豆精产国品一二三产品区| 国产日产高清欧美一区| 中文天堂最新版www在线观看 | 乱中年女人伦av三区| 欧美a级黄色片| 亚洲人成自拍网站在线观看| 老师的被到爽羞羞漫画| 国产美女在线观看| 99热这里只有精品国产动漫| 奇米影视7777狠狠狠狠色| ww4545四虎永久免费地址| 婷婷影院在线观看| 一本一本久久a久久综合精品| 成人福利视频app| 中文字幕一区二区三区久久网站 | 免费A级毛片无码A∨男男| 男女肉粗暴进来120秒动态图| 免费看美女扒开腿让男人桶| 精品久久久久久无码中文字幕|