strace實現原理

2021-06-19 11:14:12 字數 2980 閱讀 8595

引子: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 為什麼某個程序沒有開啟本來該開啟的...