0. crash和kdump 死机问题解决-x86_64-基础知识

背景知识:

x86_64体系结构的通用寄存器

  • 32位x86的通用寄存器:8个通用寄存器

    • eax 一般用作累加器(add)

    • ebx 一般作为基地址寄存器(base)

    • ecx 一般作为计数寄存器(count)

    • edx 一般作为存放数据(data)

    • esp 一般作为栈指针寄存器(stack pointer)

    • ebp 一般作为基指针寄存器(base pointer)

    • esi   一般作为源变地址寄存器(source index)

    • edi  一般作为目标地址寄存器(destinatin index)

  • x86_64通用寄存器:

    • 扩展到16个: %rax, %rbx, %rcx, %rdx, %rdi, %rsi, %rsp, %rbp, %r8, %r9, %r10, %r11, %r12, %r13, %r14, %r15

    • 把原来的e开头变成r开头,原来通用的e开头寄存器依然可用,表示低32位

    • 16个寄存器:

      • %rax 作为函数返回值使用。

      • %rsp栈指针寄存器,指向栈顶

      • %rdi, %rsi, %rdx, %rcx, %r8, %r9用作函数参数,依次对应第1参数,第2个参数....

      • %rbx, %rbp, %r12, %r14, %r15用作通用寄存器,数据存储

      • %r10, %r11用作通用寄存器

    • %rbp是栈框指针

mov指令和lea指令的区别:

  • lea指令:load effective address。一般翻译为地址传送指令。

  • lea指令例子:leal -8(%ebp), %eax

    • 取出ebp寄存器的值并减去8赋值给eax寄存器,ebp-8 -> eax

    • 不进行间接寻址,直接传送地址

  • movl -8(%ebp), %eax

    • 取出ebp的值减去8,然后再读取(ebp-8)所指向内存的内容,赋给eax,

    • 进行了间接寻址取出变量值(内容),[ebp - 8] -> eax

栈结构

  

  • 函数的调用与栈有着密切的关系,程序的执行通常是一个函数嵌套着下一个函数,无论嵌套有多深,程序总是能正确的返回到原点,这个就要依赖于栈的结构、rsp栈指针寄存器以及rbp栈基地址寄存器

  • 假设函数调用关系如下:main()->func1()->func2()

  • pop和push指令

    • push 首先将rsp值减8,然后在将操作数内容压入rsp所指向的位置。

    • pop   首先将rsp所指示的地址中的内容出栈,然后将rsp的值加8

例子:stack.c

unsigned long func2(unsigned long f2)
{
    unsigned long i2 = 2;
    f2 += i2;
    return f2;
}

unsigned long func1(unsigned long f1)
{
    unsigned long i1 = 1;
    f1+=i1;
    f1 = func2(f1);
    return f1;
}

int main()
{
    unsigned long m = func1(0);
    return m;
}
gcc stack.c 
objdump -S a.out > stack.S
stack.S
00000000004004d6 <func2>:
  4004d6: 55                    push   %rbp
  4004d7: 48 89 e5              mov    %rsp,%rbp
  4004da: 48 89 7d e8           mov    %rdi,-0x18(%rbp)
  4004de: 48 c7 45 f8 02 00 00  movq   $0x2,-0x8(%rbp)
  4004e5: 00 
  4004e6: 48 8b 45 f8           mov    -0x8(%rbp),%rax
  4004ea: 48 01 45 e8           add    %rax,-0x18(%rbp)
  4004ee: 48 8b 45 e8           mov    -0x18(%rbp),%rax
  4004f2: 5d                    pop    %rbp
  4004f3: c3                    retq   

00000000004004f4 <func1>:
  4004f4: 55                    push   %rbp
  4004f5: 48 89 e5              mov    %rsp,%rbp
  4004f8: 48 83 ec 18           sub    $0x18,%rsp
  4004fc: 48 89 7d e8           mov    %rdi,-0x18(%rbp)
  400500: 48 c7 45 f8 01 00 00  movq   $0x1,-0x8(%rbp)
  400507: 00 
  400508: 48 8b 45 f8           mov    -0x8(%rbp),%rax
  40050c: 48 01 45 e8           add    %rax,-0x18(%rbp)
  400510: 48 8b 45 e8           mov    -0x18(%rbp),%rax
  400514: 48 89 c7              mov    %rax,%rdi
  400517: e8 ba ff ff ff        callq  4004d6 <func2>
  40051c: 48 89 45 e8           mov    %rax,-0x18(%rbp)
  400520: 48 8b 45 e8           mov    -0x18(%rbp),%rax
  400524: c9                    leaveq 
  400525: c3                    retq   

