
一、正文
下面是在实际工作中遇到的一次内核(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也可以,详见:
(gdb) list *(__wake_up_common+0xd4)
__wake_up_common
kernel/sched/wait.c:86
四、定位具体出错指令
由于出错的接口函数中只是一个线程唤醒操作,因此需要进一步确认出错时,CPU 执行的汇编指令是否存在异常或者特殊性
查看 __wake_up_common 接口函数的汇编实现
如何适配crash+kdump分析arm64内核panic问题可参考如下链接:
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
3万+

被折叠的 条评论
为什么被折叠?



