Using KGDB to debug Linux

While user-space programs can be debugged with regular GDB (in combination with gdbserver), this is not the case for debugging the kernel. gdbserver is a user-space program itself and cannot control the kernel. KGDB, Kernel GDB, solves this by acting as a gdbserver that is inside the kernel.

Configuring the Kernel for KGDB

Your kernel configuration needs to have the following options set:

CONFIG_KGDB
CONFIG_KGDB_SERIAL_CONSOLE

Kernel command line

Use the kgdboc option on the kernel boot args to tell KGDB which serial port to use. Kernel bootargs can be modified in the DTS file or can be passed via bootloader if it is used.

Examples:

  • One serial port, KGDB is shared with console: console=ttyS0,115200n8 kgdboc=ttyS0,115200
  • Two serial ports, one for console, another for KGDB: console=ttyS0,115200n8 kgdboc=ttyS1,115200

These examples assume you want to attach gdb to the kernel at a later stage. Alternatively, you can add the kgdbwait option to the command line. With kgdbwait, the kernel waits for a debugger to attach at boot time. In the case of two serial ports, the kernel command line looks like the following:

console=ttyS0,115200n8 kgdboc=ttyS1,115200 kgdbwait

Connect from GDB

After the kernel is set up, you can start the debugging session. To connect to your target using a serial connection, you need to have a development PC with UART that runs GDB and a terminal program.

Stop the Kernel

First, stop the kernel on the target using a SysRq trigger. To do so, send a remote break command using your terminal program, followed by the character g: * using minicom: Ctrl-a, f, g * using Tera Term: Alt-b, g

You must also stop the kernel if you have two UARTs, even though one of the two UARTs is dedicated to KGDB.

Connect GDB

After stopping the kernel, connect GDB:

$ arc-elf32-gdb vmlinux
(gdb) set remotebaud 115200
(gdb) target remote /dev/ttyUSB0

You are then connected to the target and can use GDB like any other program. For instance, you can set a breakpoint now using b <identifier> and then continue kernel execution again using c.