/tools

Ubuntu18.04 KGDB로 디버깅하는 환경 구성

모두 다 쓰고 싶어하지만 쓰는 사람은 별로없는 gdb, 그 중에서도 kgdb를 사용하기 위해서 무슨 설정을 해주어야 되는지 알아보자.


kgdb는 커널디버깅을 하기 위해서 사용한다. 보통 임베디드 시스템에서 타겟 커널을 디버깅하기 위해서 사용하는 것 같은데, 내 경우에는 커널 모듈을 디버깅하기 위해서 VM으로 ubuntu를 가동하고 이 ubuntu의 커널을 디버깅하기 위해서 사용한다.

즉 요약하면, 이 글의 목적은 Ubuntu 서버(Host)에서 VM으로 Ubuntu(Guest)를 가동시키고 Guest의 커널을 Host에서 디버깅하는 것이다.


3개의 terminal을 띄워 두고 시작한다.

Host : 첫번째 창은 Host로 가상머신을 구동하는 역할을 한다.

gdb : 두번째 창은 gdb를 구동시키는 창이다.

Guest : 세번째 창은 guest의 터미널이다.


Host

Create ubuntu image

ubuntu image를 만들어야 한다. virt-manager를 사용한다면 .qcow2 파일이 이에 해당한다. (기본 위치는 /var/lib/libvirt/images/ 밑)

virt-manager로 VM을 구동시키는 법은 여기에서 확인 할 수 있다.

Write shell command

qemu 커맨드로 가상 VM 켜는 것은 아래의 쉘스크립트를 작성해서 실행하면 된다.

(tcp 포트로 5555를 사용함을 유의)

#!/bin/bash

qemu-system-x86_64 \
        --enable-kvm --nographic \
        -smp 1 -m 2g \
        -drive file=/var/lib/libvirt/images/ubuntu18.04-spark.qcow2,format=qcow2 \
        -net nic -net user,hostfwd=tcp::5555-:22 \
        -serial pty 

실행하면 qemu-system-x86_64: -serial pty: char device redirected to /dev/pts/4 (label serial0) 이 뜨는데, 이 디바이스 이름을 기억해 놓자 (/dev/pts/4)


Guest

ssh to VM

qemu로 VM을 구동 시켰으니 VM에 접속해야한다.

guest의 터미널의 접속하는 방법은 ssh를 이용하는 것이다.

qemu를 실행할 때, port번호 5555번을 guest의 22번 포트로 터널을 뚫어 주었기 때문에 localhost의 5555번 포트로 접속가능하다. (-net user,hostfwd=tcp::5555-:22)

ssh localhost -p5555

혹시 안된다면 VM에 openssh-server가 설치되어있지 않은 것이니 apt install openssh-server로 설치한다.

Grub setting

kgdb를 사용하기 위해서 Grub의 커맨드라인을 설정해주어야 한다.

(guest)$ sudo vim /etc/default/grub
(guest)$ GRUB_CMDLINE_LINUX_DEFAULT="quiet splash kgdboc=ttyS0,115200 nokaslr"

위의 커맨드라인에서 nokaslr 옵션은 커널소스코드 주소의 베이스가 동적으로 변하는 것을 막아줘서 디버그 심볼과 매칭이되게 해준다. 변경사항을 저장하자.

(guest)$ sudo update-grub

Guest에서 gdb에게 컨트롤을 넘겨주는 방법은 아래 커맨드를 입력하는 것으로 가능하다. 위의 두 줄은 한번만 설정해주면 되고, 세번째 줄이 sysrq 시스템콜을 날려서 gdb로 컨트롤을 넘겨주는 커맨드이다.

(guest)$ sudo bash -c "echo ttyS0,115200 > /sys/module/kgdboc/parameters/kgdboc"
(guest)$ sudo bash -c "echo 1 > /proc/sys/kernel/sysrq"
(guest)$ sudo bash -c "echo g > /proc/sysrq-trigger"

위의 트리거를 발생시키면 host의 gdb로 컨트롤이 넘어가게된다.


