Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

106258
1323
114608


ARM64 - Data Abort Exception(익셉션) Vector 실행 [Linux][ARM] Core Analysis

이번 시간에는 Abort 즉 프로그램에 문제가 생겨서 Exception이 생겼을 때 동작 흐름에 대해
점검해보고자 해요.

ARM에 대한 자료와 세미나를 통해 Exception에 대해서 엄청나게 많이 들었잖아요.
뭐, data abort, prefetch abort, undefined abort 등등이죠.

이제 ARM64 아키텍처에서는 이 Abort를 어떻게 처리하고 있는 지 살펴보도록 할께요 

우선 아래 코드와 같이 익셉션 벡터가 정의되어 있구요.
그런데 abort가 발생할 때는 el1_sync 벡터로 프로그램 카운터가 이동하게 되어 있어요.
/*
 * Exception vectors.
 */

.align 11
ENTRY(vectors)
ventry el1_sync_invalid // Synchronous EL1t
ventry el1_irq_invalid // IRQ EL1t
ventry el1_fiq_invalid // FIQ EL1t
ventry el1_error_invalid // Error EL1t

ventry el1_sync // Synchronous EL1h  //<<--
ventry el1_irq // IRQ EL1h
ventry el1_fiq_invalid // FIQ EL1h
ventry el1_error_invalid // Error EL1h

ventry el0_sync // Synchronous 64-bit EL0
ventry el0_irq // IRQ 64-bit EL0
ventry el0_fiq_invalid // FIQ 64-bit EL0
ventry el0_error_invalid // Error 64-bit EL0

#ifdef CONFIG_COMPAT
ventry el0_sync_compat // Synchronous 32-bit EL0
ventry el0_irq_compat // IRQ 32-bit EL0
ventry el0_fiq_invalid_compat // FIQ 32-bit EL0
ventry el0_error_invalid_compat // Error 32-bit EL0
#else
ventry el0_sync_invalid // Synchronous 32-bit EL0
ventry el0_irq_invalid // IRQ 32-bit EL0
ventry el0_fiq_invalid // FIQ 32-bit EL0
ventry el0_error_invalid // Error 32-bit EL0
#endif
END(vectors)

그럼 보통 커널은 EL1(Exception Level 1)에서 돌고 있으니 el1_sync 코드를 살펴볼께요.

[1]: "mrs x1, esr_el1" 코어 프로세스 명령어로 신드롬 레지스터 정보를 얻어와요.
        보통 Abort가 발생할 때 ARM 프로세스가 Abort 정보를 저장해 놓거든요.
[2]: 26 비트만큼 레지스터를 왼쪽으로 Shift(ESR_ELx_EC_SHIFT) 시켜서 exception class 정보를 얻어와요. 
[3]: Data abort인 경우 el1_da 심볼로 점프
[4]: Undefined Instruction인 경우 el1_undef  심볼로 점프
[5]: stack alignment exception인 경우(보통 스택이 깨졌을 때) el1_sp_pc 심볼로 점프
[6]: pc alignment exception인 경우 el1_sp_pc 심볼로 점프
      ARM64 비트 아키텍쳐에서 프로그램 카운터의 마지막 바이트은 당연히 0x0, 0x8 중의 하나인데,
       다른 값이면 이 Exception Vector로 동작해요. 함수 포인터로 콜백함수를 처리할 때 오동작하는 경우가 있어요.
[7]: unknown exception인 경우 el1_undef  심볼로 점프
[8]: debug exception인 경우 el1_dbg 심볼로 점프
/*
 * EL1 mode handlers.
 */
.align 6
el1_sync:
kernel_entry 1
mrs x1, esr_el1 // read the syndrome register //<<--[1]
lsr x24, x1, #ESR_ELx_EC_SHIFT // exception class  //<<--[2]
cmp x24, #ESR_ELx_EC_DABT_CUR // data abort in EL1
b.eq el1_da //<<--[3]
cmp x24, #ESR_ELx_EC_SYS64 // configurable trap
b.eq el1_undef //<<--[4]
cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception
b.eq el1_sp_pc //<<--[5]
cmp x24, #ESR_ELx_EC_PC_ALIGN // pc alignment exception
b.eq el1_sp_pc //<<--[6]
cmp x24, #ESR_ELx_EC_UNKNOWN // unknown exception in EL1
b.eq el1_undef //<<--[7]
cmp x24, #ESR_ELx_EC_BREAKPT_CUR // debug exception in EL1
b.ge el1_dbg //<<--[8]
b el1_inv

Data Abort
do_mem_abort() 함수로 점프하네요.
do_mem_abort -> arm64_notify_die -> die
el1_da:
/*
* Data abort handling
*/
mrs x3, far_el1
enable_dbg
// re-enable interrupts if they were enabled in the aborted context
tbnz x23, #7, 1f // PSR_I_BIT
enable_irq
1:
clear_address_tag x0, x3
mov x2, sp // struct pt_regs
bl do_mem_abort

// disable interrupts before pulling preserved data off the stack
disable_irq
kernel_exit 1

PC/Stack alligment abort
do_sp_pc_abort() 함수로 점프하는군요.
아래 코드 흐름으로 die 함수가 호출되어 각종 디버깅 정보(프로세스, 콜 트레이스)을 출력하고 리셋이 되죠.
do_sp_pc_abort -> arm64_notify_die -> die
el1_sp_pc:
/*
* Stack or PC alignment exception handling
*/
mrs x0, far_el1
enable_dbg
mov x2, sp
b do_sp_pc_abort

Undefined Instruction abort
아래 코드 흐름으로 die 함수가 호출되어 각종 디버깅 정보(프로세스, 콜 트레이스)을 출력하고 리셋되요.
do_undefinstr -> arm64_notify_die -> die
el1_undef:
/*
* Undefined instruction
*/
enable_dbg
mov x0, sp
b do_undefinstr

Debug exception
아래 코드 흐름으로 die가 처리되요.
do_debug_exception -> arm64_notify_die -> die
el1_dbg:
/*
* Debug exception handling
*/
cmp x24, #ESR_ELx_EC_BRK64 // if BRK64
cinc x24, x24, eq // set bit '0'
tbz x24, #0, el1_inv // EL1 only
mrs x0, far_el1
mov x2, sp // struct pt_regs
bl do_debug_exception
kernel_exit 1


Reference(프로세스 관리)
4.9 프로세스 컨택스트 정보는 어떻게 저장할까?
 4.9.1 컨택스트 소개
 4.9.2 인터럽트 컨택스트 정보 확인하기
 4.9.3 Soft IRQ 컨택스트 정보 확인하기
 4.9.4 선점 스케줄링 여부 정보 저장
4.10 프로세스 디스크립터 접근 매크로 함수
 4.10.1 current_thread_info()
 4.10.2 current 매크로란
4.11 프로세스 디버깅
 4.11.1 glibc fork 함수 gdb 디버깅
 4.11.2 유저 프로그램 실행 추적 

핑백

덧글

댓글 입력 영역