Linux Kdump和Crash工具

文章目录

  • 一、Kdump 和 Crash 工具介绍
    • 1.1 Kdump
    • 1.2 Crash
  • 二、配置kdump和Crash工具
    • 2.1 安装kexec-tools
    • 2.2 设置crashkernel预留内存大小
    • 2.3 修改kdump默认配置/etc/kdump.conf
    • 2.4 开启kdump服务
    • 2.5 测试kdump功能 检查kdump是否开启成功
    • 2.6 手动触发crash
    • 2.7 查看生成的crash文件
  • 三、Crash命令
    • 3.1 bt 查看异常时的堆栈
    • 3.2 dis命令
    • 3.3 其他
    • 参考文章:

一、Kdump 和 Crash 工具介绍

1.1 Kdump

Kdump是一种基于kexec的Linux内核崩溃捕获机制,kexec的全称是Kernel execution,即立即执行,它可以跳过BIOS或者bootloader等引导程序,快速启动一个新的内核。这样第一个内核的内存就得以保留。在第二个内核中可以对第一个内核产生的崩溃数据进行分析。

1.2 Crash

Crash是由Red Hat Enterprise Linux 项目师开发的,和Kdump配套使用的一个用于分析内核转储文件的工具。

Kdump+Crash分析宕机问题的流程并不复杂,首先Kdump会在内存中保留一块区域,这个区域用来存放捕获内核。当生产内核在运行过程中遇到崩溃等情况。Kdump会通过kexec机制自动启动捕获内核,跳过BIOS,以免破坏了生产内核的内存,然后把生产内核的完整信息(包括CPU寄存器,栈数据等)转储到指定文件中。接着使用Crash工具来分析这个转储文件,以快速定位宕机问题。

二、配置kdump和Crash工具

目前大部分服务器基于RHEL或者其开源版本Centos部署,本节介绍如何在Centos中配置和安装Kdump和Crash工具。

2.1 安装kexec-tools

yum install kexec-tools

2.2 设置crashkernel预留内存大小

GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/root rd.lvm.lv=centos/swap crashkernel=256M"

修改crashkernel的大小,我的系统内存是3G,保留了256M,注意预留内存大小,过小会导致生成coredump文件失败(不知道设置多少时,可以尝试每次增加128M)

修改后还需重新生成grub配置文件,重启系统才能生效

[vagrant@localhost ~]$ grub2-mkconfig -o /boot/grub2/grub.cfg
[vagrant@localhost ~]$ reboot
[root@localhost ~]$ cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=256M rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

2.3 修改kdump默认配置/etc/kdump.conf

centos7 默认已安装kdump,根据需要修改默认配置

[root@localhost ~]$ vi /etc/kdump.conf
path /var/crash #指定coredump文件存储位置
core_collector makedumpfile -c -l --message-level 1 -d 31 #增加-c参数,代表压缩coredump文件
default reboot #生成coredump后,重启系统

2.4 开启kdump服务

systemctl start kdump.service //启动kdump
systemctl enable kdump.service //设置开机启动

2.5 测试kdump功能 检查kdump是否开启成功

[root@localhost ~]# service kdump status
Redirecting to /bin/systemctl status kdump.service
● kdump.service - Crash recovery kernel arming
   Loaded: loaded (/usr/lib/systemd/system/kdump.service; enabled; vendor preset: enabled)
   Active: active (exited) since Wed 2022-11-16 10:48:09 CST; 18s ago
  Process: 1342 ExecStart=/usr/bin/kdumpctl start (code=exited, status=0/SUCCESS)
 Main PID: 1342 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/kdump.service
...
Jan 05 11:07:03 localhost.localdomain kdumpctl[1082]: Starting kdump: [OK]
...

如果看到”Starting kdump: [OK]“字样,说明Kdump服务已经成功配置。

2.6 手动触发crash

[root@cloud ~]# echo 1 > /proc/sys/kernel/sysrq ; echo c > /proc/sysrq-trigger

如果Kdump配置正确,上述命令会让系统快速重启并且启动捕获内核以进行转储。

2.7 查看生成的crash文件

[root@localhost ~]# ls /var/crash/
127.0.0.1-2022-11-16-11:11:43

转储完成之后会自动切换回生产内核。在/var/crash目录下存放了对应的coredump目录。(在2.3节中设置了将coredump目录存放在/var/crash中)。该目录是以IP地址和日期来命令的,目录里面包含了vmcorevmcore-dmesg.txt两个文件,其中vmcore是捕获的内核转储文件vmcore-dmesg.txt是生产内核发生崩溃时生成的内核日志信息

三、Crash命令

在使用Crash工具进行分析之前,需要安装生产内核对应的调试信息的内核符号表。

sudo yum update -y
sudo yum install -y kernel-debuginfo-$(uname -r)

安装完成之后,带调试符号信息的内核在/usr/lib/debug/lib/modules/目录下面

crash vmcore /usr/lib/debug/lib/modules/$(uname -r)/vmlinux

这里vmlinux提供内核符号表,里面存了大量的全局变量地址和数据结构原理和代码等。 crash 根据你输入的命令去vmlinux中查找符号和地址,再去vmcore里面对应的位置获取真实数据,这样解析就完成了。

3.1 bt 查看异常时的堆栈

