为分析内核,在有限的机器上用虚拟机装了CentOS.6.9.i386.minimal,重新编译了3.19.8内核并克隆。当使用/proc/kcore进行内核动态映像调试时,发现与kgdb远程调试端读到的内存数据不一样。运行内核的测试机上的/proc/kcore里面的数据大多都为0,几乎没有一处用途。不管我进行多少次core-file去刷新/proc/kcore,结果也是无功而返。开始以为gdb与新内核不兼容,但并不是,用hexdump去读取/proc/kcore的数据,只有开头一小段是有数据迹象,其余都基本为0。/proc/kcore大小约为1G,内核arch为x86。
新内核是按默认配置进行编译,不知道是否其中有配置影响了/proc/kcore文件系统,于是我切换到随CentOS.6.9发布的内核2.6.32-696.el6.i686。结果出来了,在CentOS官方编译的32位内核中,hexdump同样只可以读到/proc/kcore第一个页面大小的数据内容,当读取到其余空间的内容时,只返回000100(也就是一个页面的大小数值)。
那就可能跟编译选项有关,于是找遍了menuconfig,和比较/boot目录里的config-$(uname -r),再参考kconfig里面的参考说明,好像也没有找到相关的选项。最后手段就是去调试文件系统下的kcore了。

kcore模块的代码在$YourSrcDir/fs/proc/kcore.c。先去阅读代码找出有用的函数作为断点切入分析。kcore.c文件不大,只有600不到700行,只要稍为熟识文件系统就可以分析。
kcore特殊文件只实现了(虚)文件系统中的 file_operations 接口,系统调用文件IO,映射相关的接口。

static const struct file_operations proc_kcore_operations = {
.read = read_kcore,
.open = open_kcore,
.llseek = default_llseek,
};

kcore只为文件系统提供了read, open, seek三种操作服务。也就是说我们只可以通过系统调用进行kcore的这三种操作。

下面是kcore.c模块相关的数据结构和静态变量:

// kcore.h
enum kcore_type {
KCORE_TEXT,
KCORE_VMALLOC,
KCORE_RAM,
KCORE_VMEMMAP,
KCORE_OTHER,
}; struct kcore_list {
struct list_head list;
unsigned long addr;
size_t size;
int type;
}; struct vmcore {
struct list_head list;
unsigned long long paddr;
unsigned long long size;
loff_t offset;
};
// kcore.c模块的静态变量:
static LIST_HEAD(kclist_head);
static DEFINE_RWLOCK(kclist_lock);
static int kcore_need_update = ;

这里主要有两类地址,KCORE_VMALLOC和KCORE_RAM。KCORE_RAM,在32位内核中内核地址与物理地址存在一种简单的对应关系,内核地址=物理地址+3G,所以叫KCORE_RAM。但是3G到4G的地址空间中,也不是全部应用这一简单映射关系的,还有一块特殊的区域,就是KCORE_VMALLOC,它位于4G地址空间的最高256M,即0xf0000000到0xfffff000内。

VMALLOC这部分虚拟地址是用在ioremamp,也就是外部设备存储单元使用到的I/O mapped地址。这区域的VMALLOC要与内存管理mm中的vm_area区分好。vmalloc是从内核地址空间,0xc0000000到high_memory(即VMALLOC_START - VMALLOC_OFFSET)为止,进行虚拟空间分配,使用vm_struct结构和vmlist全局队列管理。进程的内存空间由mm_struct结构和vm_area_struct结构进行管理。

// pgtable_32.c
unsigned long __FIXADDR_TOP = 0xfffff000;
EXPORT_SYMBOL(__FIXADDR_TOP);
// fixmap.h
#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
// pgtable_32_types.h
#define VMALLOC_START ((unsigned long)high_memory + VMALLOC_OFFSET)
#ifdef CONFIG_HIGHMEM
# define VMALLOC_END (PKMAP_BASE - * PAGE_SIZE)
#else
# define VMALLOC_END (FIXADDR_START - * PAGE_SIZE)
#endif
#define MODULES_VADDR VMALLOC_START
#define MODULES_END VMALLOC_END
#define MODULES_LEN (MODULES_VADDR - MODULES_END)

变量high_memory标志着具体物理内存的上限所对应的虚拟地址,这是在系统初始化时设置好的。通过kgdb调试,查看到high_memory为0xf0000000。

