Kernel Debug With Kgdb

Β· 1619 words Β· 4 minute read

κ°œμš” πŸ”—

ν•„μžμ—κ²ŒλŠ” 디버깅이 ν˜„μ—…μ—μ„œ κ°€μž₯ λ§Žμ€ μ‹œκ°„μ„ μ†Œλͺ¨ν•˜λŠ” 일이닀. 업무 νš¨μœ¨μ„ μœ„ν•΄μ„œ 디버깅 ν•˜λŠ” 방법을 찾던 도쀑 μ»€λ„μ—μ„œ μ œκ³΅ν•˜λŠ” kdb와 kgdbλ₯Ό μ΄μš©ν•˜λŠ” 방법에 λŒ€ν•œ μ„Έλ―Έλ‚˜λ₯Ό 보게 λ˜μ—ˆλ‹€. μœ νˆ¬λΈŒμ—μ„œ Β«Using Serial kdb / kgdb to Debug the Linux Kernel - Douglas Anderson, GoogleΒ» κ²€μƒ‰ν•œ μ˜μƒμΈλ°, KDB와 KGDB ν™œμš©ν•˜λŠ” 방법에 λŒ€ν•΄ μƒμ„Έν•˜κ²Œ μ„€λͺ…ν•˜κ³  μžˆλ‹€. λ³Έ ν¬μŠ€νŒ…μ—μ„œλŠ” 링크의 μ˜μƒμ„ ν…ŒμŠ€νŠΈ ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•œ 디버깅 ν™˜κ²½ ꡬ성 방법에 λŒ€ν•΄μ„œλ§Œ κ°„λ‹¨ν•˜κ²Œ μ •λ¦¬ν•œλ‹€.

KDB/KGDB λ₯Ό μ΄μš©ν•˜λŠ” 방법은 Trace32 λ₯Ό μ΄μš©ν•˜μ—¬ 디버깅할 수 μ—†λŠ” ν™˜κ²½μ—μ„œ 맀우 μœ μš©ν•˜λ‹€. νƒ€κ²Ÿ λ³΄λ“œμ— 따라 JTAG 디버깅 ν¬νŠΈκ°€ λ‚˜μ™€μžˆμ§€ μ•Šμ€ κ²½μš°λ„ κ½€ 있기 λ•Œλ¬Έμ΄λ‹€. ν•œ 가지 λ‹¨μ μœΌλ‘œλŠ” 디버깅 ν™˜κ²½ ꡬ성이 생각보닀 λ³΅μž‘ν•˜λ‹€.

ν™˜κ²½ ꡬ성을 μœ„ν•΄ ν•„μš”ν•œ μž‘μ—…μ€ μ•„λž˜μ™€ κ°™λ‹€.

  1. De-muxing Serial communication (kdmx)
  2. Kernel configuration
  3. Attaching GDB

Demuxing Serial Communication using kdmx πŸ”—

ν•„μžλŠ” 라즈베리파이λ₯Ό μ΄μš©ν•˜μ—¬ 디버깅 ν™˜κ²½μ„ κ΅¬μ„±ν–ˆλ‹€. ν˜ΈμŠ€νŠΈκ°€ λ¦¬λˆ…μŠ€ λž©νƒ‘μ΄μ—ˆμœΌλ©΄ μ’‹μ•˜κ² μ§€λ§Œ, μ•ˆνƒ€κΉκ²Œλ„ λ§₯ OS ν™˜κ²½μ„ μ‚¬μš©ν•˜μ˜€λ‹€. νƒ€κ²Ÿ λ³΄λ“œμ™€ μ‹œλ¦¬μ–Ό 톡신을 ν•œλ‹€λŠ” κ°€μ • ν•˜μ—, GDB와 터미널 ν™˜κ²½μ„ ν•˜λ‚˜μ˜ μ‹œλ¦¬μ–Ό 포트둜 μ—°κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” 가상 μ‹œλ¦¬μ–Ό 포트λ₯Ό μƒμ„±ν•˜κ³  톡신을 De-mux ν•΄μ£ΌλŠ” ν”„λ‘œκ·Έλž¨μ΄ ν•„μš”ν•˜λ‹€. 그리고 이λ₯Ό μœ„ν•œ κ°„λ‹¨ν•œ 도ꡬ가 kdmx이닀. 본래 agent-proxy λΌλŠ” ν”„λ‘œμ νŠΈ 밑에 κ°„λ‹¨ν•œ ν”„λ‘œκ·Έλž¨ ν˜•νƒœλ‘œ λ“€μ–΄κ°€ μžˆμ§€λ§Œ, μ†μ‰½κ²Œ λ°›μ•„μ„œ λ³„λ„μ˜ ν™˜κ²½ λ³€μˆ˜ μ„€μ • 없이 κ³§λ°”λ‘œ λΉŒλ“œκ°€ κ°€λŠ₯ν•˜λ‹€.

