0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

內(nèi)核trace工具surtrace-cmd簡介

Linux閱碼場 ? 來源:Linux內(nèi)核之旅 ? 作者:liaozhaoyan ? 2022-03-30 15:39 ? 次閱讀

1、引子:從三板斧開始

?說起三板斧,我們首先想到的就是隋唐英雄程咬金,他手持宣花大斧,遇到對手先掄三招(嚴格意義來說,是兩招半)過去,大部分情況下都能將對手撂倒,大不了不行就拖斧跑路。

?今天登場的surftrace,就是一款類似于三板斧的工具,使用者只需掌握相關(guān)的內(nèi)核知識,就可以快速上手使用。先看一個現(xiàn)實的案例。

1.1、誰喚醒了羅伯特

?在定位調(diào)度問題時,Robert進程總是被意外喚醒,因此需要知道都有哪些進程把Robert進程(pid為1234)給喚醒了。

?解決方案:內(nèi)核采用try_to_wake_up函數(shù)來喚醒一個線程,函數(shù)原型:

static int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)

?該函數(shù)第一個入?yún)truct task_struct 包含任務(wù)pid信息,通過過濾pid以及獲取current信息,就可以找到是誰喚醒了。

?上面的問題非常容易通過ko、systemtap、bcc、bpftrace等方案實現(xiàn)。只是上述方案都存在一個共同的需求:沒有現(xiàn)成的命令可以使用,均需要編碼實現(xiàn),調(diào)試費時費力,問題定位了,可能就丟一邊了。

1.2、surftrace登場

?先放碼出來:

pip install surftracesurftrace 'p try_to_wake_up pid=%0->pid comm=$comm f:pid==1234'

?輸出結(jié)果

surftrace 'p try_to_wake_up pid=%0->pid comm=$comm f:pid==1234'echo 'p:f0 try_to_wake_up pid=+0x948(%di):u32 comm=$comm' >> /sys/kernel/debug/tracing/kprobe_eventsecho 'pid==1234' > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/filterecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on -0     [011] d.h. 11766726.224113: f0: (try_to_wake_up+0x0/0x580) pid=1234 comm="swapper/11" <...>-2166943 [011] d.h. 11766727.225113: f0: (try_to_wake_up+0x0/0x580) pid=1234 comm="python3" -0     [008] d.h. 11766728.226114: f0: (try_to_wake_up+0x0/0x580) pid=1234 comm="swapper/8" -0     [008] d.h. 11766729.227114: f0: (try_to_wake_up+0x0/0x580) pid=1234 comm="swapper/8" <...>-3391432 [008] d.h. 11766730.228131: f0: (try_to_wake_up+0x0/0x580) pid=1234 comm="docker-proxy-cu"^Cecho 0 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho -:f0 >> /sys/kernel/debug/tracing/kprobe_eventsecho 0 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on

?有沒有一種上三板斧即收效的感覺?

2、surftrace簡介

?surftrace是在ftrace和libbpf基礎(chǔ)上封裝的一系列工具集,用于trace內(nèi)核信息。

?項目鏈接:https://github.com/aliyun/surftrace.git

我們接下來要介紹的surftrace-cmd基于ftrace封裝實現(xiàn),首先就需要從ftrace開始說起

2.1、ftrace原理與不足

?關(guān)于ftrace的介紹,可以參考其davaddi的文章:問題排查利器:Linux 原生跟蹤工具 Ftrace 必知必會,這篇文章介紹的比較詳細。概括的說:ftrace是一個內(nèi)核中的追蹤器,用于幫助系統(tǒng)開發(fā)者或設(shè)計者查看內(nèi)核運行情況,它可以被用來調(diào)試或者分析延遲/性能等常見問題。如今ftrace已經(jīng)成為一個開發(fā)框架,從2.6內(nèi)核開始引入,是一套公認安全、可靠、高效的內(nèi)核數(shù)據(jù)獲取方式。

?但是ftrace對使用者的要求比較高,以對內(nèi)核符號 wake_up_new_task 進行trace,同時要獲取入?yún)?struct task_struct *)->comm 成員信息為例,啟動配置需要經(jīng)歷三個步驟:

