crash常用命令讲解

本文介绍了crash工具,RedHat开源的内核分析工具,用于解析内核dump文件,演示了log、ps、bt、runq、task等常用命令及其功能,帮助开发者快速定位和分析内核稳定性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

        crash工具是redhat公司的提供的一个开源的内核分析工具,它是在gdb的基础上实现了解析内核的功能,比如查看各个线程的内核栈、各任务的状态、内存的使用情况、中断的统计计数等等,我们可以根据当前内核里的数据来分析一些偶现的稳定性问题。这篇文章我们讲解一些常用的crash命令,让大家能快速上手。

运行crash

        在项目中crash常用于分析内核的dump文件,用qemu来生成内核dump文件并用crash工具解析的详细步骤请参考 通过qemu和crash分析崩溃内核 这篇文章。crash运行起来后的日志如下:

max@ubuntu2204:~$ ./crash-8.0.4/crash dump.img linux-stable/build/vmlinux --machdep vabits_actual=48 
crash 8.0.4
Copyright (C) 2002-2022  Red Hat, Inc.
……
……
      KERNEL: linux-stable/build/vmlinux
    DUMPFILE: dump.img
        CPUS: 8
        DATE: Sun Jan 21 23:02:14 CST 2024
      UPTIME: 00:02:57
LOAD AVERAGE: 0.76, 0.25, 0.09
       TASKS: 98
    NODENAME: (none)
     RELEASE: 6.7.0
     VERSION: #8 SMP PREEMPT Sun Jan 21 22:29:54 CST 2024
     MACHINE: aarch64  (unknown Mhz)
      MEMORY: 2 GB
       PANIC: ""
         PID: 0
     COMMAND: "swapper/0"
        TASK: ffff8000824d3ec0  (1 of 8)  [THREAD_INFO: ffff8000824d3ec0]
         CPU: 0
       STATE: TASK_RUNNING (ACTIVE)
     WARNING: panic task not found
crash> 
crash>

如上所示,crash运行起来后会打印出crash的版本信息和dump文件中的内核的相关信息,同时显示“crash>”提示符,这表示crash初步解析dump文件成功了。下面我们继续演示如何通过crash命令查看内核里的数据。

crash常用命令

log命令

log命令可以查看内核ringbuffer中的全部日志,如下:

crash> log
[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x411fd070]
[    0.000000] Linux version 6.7.0 (max@ubuntu2204) (aarch64-linux-gnu-gcc (Linaro GCC 7.5-2019.12) 7.5.0, GNU ld (Linaro_Binutils-2019.12) 2.28.2.20170706) #8 SMP PREEMPT Sun Jan 21 22:29:54 CST 2024
[    0.000000] KASLR disabled on command line
[    0.000000] random: crng init done
[    0.000000] Machine model: linux,dummy-virt
[    0.000000] efi: UEFI not found.
[    0.000000] NUMA: No NUMA configuration found
……
……
crash>

ps命令

ps命令可以查看当前内核中都有哪些任务,该命令会打印出各个任务的pid、ppid、任务状态、该任务对应的task_struct的虚拟地址、任务名称等等,如下:

crash> ps
      PID    PPID  CPU       TASK        ST  %MEM      VSZ      RSS  COMM
>       0       0   0  ffff8000824d3ec0  RU   0.0        0        0  [swapper/0]
>       0       0   1  ffff000002d68ec0  RU   0.0        0        0  [swapper/1]
>       0       0   2  ffff000002d69d80  RU   0.0        0        0  [swapper/2]
>       0       0   3  ffff000002d6ac40  RU   0.0        0        0  [swapper/3]
>       0       0   4  ffff000002d6bb00  RU   0.0        0        0  [swapper/4]
>       0       0   5  ffff000002d6c9c0  RU   0.0        0        0  [swapper/5]
>       0       0   6  ffff000002d6d880  RU   0.0        0        0  [swapper/6]
        0       0   7  ffff000002d6e740  RU   0.0        0        0  [swapper/7]
        1       0   2  ffff000002cf8000  IN   0.0     2276     1228  linuxrc
        2       0   3  ffff000002cf8ec0  IN   0.0        0        0  [kthreadd]
        3       2   0  ffff000002cf9d80  IN   0.0        0        0  [pool_workqueue_]
        4       2   0  ffff000002cfac40  ID   0.0        0        0  

其中左侧有” > ”箭头标注的任务就是当前各个cpu上正在运行的任务。

bt命令

bt命令是查看内核中某些任务的内核栈,比如bt -a是查看当前各个cpu上正在运行的任务的内核栈,如下:

crash> bt -a
PID: 0        TASK: ffff8000824d3ec0  CPU: 0    COMMAND: "swapper/0"
 #0 [ffff8000824c3d40] cpu_do_idle at ffff8000810a2a24
 #1 [ffff8000824c3d50] default_idle_call at ffff8000810a2b9c
 #2 [ffff8000824c3d70] do_idle at ffff8000800d6094
 #3 [ffff8000824c3de0] cpu_startup_entry at ffff8000800d6338
 #4 [ffff8000824c3e00] rest_init at ffff8000810a2e84
 #5 [ffff8000824c3e20] arch_call_rest_init at ffff800081b9096c
 #6 [ffff8000824c3e30] start_kernel at ffff800081b90ecc
