为分析内核,在有限的机器上用虚拟机装了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. Letter Combinations of a Phone Number:深度优先和广度优先两种解法

    Letter Combinations of a Phone Number Given a digit string, return all possible letter combinations ...

  2. vuejs学习笔记(1)--属性,事件绑定,ajax

    属性 v-for 类似于angular中的 ng-repeat ,用于重复生成html片段: <ul id="box"> <li v-for="(v, ...

  3. 轻量级代码生成器-OnlyCoder

    程序猿利器:代码生成器,使用代码生成器已经好几年了,增删改查各种生成,从UI到DATA层均生成过.之前有使用过动软的,T4模板等....  T4生成实体还是没有问题的,但是生成MVC视图就有点烦杂了, ...

  4. Android ShellUtils

    Android中执行Shell命令的工具类 public class ShellUtils { public static final String COMMAND_SU = "su&quo ...

  5. 关于C++ 循环

    有的时分,可能需求屡次履行同一块代码.通常情况下,句子是顺序履行的:函数中的第一个句子先履行,接着是第二个句子,依此类推. 编程言语供给了答应更为杂乱的履行途径的多种操控结构. 循环句子答应咱们屡次履 ...

  6. [Python]再学 socket 之非阻塞 Server

    再学 socket 之非阻塞 Server 本文是基于 python2.7 实现,运行于 Mac 系统下 本篇文章是上一篇初探 socket 的续集, 上一篇文章介绍了:如何建立起一个基本的 sock ...

  7. T-SQL语句中的转换函数

    书接上回 前面讲了聚合函数.字符串函数 今天一起来看下转换函数 首先是 值类型转换 ),degree) 在C#里面是convert,现在在SQL中也是他,convert(转换类型,被转换列)from ...

  8. 【从无到有】JavaScript新手教程——1.简介、变量和运算符

    今天带大家来学习一下在网页制作过程中很常用的JavaScript(简称JS).   一.JS的作用: 表单验证,减轻服务端的压力 添加页面动画效果 动态更改页面内容 Ajax网络请求 二.[使用JS的 ...

  9. 多个git账号的SSH配置

    一般使用git都只需要维持一个默认的git账户就可以打天下了. 但如果自己确实需要多个git账号的需求的话,就有必要配置多个ssh key了. 首先为生成多个ssh key ssh-keygen -t ...

  10. Lambda表达式效率问题

    原文 http://www.importnew.com/17262.html 有许许多多关于 Java 8 中流效率的讨论,但根据 Alex Zhitnitsky 的测试结果显示:坚持使用传统的 Ja ...