Fprobe - 函式入口/出口探針¶
簡介¶
Fprobe 是一個基於 ftrace 中的函式圖跟蹤特性的函式入口/出口探針。 如果你不想跟蹤所有函式,而是想在特定函式的入口和出口處附加回調,類似於 kprobes 和 kretprobes,你可以使用 fprobe。 與 kprobes 和 kretprobes 相比,fprobe 可以用單個處理程式更快地對多個函式進行檢測。 本文件描述如何使用 fprobe。
fprobe 的用法¶
fprobe 是 ftrace(+ 類似 kretprobe 的返回回撥)的包裝器,用於將回調附加到多個函式入口和出口。 使用者需要設定 struct fprobe 並將其傳遞給 register_fprobe()。
通常,fprobe 資料結構使用 entry_handler 和/或 exit_handler 初始化,如下所示。
struct fprobe fp = {
.entry_handler = my_entry_callback,
.exit_handler = my_exit_callback,
};
要啟用 fprobe,請呼叫 register_fprobe(), register_fprobe_ips(), 和 register_fprobe_syms() 之一。 這些函式使用不同型別的引數註冊 fprobe。
register_fprobe() 透過函式名過濾器啟用 fprobe。 例如,這會在 “func*()” 函式上啟用 @fp,但 “func2()” 除外。
register_fprobe(&fp, "func*", "func2");
register_fprobe_ips() 透過 ftrace 位置地址啟用 fprobe。 例如:
unsigned long ips[] = { 0x.... };
register_fprobe_ips(&fp, ips, ARRAY_SIZE(ips));
並且 register_fprobe_syms() 透過符號名稱啟用 fprobe。 例如:
char syms[] = {"func1", "func2", "func3"};
register_fprobe_syms(&fp, syms, ARRAY_SIZE(syms));
要停用(從函式中刪除)此 fprobe,請呼叫
unregister_fprobe(&fp);
你可以暫時(軟)停用 fprobe,方法是:
disable_fprobe(&fp);
並透過以下方式恢復:
enable_fprobe(&fp);
以上是透過包含標頭檔案定義的
#include <linux/fprobe.h>
與 ftrace 相同,註冊的回撥將在呼叫 register_fprobe() 之後和返回之前的一段時間後開始被呼叫。 請參閱 Documentation/trace/ftrace.rst。
此外,unregister_fprobe() 將保證在 unregister_fprobe() 返回後,函式不再呼叫進入和退出處理程式,與 unregister_ftrace_function() 相同。
fprobe 進入/退出處理程式¶
進入/退出回撥函式的原型如下:
int entry_callback(struct fprobe *fp, unsigned long entry_ip, unsigned long ret_ip, struct ftrace_regs *fregs, void *entry_data);
void exit_callback(struct fprobe *fp, unsigned long entry_ip, unsigned long ret_ip, struct ftrace_regs *fregs, void *entry_data);
請注意,@entry_ip 儲存在函式入口處並傳遞給退出處理程式。 如果進入回撥函式返回 !0,則將取消相應的退出回撥。
- @fp
這是與此處理程式相關的 fprobe 資料結構的地址。 你可以將 fprobe 嵌入到你的資料結構中,並透過 @fp 中的 container_of() 宏獲取它。 @fp 不得為 NULL。
- @entry_ip
這是被跟蹤函式的 ftrace 地址(包括進入和退出)。 請注意,這可能不是函式的實際入口地址,而是 ftrace 被檢測的地址。
- @ret_ip
這是被跟蹤函式將返回到的返回地址,位於呼叫者中的某個位置。 這可以在進入和退出時使用。
- @fregs
這是進入和退出時的 ftrace_regs 資料結構。 這包括函式引數或返回值。 因此,使用者可以透過適當的 ftrace_regs_* API 訪問這些值。
- @entry_data
這是一個本地儲存,用於在進入和退出處理程式之間共享資料。 預設情況下,此儲存為 NULL。 如果使用者在註冊 fprobe 時指定了 exit_handler 欄位和 entry_data_size 欄位,則會分配儲存空間並將其傳遞給 entry_handler 和 exit_handler。
同一函式上的進入資料大小和退出處理程式¶
由於進入資料透過每個任務的堆疊傳遞,並且其大小有限,因此每個探針的進入資料大小限制為 15 * sizeof(long)。 你還需要注意不同的 fprobe 正在探測同一個函式,此限制會變小。 進入資料大小與 sizeof(long) 對齊,並且每個具有退出處理程式的 fprobe 在堆疊上使用 sizeof(long) 空間,你應該儘可能減少同一函式上的 fprobe 數量。
丟失計數器¶
fprobe 資料結構具有 fprobe::nmissed 計數器欄位,與 kprobes 相同。 在以下情況下,此計數器會遞增:
fprobe 無法獲取 ftrace_recursion 鎖。 這通常意味著其他 ftrace 使用者跟蹤的函式是從 entry_handler 呼叫的。
由於無法從每個任務的影子堆疊中分配資料緩衝區,fprobe 無法設定函式退出。
fprobe::nmissed 欄位在這兩種情況下都會遞增。 因此,前者跳過進入和退出回撥,後者跳過退出回撥,但在兩種情況下,計數器都將增加 1。
請注意,如果在註冊 fprobe 時,你將 FTRACE_OPS_FL_RECURSION 和/或 FTRACE_OPS_FL_RCU 設定為 fprobe::ops::flags (ftrace_ops::flags),則此計數器可能無法正常工作,因為 ftrace 會跳過增加計數器的 fprobe 函式。
函式和結構¶
-
struct fprobe_hlist_node¶
基於地址的 fprobe 雜湊列表節點。
定義:
struct fprobe_hlist_node {
struct hlist_node hlist;
unsigned long addr;
struct fprobe *fp;
};
成員
hlist地址搜尋雜湊表的 hlist 節點。
addrfp 的探測地址之一。
fp擁有此節點的 fprobe。
-
struct fprobe_hlist¶
fprobe 的雜湊列表節點。
定義:
struct fprobe_hlist {
struct hlist_node hlist;
struct rcu_head rcu;
struct fprobe *fp;
int size;
struct fprobe_hlist_node array[] ;
};
成員
hlist用於存在性檢查雜湊表的 hlist 節點。
rcu用於 RCU 延遲釋放的 rcu_head。
fp擁有此 fprobe_hlist 的 fprobe。
sizearray 的大小。
array每個要探測的地址的 fprobe_hlist_node。
-
struct fprobe¶
基於 ftrace 的探針。
定義:
struct fprobe {
unsigned long nmissed;
unsigned int flags;
size_t entry_data_size;
fprobe_entry_cb entry_handler;
fprobe_exit_cb exit_handler;
struct fprobe_hlist *hlist_array;
};
成員
nmissed用於丟失事件的計數器。
flags狀態標誌。
entry_data_size私有資料儲存大小。
entry_handler函式入口的回撥函式。
exit_handler函式退出的回撥函式。
hlist_array用於從 IP 雜湊表搜尋 fprobe 的 fprobe_hlist。
引數
struct fprobe *fp要停用的 fprobe。
描述
這將軟停用 fp。 請注意,這不會從函式入口中刪除 ftrace 掛鉤。
引數
struct fprobe *fp要啟用的 fprobe。
描述
這將軟啟用 fp。
-
int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter)¶
透過模式將 fprobe 註冊到 ftrace。
引數
struct fprobe *fp要註冊的 fprobe 資料結構。
const char *filter探測符號的萬用字元模式。
const char *notfilterNOT 探測符號的萬用字元模式。
描述
將 fp 註冊到 ftrace,以在與 filter 匹配的符號上啟用探測。 如果 notfilter 不為 NULL,則不會探測與 notfilter 匹配的符號。
如果 fp 註冊成功,則返回 0,否則返回 -errno。
引數
struct fprobe *fp要註冊的 fprobe 資料結構。
unsigned long *addrs目標函式地址的陣列。
int numaddrs 的條目數。
描述
將 fp 註冊到 ftrace,以在 addrs 給定的地址上啟用探測。 addrs 必須是 ftrace 位置地址的地址,該地址可能是符號地址 + 架構相關的偏移量。 如果你不確定這意味著什麼,請使用其他註冊函式。
如果 fp 註冊成功,則返回 0,否則返回 -errno。
引數
struct fprobe *fp要註冊的 fprobe 資料結構。
const char **syms目標符號的陣列。
int numsyms 的條目數。
描述
將 fp 註冊到 syms 陣列給定的符號。 如果你確定符號存在於核心中,這將非常有用。
如果 fp 註冊成功,則返回 0,否則返回 -errno。
引數
struct fprobe *fp要登出的 fprobe 資料結構。
描述
登出 fprobe(並從函式條目中刪除 ftrace 掛鉤)。
如果 fp 登出成功,則返回 0,否則返回 -errno。