임베디드를 좋아하는 조금 특이한 개발자?

[Linux Debugging] QEMU로 실행한 Linux를 GDB로 디버깅 본문

Embedded/Linux

[Linux Debugging] QEMU로 실행한 Linux를 GDB로 디버깅

Gordon_ 2025. 8. 5. 17:52

- 개발 환경

WSL2 (Ubuntu 24.04 LTS)

buildroot (2024.02)

Qemu emulator (8.2.2 (Debian 1:8.2.2+ds-0ubuntu1.8))

- 사전 필요 작업

https://littlebitodd-developer.tistory.com/74

 

[Linux Debugging] Buildroot를 통해 디버깅할 리눅스 빌드

- 개발 환경WSL2 (Ubuntu 24.04 LTS)buildroot(2024.02)1. 서론 리눅스 커널을 공부하면서 어떻게 하면 일반적인 어플리케이션을 디버깅 할 때 처럼 직관적이고 커널의 코드흐름을 확인 할 수 있는 방법을 고

littlebitodd-developer.tistory.com


1. 서론

  지난 포스트를 통해 디버깅할 리눅스를 Buildroot를 통해 빌드하고 Qemu 에뮬레이터를 통해 리눅스를 직접 부팅까지 해보았습니다. 이번 포스트에서는 Qemu에서 실행한 리눅스에 GDB를 연결하여 디버깅하는 방법을 알아보도록 하겠습니다.

 

주의)

반드시 이전 포스트을 따라서 빌드한 리눅스을 사용하시기 바랍니다.

 

2. GDB 옵션을 추가하여 Qemu 실행

qemu-system-aarch64 -M virt -cpu cortex-a57 -smp 1 -kernel ./output/images/Image -drive file=./output/images/rootfs.ext4,if=none,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -append "root=/dev/vda console=ttyAMA0" -nographic -S -gdb tcp::1234,ipv4

 

이전 명령어에서 GDB 관련 옵션을 추가하였습니다.
-S -gdb tcp::1234,ipv4

  • -S 옵션
    Qemu를 실행하자마자 멈추는 옵션입니다. GDB가 연결되고 BreakPoint를 설정 한 후 프로그램을 실행하기 위함입니다.
  • -gdb tcp::1234,ipv4
    GDB를 연결하기 위한 방법을 설정하는 옵션입니다. tcp를 통해 연결이 되면 포트 번호는 1234로 설정하였습니다.

 

3. GDB를 통해 리눅스 디버깅

 이제 실제로 리눅스를 디버깅하기 위해 GDB를 설정하고 디버깅을 해보도록 하겠습니다. 예시로서 저는 리눅스가 부팅되는 과정을 알고 싶기에 start_kernel() 함수을 디버깅 해보도록 하겠습니다.

 

  새로운 터미널을 실행하고 아래의 명령어로 gdb를 실행합니다. 

# GDB 실행
./output/host/bin/aarch64-buildroot-linux-gnu-gdb

 

위 GDB는 Buildroot에서 타겟보드에 맞춘 전용 GDB입니다. gdb-multiarch를 사용하여도 상관없을 것으로 예상하지만 테스트하지 않았으므로 문제가 생길 수 있습니다.

 

  먼저 실행한 후 디버깅 심볼이 저장되어 있는 vmlinux 부터 로딩합니다. 해당 파일을 로딩하지 않는다면 디버깅 심볼이 없어 BreakPoint을 제대로 설정할 수 없거나 C언어가 아닌 어셈블리언어가 보일 수 있습니다. 그다음 현재 멈추어 있는 Qemu에 연결합니다. 그리고 마지막으로 디버깅할 함수에 브레이크 포인트를 설정합니다. 

 

주의)

저의 경우 buildroot의 버전이 2024.02이므로 해당 버전에서의 리눅스 버전이 6.1.44 입니다.

그러므로 buildroot의 버전이 다를 경우 리눅스의 버전이 달라질 수 있습니다.

# 디버깅 심볼이 있는 ELF 파일을 로드
(gdb) file ./output/build/linux-6.1.44/vmlinux
# QEMU에 연결
(gdb) target remote localhost:1234
# start_kernel의 진입점에 BreakPoint 설정
(gdb) break start_kernel

 

   gdb에서 continue 명령어를 통해 Qemu에서 멈추어 있던 리눅스를 실행합니다. 하지만 위에서 start_kernel에 BreakPoint를 설정하였기에 start_kernel()함수에서 멈춘 것을 확인 할 수 있습니다.

(gdb) continue

 

 

이제 디버깅 하기 쉽도록 layout을 설정합니다. (만약 layout 명령어가 없다면 buildroot에서 tui 설정을 해야합니다.)

  • layout src : 다음으로 실행할 C언어 코드를 확인하기 위한 layout
  • layout regs : 코드를 실행할 때마다 변하는 register를 확인하기 위한 layout
(gdb) layout src
(gdb) layout regs

 

이제 next 또는 step 명령어로 디버깅 할 수 있습니다.