ioctl을 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” BSD κ³„μ—΄μ—μ„œλŠ” μ•½κ°„μ˜ μˆ˜μ •μ‚¬ν•­μ΄ ν•„μš”ν•˜μ§€λ§Œ ν•„μžκ°€ μ˜¬λ €λ†“μ€ μ €μž₯μ†Œ λ‚΄μ˜ μ½”λ“œ(https://github.com/seokbeomKim/kdmx)λ₯Ό μ΄μš©ν•˜λ©΄ λœλ‹€. λ¦¬λˆ…μŠ€ 계열이라면, git://git.kernel.org/pub/scm/utils/kernel/kgdb/agent-proxy.git μ—μ„œ λ‹€μš΄λ°›μ•„μ„œ μ‚¬μš©ν•˜λ„λ‘ ν•˜μž.

kdmx λ₯Ό λΉŒλ“œν•œ 뒀에 μ•„λž˜μ™€ 같이 μ‹€ν–‰ν•΄μ£Όλ©΄, pseudo ttyκ°€ λ§Œλ“€μ–΄μ§„ 것을 확인할 수 μžˆλ‹€.

1
2
3
4
5
6
β”Œβ”€[sukbeom@Sukbeomui-MacBookPro] - [~/Workspaces/kdmx/kdmx] - [3061]
└─[$] ./kdmx -p /dev/tty.usbserial-0001 -b 115200                                                                         [23:37:07]
/dev/ttys000 is slave pty for terminal emulator
/dev/ttys003 is slave pty for gdb

Use <ctrl>C to terminate program

ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ /dev/ttys000 λ₯Ό μ—΄μ–΄ μ•„λž˜μ™€ 같이 ν™•μΈν•΄λ³΄μž.

1
2
3
4
5
6
7
8
9
$ minicom -D /dev/ttys000 -b 115200

Welcome to minicom 2.8

OPTIONS:
Compiled on Jan  4 2021, 00:04:46.
Port /dev/ttys000, 23:52:43

Press Meta-Z for help on special keys

Kernel Configuration πŸ”—

μ•„λž˜μ˜ 컀널 μ„€μ • ν”Œλž˜κ·Έλ“€μ„ ν™•μΈν•œλ‹€. 컀널 컴파일 ν•˜λŠ” 방법은 디버깅 ν™˜κ²½ ꡬ성과 λ‹€λ₯Έ λ‚΄μš©μ΄λ―€λ‘œ 이 ν¬μŠ€νŒ…μ—μ„œ μžμ„Έν•˜κ²Œ μ„€λͺ…ν•˜μ§€ μ•Šκ² λ‹€.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
CONFIG_KGDB_KDB=y
CONFIG_KDB_DEFAULT_ENABLE=0x1
CONFIG_KDB_KEYBOARD=y
CONFIG_KDB_CONTINUE_CATASTROPHIC=0
# CONFIG_WATCHDOG is not set
# CONFIG_WQ_WATCHDOG is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
CONFIG_MAGIC_SYSRQ_SERIAL=y
CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="."

Attaching GDB πŸ”—

이제 KGDBλ₯Ό 직접 μ΄μš©ν•΄λ³΄μž. ν•„μžλŠ” 컴파일용 λ¦¬λˆ…μŠ€ μ„œλ²„μ—μ„œ 컀널을 λΉŒλ“œν•˜κ³  μƒμ„±λœ vmlinux νŒŒμΌμ„ Mac OS에 λ³΅μ‚¬ν•˜μ—¬ 심볼을 λ‘œλ“œν•˜λŠ”λ° μ‚¬μš©ν•˜μ˜€λ‹€. λ§₯용 gdbκ°€ ν•„μš”ν•˜λ‹€λ©΄ λ°˜λ“œμ‹œ https://seokbeomkim.github.io/posts/kernel-hacking-on-mac/ ν¬μŠ€νŒ…μ„ μ°Έκ³ ν•˜λ„λ‘ ν•œλ‹€. (homebrew λ₯Ό μ΄μš©ν•˜μ—¬ gdb λ₯Ό μ„€μΉ˜ν•΄λ΄€μž μ •μƒμ μœΌλ‘œ λ™μž‘ν•˜μ§€ μ•ŠμœΌλ‹ˆ λ°˜λ“œμ‹œ ν¬μŠ€νŒ…μ— κΈ°μˆ λœλŒ€λ‘œ 직접 GDBλ₯Ό λΉŒλ“œν•΄ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.) μš°λΆ„νˆ¬μ™€ 같은 λ°λΉ„μ•ˆ 계열이라면 gdb-multiarchλ₯Ό, μ•„μΉ˜λ¦¬λˆ…μŠ€λΌλ©΄ AUR 내에 μžˆλŠ” 컴파일러 νŒ¨ν‚€μ§€λ“€μ„ μ΄μš©ν•˜μž.

λ¨Όμ €, kdmx λ₯Ό μ΄μš©ν•˜μ—¬ μ‹œλ¦¬μ–Ό 톡신이 μ œλŒ€λ‘œ demuxing 되고 μžˆλ‹€λŠ” κ°€μ • ν•˜μ— μ§„ν–‰ν•œλ‹€. λ‹¨μˆœν•˜κ²Œ kgdb의 λ™μž‘μ„ ν…ŒμŠ€νŠΈν•  λͺ©μ μ΄λ―€λ‘œ, sysrq λ₯Ό μ΄μš©ν•˜μ—¬ kdb에 μ§„μž…ν•˜μ—¬ kgdbλ₯Ό 뢙인 λ’€ 고의둜 컀널 νŒ¨λ‹‰μ„ λ°œμƒμ‹œμΌœ gdb둜 μ–΄λ–»κ²Œ 뢄석 κ°€λŠ₯ν•œμ§€λ₯Ό 보일 것이닀.

λ¨Όμ €, kgdb μ—μ„œ μ‚¬μš©ν•  μ‹œλ¦¬μ–Όμ„ μ•„λž˜μ™€ 같이 μ„€μ •ν•΄μ€€λ‹€.

1
2
3
root@raspberrypi:/home/pi# who | awk '{print $2}' > /sys/module/kgdboc/parameters/kgdboc
root@raspberrypi:/home/pi# cat /sys/module/kgdboc/parameters/kgdboc
ttyS0

이제 sysrq λ₯Ό μ΄μš©ν•˜μ—¬ KDB둜 μ§„μž…ν•œ λ’€ kgdb λ₯Ό μ‹€ν–‰ν•œλ‹€.

1
2
3
4
5
6
7
8
9
root@raspberrypi:/home/pi# echo g > /proc/sysrq-trigger
[ 1141.184978] sysrq: DEBUG

Entering kdb (current=0x836b8000, pid 552) on processor 0 due to Keyboard Entry
[0]kdb>

[0]kdb>
[0]kdb> kgdb
Entering please attach debugger or use + or

이제 ν˜ΈμŠ€νŠΈμ—μ„œ GDBλ₯Ό μ‹€ν–‰ν•œ λ’€ μ‹œλ¦¬μ–Ό ν†΅μ‹ μœΌλ‘œ λΆ™μ—¬μ€€λ‹€. μ•„λž˜μ™€ 같이 μ •μƒμ μœΌλ‘œ attach κ°€ 된 것을 μ•Œ 수 μžˆλ‹€.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ ./arm-linux-gnueabihf-gdb ~/Workspaces/rpi/vmlinux
(gdb) file ~/Workspace/rpi/vmlinux
(gdb) cd /Volumes/Kernel/rpi_kernel
(gdb) target remote /dev/ttys003
Remote debugging using /dev/ttys003
warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread
[Switching to Thread 4294967294]
arch_kgdb_breakpoint () at ./arch/arm/include/asm/kgdb.h:46
warning: Source file is more recent than executable.
46		asm(__inst_arm(0xe7ffdeff));
(gdb)

끝맺음 πŸ”—

ν˜„μ—…μ—μ„œ λ‹€λ₯Έ μ‚¬λžŒλ“€μ˜ 디버깅 방법을 λ³΄λ©΄μ„œ κ°€μž₯ λ‹΅λ‹΅ν•œ 뢀뢄은 디버깅 μ‹œμ— νˆ΄μ„ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 점이닀. λͺ‡λͺ‡ μŠ€νƒ€ 개발자의 경우 디버깅 νˆ΄μ„ μ‹«μ–΄ν•˜κ³  둜그 λ©”μ‹œμ§€λ§ŒμœΌλ‘œλ„ μΆ©λΆ„ν•˜λ‹€κ³  ν•˜λŠ”λ° κ°œμΈμ μœΌλ‘œλŠ” μ΄λŸ¬ν•œ μ˜κ²¬μ— λ°˜λŒ€ν•œλ‹€. 둜그 λ©”μ‹œμ§€λ₯Ό μ΄μš©ν•˜μ—¬ 문제λ₯Ό ν•΄κ²°ν•˜λŠ” λ°©ν–₯을 μ„Έμš°κ³  λΆ„μ„ν•˜λŠ” 것도 μ€‘μš”ν•˜μ§€λ§Œ, κ·ΈλŸ¬ν•œ 문제 해결에 도움을 μ£ΌλŠ” 도ꡬλ₯Ό μ΄μš©ν•˜μ—¬ λΆˆν•„μš”ν•œ μ‹œκ°„μ„ μ€„μ΄λŠ” 것도 μ€‘μš”ν•˜λ‹€. λ¬Όλ‘ , κ·Έλ“€μ²˜λŸΌ λ˜‘λ˜‘ν•˜μ§€ μ•Šμ€ 것도 μ€‘μš”ν•œ μ΄μœ λ‹€.