内核调试之Kdump的原理及配置

术语介绍

生产内核(production kernel):产品或者线上服务器当前运行的内核。

捕获内核(capture kernel):系统崩溃时,使用kexec启动的内核,该内核用于捕获生产内核当前内存中的运行状态和数据信息。

Kdump简介

当系统崩溃时,kdump利用kexec启动第二个内核,这个内核驻留在宿主系统内存保留区中,而且宿主内核无法访问它。第二个内核会捕获到崩溃内核的内存上下文并保存到dump文件中(vmcore)。

Kdump工作原理

Kdump的核心实现基于Kexec(Kernel execution),kexec类似于Linux的exec系统调用。

Kexec可以快速启动一个新的内核(捕获内核),它会跳过BIOS或者Bootloader等引导程序的初始化阶段,这个特性可以让系统崩溃时快速切换到捕获内核,这样生产内核的内存就得到保留,Kdump的工作流程如下图所示:

捕获内核启动后,会像一般内核一样,去运行为它创建的ramdisk上的init程序。捕获内核ramdisk中的init脚本就可以通过通常的文件读写和网络来实现各种策略了。而各种转储机制就是在init中实现的。

为了在生产内核崩溃时能顺利启动捕获内核,捕获内核以及它的ramdisk是事先放到生产内核的内存中的(保留内存)。

安装Kdump

在rhel/centos7.x系统上,kdump服务默认已经安装并且启用了。

但是有些时候,比如自定义安装系统时,可能kdump就不一定被安装及启用。

可以查看系统是否已经安装:

[root@ecs-3370 ~]# rpm -q kexec-tools
kexec-tools-2.0.15-33.el7.x86_64

若没有安装,则可以执行命令安装

yum install kexec-tools

配置Kdump

配置预留内存

上文提到,要生成内核崩溃转储文件,需要预留内存空间给kdump服务,具体需要预留多大空间,主要有两方面因素:

  • 取决于系统硬件架构,可以使用uname -m命令查看。

  • 取决于系统总的内存大小。

在大多数系统中,kdump服务默认下会自动评估需要预留的内存大小,前提是系统总大小要满足一定条件。

上面那个页面点击进去之后,可看到:

默认自动分配了160M(根据我当前主存4GB来确定的),也可以勾选"Manul",然后手动修改预留给kdump服务的内存大小,不建议改太大,因为预留的这部分内存系统不能再使用了,意味着系统可用内存变小。

在centos7/RHEL7上,默认已经安装及配置了kdump服务,可以查看系统启动参数:

[root@ecs-3370 ~]# cat /proc/cmdline 
BOOT_IMAGE=/boot/vmlinuz-3.10.0-1062.el7.x86_64 root=UUID=fac7eb66-a4af-4ab4-9318-f66dc5c8dbe1 ro crashkernel=auto spectre_v2=retpoline rhgb quiet LANG=en_US.UTF-8 init 3

其中crashkernel=auto,说明系统自动分配预留给kdump内存大小。

修改系统启动参数中crashkernel参数,在/boot/grub2/grub.cfg文件中,找到menuentry中当前内核启动参数那行:

[root@ecs-3370 ~]# cat /boot/grub2/grub.cfg 
...
menuentry 'CentOS Linux (0-rescue-e0972351d26748d6941cfc55f8a027e4) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-e0972351d26748d6941cfc55f8a027e4-advanced-fac7eb66-a4af-4ab4-9318-f66dc5c8dbe1' {
    load_video
    insmod gzio
    insmod part_msdos
    insmod ext2
    set root='hd0,msdos2'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos2 --hint-efi=hd0,msdos2 --hint-baremetal=ahci0,msdos2 --hint='hd0,msdos2'  fac7eb66-a4af-4ab4-9318-f66dc5c8dbe1
    else
      search --no-floppy --fs-uuid --set=root fac7eb66-a4af-4ab4-9318-f66dc5c8dbe1
    fi
    linux16 /boot/vmlinuz-0-rescue-e0972351d26748d6941cfc55f8a027e4 root=UUID=fac7eb66-a4af-4ab4-9318-f66dc5c8dbe1 ro crashkernel=auto spectre_v2=retpoline rhgb quiet init 3
    initrd16 /boot/initramfs-0-rescue-e0972351d26748d6941cfc55f8a027e4.img
}
...

