首先,linux的程序狀態大體分為以下幾種:(以上內容來自ps命令的manual手冊)
d (task_uninterruptible),不可中斷的睡眠狀態。ptrace系統呼叫的原型: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),退出狀態,程序成為殭屍程序。
long ptrace(enum __ptrace_request request, pid_t pid,void *addr,void *data);
4個引數的含義分別為:
enum __ptrace_request request:指示了ptrace要執行的命令。其原理是基於ptrace系統呼叫,在被除錯程式和gdb之間建立追蹤關係。所有傳送給被除錯程式(被追蹤執行緒)的訊號(除sigkill)都會被gdb截獲,而被追蹤者會被阻塞,這時子程序的狀態就會被系統標註為task_traced。而gdb收到訊號後,就可以對停止下來的子程序進行檢查和修改,然後讓子程序繼續執行。pid_t pid: 指示ptrace要跟蹤的程序。
void *addr: 指示要監控的記憶體位址。
void *data: 存放讀取出的或者要寫入的資料。
ptrace是如此的強大,以至於有很多大家所常用的工具都基於ptrace來實現,如strace和gdb。接下來,我們借由對strace和gdb的實現,來看看ptrace是如何使用的。
可通過man手冊檢視具體使用:man ptrace
request引數的主要選項:
ptrace_traceme:由子程序呼叫,表示本程序將被其父程序跟蹤,交付給這個程序的所有訊號,即使訊號是忽略處理的(除sigkill之外),都將使其停止,父程序將通過wait()獲知這一情況。gdb常用的使用方法有斷點設定和單步除錯,接下來我們來分析一下他們是如何實現的。ptrace_attach:attach到乙個指定的程序,使其成為當前程序跟蹤的子程序,而子程序的行為等同於它進行了一次ptrace_traceme操作。但是,需要注意的是,雖然當前程序成為被跟蹤程序的父程序,但是子程序使用getppid()的到的仍將是其原始父程序的pid。
這下子gdb的attach功能也就明朗了。當你在gdb中使用attach命令來跟蹤乙個指定程序/執行緒的時候,gdb就自動成為該程序的父程序,而被跟蹤的程序則使用了一次ptrace_traceme,gdb也就順理成章的接管了這個程序。
ptrace_cont:繼續執行之前停止的子程序。可同時向子程序交付指定的訊號。
1.建立除錯關係:
用gdb除錯程式有2種模式,包括使用gdb啟動程式,以及attach到現有程序。分別對應下面2種建立除錯關係的方法:
1)fork: 利用fork+execve執行被測試的程式,子程序在執行execve之前呼叫ptrace(ptrace_traceme),建立了與父程序(debugger)的跟蹤關係。2.斷點原理:2) attach: debugger可以呼叫ptrace(ptrace_attach,pid,...),建立自己與程序號為pid的程序間的跟蹤關係。即利用ptrace_attach,使自己變成被除錯程式的父程序(用ps可以看到)。用attach建立起來的跟蹤關係,可以呼叫ptrace(ptrace_detach,pid,...)來解除。注意attach程序時的許可權問題,如乙個非root許可權的程序是不能attach到乙個root程序上的。
1) 斷點的實現原理,就是在指定的位置插入斷點指令,當被除錯的程式執行到斷點的時候,產生sigtrap訊號。該訊號被gdb捕獲並進行斷點命中判定,當gdb判斷出這次sigtrap是斷點命中之後就會轉入等待使用者輸入進行下一步處理,否則繼續。3.單步跟蹤原理:2) 斷點的設定原理: 在程式中設定斷點,就是先將該位置的原來的指令儲存,然後向該位置寫入int 3。當執行到int 3的時候,發生軟中斷,核心會給子程序發出sigtrap訊號,當然這個訊號會被**給父程序。然後用儲存的指令替換int3,等待恢復執行。
3) 斷點命中判定:gdb把所有的斷點位置都存放在乙個鍊錶中,命中判定即把被除錯程式當前停止的位置和鍊錶中的斷點位置進行比較,看是斷點產生的訊號,還是無關訊號。
4) 條件斷點的判定:原理同3),只是恢復斷點處的指令後,再多加一步條件判斷。若表示式為真,則觸發斷點。由於需要判斷一次,因此加入條件斷點後,不管有沒有觸發到條件斷點,都會影響效能。在x86平台,某些硬體支援硬體斷點,在條件斷點處不插入int 3,而是插入乙個其他指令,當程式走到這個位址的時候,不發出int 3訊號,而是先去比較一下特定暫存器和某個位址的內容,再決定是否傳送int 3。因此,當你的斷點的位置會被程式頻繁地「路過」時,盡量使用硬體斷點,會對提高效能有幫助。
這個最簡單,因為ptrace本身支援單步功能,呼叫ptrace(ptrace_singlestep,pid,...)即可。
gdb除錯的實現都是建立在訊號的基礎上的,在使用引數為ptrace_traceme或ptrace_attach的ptrace系統呼叫建立除錯關係後,交付給目標程式的任何訊號首先都會被gdb截獲。
因此gdb可以先行對訊號進行相應處理,並根據訊號的屬性決定是否要將訊號交付給目標程式。
1、設定斷點:
訊號是實現斷點的基礎,當用breakpoint 設定乙個斷點後,gdb會在=找到該位置對應的具體位址,然後向該位址寫入斷點指令int3,即0xcc。
目標程式執行到這條指令時,就會觸發sigtrap訊號,gdb會首先捕獲到這個訊號。然後根據目標程式當前停止的位置在gdb維護的斷點鍊錶中查詢,若存在,則可判定為命中斷點。
gdb暫停目標程式執行的方法是想起傳送sigstop訊號。
2、next單步除錯:
next指令可以實現單步除錯,即每次只執行一行語句。一行語句可能對應多條及其指令,當執行next指令時,gdb會計算下一條語句對應的第一條指令的位址,然後控制目標程式走到該位置停止。
1:gdb除錯原理——ptrace系統呼叫
2:gdb的工作原理
3:ptrace 詳解
除錯步驟:
1:gdb除錯多程序與多執行緒
2:gdb 除錯多程序或者多執行緒應用
GDB除錯原理 ptrace系統呼叫
全部關於gdb的文章索引請點這裡 引子 gdb基本上大家都在用,你有沒有想過它的實現原理是什麼?為什麼它可以控制程式執行 中斷 訪問記憶體甚至直接使程式流程改變?在使用gdb除錯程式時,程式的程序狀態是 t 但又似乎並非接到了sigstop訊號,那麼這個 t 是什麼呢?追根溯源,我們今天來研究一下l...
強悍的ptrace 程序追蹤,系統呼叫能手
strace gdb與ptrace 具體 見patents 理解 ptrace 函式 所有的系統呼叫陷入核心的方式都是一樣的,所以僅僅是陷入核心空間是不夠的。因此必須把系統呼叫號一併傳給核心。在x86上,這個傳遞動作是通過在觸發軟中 斷前把呼叫號裝入eax暫存器實現的。這樣系統呼叫處理程式一旦執行,...
gdb的工作原理
基本概念 gdb是做什麼的 怎麼用,就不再重述了,這裡主要從大方向講述下gdb的原理。gdb主要功能的實現基於系統函式ptrace,通過man手冊可以了解到,ptrace可以讓父程序觀察和控制其子程序的檢查 執行。函式的原型 man 2 ptrace include long ptrace enum...