……
……

当前系统中有8个cpu,所以bt -a命令会依次打出8个cpu上运行的任务的内核栈。同时也可以通过指定某个任务的pid或task_struct来打印该任务的内核栈,比如查看pid为17的任务的内核栈,如下:

crash> bt 17
PID: 17       TASK: ffff000002d68000  CPU: 0    COMMAND: "migration/0"
 #0 [ffff800082a93d60] __switch_to at ffff8000810a80d4
 #1 [ffff800082a93d80] __schedule at ffff8000810a8418
 #2 [ffff800082a93e10] schedule at ffff8000810a8a2c
 #3 [ffff800082a93e30] smpboot_thread_fn at ffff8000800b8898
 #4 [ffff800082a93e70] kthread at ffff8000800b29ac
crash>

比如查看task_struct的虚拟地址为ffff000002d53b00的任务的内核栈,如下:

crash> bt ffff000002d53b00
PID: 13       TASK: ffff000002d53b00  CPU: 0    COMMAND: "rcu_tasks_kthre"
 #0 [ffff800082a73ca0] __switch_to at ffff8000810a80d4
 #1 [ffff800082a73cc0] __schedule at ffff8000810a8418
 #2 [ffff800082a73d50] schedule at ffff8000810a8a2c
 #3 [ffff800082a73d70] rcu_tasks_one_gp at ffff800080109b00
 #4 [ffff800082a73e20] rcu_tasks_kthread at ffff800080109f28
 #5 [ffff800082a73e70] kthread at ffff8000800b29ac
crash>

runq命令

runq命令可以查看当前各个cpu对应的rq上都有哪些就绪任务,该命令会分别打印出rq上的rt和cfs的就绪队列上的任务,如下:

crash> runq
CPU 0 RUNQUEUE: ffff00007fb33000
  CURRENT: PID: 0      TASK: ffff8000824d3ec0  COMMAND: "swapper/0"
  RT PRIO_ARRAY: ffff00007fb33200
     [no tasks queued]
  CFS RB_ROOT: ffff00007fb330c0
     [no tasks queued]
……
……
CPU 7 RUNQUEUE: ffff00007fbcd000
  CURRENT: PID: 100    TASK: ffff000008268000  COMMAND: "dd"
  RT PRIO_ARRAY: ffff00007fbcd200
     [no tasks queued]
  CFS RB_ROOT: ffff00007fbcd0c0
     [no tasks queued]
crash>

task 命令

task命令可以查看某个任务对应的task_stuct实例里的各个成员的值,比如查看pid为3的任务,如下:

