文章目录

  • 一、调试环境准备
  • 二、使用crash分析vmcore
    • 1、bt命令
    • 2、log命令
    • 3、dis命令
    • 4、mod命令
    • 5、sym命令
    • 6、ps命令
    • 7、files命令
    • 8、vm命令
    • 9、task命令
    • 10、kmem命令
    • 11、struct命令
    • 13、p命令
    • 14、查看某个命令使用方法及使用示例
    • 15、其它命令
  • 三、写在最后

我们在 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,需要:

  • crash工具
  • 崩溃转储文件(vmcore)
  • 发生崩溃的内核映像文件(vmlinux),包含调试内核所需调试信息

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

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

  • kernel-debuginfo
  • kernel-debuginfo-common

对于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即可。

对于oracle linux系统,可以在https://oss.oracle.com/上下载内核调试包,比如现在要找oracle linux6.6的:

# wget https://oss.oracle.com/ol6/debuginfo/kernel-uek-debuginfo-3.8.13-44.1.1.el6uek.x86_64.rpm
# wget https://oss.oracle.com/ol6/debuginfo/kernel-uek-debuginfo-common-3.8.13-44.1.1.el6uek.x86_64.rpm

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

rpm -ivh *.rpm

安装完成后,可以在/lib/debug/lib/modules/3.10.0-957.el7.x86_64/(或者是/usr/lib/…下面)目录下看到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


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

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

1、bt命令

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

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

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

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

2、log命令

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

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

3、dis命令

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

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

4、mod命令

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

重装加载进改内核模块:

crash> mod -s my_test_lkm /mnt/hgfs/test_ko/lkm-test05/my_test_lkm.koMODULE       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转换查看系统符号信息
sym addr 通过虚拟地址,显示symbol和源码位置

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行,查看代码可以发现:

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

sym symbol 通过symbol,显示虚拟地址和源码位置:

crash> sym vfs_fstat
ffffffff81196f30 (T) vfs_fstat ../debug/kernel-3.8.13/linux-3.8.13-44.1.1.el6uek/fs/stat.c: 59

6、ps命令

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

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

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

查看指定进程的进程树(ps -p pid)

crash> ps -p 85151
PID: 0      TASK: ffffffff818b6420  CPU: 0   COMMAND: "swapper/0"PID: 1      TASK: ffff881f91dae040  CPU: 28  COMMAND: "init"PID: 14544  TASK: ffff881f8d7b05c0  CPU: 11  COMMAND: "init.tfa"PID: 85138  TASK: ffff880bab01a400  CPU: 8   COMMAND: "tfactl"PID: 85151  TASK: ffff880b7a728380  CPU: 17  COMMAND: "perl"

7、files命令

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

8、vm命令

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

9、task命令

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

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查看:

11、struct命令

1、查看结构体成员变量,直接struct后面跟结构体名,比如我要看下内核中dentry结构体的定义,可以这样:

crash> struct dentry
struct dentry {unsigned int d_flags;seqcount_t d_seq;struct hlist_bl_node d_hash;struct dentry *d_parent;struct qstr d_name;struct inode *d_inode;unsigned char d_iname[32];unsigned int d_count;spinlock_t d_lock;const struct dentry_operations *d_op;struct super_block *d_sb;long unsigned int d_time;void *d_fsdata;struct list_head d_lru;union {struct list_head d_child;struct callback_head d_rcu;} d_u;struct list_head d_subdirs;struct hlist_node d_alias;
}
SIZE: 192

2、查看成员变量在结构体中的偏移量,struct加-o选项:

crash> struct dentry -o
struct dentry {[0] unsigned int d_flags;[4] seqcount_t d_seq;[8] struct hlist_bl_node d_hash;[24] struct dentry *d_parent;[32] struct qstr d_name;[48] struct inode *d_inode;[56] unsigned char d_iname[32];[88] unsigned int d_count;[92] spinlock_t d_lock;[96] const struct dentry_operations *d_op;[104] struct super_block *d_sb;[112] long unsigned int d_time;[120] void *d_fsdata;[128] struct list_head d_lru;union {struct list_head d_child;struct callback_head d_rcu;[144] } d_u;[160] struct list_head d_subdirs;[176] struct hlist_node d_alias;
}
SIZE: 192crash> struct dentry.d_inode
struct dentry {[48] struct inode *d_inode;
}

3、查看内存中指定结构体的值,struct后跟指针地址

