arm64内核crash分析--- Unable to handle kernel paging request at virtual address dead000000000100

一、正文

下面是在实际工作中遇到的一次内核(5.4.195)访问非法内存地址(空指针)导致出错的现场,在这里记录一下简单的分析流程为以后遇到类似的问题作为参考。

[    T9] 000: Unable to handle kernel paging request at virtual address dead000000000100
[    T9] 000: Mem abort info:
[    T9] 000:   ESR = 0x96000004
[    T9] 000:   EC = 0x25: DABT (current EL), IL = 32 bits
[    T9] 000:   SET = 0, FnV = 0
[    T9] 000:   EA = 0, S1PTW = 0
[    T9] 000: Data abort info:
[    T9] 000:   ISV = 0, ISS = 0x00000004
[    T9] 000:   CM = 0, WnR = 0
[    T9] 000: [dead000000000100] address between user and kernel address ranges
[    T9] 000: Internal error: Oops: 96000004 [#1] PREEMPT_RT SMP
[T241148] 003: free_user_queue_list:260 Potential queue leak, Process Id 241110 
[    T9] 000: Modules linked in: ip6table_filter ip6_tables fuse nf_log_ipv4 nf_log_common xt_LOG xt_ecn xt_comment xt_mark xt_multiport rg_mtdoops(O) rg_thread_det(O) rg_edac(O) pshk(O) proc_monitor(O) lpbk_1000m(O) aer_print(O) aer_attach(O) btrfs xor xor_neon zstd_decompress zstd_compress xxhash lzo_compress raid6_pq i2c_mux_pca954x lpc_cpld_dev(O) rte_kni(O) igb_uio(O) board_mgr(O) phytium_ce(O) yt6801(O)
[    T9] 000: CPU: 0 PID: 9 Comm: ksoftirqd/0 Tainted: G        W  O      5.4.195-rt74+ #1
[    T9] 000: Hardware name: Ps2364 Development Board (DT)
[    T9] 000: pstate: 80000009 (Nzcv daif -PAN -UAO)
[    T9] 000: pc : __wake_up_common+0xd4/0x170
[    T9] 000: lr : __wake_up_common+0x80/0x170
[    T9] 000: sp : ffff800010fcb310
[    T9] 000: x29: ffff800010fcb310 x28: 00000000acbdfd94 
[    T9] 000: x27: 0000000000000000 x26: 0000000000000000 
[    T9] 000: x25: 0000000000000003 x24: 0000000000000001 
[    T9] 000: x23: 0000000000000001 x22: ffff800010fcb3b0 
[    T9] 000: x21: ffff0105b5cee258 x20: 0000000000000001 
[    T9] 000: x19: dead0000000000e8 x18: 0000000000000000 
[    T9] 000: x17: 0000000000000000 x16: 0000000000000000 
[    T9] 000: x15: 0000000000000000 x14: 0005000001804800 
[    T9] 000: x13: 0000000000000001 x12: 0000000000000000 
[    T9] 000: x11: 0000000000000000 x10: 0000000000000068 
[    T9] 000: x9 : ffff0106d6010520 x8 : 0000000040000000 
[    T9] 000: x7 : 0000000000210d00 x6 : ffff8000dc09bdc0 
[    T9] 000: x5 : ffff8000100f4d50 x4 : 0000000000000000 
[    T9] 000: x3 : 0000000000000000 x2 : 0000000000000001 
[    T9] 000: x1 : 0000000000000000 x0 : 0000000000000000 
[    T9] 000: Call trace:
[    T9] 000:  __wake_up_common+0xd4/0x170
[    T9] 000:  __wake_up_common_lock+0x74/0xc0
[    T9] 000:  __wake_up+0x14/0x20
[    T9] 000:  ep_poll_callback+0x9c/0x230
[    T9] 000:  __wake_up_common+0x80/0x170
[    T9] 000:  __wake_up_common_lock+0x74/0xc0
[    T9] 000:  __wake_up+0x14/0x20
[    T9] 000:  __sctp_write_space+0xb0/0xe0
[    T9] 000:  sctp_wfree+0xf0/0x1e0
[    T9] 000:  skb_release_head_state+0x40/0xc0
[    T9] 000:  skb_release_all+0x14/0x30
[    T9] 000:  consume_skb+0x40/0x120
[    T9] 000:  sctp_chunk_put+0x58/0x80
[    T9] 000:  sctp_chunk_free+0x24/0x30
[    T9] 000:  sctp_outq_sack+0x340/0x560
[    T9] 000:  sctp_do_sm+0xe48/0x1530
[    T9] 000:  sctp_assoc_bh_rcv+0xdc/0x220
[    T9] 000:  sctp_inq_push+0x48/0x60
[    T9] 000:  sctp_rcv+0x4d8/0xcb0
[    T9] 000:  ip_protocol_deliver_rcu+0x3c/0x210
[    T9] 000:  ip_local_deliver_finish+0x64/0x80
[    T9] 000:  ip_local_deliver+0xf4/0x100
[    T9] 000:  ip_rcv_finish+0x3c/0x50
[    T9] 000:  ip_rcv+0xd0/0xe0
[    T9] 000:  __netif_receive_skb_one_core+0x50/0x80
[    T9] 000:  __netif_receive_skb+0x28/0x70
[    T9] 000:  process_backlog+0xb8/0x1f0
[    T9] 000:  net_rx_action+0x1a8/0x4f0
[    T9] 000:  __do_softirq+0x154/0x3f8
[    T9] 000:  run_ksoftirqd+0x5c/0x80
[    T9] 000:  smpboot_thread_fn+0x258/0x320
[    T9] 000:  kthread+0x118/0x150
[    T9] 000:  ret_from_fork+0x10/0x18
[    T9] 000: Code: a9446bf9 f9402bfb a8c67bfd d65f03c0 (f9400e60) 
[    T9] 000: ---[ end trace 0000000000000004 ]---
[    T9] 000: Kernel panic - not syncing: Fatal exception
[    T9] 000: SMP: stopping secondary CPUs
[    T9] 000: Kernel Offset: disabled
[    T9] 000: CPU features: 0x00006,0a00a808
[    T9] 000: Memory Limit: none
[    T9] 000: L1 CACHE ce_count = 0x0
[    T9] 000: L1 CACHE ue_count = 0x0
[    T9] 000: L2 CACHE ce_count = 0x0
[    T9] 000: L2 CACHE ue_count = 0x0
[    T9] 000: L3 CACHE ce_count = 0x0
[    T9] 000: L3 CACHE ue_count = 0x0
[    T9] 000: TLB CACHE ce_count = 0x0
[    T9] 000: TLB CACHE ue_count = 0x0
[    T9] 000: DDR ce_count = 0x0
[    T9] 000: DDR ue_count = 0x0
[    T9] 000: Cache/TLB/DDR: no ue/ce

二、dump信息说明

  • pc:(Program Counter)pc 指针,记录当前执行哪一条指令;存储当前 CPU 正在执行指令的地址
  • lr:(Link Register)x30 寄存器,保存函数返回地址
  • sp:(Stack Pointer)栈指针
  • fp:(Frame Pointer)x29 寄存器

三、根据dump出的函数调用具体代码

1、最终出错代码

pc : __wake_up_common+0xd4/0x170

2、gdb定位具体代码

使用nm+addr2line也可以,详见:

linux kernel通过堆栈地址定位到对应源代码位置_内核堆栈报错怎么和源码对上-CSDN博客文章浏览阅读393次,点赞7次,收藏3次。nm addr2line_内核堆栈报错怎么和源码对上https://blog.csdn.net/weixin_43412488/article/details/137510740?spm=1001.2014.3001.5502icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_43412488/article/details/137510740?spm=1001.2014.3001.5502

(gdb) list *(__wake_up_common+0xd4)
__wake_up_common
kernel/sched/wait.c:86

四、定位具体出错指令

由于出错的接口函数中只是一个线程唤醒操作,因此需要进一步确认出错时,CPU 执行的汇编指令是否存在异常或者特殊性

查看 __wake_up_common 接口函数的汇编实现

如何适配crash+kdump分析arm64内核panic问题可参考如下链接:

ARM64使能kdump_arm64 kdump-CSDN博客文章浏览阅读636次,点赞8次,收藏16次。arm64使能kdump_arm64 kdumphttps://blog.csdn.net/weixin_43412488/article/details/142923702?spm=1001.2014.3001.5502icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_43412488/article/details/142923702?spm=1001.2014.3001.5502

crash> dis __wake_up_common
0xffffffc010090a50 <__wake_up_common>:  mov     x9, x30
0xffffffc010090a54 <__wake_up_common+4>:        nop
0xffffffc010090a58 <__wake_up_common+8>:        paciasp
0xffffffc010090a5c <__wake_up_common+12>:       stp     x29, x30, [sp, #-96]!
0xffffffc010090a60 <__wake_up_common+16>:       mov     x29, sp
0xffffffc010090a64 <__wake_up_common+20>:       stp     x21, x22, [sp, #32]
0xffffffc010090a68 <__wake_up_common+24>:       mov     x22, x5
0xffffffc010090a6c <__wake_up_common+28>:       stp     x23, x24, [sp, #48]
0xffffffc010090a70 <__wake_up_common+32>:       stp     x25, x26, [sp, #64]
0xffffffc010090a74 <__wake_up_common+36>:       mov     w25, w1
0xffffffc010090a78 <__wake_up_common+40>:       mov     w26, w3
0xffffffc010090a7c <__wake_up_common+44>:       str     x27, [sp, #80]
0xffffffc010090a80 <__wake_up_common+48>:       mov     x27, x4
0xffffffc010090a84 <__wake_up_common+52>:       cbz     x5, 0xffffffc010090a90 <__wake_up_common+64>
0xffffffc010090a88 <__wake_up_common+56>:       ldr     w1, [x5]
0xffffffc010090a8c <__wake_up_common+60>:       tbnz    w1, #2, 0xffffffc010090b54 <__wake_up_common+260>
0xffffffc010090a90 <__wake_up_common+64>:       ldr     x6, [x0, #48]        // ------(1)
0xffffffc010090a94 <__wake_up_common+68>:       add     x21, x0, #0x30       // ------(2)
0xffffffc010090a98 <__wake_up_common+72>:       sub     x6, x6, #0x18        // ------(3)
0xffffffc010090a9c <__wake_up_common+76>:       add     x0, x6, #0x18
0xffffffc010090aa0 <__wake_up_common+80>:       cmp     x21, x0
0xffffffc010090aa4 <__wake_up_common+84>:       b.eq    0xffffffc010090b8c <__wake_up_common+308>  // b.none
0xffffffc010090aa8 <__wake_up_common+88>:       stp     x19, x20, [sp, #16]
0xffffffc010090aac <__wake_up_common+92>:       mov     w23, w2
0xffffffc010090ab0 <__wake_up_common+96>:       mov     w24, #0x0           // ------(4)            // #0
0xffffffc010090ab4 <__wake_up_common+100>:      ldr     x19, [x6, #24]      // ------(5)
0xffffffc010090ab8 <__wake_up_common+104>:      sub     x19, x19, #0x18     // ------(5)
0xffffffc010090abc <__wake_up_common+108>:      nop
0xffffffc010090ac0 <__wake_up_common+112>:      ldr     w20, [x6]
0xffffffc010090ac4 <__wake_up_common+116>:      mov     x0, x6
0xffffffc010090ac8 <__wake_up_common+120>:      mov     x3, x27
0xffffffc010090acc <__wake_up_common+124>:      mov     w2, w26
0xffffffc010090ad0 <__wake_up_common+128>:      mov     w1, w25
0xffffffc010090ad4 <__wake_up_common+132>:      tbnz    w20, #2, 0xffffffc010090b38 <__wake_up_common+232>
0xffffffc010090ad8 <__wake_up_common+136>:      ldr     x5, [x6, #16]      // ------(6)
0xffffffc010090adc <__wake_up_common+140>:      blr     x5
0xffffffc010090ae0 <__wake_up_common+144>:      cmp     w0, #0x0           // ------(7)
0xffffffc010090ae4 <__wake_up_common+148>:      b.lt    0xffffffc010090b14 <__wake_up_common+188>  // b.tstop
0xffffffc010090ae8 <__wake_up_common+152>:      b.eq    0xffffffc010090af8 <__wake_up_common+160>  // b.none
0xffffffc010090aec <__wake_up_common+156>:      tbz     w20, #0, 0xffffffc010090af8 <__wake_up_common+168>
0xffffffc010090af0 <__wake_up_common+160>:      subs    w23, w23, #0x1
0xffffffc010090af4 <__wake_up_common+164>:      b.eq    0xffffffc010090b14 <__wake_up_common+188>  // b.none
0xffffffc010090af8 <__wake_up_common+168>:      cbz     x22, 0xffffffc010090b38 <__wake_up_common+232>
0xffffffc010090afc <__wake_up_common+172>:      add     w24, w24, #0x1
0xffffffc010090b00 <__wake_up_common+176>:      cmp     w24, #0x40
0xffffffc010090b04 <__wake_up_common+180>:      b.le    0xffffffc010090b38 <__wake_up_common+232>
0xffffffc010090b08 <__wake_up_common+184>:      add     x0, x19, #0x18
0xffffffc010090b0c <__wake_up_common+188>:      cmp     x21, x0
0xffffffc010090b10 <__wake_up_common+192>:      b.ne    0xffffffc010090bb0 <__wake_up_common+344>  // b.any
0xffffffc010090b14 <__wake_up_common+196>:      ldp     x19, x20, [sp, #16]
0xffffffc010090b18 <__wake_up_common+200>:      mov     w0, w23
0xffffffc010090b1c <__wake_up_common+204>:      ldp     x21, x22, [sp, #32]
0xffffffc010090b20 <__wake_up_common+208>:      ldp     x23, x24, [sp, #48]
0xffffffc010090b24 <__wake_up_common+212>:      ldp     x25, x26, [sp, #64]
0xffffffc010090b28 <__wake_up_common+216>:      ldr     x27, [sp, #80]
0xffffffc010090b2c <__wake_up_common+220>:      ldp     x29, x30, [sp], #96
0xffffffc010090b30 <__wake_up_common+224>:      autiasp
0xffffffc010090b34 <__wake_up_common+228>:      ret
0xffffffc010090b38 <__wake_up_common+232>:      ldr     x0, [x19, #24]      // ------(8)
0xffffffc010090b3c <__wake_up_common+236>:      add     x2, x19, #0x18
0xffffffc010090b40 <__wake_up_common+240>:      mov     x6, x19
0xffffffc010090b44 <__wake_up_common+244>:      cmp     x21, x2
0xffffffc010090b48 <__wake_up_common+248>:      sub     x19, x0, #0x18
0xffffffc010090b4c <__wake_up_common+252>:      b.ne    0xffffffc010090ac0 <__wake_up_common+104>  // b.any
0xffffffc010090b50 <__wake_up_common+256>:      b       0xffffffc010090b14 <__wake_up_common+196>
0xffffffc010090b54 <__wake_up_common+260>:      ldp     x1, x3, [x22, #24]
0xffffffc010090b58 <__wake_up_common+264>:      mov     x5, #0x100                      // #256
0xffffffc010090b5c <__wake_up_common+268>:      mov     x4, #0x122                      // #290
0xffffffc010090b60 <__wake_up_common+272>:      movk    x5, #0xdead, lsl #48
0xffffffc010090b64 <__wake_up_common+276>:      movk    x4, #0xdead, lsl #48
0xffffffc010090b68 <__wake_up_common+280>:      add     x21, x0, #0x30
0xffffffc010090b6c <__wake_up_common+284>:      sub     x6, x1, #0x18
0xffffffc010090b70 <__wake_up_common+288>:      str     x3, [x1, #8]
0xffffffc010090b74 <__wake_up_common+292>:      add     x0, x6, #0x18
0xffffffc010090b78 <__wake_up_common+296>:      str     x1, [x3]
0xffffffc010090b7c <__wake_up_common+300>:      cmp     x21, x0
0xffffffc010090b80 <__wake_up_common+304>:      str     wzr, [x22]
0xffffffc010090b84 <__wake_up_common+308>:      stp     x5, x4, [x22, #24]
0xffffffc010090b88 <__wake_up_common+312>:      b.ne    0xffffffc010090aa8 <__wake_up_common+80>  // b.any
0xffffffc010090b8c <__wake_up_common+316>:      mov     w23, w2
0xffffffc010090b90 <__wake_up_common+320>:      mov     w0, w23
0xffffffc010090b94 <__wake_up_common+324>:      ldp     x21, x22, [sp, #32]
0xffffffc010090b98 <__wake_up_common+328>:      ldp     x23, x24, [sp, #48]
0xffffffc010090b9c <__wake_up_common+332>:      ldp     x25, x26, [sp, #64]
0xffffffc010090ba0 <__wake_up_common+336>:      ldr     x27, [sp, #80]
0xffffffc010090ba4 <__wake_up_common+340>:      ldp     x29, x30, [sp], #96
0xffffffc010090ba8 <__wake_up_common+344>:      autiasp
0xffffffc010090bac <__wake_up_common+348>:      ret
0xffffffc010090bb0 <__wake_up_common+352>:      mov     x1, x22
0xffffffc010090bb4 <__wake_up_common+356>:      mov     w2, #0x4                        // #4
0xffffffc010090bb8 <__wake_up_common+360>:      str     w2, [x1], #24
0xffffffc010090bbc <__wake_up_common+364>:      ldr     x2, [x19, #32]
0xffffffc010090bc0 <__wake_up_common+368>:      str     x1, [x19, #32]
0xffffffc010090bc4 <__wake_up_common+372>:      stp     x0, x2, [x22, #24]
0xffffffc010090bc8 <__wake_up_common+376>:      str     x1, [x2]
0xffffffc010090bcc <__wake_up_common+380>:      ldp     x19, x20, [sp, #16]
ke_up_common+200>

1、结构体分析

2、汇编分析

(1)此处的含义是将X0 + 48的内存地址里面的值保存到X6寄存器。X0是函数的第一个入参,即wq_head的地址,结合结构体偏移分析,X6保存的是wait_queue_head结构体中list_head链表next指针的值,即wait_queue链表首节点next指针的地址值。

crash> struct -o wait_queue_head
struct wait_queue_head {
   [0] spinlock_t lock;
  [48] struct list_head head;
}
SIZE: 64
crash> struct -o list_head      
struct list_head {
   [0] struct list_head *next;
   [8] struct list_head *prev;
}
SIZE: 16
crash> struct -o wait_queue_entry
struct wait_queue_entry {
   [0] unsigned int flags;
   [8] void *private;
  [16] wait_queue_func_t func;
  [24] struct list_head entry;
}
SIZE: 40

(2)此处的含义是将X0 + 0x30后的值保存到X21寄存器中,即X21保存的是wait_queue_head结构体中list_head链表地址。

(3)此处是将X6 - 0x18的值保存到X6寄存器中,即X6寄存器保存的是wait_queue_entry节点的首地址。

(4)将cnt变量初始化为0,并将值保存在W24寄存器中。这里从panic栈的寄存器中可以看出,X24的寄存器值为1,由此可以得出,问题线程是循环一次在第二次遍历链表的时候出错的,即wait_queue_entry首节点的next指针中保存的值为空。

(5)将X6 + 24地址里的值保存到X19寄存器中,即X6保存的是wait_queue_entry节点next指针的值,即下一个wait_queue_entry节点next指针的地址。然后sub X19, X19 #0x18,是将X19的值减去0x18。

(6)将X6 + 16地址里面的内容保存到X5寄存器中,即X5寄存器保存的是wait_queue_entry节点回调函数func的地址。

(7)将curr->func(xxx)函数执行的返回值W0与0比较,从panic栈中可以看到X0的值为0,因此可以判断回调函数返回值为0,回调函数执行成功。

(8)此处为具体出错指令:ldr X0, [X19, #24],将X19 + 24后地址里面的内容保存到X0中,从panic栈中看出X19寄存器的值为dead0000000000e8,dead0000000000e8 + 24 = dead000000000100刚好是panic中的非法内存地址,也就是说X19寄存器的值保存错了。

从以上汇编指令分析中可以看出,在执行一次链表遍历后,第二次访问出现非法内存问题,即wait_queue第一个节点的next指针保存的地址是已经释放的节点。看func函数信息可以观察处问题原因,从而判断是哪个回调函数在处理当前链表节点。

结合panic栈中X5寄存器的值ffff8000100f4d50,crash分析即可。

crash> sym ffff8000100f4d50

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值