全部關於gdb的文章索引請點這裡
引子:gdb基本上大家都在用,你有沒有想過它的實現原理是什麼?為什麼它可以控制程式執行、中斷、訪問記憶體甚至直接使程式流程改變?
在使用gdb除錯程式時,程式的程序狀態是」t」,但又似乎並非接到了sigstop訊號,那麼這個」t」是什麼呢?
追根溯源,我們今天來研究一下linux下這個強大的系統呼叫:ptrace()
首先,linux的程序狀態大體分為以下幾種:
d (task_uninterruptible),不可中斷的睡眠狀態。
r (task_running),程序執行中。
s (task_interruptible),可中斷的睡眠狀態。
t (task_stopped),暫停狀態。
t (task_traced),程序被追蹤。
w (task_paging),程序調頁中,2.6以上版本的核心中已經被移除。
x (task_dead – exit_dead),退出狀態,程序即將被銷毀。
z (task_dead – exit_zombie),退出狀態,程序成為殭屍程序。
(以上內容來自ps命令的manual手冊,原文請看↓)
請看ptrace系統呼叫手冊↓
ptrace的原型可以看到是:
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
4個引數的含義分別為:
enum __ptrace_request request:指示了ptrace要執行的命令。
pid_t pid: 指示ptrace要跟蹤的程序。
void *addr: 指示要監控的記憶體位址。
void *data: 存放讀取出的或者要寫入的資料。
描述譯文如下:
ptrace()系統呼叫提供了乙個方法,該方法使乙個程式(追蹤者)可以觀察和控制另外乙個程式(被追蹤者)的執行,並檢查和改變被追蹤者的記憶體及暫存器。它主要用於實現斷點除錯和追蹤系統呼叫。
被追蹤者首先需要被追蹤者attach(這個詞實在不知道咋翻譯了……但是程式設計師應該都懂@_@)。該行為以及後續操作是執行緒獨立的:在乙個多執行緒的程序中,每乙個執行緒可以被乙個獨立的(可能是不同的)追蹤者attach,或者乾脆不理會。因此,被追蹤者永遠是「乙個執行緒」,而不是乙個(可能是多執行緒的)程序。使用ptrace命令的方法是追蹤程式傳送如下命令給被追蹤程式:
ptrace(ptrace_foo, pid, …)
pid即linux系統分配的執行緒號。
當被追蹤時,被追蹤執行緒在接收訊號時會被停止,即使那個訊號是被忽略的也是如此(sigkill除外)。追蹤程式會在乙個呼叫waitpid(或者其他類wait系統呼叫)時收到通知,該呼叫會返回乙個包含被追蹤執行緒停止的原因的狀態值。當被追蹤執行緒停止時,追蹤程式可以使用多種ptrace請求來檢查和編輯被追蹤執行緒。追蹤程式可以讓被追蹤執行緒繼續執行,有選擇地忽略發過來的訊號(甚至可以傳送乙個完全不同的訊號給被追蹤執行緒)。
可以看到,ptrace確實是乙個強大的系統呼叫;gdb就是基於ptrace這個系統呼叫來做的。其原理是利用ptrace系統呼叫,在被除錯程式和gdb之間建立追蹤關係。然後所有傳送給被除錯程式(被追蹤執行緒)的訊號(除sigkill)都會被gdb截獲,gdb根據截獲的訊號,檢視被除錯程式相應的記憶體位址,並控制被除錯的程式繼續執行。gdb常用的使用方法有斷點設定和單步除錯,接下來我們來分析一下他們是如何實現的。
1.建立除錯關係:
用gdb除錯程式有2種模式,包括使用gdb啟動程式,以及attach到現有程序。分別對應下面2種建立除錯關係的方法:
1) fork: 利用fork+execve執行被測試的程式,子程序在執行execve之前呼叫ptrace(ptrace_traceme),建立了與父程序(debugger)的跟蹤關係。
2) attach: debugger可以呼叫ptrace(ptrace_attach,pid,...),建立自己與程序號為pid的程序間的跟蹤關係。即利用ptrace_attach,使自己變成被除錯程式的父程序(用ps可以看到)。用attach建立起來的跟蹤關係,可以呼叫ptrace(ptrace_detach,pid,...)來解除。注意attach程序時的許可權問題,如乙個非root許可權的程序是不能attach到乙個root程序上的。
2.斷點原理:
1) 斷點的實現原理,就是在指定的位置插入斷點指令,當被除錯的程式執行到斷點的時候,產生sigtrap訊號。該訊號被gdb捕獲並進行斷點命中判定,當gdb判斷出這次sigtrap是斷點命中之後就會轉入等待使用者輸入進行下一步處理,否則繼續。
2) 斷點的設定原理: 在程式中設定斷點,就是先將該位置的原來的指令儲存,然後向該位置寫入int 3。當執行到int 3的時候,發生軟中斷,核心會給子程序發出sigtrap訊號,當然這個訊號會被**給父程序。然後用儲存的指令替換int3,等待恢復執行。
3) 斷點命中判定:gdb把所有的斷點位置都存放在乙個鍊錶中,命中判定即把被除錯程式當前停止的位置和鍊錶中的斷點位置進行比較,看是斷點產生的訊號,還是無關訊號。
4) 條件斷點的判定:原理同3),只是恢復斷點處的指令後,再多加一步條件判斷。若表示式為真,則觸發斷點。由於需要判斷一次,因此加入條件斷點後,不管有沒有觸發到條件斷點,都會影響效能。在x86平台,某些硬體支援硬體斷點,在條件斷點處不插入int 3,而是插入乙個其他指令,當程式走到這個位址的時候,不發出int 3訊號,而是先去比較一下特定暫存器和某個位址的內容,再決定是否傳送int 3。因此,當你的斷點的位置會被程式頻繁地「路過」時,盡量使用硬體斷點,會對提高效能有幫助。
3.單步跟蹤原理:
這個最簡單,因為ptrace本身支援單步功能,呼叫ptrace(ptrace_singlestep,pid,...)即可,如下圖說明:
gdb的原理 ptrace系統呼叫
首先,linux的程序狀態大體分為以下幾種 以上內容來自ps命令的manual手冊 d task uninterruptible 不可中斷的睡眠狀態。r task running 程序執行中。s task interruptible 可中斷的睡眠狀態。t task stopped 暫停狀態。t ta...
GDB除錯原理
gdb偵錯程式可以啟動某些程序,然後對其進行除錯,或者將自己本身關聯到乙個已存在的程序之上。它可以單步執行 設定斷點然後執行程式,檢查變數的值以及跟蹤呼叫棧等等。gdb通過乙個系統呼叫 ptrace 接管乙個程序的執行 ptrace系統呼叫是乙個功能眾多且相當複雜的工具,能允許乙個程序控制另乙個程序...
Linux系統 gdb除錯技巧
gdb除錯技巧 前言 我們知道,在linux環境下除錯 是不輕鬆的,至少很多ide整合開發環境下的除錯工具都比linux下的除錯要好用。但是linux也有像gdb這樣的工具,幫助我們進行相對方便的除錯。使用 g選項允許gdb除錯 我們在linux環境下編譯 時,預設生成的可執行檔案是沒有辦法使用 g...