0000000000400526 <main>:
  400526: 55                    push   %rbp
  400527: 48 89 e5              mov    %rsp,%rbp
  40052a: 48 83 ec 10           sub    $0x10,%rsp
  40052e: bf 00 00 00 00        mov    $0x0,%edi
  400533: e8 bc ff ff ff        callq  4004f4 <func1>
  400538: 48 89 45 f8           mov    %rax,-0x8(%rbp)
  40053c: 48 8b 45 f8           mov    -0x8(%rbp),%rax
  400540: c9                    leaveq 
  400541: c3                    retq   
  400542: 66 2e 0f 1f 84 00 00  nopw   %cs:0x0(%rax,%rax,1)
  400549: 00 00 00 
  40054c: 0f 1f 40 00           nopl   0x0(%rax)

假如栈开始的地址为0x1000

如何触发dump

kdump通常用于系统假死机(unresposive)和panic,也就是没有响应的情况。硬件问题导致的直接死机,kdump无能为力。

kdump触发条件有哪些?

1.手动触发

SysRq               echo c > /proc/sysrq-trigger
NMI via IPMI                ipmitool power diag
NMI via virsh                virsh inject-nmi  MyGuestName
Beware of                    Kernel.unkown_nmi_panic=1

2.自动触发

Watchdog            Boot cmdline: nmi_watchdog=1
Softlockup          sysctl kernel.softlockup_panic=1
Out of Memory       sysctl vm.panic_on_oom=1

实验0:安装kdump和crash

1.工具安装

yum install kernel-debuginfo kexec-tools crash

2.设置crashkernel预留内存大小,修改/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="rd.lvm.lv=cl/root rd.lvm.lv=cl/swap crashkernel=400M"
GRUB_DISABLE_RECOVERY="true"

3.需要重新生成grub配置文件,重启系统才能生效

grub2-mkconfig -o /boot/grub2/grub.cfg
reboot

4.开启kdump服务

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

5.检查kdump服务时否开启?

# 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 Fri 2021-06-18 04:44:54 EDT; 45min ago
Main PID: 991 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/kdump.service


Jun 18 04:44:54 localhost.localdomain dracut[2984]: drwxr-xr-x   2 root     root            0 Jun 18 04:44 usr/share/zoneinfo/America
Jun 18 04:44:54 localhost.localdomain dracut[2984]: -rw-r--r--   1 root     root         3519 Mar 27  2017 usr/share/zoneinfo/America/New_York
Jun 18 04:44:54 localhost.localdomain dracut[2984]: drwxr-xr-x   2 root     root            0 Jun 18 04:44 var
Jun 18 04:44:54 localhost.localdomain dracut[2984]: lrwxrwxrwx   1 root     root           11 Jun 18 04:44 var/lock -> ../run/lock
Jun 18 04:44:54 localhost.localdomain dracut[2984]: lrwxrwxrwx   1 root     root            6 Jun 18 04:44 var/run -> ../run
Jun 18 04:44:54 localhost.localdomain dracut[2984]: ========================================================================
Jun 18 04:44:54 localhost.localdomain dracut[2984]: *** Creating initramfs image file '/boot/initramfs-3.10.0-957.1.3.el7.x86_64kdump.img' done ***
Jun 18 04:44:54 localhost.localdomain kdumpctl[991]: kexec: loaded kdump kernel
Jun 18 04:44:54 localhost.localdomain kdumpctl[991]: Starting kdump: [OK]
Jun 18 04:44:54 localhost.localdomain systemd[1]: Started Crash recovery kernel arming.

6.手动触发一下crash dump

echo 1 >/proc/sys/kernel/sysrq; echo c > /proc/sysrq-trigger

系统会自动重启,重启后可以看到在/var/crash/目录下生成了coredump文件

打开crash来分析:

