Linux Kernel Debugging Setup With Gdb and Qemu

  1. Create a worksplace folder
  2. Download the kernel and compile it with:
1
2
3
4
5
make defconfig
scripts/config -e DEBUG_INFO_DWARF5 -e GDB_SCRIPTS -e FRAME_POINTER
make LLVM=1 -j8
make LLVM=1 scripts_gdb
./scripts/clang-tools/gen_compile_commands.py
  1. Clone buildroot into a different folder (in the parent workspace folder)
  2. Configure it with make nconfig as you want (don’t enable the kernel) and generate an ext4 output file (build it too)
  3. Copy the following file (as a barebone) into the worksplace folder:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/bin/sh

BUILDROOT="buildroot-2023.11.1"
BUILDROOT_EXT="${BUILDROOT}/output/images/rootfs.ext4"
BUILDROOT_OVERLAY="${BUILDROOT}/output/overlay"

set -e

build_action() {
  cd $1
  echo "[*] Building $1"
  make LLVM=1 -j `nproc`
}

build_image_action() {
  cd $1
  echo "[*] Building $1 (as we might want to install modules into the image)"
  make LLVM=1 -j `nproc`
  echo "[*] Building & installing $1 modules"
  make modules_install INSTALL_MOD_PATH="../$BUILDROOT_OVERLAY"
  echo "[*] Building $BUILDROOT"
  cd ..
  cd $BUILDROOT
  make -j `nproc`
}

lsp_action() {
  cd $1
  echo "[*] Generating $1 compile_commands.json"
  ./scripts/clang-tools/gen_compile_commands.py
  echo "[*] Generating $1 cscope"
  make -j `nproc` cscope
}

run_action() {
  echo "[*] Running qemu"
  qemu-kvm -kernel $1/arch/x86_64/boot/bzImage \
	  -drive file=$BUILDROOT_EXT,format=raw \
	  -net nic -net user,hostfwd=tcp::2222-:22 \
	  -nographic \
	  -append "root=/dev/sda console=ttyS0"
}

debug_action() {
  echo "[*] Opening gdb shell"
  foot sh -c "cd $PWD/$1; gdb -ex 'target remote localhost:1234' -ex 'source \
    vmlinux-gdb.py' $PWD/$1/vmlinux" 1>/dev/null 2>/dev/null &
  echo "[*] Running qemu w/gdbserver"
  qemu-system-x86_64 -kernel $1/arch/x86_64/boot/bzImage \
	  -drive file=$BUILDROOT_EXT,format=raw \
	  -nographic \
	  -append "nokaslr root=/dev/sda console=ttyS0" \
	  -S \
	  -s
}

case $1 in
  build) build_action $2;;
  buildimage) build_image_action $2;;
  run) run_action $2;;
  lsp) lsp_action $2;;
  debug) debug_action $2;;
  *)
    echo "[!] Wrong command" ;
    exit 1 ;;
esac
  1. Run ./script debug linux/ (choose the linux kernel folder, that way you can have different versions at the same time).

Note: You will have to add add-auto-load-safe-path <fullpath>/linux/scripts/gdb/vmlinux-gdb.py to your ~/.gdbinit.