【内核崩溃kdump(sysdump)和crash分析】

内核崩溃kdump(sysdump)和crash分析

系统一旦崩溃,内核就没法正常工作了,这个时候需要触发一种转存储机制(kernel中的kdump, unisoc的sysdump)。转存机制提供一个用于捕获当前运行现场的内核,该内核会将此时内存中的所有运行状态和数据信息收集到一个dump core文件中以便之后分析崩溃原因。

在系统发生诸如Kernel crash等异常时,在Kernel中完成flush cache等处理后,重启进入dump内核收集和保存现场数据。

crash, 是某个特定时刻(如kernel panic)的系统RAM的快照,需要转存的现场数据。

约束条件:

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

1.kdump

kdump是kernel原生的一个系统奔溃时的现场转存工具。kdump是RHEL5之后才支持的,2006被主线接收为内核的一部分。它的原理简单来说是在内存中保留一块区域,这块区域用来存放capture kernel,当production kernel发生crash的时候,通过kexec把保留区域的capure kernel给运行起来,再由捕获内核负责把产品内核的完整信息,包括CPU寄存器、堆栈数据等转储到指定位置的文件中。

(1) kdump运行原理介绍

kdump实现了"双内核"布局,Kdump 在内核在内核panic后,立即调用kexec 引导到转储捕获内核(capture kernel),使用 kexec 引导 “覆盖” 当前运行的内核。

该“转储捕获内核”的内存区域由主内核的bootargs参数 crashkernel 或dts指定。“转储捕获内核”可以是专门build的单独 Linux 内核image,也可以在支持可重定位内核的系统架构上重用主内核映像。

kexec(kernel execution,类似于 Unix 或 Linux 的系统调用 exec)是 Linux 内核的一种机制,其允许从当前运行的内核启动新内核。kexec 会跳过由系统固件(BIOS或UEFI、bootloader)执行的引导加载程序阶段和硬件初始化阶段,直接将新内核加载到主内存并立即开始执行。这避免了完全重新启动的漫长时间,并且可以通过最小化停机时间来满足系统高可用性要求。

注意: 不经过bootloader或bios阶段,直接从主kernel启动到“转储捕获内核”进行。

图 1-1 Kdump 原理架构图

(2) dump触发方式

1.手动触发

  • 通过sysrq触发

    echo c /proc/sysrq-trigger

  • 通过IPMI触发不可屏蔽中断

    ipomitool power diag

  • 通过virsh触发不可屏蔽中断

    virsh inject-nmi MyGuestName

  • Beware of

    kernel.unkonow_nmi_panic=1

2.自动触发

  • watchdong(看门狗)

    cmdline中:nmi_watchdog=1

  • softlockup(软锁)

    sysctl kernel.softlockup_panic=1

  • 内存越界

    sysctl vm.panic_on_oom=1

3.自动触发kdump的条件

2.sysdump

SysDump即Dump system memory,是sysdump的一种转存储机制,是将发生异常时的内存信息、寄存器信息等有效信息转存为文件,以便于借助分析工具分析问题现场。

在系统发生诸如Kernel crash等异常时,在Kernel中完成flush cache等处理后,重启进入Uboot(或LK等bootloader阶段)中完成所有数据的保存,保存过程会有相应屏幕提示,完成后根据屏幕提示重启手机,导出异常数据文件进行分析。

SysDump分为FullDump和MiniDump两个子功能,两个子功能是互不影响的。

  • FullDump保存完整DDR信息,可以支持两种存储路径Dump2SD和Dump2PC。Dump2SD功能依赖于SD卡,即设备需支持插入SD卡。
  • MiniDump保存少量信息到单独的SysDumpdb分区,然后再由native sevice 程序将分区保存的raw数据整理解析后放置到/sdcard/MiniDump路径下。

MiniDump功能仅Android系统的设备支持。

在资源允许的条件下,优先选择保存分析FullDump日志,因为其保存了完整的现场信息快照,更有利于深入分析问题。

(1) sysdump运行原理介绍

2.sysdump运行原理介绍
系统异常和组合键主动触发系统异常都会走到Kernel的处理流程,但长按7s(秒)的操作不会进入Kernel处理流程。

  • MiniDump在Kernel阶段完成初始化和异常处理时的数据保存。
  • Uboot中完成数据的存储操作,包括FullDump 和MiniDump。
(2) dump触发方式

硬件配置不同,SysDump触发方式也有所差异,具体如下。

4.sysdump的触发方式

3.转存文件的解析—crash工具

前面提到,当系统崩溃时,通过kdump或sysdump可以获得当时的内存转储文件vmcore,但是该如何分析vmcore呢?

crash是一个用于分析内核转储文件的工具,一般和kdump搭配使用,sysdump也可以使用该工具解析。

使用crash时,要求调试内核vmlinux在编译时带有-g选项,即带有调试信息。如果没有指定vmcore,则默认使用实时系统的内存来分析。

值得一提的是,crash也可以用来分析实时的系统内存,是一个很强大的调试工具。crash使用gdb作为内部引擎,语法类似于gdb,命令的使用说明可以用 help来查看。

(1) crash工具的依赖