如果没有crashkernel参数,则在该行参数中加入:

crashkernel=160M

修改完后,重启系统会生效。

注:在rhel6.x 5.x上配置文件路径可能会有所不同,找到grub.conf文件修改即可。

配置vmcore产生路径

内核crash转储文件可以存储在本地磁盘上,也可以使用nfs或者ssh协议通过网络发送到其它地方。

/etc/kdump.conf配置文件可以配置很多选项,比如配置dump转储文件存放位置、是否压缩dump文件数据、当kdump失败后的行为等待。详细可以查看该文件注释:

移到最下面,可以看到默认配置:

#raw /dev/vg/lv_kdump
#ext4 /dev/vg/lv_kdump
#ext4 LABEL=/boot
#ext4 UUID=03138356-5e61-4ab3-b58e-27507ac41937
#nfs my.server.com:/export/tmp
#ssh user@my.server.com
#sshkey /root/.ssh/kdump_id_rsa
path /var/crash
core_collector makedumpfile -l --message-level 1 -d 31
#core_collector scp
#kdump_post /var/crash/scripts/kdump-post.sh
#kdump_pre /var/crash/scripts/kdump-pre.sh
#extra_bins /usr/bin/lftp
#extra_modules gfs2
#default shell
#force_rebuild 1
#force_no_rebuild 1
#dracut_args --omit-drivers "cfg80211 snd" --add-drivers "ext2 ext3"
#fence_kdump_args -p 7410 -f auto -c 0 -i 10
#fence_kdump_nodes node1 node2

可以看到,vmcore默认路径是在/var/path,可以修改该路径,之后重启kdump服务生效

[root@ecs-3370 ~]# systemctl restart kdump

测试kdump服务及配置是否真正生效

使用如下命令简单快速测试:

echo c > /proc/sysrq-trigger

如果Kdump配置正确,上述命令会让系统快速重启并且启动捕获内核进行转储,转储完成后会自动切换为生产内核,待系统重启完成后,登录系统,可以查看到 /var/crash目录下,已经有vmcore dump文件生成,vmcore-dmesg.txt文件可以查看到崩溃时系统日志信息:

[root@yglocal ~]# tree /var/crash/
/var/crash/
├── 127.0.0.1-2019-08-06-17:30:37
│   ├── vmcore
│   └── vmcore-dmesg.txt
├── 127.0.0.1-2020-03-20-14:59:51
│   ├── vmcore
│   └── vmcore-dmesg.txt
├── 127.0.0.1-2023-01-2-16:30:56
    ├── vmcore
    └── vmcore-dmesg.txt

什么是crash

Crash是一个用于分析内核转储文件的工具,和Kdump配套使用。Kdump会在内存中保留一块区域,这个区域用于存放捕获内核,生产内核运行过程中崩溃时,Kdump通过Kexec机制自动启动捕获内核,对生产内核的完整信息(CPU寄存器、栈帧数据等)进行保存,生产内核重启后,使用Crash工具来分析这个转储的文件。

Kdump测试

调试环境准备

使用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/上下载内核调试包

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

[root@ecs tmp]# ll /tmp/
-rw-r--r-- 1 root root 462533696 Oct 20  2020 kernel-debuginfo-3.10.0-1160.el7.x86_64.rpm
-rw-r--r-- 1 root root  65172668 Oct 20  2020 kernel-debuginfo-common-x86_64-3.10.0-1160.el7.x86_64.rpm

安装完成后,可以在安装的文件中找到vmlinux内核映像文件:

[root@ecs tmp]# rpm -ql kernel-debuginfo | grep vmlinux
/usr/lib/debug/lib/modules/3.10.0-1160.el7.x86_64/vmlinux

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

yum install crash

使用crash分析vmcore

分析vmcore文件,执行命令:

[root@ecs tmp]# crash /usr/lib/debug/lib/modules/3.10.0-1160.el7.x86_64/vmlinux /var/crash/127.0.0.1-2023-01-09-16\:16\:49/vmcore

