2.3 函数:__print_symbol( )
文件包含:
#include <linux/kallsyms.h>
函数定义:
在内核源码中的位置:linux-3.19.3/kernel/kallsyms.c
函数定义格式:void __print_symbol(const char *fmt, unsigned long address)
函数功能描述:
该函数的功能与sprint_symbol( )的函数功能是相似的(见本章中sprint_symbol( )函数的分析),实际上,__print_symbol( )函数的实现中调用了函数sprint_symbol( )。
该函数根据一个内存中的地址address查找一个内核符号,并将该符号的基本信息,例如符号名name、它在内核符号表中的偏移offset和大小size、所属的模块名(如果有的话)等信息以格式化串fmt的形式输出。而sprint_symbol( )函数则是将这些信息放到文本缓冲区buffer中。
输入参数说明:
fmt:输出内核符号基本信息所依据的格式串,由于符号信息是连接成一个字符串的(见本章中sprint_symbol( )函数的分析),因此fmt格式化串中一般包含一个“%s”。
address:内核符号中的某一地址,为输入型参数。
返回参数说明:
该函数无返回值。
实例解析:
编写测试文件:__print_symbol.c
头文件及全局变量声明如下:
#include <linux/module.h> #include <linux/init.h> #include <linux/kallsyms.h> MODULE_LICENSE("GPL"); static int __init __print_symbol_init(void); static void __exit __print_symbol_exit(void); // 符号a_symbol int a_symbol(void) //此处void必须添加 { return 1; } EXPORT_SYMBOL(a_symbol);
模块初始化函数:
int __init __print_symbol_init(void) { char * fmt; //格式化字符串 unsigned long address; //表示符号地址 char * name; //模块名字 struct module * fmodule = NULL; //指向一个模块的指针 address = (unsigned long) __builtin_return_address(0); //当前函数的返回地址 fmt = "it's the first part, \n %s"; __print_symbol(fmt , address ); printk("\n\n"); name = "psmouse"; //可以通过命令lsmod查看当前内核模块,然后选择一个 fmodule = find_module( name ); //查找模块名为“psmouse”的模块 if( fmodule ! = NULL ) { printk("fmodule->name: %s\n", fmodule->name); /* 将模块的内存起始地址赋值给address */ address = (unsigned long)fmodule->module_core; fmt = "it's the second part, \n %s"; __print_symbol(fmt , address ); } printk("\n\n"); /*将当前模块中符号a_symbol的地址加上偏移量 5 赋值给address */ address = (unsigned long)a_symbol + 5; fmt = "it's the third part, \n %s"; __print_symbol(fmt , address ); printk("\n\n"); return 0; }
模块退出函数:
void __exit __print_symbol_exit(void) { printk("module exit ok! \n"); }
模块初始化及退出函数调用:
module_init(__print_symbol_init); module_exit(__print_symbol_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod __print_symbol.ko插入模块,然后执行命令dmesg -c,会出现如图2-4所示的结果。
图2-4 插入__print_symbol模块后系统输出信息
结果分析:
测试程序中调用了f ind_module( )内核函数,它的功能是根据所给的模块名字来获得模块描述符指针的,关于其详细说明见本章中该函数的分析。
关于图2-4所示输出信息内容的说明请参考本章sprint_symbol( )函数的分析。
格式化串赋值如fmt = "it's the f irst part, \n %s",其类似于C语言中的printf( )函数的第一个参数。调用__print_symbol(fmt, address),根据address查找特定符号的基本信息,先把信息存放到文本缓冲区buffer中,然后以格式化串fmt的形式输出。