使用crash分析linux内核崩溃转储文件vmcore

2020-04-21  本文已影响0人  大胖005

我们在Kdump-内核崩溃转储服务中,介绍了kdump服务可以在系统崩溃时,生成崩溃转储文件vmcore,便于我们分析内核崩溃原因,那么,下面我们就来看下如何使用crash工具可以帮助我们分析系统崩溃原因。

crash工具,跟gdb很类似,它可以交互的分析运行中的内核,也可以分析由kdump、netdump、diskdump、xendump产生的core dump文件。

本文实验环境:

[root@yglocal ~]# cat /etc/redhat-release 
CentOS Linux release 7.6.1810 (Core) 
[root@yglocal ~]# uname -r
3.10.0-957.el7.x86_64

一、调试环境准备

使用crash工具分析vmcore,需要:

一般系统在安装后在/boot目录下,也有个内核映像文件,vmlinuxz开头的文件,但是它是压缩过后的,无法完成调试工作,如下图: vmlinuxz

所以我们需要下载带有完整调试信息的内核映像文件(编译时带-g选项),内核调试信息包kernel-debuginfo有两个:

对于centos系统,可以在http://debuginfo.centos.org/上下载到各发行版本所需的调试包。
对于centos7.x,安装对应内核版本的内核调试包,执行如下即可:

# wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-common-x86_64-`uname -r`.rpm
# wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-`uname -r`.rpm

注意:如果系统为centos6.x,则将debuginfo.centos.org/后面的7改成6即可。

下载完后,安装内核调试包:

rpm -ivh *.rpm

安装完成后,可以在/lib/debug/lib/modules/3.10.0-957.el7.x86_64/目录下看到vmlinux内核映像文件:

[root@yglocal ~]# ll -th /lib/debug/lib/modules/3.10.0-957.el7.x86_64/
total 419M
drwxr-xr-x.  2 root root  119 Mar 26 13:13 vdso
drwxr-xr-x. 12 root root  128 Mar 26 13:13 kernel
-rwxr-xr-x.  2 root root 419M Nov  9  2018 vmlinux

再来安装crash工具,先查看下是否已安装

[root@yglocal ~]# rpm -q crash
crash-7.2.3-8.el7.x86_64

若没有安装过,则执行以下命令安装:

yum install crash

二、使用crash分析vmcore

分析vmcore文件,执行命令:

crash /lib/debug/lib/modules/3.10.0-957.el7.x86_64/vmlinux /var/crash/127.0.0.1-2020-04-04-14\:10\:45/vmcore
启动crash

其中下面这些信息,就是导致系统崩溃的直接原因及进程相关信息:

 PANIC: "BUG: unable to handle kernel NULL pointer dereference at 000000000000000c"
    PID: 27005
COMMAND: "pickup"
   TASK: ffff997b388ae180  [THREAD_INFO: ffff997b37f64000]
    CPU: 1
  STATE: TASK_RUNNING (PANIC)

1、bt命令

backtrace打印内核栈回溯信息,bt pid 打印指定进程栈信息。 bt命令

最重要的信息:[exception RIP: my_openat+36],指出发生异常的指令信息

RIP: ffffffffc07c5024,可以得知,发生crash的函数是my_openat中,偏移36字节处的指令。

这里,对应x86-64汇编,应用层下来的系统调用对应的6个参数存放的寄存器依次对应:rdi、rsi、rdx、rcx、r8、r9。对于多于6个参数的,仍存储在栈上。

2、log命令

打印vmcore所在的系统内核日志信息。


log命令

可以分析出当时,内核启动的各项配置,内核最后崩溃时异常日志信息。

3、dis命令

dis -l (function+offset) 10 反汇编出指令所在代码开始,10行代码


dis反汇编

幸运的话,反汇编出来会直接对应源码,我们这里只能看出执行mov 0x70(%rdi),%r13时系统崩溃。

4、mod命令

mod 查看当时内核加载的所有内核模块信息


mod命令

重装加载进改内核模块:

crash> mod -s my_test_lkm /mnt/hgfs/test_ko/lkm-test05/my_test_lkm.ko
     MODULE       NAME                            SIZE  OBJECT FILE
ffffffffc07c7000  my_test_lkm                    12740  /mnt/hgfs/test_ko/lkm-test05/my_test_lkm.ko

5、sym命令

sym 转换指定符号为其虚拟地址,显示系统中符号信息

如上面bt打印的RIP: ffffffffc07c5024,使用sym转换查看系统符号信息

crash> sym ffffffffc07c5024
ffffffffc07c5024 (t) my_openat+36 [my_test_lkm] /mnt/hgfs/test_ko/lkm-test05/my_lkm.c: 25

这时就可以看出对应到my_test_lkm模块的源码,/mnt/hgfs/test_ko/lkm-test05/my_lkm.c文件里第25行,查看代码可以发现:


sym命令

原因:这种hook写法在centos8.x上的最新系统调用约定,是内核版本4.17及之后采用的调用约定。而我当前环境是centos7.6,内核版本为3.10。0,其调用约定并不是这样的,所以这样取参数是有问题的。

6、ps命令

ps 打印内核崩溃时,正常的进程信息


ps查看当前进程信息

带 > 标识代表是活跃的进程,ps pid打印某指定进程的状态信息:

crash> ps 27005
   PID    PPID  CPU       TASK        ST  %MEM     VSZ    RSS  COMM
> 27005   7783   1  ffff997b388ae180  RU   0.2   91732   4124  pickup

7、files命令

files pid 打印指定进程所打开的文件信息


files命令

8、vm命令

vm pid 打印某指定进程当时虚拟内存基本信息


vm命令

9、task命令

task 查看当前进程或指定进程task_struct和thread_info的信息


task命令

10、kmem命令

kmen 查看当时系统内存使用信息

kmem [-f|-F|-c|-C|-i|-v|-V|-n|-z|-o|-h] [-p | -m member[,member]]

       [[-s|-S] [slab] [-I slab[,slab]]] [-g [flags]] [[-P] address]]

我们是要kmem -i查看:


kmem -i

11、其它命令

可以通过help查看到如下:


help命令

如:可以使用rd memory读取内存内容;
struct命令显示结构体定义及指定地址的结构体内容;
irq查看中断信息;
vtop查看地址页表信息等等。

三、写在最后

如果我们确定是某个内核模块导致的问题,可以反汇编出该模块的源代码:

objdump -S -D my_test_lkm.ko > lkm.S

然后vim查看lkm.S文件,查看对应的源码,我们上面调试的bt信息中[exception RIP: my_openat+36],也即是my_openat中偏移量为0x24的地方,如下图:

lkm.S
如果崩溃处对应有c代码的话,这样排查起来就简单多了。

可以关注我的微信公众号大胖聊编程,一起交流学习。

参考资料:
[1]: Red_Hat_Enterprise_Linux-7-Kernel_Administration_Guide-en-US 7.5. ANALYZING A CORE DUMP

上一篇下一篇

猜你喜欢

热点阅读