linux内核打开了ftrace之后,系统启动的时候会自动创建/sys/kernel/tracing录。
/sys/kernel/tracing目录有以下文件或者目录:
tracing_on:决定是否像ring_buff写入数据,这个跟跟踪是否开启没关系,跟踪即使开启了这个关闭,每次跟踪被触发也不会写入到/sys/kernel/tracing/trace文件里面。
trace:显示跟踪信息的文件可以使用cat等数据去读取。
trace_pipe:类似trace,每次读取完成之后会继续等待下一次数据到来。
trace_options:显示tracer打开了哪些特性。options:目录里是这些特性的开关。
buffer_size_kb:缓冲区大小,kb为单位。
buffer_total_size_kb:所有设置跟踪点的缓冲区大小。\
tracing_cpumask:设置被跟踪的cpu掩码,即使设置跟踪点,只有在掩码内的cpu触发跟踪点才会打印。
动态跟踪点:
kprobe_events:动态跟踪点设置。
kprobe_profile:所有已经设置的动态跟踪点信息。
./Documentation/trace/kprobetrace.rst,内核文档
/sys/kernel/debug/tracing/kprobe_events文件是可以设置动态跟踪点。
echo %s > /sys/kernel/debug/tracing/kprobe_events 即可设置动态跟踪点且%s可以打印进ring_buff参数信息。
%s 格式说明:
p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe
r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe
-:[GRP/]EVENT : Clear a probe
GRP : 跟踪点名称
EVENT : 事件名称
MOD : 模块名称
SYM[+offs] : 根据或者符号+偏移设置跟踪点插入位置。
MEMADDR : 直接指定跟踪点地址
FETCHARGS : 参数
%REG : 设置指定寄存器值,函数调用时会通过寄存器传入部分参数,比较有用,如%di
@ADDR : 直接指定内存地址
@SYM[+|-offs] : data数据段符号+偏移
$stackN : 显示内存指第几层堆栈函数地址
$stack : 堆栈地址
$retval : 获取返回值
$comm : 获取current的comm
+|-offs(FETCHARG) :获取FETCHARG指定地址指向的值+off偏移量
NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
FETCHARG:TYPE : type指定以何种形式写入缓冲区,支持u8-64 s8-64 x8-64分别是无符号、符号、二进制显示。以及string以字符串显示。
例子:
echo 'p:my_test icmp_rcv args1=+0(+16(%di)):string comm=$comm' > /sys/kernel/debug/tracing/kprobe_events
参数说明:args是自己指定的字符串会直接打印,%di 是读取di寄存器值,这个是icmp_rcv函数的入参,+16是di指向的结构体偏移16个字节内容也就是sk_buff里面的net_device首地址,+0则是读取net_device第一个内从name的地址,以string输出。
/sys/kernel/debug/tracing/events/kprobes/目录下会自动生成my_test/目录。
my_test/目录下会存在enable、format、filter、id、trigger五个文件。
enable:是否开启这个动态跟踪点
format:显示跟踪点触发之后打印到ring_buff的格式。
id:是此次设置跟踪点的编号
trigger:是跟踪点触发执行的命令。
开启跟踪点:echo 1 > /sys/kernel/debug/tracing/events/kprobes/my_test/enable
cat trace_pipe
cat /sys/kernel/debug/tracing/trace_pipe
<...>-4431 [000] ..s1 294478.149626: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] .Ns1 294478.149633: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] ..s1 294479.170451: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] ..s1 294479.170458: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] ..s1 294480.194439: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] ..s1 294480.194447: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] ..s1 294481.218430: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] ..s1 294481.218437: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] ..s1 294482.242423: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
<...>-4431 [000] ..s1 294482.242430: my_test: (icmp_rcv+0x0/0x390) args1="lo" comm="ping"
echo -:myprobe >> kprobe_events 清除跟踪点。
trigger详细使用可以看下Documentation/trace/events.rst文档。
如果想在跟踪点触发的时候打印跟踪的函数堆栈可以使用上面提到的trigger文件
如果想观察被跟踪函数调用堆栈可以使用如下方法:
1 disable跟踪点,disable就是echo 0 > enable
2 echo stracktrace > 到跟踪点目录下的trigger文件即可
3 enbale跟踪点,enable就是echo 1 > enable
如果只想获取前N次的触发堆栈可以使用 echo 'stacktrace:N' > trigger
移除堆栈也是非常简单,echo '! stacktrace' > trigger
trigger 支持的命令还有很多:
snapshot:触发快照
traceoff [:N]:触发了关闭跟踪点,总共执行多少次触发关闭这个动作。
hist:这个我也没用过想用可以看下内核文档
###########################################################
静态跟踪点:
events/目录下都是静态跟踪点。如events/net/netif_rx/操作方法类似动态跟踪点。