본문 바로가기

Enginius/Linux

[리눅스] kgdb를 이용해서 커널 디버깅하기 (2.6.24 에서도)

kgdb patch for linux 2.6.24

If you have searched the internet for kgdb support in Linux 2.6 kernel you would have noticed the following :

  1. kgdb support was integrated into the mainline kernel starting from kernel version 2.6.26
  2. The last kernel version for which the out-of-tree patch is available from LinSysSoft (the company responsible for kgdb support in Linux) is 2.6.15-5

This means that we have no kgdb support for kernel versions between 2.6.16 and 2.6.26. There is a small history behind this. Actually, the reason why there is no kgdb support for these kernels is because around the 2.6.16 timeframe the talks to integrate kgdb support in mainline kernel became very hot and the kgdb developers started focusing on getting kgdb merged with the mainline Linux kernel. This merging process took some time and the actual merging could only happen by 2.6.26. The reason why it took so much time is because the kgdb patch from LinSysSoft was not merged as-is and  it was changed considerably to meet the kernel guidelines and to make the kgdb specific changes simpler.

You might be lucky to apply the 2.6.15-5 patch from LinSysSoft in some closeby kernel version, 2.6.16 or 2.6.17, but trying to applying the kgdb only changes from 2.6.26 onto say some closeby kernel say 2.6.25 or 2.6.24 is non trivial as lot of changes were done to the main kernel to keep kgdb specific changes to a minimum.

I recently was required to backport the kgdb changes from 2.6.26 to 2.6.24 kernel (Ubuntu 8.04). I’ve made a patch of that which you can find here. Since my requirement was only for x86 and x86_64 architectures, I’ve just made changes for these two archs., though adding support for some other arch on top of this should be straightforward and it may only involve adding the arch specific kgdb file.

The significance of this patch is that it takes the kgdb specific changes to the pre-2.6.26 kernels which will make it possible to apply the patch to other pre-2.6.26 kernels without much changes.



1. 머릿글

Visual Studio 등으로 디버깅을 쉽게 접할수 있고 이러한 디버깅을 리눅스 기반에서 사용하기 위해서는 GDB 의 사용법을 알아야 한다. GDB 사용법 및 명령어는 본 문서에서 생략하고 커널디버깅을 위한 방법과 예제를 기술하고자 한다.

디버깅을 위해 g option으로 컴파일을 하는것과 같이 커널 디버깅을 위해서 커널 패치가 필요하다또한 일반적인GDB 에서의 소스레벨 디버깅과 같이 하기 위해서 KGDB 를 사용해서 디버깅을 하여야 한다기본적인 커널디버깅툴로 KDB 를 이용할수 있으나 이는 어셈플리레벨 혹은 그 이하의 값으로 디버깅을 진행 하기 때문에 여러움이 따른다.

KGDB를 이용해서 커널디버깅을 하기위해서는 i386 계열 PC 두대가 필요하고 가능하다면 같은 리눅스 배포판으로 테스트 하는 것이 좋다이 두대의 PC는 개발중인커널이 올라가서 디버깅을 하는 머신과 RS232c 혹은 Ethernet 으로 연결되 원격에서 GDB 등을 실행하여 디버깅을 하는 머신으로 구분된다.

리눅스에서 디버깅을 GUI 환경에서 하기 위해서는 Data Display Debug (DDD) 와 같은 프로그램이 필요하다그래고 이 DDD 를 실행하기 위해서는 lesstif와 같은 라이브러리가 필요하다.

본 문서의 범위는 머릿글에서 설명한 내용을 다룬다.

지금까지설명한 환경을 모노리딕 커널에서의 디버깅이고 커널 모듈디버깅을 위해서는 원격에서 GDB 대신 gdbmod 와 같은 프로그램을 실행해서 디버깅 해야 한다.
 

2. 디버깅 프로그램

2.1. GDB

GDB같은 디버거의 목적은 다른 프로그램 수행 중에 그 프로그램 ‘내부에서’ 무슨 일이 일어나고 있는지 보여주거나 프로그램이 잘못 실행되었을 때 무슨 일이 일어나고 있는지 보여주는 것이다. GDBC, C++ 등 으로 컴파일하는 프로그램을 디버그 할 수 있다.

쉘에서 gdb GDB를 시작하면 quit로 종료명령을 주기전까지는 터미널로부터 명령라인을 읽어 들인다. help명령을 사용하여 gdb내부에서 도움말을 볼 수 있다.

