printk()
함수는 리눅스 커널에서 메시지 출력과 디버깅을 위한 핵심 도구 중 가장 기본이 되는 도구이다. 이 글에서는 printk()
함수의 기능, 사용법, 예제 코드, 그리고 유용한 팁에 대해 알아본다.
printk()
함수
printk()
함수는 리눅스 커널에서 사용되는 표준 출력 함수로, 커널 내부에서 메시지를 출력하고 로그를 기록하는 데 사용된다. 이 함수는 사용자 공간의 printf()
함수와 유사한 형태를 갖추고 있으며, 커널 내부에서 메시지를 출력하는 가장 일반적인 방법으로 사용된다.
커널 로그 레벨(Log Level)
printk()
메시지에는 아래와 같은 로그 레벨이 있으며, 각 로그 레벨은 다른 중요도와 우선순위를 나타낸다.
Log Level | Define | 의미 |
<0> | KERN_EMEG | 시스템 Emergency 상황 |
<1> | KERN_ALERT | 즉시 출력 메시지 |
<2> | KERN_CRIT | Critical 에러 메시지 |
<3> | KERN_ERR | 에러 메시지 |
<4> | KERN_WARNING | Warning(경고) 메시지 |
<5> | KERN_NOTICE | 정상 메시지 |
<6> | KERN_INFO | 시스템 정보 메시지 |
<7> | KERN_DEBUG | 디거깅 정보 |
커널 로그 레벨 설정
커널은 /proc/sys/kernel/printk
파일을 통해 로그 레벨을 설정할 수 있다.
필자의 리눅스 머신의 현재 설정값을 확인해 보면 다음과 같다.
$ cat /proc/sys/kernel/printk
4 4 1 7
출력된 값의 의미는 다음과 같다.
순서 | 레벨 | 의미 |
1 | Console Log Level | 이 값보다 높은 우선순위 메시지들을 Console에 출력 |
2 | Default Message Log Level | 우선순위를 지정하지 않은 메시들이 갖는 우선순위 |
3 | Minimum Console Log Level | Console 로그 레벨이 설정될 수 있는 최소 |
4 | Default Console Log Level | Console 로그의 디폴트 레벨 |
필자의 로그레벨 설정으로는 KERN_WARNING
(4) 메시지 이상이 콘솔 로그에 남게 되고, 아래 printk문과 같이 따로 커널 로그를 지정하지 않고 사용하는 printk
는 “Default Message Log Level”을 갖게 되므로 KERN_WARNING
(4) 레벨을 갖게 된다.
printk("Hello, world!\n");
printk()
자료형에 따른 서식 지정
printk()
함수는 C언어의 printf()
와 같이 자료형에 따른 출력 서식을 지정해야 한다. (https://www.kernel.org/doc/Documentation/printk-formats.txt)
변수 타입 | 서식 지정자 |
int | %d 또는 %x |
unsigned int | %u 또는 %x |
long | %ld 또는 %lx |
unsigned long | %lu 또는 %lx |
long long | %lld 또는 %llx |
unsigned long long | %llu 또는 %llx |
size_t | %zu 또는 %zx |
ssize_t | %zd 또는 %zx |
s32 | %d 또는 %x |
u32 | %u 또는 %x |
s64 | %lld 또는 %llx |
u64 | %llu 또는 %llx |
커널 빌드시 printk
에 전달하는 인자와 서식 지정자가 일치하지 않으면 컴파일 에러가 발생하니 주의해야 한다.
printk()
로 함수 심벌 정보 보기
다음은 printk()
함수를 사용하여 커널에서 메시지를 출력하는 간단한 예제 코드이다.
printk("process: %s\n", current->comm);
printk("[%s:%d] caller: %pS\n", __func__, __LINE__, (void*)__builtin_return_address(0));
- line1: 프로세스의 이름을 출력한다.
current
는 현재 프로세스의 태스크 디스크립터 주소를 가르키는 매크로이다. - line2:
__func__
는 함수명을,__LINE__
은 라인수,__builtin_return_address(0)
은 현재 실행 중인 함수를 호출한 함수의 주소이다.%pS
는 아규먼트로 지정한 주소를 심벌로 변환해 출력한다.
printk()
사용시 주의점
printk
는 로드가 적지 않은 함수이기 때문에, 자주 호출되는 __schedule()
함수와 같은 곳에서 사용하게 되면 시스템에 엄청난 부담을 주게되어 락업(Lock-up), 패닉(panic)을 포함한 여러 가지 문제들이 나타날 수 있다. 따라서, 실행 빈도가 많은 곳에서는 사용을 자제해야 한다. 자주 호출되는 함수라도 정보를 출력하고 콜스택을 확인하고자 한다면 ftrace
사용을 고려할 필요가 있다.