# crash vmcore /usr/lib/debug/lib/modules/3.10.0-957.1.3.el7.x86_64/vmlinux


crash 7.2.3-8.el7
Copyright (C) 2002-2017  Red Hat, Inc.
Copyright (C) 2004, 2005, 2006, 2010  IBM Corporation
Copyright (C) 1999-2006  Hewlett-Packard Co
Copyright (C) 2005, 2006, 2011, 2012  Fujitsu Limited
Copyright (C) 2006, 2007  VA Linux Systems Japan K.K.
Copyright (C) 2005, 2011  NEC Corporation
Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc.
This program is free software, covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of it under
certain conditions.  Enter "help copying" to see the conditions.
This program has absolutely no warranty.  Enter "help warranty" for details.
GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu"...


WARNING: kernel relocated [126MB]: patching 85619 gdb minimal_symbol values


      KERNEL: /usr/lib/debug/lib/modules/3.10.0-957.1.3.el7.x86_64/vmlinux
    DUMPFILE: vmcore  [PARTIAL DUMP]
        CPUS: 4
        DATE: Fri Jun 18 05:32:32 2021
      UPTIME: 00:47:57
LOAD AVERAGE: 0.00, 0.01, 0.05
       TASKS: 413
    NODENAME: localhost.localdomain
     RELEASE: 3.10.0-957.1.3.el7.x86_64
     VERSION: #1 SMP Thu Nov 29 14:49:43 UTC 2018
     MACHINE: x86_64  (3799 Mhz)
      MEMORY: 2 GB
       PANIC: "SysRq : Trigger a crash"
         PID: 12653
     COMMAND: "bash"
        TASK: ffffa1071aca8000  [THREAD_INFO: ffffa1074b32c000]
         CPU: 3
       STATE: TASK_RUNNING (SYSRQ)


crash>

crash支持的命令:

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 cmd
  • bt命令:输出内核栈的backtrace

    • -t 显示符号信息

    • -f 显示栈的所有数据

    • -l 显示文件名和行号

    • pid 可以显示指定pid进程的backtrace

  • dis 显示反汇编

    • -l 显示反汇编以及源代码

    • -s 显示该函数的文件名和源代码

  • mod 加载模块符号表

    • -s 加载模块符号表

    • -d 删除某个模块符号表

    • -S 加载某个目录的模块符号表

  • sym 用来解析符号(symbol)

    • -l 显示所有的符号,等用于System.map

    • -m modules: 显示指定模块里的符号

    • -q string: 查找符号

  • rd 读内存

    • -p 读物理地址

    • -u 读用户虚拟地址

    • -d 显示10进制

    • -s 显示符号

    • -32 显示32位宽的值

    • -64 显示64位宽的值

    • -a 显示ASCII码

  • struct 显示数据结构的定义以及实际的值

    • struct_name: 显示内核中定义的数据结构

    • .member 显示数据结构中某个成员

    • struct_name address: 显示该数据结构在该地址的值

    • -o: 显示每个成员在数据结构中的偏移(十进制)

  • p命令:用来打印一个表达式或符号的值

    • symbol: 打印一个内核的符号的值,通常是expose出来的全局变量等。

    • symbol:n :打印某个cpu上pre-cpu变量的值

  • task: 进程的task_struct和thread_info数据结构的值

  •  runq命令:显示每个CPU的就绪队列的信息

    • -t: 显示就绪队列中的时间戳

    • -m: 显示当前进程运行的时间

  • vm命令:显示指定进程的相关内存的信息

    • -p: 显示虚拟地址和物理地址

    • -m: 显示mm_struct数据结构的值

    • -v: dump该进程所有vm_area_struct数据结构的值

    • -f 1234:数字1234在vm_flags的对应比特位

  • kmem命令:现在系统内存信息

    • -i: 显示系统内存使用的情况

    • -v: 显示系统vmalloc使用情况

    • -V: 显示系统vm_start情况

    • -z: 显示每个zone的情况

    • -s: 显示slab情况

    • -p: 显示每个页面的情况

    • -g: 显示struct page里面flag的比特位

  • list命令:用来遍历链表,并且打印链表中的成员的值

    • -h: 指定链表头list_head的地址

    • -s: 用来打印链表成员的值

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byd yes

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值