linux查询内核模块api,模块机制 – Linux内核API find_symbol

find_symbol函数功能描述:函数find_symbol()通过给定的内核符号的名字name,以及bool型参数gplok、warn来查找内核符号,并返回描述该符号的结构体指针。如果内核符号存在于动态插入的模块且参数owner不为空,则指针owner指向该模块。

find_symbol文件包含

#include

find_symbol函数定义

在内核源码中的位置:linux-3.19.3/kernel/module.c

函数定义格式:

const struct kernel_symbol *f ind_symbol(const char *name,

struct module **owner,

const unsigned long **crc,

bool gplok,

bool warn)

find_symbol输入参数说明

name:字符串常量,表示待查找的内核符号的名字,是一个输入型参数。

owner:二级指针,指向所查找的内核符号所属的内核模块的指针,是一个输出型参数,它可以为空。关于结构体module的定义请参见前面关于内核函数find_module()的分析。

crc:二级指针,*crc表示内核符号的crc值所在的地址,它是一个输出型参数。

gplok:bool型变量,如果为真,表示内核符号所属的模块支持GPL许可,如果为假,则不支持。它是一个输入型参数。

warn:bool型变量,表示是否输出警告信息。它是一个输入型参数。

find_symbol返回参数说明

如果函数find_symbol()查找内核符号成功,则返回值是kernel_symbol结构体类型的指针,它是对所查找到的内核符号的描述,如果查找失败,则返回NULL。

其中内核符号结构体kernel_symbol在内核文件linux-3.19.3/include/linux/export.h中定义:

struct kernel_symbol

{

/*value:如果EXPORT_SYMBOL(fun),则value为符号fun在内核映像中的地址*/

unsigned long value;

/*name:指向符号名fun的指针*/

const char *name;

};

find_symbol实例解析

编写测试文件:find_symbol.c

头文件及全局变量声明如下:

#include

#include

MODULE_LICENSE("GPL");

static int __init find_symbol_init(void);

static void __exit find_symbol_exit(void);

模块初始化函数:

int __init find_symbol_init(void)

{

const char * name = "symbol_A"; //待查找的内核符号的名字

struct kernel_symbol * ksymbol ; //用于接收测试函数返回值

struct module * owner; //内核符号所属的模块

const unsigned long *crc;

bool gplok = true; //模块支持GPL许可

bool warn = true; //允许输出警告信息

ksymbol = find_symbol(name, &owner, &crc, gplok, warn); //调用待测试函数

if( ksymbol ! = NULL )

{

/*输出查找到的内核符号在内存中的地址*/

printk("ksymbol->value : %lx\n", ksymbol->value);

printk("ksymbol->name : %s\n", ksymbol->name); //输出内核符号名字

}

else

printk("Failed to find symbol %s\n", name);

if( owner ! = NULL )

{

/*输出内核符号所属的模块的名字*/

printk("owner->name : %s\n", owner->name);

}

if( crc ! = NULL )

{

/* 输出内核符号的crc值所在的地址*/

printk("*crc : %lx\n", *crc);

}

return 0;

}

模块退出函数:

void __exit find_symbol_exit(void)

{

printk("module exit ok! \n");

}

模块初始化及退出函数调用:

module_init(find_symbol_init);

module_exit(find_symbol_exit);

实例运行结果及分析:

首先编译模块,执行命令insmod f ind_symbol.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。

cc9564ccc99cfc25b8c23d2f520db236.png

结果分析:

在该测试程序中,调用find_symbol()内核函数查找名字为“symbol_A”的内核符号,然后输出该符号的相关信息,如内存地址、所属模块名等。

由kernel_symbol类型的结构体指针ksymbol接收函数返回值,通过输出ksymbol->value可知内核符号“symbol_A”的内存地址为0xffffffffa0311000,输出ksymbol->name为“symbol_A”说明与传入的内核符号名相同。owner为内核符号所属的模块,由owner->name得知模块名为“test_module”。最后输出*crc为0x26b316c0。

为了验证上述结果的正确性,在终端通过命令cat /proc/kallsyms | grep symbol_A显示内核符号symbol_A的相关信息,如图所示。

e2610dc0f9fbe06408e7e95d87eb8c4e.png

虚拟文件系统proc中的kallsym文件列出了所有内核符号的相关信息,它是在内核启动时将内核符号添加到kallsym符号表中的。动态插入的模块中所包含的符号也会动态加载到该kallsyms符号表中。

关于内核符号的说明:

现在通过一个实例文件test_module.c说明内核符号的导出,该文件的代码如下:

#include

#include

MODULE_LICENSE("GPL");

static int __init test_module_init(void);

static void __exit test_module_exit(void);

int symbol_A(void)

{

return 1;

}

EXPORT_SYMBOL(symbol_A);

int symbol_B(void)

{

return 0;

}

EXPORT_SYMBOL(symbol_B);

static int symbol_1 = 1;

int symbol_2 = 2;

int symbol_3 = 3;

EXPORT_SYMBOL(symbol_3);

int __init test_module_init(void)

{

printk("<0>hello world");

return 0;

}

void __exit test_module_exit(void)

{

printk("<0>module exit ok! \n");

}

module_init(test_module_init);

module_exit(test_module_exit);

编译模块,生成test_module.ko文件,对该文件执行nm命令即nm -l test_module.ko,显示信息如图所示。

c0f99373ca0e5ea3a3c7a73f2edc5387.png

上图中第三列均为test_module.ko文件中的内核符号,第一列为相应的地址,第二列为内核符号的属性,r表示只读,A表示在内存中的地址是绝对的,D表示内核符号在数据区初始化,T表示全局,t表示局部,U表示符号未定义。

从图中可以看出symbol_1并未显示出来,因为它被定义为static类型,symbol_2和symbol_3为全局数据对象,另外可以看到symbol_3在模块的字符串表和符号表中,即存在__ksymtab_symbol_3、__kstrtab_symbol_3、__crc_symbol_3,而symbol_2则没有,这是因为它没有通过export导出。通过export导出的符号在模块的字符串表和符号表中有相应的入口地址,可以方便地被其他模块加载。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值