内核调试工具 — kdump & crash
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,以下是几个常用配置:
# path /var/crash
默认的vmcore存放目录为/var/crash/%HOST-%DATE/,包括两个文件:vmcore和vmcore-dmesg.txt
# ssh <user@service>
will copy /proc/vmcore to <user@server>:<path>/%HOST-%DATE/ via SSH
make sure user has necessary write permissions on server.
自动拷贝到远程机器上。
# default <reboot | halt | poweroff | shell | mount_root_run_init>
Actions to perform in case dumping to intended target fails.
转储失败时执行。
(3) 启动服务
# chkconfig kdump on // 开机启动
# 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是否正常工作。
# 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映像文件,查看捕获内核是否加载到内存中:
# cat /sys/kernel/kexec_crash_loaded
缩小捕获内核占用的内存:
# echo N > /sys/kernel/kexec_crash_size
crash简介
当系统崩溃时,通过kdump可以获得当时的内存转储文件vmcore,但是该如何分析vmcore呢?
crash是一个用于分析内核转储文件的工具,一般和kdump搭配使用。
使用crash时,要求调试内核vmlinux在编译时带有-g选项,即带有调试信息。
如果没有指定vmcore,则默认使用实时系统的内存来分析。
值得一提的是,crash也可以用来分析实时的系统内存,是一个很强大的调试工具。
crash使用gdb作为内部引擎,语法类似于gdb,命令的使用说明可以用<cmd> help来查看。
使用crash需要安装crash工具包和内核调试信息包:
crash
kernel-debuginfo-common
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基本输出
# crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/%HOST-%DATE/vmcore
KERNEL: /usr/lib/debug/lib/modules/2.6.32-358.el6.x86_64/vmlinux
DUMPFILE: vmcore [PARTIAL DUMP]
CPUS: 12
DATE: Fri Sep 19 16:47:01 2014
UPTIME: 7 days, 06:37:46
LOAD AVERAGE: 0.19, 0.05, 0.01
TASKS: 282
NODENAME: localhost.localdomain
RELEASE: 2.6.32-358.el6.x86_64
VERSION: #1 SMP Tue Oct 29 10:18:21 CST 2013
MACHINE: x86_64 (1999 Mhz)
MEMORY: 48 GB
PANIC: "Oops: 0002 [#1] SMP " (check log for details)
PID: 0
COMMAND: "swapper"
TASK: ffffffff81a8d020 (1 of 12) [THREAD_INFO: ffffffff81a00000]
CPU: 0
STATE: TASK_RUNNING (PANIC)
这些基本输出信息简单明了,可由sys命令触发。
(4) crash常用命令
bt:打印函数调用栈,displays a task's kernel-stack backtrace,可以指定进程号bt <pid>。
log:打印系统消息缓冲区,displays the kernel log_buf contents,如log | tail -n 30。
ps:显示进程的状态,>表示活跃的进程,如ps | grep RU。
sys:显示系统概况。
kmem -i:显示内存使用信息。
dis <addr>:对给定地址进行反汇编。
exception RIP即为造成错误的指令。
关于log命令:
内核首先把消息打印到内核态的ring buffer,用户态的klogd负责读取并转发给syslogd,让它记录到磁盘。
在内核崩溃时,可能无法把消息记录到磁盘,但是ring buffer中一般会有记录。所以log命令有时候能查看
到系统日志中所缺失的信息。
(5) 结构体和变量
查看结构体中所有成员的值,例如:
# ps | grep RU
> 0 0 0 ffffffff81a8d020 RU 0.0 0 0 [swapper]
# struct task_struct ffffffff81a8d020
struct task_struct {
state = 0,
stack = 0xffffffff81a00000,
usage = {
counter = 2
},
flags = 2097408,
显示整个结构体的定义:
# struct task_struct
struct task_struct {
volatile long int state;
void *stack;
atomic_t usage;
unsigned int flags;
显示整个结构体的定义,以及每个成员的偏移:
# struct -o task_struct
struct task_struct {
[0] volatile long int state;
[8] void *stack;
[16] atomic_t usage;
[20] unsigned int flags;
...
显示结构体中的成员定义,以及它的偏移:
# struct task_struct.pid
struct task_struct {
[1192] pid_t pid;
}
显示结构体中成员的值:
# struct task_struct.pid ffffffff81a8d020
pid = 0
查看全局变量的值:
# p sysctl_tcp_rmem
sysctl_tcp_rmem = $4 =
{40960, 873800, 41943040}
查看percpu全局变量(加前缀per_cpu_):
# p per_cpu__irq_stat
PER-CPU DATA TYPE:
irq_cpustat_t per_cpu__irq_stat; // 变量类型的声明
PER-CPU ADDRESSES:
[0]: ffff880028216540 // 0号CPU对应变量的地址
[1]: ffff880645416540
...
查看0号CPU对应变量的值:
# struct irq_cpustat_t ffff880028216540
struct irq_cpustat_t {
__softirq_pending = 0,
__nmi_count = 4780195,
irq0_irqs = 148,
...
(6) 反汇编和源码行
反汇编:
# dis ffffffffa021ba91 // 反汇编一条指令
# dis -l probe_2093+497 10 // 反汇编从某个地址开始的10条指令
对于内核中的符号:
# sym tcp_v4_do_rcv // 通过symbol,显示虚拟地址和源码位置
# sym ffffffff8149f930 // 通过虚拟地址,显示symbol和源码位置
对于模块中的符号:
需要先加载相应的模块进来,才能显示符号对应的源码:
# mod // 查看模块
# mod -s module /path/to/module.ko // 加载模块
# sym symbol // 显示符号对应的模块源码,也可以用virtual address
(7) 修改内存
提供动态的修改运行中内核的功能,以供调试,但是RHEL和CentOS上不允许。
wr:modifies the contents of memory.
wr [-u | -k | -p] [-8 | -16 | -32 | -64] [address | symbol] value
使用例子:
# p sysctl_tcp_timestamps
sysctl_tcp_timestamps = $3 = 1
# wr sysctl_tcp_timestamps 0
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的更多相关文章
- 记一次Linux内核崩溃:kdump,crash,vmcore
原理 Linux内核发送崩溃时,kdump会生成一个内核转储文件vmcore. 可以通过分析vmcore分析出内核崩溃的原因. crash是一个被广泛应用的内核奔溃转储文件分析工具.使用crash调试 ...
- 使用kdump内核调试工具遇到的问题及解决
修改linux内核代码或者内核模块的时候,搞不好就会造成linux死机崩溃,crash死机后/var/log/kern.log里面不会有任何异常信息记录.这时候kdump就会派上用场了,网上kdump ...
- 转 -Linux 自检和 SystemTap (强大的内核调试工具)---包含下载地址
下载: http://www.oschina.net/p/systemtap/ https://sourceware.org/systemtap/ftp/releases/ Linux 自检和 S ...
- kdump+crash
参考:http://www.360doc.com/content/19/0205/08/36367108_813163495.shtml https://blog.csdn.net/u01436103 ...
- 一个未完成的2.6.32-220内核踩内存crash分析记录
遇到一个crash,log如下: BUG: unable to handle kernel NULL pointer dereference at (null) IP: [<ffffffff81 ...
- 内核调试工具——strace
简介 strace常用来跟踪进程执行时的系统调用和所接收的信号. 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核 ...
- Linux内核调试:kdump、vmcore、crash、kernel-debuginfo【转】
转自:https://blog.csdn.net/guowenyan001/article/details/19807555 一.简介 linux内核发送崩溃时,kdump会生成一个内核转储文件vmc ...
- kdump机制和crash常见使用
kdump简介 kdump是系统崩溃的时候,用来转储运行内存的一个工具. 系统一旦崩溃,内核就没法正常工作了,这个时候将由kdump提供一个用于捕获当前运行信息的内核, 该内核会将此时内存中的所有运行 ...
- linux 保留内核中sas驱动的加载导致crash问题
[root@localhost ~]# uname -a Linux localhost.localdomain -.el7.x86_64 问题描述,在crash的时候,小内核因为分配中断号失败而触发 ...
随机推荐
- PGM:基于模板的表示
http://blog.csdn.net/pipisorry/article/details/52537660 引言 概率图模型(无论贝叶斯网或马尔可夫网)在一个固定的随机变量集X上具体指定了一个联合 ...
- iOS开发基础之开发证书的说明和发布
1.首先通过钥匙串访问--证书助理--从证书颁发机构请求证书--填写证书信息(邮箱,常用名称,存储到磁盘)--存储为(自定义名称.certSigningReuqest,简称CSR文件,只是为了提交到苹 ...
- springMVC源码分析--AbstractHandlerMethodMapping获取url和HandlerMethod对应关系(十)
在之前的博客springMVC源码分析--AbstractHandlerMapping(二)中我们介绍了AbstractHandlerMethodMapping的父类AbstractHandlerMa ...
- 在自己笔记本电脑上如何访问虚拟机的内容、包括可以使用ssh、访问tomcat、访问nginx
1.给自己的电脑设置一个回环网卡,关于如何配置回环网卡,可以百度搜索一下 设置好后的状态如下: 并把回环网卡的ipv4的值设置成192.168.1.1 配置如下: 2.将vmware中的"虚 ...
- Dynamics CRM2013 在Visual Studio中开启脚本的Xrm.Page智能提示
前面篇博文http://blog.csdn.net/vic0228/article/details/49663751提到了通过引用XrmPage-vsdoc.js文件来启用Xrm.Page的智能提示, ...
- shell入门之expr的使用
在expr中加减乘除的使用,脚本如下: #!/bin/sh #a test about expr v1=`expr 5 + 6` echo "$v1" echo `expr 3 + ...
- Android开发学习之路--Service之初体验
android最后一个组件便是service了,终于学习到最后一个组件了,从年前的开发环境的搭建,到现在学到最后一个组件花了三周的时间,期间记录的点点滴滴,照着书本学习编写的代码都受益匪浅,这里要感谢 ...
- 1.Maven+SpringMVC+Eclipse软件安装配置,Maven报插件错误,Eclipse总是卡死的解决办法,导入一个maven工程后 一直显示importing maven project
使用Maven+SpringMVC+Eclipse软件安装配置过程中的问题: 1.Eclipse总是卡死的解决办法: 一:内存不足所以会卡死,配置一下eclipse.ini修改这几个值就好了-X ...
- Java-IO之BufferedReader(字符缓冲输入流)
BufferedReader是缓冲字符输入流,继承于Reader,BufferedReader的作用是为其他字符输入流添加一些缓冲功能. BufferedReader主要的函数列表: Buffered ...
- Java进阶(六)Java反射机制可恶问题NoSuchFieldException
作为一种重要特性,Java反射机制在很多地方会用到.在此做一小结,供朋友们参考. 首先从一个问题开始着手. 可恶的问题又来了,NoSuchFieldException,如下图所示: 完全不知道这个qu ...