程序跟蹤的系統呼叫是ptrace(),通過
ptrace
,乙個程序可以動態的讀寫另乙個程序的記憶體和暫存器,包括資料段、**段、堆疊以及所有的暫存器。從概念上來說,著似乎也是程序間通訊的一種方法。但實際上,這種通訊是單方面的,被跟蹤的程序並不知道自己是在收到控制和監視的條件下進行。從這個角度來說,這又不屬於程序間通訊。
ptrace格式:
int ptrace(int request,//具體操作
int pid,
int addr,//操作目標的位址
int data)
request引數是由若干巨集組成的。比如使用
gdb的時候,給出的巨集是
ptrace_attach
,也就是「
attach
」到被跟蹤程序,之後使用各種操作來讀寫。這裡的
addr
就是其位址。或者通過
ptrace_singlestep
、ptrace_kill
等來控制被跟蹤程序的執行,最後通過
ptrace_detach
脫離程序跟蹤關係。
#define ptrace_traceme 0
#define ptrace_peektext 1
#define ptrace_peekdata 2
#define ptrace_peekusr 3
#define ptrace_poketext 4
#define ptrace_pokedata 5
#define ptrace_pokeusr 6
#define ptrace_cont 7
#define ptrace_kill 8
#define ptrace_singlestep 9
#define ptrace_attach 0x10
#define ptrace_detach 0x11
#define ptrace_syscall 24
與其他系統呼叫一樣,ptrace()在核心的實現是
sys_ptrace()。
跟蹤有兩種情況,一種是程序主動請求跟蹤,還有一種是被跟蹤程序本來就是跟蹤程序通過fork和
exec
啟動的(比如
gdb)。所以在函式開頭的時候會
if檢測,這次跟蹤是不是主動請求的跟蹤,如果是就在該程序修改標誌位。
接下來就根據引數pid找到其
task_struct
。不過,一號程序
init()
是不允許被跟蹤的,同時也不能夠跟蹤自己。
找到task_struct後會修改其所在頁面的使用計數。原因是有些操作可能會發生程序排程,為了防止子程序得到機會先執行並且
exit()
釋放task_struct
頁面。
如果兩個程序主動請求跟蹤,但是兩個程序不屬於乙個使用者組,那就要將當前程序提到特權使用者才行。此外,乙個程序不能夠被多個程序跟蹤。所以在這裡還得再檢測一下。
父程序存在著生父和養父之分,養父平常和生父指向同乙個程序。但是在存在跟蹤的情況下,養父就是「跟蹤者」,接下來就會對養父進行修改。
在讀取被跟蹤程序物理頁面的時候,為了保證資料正確,會將被跟蹤的子程序的狀態置於task_stop,實現原子操作。
一般來說,讀取被跟蹤程序的使用者空間和系統空間方法是不一樣的,跟蹤程序只能說在使用者空間下跟蹤。也就是說不能夠讀取被跟蹤者的系統空間。為了讀取被跟蹤者的系統空間裡的資訊,就要進行乙個軟中斷。在日常的gdb下,我們在編譯的時候總要
-g。這個
-g就是為處理乙個
sigtrap
訊號做準備。
Linux下使用gdb除錯跟蹤程序
可以使用gdb strace命令 推薦gdb 本文主要介紹使用gdb在linux下直接對程序進行跟蹤除錯 若想使用gdb對程序除錯,需要在編譯程式時加入相關的選項 set cmake build type debug set cmake cxx flags debug env o0 wall g2 ...
Linux核心啟動原始碼跟蹤 gdb除錯篇
核心的編譯和環境的搭建過程如圖 分析核心原始碼 include 13 14static struct signal struct init signals init signals init signals 15static struct sighand struct init sighand in...
linux之strace命令跟蹤程序的系統呼叫
作業系統的程序空間分為使用者空間和核心空間,作業系統核心直接執行在硬體上,提供裝置管理 記憶體管理 任務排程等功能,我們使用者空間不能直接呼叫,所以就有了系統呼叫 執行在使用者空間的程式向作業系統核心請求需要更高許可權執行的服務 系統呼叫提供使用者程式與作業系統之間的介面。使用者空間通過api請求核...