如何使用 LKM 内的 perf 接口读取已停用的指令?

问题描述

如何从内核空间内部读取 PMU?

对于分析任务,我需要从内核内部读取 PMU 提供的停用指令。 perf_event_open 系统调用似乎提供了这种能力。在我的源代码中我

#include <linux/syscalls.h>

为 perf_event_attr 结构设置我的参数并调用 sys_perf_event_open()。提到的头文件包含函数声明。检查“/proc/kallsyms”时,确认存在名为sys_perf_event_open 的系统调用。该符号在全球范围内可用 T 表示:

ffffffff8113fe70 T sys_perf_event_open

所以据我所知,一切都应该有效。

不过,在编译或插入 LKM 时,我收到一个警告/错误,指出 sys_perf_event_open 不存在。

WARNING: "sys_perf_event_open" [/home/vagrant/mods/lkm_read_pmu/read_pmu.ko] undefined!

我需要做什么才能获得那些退役指令计数器?

解决方法

/proc/kallsyms 文件显示了源代码中定义的所有内核符号。没错,大写的T表示内核二进制的文本部分中的全局符号,但是这里的“全局”的含义是根据C语言来定义的。也就是说,它可以在内核本身的其他文件中使用。不能仅仅因为内核模块是全局的就从内核模块调用内核函数。

内核模块只能使用内核源代码中用 EXPORT_SYMBOL 导出的内核符号。从内核 2.6.0 开始,没有任何系统调用被导出,因此您不能从内核模块调用它们中的任何一个,包括 sys_perf_event_open。系统调用实际上是为了从用户空间调用而设计的。这一切意味着您不能在内核模块中使用 perf_event 子系统。

也就是说,我认为您可以修改内核以将 EXPORT_SYMBOL 添加到 sys_perf_event_open。这将使它成为一个导出符号,这意味着它可以从内核模块中使用。