文章目录

  • 前言
  • 概述
  • 使用 /dev/kmem
  • 使用 /proc/kallsyms
  • 验证
  • 进阶

前言

上篇文章我们介绍了 /dev/mem,今天再来介绍下它的好兄弟 /dev/kmem

crw-r----- 1 root kmem 1, 1 May 26 06:10 /dev/mem
crw-r----- 1 root kmem 1, 2 May 26 06:10 /dev/kmem

对比一下:

  • /dev/mem:映射系统所有的物理内存
  • /dev/kmem:映射系统所有的内核态虚拟内存

概述

简单来说,通过 /dev/mem 我们可以查询一个物理地址上的数据是多少,
通过 /dev/kmem 我们可以查询一个内核虚拟地址上的数据是多少。
要知道,CPU 或着说内核看到的地址都是虚拟地址,我们在内核中使用 printk 打印出一个全局变量的地址,后面想要继续追踪该地址上值的变化,这时候再用 /dev/mem 就不行了,因为打印出的地址是一个虚拟地址,而通过 /dev/mem 访问的是物理地址。这种情况下应该使用 /dev/kmem,通过它可以访问内核虚拟内存。

使用 /dev/kmem

由于/dev/kmem 暴露的权限过大,存在安全隐患,所以内核一般默认禁用该设备,仅仅保留 /dev/mem。我们想要使用 /dev/kmem,可以打开 CONFIG_DEVKMEM=y 这个编译选项。

使用 /proc/kallsyms

有了 /dev/kmem 设备,我们就可以访问内核虚拟内存了,但是我们访问哪个地址呢?如何知道一个全局变量的虚拟内存地址呢?答案是可以使用 /proc/kallsyms 查看内核符号信息。

# cat /proc/kallsyms
c0008000 T stext
c0008000 T _text
c000808c t __create_page_tables
c0008138 t __turn_mmu_on_loc
c0008144 t __fixup_smp
c00081ac t __fixup_smp_on_up
c00081d0 t __fixup_pv_table
c0008224 t __vet_atags
c0008280 T _stext
c0008280 T __turn_mmu_on
c0008280 T __idmap_text_start
c00082a0 T cpu_resume_mmu
c00082a0 t __turn_mmu_on_end
c00082c4 T cpu_ca15_reset
c00082c4 T cpu_ca8_reset
c00082c4 T cpu_ca9mp_reset
c00082c4 T cpu_v7_bpiall_reset
c00082c4 T cpu_v7_reset
c00082e0 T __idmap_text_end
c0009000 T asm_do_IRQ
c0009000 T __exception_text_start
c0009000 T __hyp_idmap_text_end
c0009000 T __hyp_idmap_text_start
c0009014 T do_undefinstr
c0009268 T handle_fiq_as_nmi
c00092ec T do_IPI
c00092f0 T do_DataAbort
c00093a4 T do_PrefetchAbort
c000943c T gic_handle_irq
c0009508 T __do_softirq
。。。

第一列为符号地址,第二列为类型,第三列为符号名

第二列的类型:
大写字母表示该符号没有被 static 修饰,可以被整个内核代码使用;
小写字母表示该符号被 static 修饰了,只能在当前文件使用。

b 符号在未初始化数据区(BSS)
c 普通符号,是未初始化区域
d 符号在初始化数据区
g 符号针对小object,在初始化数据区
i 非直接引用其他符号的符号
n 调试符号
r 符号在只读数据区
s 符号针对小object,在未初始化数据区
t 符号在代码段
u 符号未定义

我们找个全局变量练练手

# cat /proc/kallsyms | grep " D "
#

却发现没有找到任何全局变量,这是怎么回事?
原来,内核只开启了 CONFIG_KALLSYMS=y

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

我们还需要开启下面编译选项

CONFIG_KALLSYMS_ALL=y # 符号表中包括所有的变量(包括没有用 EXPORT_SYMBOL 导出的变量)

重新编译后,便可列出全局变量符号了

# cat /proc/kallsyms | grep " D "
c0884000 D __per_cpu_load
c0884000 D __per_cpu_start
c0884048 D cpu_data
c0884208 D harden_branch_predictor_fn
c0884210 D process_counts
c0884260 D ksoftirqd
c0884280 D kernel_cpustat
c08842d0 D kstat
c08842fc D select_idle_mask
c0884300 D load_balance_mask
c088432c D sd_llc
c0884330 D sd_llc_size
c0884334 D sd_llc_id
c0884338 D sd_llc_shared
c088433c D sd_numa
c0884340 D sd_asym
c0888480 D srcu_online
c08895c0 D hrtimer_bases
c0889818 D tick_cpu_device
c0889944 D pcpu_drain
c0889978 D dirty_throttle_leaks
c0889b2c D __kmap_atomic_idx
c088a008 D cpuidle_devices
c088a010 D cpuidle_dev
c088a4e8 D flush_works

比方说,我们想查看变量 flush_works 的值,其虚拟地址为 0xc088a4e8 = 3230180584,那么,使用下面命令就可以从 /dev/kmem 中读取该变量的值了

# dd if=/dev/kmem bs=1 count=4 skip=3230180584 | hexdump
4+0 records in
4+0 records out
0000000 60af 7ce4
0000004

验证

为了验证读取到值的正确性,我们在内核(usb.c)中添加一个全局变量进行测试,添加代码如下

