Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

106258
1323
114608


[리눅스커널][스케줄링] 크래시 유틸리티로 컨택스트 스위칭 디버깅하기 10. Process Scheduling

크래시 유틸리티로 컨택스트 스위칭 디버깅하기

이번에는 크래시 유틸리티를 활용해 컨택스트 정보를 확인하겠습니다.

다음 정보는 ARM 코어에서 실행 중인 프로세스의 레지스터 세트입니다.
pc : [<80f65224>]   lr : [<80f65bcc>]      psr: 0x80f655ac
sp : 0x9b7dfce8   ip : 0x9b7dfd74   fp : 0x9b7dfd64
r10: 0x0   r9 : 0x9f89ea00   r8 : 0x9db8b200
r7 : 0x81709294   r6 : 0x9eb07000   r5 : 0x828ea000   r4 : 0xa6b46780
r3 : 0x00000000   r2 : 0x036db918   r1 : 0x00000089   r0 : 0x72fbe0b8

ARM 코어 레지스터 세트에는 ARM 코어에서 실행 중인 프로세스의 코드 정보로 가득차 있습니다.
그럼 위 레지스터 세트는 어떤 코드를 실행 일 때 정보일까요?

위 레지스터 세트를 채우면서 실행 중인 주인공은 라즈베리파이에서 볼 수 있는 "lxpanel" 프로세스이며 다음 콜스택으로 실행 중이었습니다.
1 crash> bt 718
2 PID: 718   TASK: 9eb07000  CPU: 2   COMMAND: "lxpanel"
3 #0 [<80f65224>] (__schedule) from [<80f65bcc>]
4 #1 [<80f65b80>] (schedule) from [<801e059c>]
5 #2 [<801e0480>] (futex_wait_queue_me) from [<801e11b8>]
6 #3 [<801e10a0>] (futex_wait) from [<801e2e14>]
7 #4 [<801e2cf4>] (do_futex) from [<801e3a58>]
8 #5 [<801e3938>] (sys_futex) from [<80108f20>]


위 콜스택은 리눅스 코어 덤프를 로딩해서 프로세스 정보를 디버깅할 수 있는 크래시 유틸리티 프로그램에서 확인한 내용입니다. "bt [pid]" 명령어를 입력하면 프로세스의 콜스택을 확인할 수 있습니다.


레지스터 세트에서 프로그램 카운터는 80f65224이며 __schedule() 함수 내 주소를 의미합니다.

ARM 코어 프로그램 카운터 레지스터에 저장된 함수 주소는 무엇을 의미할까요?
이는 현재 ARM 코어에서 해당 주소에 있는 어셈블리 코드를 실행 중인 것입니다. 
프로그램 카운터에 코드 주소를 지정하면 ARM ALU에서 어셈블리 코드에 대한 사칙연산을 수행합니다.

코어 덤프에서 ARM 레지스터 세트를 어디에 저장하는지 확인해 봅시다.
1  crash> ps 718
2    PID    PPID  CPU   TASK    ST  %MEM     VSZ    RSS  COMM
3 >  718      1   2  9eb07000  WA   0.1   13540   1704  lxpanel

3 번째 줄 정보로 보아 프로세스 태스크 디스크립터 주소가 9eb07000 이라는 사실을 알 수 있습니다. 참고로, TASK란 필드는 프로세스 태스크 디스크립터를 의미합니다.
 
이번엔 다음 명령어를 입력해서 9eb07000 주소를 태스트 디스크립터 구조체로 캐스팅해보겠습니다. 
1 crash> struct task_struct 9eb07000
2 struct task_struct {
3  state = 256,
4  stack = 0x9b7de000,
5  usage = {
6    counter = 3
7  },

4 번째 줄 정보로 프로세스 스택 최상단 주소는 0x9b7de000입니다.

이번엔 다음 명령어로 프로세스 스택 최상단 주소인 0x9b7de000 를 struct thread_info.cpu_context 필드로 캐스팅해보겠습니다.
1  crash> struct thread_info.cpu_context 0x9b7de000
2   cpu_context = {
3     r4 = 0xa6b46780,
4     r5 = 0x828ea000,
5     r6 = 0x9eb07000,
6     r7 = 0x81709294,
7     r8 = 0x9db8b200,
8     r9 = 0x9f89ea00,
9     sl = 0x0,
10    fp = 0x9b7dfd64,
11    sp = 0x9b7dfce8,
12    pc = 0x80f655ac,
13    extra = {0x0, 0x0}
14  }
  
위 출력 메시지를 보면 cpu_context 세부 필드에 레지스터 세트 정보가 보입니다. r4~pc 필드가 해당 프로세스가 실행 중일 때 ARM 레지스터 세트 값입니다. 

달리 보면 이 프로세스가 컨택스트 스위칭을 실행할 때 저장한 ARM 레지스터 세트 값입니다.

그런데 pc 필드를 보면 0x80f655ac 주소를 확인할 수 있습니다.
0x80f655ac 주소의 정체는 무엇일까요? 0x80f655ac 주소 근처 코드를 보면 확인할 수 있습니다.
1 crash> dis 0x80f6559c 100
2 0x80f6559c <__schedule+0x37c>:  ldr     r2, [r5, #4]
3 0x80f655a0 <__schedule+0x380>:  mov     r0, r6
4 0x80f655a4 <__schedule+0x384>:  ldr     r1, [r6, #4]
5 0x80f655a8 <__schedule+0x388>:  bl      0x8010f96c <__switch_to>
6 0x80f655ac <__schedule+0x38c>:  bl      0x80158eec <finish_task_switch>

5 번째 줄 코드를 보면 __switch_to() 함수를 호출하는 어셈블리 코드입니다.
즉, 컨택스트 스위칭될 때 실행하는 함수 주소입니다.

5 번째 줄 코드는 C 코드로는 어떤 형태일까요?
[https://elixir.bootlin.com/linux/v4.14.70/source/kernel/sched/core.c]
1 static __always_inline struct rq *
2 context_switch(struct rq *rq, struct task_struct *prev,
3        struct task_struct *next, struct rq_flags *rf)
4{
...
5 /* Here we just switch the register state and the stack. */
6 switch_to(prev, next, prev);
7 barrier();
8
9 return finish_task_switch(prev);
10 }

위 코드 기준으로 context_switch() 함수 6 번째 줄 코드입니다.

"혹시 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답변 올려드리겠습니다!" 

Thanks,
Austin Kim(austindh.kim@gmail.com)

Reference(프로세스 스케줄링)

스케줄링 소개
프로세스 상태 관리
   어떤 함수가 프로세스 상태를 바꿀까?
스케줄러 클래스
런큐
CFS 스케줄러
   CFS 관련 세부 함수 분석  
선점 스케줄링(Preemptive Scheduling)   
프로세스는 어떻게 깨울까?
스케줄링 핵심 schedule() 함수 분석
컨택스트 스위칭
스케줄링 디버깅
   스케줄링 프로파일링
     CPU에 부하를 주는 테스트   
     CPU에 부하를 주지 않는 테스트



덧글

댓글 입력 영역