디버깅을 하기 위해서는 –g옵션을 주고 컴파일/링크 해야 한다만약 링크가 libg.a를 찾을 수 없다고 하면서 실패하게 되면, /usr/lib/ligb.a를 갖고 있지 않기 때문이다그 파일은 특별한 라이브러리로서 디버깅 가능 C 라이브러리이다. libc 패키지에 포함되어 있거나 또는 libc 소스 코드를 받아서 컴파일 하면 생긴다. /usr/lib/libc.a /usr/lib/libg.a로 링크 시켜도 된다.

GDB는 임베디드 시스템을 디버깅할 때 사용되는 '원격모드를 지원한다원격 디버깅은 GDB가 한 머신 상에서 동작하고디버그할 프로그램은 다른 머신 상에서 동작하는 것을 말한다. GDB GDB 프로토콜을 알고 있는 원격지의 'stub'과 직렬 포트 혹은 TCP/IP를 통해 통신할 수 있다.

2.2. Kernel Oops

일반적인 어플리케이션에서 다른프로세스의 메모리 영역등과 같이 유효하지 않은 포인터를 참고 할 때 Segmentation fault가 발생하여 발생한 어플리케이션 전체가 죽게된다그러나 커널의 경우 커널 웁스 오류가 발생한다사용자 레벨에서의 세그먼트 오류와는 달리 커널 웁스가 발생할 경우 해당 프로세스만 죽고 커널을 계속 해서 돌아가게 된다.

커널 웁스가 발생 하였을경우 문제를 해셜하는 과정에서 필요한 CPU register, 호출 체인 추적등을 제공한다이러한 정보를 klogd가 읽어서 readable 한 정보로 바꿔서 syslogd에 전달한다아래에서 설명할 디버깅 툴에서는 Kernel Oops 가 발생할 경우 해당 코드 위치를 디버깅 세션 내에서 즉시 알려주기 때문에 별도 과정을 거칠 필요없이 알수 있다.

2.3. KDB

GDB GNU 디버거라면 KDB Kernel 디버거 정도로 쉽게 이해가 가능하다. SGI 에서 진행하는 오픈소스 프로젝트이며 2.2, 2.4, 2.6 버전 커널을 기반으로 하는 내장 커널 디버거이다다시말해 커널내부에 디버깅정보가 수록된다. BreakPoint 설정과 메모리 및 자료구조 검사프로세스 상태를 별도 외부 시스템없이 로컬에서 살펴볼수 있는 프레임워크를 제공한다.

그러나 뒤에서 설명할 KGDB와는 달리 심볼릭 정보나 소스코드 단계에서 디버깅을 지원하지 않으므로 어셈블리 수준에서 커널 동작 원리를 이해하지 못하면 사용이 어렵다또한 쉘이 뜨기전에부팅과정에서 커널패닉등이 발생하면 디버깅 정보를 살필수 없는 단점이 있다.

2.4. KGDB

linsyssoft 에서 개발중이며 Sourceforge 에서도 다운로드 받을 수 있다.

KGDB 프로젝트 홈페이지는 http://kgdb.linsyssoft.com/ 이며 KGDB는 커널 패치 형식으로 kernel.org등에서 다운받은 커널소스를 패치해야 한다.  프로젝트 홈페이지에 가면 어떤 버전을 다운 받아야 하는지 나와있고 홈페이지에서 다운 받을수 있는 Quick Start 등을 참고 하면 패치 방법이 나와있다.

GDB에서 제공하는 원격 디버깅 모드를 리눅스 커널에 사용되는 소스-레벨 디버거인 KGDB에서도 사용된다. KGDB를 사용하면 커널 개발자는 일반 응용 프로그램과 마찬가지로 커널을 디버깅할 수 있다. KGDB는 커널 코드내에 중단점을 삽입하는 것이 가능하며코드를 한 단계씩 실행(step)시키거나변수의 값을 관찰하는 것이 가능하다하드웨어 디버깅 레지스터를 포함하고 있는 프로세서에서는 감시점(watchpoint)을 설정하여 특정 메모리 주소가 접근되거나 실행될 때 중단점을 설정할 수 있다. KGDB는 디버깅할 머신에 직렬 케이블이나 이더넷을 통해 연결될 또 다른 머신을 필요로 한다. FreeBSD에서는 Firewire DMA를 이용한 디버깅도 가능하다.

