¿Cómo depurar el kernel de Linux con GDB y QEMU?
linux-kernel (5)
Cuando intentas iniciar vmlinux exe usando gdb, lo primero que hace gdb es emitir cmds:
(gdb) target localhost local: 1234
(gdb) rompe start_kernel
(continuar)
Esto romperá el kernel en start_kernel.
Soy nuevo en el desarrollo del kernel y me gustaría saber cómo ejecutar / depurar el kernel de Linux utilizando QEMU y gdb. De hecho, estoy leyendo el libro de Robert Love, pero desafortunadamente no ayuda al lector sobre cómo instalar las herramientas adecuadas para ejecutar o depurar el kernel ... Entonces, lo que hice fue seguir este tutorial http://opensourceforu.efytimes.com/2011/02/kernel-development-debugging-using-eclipse/ . Estoy usando eclipse como un IDE para desarrollar en el kernel, pero primero quería que funcione en QEMU / gdb. Entonces, lo que hice hasta ahora fue:
1) Para compilar el kernel con:
make defconfig (then setting the CONFIG_DEBUG_INFO=y in the .config)
make -j4
2) Una vez que la compilación termina, ejecuto Qemu usando:
qemu-system-x86_64 -s -S /dev/zero -kernel /arch/x86/boot/bzImage
que lanzan el kernel en estado "detenido"
3) Por lo tanto, tengo que usar gdb, intento el siguiente comando:
gdb ./vmlinux
que lo ejecuta correctamente pero ... Ahora no sé qué hacer ... Sé que tengo que usar la depuración remota en el puerto 1234 (puerto predeterminado utilizado por Qemu), usando vmlinux como el archivo de tabla de símbolos para depuración
Entonces mi pregunta es: ¿qué debo hacer para ejecutar kernel en Qemu, adjuntar mi depurador y así lograr que funcionen juntos para facilitar mi vida con el desarrollo del kernel?
En cuanto a mí, la mejor solución para depurar el kernel es usar gdb del entorno Eclipse. Solo debes establecer el puerto apropiado para gdb (debe ser el mismo que el especificado en qemu cadena de ejecución) en la sección de depuración remota. Aquí está el manual: http://www.sw-at.com/blog/2011/02/11/linux-kernel-development-and-debugging-using-eclipse-cdt/
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, veo 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 diferentes modos de CPU (modo real en BIOS vs. modo largo cuando Linux arranca). 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, tuve que interrumpir algo durante el arranque, así que después de algunos 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
permite especificar comandos que deben ejecutarse cuando se inician. Esto hace que la automatización sea un poco más fácil. Para conectarse a QEMU (que ya debería haberse iniciado), interrumpir una función y continuar la ejecución, use:
gdb -ex ''target remote localhost:1234'' -ex ''break rapl_pmu_init'' -ex c ./vmlinux
Lo 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 sea echar un vistazo a un tutorial decente de GDB para llevarse bien con lo que está haciendo. Este se ve bastante bien.
Procedimiento paso a paso probado en el host Ubuntu 16.10
Para empezar desde cero rápidamente, he realizado un ejemplo mínimo de QEMU + Buildroot completamente automatizado en: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/c7bbc6029af7f4fab0a23a380d1607df0b2a3701/gdb-step-debugging.md los pasos están cubiertos a continuación.
Primero obtenga un sistema de archivos raíz rootfs.cpio.gz
. Si necesita uno, considere:
- una
init
mínima, 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 ver 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, se necesitaba hbreak
, se ignoraron los breakpoints del software break
. Ya no es el caso en 16.10. Ver también: https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944
La disconnect
desordenada y lo que viene después son para evitar 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 remota del paquete ''g'' es demasiado larga
- http://wiki.osdev.org/QEMU_and_GDB_in_long_mode osdev.org es, como de costumbre, una fuente increíble 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 optimizar el kernel de Linux y compilarlo con -O0? - GDB 7.11 hará estallar su memoria en algunos tipos de finalización de pestañas, incluso después de la corrección de
max-completions
: Interrupción de finalización de pestañas para binarios grandes Probablemente algún caso de esquina que no estaba cubierto en ese parche. Entonces, unulimit -Sv 500000
es una acción inteligente antes de la depuración. Sopló específicamente cuandosys_execve
file<tab>
para el argumento defilename
defilename
desys_execve
como en: https://.com/a/42290593/895245
Ver 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 del kernel de Linux en vivo, cómo se hace y qué herramientas se usan?