crash 7.2.3-11.el7_9.1
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 [578MB]: patching 87292 gdb minimal_symbol values

      KERNEL: /usr/lib/debug/lib/modules/3.10.0-1160.el7.x86_64/vmlinux
    DUMPFILE: /var/crash/127.0.0.1-2023-01-09-16:16:49/vmcore  [PARTIAL DUMP]
        CPUS: 4
        DATE: Mon Jan  9 16:16:47 2023
      UPTIME: 32 days, 06:03:53
LOAD AVERAGE: 0.10, 0.05, 0.06
       TASKS: 132
    NODENAME: ecs
     RELEASE: 3.10.0-1160.el7.x86_64
     VERSION: #1 SMP Mon Oct 19 16:18:59 UTC 2020
     MACHINE: x86_64  (2200 Mhz)
      MEMORY: 16 GB
       PANIC: "SysRq : Trigger a crash"
         PID: 31407
     COMMAND: "bash"
        TASK: ffff961ff63cb180  [THREAD_INFO: ffff961ff3bbc000]
         CPU: 2
       STATE: TASK_RUNNING (SYSRQ)

crash> 

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

       PANIC: "SysRq : Trigger a crash"
         PID: 31407
     COMMAND: "bash"
        TASK: ffff961ff63cb180  [THREAD_INFO: ffff961ff3bbc000]
         CPU: 2
       STATE: TASK_RUNNING (SYSRQ)

crash常用命令

help命令

help命令用于在线查看crash命令的帮助,在crash命令行中输入help命令可以查看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              

crash version: 7.2.3-11.el7_9.1   gdb version: 7.6
For help on any command above, enter "help <command>".
For help on input options, enter "help input".
For help on output options, enter "help output".

help命令不仅可以查看crash支持的命令,还可以查看某个子命令的帮助说明,如查看bt命令的帮助说明。

crash> help bt

NAME
  bt - backtrace

SYNOPSIS
  bt [-a|-c cpu(s)|-g|-r|-t|-T|-l|-e|-E|-f|-F|-o|-O|-v] [-R ref] [-s [-x|d]]
     [-I ip] [-S sp] [pid | task]

DESCRIPTION
  Display a kernel stack backtrace.  If no arguments are given, the stack
  trace of the current context will be displayed.

       -a  displays the stack traces of the active task on each CPU.
           (only applicable to crash dumps)
       -A  same as -a, but also displays vector registers (S390X only).
   -c cpu  display the stack trace of the active task on one or more CPUs,
           which can be specified using the format "3", "1,8,9", "1-23",
           or "1,8,9-14". (only applicable to crash dumps)
       -g  displays the stack traces of all threads in the thread group of
           the target task; the thread group leader will be displayed first.
...

bt命令

bt命令查看一个进程的内核栈的函数调用关系,包括所有异常栈的信息,常用参数如下。

  • -f:显示每一栈帧里的数据。

  • -l:显示文件名和行号。

  • -t:显示栈中所有的文本符号。

  • pid:显示指定pid的进程的内核栈的函数调用信息。

crash> bt
PID: 31407  TASK: ffff961ff63cb180  CPU: 2   COMMAND: "bash"
 #0 [ffff961ff3bbfab0] machine_kexec at ffffffffa5266294
 #1 [ffff961ff3bbfb10] __crash_kexec at ffffffffa5322562
 #2 [ffff961ff3bbfbe0] crash_kexec at ffffffffa5322650
 #3 [ffff961ff3bbfbf8] oops_end at ffffffffa598b798
 #4 [ffff961ff3bbfc20] no_context at ffffffffa5275d14
 #5 [ffff961ff3bbfc70] __bad_area_nosemaphore at ffffffffa5275fe2
 #6 [ffff961ff3bbfcc0] bad_area_nosemaphore at ffffffffa5276104
 #7 [ffff961ff3bbfcd0] __do_page_fault at ffffffffa598e750
 #8 [ffff961ff3bbfd40] trace_do_page_fault at ffffffffa598ea26
 #9 [ffff961ff3bbfd80] do_async_page_fault at ffffffffa598dfa2
