우선 콜스택부터 점검을 해보면, "kswapd0" 프로세스에서 slab cache를 scanning 하는 도중 커널 크래시가 발생하였음을 알 수 있습니다. 메모리가 부족한 상태로 보입니다. ("kswapd0" 프로세스는 page memory가 부족할 때 실행됩니다.)
-000|do_DataAbort(addr = 3244789312, fsr = 3245415784, regs = 0xC1678E40)
-001|__dabt_svc(asm)
-->|exception
-002|test_and_set_bit(asm) // <<**** kernel panic
-003|bit_spin_lock(inline)
-003|hlist_bl_lock(inline)
-003|mb_cache_shrink_scan(?, ?)
-004|shrink_slab_node(shrinkctl = 0xED1C9F08, shrinker = 0xC1721FF0, ?, ?)
-005|shrink_slab(shrinkctl = 0xED1C9F08, nr_pages_scanned = 871, lru_pages = 392
-006|kswapd_shrink_zone(inline)
-006|balance_pgdat(inline)
-006|kswapd(p = 0xC1830580)
-007|kthread(_create = 0xED18ED80)
-008|ret_from_fork(asm)
-009|ret_fast_syscall(asm)
커널 패닉이 발생한 주소는 0xC037B07C인데, r12가 0x2이라서 "strneb r1,[r12] " 명령어 실행 도중 data abort가 trigger되었습니다.
NSR:C037B078|E211C003 _test_and_set_bit: ands r12,r1,#0x3 ; r12,r1,#3
___NSR:C037B07C|15CC1000 strneb r1,[r12] <<-- kernel panic
그럼 r12가 왜 0x2가 되었는지. 그리고 어떤 데이터 structure였는지 코드 리뷰를 해보면,
bit_spin_lock() 함수에서 _test_and_set_bit() 함수 호출 시 r9(0xE9C25A4E)에서 r1으로 copy를 하고,
______addr/line|code_____|label__________________|mnemonic________________|comment
NSR:C0256018|E3A00000 mov r0,#0x0 ; r0,#0
NSR:C025601C|E1A01009 cpy r1,r9
NSR:C0256020|EB049414 bl 0xC037B078 ; _test_and_set_bit
_test_and_set_bit() 함수 첫 instruction에서 "ands r12,r1,#0x3" 동작으로 r12가 0x2가 되었습니다.
NSR:C037B078|E211C003 _test_and_set_bit: ands r12,r1,#0x3 ; r12,r1,#3 // <<-- r1: 0xE9C25A4E
___NSR:C037B07C|15CC1000 strneb r1,[r12] <<-- kernel panic
그럼, bit_spin_lock() 함수에서 _test_and_set_bit() 함수 호출 시 쓰이는 r9의 출처는 어디 일까요?
@C0255FF8 주소에서 "ldr r9,r4,#0x34" 인스트럭션으로 r9가 0xE9C25A4E로 업데이트됩니다.
NSR:C0255FF8|E5949034 ldr r9,[r4,#0x34]
NSR:C0255FFC|E3C3303F bic r3,r3,#0x3F ; r3,r3,#63
NSR:C0256000|E5932004 ldr r2,[r3,#0x4]
NSR:C0256004|E2822001 add r2,r2,#0x1 ; r2,r2,#1
NSR:C0256008|E5832004 str r2,[r3,#0x4]
NSR:C025600C|E1A0300D cpy r3,r13
NSR:C0256010|E3C35D7F bic r5,r3,#0x1FC0 ; r5,r3,#8128
NSR:C0256014|E3C5A03F bic r10,r5,#0x3F ; r10,r5,#63
NSR:C0256018|E3A00000 mov r0,#0x0 ; r0,#0
NSR:C025601C|E1A01009 cpy r1,r9
NSR:C0256020|EB049414 bl 0xC037B078 ; _test_and_set_bit
아래 offset 명령어로 R4: 0xDAC71BC0 = struct mb_cache_entry 임을 알 수 있습니다.
offsetof(struct mb_cache_entry,e_block_hash_p) = 0x34
(struct mb_cache_entry*)0xDAC71BC0 // <<-- R4
e_lru_list = (next = 0xDAC71BC0, prev = 0xDAC71BC0),
e_cache = 0xE698B000,
e_used = 0x0,
e_queued = 0x0,
e_refcnt = (counter = 0x0),
e_bdev = 0xEDC4CC00,
e_block = 0x8313,
e_block_list = (next = 0x0, pprev = 0xE9C25A4C),
e_index = (o_list = (next = 0x0, pprev = 0xE9C26808), o_key = 0x396FB86C),
e_block_hash_p = 0xE9C25A4E // <<--R9
first = 0xDAC7 -> (
next = 0x0, // <<--?
pprev = 0x0)), // <<--?
e_index_hash_p = 0xE9C26808)
그런데 논리적으로 문제가 될만한 디버깅 정보는 찾기 어렵습니다.
#커널 크래시 디버깅 및 TroubleShooting
- Race로 mmc_wait_data_done() 함수에서 커널 패닉
- "cat /d/shrinker" 입력 시 커널 패닉
- 함수 포인터 미지정으로 xfrm_local_error() 커널 패닉
- preempt 조건으로 ___might_sleep() 함수 크래시
- 스택 카나리: __stack_chk_fail() 함수 크래시
- 스택 카나리: tcp_v4_rcv -> __stack_chk_fail 크래시
- 뮤텍스 데드락(Mutex Deadlock)으로 락업(lockup)
- 디바이스 드라이버 Signature 문제로 커널 크래시
- 메모리 불량 커널 크래시 @find_vma_links()
- 메모리 불량 커널 크래시 @ttwu_do_activate()
- Race로 ipv6_ifa_notify() Stuck - watchdog reset
- tty_wakeup() 함수 Data Abort
- irq_affinity_notify() 함수 Data Abort
- cpuacct_charge() 함수 Data Abort
- 워크큐(workqueue) 락업(1)
- 워크큐(workqueue) 락업(2)
- 워크큐(workqueue) 락업(3)
'Core BSP 분석 > 커널 트러블슈팅' 카테고리의 다른 글
[tegra4i] UI freeze due to RT class 프로세스 (0) | 2023.05.07 |
---|---|
[리눅스커널] Crash: 비트 플립 @profile_tick() (0) | 2023.05.07 |
[리눅스][커널] 커널 크래시 분석은 왜 중요할까? (0) | 2023.05.07 |
[Linux][Kernel] 커널 크래시란 (0) | 2023.05.07 |
[Kernel][Crash] 워크큐(workqueue) 락업(3) at [0321] (0) | 2023.05.07 |