gdb這個debug工具,應該無人不知吧。服務器開發(fā)和客戶端開發(fā)人員應該都或多或少的通過這個工具排查問題。但有沒有想過它的實現原理,為什么打斷點能夠在斷點處停止運行?為什么能查看cpu寄存器?等等。我們就帶著這些疑問接著往下看。 知識鋪墊 我們都聽說過系統(tǒng)調用,這里簡單的解釋下系統(tǒng)調用的含義。操作系統(tǒng)提供了一種標準的服務來讓程序員實現對底層的硬件和服務的控制,比如申請、釋放內存,打開、關閉文件等等,這就叫做系統(tǒng)調用(system calls)。 系統(tǒng)調用的過程比較復雜,大致流程是這樣的:將相關參數放進系統(tǒng)調用的相關寄存器中,然后調用軟中斷(0x80),這個中斷作用就是讓一個程序從用戶態(tài)陷入到內核態(tài)執(zhí)行,程序將參數和系統(tǒng)調用號交給內核,內核來執(zhí)行。 看完這個知識鋪墊,估計心里猜測跟系統(tǒng)調用有關系了。確實不是特別高大上的技術,只是利用了Linux提供的非常優(yōu)雅的方式:ptrace系統(tǒng)調用,用man查看以下這個系統(tǒng)調用。ptrace可以讓父進程觀察和控制其子進程的檢查、執(zhí)行,改變其寄存器和內存的內容。主要的作用就是大家常用的打斷點的功能了,還有一個功能是打印系統(tǒng)調用的軌跡信息。 我們先來看下這個ptrace函數的原型: #include <sys/ptrace.h>long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); 第一個參數決定了ptrace的行為與其他參數的使用方法??扇〉闹涤校?/p> PTRACE_MEPTRACE_PEEKTEXTPTRACE_PEEKDATAPTRACE_PEEKUSERPTRACE_POKETEXTPTRACE_POKEDATAPTRACE_POKEUSERPTRACE_GETREGSPTRACE_GETFPREGS,PTRACE_SETREGSPTRACE_SETFPREGSPTRACE_CONTPTRACE_SYSCALL,PTRACE_SINGLESTEPPTRACE_DETACH 下面對常用的幾種模式進行說明。
詳細可參考《http:///linux/man-pages/man2/ptrace.2.html》 gdb三種調試方式 看完ptrace使用方法,再來看看gdb的三種調試方式。
斷點的實現過程 再回到剛文章開頭的問題,斷點是怎樣實現的呢?我從上面文字中知道gdb調試的實現都是建立在信號的基礎上的。在使用參數為PTRACE_TRACEME或PTRACE_ATTACH的ptrace系統(tǒng)調用建立調試關系后,交付給目標程序的任何信號首先都會被gdb截獲。 因此gdb可以先行對信號進行相應處理,并根據信號的屬性決定是否要將信號交付給目標程序。 當用breakpoint 設置一個斷點后,gdb會在=找到該位置對應的具體地址,然后向該地址寫入斷點指令INT3,即0xCC。 目標程序運行到這條指令時,就會觸發(fā)SIGTRAP信號,gdb會首先捕獲到這個信號。然后根據目標程序當前停止的位置在gdb維護的斷點鏈表中查詢,若存在,則可判定為命中斷點。 喜歡這篇文章,請不要忘記點擊右下方“在看”,謝謝! |
|