Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

15192
888
89788


[리눅스커널][인터럽트]인터럽트 벡터에서 스택 푸쉬 확인하기 5장. 인터럽트 핸들링

5.3.2. 인터럽트 벡터에서 스택 푸쉬 확인

이번 소절에서는 실제 프로세스 스택 메모리를 보면서 인터럽트 벡터에서 프로세스 레지스터 세트를 푸시하는 과정을 살펴봅니다.

먼저 콜스택을 소개합니다.
-000|account_group_exec_runtime(inline)
-000|update_curr()
-001|check_spread(inline)
-001|put_prev_entity()
-002|put_prev_task_fair()
-003|pick_next_task_rt(inline)
-003|pick_next_task_rt()
-004|pick_next_task(inline)
-004|__schedule()
-005|arch_local_irq_disable(inline)
-005|preempt_schedule_irq()
-006|svc_preempt(asm)
-007|__irq_svc(asm)
 -->|exception
-008|blk_flush_plug_list()
-009|current_thread_info(inline)
-009|blk_finish_plug()
-010|ext4_writepages()
-011|__filemap_fdatawrite_range()
-012|filemap_write_and_wait_range()
-013|ext4_sync_file()
-014|vfs_fsync()
-015|fdput(inline)
-015|do_fsync()
-016|ret_fast_syscall(asm)

ret_fast_syscall() 함수에서 do_fsync() 함수 방향으로 호출하여 account_group_exec_runtime() 함수까지 실행하고 있는 흐름입니다.

여기서 7번 콜스택에 __irq_svc 인터럽트 벡터가 보입니다. 이로 인터럽트 발생했음을 알 수 있습니다. 

조금 더 자세히 살펴보면 ret_fast_syscall()~blk_flush_plug_list() 함수 실행 구간 콜스택 흐름으로 동작하고 있었습니다. blk_flush_plug_list() 함수 실행 도중 인터럽트가 발생해서 __irq_svc 인터럽트 벡터가 실행된 것입니다. 

위 콜스택에서 인터럽트 벡터인 __irq_svc() 함수가 호출된 시점의 스택 메모리 주소 0xCE4F9D84로 이동해서 스택 덤프를 확인하면 아래 화살표와 같이 스택에 푸쉬된 레지스터를 확인할 수 있습니다. 
[명령어: d.v %symbol.l 0xCE4F9D80]
________address||value_______|symbol
NSD:CE4F9D80| 0x20070013
NSD:CE4F9D84| 0xFFFFFFFF   
NSD:CE4F9D88| 0xCE4F9DE4
NSD:CE4F9D8C| 0xC0FF97B4   \\vmlinux\Global\__irq_svc+0x74
NSD:CE4F9D90| 0xCE4F8000
NSD:CE4F9D94| 0xCE4F8000
NSD:CE4F9D98| 0xCE4F9DAC
NSD:CE4F9D9C| 0xC0FF4E2C   \\vmlinux\sched/core\preempt_schedule_irq+0x50
NSD:CE4F9DA0| 0xC039B9DC   \\vmlinux\blk-core\blk_flush_plug_list+0x1A4
NSD:CE4F9DA4| 0xC039B9E0   \\vmlinux\blk-core\blk_flush_plug_list+0x1A8
NSD:CE4F9DA8| 0x1           
NSD:CE4F9DAC| 0xC0FF97D8   \\vmlinux\Global\svc_preempt+0x8
NSD:CE4F9DB0| 0x0           /* R0  */ 
NSD:CE4F9DB4| 0xCECC72B4   /* R1 */   
NSD:CE4F9DB8| 0x1           /* R2 */         
NSD:CE4F9DBC| 0x0           /* R3 */
NSD:CE4F9DC0| 0xCE4F9E00   /* R4 */
NSD:CE4F9DC4| 0xEAD60A60   /* R5 */
NSD:CE4F9DC8| 0x1           /* R6 */
NSD:CE4F9DCC| 0xCE4F9E00   /* R7 */ 
NSD:CE4F9DD0| 0x0           /* R8 */
NSD:CE4F9DD4| 0x60070013   /* R9 */
NSD:CE4F9DD8| 0xCE4F8000   /* R10 */
NSD:CE4F9DDC| 0x1           /* R11 */
NSD:CE4F9DE0| 0x60070093   /* R12 */
NSD:CE4F9DE4| 0xCE4F9E00  /* R13, 스택 주소 */
NSD:CE4F9DE8| 0xC039B9DC  blk_flush_plug_list+0x1A4 /* R14 */
NSD:CE4F9DEC| 0xC039B9E0  blk_flush_plug_list+0x1A8 /* PC */
NSD:CE4F9DF0| 0x20070013
NSD:CE4F9DF4| 0xFFFFFFFF

0xCE4F9DB0~0xCE4F9DEC 메모리 주소 사이에 인터럽트 발생 전 실행 정보인 레지스터 세트가 보입니다. 오른쪽에 /* R0  */ 형식인 주석문 내 텍스트는 레지지스터를 의미합니다.

위 메모리 덤프를 보면 0x4c 공간만큼 스택 공간을 할당한 다음에 실행 중인 레지스터를 r0부터 pc까지 스택에 저장하고 있습니다. 이 레지스터들은 인터럽트를 처리하고 난 다음에 다시 이전에 실행 중인 프로세스가 다시 읽습니다. 이후 어떤 동작을 할까요? 당연히 인터럽트가 발생해서 멈췄던 코드 다음부터 실행하게 됩니다. 

인터럽트 벡터를 어셈블리로 분석하는 것은 매우 어려운 도전입니다. 하지만 몇 번 메모리에 레지스터가 쌓이는 동작을 그리면 프로세스 정보를 저장하는 동작이 더 오랫동안 남을 것입니다.

이제 인터럽트 벡터에서 프로세스 레지스터를 저장하고 서브 루틴을 실행하는 코드까지 확인했으니 다음 장에선 인터럽트 핸들러를 처리하는 흐름을 살펴 보겠습니다.

# Reference (인터럽트 처리)


핑백

덧글

댓글 입력 영역