跳转到内容跳转到页面导航:上一页 [访问键 p]/下一页 [访问键 n]
适用于 openSUSE Leap 15.6

5 内核探针 编辑源文件

内核探针是一组用于收集 Linux 内核调试和性能信息的工具。开发人员和系统管理员使用它们来调试内核,或查找系统性能瓶颈。报告的数据然后可以用于调整系统以获得更好的性能。

您可以将这些探针插入到任何内核例程中,并指定在命中特定断点后调用的处理程序。 内核探针的主要优点是,您在探针中进行更改后,无需重建内核和重新启动系统。

要使用内核探针,通常需要编写或获取特定的内核模块。 这些模块包括 initexit 函数。 init 函数(例如 register_kprobe())注册一个或多个探针,而 exit 函数则取消注册它们。 注册函数定义 探针插入的位置命中探针后调用的处理程序。 要一次性注册或取消注册一组探针,可以使用相关的 register_<PROBE_TYPE>probes()unregister_<PROBE_TYPE>probes() 函数。

调试和状态消息通常使用 printk 内核例程报告。 printk 是用户空间 printf 例程的内核空间等效项。 有关 printk 的更多信息,请参阅 记录内核消息。 通常,您可以可以通过检查 systemd 日志的输出来查看这些消息(请参阅 “参考”手册,第 11 章“journalctl:查询 systemd 日志”)。 有关日志文件的更多信息,请参阅 第 3 章,系统日志文件

5.1 支持的架构 编辑源文件

内核探针在以下架构上完全实现

  • x86

  • AMD64/Intel 64

  • Arm

  • POWER

内核探针在以下架构上部分实现

  • IA64(不支持指令 slot1 上的探针)

  • sparc64(尚未实现返回探针)

5.2 内核探针类型 编辑源文件

有三种类型的内核探针:KprobesJprobesKretprobes。 Kretprobes 有时称为 返回探针。 您可以在 Linux 内核中找到所有三种类型探针的源代码。 请参阅目录 /usr/src/linux/samples/kprobes/(软件包 kernel-source)。

5.2.1 Kprobes 编辑源文件

Kprobes 可以附加到 Linux 内核中的任何指令。 注册 Kprobes 时,它会将断点插入到被探测指令的第一个字节处。 当处理器命中此断点时,处理器寄存器将被保存,并且处理将传递给 Kprobes。 首先,将执行 预处理程序,然后将执行被探测的指令,最后将执行 后处理程序。 然后将控制权传递给探针点后的指令。

5.2.2 Jprobes 编辑源文件

Jprobes 通过 Kprobes 机制实现。 它插入到函数的入口点,并允许直接访问被探测函数的参数。 其处理程序例程必须具有与被探测函数相同的参数列表和返回值。 要结束它,请调用 jprobe_return() 函数。

当命中 jprobe 时,处理器寄存器将被保存,并且指令指针将定向到 jprobe 处理程序例程。 然后将控制权传递给处理程序,其寄存器内容与被探测的函数相同。 最后,处理程序调用 jprobe_return() 函数,并将控制权切换回控制函数。

通常,您可以将多个探针插入到一个函数中。 但是,Jprobe 仅限于每个函数一个实例。

5.2.3 返回探针 编辑源文件

返回探针也通过 Kprobes 实现。 当调用 register_kretprobe() 函数时,kprobe 将附加到被探测函数的入口处。 命中探针后,内核探针机制将保存被探测函数的返回地址并调用用户定义的返回处理程序。 然后将控制权传递回被探测的函数。

在调用 register_kretprobe() 之前,需要设置 maxactive 参数,该参数指定可以同时探测的函数实例数量。 如果设置得太低,则会错过一定数量的探针。

5.3 Kprobes API 编辑源文件

Kprobes 的编程接口由用于注册和取消注册所有使用的内核探针及其关联探针处理程序的函数组成。 有关这些函数及其参数的更详细描述,请参阅 第 5.5 节,“更多信息” 中的信息来源。

register_kprobe()

在指定的地址插入断点。 命中断点时,将调用 pre_handlerpost_handler

register_jprobe()

在指定的地址插入断点。 该地址需要是被探测函数的第一个指令的地址。 命中断点时,将运行指定的处理程序。 处理程序应具有与被探测函数相同的参数列表和返回类型。

register_kretprobe()

为指定的函数插入返回探针。 当被探测的函数返回时,将运行指定的处理程序。 此函数在成功时返回 0,或在失败时返回负错误编号。

unregister_kprobe()unregister_jprobe()unregister_kretprobe()

删除指定的探针。 可以在探针注册后随时使用它。

register_kprobes()register_jprobes()register_kretprobes()

插入指定数组中的每个探针。

unregister_kprobes()unregister_jprobes()unregister_kretprobes()

删除指定数组中的每个探针。

disable_kprobe()disable_jprobe()disable_kretprobe()

暂时禁用指定的探针。

enable_kprobe()enable_jprobe()enable_kretprobe()

暂时启用禁用的探针。

5.4 debugfs 接口 编辑源文件

在最近的 Linux 内核中,Kprobes 仪器化使用内核的 debugfs 接口。 它可以列出所有已注册的探针并全局打开或关闭所有探针。

5.4.1 列出已注册的内核探针 编辑源文件

所有当前已注册探针的列表位于 /sys/kernel/debug/kprobes/list 文件中。

saturn.example.com:~ # cat /sys/kernel/debug/kprobes/list
c015d71a  k  vfs_read+0x0   [DISABLED]
c011a316  j  do_fork+0x0
c03dedc5  r  tcp_v4_rcv+0x0

第一列列出内核中插入探针的地址。 第二列打印探针的类型:k 表示 kprobe,j 表示 jprobe,r 表示返回探针。 第三列指定探针的符号、偏移量和可选的模块名称。 以下可选列包括探针的状态信息。 如果探针插入到不再有效的虚拟地址上,则标记为 [GONE]。 如果探针被暂时禁用,则标记为 [DISABLED]

5.4.2 全局启用/禁用内核探针 编辑源文件

文件 /sys/kernel/debug/kprobes/enabled 表示一个开关,您可以使用它全局强制打开或关闭所有已注册的内核探针。 要关闭它们,只需输入

# echo "0" > /sys/kernel/debug/kprobes/enabled

在命令行中作为 root。 要再次打开它们,请输入

# echo "1" > /sys/kernel/debug/kprobes/enabled

使用此类操作,您不会更改探针的状态。 如果探针被暂时禁用,则在输入后一个命令后,它不会自动启用,但仍处于 [DISABLED] 状态。

5.5 更多信息 编辑源文件

要了解有关内核探针的更多信息,请查看以下信息来源

  • 关于内核探针的详尽但更具技术性的信息位于 /usr/src/linux/Documentation/trace/kprobes.txt(软件包 kernel-source)。

  • 所有三种类型探针的示例(以及相关的 Makefile)位于 /usr/src/linux/samples/kprobes/ 目录中(软件包 kernel-source)。

  • 有关 Linux 内核模块和 printk 内核例程的深入信息可以在 Linux 内核模块编程指南 中找到

打印此页面