If you don’t want to read the whole thing, just go to the TLDR section with the precise steps on what and how to install/configure.
Debugging the operation system in real time and seeing how interrupts occurs and threads context switching is a fascinating thing I must say. While working on a PingPorts, I was curious how the OS network stack decides when to send a TCP Reset (RST) packet when nobody listens on the port (spoiler alert! See
tcp_v4_rcv function, which calls
__inet_lookup_skb and branching to
no_tcp_socket). Quickly looking at the TCP/IP implementation in the kernel did not give any specific results, so I decided to setup virtual machine with the latest kernel compiled in debug mode and step in
gdb to observe what is happening there. Here is steps to configure VirtualBox, build the Linux kernel and finally debug using
For the sake of clarity:
Host- The actual physical computer on which a virtual machine is running.
Guest- Virtual machine running on a host.
I’ve used Ubuntu as
guest OS installed on VirtualBox. Make sure you’ve installed Guest Additions on
guest to be able to share compiled kernel with
Shared Folders settings). After the
guest OS is installed, let’s configure the Serial Ports in VirtualBox, so
host can communicate with the
guest, let’s call it
Serial port configuration in VirtualBox
The next step is to install all the required software packages on
guest, needed to build the kernel:
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison
Building Linux Kernel
Go ahead and pick kernel version you want to debug, in my case it was the latest stable version on the time of writing, then, clone the source code on a
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git.
.config file in the kernel source root folder must be adjusted, in order to build the debug version of kernel. First, let’s copy existing kernel configuration in
cp /boot/config-<your_kernel_release> .config to the root folder with the kernel source code. Then, change the following configuration properties by opening
.config file in text editor or running
make menuconfig in a source code root folder:
y. As the name says, this will enable including debug information into output executable modules.
y. This enables built-in kernel debugger.
- Comment out
CONFIG_RANDOMIZE_BASE, to disabled KASLR. This is needed as
gdbwill fail to identify the correct address of symbols, when trying to set breakpoints, using function name, etc.
y. This will create a symbolic link to the
gdbhelper commands and functions for kernel debugging in a source code root folder.
y. This will enable usage of
gdbover the serial console.
Now, the final step is to actually start the build process: switch to the root source code directory and run:
make and then
make modules, this will take some time. Then, once it has been compiled, run the installation process:
sudo make modules_install,
sudo make install and
guest you need to enable debugging support during the boot process by editing the boot settings file:
/etc/default/grub. Just append the following line:
GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 nokaslr kgdboc=kbd,ttyS0,115200" to the end of the file and reboot the
kgdb over serial console.
Now, the next step is to convert the socket created by VirtualBox (
/tmp/debug-pipe) using socat tool to PTY using the following command:
socat -d -d -d -d /tmp/debug-pipe PTY,link=/tmp/debug-pipe-pty.
OK, now the PTY is ready on the
/tmp/debug-pipe-pty and the final step is to start
gdb on a
host and attach it to the
But first, let’s share the
guest kernel source code folder with the
host machine, so
gdb can load the
vmlinux file from this folder.
After the kernel source code folder is available to
host machine, run the following command in kernel source code root folder on a
gdb vmlinux -ex "target remote /tmp/debug-pipe-pty" and immediately run the
echo g > /proc/sysrq-trigger on
guest machine to debug break in
gdb on a
If everything works fine, there must be the following output from
GDB on host system connected to guest
- VirtualBox Setup:
- Install Ubuntu on VirtualBox.
- Install Guest Additions.
- Install required packages:
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison.
- Add serial port:
/tmp/debug-pipein Serial Ports settings.
- Building Linux Kernel:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.giton the
- Copy current kernel config file on
guestto kernel source code root folder:
cp /boot/config-<your_kernel_release> .config.
.configfile in kernel source code root folder:
- Comment out
make modulesin the kernel source code root folder.
- After compilation is finished, run:
sudo make modules_install,
sudo make installand
- Debugger Setup:
GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 nokaslr kgdboc=kbd,ttyS0,115200"to
guestmachine and reboot.
socat -d -d -d -d /tmp/debug-pipe PTY,link=/tmp/debug-pipe-ptyon
- Share the Linux kernel source code folder from
gdb vmlinux -ex "target remote /tmp/debug-pipe-pty"on the
hostmachine in the kernel source code folder.
echo g > /proc/sysrq-triggeron the