echo 'p:f0 wake_up_new_task comm=+0x678(%di):string' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on

?要想停止需要繼續(xù)配置如下:

echo 0 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho -:f0 >> /sys/kernel/debug/tracing/kprobe_eventsecho 0 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on

?一共需要六個步驟。其中,最困難的是第一個參數(shù)解析步驟。通常情況下,需要使用gdb 加載對應(yīng)內(nèi)核vmlinux, 對 struct task_struct 結(jié)構(gòu)體中 comm成員進行偏移計算。上述方法如果不經(jīng)常使用,重新手工操作的時間成本非常高,導(dǎo)致真正直接采用ftrace對內(nèi)核信息進行采集的案例非常少,相關(guān)資料文獻也匱乏。

2.2、surftrace目標

?surftrace的主要目標是為了降低內(nèi)核trace難度,以達到快速高效獲取內(nèi)核信息目標。綜合來說要達到以下效果:

  • 一鍵trace內(nèi)核符號,并獲取指定內(nèi)核數(shù)據(jù);

  • 除了C和linux 操作系統(tǒng)內(nèi)核,用戶無需新增學(xué)習(xí)掌握其它知識點(需要獲取數(shù)據(jù)進行二次處理除外);

  • 覆蓋大部分主流發(fā)行版內(nèi)核;

  • 類似bcc開發(fā)模式,達到libbpf最佳資源消耗;

3、surftrace 命令使用

?使用surftrace,需要滿足以下條件:

  • 公開發(fā)行版linux內(nèi)核,支持目錄參考:http://pylcc.openanolis.cn/version/ (持續(xù)更新)

  • 內(nèi)核支持ftrace,已配置了debugfs,root權(quán)限;

  • Python2 >= 2.7; Python3 >= 3.5,已安裝pip;

surftrace支持 remote(默認),local和gdb三種表達式解析器,要求分別如下:

  • remote mode:可以訪問pylcc.openanolis.cn

  • local mode:從http://pylcc.openanolis.cn/db/ 下載對應(yīng)arch和內(nèi)核的下載到本地

  • gdb mode:gdb version > 8.0,存放有對應(yīng)內(nèi)核的vmlinux;對于gdb模式而言,不受公開發(fā)行版內(nèi)核限制

3.1、安裝

?我們以龍蜥 4.19.91-24.8.an8.x86_64內(nèi)核為例,需要root用戶,執(zhí)行以下命令進行安裝:

pip3 install surftraceCollecting surftrace  Downloading http://mirrors.cloud.aliyuncs.com/pypi/packages/b9/a2/f7e04bb8ebb12e6517162a70886e3ffe8d466437b15624590c9301fdcc52/surftrace-0.2.tar.gzBuilding wheels for collected packages: surftrace  Running setup.py bdist_wheel for surftrace ... done  Stored in directory: /root/.cache/pip/wheels/cf/28/93/187f359be189bf0bf4a70197c53519c6ca54ffb957bcbebf5aSuccessfully built surftraceInstalling collected packages: surftraceSuccessfully installed surftrace-0.2

?檢查安裝是否成功

surftrace --helpusage: surftrace [-h] [-v VMLINUX] [-m MODE] [-d DB] [-r RIP] [-f FILE]                 [-g GDB] [-F FUNC] [-o OUTPUT] [-l LINE] [-a ARCH] [-s] [-S]                 [traces [traces ...]]
Trace ftrace kprobe events.
positional arguments:  traces                set trace args.
optional arguments:  -h, --help            show this help message and exit  -v VMLINUX, --vmlinux VMLINUX                        set vmlinux path.  -m MODE, --mode MODE  set arg parser, fro  -d DB, --db DB        set local db path.  -r RIP, --rip RIP     set remote server ip, remote mode only.  -f FILE, --file FILE  set input args path.  -g GDB, --gdb GDB     set gdb exe file path.  -F FUNC, --func FUNC  disasassemble function.  -o OUTPUT, --output OUTPUT                        set output bash file  -l LINE, --line LINE  get file disasemble info  -a ARCH, --arch ARCH  set architecture.  -s, --stack           show call stacks.  -S, --show            only show expressions.
examples:

