Linux基礎系列-DEBUG

來源:互聯網
上載者:User

linux的調試包括了使用者層的調試和核心的調試,主要使用的工具就包括gdb和kgdb。

該篇著重介紹linux編程環境中,調試器的工作原理,關鍵技術,平台依賴部分的區別,較少著墨用法。如果時間充分,會touch一下multi—thread的調試

+++++++++++++++++++++++++++++++++++++++++++++++++++++++

一,debugger 工作基礎

看似神秘的debugger其實工作在一些簡單的技術上,雖然不同的平台會有一些差異,但其基本原理還是類似的,下面還是以linux為例作一下備忘錄(從一個朋友那瞭解到windows也有一個開源系統在進行,很強大,但真擔心生不逢時啊.....)吧啊:

1)ptrace。ptrace提供了一種使父進程得以監視和控制其它進程的方式,它還能夠改變子進程中的寄存器和核心映像,因而可以實現斷點調試和系統調用的跟蹤。使用ptrace,你可以在使用者層攔截和修改系統調用(sys call)。

2)ELF format。ELF檔案格式提供了很多對debug有用的資訊。

3)DWARF format。這是調試資訊存放在二進位檔案中的一種格式,和ELF不是一個層次的。當我們在編譯的時候使用-g參數後,編譯器會從源檔案中收集大量的資訊,例如變數 名、變數類型、變數所在行號、函數名、函數參數、函數的位址範圍、行號和地址的對應關係等等,然後按照一種特定的格式寫入到編譯後的檔案中。調試的時候, 調試器便從檔案中讀取並解析這些資訊,以產生人們可讀性比較強的資訊。簡單的說,調試資訊就是在機器碼和對應的原始碼之間建立一座橋樑,大大方便和提高了 偵錯工具的能力。DWARF的全稱是"Debugging With Attributed Record Formats",遵從GNU FDL授權。

4)/proc。linux的proc檔案系統中會包含很多關於運行程式的資訊。


添加一點對系統調用的解釋,也算是完成debug所必需的:作業系統提供了一種標準的服務來讓程式員實現對底層硬體和服務的控制(比如檔案系統),叫做系統調用(system calls)。當一個程式需要作系統調用的時候,它將相關參數放進系統調用相關的寄存器,然後調用非強制中斷0x80,這個中斷就像一個讓程式得以接觸到核心模式的視窗,程式將參數和系統調用號交給核心,核心來完成系統調用的執行。

 


二,debugger如何工作


在使用參數為PTRACE_TRACEME或PTRACE_ATTACH的ptrace系統調用建立調試關係之後,交付給目標程式的任何訊號(除SIGKILL之外)都將被gdb先行截獲,或在遠端偵錯中被gdbserver截獲並通知gdb。

gdb中對於訊號的處理可以通過handle signal keywords... 來進行行為設定,具體包括:

nostop/stop, noprint/print, noignore/ignor。

gdb因此有機會對訊號進行相應處理,並根據訊號的屬性決定在繼續目標程式運行時是否將之前截獲的訊號實際交付給目標程式或如何處理。

對於gdb中的訊號,這裡有兩點注意:

1),可以使用signal命令,產生一個訊號給被調試的程式,但這裡和在shell用kill想程式發訊號不同,kill發的訊號是被gdb截獲的,而signal命令發的訊號是直接發給被偵錯工具的。

2),特別注意的是,如果一個任務處於TRACING狀態後,當這個進程的接受到任何訊號(除了SIGKILL),都會使其停止,哪怕你設定了nostop,這兒從字面來看特別容易產生誤會,這也是有時候一個有很多訊號互動的程式,在gdb中運行時會變慢。

 

下面以gdb為例簡單介紹一下debugger幾個基本behaviour的實現(很多內容來源於劉東(雨絲風片)的文章):

1)run

當我們在gdb中執行run的時候,gdb將完成以下操作:

1,通過fork系統調用建立一個新進程

2,在新建立的子進程中通過ptrace執行TRACEME操作

3,在進程成中通過execv系統調用載入使用者指定的可執行檔。

0,命令響應gdb的工作模式是由外來事件來激勵的。共有兩個外來事件源,一個是標準輸入(使用者輸入的調試命令),一個是遠端連線上報的事件。

 

2) gdbsever

大部分時候我們都要在目標機上進行遠端偵錯,這時候就需要在tagert上使用到gdbsever,在host上我們繼續使用gdb串連gdbsever,進行我們的調試。
1,gdb和gdbsever之間的通訊資料格式由gdb遠程串列協議(remote serial protocol)定義。2,gdbsever的啟動方式也是相當於在target上運行一個進程,並TRACE它,再使用exec執行指定的程式。

3) breakpoint

在gdb中,大部分操作都是使用signal來驅動的。訊號也是實現斷點功能的基礎,譬如在X86平台上,向某個地址打入斷點,實際上就是往該地址寫入斷點指令INT3。目標程式運行到這條指令之後就會觸發SIGTRAP訊號,gdb捕獲到這個訊號,根據目標程式當前停止位置查詢gdb維護的斷點鏈表,若發現在該地址確實存在斷點,則可判定為斷點命中。

4) 單步

  • 指令級單步

瞭解step之前要瞭解指令級單步。所謂指令級單步就是gdb控制目標程式只運行一條指令後立即停止。指令級單步是next step等運行類調試命令的基礎。

指令級單步分為硬體單步和軟體單步兩種。硬體單步指CPU架構本身直接支援指令級單步,目標程式可以在運行一條指令之後自動停止。軟體單步指CPU不支援指令級單步,需要gdb用軟體方法來實現指令級單步。

X86,PPC都支援硬體單步。在該模式中,CPU每執行一條指令,就會產生一個單步異常,通知gdb進行處理。

arm和mips不支援硬體單步。在這種情況下,gdb採用臨時的軟體斷點來類比單步的方法。在需要執行指令的下一條指令處臨時插入一個斷點,然後讓目標程式繼續運行,它會在執行完當前指令之後遇到下一條指令處的臨時斷點,於是目標程式停止,通知gdb命中斷點,gdb再將此斷點刪除,由此來完成指令級單步的過程。

  • C代碼級單步

next命令實現C代碼級的單步,其實現機制中引入了step_range,step_range_start和step_range_end的概念。執行next命令時,gdb會計算出當前停止位置的C語句的第一條指令的地址作為step_range_start,然後計算出當前停止位置下一條的C語句的第一條指令的地址作為step_rang_end,然後控制目標程式從當前停止位置開始走指令級單步,直至PC超出step_range為止。

step命令和next命令一樣,也是實現C代碼級的單步,對於簡單語句,step完全等同於next。不同的是,若單步過程中遇到函數調用,step命令將停止在子函數的起始處,而不是將其跨越(無調試資訊的子函數除外)。

三,關鍵技術

本來還想做個介紹debug依賴的技術,但網上資源已經很豐富了,而且這些關鍵技術要做到備忘,需要的篇幅也太長了,這裡僅列出參考資源,上面有些內容也來自這些參考資源,感謝這些無私的作者。

ptrace http://blogold.chinaunix.net/u/19651/showart_362901.html

dwarf  http://hi.baidu.com/delovery/blog/item/5827f124e46a853b8744f933.html

ELF       http://cs.mipt.ru/docs/comp/eng/os/linux/howto/howto_english/elf/elf-howto.html#toc1

我還儲存了一個非常好的關於ELF文檔,我會將它放到CSDN上讓大家共用。


multi 的內容還不知道怎麼去寫抓住關鍵點,稍後補充吧。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.