El proceso es prácticamente el indicado de forma extensa aquí salvo que esta vez no vamos a generar paquetes deb para instalar el kernel. Esta vez vamos a modificar un par de opciones en el kernel y compilaremos sin generar paquetes deb.
La finalidad es arrancar con ese kernel con qemu con modo debug (ver aquí como compilar qemu con opción debug).
Compilando el kernel con las opciones Kernel debug
Lo ideal es realizar esto sobre una máquina virtual limpia (ver aquí como).
Instalamos dependencias
# apt install -y wget xz-utils make gcc ncurses-dev flex bison devscripts bc rsync libelf-dev libssl-dev dwarves hwinfo
Descargamos el kernel
$ kernelUrlXz="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.1.tar.xz"
$ wget "$kernelUrlXz"
Descomprimimos el kernel
$ tar xfvJ linux-5.15.1.tar.xz
Copiamos la configuración actual del kernel actual como base
$ cd linux-5.15.1
$ apt clean
$ apt autoclean
$ make clean && make mrproper
$ cp /boot/config-$(uname -r) ./.config
Cargamos la configuración para realizar algunos cambios (activamos Compile the kernel with debug info y Provide GDB scripts for kernel debugging)
CONFIG_DEBUG_INFO=y
CONFIG_GDB_SCRIPS=y
CONFIG_DEBUG_KERNEL=y
$ make menuconfig
Estarán dentro de Kernel hacking y Compile-time checks and compiler options. Luego seguimos sin olvidarnos de guardar (save).
Aunque en la foto sale marcado se ha de desmarcar: «Strip assembler-generated symbols during link».
En www.kernelconfig.io/ vamos a poder ver lo que es cada opción.
Eliminamos la línea de CONFIG_SYSTEM_TRUSTED_KEYS
$ grep -i "CONFIG_SYSTEM_TRUSTED_KEYS" .config
$ sed -i '/CONFIG_SYSTEM_TRUSTED_KEYS/d' .config
Compilamos el kernel
$ make -j$(nproc) LOCALVERSION="-fanta"
$ make -j$(nproc) LOCALVERSION="-fanta" modules_install
Si todo va bien finalmente obtendremos el kernel: vmlinux . Ese kernel es el que vamos a utilizar de modo que si hemos compilado dentro de una máquina virtual hemos de sacarlo de allí.
Al hacer un «file vmlinux» veremos algo así como esto:
vmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=0640dce80e92c0eb885b4267063cdcf18517de15, with debug_info, not stripped
Lo interesante es que es un kernel compilado con debug info y «not stripped».
Necesitaremos un ramdisk
Creando disco RAM
mkinitramfs -o ramdisk.img
Lanzar el kernel con Qemu
$ /usr/local/bin/qemu-system-x86_64 -gdb tcp::1234 -S -m 512M -kernel vmlinux -initrd ramdisk.img -append nokaslr -append "console=ttyS0" -nographic
De esta forma lanzaremos el qemu que compilamos para disponer de opción debug.
Con -gdb tcp::1234
ponemos el gdbserver que lleva Qemu a la escucha en el 1234 .
Con -S se paraliza nada más comenzar.
Con -m indicamos que dispone la máquina de 512 Megas de RAM (más que suficientes).
Con -kernel indicamos la ruta en la que tenemos compilado el kernel.
Con -initrd el ramdisk
Redirigimos la salida a ttyS0 e indicamos que no se ejecute en una ventana y si en modo texto en el terminal que estemos usando.
Ejecutar GDB remote
Mientras está funcionando (en espera) la máquina virtual con el kernel podemos conectar con gdb así:
$ gdb vmlinux -ex 'set arch i386:x86-64:intel' -ex 'target remote localhost:1234' -ex 'break start_kernel' -ex 'continue'
Este comando es buena cosa pero es largo. Quizás simplemente te interesa hacerlo así:
$ gdb
target remote :1234
c
Con «c» y «control + c» podemos controlar el control de flujo. Con «c» continuamos la ejecución y con control+c paralizamos.
Se pueden añadir break points. Por ejemplo: hb start_kernel
Y eso es lo que quería comentar.
Espero le sea de ayuda. Un saludo cordial.