为什么我的内核只可以读到/proc/kcore的一个页面的数据,其它地址上的数据全为0呢,那么参考读操作函数read_kcore。
这个函数主要是将/proc/kcore文件尺寸的线性地址空间映射到不同的区域进行读操作,与内存(文件)映射类似。
1.read_kcore将第一个页面的地址空间的读操作,映射为一个ELF core header头结构的数据内容。
2.从这个头结构偏移后的地址,使用内核地址的简单映射规则,进行映射,即 addr + 3G - sizeof(ELF core header)。
3.分别分派到kcore_list区域进行读操作。
4.如果访问地址满足is_vmalloc_or_module_addr,则进行vread,并copy_to_user。
5.如果访问地址满足kern_addr_valid,则直接进行copy_to_user。
6.其余情况clear_user。

先来看kcore是如何将kcore文件的线性地址映射到内核地址的,下面的相关函数的反汇编代码:

这里要注意的是,代码是被-O2优化过的,反汇编并不能与代码很好地对应,开头两行可能是承着某处的跳转的。从行文来看%esi优化为变量elf_buflen。

将图的下面4行汇编逆向为 0xc0000000 - elf_buflen + *fpos。 也就是 offset + 3G - sizeof(ELF core header)。

再来看kcore一共有几个映射区间,只要walk through一下kclist_head队列就可以知道。自己写一下调试脚本就可以得到。

kclist_head有两个区间,地址区间与info files查看到映像区间一致。分别是0xf0800000开始的KCORE_VMALLOC区间,和0xc0000000开始的KCORE_RAM区间。 这两个区间下面还会进行说明。

这就好办了,断点设置在read_kcore跑一次。结果发现在头部分偏移之后的地址量的读操作一切都被clear_user,也就是填0。对应高地址(即vmalloc,ioremap)的读操作则是正常的。代码已经被-O2优化过,用混合反汇编出来的代码和汇编对应也是乱七八糟的。不过好在符号信息还在,那就设断点到kern_addr_valid,却发现找不到符号。经过汇编分析后发现,代码在判断is_vmalloc_or_module_addr失败后直接进行clear_user。按代码的逻辑应该是先进行kern_addr_valid判断。也就是访问地址不在最高 处的vamlloc,再判断是否在内核有效的地址空间内。但实际的反汇编代码却根本找不到这个判断逻辑。查阅kern_addr_valid在不同arch下实现后,发现x86下这个函数只是一个开关。

// arch/x86/include/asm/pgtable_32.h
#ifdef CONFIG_FLATMEM
#define kern_addr_valid(addr) (1)
#else
#define kern_addr_valid(kaddr) (0)
#endif

终于发现在arch x86中,内存管理模型影响了/proc/kcore特殊文件的运作。只有在FLAT模型下的内存管理,/proc/kcore才能提供正常的服务。内核中默认配置是使用SPARSE模型的,不管理是什么arch的处理器。CentOS的32位内核也使用了这一默认配置,经过/boot/config-2.6.32-696.el6.i686核实。

内核3.19.8重新进行menuconfig配置,选用FLAT内存管理模型,再次编译后。OK!/proc/kcore特殊文件正常读出内核内存映像的数据。x86 32位的内核必须使用FLAT内存管理模型,即CONFIG_FLATMEM_ENABLE=y,才可以正常使用/proc/kcore。

在重编译后,我懒得编译modules,使用原来SPARSE内存模型编译出来的modules进行安装。安装时提示许多mm_section符号缺失的warning,实际运行内核时也就杯具了。幸好是虚拟机,回退重新全部编译就是了,机器配置有限,至少就一个半小时。

现在大家都用arch x86_64的内核,内核不会出现这个问题,arch arm和arch arm64也不会有这个问题,只是我机器资源有限只能使用32位的内核,所以碰上了这个问题。
x86 32位的内核必须使用FLAT内存管理模型,即CONFIG_FLATMEM_ENABLE=y,才可以正常使用/proc/kcore。

