kdump简介

kdump是系统崩溃的时候,用来转储运行内存的一个工具。

系统一旦崩溃,内核就没法正常工作了,这个时候将由kdump提供一个用于捕获当前运行信息的内核,

该内核会将此时内存中的所有运行状态和数据信息收集到一个dump core文件中以便之后分析崩溃原因。

一旦内存信息收集完成,可以让系统将自动重启。

kdump是RHEL5之后才支持的,2006被主线接收为内核的一部分。它的原理简单来说是在内存中保留一块

区域,这块区域用来存放capture kernel,当production kernel发生crash的时候,通过kexec把保留区域的

capure kernel给运行起来,再由捕获内核负责把产品内核的完整信息 - 包括CPU寄存器、堆栈数据等转储

到指定位置的文件中。

kdump原理

kexec是kdump机制的关键,包含两部分:

内核空间的系统调用kexec_load。负责在生产内核启动时将捕获内核加载到指定地址。

用户空间的工具kexec-tools。将捕获内核的地址传递给生产内核,从而在系统崩溃的时候找到捕获内核的地址并运行。

kdump是一种基于kexec的内核崩溃转储机制。当系统崩溃时,kdump使用kexec启动到第二个内核。第二个内核通常

叫做捕获内核,以很小内存启动以捕获转储镜像。第一个内核保留了内存的一部分给第二个内核启动使用。

由于kdump利用kexec启动捕获内核,绕过了BIOS,所以第一个内核的内存得以保留。这是内存崩溃转储的本质。

捕获内核启动后,会像一般内核一样,去运行为它创建的ramdisk上的init程序。而各种转储机制都可以事先在init中实现。

为了在生产内核崩溃时能顺利启动捕获内核,捕获内核以及它的ramdisk是事先放到生产内核的内存中的。

生产内核的内存是通过/proc/vmcore这个文件交给捕获内核的。为了生成它,用户工具在生产内核中分析出内存的使用和

分布等情况,然后把这些信息综合起来生成一个ELF头文件保存起来。捕获内核被引导时会被同时传递这个ELF文件头的

地址,通过分析它,捕获内核就可以生成出/proc/vmcore。有了/proc/vmcore这个文件,捕获内核的ramdisk中的脚本就

可以通过通常的文件读写和网络来实现各种策略了。

kdump配置

RHEL5开始,kexec-tools是默认安装的。

如果需要调试kdump生成的vmcore文件,需要手动安装kernel-debuginfo包。

(1) 预留内存

可以修改内核引导参数,为启动捕获内核预留指定内存。

/etc/grub.conf (一般为/boot/grub/grub.conf的软链接)中:

crashkernel=Y@X,Y是为kdump捕获内核保留的内存,X是保留部分内存的起始位置。

默认为crashkernel=auto,可自行设定如crashkernel=256M

(2) 配置文件

配置文件为/etc/kdump.conf,以下是几个常用配置:

  1. # path /var/crash

默认的vmcore存放目录为/var/crash/%HOST-%DATE/,包括两个文件:vmcore和vmcore-dmesg.txt

(3) 启动服务

  1. # chkconfig kdump on // 开机启动
  2. # service kdump status // start、stop、restart等

(4) 功能验证

Magic System request key is a magical key combo you can hit which the kernel will respond to regardless

of whatever else it is doing, unless it is completely locked up.

使用sysrq需要编译选项CONFIG_MAGIC_SYSRQ的支持。详细信息可看documentation/sysrq.txt。

故意让系统崩溃,来测试kdump是否正常工作:

  1. # echo c > /proc/sysrq-trigger

Will perform a system crash by a NULL pointer dereference.

A crash dump will be taken if configured.

Magic SysRq还有一些很有趣的值,有的具有很大的破环性,输出在/var/log/messages:

f:call oom_kill to kill a memory hog process. 执行oom killer。

l:shows a stack backtrace for all active CPUs. 打印出所有CPU的stack backtrace。

m:dump current memory info. 打印出内存使用信息。

p:dump the current registers and flags. 打印出所在CPU的寄存器信息。

(5) 捕获内核

捕获内核是一个未压缩的ELF映像文件,查看捕获内核是否加载到内存中:

  1. # cat /sys/kernel/kexec_crash_loaded

缩小捕获内核占用的内存:

  1. # echo N > /sys/kernel/kexec_crash_size

crash简介

当系统崩溃时,通过kdump可以获得当时的内存转储文件vmcore,但是该如何分析vmcore呢?