2.5. Data Display Debugger (DDD)

DDD는 일반적으로 다른 디버거보다 사용하는데 편리한 인터페이스를 제공하고또 디버깅을 하는데 필요한 환경을 손쉽게 설정할 수 있다하지만디버거는 기본적으로 gdb를 사용하고인터페이스만을 제공한다따라서 DDD gdb가 꼭 있어야만 한다. gdb말고도, dbx xdb, jdb를 이용할 수도 있다.

DDD의 소스는 http://www.gnu.org/software/ddd/#Getting 을 참고해서 쉽게 구할 수 있다물론 RedHat 계열의 배포판에서는 rpm 패키지로도 구할 수 있다그러나 의존성 문제 때문에 설치에 많은 어려움이 따라 뒤에서 설명할 테스트에서는 소스를 받아 컴파일 하는 방법으로 진행 하였다.

DDD에는 두 가지 버전이 있다하나는 Motif의 동적 라이브러리를 이용하는 버전이고다른 하나는 정적 라이브러리를 이용하는 것이다정적 라이브러리를 이용한 버전은 자신의 리눅스에 Motif가 설치되어 있지 않는 사용자를 위한 버전이다그러나 Motif는 유료 프로그램이고 구해서 설치를 해 보았지만 2.6 기반 커널에서 쉽게 컴파일되지 않았다그래서 무료로 사용할수 있는 Lesstif를 다운받아 사용할수 있다http://www.lesstif.org 에서 개발중이며 Sourceforge 에서 다운이 가능하다.


3. KGDB 테스트

3.1. 준비

KGDB  RS232C 혹은 Ethernet 등으로 연결된 두대의 machine 을이용하여 커널을 디버깅 하는 프래임 워크 이다.  Target machine에서는 KGDB 패치를 한 커널을 컴파일 하여 이 이미지를 이용해서 부팅을 하고 원격 Development machine 연결을 기다린후 원격 gdb 에서 continue 명령으로 부팅을 계속 하면서 커널을 디버깅한다.

테스트를 위해서 아래와 같은 환경을 구축하였다.

1.     Target machine

A.       Intel centrino Coreduo Processor(1.66Ghz), 1024Mb memory,

B.       Fedora Core 6

2.     Development machine

A.       Intel centrino mobile Processor (1.4Ghz), 1024Mb memory

B.       Fedora Core 4

두대의 컴퓨터(노트북)을 이용하였고 각 컴퓨터는 RS232C 케이블로 연결하였다또한 커널 컴파일 및 디버깅을 위해 아래와 같은 프로그램 및 커널을 사용하였다.

표 1 KGDB 디버깅을 위한 프로그램

프로그램

버전

Linux Kernel

2.6.15.5

KGDB Patch

2.4 (linux-2.6.15.5-kgdb-2.4.tar.bz2)

gdb

6.3.0.0.-1.2rh

Data Display Debugging (DDD)

3.3.10

Lesstif

0.95.0

 

이외에 컴퓨터 두대 연결을 위한 RS232C 케이블이 필요하다.

3.2. Target machine

Target machine 에서는 KGBD 패치된 커널을 컴파일하여 부팅하게 된다 커널 컴파일을 하기위해 KGDB 웹 사이트의 메뉴얼에 나와있는데로 패치를 해야 하는데커널 패치의 순서 또한 중요하다.

3.2.1. 커널 패치

표 2 커널 패치 순서

1. core-lite.patch

KGDB 구조 및 인터페이스 제공

2. core.patch

‘’

3. i386-lite.patch

i386 계열의 패치

4. i386.patch

‘’

5. 8250.patch

시리얼 통신을 위한 패치

 

위의 순서에 따라 패치를 하고 패치가 완성된 커널로 configuration을 해야 한다페도라 4 에서는 문제가 없었지만 페도라 6 에서는 xconfig 에서 문제가 발생해서 컴파일되지 않았다실제 페도라 6에서 작업을 했기 때문에 menuconfig 에서 작업을 하였다.

3.2.2. 커널 컴파일

make 명령에서 NFS 쪽 컴파일 부분이 에러가 나고 리턴이 되는데 매뉴얼에 없는 내용이어서 단순히 configuration 시에 NFS 부분 체크를 지워서 커널에 포함시키지 않았다나중에 NFS를 이용하면 편하게 소스레벨 디버깅을 할수 있는데 테스트에서는 없이 그냥 진행 하였다.

