Linux kernel 寄存器\u kprobe正在返回-2

Linux kernel 寄存器\u kprobe正在返回-2,linux-kernel,kernel-module,kprobe,Linux Kernel,Kernel Module,Kprobe,为了便于学习,我试图钩住一些内核函数,我在下面编写了简单的内核模块,但是由于某些原因,寄存器\u kprobe总是返回-2。我没有发现任何关于它所说的错误的意思,也不知道如何继续。起初我认为这是因为list\u add是一个内联函数,所以我尝试用kvm\u create\u vm替换它,得到了相同的结果。然后我检查了/proc/kallsyms,发现两者都没有出现在那里。所以我选择了导出的kvm_alloc,仍然得到了错误-2。我还尝试了alloc\u uid,但效果很好 我的问题是:什么样的函

为了便于学习,我试图钩住一些内核函数,我在下面编写了简单的内核模块,但是由于某些原因,
寄存器\u kprobe
总是返回-2。我没有发现任何关于它所说的错误的意思,也不知道如何继续。起初我认为这是因为
list\u add
是一个内联函数,所以我尝试用
kvm\u create\u vm
替换它,得到了相同的结果。然后我检查了
/proc/kallsyms
,发现两者都没有出现在那里。所以我选择了导出的
kvm_alloc
,仍然得到了错误-2。我还尝试了
alloc\u uid
,但效果很好

我的问题是:什么样的函数可以与
kprobes
挂钩

未定义内核__
#定义内核__
#未定义模块
#定义模块
#包括
#包括
#包括
#包括
模块许可证(“GPL”);
静态int pre(结构kprobe*kp,结构pt_regs*regs){
printk(KERN_INFO“它正在工作!\n”);
返回0;
}
静态结构kprobe kp={
.symbol\u name=“列表添加”,
.pre_handler=pre,
.post_handler=NULL,
.fault_handler=NULL
};
int init_模块(void){
printk(KERN_INFO“Hi\n”);
printk(KERN_INFO“register_kprobe:%d\n”,register_kprobe(&kp));
返回0;
}
空洞清理_模块(空洞){
取消注册_kprobe(&kp);
printk(KERN_INFO“Bye\n”);
}
编辑
我划过的那条线是我感到困惑的主要原因。我没有拼写
kvm\u alloc
,它应该是
kvmalloc
,不带下划线。这个函数被很好地钩住了。

负返回值通常可以解释为否定的
errno
值。看一看左右:

因此,问题似乎是
register\u kprobe
找不到什么,可能是
list\u add
符号。让我们深入了解来源,找出原因

调用以解析符号名称,该名称依次调用,它是的
#define
。因此,似乎您需要将想要挂接到kallsyms中的符号挂接起来,这样才能起作用

有关kprobes的文档,请查看内核源代码树中的。关于kprobe'ing内联函数,它说:

如果在可内联的函数中安装探测器,Kprobes会 不尝试查找函数的所有内联实例,并且 在那里安装探针。gcc可以在不被询问的情况下内联函数, 因此,如果你没有看到预期的探针命中,请记住这一点

因此,它对内联函数并不起作用

现在我们已经解决了问题,让我们寻找解决方案。不过,您可能需要为此重新编译内核


首先,确保内核配置选项
CONFIG_KALLSYMS\u ALL
处于启用状态,以确保KALLSYMS了解更多符号。然后,尝试将
list\u add
的实现移动到一个单独的
.c
文件中,并向其中添加
\u属性((noinline))
。新的内核构建速度会慢一些,但我认为您的kprobe模块应该可以使用它。

要探测内联函数,您需要找到它们的内联实例所在的所有PC地址,并将这些地址放到struct kprobes.addr字段中。systemtap之类的工具会在debuginfo中搜索此类内联函数以计算PC地址。参见readelf-wvmlinux;DW_TAG_inlined_子程序、DW_AT_low_pc等

#define ENOENT       2  /* No such file or directory */