3.2、常規(guī)函數(shù)入口trace

?接下來我們以 以下兩個常用內(nèi)核符號為例,它的原型定義如下:

void wake_up_new_task(struct task_struct *p);struct file *do_filp_open(int dfd, struct filename *pathname, const struct open_flags *op);

3.2.1、追蹤符號入口和返回點

命令:surftrace 'p wake_up_new_task' 'r wake_up_new_task'

surftrace 'p wake_up_new_task' 'r wake_up_new_task'echo 'p:f0 wake_up_new_task' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 'r:f1 wake_up_new_task' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f1/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on surftrace-2336  [001] ....  1447.877666: f0: (wake_up_new_task+0x0/0x280) surftrace-2336  [001] d...  1447.877670: f1: (_do_fork+0x153/0x3d0 <- wake_up_new_task)

?示例中入?yún)⒂袃蓚€表達式,所有表達式要用單引號括起來。

  • 'p wake_up_new_task':p表示表示probe函數(shù)入口;

  • 'r wake_up_new_task':r表示probe函數(shù)返回位置;

?后面的wake_up_new_task是要trace的函數(shù)符號,這個符號必須要在tracing/available_filter_functions 中可以找到的。

3.2.2、獲取函數(shù)入?yún)?/span>

?要獲取 do_filp_open 函數(shù) 第一個入?yún)fd,它的數(shù)據(jù)類型是:int。

命令:surftrace 'p do_filp_open dfd=%0'

surftrace 'p do_filp_open dfd=%0'echo 'p:f0 do_filp_open dfd=%di:u32' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on surftrace-2435  [001] ....  2717.606277: f0: (do_filp_open+0x0/0x100) dfd=4294967196 AliYunDun-1812  [000] ....  2717.655955: f0: (do_filp_open+0x0/0x100) dfd=4294967196 AliYunDun-1812  [000] ....  2717.856227: f0: (do_filp_open+0x0/0x100) dfd=4294967196

  • dfd是自定義變量,可以自行定義,名字不沖突即可

  • %0表示第一個入?yún)ⅲ?1表示第二個……

?前面打印中,dfd是按照十進制顯示的,可能沒有十六進制那么直觀,指定十六進制的方法:

?命令:surftrace 'p do_filp_open dfd=X%0'

surftrace 'p do_filp_open dfd=X%0'echo 'p:f0 do_filp_open dfd=%di:x32' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on surftrace-2459  [000] ....  3137.167885: f0: (do_filp_open+0x0/0x100) dfd=0xffffff9c AliYunDun-1812  [001] ....  3137.171997: f0: (do_filp_open+0x0/0x100) dfd=0xffffff9c AliYunDun-1826  [001] ....  3137.201401: f0: (do_filp_open+0x0/0x100) dfd=0xffffff9c

?傳參編號%前面使用了X進制類型標識符,共有SUX三種類型,分別對應(yīng)有符號十進制、無符號十進制和十六進制,不指定默認為U類型。

3.2.3、解析入?yún)⒔Y(jié)構(gòu)體

?wake_up_new_task入?yún)㈩愋蜑閟truct task_struct *,如果要獲取入?yún)⒅衏omm成員,即任務(wù)名,

命令:surftrace 'p wake_up_new_task comm=%0->comm'

surftrace 'p wake_up_new_task comm=%0->comm'echo 'p:f0 wake_up_new_task comm=+0xae0(%di):string' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on surftrace-2421  [000] ....  2368.261019: f0: (wake_up_new_task+0x0/0x280) comm="surftrace" bash-2392  [001] ....  2375.809655: f0: (wake_up_new_task+0x0/0x280) comm="bash" bash-2392  [001] ....  2379.038534: f0: (wake_up_new_task+0x0/0x280) comm="bash" bash-2392  [000] ....  2381.237443: f0: (wake_up_new_task+0x0/0x280) comm="bash"

?方法和C語言獲取結(jié)構(gòu)體成員方法一樣。