int lyj_ccc = 0x1234;/** Init*/
static int __init usb_init(void)
{int retval;int lyj_ddd = 0x5678;printk("&lyj_ccc = %p\n", &lyj_ccc);
printk("lyj_ccc = 0x%x\n", lyj_ccc);
printk("&lyj_ddd = %p\n", &lyj_ddd);
printk("lyj_ddd = 0x%x\n", lyj_ddd);if (usb_disabled()) {pr_info("%s: USB support disabled\n", usbcore_name);return 0;}

重新编译内核,内核启动阶段打印如下

SCSI subsystem initialized
&lyj_ccc = c08b65a8
lyj_ccc = 0x1234
&lyj_ddd = dd03fef4
lyj_ddd = 0x5678
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb

系统启动完毕后,我们使用 /dev/kmem 进行读取,先使用 /proc/kallsyms 查看符号 lyj_ccc 对应的虚拟地址(其实,在内核启动阶段也打印了该变量的地址,只不过正常情况下我们不会手动添加代码去打印,使用 kallsyms 查看才是更通用的手段

# cat /proc/kallsyms | grep lyj
c08b65a8 D lyj_ccc

看到在符号表中只有 lyj_ccc,而没有 lyj_ddd,因为 lyj_ddd 是局部变量,不是符号(我的理解:符号是全局变量和函数名称)。
拿到变量的虚拟地址 0xc08b65a8 后,我们使用如下命令查看变量的值

# dd if=/dev/mem bs=1 count=4 skip=3230361000 | hexdump
dd: /dev/mem: Bad address# dd if=/dev/kmem bs=1 count=4 skip=3230361000 | hexdump
4+0 records in
4+0 records out
0000000 1234 0000
0000004

可以看到,使用 /dev/mem 是无法查看的,因为它查看的是物理地址。
使用 /dev/kmem 可以读取,且读到的值和代码一致,说明读取成功。

/dev/kmem /proc/kallsyms相关推荐

  1. 构建/dev/kmem枚举所有Linux内核模块(包括隐藏的)

    Linux系统不是可以有lsmod枚举所有内核模块吗?procfs不香吗?干嘛还要费事从/dev/kmem里去枚举? 其实,Linux是后来的事了,在最初的UNIX时代,像ps之类的枚举进程的,都是从 ...

  2. Linux环境 网络流量统计/proc/net/dev和/proc/net/snmp

    在Linux系统中,系统调用是操作系统提供给应用程序使用操作系统服务的重要接口,但同时也正是通过系统调用机制,操作系统屏蔽了用户直接访问系统内核的可能性.幸运的是Linux提供了LKM机制可以使我们在 ...

  3. Linux /proc/pid目录下相应文件的信息说明和含义

    Proc是一个虚拟文件系统,在Linux系统中它被挂载于/proc目录之上.Proc有多个功能 ,这其中包括用户可以通过它访问内核信息或用于排错,这其中一个非常有 用的功能,也是Linux变得更加特别 ...

  4. [device]/proc/devices and /dev/

    1. /proc/devices和/dev cat /proc/devices 列出在当前运行的内核中已经注册的设备名称以及设备的Major主设备号.其中的设备信息是驱动程序在加载时生成的,也可以说是 ...

  5. 浅谈/proc/net/dev的由来

    我们都知道可以从/proc/net/dev下去读取网络设备收发包时相关的数据,但之前从来没有关注这些文件的来源,直到前几天遇到一个wifi的tx和rx等数据都为0的问题不得不去探索原因,起初以为/pr ...

  6. /proc文件夹介绍

    Linux系统上的/proc目录是一种文件系统,即proc文件系统.与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过 ...

  7. Linux之 proc文件系统

    用户态与内核态交互的接口之一,管理方式与普通文件相同 每个节点的文件权限(读/写)决定其查看和配置权限 大量LINUX系统参数和状态信息可通过proc节点查看或配置 /proc/<pid> ...

  8. Linux系统proc详解

    原文链接:https://www.cnblogs.com/liushui-sky/p/9354536.html 目录 一.        进程目录中的常见文件介绍 1.1 cmdline 1.2.cw ...

  9. 深入理解linux系统下proc文件系统内容

    另外,可以参考这个http://www.centos.org/docs/5/html/5.1/Deployment_Guide/ch-proc.html 内容摘要:Linux系统上的/proc目录是一 ...

最新文章

  1. UITableView数据的添加、删除、移动
  2. java void传参,Java中的传参
  3. 网站被k不要慌,看看“老油条”们是怎么解决的吧!
  4. php如何生成订单号,php如何生成不重复订单号
  5. 硬盘基本知识(磁头、磁道、扇区、柱面) 转
  6. (转)Spring Boot (十九):使用 Spring Boot Actuator 监控应用
  7. SAP License:SAP CWM功能及限制
  8. 说三件可能你不知道的小事
  9. Navicat 12.1 Macos 激活指南
  10. 小米9pro计算机打不开,小米9pro怎么连接电脑
  11. 如何为长期旅行做准备
  12. excel数据可视化
  13. 影响债市行情的主要因素_决定债券收益的十大因素
  14. 用python画一些有趣的图案(001)
  15. HTTPS详解及HTTPS实验
  16. vue 项目下JS内存溢出
  17. 电磁兼容(EMC)测试
  18. 常见的分布式数据库有哪些
  19. 晶闸管输出光耦合器TLP541参数及应用实例
  20. Kindle PaperWhite3 越狱和PDF插件的安装

热门文章

  1. Java实现sha256加密的工具类
  2. ubuntu 罗技鼠标驱动安装及使用
  3. 二叉树的序列化和反序列化——C++
  4. EntityFrameWork 从入门到熟悉(3)-CodeFirst
  5. ORA-01654 索引 无法通过 扩展 2种情况分析
  6. 找不到包 com.mapbar.android.location
  7. 香农定律和奈奎斯特准则
  8. C语言实践项目-小明最多能买多少支玫瑰?(初学者作业)
  9. 天猫整站Springboot 从零开始搭建(二)
  10. 排列问题(递归算法)