crash> task 3
PID: 3        TASK: ffff000002cf9d80  CPU: 0    COMMAND: "pool_workqueue_"
struct task_struct {
  thread_info = {
    flags = 8,
    {
      preempt_count = 4294967298,
      preempt = {
        count = 2,
        need_resched = 1
      }
    },
    cpu = 0
  },
  __state = 1,
  saved_state = 0,
  stack = 0xffff800082a20000,
  usage = {
……
……

也可以根据某个task_struct实例的虚拟地址查看该实例里的各个成员的值,如下:

crash> task ffff000002cf9d80
PID: 3        TASK: ffff000002cf9d80  CPU: 0    COMMAND: "pool_workqueue_"
struct task_struct {
  thread_info = {
    flags = 8,
    {
      preempt_count = 4294967298,
      preempt = {
        count = 2,
        need_resched = 1
      }
    },
    cpu = 0
  },
  __state = 1,
  saved_state = 0,
  stack = 0xffff800082a20000,
……
……

命令

p命令可以打印出某个变量的值,也可以打印出某个结构体实例中的各成员的值,如下:

crash> p linux_banner
linux_banner = $2 = 0xffff800081620c30 <linux_banner> "Linux version 6.7.0 (max@ubuntu2204) (aarch64-linux-gnu-gcc (Linaro GCC 7.5-2019.12) 7.5.0, GNU ld (Linaro_Binutils-2019.12) 2.28.2.20170706) #8 SMP PREEMPT Sun Jan 21 22:29:54 CST 2024\n"
crash>

比如打印出 init_mm 这个实例里各个成员的值,如下:

crash> p init_mm
init_mm = $3 = {
  {
    {
      mm_count = {
        counter = 1
      }
    },
    mm_mt = {
      {
        ma_lock = {
          {
            rlock = {
              raw_lock = {
……
……

sym命令

sym命令用于处理符号相关的操作,比如把某个符号转换成对应的虚拟地址,假如我们要找到linux_banner字符数组的起始虚拟地址, 对应的命令如下:

crash> sym linux_banner
ffff800081620c30 (D) linux_banner
crash>

rd 命令

rd命令可以读取指定虚拟地址或物理地址的数据,比如读取起始地址为ffff800081620c30,长度为 128 的这段内存的数据,如下:

crash> rd ffff800081620c30 128
ffff800081620c30:  65762078756e694c 2e36206e6f697372   Linux version 6.
ffff800081620c40:  78616d2820302e37 3275746e75627540   7.0 (max@ubuntu2
ffff800081620c50:  6161282029343032 696c2d3436686372   204) (aarch64-li
ffff800081620c60:  2d756e672d78756e 6e694c2820636367   nux-gnu-gcc (Lin
ffff800081620c70:  20434347206f7261 393130322d352e37   aro GCC 7.5-2019
ffff800081620c80:  352e37202932312e 20554e47202c302e   .12) 7.5.0, GNU 
ffff800081620c90:  616e694c2820646c 74756e69425f6f72   ld (Linaro_Binut
ffff800081620ca0:  393130322d736c69 322e32202932312e   ils-2019.12) 2.2
ffff800081620cb0:  373130322e322e38 3823202936303730   8.2.20170706) #8
ffff800081620cc0:  45525020504d5320 6e75532054504d45    SMP PREEMPT Sun
ffff800081620cd0:  203132206e614a20 34353a39323a3232    Jan 21 22:29:54
ffff800081620ce0:  3230322054534320 0000000000000a34    CST 2024.......

同时我们也可以通过-r参数把这段内存里的数据单独保存到指定文件,如下:

crash> rd ffff800081620c30 128 -r test.dat
128 bytes copied from 0xffff800081620c30 to test.dat
crash>

vtop 命令

vtop命令是把虚拟地址转换成对应的物理地址,比如把虚拟地址ffff800081620c30转成对应的物理地址,如下:

crash> vtop ffff800081620c30
VIRTUAL           PHYSICAL        
ffff800081620c30  41820c30        

PAGE DIRECTORY: ffff800081b86000
   PGD: ffff800081b86800 => 10000000bffff003
   PUD: ffff00007ffff010 => 10000000bfffe003
   PMD: ffff00007fffe058 => 60000041800781
  PAGE: 41800000  (2MB)

     PTE        PHYSICAL  FLAGS
60000041800781  41800000  (VALID|RDONLY|SHARED|AF|PXN|UXN)

      PAGE       PHYSICAL      MAPPING       INDEX CNT FLAGS
fffffc0000060800 41820000                0        0  1 3fffc0000004000 reserved
crash>

其中PHYSICAL的值就是对应的物理地址。

pte 命令

pte命令可以把一个页表项里的值转换为对应的物理地址,如下:

crash> pte 18000000bfff7003
      PTE         PHYSICAL  FLAGS
18000000bfff7003  bfff7000  (VALID)
crash>

kmem 命令

kmem命令可以查看内存的相关信息,比如查看当前内存的使用情况,如下:

crash> kmem -i
                 PAGES        TOTAL      PERCENTAGE
    TOTAL MEM   505032       1.9 GB         ----
         FREE   486466       1.9 GB   96% of TOTAL MEM
         USED    18566      72.5 MB    3% of TOTAL MEM
       SHARED      408       1.6 MB    0% of TOTAL MEM
      BUFFERS       59       236 KB    0% of TOTAL MEM
       CACHED      453       1.8 MB    0% of TOTAL MEM
         SLAB     2707      10.6 MB    0% of TOTAL MEM
   TOTAL HUGE        0            0         ----
    HUGE FREE        0            0    0% of TOTAL HUGE
   TOTAL SWAP        0            0         ----
    SWAP USED        0            0    0% of TOTAL SWAP
    SWAP FREE        0            0    0% of TOTAL SWAP
 COMMIT LIMIT   252516     986.4 MB         ----
    COMMITTED        0            0    0% of TOTAL LIMIT
crash> 

struct命令

struct命令实现了结构体操作相关的功能,比如可以查看某个结构体内的各成员的偏移,以及该结构体总的大小,如下:

crash> struct -o tasklet_struct
struct tasklet_struct {
   [0] struct tasklet_struct *next;
   [8] unsigned long state;
  [16] atomic_t count;
  [20] bool use_callback;
       union {
  [24]     void (*func)(unsigned long);
  [24]     void (*callback)(struct tasklet_struct *);
       };
  [32] unsigned long data;
}
SIZE: 40
crash>

也可以按照指定结构体来解析指定的内存,比如:

crash> struct tasklet_head ffff00007fb2aa98
struct tasklet_head {
  head = 0x0,
  tail = 0xffff00007fb2aa98
}
crash>

除了上面列举到的命令外,crash还有一些其他命令,比如list、waitq、vm等等,大家可以通过help命令查看详细说明,这里不再一一列举。

        我们在解决实际问题过程中,可以根据crash的各个命令灵活组合运用,从而获取到自己需要的信息,找到有用的线索。

请关注微信公众号 “Linux研习社” 获取更多技术内容:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值