Win*_*ser 1 kernel-module linux-kernel
在内核模块中,如何列出所有内核符号及其地址?不应重新编译内核。
我知道接口中的“ cat / proc / kallsyms”,但是如何使用诸如之类的函数直接从内核数据结构中获取它们kallsyms_lookup_name。
工作模块代码:
#include <linux/module.h>
#include <linux/kallsyms.h>
static int prsyms_print_symbol(void *data, const char *namebuf,
struct module *module, unsigned long address)
{
pr_info("### %lx\t%s\n", address, namebuf);
return 0;
}
static int __init prsyms_init(void)
{
kallsyms_on_each_symbol(prsyms_print_symbol, NULL);
return 0;
}
static void __exit prsyms_exit(void)
{
}
module_init(prsyms_init);
module_exit(prsyms_exit);
MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Module for printing all kernel symbols");
MODULE_LICENSE("GPL");
Run Code Online (Sandbox Code Playgroud)
kernel / kallsyms.c实现/proc/kallsyms。它的某些功能可供外部使用。它们通过EXPORT_SYMBOL_GPL()宏导出。是的,您的模块应具有GPL使用许可。这些功能是:
kallsyms_lookup_name()kallsyms_on_each_symbol()sprint_symbol()sprint_symbol_no_offset()要使用这些功能,请包含<linux/kallsyms.h>在模块中。应该提到的是,CONFIG_KALLSYMS必须=y在内核配置中启用()。
要打印所有符号,您显然必须使用kallsyms_on_each_symbol()函数。文档接下来会说:
/* Call a function on each kallsyms symbol in the core kernel */
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
unsigned long), void *data);
Run Code Online (Sandbox Code Playgroud)
在哪里fn应该为找到的每个符号调用您的回调函数,并且data是指向您的一些私有数据的指针(将作为第一个参数传递给您的回调函数)。
回调函数必须具有下一个签名:
int fn(void *data, const char *namebuf, struct module *module,
unsigned long address);
Run Code Online (Sandbox Code Playgroud)
将使用以下参数为每个内核符号调用此函数:
data:将包含指向您作为最后一个参数传递给您的私人数据的指针 kallsyms_on_each_symbol()namebuf:将包含当前内核符号的名称module:永远是NULL,只要忽略那个address:将包含当前内核符号的地址返回值应始终为0(在非零返回值时,通过符号进行的迭代将被中断)。
回答您评论中的问题。
另外,有没有一种方法可以输出每个函数的大小?
是的,您可以使用sprint_symbol()我上面提到的功能来做到这一点。它将以以下格式打印符号信息:
symbol_name+offset/size [module_name]
Run Code Online (Sandbox Code Playgroud)
例:
psmouse_poll+0x0/0x30 [psmouse]
Run Code Online (Sandbox Code Playgroud)
如果符号是内置的,则可以省略模块名称部分。
我尝试了该模块,并使用“ dmesg”查看了结果。但是缺少许多符号,例如“ futex_requeue”。输出符号数约为10K,而当我使用“ nm vmlinux”时,输出符号数为100K。
这很可能是因为您的printk缓冲区大小不足以存储上面模块的所有输出。
让我们对上述模块进行一些改进,以便它通过miscdevice提供符号信息。另外,我们还根据要求将函数大小添加到输出中。代码如下:
symbol_name+offset/size [module_name]
Run Code Online (Sandbox Code Playgroud)
这是如何使用它:
$ sudo insmod prsyms2.ko
$ sudo cat /dev/prsyms2 >symbols.txt
$ wc -l symbols.txt
$ sudo rmmod prsyms2
Run Code Online (Sandbox Code Playgroud)
文件symbols.txt将以以下格式包含所有内核符号(内置和来自加载的模块):
ffffffffc01dc0d0 psmouse_poll+0x0/0x30 [psmouse]
Run Code Online (Sandbox Code Playgroud)
看来我可以
kallsyms_lookup_name()用来查找函数的地址,然后可以使用函数指针来调用该函数吗?
是的你可以。如果我没记错的话,那就是反射。以下是如何执行此操作的示例:
psmouse_poll+0x0/0x30 [psmouse]
Run Code Online (Sandbox Code Playgroud)