?結(jié)構(gòu)體類型可以級聯(lián)訪問:

 surftrace 'p wake_up_new_task uesrs=S%0->mm->mm_users'echo 'p:f0 wake_up_new_task uesrs=+0x58(+0x850(%di)):s32' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on surftrace-2471  [001] ....  3965.234680: f0: (wake_up_new_task+0x0/0x280) uesrs=2 bash-2392  [000] ....  3970.094475: f0: (wake_up_new_task+0x0/0x280) uesrs=1 bash-2392  [000] ....  3971.954463: f0: (wake_up_new_task+0x0/0x280) uesrs=1surftrace 'p wake_up_new_task node=%0->se.run_node.rb_left'echo 'p:f0 wake_up_new_task node=+0xa8(%di):u64' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on surftrace-2543  [001] ....  5926.605145: f0: (wake_up_new_task+0x0/0x280) node=0 bash-2392  [001] ....  5940.292293: f0: (wake_up_new_task+0x0/0x280) node=0 bash-2392  [001] ....  5945.207106: f0: (wake_up_new_task+0x0/0x280) node=0 systemd-journal-553   [000] ....  5953.211998: f0: (wake_up_new_task+0x0/0x280) node=0

3.2.4、設(shè)置過過濾器

?過濾器需要放在表達式最后,以f:開頭,可以使用括號和&& ||邏輯表達式進行組合,具體寫法可以參考ftrace文檔說明

?命令行 surftrace 'p wake_up_new_task comm=%0->comm f:comm=="python3"'

surftrace 'p wake_up_new_task comm=%0->comm f:comm=="python3"'echo 'p:f0 wake_up_new_task comm=+0xb28(%di):string' >> /sys/kernel/debug/tracing/kprobe_eventsecho 'comm=="python3"' > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/filterecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on <...>-2640781 [002] .... 6305734.444913: f0: (wake_up_new_task+0x0/0x250) comm="python3" <...>-2640781 [002] .... 6305734.447806: f0: (wake_up_new_task+0x0/0x250) comm="python3" <...>-2640781 [002] .... 6305734.450897: f0: (wake_up_new_task+0x0/0x250) comm="python3"

?系統(tǒng)會默認提供 'common_pid', 'common_preempt_count', 'common_flags', 'common_type' 這5個變量作為過濾器,該變量由系統(tǒng)提供,無需額外定義。

3.2.5、函數(shù)內(nèi)部追蹤

?函數(shù)內(nèi)部追蹤需要結(jié)合函數(shù)內(nèi)部匯編代碼進行推導(dǎo),該方法并不通用,該內(nèi)容操作進供參考。反匯編do_filp_open函數(shù)

3699  in fs/namei.c   0xffffffff812adb65 <+85>:  mov    %r13d,%edx   0xffffffff812adb70 <+96>:  or     $0x40,%edx   0xffffffff812adb73 <+99>:  mov    %r12,%rsi   0xffffffff812adb76 <+102>:  mov    %rsp,%rdi   0xffffffff812adb89 <+121>:  callq  0xffffffff812ac760    0xffffffff812adb92 <+130>:  mov    %rax,%rbx
3700  in fs/namei.c   0xffffffff812adb8e <+126>:  cmp    $0xfffffffffffffff6,%rax   0xffffffff812adb95 <+133>:  je     0xffffffff812adbb4 164>
3701  in fs/namei.c   0xffffffff812adbb4 <+164>:  mov    %r13d,%edx   0xffffffff812adbb7 <+167>:  mov    %r12,%rsi   0xffffffff812adbba <+170>:  mov    %rsp,%rdi   0xffffffff812adbbd <+173>:  callq  0xffffffff812ac760    0xffffffff812adbc2 <+178>:  mov    %rax,%rbx   0xffffffff812adbc5 <+181>:  jmp    0xffffffff812adb97 135>
3702  in fs/namei.c   0xffffffff812adb97 <+135>:  cmp    $0xffffffffffffff8c,%rbx   0xffffffff812adb9b <+139>:  je     0xffffffff812adbc7 183>

?對應(yīng)源碼

