rawtracepoint机制介绍

说明

通过查看 /sys/kernel/debug/tracing/events/raw_syscalls 目录,你可以获取系统中所有可用的 raw_tracepoint 的列表。

请注意,访问 /sys/kernel/debug/tracing 目录通常需要 root 权限或者在调试组中的用户权限。因此,你可能需要以超级用户(root)或使用 sudo 来执行上述命令。

希望这能帮助你在 Linux 系统上查看系统中的 raw_tracepoint,而无需依赖第三方工具。在当前目录下查看,可以看到如下的文件:

1
2
3
4
5
6
7
8
# ls -al  /sys/kernel/debug/tracing/events/raw_syscalls/
total 0
drwxr-x--- 4 root root 0 7月 27 10:17 .
drwxr-x--- 123 root root 0 7月 27 10:17 ..
-rw-r----- 1 root root 0 7月 27 10:17 enable
-rw-r----- 1 root root 0 7月 27 10:17 filter
drwxr-x--- 2 root root 0 7月 27 10:17 sys_enter
drwxr-x--- 2 root root 0 7月 27 10:17 sys_exit

可以看到,在当前的目录下,存在两个raw_tracepoint类型的系统调用,分别是sys_entersys_exit。一般情况下,在Linux默认情况下,都会存在sys_entersys_exit,这两个raw_tracepoint类型的系统调用。

Raw Tracepoint 是一种更底层的跟踪机制,它允许开发人员在内核中的任意位置定义自定义的跟踪事件。Raw Tracepoint 提供了更大的灵活性,因为开发人员可以在内核的任意代码路径中插入跟踪点,以捕获感兴趣的事件。与 Tracepoint 不同,Raw Tracepoint 的定义和触发点是在内核编译时生成的,而不是在源代码中静态定义的。开发人员可以使用 tracepoint.h 头文件中的宏来定义和触发 Raw Tracepoint。

sys_enter

/sys/kernel/debug/tracing/events/raw_syscalls/sys_enter 查看目录下具体的内容:

1
2
3
4
5
6
7
8
9
10
total 0
drwxr-x--- 2 root root 0 7月 6 09:56 .
drwxr-x--- 4 root root 0 7月 6 09:56 ..
-rw-r----- 1 root root 0 7月 6 09:56 enable
-rw-r----- 1 root root 0 7月 6 09:56 filter
-r--r----- 1 root root 0 7月 6 09:56 format
-r--r----- 1 root root 0 7月 6 09:56 hist
-r--r----- 1 root root 0 7月 6 09:56 id
--w------- 1 root root 0 7月 6 09:56 inject
-rw-r----- 1 root root 0 7月 6 09:56 trigger

每个文件的含义如下:

  • enable: 用于启用或禁用 sys_enter 事件的跟踪。通过向该文件写入 10 来启用或禁用跟踪。
  • filter: 用于设置 sys_enter 事件的过滤器。你可以将过滤条件写入该文件,以便只跟踪满足条件的 sys_enter 事件。
  • format: 包含了 sys_enter 事件的格式定义。你可以读取该文件来获取 sys_enter 事件的参数和输出格式。
  • hist: 包含了 sys_enter 事件的历史记录,包括每个事件的计数和时间戳等信息。
  • id: 包含了 sys_enter 事件的唯一标识符。
  • inject: 用于触发 sys_enter 事件的注入。通过向该文件写入相应的值,可以手动触发 sys_enter 事件。
  • trigger: 用于触发 sys_enter 事件的触发器。通过向该文件写入相应的值,可以触发 sys_enter 事件。

针对其中的几个主要文件进行分析:

format

1
2
3
4
5
6
7
8
9
10
11
12
name: sys_enter
ID: 348
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:long id; offset:8; size:8; signed:1;
field:unsigned long args[6]; offset:16; size:48; signed:0;

print fmt: "NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)", REC->id, REC->args[0], REC->args[1], REC->args[2], REC->args[3], REC->args[4], REC->args[5]

通过print fmt,可以看到具体的输出格式,NR表示系统调用号,后面的%lx表示具体的参数,REC->args[0]表示第一个参数,REC->args[1]表示第二个参数,以此类推。

在内核文件 syscalls.h 中也可以找到对应的定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS

TRACE_EVENT_FN(sys_enter,

TP_PROTO(struct pt_regs *regs, long id),

TP_ARGS(regs, id),

TP_STRUCT__entry(
__field( long, id )
__array( unsigned long, args, 6 )
),

TP_fast_assign(
__entry->id = id;
syscall_get_arguments(current, regs, __entry->args);
),

TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)",
__entry->id,
__entry->args[0], __entry->args[1], __entry->args[2],
__entry->args[3], __entry->args[4], __entry->args[5]),

syscall_regfunc, syscall_unregfunc
);

内核态

为了方便演示raw_tracepoint的功能,

参考

https://mozillazg.com/2022/05/ebpf-libbpf-raw-tracepoint-common-questions-en.html