Linux kernel를 디버깅 하는 방법으로 QEMU와 JTAG을 이용한 방법 등이 있다.

여기서는 x86 64비트 환경에서 QEMU와 gdb로 디버깅 하는 방법을 설명한다.

패키지 설치

먼저 gdb, qemu 등 패키지들을 설치한다.

Ubuntu의 경우 다음 명령을 실행한다.

$ sudo apt install gdb qemu-system-x86 curl git libncurses5-dev build-essential libssl-dev bc flex bison libelf-dev

Linux kernel 다운로드

Linux kernel 빌드를 위해 kernel.org 또는 github 에서 소스 코드를 다운로드 받는다.

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

Linux kernel 설정

Linux 기본 설정파일을 세팅하고 kvm 가속 설정을 한다.

디버깅에 필요한 디버깅 심볼과 GDB용 스크립트를 설정한다.

$ cd linux
$ make defconfig
$ make kvm_guest.config
$ sed -i 's/^# CONFIG_DEBUG_INFO is not set/CONFIG_DEBUG_INFO=y/' .config
$ sed -i 's/^CONFIG_DEBUG_INFO_NONE=y/CONFIG_DEBUG_INFO=y\n# CONFIG_DEBUG_INFO_NONE is not set/' .config
$ sed -i 's/^# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set/CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y/' .config
$ echo CONFIG_GDB_SCRIPTS=y >> .config
$ make olddefconfig

커널 빌드 및 bzImage 복사

커널 이미지를 빌드한다.

$ make -j`nproc`
  • arch/x86_64/boot/bzImage : 심볼이 제거된 커널 이미지
  • vmlinux : 디버깅 심볼이 있는 커널 이미지

Ubuntu 다운로드

정상적으로 부팅해 shell까지 실행하려면 리눅스 배포판이 필요하다. ISO 설치 이미지로 배포판을 설치하거나 미리 설치된 이미지를 다운로드한다.

여기서는 Ubuntu 이미지를 다운로드 받아 사용한다. Ubuntu cloud 등에서 이미지를 받으면 설치 시간을 단축할 수 있다.

$ curl https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img -o ubuntu.img

Linux kernel 디버깅

QEMU를 실행한다. -s와 -S 옵션 때문에 gdb 포트 1234를 열어둔 상태로 멈춰있다.

$ qemu-system-x86_64 -smp 2 -m 512M -kernel $PWD/arch/x86/boot/bzImage -serial mon:stdio -append "root=/dev/sda1 console=ttyS0,115200 nokaslr" -drive file=ubuntu.img,index=0 -device e1000,netdev=net0 -netdev user,id=net0 -nographic -s -S

GDB를 연결하고 심볼들을 로드한다.

$ gdb
(gdb) set auto-load safe-path .
(gdb) add-auto-load-safe-path .
(gdb) file vmlinux
Reading symbols from vmlinux...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x000000000000fff0 in exception_stacks ()
(gdb) break start_kernel
Breakpoint 1 at 0xffffffff82fb8c19: file init/main.c, line 930.
(gdb) continue
...
  • lx-iomem : IO 메모리를 보여준다.
  • lx-cpus : cpu 상태를 보여준다.
  • lx-ps : 현재 프로세스를 보여준다.
  • lx-cmdline : cmdline 을 보여준다.
  • lx-dmesg : 커널 메세지를 보여준다.

기타

  • -cpu host -accel kvm 명령어로 kvm 활성화하면 빠르다. 하지만 break가 안되서 hbreak를 사용해야 한다.
  • storage와 network를 virtio 등으로 로드하면 조금 더 빠른 설정이 가능하다.
  • Ubuntu cloud 이미지를 실행하면 일부 설정 에러 메세지가 뜬다. cloud-util과 cloud-config로 초기화하면 에러메세지를 없앨수 있다.
  • QEMU의 console 단축키는 Ctrl-a c 다. quit 명령어로 종료가 가능하다.

References

https://www.kernel.org/doc/html/v5.19/dev-tools/gdb-kernel-debugging.html