struct file *do_filp_open(int dfd, struct filename *pathname,      const struct open_flags *op){    struct nameidata nd;    int flags = op->lookup_flags;    struct file *filp;      set_nameidata(&nd, dfd, pathname);    filp = path_openat(&nd, op, flags | LOOKUP_RCU);    if (unlikely(filp == ERR_PTR(-ECHILD)))      filp = path_openat(&nd, op, flags);    if (unlikely(filp == ERR_PTR(-ESTALE)))      filp = path_openat(&nd, op, flags | LOOKUP_REVAL);    restore_nameidata();    return filp;}

要獲取 3699行 filp = path_openat(&nd, op, flags | LOOKUP_RCU) 對應(yīng)的filp的值

surftrace 'p do_filp_open+121 filp=X!(u64)%ax'echo 'p:f0 do_filp_open+121 filp=%ax:x64' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on <...>-1315799 [006] d.Z. 6314249.201847: f0: (do_filp_open+0x79/0xd0) filp=0xffff929db2819840 <...>-4006158 [014] d.Z. 6314249.326736: f0: (do_filp_open+0x79/0xd0) filp=0xffff929daeac48c0

?變量表達式:filp=X!(u64)%ax 中,使用!對寄存器類型進行數(shù)據(jù)類型強制轉(zhuǎn)換,括號當中的是是數(shù)據(jù)類型定義。

?展開 struct file 結(jié)構(gòu)體定義:

struct file {    union {        struct llist_node fu_llist;        struct callback_head fu_rcuhead;    } f_u;    struct path f_path;    struct inode *f_inode;    const struct file_operations *f_op;    spinlock_t f_lock;    enum rw_hint f_write_hint;    atomic_long_t f_count;    unsigned int f_flags;    fmode_t f_mode;    struct mutex f_pos_lock;    loff_t f_pos;    struct fown_struct f_owner;    const struct cred *f_cred;    struct file_ra_state f_ra;    u64 f_version;    void *f_security;    void *private_data;    struct list_head f_ep_links;    struct list_head f_tfile_llink;    struct address_space *f_mapping;    errseq_t f_wb_err;}

如果要獲取此時的f_pos值,可以這樣獲取

  • 命令行:surftrace 'p do_filp_open+121 pos=X!(struct file*)%ax->f_pos'

surftrace 'p do_filp_open+121 pos=X!(struct file*)%ax->f_pos'echo 'p:f0 do_filp_open+121 pos=+0x68(%ax):x64' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on <...>-1334277 [010] d.Z. 6314645.646230: f0: (do_filp_open+0x79/0xd0) pos=0x0 <...>-2916553 [002] d.Z. 6314645.653164: f0: (do_filp_open+0x79/0xd0) pos=0x0 <...>-2916553 [002] d.Z. 6314645.653253: f0: (do_filp_open+0x79/0xd0) pos=0x0

?獲取方法和前面保持一致。

3.3、獲取返回值

?前文已經(jīng)描述采用r 對事件類型進行標識,返回寄存器統(tǒng)一用$retval標識,與ftrace保持一致,以獲取do_filp_open函數(shù)返回值為例:

  • 命令行:surftrace 'r do_filp_open filp=$retval'

surftrace 'r do_filp_open filp=$retval'echo 'r:f0 do_filp_open filp=$retval:u64' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on <...>-1362926 [010] d... 6315264.198718: f0: (do_sys_openat2+0x1b6/0x260 <- do_filp_open) filp=18446623804769722880 <...>-4006154 [008] d... 6315264.256749: f0: (do_sys_openat2+0x1b6/0x260 <- do_filp_open) filp=18446623804770426624 <...>-4006154 [008] d... 6315264.256776: f0: (do_sys_openat2+0x1b6/0x260 <- do_filp_open) filp=18446623804770425344

獲取 struct file 中f_pos成員

  • 命令行:surftrace 'r do_filp_open pos=$retval->f_pos'

