__module_address函数功能描述:函数__module_address( )根据给定的一个内存地址addr,获得该内存地址所在的模块。
__module_address文件包含
#include <linux/module.h>
__module_address函数
在内核源码中的位置:linux-3.19.3/kernel/module.c
函数定义格式:
struct module *__module_address(unsigned long addr)
__module_address输入参数说明
addr:其值表示内存地址。
__module_address返回参数说明
如果内存地址addr在某一模块的地址空间中,则返回指向该模块的结构体指针,否则返回NULL。
__module_address实例解析
编写测试文件:__module_address.c
头文件及全局变量声明如下:
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
static int __init __module_address_init(void);
static void __exit __module_address_exit(void);
模块初始化函数:
int a_module(void) //此处定义一个自己添加的内核函数,函数参数必须写入void
{
return 0;
}
int __init __module_address_init(void)
{
struct module * ret ; //用于接收测试函数返回值
unsigned long addr = (unsigned long)a_module; //得到内核符号a_module的地址
/*调用__module_address( )函数之前,必须禁止中断,以防止模块在执行操作期间被释放*/
preempt_disable( ); //禁止抢占
ret = __module_address(addr) ;
preempt_enable( ); //允许抢占
/* 如果返回不为空,则输出该模块的信息 */
if( ret ! = NULL )
{
printk("ret->name: %s\n", ret->name); //输出模块名
printk("ret->state: %d\n", ret->state); //输出模块状态
printk("ret->core_size: %d\n", ret->core_size); //输出模块core段所占空间大小
printk("refs of %s is %d \n", ret->name, module_refcount(ret));
// 输出模块引用计数
}
else
{
printk("__module_address return NULL ! \n");
}
return 0;
}
模块退出函数:
void __exit __module_address_exit(void)
{
printk("module exit ok! \n");
}
模块初始化及退出函数调用:
module_init(__module_address_init);
module_exit(__module_address_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod __module_address.ko插入模块,然后执行命令dmesg -c,出现如图所示的结果。
结果分析:
在该测试程序中,首先令函数__module_address()的参数addr取值为函数a_module()的入口地址,显然addr所表示的内存地址在待加载模块__module_address中。
然后调用__module_address()函数,为了防止模块被释放,需要禁止抢占,宏preempt_disable()和preempt_enable()分别用来实现禁止内核抢占和允许内核抢占。如果查找到内存地址addr所属的模块,则输出该模块的name、state等信息。由上图中的输出信息可知,ret->name
恰为“__module_address”, ret->state
为1(即表示该模块处于正在被加载的MODULE_STATE_COMING状态,见下面关于枚举类型module_state的说明), ret->core_size
为12469字节,然后调用module_refcount()得到该模块的引用计数为1。