printf

프로그램을 작성하시면서 가장 많이 사용하시는 디버깅 방법으로 어떤 것을 사용하시나요? 저는 printf()를 가장 많이 사용합니다. 모듈 프로그래밍하시는 분들께 물어 보면 역시 모듈 프로그래밍에도 printk를 가장 많이 사용한다고 합니다.

그러나 printf()도 매우 무거운 함수 중에 하나입니다. 즉, printf()가 소요하는 시간이 매우 깁니다. 실제 release되는 버전에는 당연히 디버깅을 위한 printf()를 제거하겠지만 디버깅을 위한 것이 아니더라도 printf() 사용은 가급적 피하는 것이 좋습니다.

printk

더욱이 커널 속에서 한 몸이 되어 돌아가는 모듈은 아무래도 다이어트해서 가변운 것이 좋겠습니다. 그러므로 디버깅뿐만 아니라 release 버전에서도 가능한한 printk() 함수를 자제하는 것이 좋습니다.

특히 주의하실 것은 printk()나 시간과 관계있는 루틴에 사용하면 정작 배포용 버전을 만들 때 고생할 수 있습니다. 즉, 디버깅을 위해 printk()를 삽입했는데, 이럴 때에는 모듈이 매우 정상적으로 실행됩니다. 그러나 디버깅을 위한 printk()를 제거하면 매우 엉뚱하게 작동할 수 있다는 것이죠.

또는 printk() 때문에 처음부터 실행이 아예 엉뚱하게 진행될 수 있습니다. 이 모두 printk()가 예상보다 더 긴 지연시간을 발생하기 때문입니다. 그러므로 printk() 나 pritnf()를 사용하실 때에는 항상 조심하셔야 합니다. 특히 시간에 민감한 루틴, 빨리 응답해 주어야하는 루틴에는 특히 주의 하셔야 합니다.

부팅 메시지 dmesg

리눅스가 부팅하게 되면 부팅되는 과정 중에 시스템 운영에 필요한 문자 정보를 출력해 줍니다. 디바이스 드라이버가 시스템에 설치된 장치와 직접적인 관계를 가지고 있으므로 부팅할 때, 사용자를 위해 필요한 정보를 출력해 주는 것이 좋습니다.

부팅 메시지는 언제라도 쉘에서 dmesg로 내용을 볼 수 있습니다. 아래는 dmesg로 부팅 중에 출력된 정보 중 프레임 버퍼 정보만 출력하게 한 것 입니다.

]$ dmesg | grep fb
vesafb: framebuffer at 0xf8000000, mapped to 0xd0880000, size 1200k
vesafb: mode is 640x480x16, linelength=1280, pages=0
vesafb: protected mode interface info at 00ff:44f0
vesafb: scrolling: redraw
vesafb: Truecolor: size=0:5:6:5, shift=0:11:5:0
fb0: VESA VGA frame buffer device
]$

커널에 모듈로 등록할 때 시스템에 대한 정보 및 모듈이 어떤 상태로 초기화나 설정되었는지 출력해 주는 것은 매우 유용한 정보입니다. 아울러 커널에 모듈 등록에 실퍠했다고 하더라도 실패한 정보를 출력해 주는 것이 시스템 운영자에게 큰 도움이 됩니다.

커널 버전 정보

모듈 프로그램은 당연히 커널과 관련이 깊습니다. 커널 버전에 따라서 특정 루틴의 처리 방법을 바꾸시려면 /linux/version.h 에서 제공되는 LINUX_VERSION_CODE 값을 확인하시면 됩니다.

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>

int __init init_hello_2_6_9( void)
{
  printk( KERN_ALERT "Kernel is 2.6.9 or newest version.n" );
  
  // 커널 2.6.9 이상 버전에서 수행할 코드 작성
  
  return 0;
}

int __init init_hello_etc( void)
{
  printk( KERN_ALERT "Kernel is older than 2.6.9.n" );

  // 커널 2.6.9 이전 버전에서 수행할 코드 작성

  return 0;
}


void __exit exit_hello(void)
{
  printk( KERN_ALERT "Good-bye~n" );
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 9)

   module_init( init_hello_2_6_9 );

#else

   module_init( init_hello_etc );

#endif

   module_exit( exit_hello );

MODULE_LICENSE( "GPL" );
  • LINUX_VERSION_CODE 는 커널 소스 버전 번호로 정수 값입니다.
  • KERNEL_VERSION은 인수 값으로 버전 번호를 정수로 구해 주는 매크로 함수입니다.

 

태그: *디바이스드라이버