GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo depurar el kernel de Linux con GDB y QEMU?

Yo intentaría:

(gdb) target remote localhost:1234
(gdb) continue

El uso de la opción '-s' hace que qemu escuche en el puerto tcp::1234, al que puede conectarse como localhost:1234 si está en la misma máquina. La opción '-S' de Qemu hace que Qemu detenga la ejecución hasta que usted dé el comando de continuar.

Lo mejor probablemente sería echar un vistazo a un tutorial GDB decente para llevarse bien con lo que está haciendo. Este se ve bastante bien.


Procedimiento paso a paso probado en host Ubuntu 16.10

Para comenzar desde cero rápidamente, hice un ejemplo mínimo de QEMU + Buildroot totalmente automatizado en:https://github.com/cirosantilli/linux-kernel-module-cheat/blob/c7bbc6029af7f4fab0a23a380d1607df0b2a3701/gdb-step-debugging.md Mayor Los pasos se describen a continuación.

Primero obtenga un sistema de archivos raíz rootfs.cpio.gz . Si necesita uno, considere:

  • un init mínimo -solo imagen ejecutable:https://unix.stackexchange.com/questions/122717/custom-linux-distro-that-runs-just-one-program-nothing-else/238579#238579
  • un sistema interactivo Busybox:https://unix.stackexchange.com/questions/2692/what-is-the-smallest-possible-linux-implementation/203902#203902

Luego en el kernel de Linux:

git checkout v4.15
make mrproper
make x86_64_defconfig
cat <<EOF >.config-fragment
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_GDB_SCRIPTS=y
EOF
./scripts/kconfig/merge_config.sh .config .config-fragment
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage \
                   -initrd rootfs.cpio.gz -S -s \
                   -append nokaslr

En otra terminal, desde el interior del árbol del kernel de Linux, supongamos que desea iniciar la depuración desde start_kernel :

gdb \
    -ex "add-auto-load-safe-path $(pwd)" \
    -ex "file vmlinux" \
    -ex 'set arch i386:x86-64:intel' \
    -ex 'target remote localhost:1234' \
    -ex 'break start_kernel' \
    -ex 'continue' \
    -ex 'disconnect' \
    -ex 'set arch i386:x86-64' \
    -ex 'target remote localhost:1234'

¡¡y hemos terminado!!

Para los módulos del kernel, consulte:¿Cómo depurar los módulos del kernel de Linux con QEMU?

Para Ubuntu 14.04, GDB 7.7.1, hbreak se necesitaba, break Se ignoraron los puntos de interrupción del software. Ya no es el caso en 16.10. Consulte también:https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944

El desordenado disconnect y lo que viene después es solucionar el error:

Remote 'g' packet reply is too long: 000000000000000017d11000008ef4810120008000000000fdfb8b07000000000d352828000000004040010000000000903fe081ffffffff883fe081ffffffff00000000000e0000ffffffffffe0ffffffffffff07ffffffffffffffff9fffff17d11000008ef4810000000000800000fffffffff8ffffffffff0000ffffffff2ddbf481ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000

Temas relacionados:

  • https://sourceware.org/bugzilla/show_bug.cgi?id=13984 podría ser un error de GDB
  • La respuesta del paquete 'g' remoto es demasiado larga
  • http://wiki.osdev.org/QEMU_and_GDB_in_long_mode osdev.org es, como de costumbre, una excelente fuente para estos problemas
  • https://lists.nongnu.org/archive/html/qemu-discuss/2014-10/msg00069.html
  • nokaslr :https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb/421287#421287

Limitaciones conocidas:

  • el kernel de Linux no es compatible (y ni siquiera compila sin parches) con -O0 :¿Cómo desoptimizar el kernel de Linux y compilarlo con -O0?
  • GDB 7.11 te hará perder la memoria en algunos tipos de finalización de pestañas, incluso después del max-completions corrección:Interrupción de finalización de tabulación para binarios grandes Probablemente algún caso de esquina que no se cubrió en ese parche. Así que un ulimit -Sv 500000 es una sabia acción antes de la depuración. Explotó específicamente cuando tabulé completando file<tab> para el filename argumento de sys_execve como en:https://stackoverflow.com/a/42290593/895245

Véase también:

  • https://github.com/torvalds/linux/blob/v4.9/Documentation/dev-tools/gdb-kernel-debugging.rst "documentación" oficial del kernel de Linux
  • Depuración en vivo del kernel de Linux, ¿cómo se hace y qué herramientas se utilizan?

La respuesta de BjoernID realmente no funcionó para mí. Después de la primera continuación, no se alcanza ningún punto de interrupción y en la interrupción, vería líneas como:

0x0000000000000000 in ?? ()
(gdb) break rapl_pmu_init
Breakpoint 1 at 0xffffffff816631e7
(gdb) c
Continuing.
^CRemote 'g' packet reply is too long: 08793000000000002988d582000000002019[..]

Supongo que esto tiene algo que ver con los diferentes modos de CPU (modo real en BIOS versus modo largo cuando Linux ha arrancado). De todos modos, la solución es ejecutar QEMU primero sin esperar (es decir, sin -S ):

qemu-system-x86_64 -enable-kvm -kernel arch/x86/boot/bzImage -cpu SandyBridge -s

En mi caso, necesitaba romper algo durante el arranque, así que después de unos decisegundos, ejecuté el comando gdb. Si tiene más tiempo (por ejemplo, necesita depurar un módulo que se carga manualmente), entonces el tiempo realmente no importa.

gdb le permite especificar los comandos que deben ejecutarse cuando se inicia. Esto hace que la automatización sea un poco más fácil. Para conectarse a QEMU (que ahora ya debería estar iniciado), interrumpa una función y continúe con la ejecución, use:

gdb -ex 'target remote localhost:1234' -ex 'break rapl_pmu_init' -ex c ./vmlinux

Linux
  1. Cómo depurar programas C en Linux usando gdb

  2. Cómo crear un alias y usar el comando Alias ​​en Linux

  3. Cómo capturar sesiones de terminal y salida con el comando de script de Linux

  4. Linux:¿cómo sabe el kernel de Linux los números mayores y menores de los dispositivos?

  5. ¿Cómo leer, comprender, analizar y depurar un kernel panic de Linux?

Cómo usar el comando de suspensión de Linux con ejemplos

Cómo usar el comando who en Linux con ejemplos

Cómo verificar la versión del kernel en Linux

Encuentre el nombre de distribución de Linux, la versión y los detalles del kernel

Cómo encontrar archivos con el comando fd en Linux

Cómo instalar y asegurar Apache con HTTPS en Fedora Linux