crash> bt
PID: 53022  TASK: ffff9dbe1ebc1040  CPU: 0   COMMAND: "bash"
 #0 [ffff9dbe2060bae0] machine_kexec at ffffffffb7e63674
 #1 [ffff9dbe2060bb40] __crash_kexec at ffffffffb7f1ce12
 #2 [ffff9dbe2060bc10] crash_kexec at ffffffffb7f1cf00
 #3 [ffff9dbe2060bc28] oops_end at ffffffffb856c758
 #4 [ffff9dbe2060bc50] no_context at ffffffffb855aa7e
 #5 [ffff9dbe2060bca0] __bad_area_nosemaphore at ffffffffb855ab15
 #6 [ffff9dbe2060bcf0] bad_area_nosemaphore at ffffffffb855ac86
 #7 [ffff9dbe2060bd00] __do_page_fault at ffffffffb856f6b0
 #8 [ffff9dbe2060bd70] do_page_fault at ffffffffb856f915
 #9 [ffff9dbe2060bda0] page_fault at ffffffffb856b758
    [exception RIP: sysrq_handle_crash+22]
    RIP: ffffffffb8261bf6  RSP: ffff9dbe2060be58  RFLAGS: 00010246
    RAX: ffffffffb8261be0  RBX: ffffffffb8ae4c60  RCX: 0000000000000000
    RDX: 0000000000000000  RSI: ffff9dbe3a613898  RDI: 0000000000000063
    RBP: ffff9dbe2060be58   R8: ffffffffb8de38bc   R9: 6873617263206120
    R10: 000000000000073a  R11: 0000000000000739  R12: 0000000000000063
    R13: 0000000000000000  R14: 0000000000000004  R15: 0000000000000000
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
#10 [ffff9dbe2060be60] __handle_sysrq at ffffffffb826241d
#11 [ffff9dbe2060be90] write_sysrq_trigger at ffffffffb8262888
#12 [ffff9dbe2060bea8] proc_reg_write at ffffffffb80b7f30
#13 [ffff9dbe2060bec8] vfs_write at ffffffffb80410a0
#14 [ffff9dbe2060bf08] sys_write at ffffffffb8041ebf
#15 [ffff9dbe2060bf50] system_call_fastpath at ffffffffb8574ddb
    RIP: 00007f8feee9aba0  RSP: 00007ffcde15a468  RFLAGS: 00000246
    RAX: 0000000000000001  RBX: 0000000000000002  RCX: ffffffffffffffff
    RDX: 0000000000000002  RSI: 00007f8fef7c6000  RDI: 0000000000000001
    RBP: 00007f8fef7c6000   R8: 000000000000000a   R9: 00007f8fef7ae740
    R10: 00007f8fef7ae740  R11: 0000000000000246  R12: 00007f8fef173400
    R13: 0000000000000002  R14: 0000000000000001  R15: 0000000000000000
    ORIG_RAX: 0000000000000001  CS: 0033  SS: 002b

其中第一行显示了进程的pid,task_struct结构体地址,进程所在CPU和运行进程的命令。

后面的栈帧列出了该进程在内核态的函数调用关系,执行顺序是从下往上。#15是最开始执行的系统调用,一般#0是切换到crashkernel的执行。重点关注#9这个位置,打印出很多寄存器的地址, 标准的信息是 exception RIP表示出问题时候执行的指令。

3.2 dis命令

dis命令可以用来输出反汇编结果。如显示10行崩溃点的反汇编代码。

crash> dis sysrq_handle_crash+22 10
0xffffffffb8261bf6 <sysrq_handle_crash+22>:     movb   $0x1,0x0
0xffffffffb8261bfe <sysrq_handle_crash+30>:     pop    %rbp
0xffffffffb8261bff <sysrq_handle_crash+31>:     retq
0xffffffffb8261c00 <sysrq_handle_loglevel>:     nopl   0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffffb8261c05 <sysrq_handle_loglevel+5>:   push   %rbp
0xffffffffb8261c06 <sysrq_handle_loglevel+6>:   xor    %eax,%eax
0xffffffffb8261c08 <sysrq_handle_loglevel+8>:   movl   $0x7,0x7e599e(%rip)        # 0xffffffffb8a475b0
0xffffffffb8261c12 <sysrq_handle_loglevel+18>:  mov    %rsp,%rbp
0xffffffffb8261c15 <sysrq_handle_loglevel+21>:  push   %rbx
0xffffffffb8261c16 <sysrq_handle_loglevel+22>:  lea    -0x30(%rdi),%ebx

其中 movb $0x1,0x0 表示把数字1赋值到地址0,地址0系统会判断为空指针,所以产生了panic,除此之外查看bt的打印,上面有write_sysrq_trigger函数,说明是我们手动echo c写sysrq-trigger触发的。

3.3 其他

使用help命令可以查看其他更多命令

crash> help

*              extend         log            rd             task
alias          files          mach           repeat         timer
ascii          foreach        mod            runq           tree
bpf            fuser          mount          search         union
bt             gdb            net            set            vm
btop           help           p              sig            vtop
dev            ipcs           ps             struct         waitq
dis            irq            pte            swap           whatis
eval           kmem           ptob           sym            wr
exit           list           ptov           sys            q

也可以使用help命令具体查看某一个子命令的帮助说明,如查看struct命令的帮助说明。

crash> help struct

NAME
  struct - structure contents

SYNOPSIS
  struct struct_name[.member[,member]][-o][-l offset][-rfuxdp]
         [address | symbol][:cpuspec] [count | -c count]

DESCRIPTION
  This command displays either a structure definition, or a formatted display
  of the contents of a structure at a specified address.  When no address is
  specified, the structure definition is shown along with the structure size.
  A structure member may be appended to the structure name in order to limit
  the scope of the data displayed to that particular member; when no address
  is specified, the member's offset and definition are shown.

    struct_name  name of a C-code structure used by the kernel.

参考文章:

  1. Centos7/RHEL7 开启kdump
  2. crash分析linux内核崩溃转储文件vmcore
  3. Linux内核:分析coredump文件 - 内核代码崩溃

你可能感兴趣的:(Linux,内核调试,linux)