정보공간_1

[3기 대전 김재원] Linux Kernel Debugging - Dynamic Probes(3) 본문

IT 놀이터/Elite Member Tech & Talk

[3기 대전 김재원] Linux Kernel Debugging - Dynamic Probes(3)

알 수 없는 사용자 2013. 3. 5. 17:03
안녕하세요! 
대전 멤버십 22-1기 김재원입니다.

Kernel을 다시 빌드 하지 않고 동적으로 디버깅하는 Dynamic Probes에 대해서 계속 연재 하도록 하겠습니다. 

Dynamic Probes
1. kprobe        
2. Jprobe        


지난시간에는 Dynamic Probes에 가장 기본인 Kprobe와 함수의 Entry부분에 접근하여 Function의 Parameter에 접근 할수 있는 Jprobe에 대해서 알아 보았습니다.

이번시간에는 Dynamic Probes의 마지막인  Kretprobe를 하겠습니다.

Kretprobe

우선 Kretprobe를 사용하기 위해서는 커널 컴파일 옵션에서 CONFIG_KRETPROBES = y 가 되어 있어야 합니다.

kretprobe의 간단한 동작원리를 설명하면 일반적으로 Function의 return 주소는 Stack의 최상위에 위치해 있습니다. 이 위치를 변경시켜 Handler를 가지고 오는 방식입니다.

Kretprobe도 Jprobe와 유사하게 Kprobe를 이용하여 구성되어 있지만, 동작방법에는 약간의 차이가 있습니다. 

구조

Kretprobe 구조체를 한번 보겠습니다.

 struct kretprobe

kretprobe 역시 struct kprobe kp를 가지고 있습니다. jprobe보다 더욱 많은 변수들을 가지고 있는 것을 볼 수 있습니다. 함수 시작지점에서 실행되는 것이 아닌 Return시 실행되어야 하기때문에 약간더 복잡한 구조를 가지고 있습니다.

각 변수들과 자세한 동작원리를 살펴 보겠습니다.

kretprobe_handler_t handler 는 return이 될때의 실행할 handler이며

kretprobe_handler_t entry_handler는 Function이 실행되는 Entry부분에서 실행할 handler입니다. entry_handler는 register시 kprobe의 pre_handler에 연결하게 됩니다. kprobe의 pre_handler 와 같다고 보면됩니다.

kprobe와 jprobe는 인터럽트와 선점이 금지된 상태에서 실행이 됩니다. 하지만 kretprobe는 return 되는 시점까지 기다려야 하기때문에 인터럽트와 선점금지 되는 시간이 길어 지기 때문에 kretprobe가 실행되는 순간에 인터럽트와 context switching이 발생될 수 있습니다.

그래서 kretprobe에는 maxactivenmissed가 있습니다. 구조체 바로위 주석에도 maxactive와 nmissed에 대한 설명이 있습니다. maxactive는 동시에 실행될 수 있는 kretprobe_instance 구조체의 개수입니다. maxactive에서 정의한 숫자가 넘어간다면 nmissed의 값이 올라 가게됩니다. nmissed는 실행되지 않고 miss된 개수입니다.

data_size의 경우 entry_handler에서 handler로 Data를 넘겨주고 싶은 경우 함수생성시 data_size만큼 큰값을 할당합니다.

hlist_head free_instances는 할당된 kretprobe_instance를 list를 통하여 관리하게됩니다.

 

동작원리

 Kretprobe 동작원리
 



kretprobe에 register된 Fuction을 호출하게되면 breakpoint exception이 발생하고 pre_handler_kretprobe()가 호출됩니다. maxactive보다 많은 kretprobe_instace가 있으면 nmissed를 증가시키고 종료되며 maxactive보다 작은 kretprobe_instance가 있으면 kretprobe_instance를 생성하고 entry_handler를 실행하게 됩니다.

entry_handler가 끝나게 되면 본격적으로 reture 시 handler를 실행할 준비를 합니다.

arch_prepare_kretprobe()함수를 실행하면 원래 return값이 오게되는 Stack의 최상위값을 저장하고 "Trampoline"이라는 값과 교체하게 됩니다.

이제 exception에서 벗어나게 되면 return 시점에서 "Trampoline"의 코드가 수행됩니다. "Trampoline"이 모두 수행된후 원래 함수가 리된되어야 할 위치로 돌아가 정상적인 실행이 됩니다.

 

예제

이제 예제를 통하여 실제로 사용해 보도록 하겠습니다.

 Kernel 소스의 sample 예제를 조금 수정하여 실행 해보도록 하겠습니다.

 Kernel Module

이 예제는 "do_fork" Function을 추적하여 Fuction의 entry_handler에서 ktime_get을 이용하여 시간을 받아 return 되는 handler에넘겨 함수가 실행되는 시간을 측정하고 return 값을 출력하는 소스입니다.

Kprobe와 Jprobe 를 보셨다면 사용하는데 크게 어려울 것이 없습니다.

결과는 다음과 같다.

 Log 내용

 

결과를 보면 return 값과 함수가 걸린 시간이 나오게 된다.

kretprobe를 이용하여 함수의 성능을 측정할 수도 있고, return 값을 분석하거나 return 값을 변경할 수 있다.

---------------------------------------------------------------------------------------------------

출처 : Linux Kernel Documentation => Kprobe.txt

http://studyfoss.egloos.com => F/OSS study