Uprobe-tracer: 基于 Uprobe 的事件追踪¶
- 作者:
Srikar Dronamraju
概述¶
基于 Uprobe 的追踪事件类似于基于 kprobe 的追踪事件。要启用此功能,请使用 CONFIG_UPROBE_EVENTS=y 构建内核。
与 kprobe 事件追踪器类似,此功能不需要通过 current_tracer 激活。 相反,通过 /sys/kernel/tracing/uprobe_events 添加探针点,并通过 /sys/kernel/tracing/events/uprobes/<EVENT>/enable 启用它。
但是,与 kprobe 事件追踪器不同,uprobe 事件接口期望用户计算对象中探针点的偏移量。
您也可以使用 /sys/kernel/tracing/dynamic_events 而不是 uprobe_events。该接口还将提供对其他动态事件的统一访问。
uprobe_tracer 概要¶
p[:[GRP/][EVENT]] PATH:OFFSET [FETCHARGS] : Set a uprobe
r[:[GRP/][EVENT]] PATH:OFFSET [FETCHARGS] : Set a return uprobe (uretprobe)
p[:[GRP/][EVENT]] PATH:OFFSET%return [FETCHARGS] : Set a return uprobe (uretprobe)
-:[GRP/][EVENT] : Clear uprobe or uretprobe event
GRP : Group name. If omitted, "uprobes" is the default value.
EVENT : Event name. If omitted, the event name is generated based
on PATH+OFFSET.
PATH : Path to an executable or a library.
OFFSET : Offset where the probe is inserted.
OFFSET%return : Offset where the return probe is inserted.
FETCHARGS : Arguments. Each probe can have up to 128 args.
%REG : Fetch register REG
@ADDR : Fetch memory at ADDR (ADDR should be in userspace)
@+OFFSET : Fetch memory at OFFSET (OFFSET from same file as PATH)
$stackN : Fetch Nth entry of stack (N >= 0)
$stack : Fetch stack address.
$retval : Fetch return value.(\*1)
$comm : Fetch current task comm.
+|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*2)(\*3)
\IMM : Store an immediate value to the argument.
NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
(u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
(x8/x16/x32/x64), "string" and bitfield are supported.
(\*1) only for return probe.
(\*2) this is useful for fetching a field of data structures.
(\*3) Unlike kprobe event, "u" prefix will just be ignored, because uprobe
events can access only user-space memory.
类型¶
fetch-args 支持多种类型。 Uprobe 追踪器将按给定的类型访问内存。前缀“s”和“u”表示这些类型分别是带符号的和无符号的。“x”前缀表示它是无符号的。追踪的参数以十进制(“s”和“u”)或十六进制(“x”)显示。在没有类型转换的情况下,根据架构使用“x32”或“x64”(例如,x86-32 使用 x32,而 x86-64 使用 x64)。 字符串类型是一种特殊类型,它从用户空间获取一个“以 null 结尾”的字符串。位域是另一种特殊类型,它接受 3 个参数:位宽、位偏移和容器大小(通常为 32)。语法是
b<bit-width>@<bit-offset>/<container-size>
对于 $comm,默认类型是“string”; 任何其他类型都是无效的。
事件分析¶
您可以通过 /sys/kernel/tracing/uprobe_profile 检查每个事件的探针命中总数。 第一列是文件名,第二列是事件名称,第三列是探针命中次数。
使用示例¶
添加一个探针作为新的 uprobe 事件,如下所示向 uprobe_events 写入新定义(在可执行文件 /bin/bash 中 0x4245c0 的偏移量处设置一个 uprobe)
echo 'p /bin/bash:0x4245c0' > /sys/kernel/tracing/uprobe_events添加一个探针作为新的 uretprobe 事件
echo 'r /bin/bash:0x4245c0' > /sys/kernel/tracing/uprobe_events取消设置注册的事件
echo '-:p_bash_0x4245c0' >> /sys/kernel/tracing/uprobe_events打印出已注册的事件
cat /sys/kernel/tracing/uprobe_events清除所有事件
echo > /sys/kernel/tracing/uprobe_events
以下示例展示了如何在探针的文本地址处转储指令指针和 %ax 寄存器。在 /bin/zsh 中探测 zfree 函数
# cd /sys/kernel/tracing/
# cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp
00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh
# objdump -T /bin/zsh | grep -w zfree
0000000000446420 g DF .text 0000000000000012 Base zfree
0x46420 是加载在 0x00400000 的对象 /bin/zsh 中 zfree 的偏移量。因此,uprobe 的命令将是
# echo 'p:zfree_entry /bin/zsh:0x46420 %ip %ax' > uprobe_events
而 uretprobe 的命令将是相同的
# echo 'r:zfree_exit /bin/zsh:0x46420 %ip %ax' >> uprobe_events
注意
用户必须显式计算对象中探针点的偏移量。
我们可以通过查看 uprobe_events 文件来查看已注册的事件。
# cat uprobe_events
p:uprobes/zfree_entry /bin/zsh:0x00046420 arg1=%ip arg2=%ax
r:uprobes/zfree_exit /bin/zsh:0x00046420 arg1=%ip arg2=%ax
可以通过查看文件 events/uprobes/zfree_entry/format 来查看事件的格式。
# cat events/uprobes/zfree_entry/format
name: zfree_entry
ID: 922
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int common_padding; offset:8; size:4; signed:1;
field:unsigned long __probe_ip; offset:12; size:4; signed:0;
field:u32 arg1; offset:16; size:4; signed:0;
field:u32 arg2; offset:20; size:4; signed:0;
print fmt: "(%lx) arg1=%lx arg2=%lx", REC->__probe_ip, REC->arg1, REC->arg2
定义后,默认情况下每个事件都被禁用。 要追踪这些事件,您需要通过以下方式启用它
# echo 1 > events/uprobes/enable
让我们开始追踪,休眠一段时间并停止追踪。
# echo 1 > tracing_on
# sleep 20
# echo 0 > tracing_on
此外,您可以通过以下方式禁用该事件
# echo 0 > events/uprobes/enable
您可以通过 /sys/kernel/tracing/trace 查看追踪的信息。
# cat trace
# tracer: nop
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
zsh-24842 [006] 258544.995456: zfree_entry: (0x446420) arg1=446420 arg2=79
zsh-24842 [007] 258545.000270: zfree_exit: (0x446540 <- 0x446420) arg1=446540 arg2=0
zsh-24842 [002] 258545.043929: zfree_entry: (0x446420) arg1=446420 arg2=79
zsh-24842 [004] 258547.046129: zfree_exit: (0x446540 <- 0x446420) arg1=446540 arg2=0
输出显示 uprobe 被 pid 24842 触发,ip 为 0x446420,ax 寄存器的内容为 79。uretprobe 被触发,ip 为 0x446540,对应的函数入口为 0x446420。