zoukankan      html  css  js  c++  java
  • Linux内核API sprint_symbol【转】

    转自:https://deepinout.com/linux-kernel-api/linux-kernel-api-module-mechanism/linux-kernel-api-sprint_symbol.html

    sprint_symbol函数功能描述:该函数根据一个内存中的地址address查找一个内核符号,并将该符号的基本信息,如符号名name、它在内核符号表中的偏移offset和大小size、所属的模块名(如果有的话)等信息连接成字符串赋值给文本缓冲区buffer。

    其中所查找的内核符号可以是原本就存在于内核中的符号,也可以是位于动态插入的模块中的符号。

    sprint_symbol文件包含

    #include <linux/kallsyms.h>
    C

    sprint_symbol函数定义

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

    函数定义格式:

    int sprint_symbol(char *buffer, unsigned long address)
    C

    sprint_symbol输入参数说明

    buffer:文本缓冲区,它用来记录内核符号的信息,它是一个输出型参数。

    address:内核符号中的某一地址,为输入型参数。

    sprint_symbol返回参数说明

    返回值是一个int型,它表示内核符号基本信息串的长度,即buffer所表示的字符串的长度。

    sprint_symbol实例解析

    编写测试文件:sprint_symbol.c

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

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/kallsyms.h>
    MODULE_LICENSE("GPL");
    static int __init sprint_symbol_init(void);
    static void __exit sprint_symbol_exit(void);
    
    // 符号a_symbol
    int a_symbol(void)
    {
        return 1;
    }
    EXPORT_SYMBOL(a_symbol);
    C

    模块初始化函数:

    int __init sprint_symbol_init(void)
    {
        char buffer[KSYM_SYMBOL_LEN];                     //声明一个文本缓冲区
        int ret;                                          //接收sprint_symbol( )函数返回值
        unsigned long address;                            //表示符号地址
        char * name;                                     //模块名字
        struct module * fmodule = NULL;                  //指向一个模块的指针
        address = (unsigned long) __builtin_return_address(0); //当前函数的返回地址
    
        ret = sprint_symbol( buffer , address );
        printk("ret: %d
    ", ret );                        //输出返回值
        printk("buffer: %s
    ", buffer );                  //输出文本缓冲区buffer的内容
        printk("
    ");
    
        name = "test_module";
        fmodule = find_module( name );                //查找模块名为" test_module"的模块
        if( fmodule ! = NULL )
        {
            printk("fmodule->name: %s
    ", fmodule->name);
    
            //将模块的内存起始地址赋值给address
            address = (unsigned long)fmodule->module_core;
            ret = sprint_symbol( buffer , address );
            printk("ret: %d
    ", ret );
            printk("buffer: %s
    ", buffer );
        }
        printk("
    ");
    
        //将当前模块中符号a_symbol的地址加上偏移量5赋值给address
        address = (unsigned long)a_symbol + 5;
        ret = sprint_symbol( buffer , address );
        printk("ret: %d
    ", ret );
        printk("buffer: %s
    ", buffer );
        return 0;
    }
    C

    模块退出函数:

    void __exit sprint_symbol_exit(void)
    {
        printk("module exit ok! 
    ");
    }
    C

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

    module_init(sprint_symbol_init);
    module_exit(sprint_symbol_exit);
    C

    实例运行结果及分析:

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

    结果分析:

    测试程序中调用了find_symbol()内核函数,它的功能是根据所给的模块名字来获得模块描述符指针的。

    在测试程序中首先声明一个文本缓冲区buffer,其容量为KSYM_SYMBOL_LEN,它是一个宏,在linux-3.19.3/include/linux/kallsyms.h文件中定义,是内核指定的存储内核符号基本信息的长度。

    #define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN -1) + 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN -1) + 1)
    C

    测试程序分成三个部分来测试函数sprint_symbol()的功能。

    第一部分是将参数address赋值为__builtin_return_address(0),它指当前函数的返回地址,也即测试程序中sprint_symbol_init()的返回地址。由输出信息可知,buffer的内容为“do_one_initcall+0xfe/0x189”,其中“do_one_initcall”为内核符号名,0xfe为address相对于该符号起始地址的偏移,0x189则为符号所占内存空间的大小。可以看到buffer中没有关于内核模块名的信息,这是因为do_one_initcall原本就存在于内核中,它不属于某一通过动态加载而插入内核的模块。而ret = 26则表示buffer缓冲区的内容为26字节。

    第二部分是将参数address赋值为某一模块的内存起始地址,该模块通过find_symbol()函数查找得到。输出信息中buffer的内容与第一部分的类似,只是最后增加了“[test_module]”,它是符号所属的模块名。

    第三部分将当前模块中符号a_symbol的地址加上偏移量5赋值给address,输出信息与第二部分类似。这里说明一下buffer中关于该符号的偏移量0x5,它是参数address相对于符号起始地址的偏移量,如果将address赋值为a_symbol的地址,则buffer中关于符号的偏移量将为0x0。

    【作者】张昺华
    【大饼教你学系列】https://edu.csdn.net/course/detail/10393
    【新浪微博】 张昺华--sky
    【twitter】 @sky2030_
    【微信公众号】 张昺华
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    DPDK 多进程
    dpdk helloword
    dpdk-ring-ping
    【基于python实现UI自动化】3.0 selenium
    算法题:实现 strStr()函数
    python程序设计:某体操比赛共有10名运动员参加,12名评委将根据运动员表现进行评分(满分10分),请编写Python程序,解决下列问题:
    Scrapy框架实战(五):通用爬虫 CrawlSpider
    python爬虫爬取_高德地图_主要城市迁徙意愿排行榜_19年至今数据
    年轻就该多尝试,教你20小时Get一项新技能
    LeetCode:283.移动零——简单
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/14977059.html
Copyright © 2011-2022 走看看