使用crash需要安装crash工具包和内核调试信息包:

crash
kernel-debuginfo-common
kernel-debuginfo

对于在PC上调试arm平台的异常现场,使用专用的crash工具,不需要安装,直接运行。
工具获取路径:
在这里插入图片描述
工具说明:
 crash_arm:用于32bit ARM 平台
 crash_arm64:用于64bit ARM 平台

(2) crash工具的使用

使用crash来调试vmcore,至少需要两个参数:

  • 未压缩的内核映像文件vmlinux。ubuntu默认位于/usr/lib/debug/lib/modules/$(uname -r)/vmlinux,由内核调试信息包提供。
  • 内存转储文件vmcore,由kdump或sysdump转存的内核奔溃现场快照。

对于ARM平台来说,除上述参数之外,一般还需要指定如下参数:

  • phys_offset: RAM的起始物理地址
  • vabits_actual: 实际的虚拟地址空间大小(总线位宽)
  • kimage_voffset: kernel image映射的物理地址偏移

以unisoc ARM64平台为例,crash执行命令:

./crash_arm64 -m vabits_actual=39 -m phys_offset=0x80000000 -m kimage_voffset=0xffffffbf90000000 ./vmlinux ./vmcore

(3) crash基本输出分析

crash基本输出:

~/crash$ ./crash_arm64_v8 -m vabits_actual=39 -m phys_offset=0x80000000 -m kimage_voffset=0xffffffbf90000000 ./vmlinux ./syscore

crash_arm64_v8 8.0.0++
Copyright (C) 2002-2021  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, 2020-2021  NEC Corporation
Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc.
Copyright (C) 2015, 2021  VMware, 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.

NOTE: setting vabits_actual to: 39

NOTE: setting phys_offset to: 0x80000000

NOTE: setting kimage_voffset to: 0xffffffbf90000000

GNU gdb (GDB) 10.2
Copyright (C) 2021 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 "--host=x86_64-pc-linux-gnu --target=aarch64-elf-linux".
Type "show configuration" for configuration details.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...

WARNING: cpu 0: cannot find NT_PRSTATUS note
      KERNEL: ./vmlinux  [TAINTED]
    DUMPFILE: ./syscore
        CPUS: 8 [OFFLINE: 7]
        DATE: Wed Sep 14 16:38:14 CST 2022
      UPTIME: 01:48:53
LOAD AVERAGE: 10.46, 10.99, 10.55
       TASKS: 1564
    NODENAME: localhost
     RELEASE: 5.4.190-android12-9-02871-g77dc16611297
     VERSION: #1 SMP PREEMPT Wed Sep 14 10:55:40 CST 2022
     MACHINE: aarch64  (unknown Mhz)
      MEMORY: 3 GB
       PANIC: "Kernel panic - not syncing: sysrq triggered crash"
         PID: -1
     COMMAND: "bash"
        TASK: ffffff801e604b00  (1 of 32)  [THREAD_INFO: ffffff801e604b00]
         CPU: -1
       STATE: TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE|TASK_STOPPED|TASK_TRACED|EXIT_DEAD|TASK_DEAD|EXIT_ZOMBIE|TASK_WAKING|TASK_WAKEKILL|TASK_NOLOAD|TASK_NEW

crash_arm64_v8>

这些基本输出信息简单明了,可由sys命令触发。

其中各项参数的意义为:

  1. KERNEL表示调试用内核的位置和版本信息
  2. DUMPFILE: 表示所分析的内存转储镜像
  3. CPUS: 表示本机的 CPU 数目
  4. DATE: 表示内核崩溃发生的时间
  5. UPTIME: 表示内核已正常运行的时间
  6. LOAD AVERAGE: 表示内核崩溃时系统的负载
  7. TASKS: 表示内核崩溃时系统运行的任务数
  8. NODENAME: 表示内核崩溃的机器的主机名
  9. RELEASE: 表示内核的发布版本
  10. VERSION: 表示内核的其他版本信息
  11. MACHINE: 表示 CPU 的架构和主频信息
  12. MEMORY: 表示发生内核崩溃的系统的内存大小
  13. PANIC: 表示内核崩溃的类型
  14. PID: 表示导致内核崩溃的进程号;
  15. COMMAND: 表示导致内核崩溃的进程名称
  16. TASK: 表示导致内核崩溃的进程访问的内存地址;
  17. CPU: 表示导致内核崩溃的进程占用的 CPU 数目;
  18. STATE: 表示导致内核崩溃的进程的运行状态。

需要重点关注的是 13. PANIC,它告诉我们内核奔溃的原因。一般有如下类型:

  • SysRq。即通过系统请求造成的内核崩溃,如上面测试用的命令。
  • Oops。表示内核发生了不可预期的或不正确的行为,这时会杀死相应的进程,内核可能恢复正常,也可能处于一种不确定的状态,并进而导致内核的 Panic。
  • Panic。 内核崩溃,即发生了严重且不可修复的错误, 如发生了非法的地址访问, 强制加载或卸载内核模块,以及硬件错误等等。