#10 [ffff961ff3bbfda0] async_page_fault at ffffffffa598a7a8
    [exception RIP: sysrq_handle_crash+22]
    RIP: ffffffffa5674856  RSP: ffff961ff3bbfe58  RFLAGS: 00010246
    RAX: ffffffffa5674840  RBX: ffffffffa5ee74a0  RCX: 0000000000000000
    RDX: 0000000000000000  RSI: ffff9622bfd138d8  RDI: 0000000000000063
    RBP: ffff961ff3bbfe58   R8: ffffffffa620487c   R9: ffff961ff3b88500
    R10: 00000000000003b9  R11: 00000000000003b8  R12: 0000000000000063
    R13: 0000000000000000  R14: 0000000000000004  R15: 0000000000000000
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
#11 [ffff961ff3bbfe60] __handle_sysrq at ffffffffa567507d
#12 [ffff961ff3bbfe90] write_sysrq_trigger at ffffffffa56754e8
#13 [ffff961ff3bbfea8] proc_reg_write at ffffffffa54c6d40
#14 [ffff961ff3bbfec8] vfs_write at ffffffffa544db50
#15 [ffff961ff3bbff08] sys_write at ffffffffa544e92f
#16 [ffff961ff3bbff50] system_call_fastpath at ffffffffa5993f92
    RIP: 00007f46827d1a00  RSP: 00007ffc54846a78  RFLAGS: 00000202
    RAX: 0000000000000001  RBX: 0000000000000002  RCX: 000000000149e260
    RDX: 0000000000000002  RSI: 00007f46830f6000  RDI: 0000000000000001
    RBP: 00007f46830f6000   R8: 000000000000000a   R9: 00007f46830f0740
    R10: 00007f46830f0740  R11: 0000000000000246  R12: 00007f4682aaa400
    R13: 0000000000000002  R14: 0000000000000001  R15: 0000000000000000
    ORIG_RAX: 0000000000000001  CS: 0033  SS: 002b
crash> 

上图可以看到,bt命令将系统崩溃瞬间正在运行的进程内核栈信息全部显示出来。当前进程的id是31407,task_struct数据结构的地址是0xffff961ff63cb180,当前进程运行在CPU2上,当前进程的运行命令是bash。后面的栈帧列出了该进程在内核态的调用关系,执行顺序是自下而上。

mod命令

mod命令不仅可以用来显示当前系统加载的内核模块信息,还可以用来加载某个内核模块的符号信息和调试信息等,常用参数如下。

  • -s:加载某个内核模块的符号信息。

  • -S:从某个指定目录加载所有内核模块的符号信息,默认目录是/lib/modules/<release>目录查找并加载内核模块的符号信息。

  • -d:删除某个内核模块的符号信息。

crash> mod
     MODULE       NAME                            SIZE  OBJECT FILE
ffffffffc03c2b00  floppy                         69432  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc03cc220  virtio_blk                     18323  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc03d41a0  virtio                         14959  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc03e02e0  virtio_console                 28076  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc03e54a0  pata_acpi                      13053  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc03ea640  ata_generic                    12923  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc03f00e0  virtio_ring                    22991  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc03fc120  virtio_pci                     22985  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0402040  net_failover                   18147  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0407080  mbcache                        14958  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0435440  libata                        243094  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0449040  failover                       13374  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0451360  virtio_net                     28085  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0459360  ip_tables                      27126  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0460180  serio_raw                      13434  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc0465000  crct10dif_common               12595  (not loaded)  [CONFIG_KALLSYMS]
ffffffffc046b1a0  crc32c_intel                   22094  (not loaded)  [CONFIG_KALLSYMS]
...

dis命令

dis命令用来输出反汇编结果,常用参数如下。

  • -l:显示反汇编和对应源代码的行号。

  • -r:(反向)显示从例程开始到指定地址(包括指定地址)的所有指令。

  • -s:显示对应的源代码。

如输出sysrq_handle_crash+22的反汇编结果。

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

crash> dis sysrq_handle_crash+22
0xffffffffa5674856 <sysrq_handle_crash+22>:     movb   $0x1,0x0

crash> dis -l sysrq_handle_crash+22
/usr/src/debug/kernel-3.10.0-1160.el7/linux-3.10.0-1160.el7.x86_64/drivers/tty/sysrq.c: 145
0xffffffffa5674856 <sysrq_handle_crash+22>:     movb   $0x1,0x0