/proc/kcore失效,调试其文件系统相关模块,使重新正常工作的更多相关文章

  1. python 加密算法及其相关模块的学习(hashlib,random,string,math)

    加密算法介绍 一,HASH Hash,一般翻译做“散列”,也有直接音译为”哈希”的,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值.这种 ...

  2. python加密算法及其相关模块的学习(hashlib,RSA,random,string,math)

    加密算法介绍 一,HASH Hash,一般翻译做“散列”,也有直接音译为”哈希”的,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值.这种 ...

  3. Python——电子邮件、Internet协议相关模块

    一.电子邮件相关模块 email:用于处理电子邮件 smtpd:SMTP服务器 base64:Base-16.32.64数据编码 mhlib:处理MH文件格式解析的类 mailcap:mailcap文 ...

  4. 【转】Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历))

    Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历)) 本文由 Luzhuo 编写,转发请保留该信息. 原文: http://blog. ...

  5. nodeJS---URL相关模块用法(url和querystring)

    nodeJS---URL相关模块用法(url和querystring) 一: URL模块: URL模块用于解析和处理URL的字符串,提供了如下三个方法: 1. parse 2. format 3. r ...

  6. Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历))

    Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历)) 本文由 Luzhuo 编写,转发请保留该信息. 原文: http://blog. ...

  7. python 相关模块安装 国内镜像地址

    python 相关模块安装 国内镜像地址 pipy国内镜像目前有: http://pypi.douban.com/  豆瓣 http://pypi.hustunique.com/  华中理工大学 ht ...

  8. Android开发环境——调试器 DDMS相关内容汇总

       Android开发环境将分为SDK相关内容.Eclipse ADT相关内容.模拟器AVD相关内容.调试器DDMS相关内容.日志LogCat相关内容.连接驱动ADB相关内容.内存泄露检测工具MAT ...

  9. /proc/kcore

    [root@b proc]# ls -lh /proc/kcore-r-------- 1 root root 128T Sep 29 09:39 /proc/kcore[root@b proc]# ...

随机推荐

  1. JavaWeb总结(五)—Cookie

    一.会话 1.提出问题 HTTP协议是一种无状态的协议.Web服务器本身不能识别哪些请求是同一浏览器发出的,浏览器的每一次请求都是孤立的.即使HTTP1.1支持持续连接,但当用户有一段时间没有提交请求 ...

  2. 关于Form表单一些基础知识

    1.两个重要属性: action:表单需要提交的服务器地址 method:表单提交数据使用的方法,get/post >>>get和post的区别 ①get传参使用URL传递,所有参数 ...

  3. JavaScript 简易版 自动轮播 手动轮播 菜鸟交流

    本人刚刚接触前端,许多知识还不了解,以前经常到博客园查询自己需要的东西,现在也终于反客为主了.作为新手,所展示的东西也是浅显易懂,希望同是新手的伙伴们共同交流.共同进步,若是成功捕获一位大大,也请您赐 ...

  4. 解决Tomcat: Can't load IA 32-bit .dll on a AMD 64-bit platform 问题

    错误如下: java.lang.UnsatisfiedLinkError: E:\Program Files\MyEclipse 10\apache-tomcat-7.0.23\bin\tcnativ ...

  5. html 选择器之基础选择器

    我把CSS选择器分开成三部分,第一部分是我们常用的部分,我把他叫做基本选择器:第二部分我把他称作是属性选择器,第三部分我把他称作伪类选择器 一.基础选择器 1. 通配符(*):选中所有的元素 2.元素 ...

  6. 实现TOLock过程中的一处多线程bug

    背景 最近在啃<多处理器编程的艺术>,书中的7.6节介绍了时限锁--实现了tryLock方法的队列锁. 书中重点讲解了tryLock的实现,也就是如何实现在等待超时后退出队列,放弃锁请求, ...

  7. 需求收集过程实例之 - GF Phase 1

    正统的需求过程是怎样呢?各位看客有兴趣可以问问google 百度.本人的体会是理论很清晰,现实很混沌.这篇随笔讲述的是我参与的几个项目的需求收集过程.有的很顺利,有的却是乱中求生.但是不管怎样,最终这 ...

  8. HashMap 构造函数

    HashMap总共提供了三个构造函数 /** * Constructs an empty <tt>HashMap</tt> with the default initial c ...

  9. Array和ArrayCollection作为数据源的一个应用区别

    在不用[Enabled]元标签的前提下,将一个Array赋值给DataGrid.DataList等控件的DataProvider后,当Array值发生改变时,控件显示内容不会及时更新(可调用控件的in ...

  10. Windows系统操作指令汇总

    CMD命令:开始->运行->键入cmd或command(在命令行里可以看到系统版本.文件系统版本) 1. appwiz.cpl:程序和功能 2. calc:启动计算器 3. certmgr ...