crash是一个用于分析内核转储文件的工具,一般和kdump搭配使用。

使用crash时,要求调试内核vmlinux在编译时带有-g选项,即带有调试信息。

如果没有指定vmcore,则默认使用实时系统的内存来分析。

值得一提的是,crash也可以用来分析实时的系统内存,是一个很强大的调试工具。

crash使用gdb作为内部引擎,语法类似于gdb,命令的使用说明可以用 help来查看。

使用crash需要安装crash工具包和内核调试信息包:

  1. crash
  2. kernel-debuginfo-common
  3. kernel-debuginfo

crash使用

Analyze Linux crash dump data or a live system.

crash [OPTION] NAMELIST MEMORY-IMAGE      (dumpfile form)

crash [OPTION] [NAMELIST]                                   (live system form)

使用crash来调试vmcore,至少需要两个参数:

NAMELIST:未压缩的内核映像文件vmlinux,默认位于/usr/lib/debug/lib/modules/$(uname -r)/vmlinux,由

内核调试信息包提供。

MEMORY-IMAGE:内存转储文件vmcore,默认位于/var/crash/%HOST-%DATE/vmcore,由kdump生成。

例如:# crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux   /var/crash/%HOST-%DATE/vmcore

(1) 错误类型

首先可以在vmcore-dmesg.txt中先查看错误类型,如:

  1. divide error: 0000 [#1] SMP,除数为0造成内核崩溃,由1号CPU触发。

  2. BUG: unable to handle kernel NULL pointer dereference at 000000000000012c,引用空指针。

这样一来就能知道引发内核崩溃的错误类型。

(2) 错误地点

RIP为造成内核崩溃的指令,Call Trace为函数调用栈,通过RIP和Call Trace可以确定函数的调用路径,以及在

哪个函数中的哪条指令引发了错误。

 

例如RIP为:[<ffffffff812cdb54>] ? tcp_enter_loss+0x1d3/0x23b

[<ffffffff812cdb54>]是指令在内存中的虚拟地址。

tcp_enter_loss是函数名(symbol)。

0x1d3是这条指令相对于tcp_enter_loss入口的偏移,0x23b是函数编译成机器码后的长度。

这样一来就能确定在哪个函数中引发了错误,以及错误的大概位置。

Call Trace为函数的调用栈,是从下往上看的。可以用来分析函数的调用关系。

(3) crash基本输出

  1. # crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux   /var/crash/%HOST-%DATE/vmcore
  2. KERNEL: /usr/lib/debug/lib/modules/2.6.32-358.el6.x86_64/vmlinux
  3. DUMPFILE: vmcore [PARTIAL DUMP]
  4. CPUS: 12
  5. DATE: Fri Sep 19 16:47:01 2014
  6. UPTIME: 7 days, 06:37:46
  7. LOAD AVERAGE: 0.19, 0.05, 0.01
  8. TASKS: 282
  9. NODENAME: localhost.localdomain
  10. RELEASE: 2.6.32-358.el6.x86_64
  11. VERSION: #1 SMP Tue Oct 29 10:18:21 CST 2013
  12. MACHINE: x86_64 (1999 Mhz)
  13. MEMORY: 48 GB
  14. PANIC: "Oops: 0002 [#1] SMP " (check log for details)
  15. PID: 0
  16. COMMAND: "swapper"
  17. TASK: ffffffff81a8d020 (1 of 12) [THREAD_INFO: ffffffff81a00000]
  18. CPU: 0
  19. STATE: TASK_RUNNING (PANIC)
  20. 这些基本输出信息简单明了,可由sys命令触发。

(4) crash常用命令

bt:打印函数调用栈,displays a task's kernel-stack backtrace,可以指定进程号bt 。

log:打印系统消息缓冲区,displays the kernel log_buf contents,如log | tail -n 30。

ps:显示进程的状态,>表示活跃的进程,如ps | grep RU。

sys:显示系统概况。

kmem -i:显示内存使用信息。

dis :对给定地址进行反汇编。

exception RIP即为造成错误的指令。

关于log命令:

内核首先把消息打印到内核态的ring buffer,用户态的klogd负责读取并转发给syslogd,让它记录到磁盘。

在内核崩溃时,可能无法把消息记录到磁盘,但是ring buffer中一般会有记录。所以log命令有时候能查看

到系统日志中所缺失的信息。

(5) 结构体和变量

查看结构体中所有成员的值,例如:

  1. # ps | grep RU
  2. > 0 0 0 ffffffff81a8d020 RU 0.0 0 0 [swapper]
  3. # struct task_struct ffffffff81a8d020
  4. struct task_struct {
  5. state = 0,
  6. stack = 0xffffffff81a00000,
  7. usage = {
  8. counter = 2
  9. },
  10. flags = 2097408,

显示整个结构体的定义:

  1. # struct task_struct
  2. struct task_struct {
  3. volatile long int state;
  4. void *stack;
  5. atomic_t usage;
  6. unsigned int flags;

显示整个结构体的定义,以及每个成员的偏移:

  1. # struct -o task_struct
  2. struct task_struct {
  3. [0] volatile long int state;
  4. [8] void *stack;
  5. [16] atomic_t usage;
  6. [20] unsigned int flags;
  7. ...

显示结构体中的成员定义,以及它的偏移:

  1. # struct task_struct.pid
  2. struct task_struct {
  3. [1192] pid_t pid;
  4. }

显示结构体中成员的值:

  1. # struct task_struct.pid ffffffff81a8d020
  2. pid = 0

查看全局变量的值:

  1. # p sysctl_tcp_rmem
  2. sysctl_tcp_rmem = $4 =
  3. {40960, 873800, 41943040}

查看percpu全局变量(加前缀per_cpu_):

  1. # p per_cpu__irq_stat
  2. PER-CPU DATA TYPE:
  3. irq_cpustat_t per_cpu__irq_stat; // 变量类型的声明
  4. PER-CPU ADDRESSES:
  5. [0]: ffff880028216540 // 0号CPU对应变量的地址
  6. [1]: ffff880645416540
  7. ...

查看0号CPU对应变量的值:

  1. # struct irq_cpustat_t ffff880028216540
  2. struct irq_cpustat_t {
  3. __softirq_pending = 0,
  4. __nmi_count = 4780195,
  5. irq0_irqs = 148,
  6. ...

(6) 反汇编和源码行

反汇编:

  1. # dis ffffffffa021ba91 // 反汇编一条指令
  2. # dis -l probe_2093+497 10 // 反汇编从某个地址开始的10条指令

对于内核中的符号:

  1. # sym tcp_v4_do_rcv // 通过symbol,显示虚拟地址和源码位置
  2. # sym ffffffff8149f930 // 通过虚拟地址,显示symbol和源码位置

对于模块中的符号:

需要先加载相应的模块进来,才能显示符号对应的源码:

  1. # mod // 查看模块
  2. # mod -s module /path/to/module.ko // 加载模块
  3. # sym symbol // 显示符号对应的模块源码,也可以用virtual address

(7) 修改内存

提供动态的修改运行中内核的功能,以供调试,但是RHEL和CentOS上不允许。

wr:modifies the contents of memory.

wr [-u | -k | -p] [-8 | -16 | -32 | -64] [address | symbol] value

使用例子:

  1. # p sysctl_tcp_timestamps
  2. sysctl_tcp_timestamps = $3 = 1
  3. # wr sysctl_tcp_timestamps 0
  4. wr: cannot write to /dev/crash!

我勒个擦,/dev/crash的文件属性是rw,但是crash_fops中并没有提供写函数,所以还是只读的。

这个功能很有用,但被RHEL和CentOS禁止了,所以如需动态修改运行内核还是用systemtap吧。

Reference

[1]. http://www.ibm.com/developerworks/cn/linux/l-cn-kdump1/

[2]. http://www.ibm.com/developerworks/cn/linux/l-cn-kdump2/

[3]. http://www.ibm.com/developerworks/cn/linux/l-cn-kdump3/

[4]. http://www.ibm.com/developerworks/cn/linux/l-cn-kdump4/

[5]. http://www.ibm.com/developerworks/cn/linux/l-cn-dumpanalyse/

[6]. http://people.redhat.com/anderson/crash_whitepaper/

kdump机制和crash常见使用的更多相关文章

  1. linux内核崩溃之kdump机制

    kdump相关概念 standard(production) kernel   生产内核    ,是指我们正在使用的kernel. Crash(capture)kernel             捕 ...

  2. Linux Kdump 机制详解

    文章目录 1. 简介 1.1 安装 1.2 触发 kdump 1.3 调试 kdump 1.3.1 安装 debuginfo vmlinux 1.3.2 编译 kernel 1.4 kdump-too ...

  3. 内核调试工具 — kdump & crash

    kdump简介 kdump是系统崩溃的时候,用来转储运行内存的一个工具. 系统一旦崩溃,内核就没法正常工作了,这个时候将由kdump提供一个用于捕获当前运行信息的内核, 该内核会将此时内存中的所有运行 ...

  4. Kernel Panic常见原因以及解决方法

    Technorati 标签: Kernel Panic 出现原因 1. Linux在中断处理程序中,它不处于任何一个进程上下文,如果使用可能睡眠的函数,则系统调度会被破坏,导致kernel panic ...

  5. Swift app中的Crash捕获与处理

    1. 为什么会Crash 常见的Crash原因有:访问已经被释放的内存,数组越界,使用!解包值为nil的变量.当遇到这些情况时,说明应用已经遇到了很严重的非预期错误,无法再继续运行.操作系统检测到这些 ...

  6. linux crash工具安装配置

    crash简介 crash是redhat的工程师开发的,主要用来离线分析linux内核转存文件,它整合了gdb工具,功能非常强大.可以查看堆栈,dmesg日志,内核数据结构,反汇编等等.crash支持 ...

  7. 【mysql】关于checkpoint机制

    一.简介 思考一下这个场景:如果重做日志可以无限地增大,同时缓冲池也足够大,那么是不需要将缓冲池中页的新版本刷新回磁盘.因为当发生宕机时,完全可以通过重做日志来恢复整个数据库系统中的数据到宕机发生的时 ...

  8. 进程间通信机制IPC

    进程通信是指进程之间的信息交换.PV操作是低级通信方式,例如信号量,主要是进程间以及同一进程内不同线程之间的同步手段.髙级通信方式是指以较高的效率传输大量数据的通信方式.高级通信方法主要有以下三个类. ...

  9. 常见C++面试题(三)

    strcpy和memcpy有什么区别?strcpy是如何设计的,memcpy呢?   strcpy提供了字符串的复制.即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束 ...

随机推荐

  1. JavaScript基础 -- BOM

    JavaScript三大核心: 1)核心(ECMAScript):描述了JS的语法和基本对象 2)文档对象模型(DOM):处理网页内容的方法和接口 3)浏览器对象模型(BOM):与浏览器交互的方法和接 ...

  2. go5--数组

    package main /* 数组Array 定义数组的格式:var <varName> [n]<type>,n>=0 数组长度也是类型的一部分,因此具有不同长度的数组 ...

  3. YTU 2899: D-险恶逃生 I

    2899: D-险恶逃生 I 时间限制: 1 Sec  内存限制: 128 MB 提交: 130  解决: 55 题目描述 Koha被邪恶的巫师困在一个m*n的矩阵当中,他被放在了矩阵的最左上角坐标( ...

  4. 电脑的系统盘只有10G了

    软件也是缓存多了,准备把一些让家人卸载,昨天开始布置培训任务就是有一个电报的程序,把流程说了下,从今天开始就会指导,错误点分析.

  5. Python不兼容问题

    今天遇到了一个Python2与3不兼容的坑. ride是基于robot框架的python自动化ui,但它只支持python2,而我电脑环境只有python3,想跑别人基于ride编写的测试用例,折腾了 ...

  6. Java IO 字节流与字符流 (五)

    Java的IO流分为字符流(Reader,Writer)和字节流(InputStream,OutputStream),字节流顾名思义字节流就是将文件的内容读取到字节数组,然后再输出到另一个文件中.而字 ...

  7. emma中文显示乱码问题解决

    在Linux中如果使用mysql的图形客户端,个人感觉Emma还不错.但是emma默认用apt-get 安装的话,emma是不支持中文的,这个需要自己修改一下了配置文件,或者直接修改emma程序源文件 ...

  8. 昆石VOS3000_2.1.3.2完整安装包及安装脚本

    安装包下载地址:http://www.51voip.org/post/55.html 安装教程: 上传安装包 核实 关闭selinux 是否关闭 /usr/sbin/sestatus -v cd /r ...

  9. bzoj 1867: [Noi1999]钉子和小球【dp】

    设f[i][j]为掉到f[i][j]时的概率然后分情况随便转移一下就好 主要是要手写分数比较麻烦 #include<iostream> #include<cstdio> usi ...

  10. 牛客网NOIP赛前集训营 提高组(第七场)

    中国式家长 2 链接:https://www.nowcoder.com/acm/contest/179/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K, ...