Linux内核符号表

时间:2023-01-17 06:03:46

1、形成过程

  Linux内核符号表/proc/kallsyms的形成过程

  (1)./scripts/kallsyms.c负责生成System.map
  (2)./kernel/kallsyms.c负责生成/proc/kallsyms

  (3)./scripts/kallsyms.c解析vmlinux(.tmp_vmlinux)生成kallsyms.S(.tmp_kallsyms.S),然后内核编译过程中将kallsyms.S(内核符号表)编入内核镜像uImage
内核启动后./kernel/kallsyms.c解析uImage形成/proc/kallsyms

2、内核配置

     2.6内核中,为了更好地调试内核,引入了kallsymskallsyms抽取了内核用到的所有函数地址(全局的、静态的)非栈数据变量地址,生成一个数据块,作为只读数据链接进kernel image,相当于内核中存了一个System.map。需要配置CONFIG_KALLSYMS

.config
CONFIG_KALLSYMS=y   符号表中包含所有的函数

CONFIG_KALLSYMS_ALL=y 符号表中包括所有的变量(包括没有用EXPORT_SYMBOL导出的变量)
CONFIG_KALLSYMS_EXTRA_PASS=y
make menuconfig
General setup  --->  
    [*] Configure standard kernel features (for small systems)  --->
        [*]   Load all symbols for debugging/ksymoops (选中此项,才有/proc/kallsyms接口文件, oops问题,选中此选项即可,子选项可
以忽略

              [*]   Include all symbols in kallsyms
              [*]   Do an extra kallsyms pass  

 

3、作用

    2.6版的内核中,为了更方便的调试内核代码,开发者考虑将内核代码中所有函数以及所有非栈变量的地址抽取出来,形成是一个简单的数据块(data blob:符号和地址对应),并将此链接进 vmlinux 中去。如此,在需要的时候,内核就可以将符号地址信息以及符号名称都显示出来,方便开发者对内核代码的调试。完成这一地址抽取+数据快组织封装功能的相关子系统就称之为 kallsyms。反之,如果没有 kallsyms 的帮助,内核只能将十六进制的符号地址呈现给外界,因为它能理解的只有符号地址,而并不包括人类可读的符号名称

    经常使用 Windows 的人都知道所谓的蓝屏是怎么回事,那是系统出了致命问题,而不能继续运行下去而show出的一个蓝色屏。那么对 Linux 来说,也会有致命错误的出现,如果这种错误使得Linux不可继续运行,那么Linux就会显示类似下面这样的屏幕内容(以运行在PowerPC架构下的Linux来举例,其他架构也差不多)dump出出现错误那时刻的系统状态。这种现象就是所谓的Oops,也就Linux下的蓝屏。

Linux内核符号表

    上面出现的Oops消息中,显示了出错时的CPU各寄存器的值,以及以 "Call trace:" 一行开始的C函数调用栈。注意其中除了显示在中括号内的地址,还显示了函数的名称,这就是受助于 kallsyms 的结果,否则它只能显示地址信息。要在一个内核中启用 kallsyms 功能,你必须设置 CONFIG_KALLSYMS 选项为y如果你要在 kallsyms 中包含全部符号信息,必须设置 CONFIG_KALLSYMS_ALL y

4、为何/proc/kallsyms符号地址都为0?

通过cat /proc/kallsyms得到的内核符号表中地址都为0:

00000000 T stext

00000000 T _sinittext
00000000 T _stext
00000000 T __init_begin
00000000 t __create_page_tables
00000000 t __enable_mmu_loc
00000000 t __fixup_pv_table
00000000 t __vet_atags
00000000 t __mmap_switched
00000000 t __mmap_switched_data
00000000 T lookup_processor_type
00000000 t set_reset_devices
00000000 t debug_kernel
00000000 t quiet_kernel
00000000 t init_setup
00000000 t rdinit_setup
00000000 t loglevel
00000000 t unknown_bootoption
00000000 t do_early_param
00000000 T parse_early_options

00000000 T parse_early_param

...

为什么/proc/kallsyms的内容中符号地址都是0呢???

answer:http://*.com/questions/10447491/reading-kallsyms-in-user-mode

http://onebitbug.me/2011/03/04/introducing-linux-kernel-symbols/


因为系统为了保护这些符号地址泄露,而用的一种保护手段,从而使除root用户外的普通用户不能直接查看符号地址;

原因在于内核文件kallsyms.c中的显示符号地址命令中做了如下限制:

    
    
  1. seq_printf(m, "%pK %c %s\n", (void *)iter->value,
  2.                            iter->type, iter->name);

只需要把其中的%pK换成%p就可以让普通用户查看符号地址了;很多提权漏洞一般会用到此处的修改来获取符号地址。

源代码:https://android.googlesource.com/kernel/exynos/+/android-exynos-3.4/kernel/kallsyms.c