引子:1.在linux系統中,程序狀態除了我們所熟知的task_running,task_interruptible,task_stopped等,還有乙個task_traced。這表明這個程序處於什麼狀態?
2.strace可以方便的幫助我們記錄程序所執行的系統呼叫,它是如何跟蹤到程序執行的?
3.gdb是我們除錯程式的利器,可以設定斷點,單步跟蹤程式。它的實現原理又是什麼?
所有這一切的背後都隱藏著linux所提供的乙個強大的系統呼叫ptrace().
1.ptrace系統呼叫
ptrace系統調從名字上看是用於程序跟蹤的,它提供了父程序可以觀察和控制其子程序執行的能力,並允許父程序檢查和替換子程序的核心映象(包括暫存器)的值。其基本原理是: 當使用了ptrace跟蹤後,所有傳送給被跟蹤的子程序的訊號(除了sigkill),都會被**給父程序,而子程序則會被阻塞,這時子程序的狀態就會被系統標註為task_traced。而父程序收到訊號後,就可以對停止下來的子程序進行檢查和修改,然後讓子程序繼續執行。
其原型為:
#include
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
ptrace有四個引數:
1). enum __ptrace_request request:指示了ptrace要執行的命令。
2). pid_t pid: 指示ptrace要跟蹤的程序。
3). void *addr: 指示要監控的記憶體位址。
4). void *data: 存放讀取出的或者要寫入的資料。
ptrace是如此的強大,以至於有很多大家所常用的工具都基於ptrace來實現,如strace和gdb。接下來,我們借由對strace和gdb的實現,來看看ptrace是如何使用的。
2. strace的實現
strace常常被用來攔截和記錄程序所執行的系統呼叫,以及程序所收到的訊號。如有這麼一段程式:
helloworld.c:
#include
int main()
編譯後,用strace跟蹤: strace ./helloworld
可以看到形如:
execve("./helloworld", ["./helloworld"], [/* 67 vars */]) = 0
brk(0) = 0x804a000
mmap2(null, 4096, prot_read|prot_write, map_private|map_anonymous, -1, 0) = 0xb7f18000
access("/etc/ld.so.preload", r_ok) = -1 enoent (no such file or directory)
open("/home/supperman/workspace/lib/tls/i686/sse2/libc.so.6", o_rdonly) = -1 enoent (no such file or directory)
...的一段輸出,這就是在執行helloworld中,系統所執行的系統呼叫,以及他們的返回值。
下面我們用ptrace來研究一下它是怎麼實現的。
...switch(pid = fork())
else //第二次(退出系統呼叫),獲取系統呼叫的返回值
ptrace(ptrace_syscall,pid,null,null);}}
...在上面的程式中,fork出的子程序先呼叫了ptrace(ptrace_traceme)表示子程序讓父程序跟蹤自己。然後子程序呼叫execl載入執行了helloworld。而在父程序中則使用wait系統呼叫等待子程序的狀態改變。子程序因為設定了ptrace_traceme而在執行系統呼叫被系統停止(設定為task_traced),這時父程序被喚醒,使用ptrace(ptrace_peekuser,pid,...)分別去讀取子程序執行的系統呼叫id(放在orig_eax中)以及系統呼叫返回時的值(放在eax中)。然後使用ptrace(ptrace_syscall,pid,...)指示子程序執行到下一次執行系統呼叫的時候(進入或者退出),直到子程序退出為止。
程式的執行結果如下:
process executed system call id = 11
process executed system call id = 45 with return value= 134520832
process executed system call id = 192 with return value= -1208934400
process executed system call id = 33 with return value= -2
process executed system call id = 5 with return value= -2
...其中,11號系統呼叫就是execve,45號是brk,192是mmap2,33是access,5是open...經過比對可以發現,和strace的輸出結果一樣。當然strace進行了更詳盡和完善的處理,我們這裡只是揭示其原理,感興趣的同學可以去研究一下strace的實現。
ps:
1). 在系統呼叫執行的時候,會執行pushl %eax # 儲存系統呼叫號orig_eax在程式使用者棧中。
2). 在系統呼叫返回的時候,會執行movl %eax,eax(%esp)將系統呼叫的返回值放入暫存器%eax中。
3). wifexited()巨集用來判斷子程序是否為正常退出的,如果是,它會返回乙個非零值。
4). 被跟蹤的程式在進入或者退出某次系統呼叫的時候都會觸發乙個sigtrap訊號,而被父程序捕獲。
5). execve()系統呼叫執行成功的時候並沒有返回值,因為它開始執行一段新的程式,並沒有"返回"的概念。失敗的時候會返回-1。
6). 在父程序進行進行操作的時候,用ps檢視,可以看到子程序的狀態為t,表示子程序處於task_traced狀態。當然為了更具操作性,你可以在父程序中加入sleep()。
strace學習筆記
strace學習筆記 v0.1 2013.11.15 簡介 stracestrace a.out 可以輸出a.out中依次呼叫的系統呼叫,和gdb一樣strace使 用系統呼叫pstrace實現其功能 基本功能 1.strace a.out 依次顯示各個系統呼叫 2.strace c a.out 可...
strace基本操作
可以發現很多真正在系統層面發生的呼叫,以及很細微的返回錯誤資訊,用於除錯工作。比如,軟體出錯,或是效能變慢。strace p 32000 o strace.txt 基本上完整的用法是這樣 strace o tmp output2.txt t tt e trace desc s 12 p 17129 ...
strace命令詳解
strace是乙個非常簡單的工具,它可以跟蹤系統呼叫的執行。最簡單的方式,它可以從頭到尾跟蹤binary的執行,然後以一行文字輸出系統呼叫的名字,引數和返回值。其實它可以做的更多 1 找出應用程式在啟動時讀取的是哪個配置檔案 只關心特定的系統呼叫,e 引數指定 2 為什麼某個程序沒有開啟本來該開啟的...