Configuration 메뉴에서 수정해야 할 부분은 Kernel hacking 부분을 체크하는것과 serial port 부분 라디오 버튼은 선택해주는 것과 널모뎀 속도를 115200 그리고 시리얼포트를 사용자에 맞게 수정해줘야 하는데 0으로 설정하였다.

리눅스 커널 2.6부터는 make install 명령이 자동으로 grub.conf 파일에 커널을 등록해 준다이 파일을 vi 편집기로 열어서 파일시스템 이 입력된 줄 끝에 kgdbwait 를 입력해 준다그러면 커널이 부팅이 되면서 원격 GDB 를 기다리게 된다.

3.3. Development machine

커널을 디버깅 하기 위해 gdb 등을 사용하는 machine development machine이라고 한다. Target machine 에서 사용한 패치 및 빌드된 커널을 Development machine 으로 복사를 해야 한다그리고 복사된 커널 소스를 이용하여 소스레벨 디버깅을 하게된다.

DDD를 사용하기 위해서는 표 1에서 언급한 프로그램중 lesstif  DDD 프로그램을 다운받아 설치를 해야 한다설치방법은 Lesstif 프로그램 압축해제 후 configure, make, make install 해야 하고 DDD 역시 같은 방식으로 컴파일 및 인스톨을 한다. configure 옵션으로  --prefix=<설치폴더 절대경로가 가능하며 매뉴얼에 자세히 나와 있다.

시리얼 케이블이 연결되어 있는 상태에서

3.4. 테스트

Test machine에서는 디버깅용 커널을 이용해서 부팅하면 원격 GDB 를 기다리면서 중단된다. Development machine에서는 그림 2 와 같이 널모뎀 속도설정후 GDB 를 실행 해도 되며 GDB 실행후 set remotebaud 115200 와 같이 설정을 해도 무방하다.

Linux kernel debugging

GDB 실행은 Development machine 에서 복사한 커널 소스에서 vmlinuz 파일을 디버깅 하는것으로 시작한다.

#cd /usr/src/kernel/linux-2.6.15.5

#gdb ./vmlinuz

GDB 실행후 원격 접속을 위해서 널모뎀 통신을 하는 장치를 지정해줘야 한다테스트했던 컴퓨터의 경우 0번 시리얼을 사용하였다연결후 continue 명령어로

GUI 환경에서 디버깅을 하기위해서 설치한 DDD는 그림 3과 같은 형식을 가진다두개의 창으로 구성되어 있고 윗 창에서는 소스분석 및 값 디스플레이가 가능하고 아래 창에서는 GDB 명령을 입력 할 수 있다.





OS를 어플리케이션으로 접근하는 사람은 커널 디버깅이 필요 없을지는 모르지만 사실 커널을 만지작 하면서 디버깅 없이 하는건 너무 어렵다. 

VS6.0 을 다루면서 디버깅이 뭔지 알았지만 리눅스 프로그래밍에서 GDB 같은걸로 값, 메모리등을 체크하기란 쉬운일이 아니다. 사실 나도 GDB는 printf로 대체하고 세그멘테이션 오류에 대해서는 무작정 메모리 공부를 통해 세그멘테이션 오류가 날 부분을 예상했다가 prinf 로 대체하곤한다.

그럼 커널디버거는 왜 공부하는걸까. 

불편하다. .. 다시말해 커널 프로그래밍을 잘못해서 커널 패닉생기고 리붓한다음에 커널소스 한두줄 고치고 printk 삽입하고 다시 커널컴파일 혹은 모듈컴파일하고 로드해서 혹은 이미지 만들고 재부팅한다음에 다시 하는것 보다는 커널디버거를 쓰는게 낫지 않을까.. 하는 약간의 기대감?  ( ㅡ_-);

뭐 암튼 이정도로 동기부여를 마치고 KGDB를 설치하고 이용하는데 대해서 말을시작해 보자.

Sourceforge 에서도 다운로드 받을수 있고 linsyssoft 에서도 개발중이다. 
KGDB 프로젝트 홈페이지는 http://kgdb.linsyssoft.com/ 

KGDB는 커널 패치 형식으로 kernel.org등에서 다운받은 커널소스를 패치해야 한다.  프로젝트 홈페이지에 가면 어떤 버전을 다운 받아야 하는지 나와있고 홈페이지에서 다운 받을수 있는 Quick Start 등을 참고 하면 패치 방법이 나와있다.