以上信息可用于初步分析内核崩溃的原因,内核态有三种出错情况,分别是 bug, oops和 panic。 bug 属于轻微错误, oops 代表某一用户进程出现错误,需要杀死用户进程。这时如果用户进程占用了某些信号锁,这些信号锁将永远不会得到释放,这会导致系统潜在的不稳定性。 panic 是严重错误,代表整个系统崩溃。 深入的分析需要使用更多的命令进行追踪和查找。

(4) crash常用命令

查看某个命令的详细介绍:help xxx

crash_arm64_v8> help

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

crash_arm64_v8 version: 8.0.0++   gdb version: 10.2
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".

crash_arm64_v8> help xxx

1.bt命令
打印函数调用栈,displays a task’s kernel-stack backtrace 。

  • -t: 显示符号信息
  • -f: 显示栈的所有数据
  • -l: 显示文件名和行号
  • pid: 可以显示指定pid进程的backtrace
crash_arm64_v8> ps |grep UN
    161      2   4  ffffff80b62a9e00  UN   0.0       0      0  [sprd-rotation/6]
    162      2   4  ffffff80b62abc00  UN   0.0       0      0  [sprd-rotation/7]
    228      2   0  ffffff80b52be900  UN   0.0       0      0  [slog-0-0]
    730      2   0  ffffff8088c58000  UN   0.0       0      0  [RX_THREAD]
    731      2   0  ffffff8088c58f00  UN   0.0       0      0  [RX_NET_QUEUE]
    732      2   6  ffffff8088c5cb00  UN   0.0       0      0  [SPRDWL_TX_THREA]
    847      2   6  ffffff80795bbc00  UN   0.0       0      0  [WCN_SIPC_TX_THR]
    848      2   1  ffffff80795bda00  UN   0.0       0      0  [WCN_SIPC_TX_THR]
    849      2   1  ffffff80795bad00  UN   0.0       0      0  [WCN_SIPC_TX_THR]
    937      2   1  ffffff80795be900  UN   0.0       0      0  [native_hang_det]
crash_arm64_v8> bt 937
PID: 937    TASK: ffffff80795be900  CPU: 1   COMMAND: "native_hang_det"
 #0 [ffffffc01765bc00] __switch_to at ffffffc0101022f4
 #1 [ffffffc01765bc70] __schedule at ffffffc0115f7dc0
 #2 [ffffffc01765bd00] schedule at ffffffc0115f8a3c
 #3 [ffffffc01765bdb0] schedule_timeout at ffffffc0115fe91c
 #4 [ffffffc01765be20] hang_detect_thread at ffffffc0109f86dc
 #5 [ffffffc01765be80] kthread at ffffffc0101d8e30
crash_arm64_v8>

2.dis命令

显示反汇编。dis可以反汇编指定的地址,或者反汇编指定的函数名。

  • 反汇编指定的函数
