查询内核跟踪点的常见指令:

跟踪类eBPF程序主要用于从系统中提取跟踪信息, 进而为监控、排错、性能优化等提供数据支撑。

关于追踪程序主要有下面这四类:

  • BPF_PROG_TYPE_KPROBE: 用于对特定函数进行动态插桩, 根据函数位置不同, 又可以分为内核态krpobe和用户态uprobe,但是内核函数和 用户函数的定义属于不稳定的API
  • BPF_PROG_TYPE_TRACEPOINT, 用于内核静态工作点,跟踪点可以保持稳定性, 但是不如KPROBE灵活, 无法按需增加新的灵活点
  • BPF_PROG_TYPE_PERF_EVENT, 用于性能事件跟踪、包括内核调用、定时器、硬件等各类性能数据
  • BPF_PROG_TYPE_RAW_TRACEPOINT/WRITABLE: 用于原始跟踪点

通过上面的介绍相信你对跟踪类eBPF程序已经有所了解了, 下面我们就来介绍一些关于如何查找这些内核跟踪点。

为了方便调试, 内核将所有的函数以及非栈变量的地址都抽取到了/proc/kallsyms中, 这样调试器就可以根据地址找出对应的函数和变量名称,这样做的好处就是实际含义的名称要比16进制的地址容易读的多

我们可以使用下面这个命令来进行查询:

cat /proc/kallsyms | wc -l

并不是所有的内核函数都是可跟踪的,只有显式导出的内核函数才可以被 eBPF 进行动态跟踪。因而,通常我们并不直接从内核符号表查询可跟踪点,而是使用我接下来介绍的方法

内核调试文件系统向用户空间提供了内核调试所需要的基本信息, 如内核符号列表、跟踪点、函数跟踪(ftrace)状态以及参数格式等

sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_execve/format

但是这个命令, 是基于我们已经知道跟踪的函数是什么的时候, 那我们我们如何获取所有的追踪函数, 我们可以使用bpftrace这个工具

# 查询所有内核插桩和跟踪点
sudo bpftrace -l

# 使用通配符查询所有的系统调用跟踪点
sudo bpftrace -l 'tracepoint:syscalls:*'

 使用通配符查询所有名字包含"execve"的跟踪点
sudo bpftrace -l '*execve*'

查看对应程序源码

我们在编写完成对应的程序之后, 如果我们希望去找到对应的程序源码, 此时我们可以使用bpftool这个工具.

首先在命令行中输入下面这个命令, 查看对应的程序列表, 找到对应的程序id

bpftool prog list;

比如我查看到的信息有下面这个:

37: tracepoint  tag 89ed9105e10449f4  gpl
        loaded_at 2024-04-21T05:10:17+0000  uid 0
        xlated 88B  jited 70B  memlock 4096B

其中37表示程序的标号, 然后tracepoint表示这个是一个跟踪点类型

有了这个eBPF编号之后我们就可以导出整个eBPF程序的指令, 我们可以使用下面这个命令:

//注意这个x是xlated
sudo bpftool prog dump x id 37

然后我们可以输出id对应的bpf指令, 比如显示出下面这个eBPF程序:

int hello_world(void * ctx):
   0: (b7) r1 = 33               
   1: (6b) *(u16 *)(r10 -4) = r1
   2: (b7) r1 = 1684828783          
   3: (63) *(u32 *)(r10 -8) = r1
   4: (18) r1 = 0x57202c6f6c6c6548  /* W ,olleH */
   6: (7b) *(u64 *)(r10 -16) = r1
   7: (bf) r1 = r10
   8: (07) r1 += -16
   9: (b7) r2 = 14
  10: (85) call bpf_trace_printk#-61616
  11: (b7) r0 = 0 ;返回值为0
  12: (95) exit

loumosx
1 声望0 粉丝

一生只有一个职业, 那就是程序员