surftrace 'r do_filp_open pos=$retval->f_pos'echo 'r:f0 do_filp_open pos=+0x68($retval):u64' >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on <...>-1371049 [008] d... 6315439.568814: f0: (do_sys_openat2+0x1b6/0x260 <- do_filp_open) pos=0 systemd-journal-3665  [012] d... 6315439.568962: f0: (do_sys_openat2+0x1b6/0x260 <- do_filp_open) pos=0 systemd-journal-3665  [012] d... 6315439.571519: f0: (do_sys_openat2+0x1b6/0x260 <- do_filp_open) pos=0

3.4、skb處理

?sk_buff 是linux網(wǎng)絡(luò)協(xié)議棧重要的結(jié)構(gòu)體,通過前面的方法,并不能直接解析到我們關(guān)注的報文內(nèi)容,需要進行特殊處理。以追蹤icmp接收ping報文為例,我們在__netif_receive_skb_core 函數(shù)中進行probe和過濾:

  • 命令行 surftrace 'p __netif_receive_skb_core proto=@(struct iphdr *)l3%0->protocol ip_src=@(struct iphdr *)%0->saddr ip_dst=@(struct iphdr *)l3%0->daddr data=X@(struct iphdr *)l3%0->sdata[1] f:proto==1&&ip_src==127.0.0.1'

  • 同時可能需要 執(zhí)行 ping127.0.0.1

surftrace 'p __netif_receive_skb_core proto=@(struct iphdr *)l3%0->protocol ip_src=@(struct iphdr *)%0->saddr ip_dst=@(struct iphdr *)l3%0->daddr data=X@(struct iphdr *)l3%0->sdata[1] f:proto==1&&ip_src==127.0.0.1'echo 'p:f0 __netif_receive_skb_core proto=+0x9(+0xe8(%di)):u8 ip_src=+0xc(+0xe8(%di)):u32 ip_dst=+0x10(+0xe8(%di)):u32 data=+0x16(+0xe8(%di)):x16' >> /sys/kernel/debug/tracing/kprobe_eventsecho 'proto==1&&ip_src==0x100007f' > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/filterecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/kprobes/f0/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on <...>-1420827 [013] ..s1 6316511.011244: f0: (__netif_receive_skb_core+0x0/0xc10) proto=1 ip_src=127.0.0.1 ip_dst=127.0.0.1 data=0x4a0d <...>-1420827 [013] ..s1 6316511.011264: f0: (__netif_receive_skb_core+0x0/0xc10) proto=1 ip_src=127.0.0.1 ip_dst=127.0.0.1 data=0x4a1

?協(xié)議的獲取表達式為 @(struct iphdr *)l3%0->protocol,和之前不一樣的是,寄存器的結(jié)構(gòu)體名左括號加了@符號進行特殊標記,表示需要用該結(jié)構(gòu)體來解析skb->data指針數(shù)據(jù),結(jié)構(gòu)體名和右括號后加了l3標記(命名為右標記),表示當前skb->data指向了TCP/IP 層3位置。

  • 右標記有l(wèi)2、l3、l4三個選項,也可以不標記,默認為l3,如 ip_src=@(struct iphdr *)%0->saddr,沒有右標記。

  • 報文結(jié)構(gòu)體有 'struct ethhdr', 'struct iphdr', 'struct icmphdr', 'struct tcphdr', 'struct udphdr'五類,如果協(xié)議棧層級和報文結(jié)構(gòu)體對應(yīng)不上,解析器會報參數(shù)錯誤,如右標記為l3,但是報文結(jié)構(gòu)體是 struct ethhdr類型;

  • 'struct icmphdr', 'struct tcphdr', 'struct udphdr'這三個4層結(jié)構(gòu)體增加了xdata成員,用于獲取協(xié)議對應(yīng)報文內(nèi)容。xdata有 cdata. sdata, ldata, qdata, Sdata 五種類型,位寬對應(yīng) 1 2 4 8 和字符串. 數(shù)組下標是按照位寬進行對齊的,如實例表達式中的 data=%0~$(struct icmphdr)l3->sdata[1],sdata[1]表示要提取icmp報文中的2~3字節(jié)內(nèi)容

  • surftrace 會對以 ip_xx開頭的變量進行ipv4<->u32 ,如 ip_src=@(struct iphdr *)%0->saddr,會轉(zhuǎn)成對應(yīng)的IP格式。對B16、B32、B64、b16、b32、b64開頭的變量也會進行大小端轉(zhuǎn)換,B開頭按照16進制輸出,b以10進制輸出。

