Building Android Kernel

Overview

Goal : Build a development setup in which the target machine runs a KGDB-enabled Android kernel with a Buildroot-based root file system under QEMU, while the host machine runs GDB and ADB to debug the kernel and interact with the target system.

1. Environment setup

Create a working directory.

mkdir androidDebugging && cd androidDebugging

2. Kernel building

Download the kernel

Download the kernel from the Android Common Kernel (ACK) repository. ACK kernels are stable and have strong community and upstream support.

Choose the kernel version according to your Android target.

git clone \
  --depth 1 \
  --branch android12-5.10.149_r00 \
  https://android.googlesource.com/kernel/common
cd common

Install dependencies and cross-compilation tools

Install the required build dependencies. The command below is for Fedora-based systems.

sudo dnf install \
  git bc bison flex elfutils-libelf-devel \
  ncurses-compat-libs gcc-aarch64-linux-gnu \
  qemu-system-aarch64 make \
  openssl-devel openssl-devel-engine

Generate the default kernel configuration.

ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make defconfig

Append the following options to the end of the .config file to enable KGDB, debugging symbols, and serial console support.

CONFIG_CMDLINE="console=ttyAMA0"
CONFIG_CMDLINE_FROM_BOOTLOADER=y
# CONFIG_CMDLINE_EXTEND is not set
# CONFIG_CMDLINE_FORCE is not set

CONFIG_KPROBES=y
CONFIG_KRETPROBES=y

CONFIG_CONSOLE_POLL=y
CONFIG_DEBUG_INFO_REDUCED=y
CONFIG_GDB_SCRIPTS=y

CONFIG_KGDB=y
CONFIG_KGDB_HONOUR_BLOCKLIST=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=y
CONFIG_KDB_DEFAULT_ENABLE=0x1
CONFIG_KDB_CONTINUE_CATASTROPHIC=0

CONFIG_FUNCTION_ERROR_INJECTION=y
CONFIG_ANDROID=y

Validate and normalize the configuration.

ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make olddefconfig

Compile the kernel

ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc) vmlinux Image

Compilation typically takes 10–20 minutes depending on hardware.

After a successful build, the following files are generated:

  • vmlinux (uncompressed ELF with debug symbols)
  • arch/arm64/boot/Image (bootable kernel image)

3. Create a root filesystem

Download Buildroot

cd ..
wget https://buildroot.org/downloads/buildroot-2025.05.1.tar.gz
tar xf buildroot-2025.05.1.tar.gz
cd buildroot-2025.05.1
make menuconfig

Configure Buildroot

Apply the following configuration:

  • Target ArchitectureAArch64 (little endian)
  • Target Architecture Variantcortex-A53 (found under Target options)
  • Filesystem Images → enable ext2/3/4 root filesystem
  • System configuration → set a root password
  • Target packages → Networking applications
    • enable dhcpd
    • enable iproute2
    • enable dropbear
    • enable `openssh
  • Target packages -> System Tools
    • enable android-tools

Build the filesystem. This may take 20–60 minutes.

make

The generated root filesystem image will be located at:

output/images/rootfs.ext2

4. Emulation using QEMU

Install QEMU

sudo dnf install qemu-system-arm

Create the run script

From the androidDebugging directory, create the script.

touch run.sh
#!/bin/bash
set -euo pipefail

QEMU="qemu-system-aarch64"
KERNEL="common"
ROOTFS="buildroot-2025.05.1/output/images/rootfs.ext2"

# sanity checks
if [ ! -f "$KERNEL/arch/arm64/boot/Image" ]; then
  echo "ERROR: kernel not found: $KERNEL/arch/arm64/boot/Image" >&2
  exit 1
fi
if [ ! -f "$ROOTFS" ]; then
  echo "ERROR: rootfs not found: $ROOTFS" >&2
  exit 1
fi

ARGS=()

# Core machine setup
ARGS+=("-machine" "virt")
ARGS+=("-cpu" "cortex-a53")
ARGS+=("-m" "2048")
ARGS+=("-nographic")

# Enable GDB server on tcp::1234
ARGS+=("-s")

# Kernel & rootfs
ARGS+=("-kernel" "$KERNEL/arch/arm64/boot/Image")
ARGS+=("-drive" "file=$ROOTFS,format=raw,if=virtio")

# Kernel command line
ARGS+=("-append" "console=ttyAMA0 earlycon root=/dev/vda rw")

# Networking for ADB over TCP (forward host 5555 -> guest 5555)
ARGS+=("-netdev" "user,id=net0,hostfwd=tcp::5555-:5555")
ARGS+=("-device" "virtio-net,netdev=net0")

# Optional freeze flag (halt CPU at reset)
for opt in "$@"; do
  case "$opt" in
    freeze)
      ARGS+=("-S")
      ;;
    *)
      echo "Warning: unknown option '$opt' (supported: freeze)" >&2
      ;;
  esac
done

echo "Running: $QEMU ${ARGS[*]}"
exec "$QEMU" "${ARGS[@]}"

Make the script executable.

chmod +x run.sh

5. Running the kernel with GDB

Open two terminal windows.

Terminal 1: Start QEMU (target)

./run.sh freeze

Terminal 2: Start GDB (host)

gdb common/vmlinux
(gdb) set architecture aarch64
(gdb) target remote 127.0.0.1:1234
(gdb) continue

At this point, the kernel boots under QEMU and can be debugged using GDB.

Terminal 1: Login and Run adbd

adbd --tcpip 5555

Terminal 3: ADB

adb connect localhost:5555
adb devices
adb shell

References