crash> struct dentry ffff881fbdc02c80
struct dentry {d_flags = 136, d_seq = {sequence = 4}, d_hash = {next = 0x0, pprev = 0xffffc900031bd8a0}, d_parent = 0xffff881fbdc02ec0, d_name = {{{hash = 1819047278, len = 4}, hash_len = 18998916462}, name = 0xffff881fbdc02cb8 "null"}, d_inode = 0xffff881f9011f5d0, d_iname = "null\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", d_count = 2974, d_lock = {{rlock = {raw_lock = {{head_tail = 2290387076, tickets = {head = 34948, tail = 34948}}}}}}, d_op = 0xffffffff815cce40, d_sb = 0xffff881f9011e800, d_time = 0, d_fsdata = 0x0, d_lru = {next = 0xffff881fbdc02d00, prev = 0xffff881fbdc02d00}, d_u = {d_child = {next = 0xffff881fbdc02dd0, prev = 0xffff881fbdfe1f50}, d_rcu = {next = 0xffff881fbdc02dd0, func = 0xffff881fbdfe1f50}}, d_subdirs = {next = 0xffff881fbdc02d20, prev = 0xffff881fbdc02d20}, d_alias = {next = 0x0, pprev = 0xffff881f9011f6e8}
}

注:如果要查看二阶指针的值,可以通过rd命令需要先获取一级指针的值,然后再用struct 结构体名 + addr获取具体的值,比如:

下面将通过struct file**fd的地址,获取fd指针数组中各个file结构体成员地址(二阶指针存放的是file指针的地址,所以可以通过rd获取一级指针的地址;二阶指针+8,则指向下一个file结构体指针):

对比可以看出,这种方式获取的file指针跟files命令读取到的文件指针的值相同。

13、p命令

p命令可以用来打印出表达式或者变量的值

crash> p jiffies
jiffies = $7 = 4314305182
crash>
crash> p old_close_func
old_close_func = $5 = (close_t) 0xffffffff811ffd60 <SyS_close>
crash> p SyS_close
SyS_close = $6 = {long (long)} 0xffffffff811ffd60 <SyS_close>
crash> sym SyS_close
ffffffff811ffd60 (T) SyS_close /usr/src/debug/kernel-3.10.0-693.el7/linux-3.10.0-693.el7.x86_64/fs/open.c: 1113
crash>

14、查看某个命令使用方法及使用示例

使用help+某个命令,可以查看这个命令的使用方法及使用示例:
比如我们想看struct命令如何使用,可以执行 help struct命令:

crash> help structNAMEstruct - structure contentsSYNOPSISstruct struct_name[.member[,member]][-o][-l offset][-rfuxdp][address | symbol][count | -c count]DESCRIPTIONThis command displays either a structure definition, or a formatted displayof the contents of a structure at a specified address.  When no address isspecified, the structure definition is shown along with the structure size.A structure member may be appended to the structure name in order to limitthe scope of the data displayed to that particular member; when no addressis specified, the member's offset and definition are shown.struct_name  name of a C-code structure used by the kernel..member  name of a structure member; to display multiple members of astructure, use a comma-separated list of members.-o  show member offsets when displaying structure definitions; if used with an address or symbol argument, each member willbe preceded by its virtual address.-l offset  if the address argument is a pointer to a structure member thatis contained by the target data structure, typically a pointerto an embedded list_head, the offset to the embedded member maybe entered in either of the following manners:1. in "structure.member" format.2. a number of bytes. -r  raw dump of structure data.-f  address argument is a dumpfile offset.-u  address argument is a user virtual address in the currentcontext.-x  override default output format with hexadecimal format.-d  override default output format with decimal format.-p  if a structure member is a pointer value, show the member'sdata type on the output line; and on the subsequent line(s),dereference the pointer, display the pointer target's symbolvalue in brackets if appropriate, and if possible, display thetarget data; requires an address argument.address  hexadecimal address of a structure; if the address pointsto an embedded list_head structure contained within thetarget data structure, then the "-l" option must be used.symbol  symbolic reference to the address of a structure.count  count of structures to dump from an array of structures;if used, this must be the last argument entered.-c count  "-c" is only required if "count" is not the last argumententered or if a negative number is entered; if a negativevalue is entered, the (positive) "count" structures thatlead up to and include the target structure will be displayed.Structure data, sizes, and member offsets are shown in the current outputradix unless the -x or -d option is specified.

再比如,想查看ps命令在crash工具中怎么使用,可以help ps查看:

crash> help psNAMEps - display process status informationSYNOPSISps [-k|-u|-G][-s][-p|-c|-t|-l|-a|-g|-r] [pid | taskp | command] ...DESCRIPTIONThis command displays process status for selected, or all, processesin the system.  If no arguments are entered, the process data isis displayed for all processes.  Specific processes may be selectedby using the following identifier formats:pid  a process PID.taskp  a hexadecimal task_struct pointer.command  a command name.  If a command name is made up of letters thatare all numerical values, precede the name string with a "\".The process list may be further restricted by the following options:-k  restrict the output to only kernel threads.-u  restrict the output to only user tasks.-G  display only the thread group leader in a thread group.The process identifier types may be mixed.  For each task, the followingitems are displayed:1. the process PID.2. the parent process PID.3. the CPU number that the task ran on last.4. the task_struct address or the kernel stack pointer of the process.(see -s option below)5. the task state (RU, IN, UN, ZO, ST, TR, DE, SW).6. the percentage of physical memory being used by this task.7. the virtual address size of this task in kilobytes.8. the resident set size of this task in kilobytes.9. the command name.The default output shows the task_struct address of each process under acolumn titled "TASK".  This can be changed to show the kernel stack pointer under a column titled "KSTACKP".-s  replace the TASK column with the KSTACKP column.On SMP machines, the active task on each CPU will be highlighted by anangle bracket (">") preceding its information.Alternatively, information regarding parent-child relationships,per-task time usage data, argument/environment data, thread groups,or resource limits may be displayed:-p  display the parental hierarchy of selected, or all, tasks.

