Assumptions: Host machine is linux.
- Download virtualbox
- Install a linux flavour. Preference for Debian since distro-dependent commands in the following steps will be debian-dependent
- Run your VM.
- Inside VM, download last kernel code from kernel.org
- Extract linux src code
- Copy your configuration file from
/boot/config-$(uname -r)
to.config
in the extract linux src code folder. - Make sure
.config
has the following options: CONFIG_FRAME_POINTER=y , CONFIG_KGDB=y , CONFIG_KGDB_SERIAL_CONSOLE=y , CONFIG_KGDB_KDB=y , CONFIG_KDB_KEYBOARD=y. Change if necessary. Alternatively usemake xconfig
to configure in UI. - Install compilation dependencies (debian:
sudo apt-get install build-essential libncurses-dev bison flex libssl-dev libelf-dev
) - Compile the kernel:
make -j8
- Compile kernel modules:
sudo make modules_install
- Install kernel to
/boot
:sudo make install
- Output will be in
/boot
directory. GRUB needs to be updated. On debian, run:sudo update-initramfs -c -k <KERNEL VERSION>
. Example:sudo update-initramfs -c -k 5.6.9
- After that, run
sudo update-grub
. - For more info about the compilation part, here: https://www.cyberciti.biz/tips/compiling-linux-kernel-26.html
- Go back to linux src folder and find the compiled file
vmlinux
. Send this file to your host machine, either usingscp
or virtualbox shared folders. - Reboot the VM. Afterwards, run
uname -rms
. You should see the new just-compiled version. - Run
sudo vim /etc/default/grub
- Append to
GRUB_CMDLINE_LINUX_DEFAULT
the following parameters:kgdboc=ttyS0,115200 nokaslr
. The first parameter tells the debugger to be active on serial port/dev/ttyS0
. The second one tells to load the kernel without address space layout randomization, so the debugger can find the function addresses properly. Example:GRUB_CMDLINE_LINUX_DEFAULT=quiet splash kgdboc=ttyS0,115200 nokaslr
. - Run
sudo update-grub
. - Turn off the VM.
- On the host machine, open VM settings and go to Serial Ports. Go to tab
Port 1
. MarkEnable serial port
. ChoosePort Number=COM1
,Port Mode=Host Pipe
and Path/Address=/tmp/pipe
. Don't markConnect to existing pipe/socket.
- Run the VM again.
- Open a terminal in the VM and go to su mode by running
sudo su
- Run
echo g > /proc/sysrq-trigger
to make the kernel execution stop and wait for the debugger to be attached. Note that once you run this command, the VM will be frozen until you continue the execution using GDB later. - On the host machine, run
socat -d /tmp/pipe TCP4-LISTEN:65335
. This will create a TCP connection from the/tmp/pipe
. Even though GDB supports connecting directly to serial ports, the/tmp/pipe
is a UNIX socket, so GDB does not recognize it as a serial port. Usingsocat
we can create a TCP connection and connect using GDB. - Now run GDB via
gdb ./vmlinux
where./vmlinux
is the path to the kernel binary file that you copied before. - In GDB run
target remote localhost:65335
. - At this point the debugger should be attached. Put breakpoints using
break
and typecontinue
to resume the kernel execution in the VM.
Wonderful! Thanks for sharing.