crash> dis -l sysrq_handle_crash+22 10
/usr/src/debug/kernel-3.10.0-1160.el7/linux-3.10.0-1160.el7.x86_64/drivers/tty/sysrq.c: 145
0xffffffffa5674856 <sysrq_handle_crash+22>:     movb   $0x1,0x0
/usr/src/debug/kernel-3.10.0-1160.el7/linux-3.10.0-1160.el7.x86_64/drivers/tty/sysrq.c: 146
0xffffffffa567485e <sysrq_handle_crash+30>:     pop    %rbp
0xffffffffa567485f <sysrq_handle_crash+31>:     retq   
/usr/src/debug/kernel-3.10.0-1160.el7/linux-3.10.0-1160.el7.x86_64/drivers/tty/sysrq.c: 86
0xffffffffa5674860 <sysrq_handle_loglevel>:     nopl   0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffffa5674865 <sysrq_handle_loglevel+5>:   push   %rbp
/usr/src/debug/kernel-3.10.0-1160.el7/linux-3.10.0-1160.el7.x86_64/drivers/tty/sysrq.c: 91
0xffffffffa5674866 <sysrq_handle_loglevel+6>:   xor    %eax,%eax
/usr/src/debug/kernel-3.10.0-1160.el7/linux-3.10.0-1160.el7.x86_64/drivers/tty/sysrq.c: 90
0xffffffffa5674868 <sysrq_handle_loglevel+8>:   movl   $0x7,0x7d38fe(%rip)        # 0xffffffffa5e48170
/usr/src/debug/kernel-3.10.0-1160.el7/linux-3.10.0-1160.el7.x86_64/drivers/tty/sysrq.c: 86
0xffffffffa5674872 <sysrq_handle_loglevel+18>:  mov    %rsp,%rbp
0xffffffffa5674875 <sysrq_handle_loglevel+21>:  push   %rbx
/usr/src/debug/kernel-3.10.0-1160.el7/linux-3.10.0-1160.el7.x86_64/drivers/tty/sysrq.c: 89
0xffffffffa5674876 <sysrq_handle_loglevel+22>:  lea    -0x30(%rdi),%ebx
crash> 

这里能看出执行movb $0x1,0x0时系统崩溃。

rd命令

rd命令用来读取内存地址中的值,常用参数如下。

  • -a:显示ASCII。

  • -d:显示十进制。

  • -p:读取物理地址。

  • -s:显示符号。

  • -32:显示32位宽的值。

  • -64:显示64位宽的值。

struct命令

struct命令用于显示内核中数据结构的定义或者具体的值,常用的参数如下。

  • struct_name:数据结构的名称。

  • .member:数据结构的某个成员。

  • -o:显示成员在数据结构中的偏移量。

以下命令用于显示task_struct数据结构的定义。

irq命令

irq命令用于显示中断的相关信息,常用参数如下。

  • index:显示某个指定IRQ的信息。

  • -a:显示中断的亲和性。

  • -b:显示中断的下半部信息。

  • -s:显示系统中断信息。

vm命令

vm命令用于显示进程地址空间的相关信息,常用参数如下。

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

  • -m:显示mm_struct数据结构。

  • -v:显示进程中所有vma(vm_area_struct)数据结构的值。

  • -R:搜索特定字符串或者数值。

kmem命令

kmem命令用来显示系统内存信息,常用参数如下。

  • -g:显示page数据结构里flagsde标志位。

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

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

  • -s:显示slab使用情况。

  • -v:显示vmalloc使用情况。

  • -z:显示没个zone使用情况。

  • -V:显示系统vm_stat情况。

task命令

task命令用于显示进程的task_struct数据结构和thread_info数据结构的内容。以下命令用于显示task_struct数据结构信息,其中-x表示以十六进制显示。

sym命令

sym命令用于解析内核符号信息,常用选项如下所示。

  • -l:显示所有符号信息。

  • -m:显示某个内核模块的所有符号信息。

  • -q:查询符号信息。

list命令

list命令用来遍历链表,并且可以输出链表成员的值,常用的参数如下。

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

  • -s:用来输出链表成员的值。

写在最后

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

objdump -S -D my_test.ko > my_test.S

然后vim查看my_lkm.S文件,查看对应的源码

真实案例参考

主机 I/O 请求没有正常结束导致系统重启

https://blog.csdn.net/zyqash/article/details/130077361

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值