3.5、event

?trace event 信息參考 /sys/kernel/debug/tracing/events目錄下的事件 描述,以追蹤wakeup等待超過10ms任務(wù)為例

?命令行 surftrace 'e sched/sched_stat_wait f:delay>1000000'

surftrace 'e sched/sched_stat_wait f:delay>1000000'echo 'delay>1000000' > /sys/kernel/debug/tracing/instances/surftrace/events/sched/sched_stat_wait/filterecho 1 > /sys/kernel/debug/tracing/instances/surftrace/events/sched/sched_stat_wait/enableecho 0 > /sys/kernel/debug/tracing/instances/surftrace/options/stacktraceecho 1 > /sys/kernel/debug/tracing/instances/surftrace/tracing_on-0     [001] dN.. 11868700.419049: sched_stat_wait: comm=h2o pid=3046552 delay=87023763 [ns] -0     [005] dN.. 11868700.419049: sched_stat_wait: comm=h2o pid=3046617 delay=87360020 [ns]

4、總結(jié)

?通過前面的舉例,我們可以匯總出surftrace-cmd是一款類似三板斧一樣的簡潔易用的內(nèi)核trace工具。特別是在以下應(yīng)用場景中具有明顯的方案優(yōu)勢:

  • 內(nèi)核符號快速追蹤、傳參解析、數(shù)據(jù)過濾,可以做到一鍵追蹤;

  • 函數(shù)內(nèi)部匯編級別的追蹤和數(shù)據(jù)解析,類似的情況libbpf和bcc等方案無法實現(xiàn);

  • skb報文解析,已經(jīng)做了大小端和ip格式轉(zhuǎn)換等人性化處理,方便對網(wǎng)絡(luò)報文在內(nèi)核每一個環(huán)節(jié)進行有效追蹤。

?同時,surftrace-cmd沒有內(nèi)置像libbpf中的hashmap等數(shù)據(jù)類型,如果要在內(nèi)核態(tài)做復(fù)雜的邏輯運算和存儲等場景,還是推薦采用libbpf等方案。

?后面我們將從實際案例角度出發(fā),為你展示surftrace-cmd在網(wǎng)絡(luò)、IO等內(nèi)核問題的典型應(yīng)用


原文標題:內(nèi)核trace三板斧-surtrace-cmd

文章出處:【微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    3

    文章

    1350

    瀏覽量

    40155
  • Trace
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    10550
  • 工具
    +關(guān)注

    關(guān)注

    4

    文章

    307

    瀏覽量

    27666