crash_arm64_v8> dis hang_detect_thread
0xffffffc0109f85ac <hang_detect_thread>:        sub     sp, sp, #0xa0
0xffffffc0109f85b0 <hang_detect_thread+4>:      str     x30, [x18], #8
0xffffffc0109f85b4 <hang_detect_thread+8>:      stp     x29, x30, [sp, #64]
...
0xffffffc0109f85cc <hang_detect_thread+32>:     add     x29, sp, #0x40
0xffffffc0109f85d0 <hang_detect_thread+36>:     adrp    x8, 0xffffffc011e83000 <vsock_dgram_ops+144>
0xffffffc0109f85d4 <hang_detect_thread+40>:     ldr     x8, [x8, #1672]
  • 反汇编指定的地址
crash_arm64_v8> dis 0xffffffc0109f8610
0xffffffc0109f8610 <hang_detect_thread+100>:    mov     w3, #0x1                        // #1
crash_arm64_v8> dis 0xffffffc0109f8610 6
0xffffffc0109f8610 <hang_detect_thread+100>:    mov     w3, #0x1                        // #1
0xffffffc0109f8614 <hang_detect_thread+104>:    mov     x0, x19
0xffffffc0109f8618 <hang_detect_thread+108>:    stp     w8, w9, [sp, #16]
0xffffffc0109f861c <hang_detect_thread+112>:    bl      0xffffffc0101ec1dc <__sched_setscheduler>
0xffffffc0109f8620 <hang_detect_thread+116>:    adrp    x0, 0xffffffc0125bb000 <static_ltree+24>
0xffffffc0109f8624 <hang_detect_thread+120>:    add     x0, x0, #0xe58

  • -l 参数:显示反汇编和源码
crash_arm64_v8> dis -l hang_detect_thread
/home/bryan.he/sprdroid12_trunk_22b_ump518_bringup/bsp/kernel/kernel5.4/drivers/soc/sprd/debug/sysdump/native_hang_monitor.c: 599
0xffffffc0109f85ac <hang_detect_thread>:        sub     sp, sp, #0xa0
0xffffffc0109f85b0 <hang_detect_thread+4>:      str     x30, [x18], #8
....
0xffffffc0109f85cc <hang_detect_thread+32>:     add     x29, sp, #0x40
0xffffffc0109f85d0 <hang_detect_thread+36>:     adrp    x8, 0xffffffc011e83000 <vsock_dgram_ops+144>
...
0xffffffc0109f85dc <hang_detect_thread+48>:     nop
0xffffffc0109f85e0 <hang_detect_thread+52>:     mov     w8, #0x1                        // #1
/home/bryan.he/sprdroid12_trunk_22b_ump518_bringup/bsp/kernel/kernel5.4/kernel/sched/core.c: 5428
0xffffffc0109f85e4 <hang_detect_thread+56>:     stp     xzr, xzr, [sp, #40]
...
  • -s参数:显示该函数的文件名和源代码
crash_arm64_v8> dis -s hang_detect_thread
FILE: /home/bryan.he/sprdroid12_trunk_22b_ump518_bringup/bsp/kernel/kernel5.4/drivers/soc/sprd/debug/sysdump/native_hang_monitor.c
LINE: 599

dis: hang_detect_thread: source code is not available

反汇编的其他用法:

crash_arm64_v8> dis ffffffffa021ba91 // 反汇编一条指令
crash_arm64_v8> dis -l probe_2093+497 10 // 反汇编从某个地址开始的10条指令

3.mod命令

加载模块符号表。

  • -s: 加载模块符号表
  • -d: 删除某个模块符号表
  • -S: 加载某个目录的模块符号表
# mod // 查看模块
# mod -s module /path/to/module.ko // 加载模块
# sym symbol // 显示符号对应的模块源码,也可以用virtual address

在这里插入图片描述
在这里插入图片描述

4.sym命令

用来解析符号。

  • -l: 显示所有的符号,等于用System.map。
crash_arm64_v8> sym -l
ffffffc010080000 (t) __efistub__text
ffffffc010080000 (t) _head
ffffffc010080000 (T) _text
ffffffc010080040 (t) pe_header
ffffffc010080044 (t) coff_header
ffffffc010080058 (t) optional_header
ffffffc010080070 (t) extra_header_fields
ffffffc0100800f8 (t) section_table
ffffffc010081000 (T) __exception_text_start
ffffffc010081000 (T) _stext
  • -m module: 显示指定模块里的符号
crash_arm64_v8> sym -m rpmb
ffffffc0096b3000 MODULE START: rpmb
ffffffc0096b4000 (T) __cfi_check
ffffffc0096b4368 (") __cfi_check_fail
ffffffc0096b43a8 (T) rpmb_dev_unregister
ffffffc0096b446c (t) match_by_parent
ffffffc0096b44b0 (t) rpmb_dev_release
ffffffc0096b44f4 (T) rpmb_dev_register
ffffffc0096b46b0 (t) id_read
ffffffc0096b4750 (t) reliable_wr_cnt_show
ffffffc0096b4798 (t) type_show
ffffffc0096b4840 (T) rpmb_dev_put
ffffffc0096b4870 (T) rpmb_dev_get_by_type
ffffffc0096b4904 (t) match_by_type
ffffffc0096b4950 (T) rpmb_dev_get
ffffffc0096b4988 (T) rpmb_dev_find_device
ffffffc0096b49d8 (T) rpmb_dev_find_by_device
ffffffc0096b4a34 (T) rpmb_cmd_seq
ffffffc0096b4b5c (T) rpmb_cmd_req
  • -q string: 查找符号
crash_arm64_v8> sym -q rpmb_ioctl
ffffffc010eb2134 (t) mmc_rpmb_ioctl
ffffffc010eb21b8 (t) mmc_rpmb_ioctl_compat
ffffffc0096b4f60 (t) rpmb_ioctl [rpmb]

方括号,[rpmb]告诉了该符号是属于模块rpmb的,左边是符号地址。

5.rd命令

读内存命令。

  • -p: 读物理地址
crash_arm64_v8> rd -p  0x80008000 20
        80008000:  0000000000009000 0000000000000000   ................
        80008010:  0000000000000000 0000000000007448   ........Ht......
        80008020:  0000000000007480 0000000000000000   .t..............
        80008030:  0000000000000000 00000000000074c4   .........t......
        80008040:  000000000000754c 0000000000000000   Lu..............
        80008050:  0000000000000000 000000000000733c   ........<s......
        80008060:  0000000000007424 0000000000000000   $t..............
        80008070:  0000000000000000 0000000000000000   ................
        80008080:  0000000000000000 0000000000007630   ........0v......
        80008090:  00000000000075dc 00000000000075e0   .u.......u......

  • -u: 读用户虚拟地址
crash_arm64_v8> rd -u 0000007c6d862fa8
rd: invalid kernel virtual address: 3f  type: "user pgd"
crash_arm64_v8> rd -u swapper
symbol not found: swapper
possible alternatives:
  ffffffc01012b6e8 (T) set_swapper_pgd
  ffffffc01242bba0 (b) swapper_pgdir_lock
crash_arm64_v8> rd -u swapper_spaces
rd: invalid user virtual address: ffffffc01227a9f0  type: "64-bit UVADDR"

神马情况??? 指定的地址不对?

  • -d:显示十进制,-x显示十六进制。
crash_arm64_v8> rd -d ffffffc01012b6e8
ffffffc01012b6e8:  -6215394105006979490
crash_arm64_v8> rd -x ffffffc01012b6e8
ffffffc01012b6e8:  a9be7bfdf800865e
  • -s: 显示符号
crash_arm64_v8> rd -s ffffffc01012b6e8
ffffffc01012b6e8:  __efistub_$d.9+-6215394105006979767
  • -32:显示32位宽的值
crash_arm64_v8> rd -32 ffffffc01012b6e8
ffffffc01012b6e8:  f800865e                              ^...
  • -64: 显示64位宽的值
crash_arm64_v8> rd -64 ffffffc01012b6e8
ffffffc01012b6e8:  a9be7bfdf800865e                    ^....{..

  • -a: 显示ASCII码
crash_arm64_v8> rd -a ffffffc01012b6e8
ffffffc01012b6e8:  ^
crash_arm64_v8> rd -a ffffffc01012b6e8 10
ffffffc01012b6e8:  ^
ffffffc01012b6ed:  {
ffffffc01012b6f1:  O

6.struct命令

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

  • 指定struct name: 显示内核中定义的数据结构。
crash_arm64_v8> struct vm_area_struct
struct vm_area_struct {
    unsigned long vm_start;
    unsigned long vm_end;
    struct vm_area_struct *vm_next;
    struct vm_area_struct *vm_prev;
    struct rb_node vm_rb;
    unsigned long rb_subtree_gap;
    struct mm_struct *vm_mm;
    pgprot_t vm_page_prot;
    unsigned long vm_flags;
    union {
        struct {...} shared;
        const char *anon_name;
    };
    struct list_head anon_vma_chain;
    struct anon_vma *anon_vma;
    const struct vm_operations_struct *vm_ops;
    unsigned long vm_pgoff;
    struct file *vm_file;
    void *vm_private_data;
    atomic_long_t swap_readahead_info;
    struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
    u64 android_kabi_reserved1;
    u64 android_kabi_reserved2;
    u64 android_kabi_reserved3;
    u64 android_kabi_reserved4;
    u64 android_vendor_data1;
}
SIZE: 232
  • 指定.member: 显示结构体中的某个成员。
crash_arm64_v8> struct vm_area_struct.vm_mm
struct vm_area_struct {
   [64] struct mm_struct *vm_mm;
}


  • 同时指定struct name和address地址:显示该数据结构在该地址的值。
crash_arm64_v8> struct -x vm_area_struct ffffffc0116150fc
struct vm_area_struct {
  vm_start = 0x17bd992417b92167,
  vm_end = 0x17ac55b317bda103,
  vm_next = 0x17ac8b1517ac8afc,
  vm_prev = 0x17b74cb617b745eb,
  vm_rb = {
    __rb_parent_color = 0x17b760eb17b75e34,
    rb_right = 0x17b789f617b78552,
    rb_left = 0x17b795c917b78b40
  },
  rb_subtree_gap = 0x17b7adfa17b7aa00,
  vm_mm = 0x17b89a1d17b7b08c,
  vm_page_prot = {
    pgprot = 0x17ba373317b992cf
  },
  vm_flags = 0x17ba376517ba3739,
  {
    shared = {
      rb = {
        __rb_parent_color = 0x17ba8ef017ba6d60,
        rb_right = 0x17baeb5e17bada48,
        rb_left = 0x17bdc7c217bdc797
      },
      rb_subtree_last = 0x17bd017e17bdc93b
    },
    anon_name = 0x17ba8ef017ba6d60 <error: Cannot access memory at address 0x17ba8ef017ba6d60>
  },
  anon_vma_chain = {
    next = 0x17bdc99217bdc955,
    prev = 0x17bdcbb217bdca57
  },
  anon_vma = 0x17bdcc0717bdcbf3,
 ...
  • 使用-o参数: 显示每个成员在数据结构中的偏移(默认十进制,-x指定16进制)
crash_arm64_v8> struct -o vm_area_struct
struct vm_area_struct {
    [0] unsigned long vm_start;
    [8] unsigned long vm_end;
    ....
   [80] unsigned long vm_flags;
        union {
   [88]     struct {...} shared;
   [88]     const char *anon_name;
        };
  [120] struct list_head anon_vma_chain;
  ...
}
SIZE: 232

crash_arm64_v8> struct -o -x vm_area_struct  #十六进制显示偏移
struct vm_area_struct {
   [0x0] unsigned long vm_start;
   [0x8] unsigned long vm_end;
  [0x10] struct vm_area_struct *vm_next;
         union {
  [0x58]     struct {...} shared;
  [0x58]     const char *anon_name;
         };
  [0x78] struct list_head anon_vma_chain;
  ....
}
SIZE: 0xe8

6.p命令

用来打印一个表达式或者符号的值。

  • 指定symbol: 打印一个内核的符号的值,通常是export出来的全局变量等。
crash_arm64_v8> p pid
pid = $1 =
 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
crash_arm64_v8> p init
init = $2 =
 {int (void)} 0xffffffc0120e4348 <init>
crash_arm64_v8> p init_mm
init_mm = $3 = {
  {
    mmap = 0x0,
    mm_rb = {
      rb_node = 0x0
    },
    vmacache_seqnum = 0,
    get_unmapped_area = 0x0,
    mmap_base = 0,
    mmap_legacy_base = 0,
    task_size = 0,
    highest_vm_end = 0,
    pgd = 0xffffffc01206a000,
    ....
  • 通过指定“symbol : cpuid”的方式打印某个cpu上pre-cpu变量的值。
crash_arm64_v8> p irq_stat:2
per_cpu(irq_stat, 2) = $5 = {
  __softirq_pending = 0
}
crash_arm64_v8> p irq_stat:7
per_cpu(irq_stat, 7) = $6 = {
  __softirq_pending = 0
}

7.irq命令

显示中断相关的信息。

  • index: 显示某个中断相关的信息。
crash_arm64_v8> irq 16
 IRQ   IRQ_DESC/_DATA      IRQACTION      NAME
 16   ffffff80bac33800  ffffff80b7fd8980  "sprd_serial1"
crash_arm64_v8> dis ffffff80b7fd8980
0xffffff80b7fd8980 <__efistub_$d.9+-546668967829>:      add     w20, w25, #0x88a, lsl #12
crash_arm64_v8> rd -s ffffff80b7fd8980
ffffff80b7fd8980:  __typeid__ZTSF9irqreturniPvE_global_addr+72
crash_arm64_v8> rd -a ffffff80b7fd8980
ffffff80b7fd8980:  4+b
  • -b: 显示中断下半部
SOFTIRQ_VEC      ACTION
    [0]     ffffffc011623c54  <(null)>
    [1]     ffffffc011623c60  <(null)>
    [2]     ffffffc011623c6c  <(null)>
    [3]     ffffffc011623c70  <(null)>
    [4]     ffffffc011623c68  <(null)>
    [6]     ffffffc011623c50  <__typeid__ZTSFvP14softirq_actionE_global_addr>
    [7]     ffffffc011623c58  <(null)>
    [8]     ffffffc011623c64  <(null)>
    [9]     ffffffc011623c5c  <(null)>
  • -a:显示中断亲和性
crash_arm64_v8> irq  12 -a
IRQ NAME                 AFFINITY
  1 IPI                  0-7
  2 IPI                  0-7
  3 IPI                  0-7
  4 IPI                  0-7
  5 IPI                  0-7
  6 IPI                  0-7
  7 IPI                  0-7
  9 vgic                 0-7
 10 timer@64470000       1
 12 arch_timer           0-7
 13 kvm guest vtimer     0-7
 16 sprd_serial1         0
 18 200d0000.i2c         0
 19 ....
 25 20120000.spi         0
 26 20150000.spi         0
 27 mmc0                 0
 28 mmc1                 0
 29 ufshcd               0
 30 VSP                  0
 31 JPG                  0
 50 23100000.gpu,23100000.gpu,23100000.gpu 0
 51 ...
 101 fts_ts               0-7
 102 head_aud_det_int_all 0-7
  • s: 显示系统中断信息
crash_arm64_v8> irq   -s
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
  1:     141083     147923     115758      98548      71009      54827      33703      26694    GICv3 IPI
  2:        541        482        467        456        493        447       7423       5278    GICv3 IPI
  3:          1          1          1          1          1          1          1          0    GICv3 IPI
  4:          0          0          0          0          0          0          0          0    GICv3 IPI
  5:       8409       7458       9391      12822      14395      14664       6402       7579    GICv3 IPI
  6:      29650      24306      20710      19168      11469       9064      26445      16654    GICv3 IPI
  7:          0          0          0          0          0          0          0          0    GICv3 IPI
  9:          0          0          0          0          0          0          0          0    GICv3 vgic
 10:     112944      67639      48583      45316      58016      42869      12659       9506    GICv3 timer@64470000
 12:     183638     120837      99488      97025      89706      71386      65808      60780    GICv3 arch_timer
 13:          0          0          0          0          0          0          0          0    GICv3 kvm guest vtimer
 16:          1          0          0          0          0          0          0          0    GICv3 sprd_serial1
 ...

8.task命令

进程中task_struct和thread_info数据结构的值

crash_arm64_v8> task
PID: -1     TASK: ffffff801e604b00  CPU: -1  COMMAND: "bash"
struct task_struct {
  thread_info = {
    flags = 18446744073709551615,
    addr_limit = 18446744073709551615,
    ttbr0 = 18446744073709551615,
    {
      preempt_count = 18446744073709551615,
      preempt = {
        count = 4294967295,
        need_resched = 4294967295
      }
    },
    shadow_call_stack = 0xffffffffffffffff
  },
  state = -1,
  ....

9.vm命令

显示指定进程(指定PID)的相关内存的信息。

crash_arm64_v8> vm 305
PID: 305    TASK: ffffff80b97e0f00  CPU: 1   COMMAND: "logd.klogd"
       MM               PGD          RSS    TOTAL_VM
ffffff80b9fe3840  ffffff80b9fdc000  6488k   10919116k
      VMA           START       END     FLAGS FILE
ffffff80b9875050 5716435000 5716444000    871 /first_stage_ramdisk/system/bin/logd
ffffff80b98754d8 5716444000 57164e6000    875 /first_stage_ramdisk/system/bin/logd
ffffff80b9874570 57164e6000 57164e8000 100871 /first_stage_ramdisk/system/bin/logd
ffffff80b98753f0 57164e8000 57164e9000 100873 /first_stage_ramdisk/system/bin/logd
ffffff803a9e6828 6f4a239000 6f4a7fc000     70
ffffff803a9e69f8 6f4a7fc000 6f4a7fe000 100073
ffffff803a9e7960 6f4a7fe000 6f4b239000     70
ffffff803aa4a3a0 6f4b239000 6f4b23a000 200070
ffffff803aa4a000 6f4b23a000 6f4b336000 200073
ffffff803aa4bc18 6f4b336000 6f4b337000 200070

  • -p: 显示虚拟地址和物理地址
crash_arm64_v8> vm 305 -p
PID: 305    TASK: ffffff80b97e0f00  CPU: 1   COMMAND: "logd.klogd"
       MM               PGD          RSS    TOTAL_VM
ffffff80b9fe3840  ffffff80b9fdc000  6488k   10919116k
      VMA           START       END     FLAGS FILE
ffffff80b9875050 5716435000 5716444000    871 /first_stage_ramdisk/system/bin/logd
VIRTUAL     PHYSICAL
5716435000  131e4f000
5716436000  131e50000
...
5716443000  131e64000
      VMA           START       END     FLAGS FILE
ffffff80b98754d8 5716444000 57164e6000    875 /first_stage_ramdisk/system/bin/logd
VIRTUAL     PHYSICAL
5716444000  1310b4000
...
5716478000  131172000
5716479000  FILE: /first_stage_ramdisk/system/bin/logd  OFFSET: 44000
571647a000  131d6c000
571647b000  131eb5000
571647c000  131eb4000
571647d000  131eb3000
571647e000  1320aa000
571647f000  1320a9000
...
5716485000  131ea4000

  • -m: 显示mm_struct数据结构的值
crash_arm64_v8> vm 305 -m
PID: 305    TASK: ffffff80b97e0f00  CPU: 1   COMMAND: "logd.klogd"
struct mm_struct {
  {
    mmap = 0xffffff80b9875050,
    mm_rb = {
      rb_node = 0xffffff80b8a257b0
    },
    vmacache_seqnum = 289,
    get_unmapped_area = 0xffffffc011620c2c,
    mmap_base = 489202118656,
    mmap_legacy_base = 0,
    task_size = 549755813888,
    highest_vm_end = 549578174464,
    pgd = 0xffffff80b9fdc000,
    membarrier_state = {
      counter = 0
    },
    mm_users = {
      counter = 8
    },
    mm_count = {
      counter = 1
    },
    pgtables_bytes = {
      counter = 258048
    },
    map_count = 264,
    page_table_lock = {
      {
        rlock = {
          raw_lock = {
            {
              val = {
                counter = 0
              },

  • -v: dump该进程所有vm_area_struct数据结构的值。
crash_arm64_v8> vm 305 -v
PID: 305    TASK: ffffff80b97e0f00  CPU: 1   COMMAND: "logd.klogd"
struct vm_area_struct {
  vm_start = 374035664896,
  vm_end = 374035726336,
  vm_next = 0xffffff80b98754d8,
  vm_prev = 0x0,
  vm_rb = {
    __rb_parent_color = 18446743527066391801,
    rb_right = 0x0,
    rb_left = 0x0
  },
  rb_subtree_gap = 374035664896,
  vm_mm = 0xffffff80b9fe3840,
  vm_page_prot = {
    pgprot = 27021597764227027
  },
  vm_flags = 2161,
  {
    shared = {
      rb = {
        __rb_parent_color = 18446743527066391857,
        rb_right = 0x0,
        rb_left = 0x0
      },
      rb_subtree_last = 14
    },
    anon_name = 0xffffff80b9875531 ""
  },

  • -f 1234: 数字1234在vm_flags的对应比特位
crash_arm64_v8> vm 305 -f 1234
1234: (EXEC|MAYREAD|MAYWRITE|NOHUGEPAGE|EXECUTABLE)
crash_arm64_v8> vm 305 -f 1239
1239: (READ|SHARED|MAYREAD|MAYWRITE|NOHUGEPAGE|EXECUTABLE)

10.kmem命令

当前(转存快照时)系统内存的信息。

  • -i: 显示系统内存使用情况。
crash_arm64_v8> kmem -i
                 PAGES        TOTAL      PERCENTAGE
    TOTAL MEM   704134       2.7 GB         ----
         FREE    12576      49.1 MB    1% of TOTAL MEM
         USED   691558       2.6 GB   98% of TOTAL MEM
       SHARED        0            0    0% of TOTAL MEM
      BUFFERS     1210       4.7 MB    0% of TOTAL MEM
       CACHED   379164       1.4 GB   53% of TOTAL MEM
         SLAB    57415     224.3 MB    8% of TOTAL MEM

   TOTAL HUGE        0            0         ----
    HUGE FREE        0            0    0% of TOTAL HUGE

   TOTAL SWAP   436562       1.7 GB         ----
    SWAP USED    32256       126 MB    7% of TOTAL SWAP
    SWAP FREE   404306       1.5 GB   92% of TOTAL SWAP

 COMMIT LIMIT   788629         3 GB         ----
    COMMITTED  17644777      67.3 GB  2237% of TOTAL LIMIT
  • -v: 显示系统vmalloc使用情况。

  • V:显示系统vm_stat情况

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

crash_arm64_v8> kmem -z
NODE: 0  ZONE: 0  ADDR: ffffffc01237d100  NAME: "DMA32"
  SIZE: 524288  PRESENT: 524272  MIN/LOW/HIGH: 1045/6456/7372
  VM_STAT:
        NR_FREE_PAGES: 9115
NR_ZONE_INACTIVE_ANON: 2459
  NR_ZONE_ACTIVE_ANON: 90029
NR_ZONE_INACTIVE_FILE: 218441
  NR_ZONE_ACTIVE_FILE: 21419
  NR_ZONE_UNEVICTABLE: 5570
NR_ZONE_WRITE_PENDING: 36
             NR_MLOCK: 5570
         NR_PAGETABLE: 11919
   NR_KERNEL_STACK_KB: 17456
  NR_KERNEL_SCS_BYTES: 4460544
            NR_BOUNCE: 0
           NR_ZSPAGES: 3867
    NR_FREE_CMA_PAGES: 0


NODE: 0  ZONE: 1  ADDR: ffffffc01237d780  NAME: "Normal"
  SIZE: 262143  MIN/LOW/HIGH: 560/3462/3953
  VM_STAT:
        NR_FREE_PAGES: 3461
NR_ZONE_INACTIVE_ANON: 15847
  NR_ZONE_ACTIVE_ANON: 28576
NR_ZONE_INACTIVE_FILE: 61498
  NR_ZONE_ACTIVE_FILE: 52658
  NR_ZONE_UNEVICTABLE: 20188
NR_ZONE_WRITE_PENDING: 28
             NR_MLOCK: 20188
         NR_PAGETABLE: 2998
   NR_KERNEL_STACK_KB: 7808
  NR_KERNEL_SCS_BYTES: 2007040
            NR_BOUNCE: 0
           NR_ZSPAGES: 3522
    NR_FREE_CMA_PAGES: 0


NODE: 0  ZONE: 2  ADDR: ffffffc01237de00  NAME: "Movable"
  [unpopulated]

  • -s: 显示每个slab的情况
  • -p: 显示每个页面的情况
crash_arm64_v8> kmem -p
      PAGE       PHYSICAL      MAPPING       INDEX CNT FLAGS
ffffffff0de00000 400000000                0        0  0 0
ffffffff0de00040 400001000                0        0  0 0
ffffffff0de00080 400002000                0        0  0 0
ffffffff0de000c0 400003000                0        0  0 0
ffffffff0de00100 400004000                0        0  0 0
ffffffff0de00140 400005000                0        0  0 0
ffffffff0de00180 400006000                0        0  0 0
ffffffff0de001c0 400007000                0        0  0 0
ffffffff0de00200 400008000                0        0  0 0
...
  • -g: 显示struct page里面flag的比特位
crash_arm64_v8> kmem -g
PAGE-FLAG       BIT  VALUE
PG_locked         0  000001
PG_referenced     1  000002
PG_uptodate       2  000004
PG_dirty          3  000008
PG_lru            4  000010
PG_active         5  000020
PG_workingset     6  000040
PG_waiters        7  000080
PG_error          8  000100
PG_slab           9  000200
PG_owner_priv_1  10  000400
PG_arch_1        11  000800
PG_reserved      12  001000
PG_private       13  002000
PG_private_2     14  004000
PG_writeback     15  008000
PG_head          16  010000
PG_mappedtodisk  17  020000
PG_reclaim       18  040000
PG_swapbacked    19  080000
PG_unevictable   20  100000
PG_mlocked       21  200000
PG_checked       10  000400
PG_swapcache     10  000400
PG_fscache       14  004000
PG_pinned        10  000400
PG_savepinned     3  000008
PG_foreign       10  000400
PG_xen_remapped  10  000400
PG_slob_free     13  002000
PG_double_map    14  004000
PG_isolated      18  040000

11.list命令

用来遍历链表,并且可以打印链表中成员的值。

  • -h : 指定链表头list_head的地址
  • -s: 用来打印链表成员的值

例如,mutex_waiter结构体定义:

struct mutex_waiter {
	struct list_head     list;
	struct task_struct   *task;
	...
}
crash_arm64_v8> struct mutex.owner,count,wait_list 0xffffffc0126ddf4c
  owner = {
    counter = .2
  },
wait_list = {
    next = 0xffffffc0126ddfdd,//下一个元素头
    prev = 0xffffffc0126ddf12
}

crash_arm64_v8> list -s mutex_waiter.task -h 0xffffffc0126ddfdd
ffffffc0126ddfdd
    task = 0xffffffc0126d1124
ffffffc0626ddfdd   
    task = 0xffffffc0126d1124
...
    task = ...
  • 1
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

老衲不依

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值