• Linux内核调试篇——获取内核函数地址的四种方法(一文解决)


    在内核调试中,经常需要知道某个函数的地址,或者根据函数地址找到对应的函数,从而进行更深一步的debug。

    下面介绍四种获取内核函数地址的方法:

    1、System.map

    在编译Linux内核时,会产生一个内核映像文件System.map,也叫内核符号表

    内核符号表是一个映射,它将内核代码段中的地址映射到对应的函数名或全局变量名。

    System.map文件中,每一行都包含一个内核符号,每个符号包含三部分:

    • 地址:符号在内核内存中的地址。
    • 类型:符号的类型。例如,"T"表示该符号是一个在代码段中的函数。
    • 名称:符号的名字,可以是函数名或者变量名。

    例如,我们要查找名为“do_fork”的函数的地址,可以使用以下命令:

    grep ' do_fork' System.map
    

    然后会得到类似于这样的输出:

    c0105020 T do_fork
    

    这代表,c0105020就是函数do_fork的地址,T代表该符号是个函数。

    或者,直接打开System.map搜索对应函数名或者地址。System.map内容类似如下:

    1. c0004000 A swapper_pg_dir
    2. c0008000 T __init_begin
    3. c0008000 T _sinittext
    4. c0008000 T _stext
    5. c0008000 T stext
    6. c0008034 t __enable_mmu
    7. c0008060 t __turn_mmu_on
    8. ......

    A、T、t等都代表不同的类型,具体类型的定义可参考:

    2、vmlinux

    vmlinux也是Linux编译出来的内核映像文件,可以通过nmobjdumpreadelf等工具来查看它的符号表,从而获取函数地址。

    2.1 nm读取vmlinux

    nm命令是用于查看二进制文件(如可执行文件、目标文件、库)的符号表的工具,所以可以用nm命令来读取vmlinux里的符号表。

    • nm查找vmlinux中函数名为do_fork的地址:
    nm vmlinux | grep "do_fork"
    
    • nm查找vmlinux中地址为c0105020的符号:
    nm vmlinux | grep c0105020
    

    nm命令的输出,与System.map类似,会的得到类似于以下的输出:

    c0105020 T do_fork
    

    2.2 objdump反汇编vmlinux

    objdump工具用于反汇编,可以将vmlinux反汇编出来,得到的反汇编文件就会包含函数名和对应的地址,可以直接查看文本内容。

    • 使用objdump查看vmlinux函数地址
    objdump -d vmlinux | grep "函数名"
    

    这会返回与指定函数名匹配的符号的地址、类型和名称。objdump-d选项表示反汇编代码。

    也可以将vmlinux的内容全部反汇编出来,重定向到一个文件,然后直接查看文本内容:

    objdump -D vmlinux > vmlinux_dump.txt
    

    上述命令会将vmlinux所有内容反汇编,并将结果输出到vmlinux_dump.txt文件中,-D表示反汇编所有代码段。

    2.3 readelf读取vmlinux

    使用readelf也可以读取vmlinux的符号表,命令如下:

    readelf -s vmlinux
    

    由于vmlinux比较大,如果要查找某个函数的地址,需要使用grep进行过滤。

    例如,找到do_fork函数的地址,你可以使用以下命令:

    readelf -s vmlinux | grep "do_fork"
    

    然后,你就会看到类似这样的输出:

    56481: c10601e0    96 FUNC    GLOBAL DEFAULT    1 do_fork
    

    输出内容表示,do_fork函数的地址是c10601e0

    3、/proc/kallsyms

    vmlinux是编译时生成的,假设你没有vmlinux这个文件,只有正在运行的Linux系统,此时也可以通过/proc/kallsyms获取函数地址。

    /proc/kallsyms是一个由运行中的内核动态生成的虚拟文件,它反映了当前运行的内核的状态

    通常这个节点是不会打开的,因为会增加内核大小,要使用这个节点,需要打开内核选项:

    CONFIG_KALLSYMS=y
    

    如果想获取do_fork函数的地址,可以使用以下命令:

    cat /proc/kallsyms | grep " do_fork"
    

    然后会返回一个包含do_fork函数地址的行,如:

    ffffffff810b57b0 T do_fork
    

    输出内容表示do_fork函数的地址是ffffffff810b57b0

     资料直通车:Linux内核源码技术学习路线+视频教程内核源码

    学习直通车:Linuxc/c++高级开发【直播公开课】

    零声白金VIP体验卡:零声白金VIP体验卡(含基础架构/高性能存储/golang/QT/音视频/Linux内核)

    4、内核接口

    也可以在代码中获取内核符号表,同样需要打开内核选项CONFIG_KALLSYMS=y

    kallsyms_lookup_name

    • 已知函数名,获取地址:
    1. kallsyms_lookup_name("函数名" )

    该函数会返回对应函数名的地址。

    sprint_symbol

    • 已知地址,返回对应符号:
    1. #include
    2. int sprint_symbol(char *buffer, unsigned long address)
    • buffer:符号名缓存区,保存结果。
    • address:符号地址。

    原文作者:嵌入式Linux充电站

  • 相关阅读:
    forEach和map区别
    AI强势入场,成就史上最快足球
    ios CI/CD 持续集成 组件化专题三 IOS打包Bundle与加载Bundle中的图片
    leetcode day07 最后一个单词的长度
    论文摘要的写作技巧
    自动泊车的路径动态规划问题研究附Matlab代码
    C++/Qt 小知识记录4
    MySQL数据库事务控制
    Java计算机毕业设计基于SpringBoot音乐网项目(附源码讲解)
    C语言动态实现顺序栈
  • 原文地址:https://blog.csdn.net/youzhangjing_/article/details/134512976