gdb (Host)

Download debug symbol

guest에 설치된 버전의 vmlinux를 다운로드해야 한다. vmlinux란 소스파일이 컴파일되어 나온 커널 전체의 실행파일로 생각할 수 있다.

이 때, 해당 커널버전의 디버그 심볼이 포함된 vmlinux를 다운로드 받아야 디버깅하기 수월하다.

아래와 같이 저장소 정보를 저장한다.

(host)$ echo "deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse
deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse
deb http://ddebs.ubuntu.com $(lsb_release -cs)-proposed main restricted universe multiverse" | \
sudo tee -a /etc/apt/sources.list.d/ddebs.list

Ubuntu 서버에서 Debug Symbol 아카이브 서명키를 가지고 온다. 그 후 디버그 심볼을 설치한다.

(host)$ sudo apt install ubuntu-dbgsym-keyring
(host)$sudo apt-get update
(host)$sudo apt-get install linux-image-$(uname -r)-dbgsym

/usr/lib/debug/boot/ 에 vmlinux-[VERSION]가 있을 것이다. 해당 디렉토리로 이동하여 sudo gdb vmlinux-$(uname -r)로 gdb를 실행한다.

gdb의 타겟은 qemu에서 redirect한 character device인 /dev/pts/4 이므로 아래 커맨드로 설정해준다. 이 커맨드 전에 Guest에서 트리거를 발생시켜줘야 한다.

(gdb) target remote /dev/pts/4

Problems

위의 커맨드까지 입력하면 아래의 문제점들을 확인 할 수 있다.

  1. 0xffffffffa0f77604 in ?? ()

해당 주소값에 대한 debugsymbol을 못찾아서 저렇게 뜨는것이다. 해당 커널의 디버그 심벌을 받으면 된다.

  1. /build/linux-hwe-3HpQOB/linux-hwe-5.3.0/init/main.c: No such file or directory.

해당 커널에 대한 소스코드가 없어서 현재 수행되는 부분의 소스코드를 보여줄 수 없다는 것이다.

위 두 문제에 대한 해결 방법은 해당 커널의 debugsymbol과 소스코드를 다운로드 받는 것이다. 소스코드는 다음과 같이 다운로드 받는다.

apt source linux-image-unsigned-$(uname -r)    #source code

gdb를 다시 실행해서 substitute-path를 이용해 소스코드 경로를 수정해준다. 앞의 경로가 나오면 뒤의 경로로 바꿔버리겠다는 뜻이다.

(gdb) set substitute-path /build/linux-hwe-3HpQOB/linux-hwe-5.3.0 /home/siisee11/linux-kernel/linux-hwe-5.3.0
(gdb) target remote /dev/pts/4

트리거 설정

매번 게스트에서 아래 커맨드를 사용해서 gdb로 컨트롤을 넘겨주어도 되지만,

(guest)$ sudo bash -c "echo g > /proc/sysrq-trigger"

잘 사용하지 않고 특정시점에 사용할 수 있는 시스템콜인 sync시스템콜을 breakpoint로 설정해서 트리거로 사용할 수 있다.

(gdb) b sys_sync

# 커널 5이상 부터는
(gdb) b ksys_sync

kgdbwait

게스트의 grub 커맨드라인에 kgdbwait를 추가해주면 커널은 gdb가 붙을 때 까지 기다린다.

즉, 호스트에서 qemu를 실행시킨다음에 게스트에서 바로 ssh로 접속할 수 없고, gdb를 실행시킨 이후에 컨티뉴를 해주어야 로그인 할 수 있다.

boot타임의 디버깅을 하기위해서 사용된다.

Reference

http://nickdesaulniers.github.io/blog/2018/10/24/booting-a-custom-linux-kernel-in-qemu-and-debugging-it-with-gdb/ https://wiki.ubuntu.com/Debug%20Symbol%20Packages#Getting_-dbgsym.ddeb_packages https://www.lazenca.net/display/TEC/02.Debugging+kernel+and+modules

Jaeyoun

Jaeyoun

The maintainer

Read More