SystemTap 的 Guru 模式(-g 選項)允許在腳本中直接嵌入 C 代碼,繞過安全檢查,獲得對核心資料結構的完全存取權。嵌入代碼置於 %{ ... %} 標記間,編譯器將其原樣放入生成的核心模組。
%{
#include
#include
%} /* 頂層:引入核心標頭檔 */
function read_iphdr:long(skb:long) %{ /* 函數體:完整 C 函數實作 */
struct iphdr *iph = ip_hdr((struct sk_buff *)STAP_ARG_skb);
STAP_RETVALUE = (long)iph;
%}
function is_tcp_packet:long(iphdr) { /* 混合模式:Script 語言 + 嵌入運算式 */
protocol = @cast(iphdr, "iphdr")->protocol
return (protocol == %{ IPPROTO_TCP %}) // 嵌入常數運算式
}
| 項目 | SystemTap 1.7 及之前 | SystemTap 1.8+ (含 CentOS 6.4) |
|---|---|---|
| 參數存取 | THIS->argname | STAP_ARG_argname |
| 返回值設定 | THIS->__retvalue | STAP_RETVALUE |
遷移提示:舊腳本升級時必須全域替換上述宏,否則編譯報錯。
Guru 模式下指標解參考可能導致核心崩潰,務必使用 kread 安全讀取:
struct net_device *dev;
char *name;
dev = kread(&(skb->dev)); // 安全讀取 skb->dev
name = kread(&(dev->name)); // 安全讀取 dev->name
所有 SystemTap 探測處理器與 Guru 函數均在 關閉中斷 的原子上下文執行,嵌入 C 代碼中嚴禁呼叫可能睡眠的函數(如 kmalloc(GFP_KERNEL)、mutex_lock、copy_to_user 等),違者必導致核心死鎖或崩潰。
probe begin { printf("SystemTap start!\n"); }
probe kernel.function("ip_local_deliver") {
iph = read_iphdr(pointer_arg(1));
printf("tcp packet ? %s\n", is_tcp_packet(iph) ? "yes" : "no");
}
此範例展示:頂層引入標頭檔 → Guru 函數解析 sk_buff → 混合函數判斷協定 → 探測點掛載核心函數入口。
kread/kwrite。