原文標題:內(nèi)核trace三板斧-surtrace-cmd

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    ARM內(nèi)核結(jié)構(gòu)簡介

    ARM內(nèi)核結(jié)構(gòu)簡介
    發(fā)表于 12-10 14:29

    TraceX使用簡介

    TraceX使用簡介TraceX 軟件生成跟蹤bufTrace APItx_trace_enabletx_trace_enabletx_trace_event_filtertx_trace_event_unfiltertx_trace_disabletx_trace_isr_en
    發(fā)表于 02-22 06:59

    cmd常用命令大全 cmd運行命令

    cmd常用命令大全 2K和XP下的CMD命令 accwiz.exe > 輔助工具向?qū)?/div>
    發(fā)表于 01-08 09:12 ?3.1w次閱讀

    CMD55、CMD55、CMD55、CMD55綜合測試儀新到

    CMD55、CMD55、CMD55、CMD55綜合測試儀新到9臺深圳市理想微儀器通信有限公司 聯(lián)系人:蕭小姐135-1060-9722 聯(lián)系電話:0755-83761992/837
    發(fā)表于 08-05 15:42 ?754次閱讀

    Trace thickness

    Trace thickness The thickness of a trace is usually .0014 per ounce of copper. Our standard material is 1/2 ounce copper that is plate
    發(fā)表于 12-29 09:20 ?1536次閱讀

    Lauterbach TRACE32 工具的新增支持功能可簡化

    TRACE32 工具能夠更輕松地為 MIPS 異構(gòu) CPU 系統(tǒng)或結(jié)合 MIPS CPU 與 ARM CPU 的系統(tǒng)進行調(diào)試。
    發(fā)表于 02-25 11:11 ?2875次閱讀

    TRACE32多核策略

      勞特巴赫的長期目標之一是促使TRACE32的硬件和軟件盡可能靈活。各種內(nèi)核組合、各種多核拓撲結(jié)構(gòu)、各種多核操作方式,即使是最復(fù)雜的調(diào)試和跟蹤的基礎(chǔ)結(jié)構(gòu),均可由TRACE32支持。
    發(fā)表于 09-12 18:58 ?9次下載

    AS:可視化的調(diào)試工具--FreeRTOS+Trace

    在AS開發(fā)庫中,除了直接用于程序嵌入的庫和內(nèi)核以外,還有用來調(diào)試的工具。對于FreeRTOS而言,相對的線程和任務(wù)調(diào)度是比較難于用普通的設(shè)置斷點,進行參數(shù)跟蹤來實現(xiàn)的。因此,一種可視化的調(diào)試工具就被
    的頭像 發(fā)表于 02-09 14:17 ?6715次閱讀

    Best Trace路由跟蹤工具

    Best Trace 路由跟蹤工具 Windows 客戶端
    發(fā)表于 04-13 13:46 ?4次下載

    trace32 for rt-thread support的基本使用及系統(tǒng)插件原理

    trace32上的rt-thread插件及菜單欄 4.2 trace32 加載dump以及elf文件 5.總結(jié) 1.概述 Lauterbach是全球最大的、完整的、模塊化和可升級微處理器 開發(fā)工具
    的頭像 發(fā)表于 01-07 10:34 ?5767次閱讀

    Trace - Deembed Files

    Trace - Deembed Files
    發(fā)表于 02-01 09:47 ?0次下載
    <b class='flag-5'>Trace</b> - Deembed Files

    Trace輔助工具實現(xiàn)代碼分析與實時覆蓋率統(tǒng)計

    Cortex 內(nèi)核trace 功能,在無限時長內(nèi),實現(xiàn)對所有指令的跟蹤,實現(xiàn)對偶然出現(xiàn)的、難以被復(fù)現(xiàn)的 bug 追蹤記錄。 在完整
    的頭像 發(fā)表于 10-09 15:33 ?2720次閱讀
    <b class='flag-5'>Trace</b>輔助<b class='flag-5'>工具</b>實現(xiàn)代碼分析與實時覆蓋率統(tǒng)計

    Linux ftrace工具抓 i2c trace

    抓 i2c trace adb rootecho nop > /sys/ kernel/debug/tracing/current_tracer //清空以前的跟蹤信息 echo 1 > /sys
    的頭像 發(fā)表于 07-20 11:23 ?1100次閱讀
    Linux ftrace<b class='flag-5'>工具</b>抓 i2c <b class='flag-5'>trace</b>

    如何對基于μTraceTrace32的LPC86x進行邊界掃描

    電子發(fā)燒友網(wǎng)站提供《如何對基于μTraceTrace32的LPC86x進行邊界掃描.pdf》資料免費下載
    發(fā)表于 08-17 10:22 ?4次下載
    如何對基于μ<b class='flag-5'>Trace</b>和<b class='flag-5'>Trace</b>32的LPC86x進行邊界掃描

    如何使用Intel Processor Trace工具查看任意函數(shù)執(zhí)行時間

    在上一篇文章 PT_PERF: 基于 Intel PT 的時延性能分析工具 中,我們介紹了 Intel Processor Trace 時延分析工具的背景,功能和實現(xiàn)。
    的頭像 發(fā)表于 08-07 14:24 ?273次閱讀
    如何使用Intel Processor <b class='flag-5'>Trace</b><b class='flag-5'>工具</b>查看任意函數(shù)執(zhí)行時間