15、其它命令

可以通过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的地方,如下图:

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

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

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

crash分析linux内核崩溃转储文件vmcore相关推荐

  1. crash工具分析linux内核,如何使用crash工具分析Linux内核崩溃转储文件

    满意答案 使用 crash 的先决条件 1. kernel 映像文件 vmlinux 在编译的时候必须指定了 -g 参数,即带有调试信息. 2. 需要有一个内存崩溃转储文件(例如 vmcore),或者 ...

  2. 制造内核崩溃并使用crash分析内核崩溃产生的vmcore文件

    制造内核崩溃并使用crash分析内核崩溃产生的vmcore文件 1,安装kernel-debuginfo$(uname -r).rpm和kernel-debuginfo-common-$(uname ...

  3. Linux Kdump内核崩溃转储部署详解

    最近在回顾kdump内核崩溃转储技术,刚好可以整理下相关知识点,系统性地讲解下Kdump的部署过程以及原理. kdump内核崩溃转储技术在处理linux内核遇到宕机等异常问题中,可以将其崩溃瞬间的内存 ...

  4. linux内核kdump,linux内核崩溃之kdump机制

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

  5. windows崩溃转储文件

        在默认情况下,所有的Windows系统都被设置为:当系统崩溃时,系统总是试图记录下有关当前系统的状态的信息.你可以通过用户界面看到这些设置,做法是,打开控制面板中的System工具,然后在Sy ...

  6. Linux内核中读写文件数据的方法

    Linux内核中读写文件数据的方法     有时候需要在Linuxkernel--大多是在需要调试的驱动程序--中读写文件数据.在kernel中操作文件没有标准库可用,需要利用kernel的一些函数, ...

  7. 【转】 Linux内核中读写文件数据的方法--不错

    原文网址:http://blog.csdn.net/tommy_wxie/article/details/8193954 Linux内核中读写文件数据的方法     有时候需要在Linuxkernel ...

  8. 跟踪分析Linux内核5.0系统调用处理过程

    跟踪分析Linux内核5.0系统调用处理过程 学号384 原创作业转载请注明出处+中国科学技术大学孟宁老师的Linux操作系统分析 https://github.com/mengning/linuxk ...

  9. linux内核烧制,学会分析Linux内核需要多久?8分钟

    Linux的最大的好处之一就是它的源码公开.同时,公开的核心源码也吸引着无数的电脑爱好者和程序员:他们把解读和分析Linux的核心源码作为自己的最大兴趣,把修改Linux源码和改造Linux系统作为自 ...

最新文章

  1. 二维码检测哪家强?五大开源库测评比较
  2. 基于SSM开发实现中药制剂网站系统
  3. 探讨BI可视化下的旅游大数据分析,你的钱都花哪了?
  4. 快速搭建springmvc+spring data jpa工程
  5. MAC报错:-bash: mysqlbinlog : command not found
  6. MVC html 控件扩展【转载】
  7. 一元线性回归预测:销售收入与广告支出实战
  8. android下拉刷新listView剖析
  9. 408考研计算机网络视频,计算机408考研视频哪个好
  10. javascript实现国密SM4
  11. Linux中tar命令用法
  12. 「 Mac应用加密工具」AppLocker for Mac 2.7.0
  13. 尚硅谷nodejs入门教程_笔记
  14. android自定义涂鸦,Android Studio:小Demo-“涂鸦”
  15. 超美的天环星轨动态引导页html官网源码下载
  16. java sign函数_C / C ++中是否有标准的符号函数(signum,sgn)?
  17. oracle dul误删数据,案例:Oracle dul数据挖掘 没有数据库备份非常规恢复truncate删除的数据表...
  18. PTA 帅到没朋友 (20分)
  19. 视频会议系统——多分屏
  20. [MODIS数据处理#8]批量将ET栅格的时间分辨率从8-day转换为monthly的一种思路

热门文章

  1. 上海张江科学城公布“年成绩单” 逾36亿元项目集中签约
  2. 3步!PDF Converter Master for Mac6.2中文激活版满足您一切pdf转换需求!
  3. joplin同步到apache webdav
  4. kafka rebalance机制详解
  5. SpringBoot项目main方法详解
  6. ajax局部刷新对应的div,ajax局部刷新一个div下的jsp
  7. 平时的一些手绘,有点拿不出手哈
  8. php文件大小单位单位转换
  9. 服务器配置,负载均衡时需配置MachineKey
  10. pytest中实用但不常用方法列举