우선 KGDB를 위해서는 리눅스 머신이 두대 필요 하다. 난 처음에 시리얼 통신으로 디버깅 한다기에 윈도우의 하이퍼터미널 같은것으로 가능하려나.. 했는데 원격으로 GDB를 실행하는것이어서 리눅스 머신이 두대가 필요 하다.

커널 컴파일을 하기위해 메뉴얼에 나와있는데로 패치를 해야 하는데. 커널 패치의 순서 또한 중요하다. 메뉴얼에 나와있는 순서에 따라 열심히 패치를 하고 패치가 완성된 커널로 configuration을 해야 한다. 뭐 입맛에 맞게 menuconfig 혹은 xconfig 등을 하면 되겠지만 그래도 윈도우 환경이면 xconfig가 편하지 않을까?

수정해야 할 부분은 Kernel hacking 부분을 체크하는것과 serial port 부분 라디오 버튼은 선택해주는 것으로 끝이나고 이미지를 만들고 grup에 등록 시켜주면 되는데. 메뉴얼과 약간의 다른점은 메뉴얼이 커널 2.6.15 기반으로 설명을 하고 있음에도 논리 볼륨을 사용하지 않고 커널이미지를 로드하는 디바이스가 hda1 같은 형식으로 되어 있다. Fedora 에서 타겟을 올린다면 Logical Volume구성을 입력해 줘야겠다. 

우선 여기 까지 하고 부팅은 해 봤는데 커널이미지 까지는 올라간다. 원격 머신이 필요하기 때문에 그 이상 진행은 되지 않는다.

계속되는 이야기는 언제 올라갈지 모르는 #2 에서..


여러번 커널 압축파일을 풀고 패치하고 컴파일하고 지우고를 10번 가까이 한것 같다. 몇가지 중요한점이 있었는데 커널 패치의 순서, 이왕이면 최신판 쓰기, 메뉴얼에 나와있는 버전을 사용하면 쉽다. 뭐 이런저런 문제점이 많았지만. 지금까지 한것은 두 호스트간에 시리얼 통신으로 OS 를 원격으로 디버깅하는 초기 단계 까지 가는것인데. 

 

우선  Development Machine 과  Target machine 두대로 나누어 작업을 하게된다. 쉽게 Dev 호스트에서는 GDB 를 실행 하게 되고 Target 호스트에서는 KGDB패치를 한 커널 컴파일을 하는 호스트가 된다. 두대를 시리얼 케이블로 연결해야 하고 테스트를 해야 하는데. http://kgdb.linsyssoft.com/quickstart.htm 를 보면 적합한 케이블이 없을때 핀을 맞추는법과 시리얼통신이 되는것을 테스트 하는 방법이 나와있다. 

내가 테스트 한 버전은 리눅스 커널 2.6.15.5 버전을 이용하고 KGDB 버전 2.4 를 사용했다. 패치 순서에 유의 하면서 패치를 하고 Fatal fault만 없으면 그냥 넘어가는게 낫겠다. make xconfig 혹은 menuconfig 에서 Kernel Hack 부분에서 KGDB 부분을 체크 해 주고 넘어가는데 나중에 make 할때 보면 NFS 부분 컴파일 할때 오류로 중단이 된다. 그래서 뭐 궁여지책이긴 해도 xconfig 에서 NFS 부분을 포함 하지 않았다. 워닝은 나지만 컴파일 까지 잘 되는걸 보면 GDB 용 커널이 NFS 까지 필요할까.. 싶다. 

2.6 커널에서는 귀찮은 부분이 다 사라지고 몇가지 명령어로 충분한데 grub.conf 에 등록까지 시켜주는게 너무 좋다.. ㅎㅎ 
새로만들어진 grub.conf 파일을 열어서 방금 빌드된 라인에 kgdbwait 를 추가 시켜주면 커널이 로딩되면서 부터 원격 GDB를 기다리게된다. reboot 시켜놓고 Null Modem으로 연결된 원격 호스트에서 GDB를 아래그림처럼 실행을 시킨다.

사용자 삽입 이미지

대충 이정도 화면이 나오는데. 뭐 지금 까지 한건 KGDB 의 필요성인 소스레벨 디버깅은 전혀 하지 않은 상태이다. 단순히 Ctrl+C, continue 정도만 한 화면이다. 

다음번엔 소스레벨 디버깅에 관해 계속 얘기를 해야겠다.