¿Depuración del kernel de Linux en vivo, cómo se hace y qué herramientas se usan?

¿Cuáles son los métodos y las herramientas más comunes y por qué no poco comunes que se usan para realizar la depuración en vivo en el kernel de Linux? Sé que Linus por ej. está en contra de este tipo de depuración para el kernel de Linux o menos y por lo tanto no se ha hecho mucho en ese sentido en esos años, pero honestamente ha pasado mucho tiempo desde 2000 y estoy interesado si esa mentalidad ha cambiado con respecto a Linux proyecto y qué métodos actuales se utilizan para depurar en vivo en el kernel de Linux en este momento (ya sea local o remoto)?

Las referencias a tutoriales y tutoriales sobre las técnicas y herramientas mencionadas son bienvenidas.

Otra opción es usar el controlador ICE / JTAG y GDB. Esta solución de ‘hardware’ se usa especialmente con sistemas integrados,

pero, por ejemplo, Qemu ofrece características similares:

  • Inicie qemu con un código auxiliar ‘remoto’ de gdb que escuche en ‘localhost: 1234’: qemu -s ... ,

  • luego con GDB abre el archivo kernel vmlinux comstackdo con información de depuración (puede echar un vistazo a este hilo de la lista de correo donde discuten la desoptimización del kernel).

  • conectar GDB y Qemu: target remote localhost:1234

  • veo que eres un núcleo en vivo :

     (gdb) where #0 cpu_v7_do_idle () at arch/arm/mm/proc-v7.S:77 #1 0xc0029728 in arch_idle () atarm/mach-realview/include/mach/system.h:36 #2 default_idle () at arm/kernel/process.c:166 #3 0xc00298a8 in cpu_idle () at arch/arm/kernel/process.c:199 #4 0xc00089c0 in start_kernel () at init/main.c:713 

desafortunadamente, la depuración del espacio de usuario no es posible hasta ahora con GDB (sin información de listas de tareas, sin reprogtwigción de MMU para ver contextos de proceso diferentes, …), pero si te mantienes en el kernel-space, eso es bastante conveniente.

  • info threads le darán la lista y los estados de las diferentes CPU

EDITAR:

Puede obtener más detalles sobre el procedimiento en este PDF:

Depuración de sistemas Linux usando GDB y QEMU .

Al depurar kernel de Linux, podemos utilizar varias herramientas, por ejemplo, depuradores (KDB, KGDB), volcado mientras está bloqueado (LKCD), juego de herramientas de seguimiento (LTT, LTTV, LTTng), instrumentos kernel personalizados (dprobes, kprobes). En la siguiente sección traté de resumir la mayoría de ellos, espero que esto ayude.

La herramienta LKCD (Linux Kernel Crash Dump) permite que el sistema Linux escriba el contenido de su memoria cuando se produce un locking. Estos registros pueden analizarse más a fondo para determinar la causa raíz del locking. Recursos con respecto a LKCD

Vaya, cuando el núcleo detecta un problema, imprime un mensaje Oops. Tal mensaje es generado por las instrucciones printk en el controlador de fallas (arch / * / kernel / traps.c). Un buffer de anillo dedicado en el kernel utilizado por las sentencias printk. Oops contiene información como, la CPU donde ocurrió el Oops, el contenido de los registros de la CPU, el número de Oops, la descripción, el seguimiento de la stack y otros. Recursos con respecto al núcleo Ups

Dynamic Probes es una de las herramientas de depuración populares para Linux desarrollada por IBM. Esta herramienta permite la colocación de una “sonda” en casi cualquier lugar del sistema, tanto en el espacio del usuario como en el del núcleo. La sonda consiste en algún código (escrito en un lenguaje especializado orientado a la stack) que se ejecuta cuando el control alcanza el punto dado. Recursos relacionados con Dynamic Probe enumerados a continuación

Linux Trace Toolkit es un parche de kernel y un conjunto de utilidades relacionadas que permiten el seguimiento de eventos en el kernel. El seguimiento incluye información de tiempo y puede crear una imagen razonablemente completa de lo que sucedió durante un período de tiempo determinado. Recursos de LTT, LTT Viewer y LTT Next Generation

MEMWATCH es una herramienta de detección de errores de memoria de código abierto. Funciona al definir MEMWATCH en la statement de gcc y al agregar un archivo de encabezado a nuestro código. A través de esto podemos rastrear memory leaks y corrupciones de memoria. Recursos sobre MEMWATCH

ftrace es un buen marco de rastreo para kernel de Linux. ftrace rastrea las operaciones internas del kernel. Esta herramienta incluida en el kernel de Linux en 2.6.27. Con sus diversos complementos de seguimiento, ftrace puede dirigirse a diferentes puntos de seguimiento estáticos, como eventos de progtwigción, interrupciones, E / S mapeadas en memoria, transiciones de estado de alimentación de CPU y operaciones relacionadas con sistemas de archivos y virtualización. Además, el seguimiento dynamic de las llamadas a la función del kernel está disponible, opcionalmente restringible a un subconjunto de funciones mediante globs, y con la posibilidad de generar gráficos de llamadas y proporcionar el uso de la stack. Puede encontrar un buen tutorial de ftrace en https://events.linuxfoundation.org/slides/2010/linuxcon_japan/linuxcon_jp2010_rostedt.pdf

ltrace es una utilidad de depuración en Linux, que se utiliza para mostrar las llamadas que hace una aplicación de espacio de usuario a las bibliotecas compartidas. Esta herramienta se puede utilizar para rastrear cualquier llamada de función de biblioteca dinámica. Se intercepta y registra las llamadas de la biblioteca dinámica que son llamadas por el proceso ejecutado y las señales que son recibidas por ese proceso. También puede interceptar e imprimir las llamadas al sistema ejecutadas por el progtwig.

KDB es el depurador interno del kernel de Linux. KDB sigue una interfaz de estilo shell simplista. Podemos usarlo para inspeccionar memoria, registros, listas de procesos, dmesg e incluso establecer puntos de interrupción para detenernos en una ubicación determinada. A través de KDB podemos establecer puntos de interrupción y ejecutar algunos controles básicos de kernel run ( aunque KDB no es un depurador de nivel de fuente ). Varios recursos útiles con respecto a KDB

KGDB está destinado a ser utilizado como un depurador de nivel de fuente para el kernel de Linux. Se usa junto con gdb para depurar un kernel de Linux. Se requieren dos máquinas para usar kgdb. Una de estas máquinas es una máquina de desarrollo y la otra es la máquina de destino. El núcleo a depurar se ejecuta en la máquina de destino. La expectativa es que gdb se pueda utilizar para “entrar” en el kernel para inspeccionar la memoria, las variables y mirar a través de la información de la stack de llamadas de forma similar a como un desarrollador de aplicaciones usaría gdb para depurar una aplicación. Es posible colocar puntos de corte en el código del kernel y realizar algunos pasos de ejecución limitados. Varios recursos útiles con respecto a KGDB

De acuerdo con la wiki , kgdb se fusionó en el kernel en 2.6.26 que se encuentra en los últimos años. kgdb es un depurador remoto , por lo que lo activa en su kernel y luego adjunta gdb de alguna manera. Digo de alguna manera, ya que parece que hay muchas opciones – ver conectando gdb . Dado que kgdb ahora está en el árbol fuente, yo diría que en adelante esto es lo que quieres usar.

Parece que Linus cedió. Sin embargo, enfatizaría su argumento: debería saber lo que está haciendo y conocer bien el sistema. Esta es la tierra del grano. Si algo sale mal, no obtienes segfault , obtienes cualquier cosa de algún problema oscuro más tarde o todo el sistema baja. Aquí hay dragones. Proceda con cuidado, ha sido advertido.

Otra buena herramienta para la depuración “en vivo” es kprobes / sondas dinámicas.

Esto le permite construir dinámicamente pequeños módulos pequeños que se ejecutan cuando se ejecutan ciertas direcciones, algo así como un punto de interrupción.

La gran ventaja de ellos es:

  1. No afectan el sistema, es decir, cuando se golpea una ubicación, simplemente excede el código, no detiene todo el kernel.
  2. No necesita dos sistemas diferentes interconectados (destino y depuración) como con kgdb

Lo mejor es hacer cosas como llegar a un punto de interrupción y ver qué valores de datos hay, o verificar si las cosas se han cambiado / sobrescrito, etc. Si quiere “pasar por el código”, no lo hace.

En realidad, la broma es que Linux ha tenido un depurador en núcleo desde 2.2.12, xmon , pero solo para la architecture powerpc (en realidad era ppc aquel entonces).

No es un depurador de nivel de fuente, y casi no está documentado, pero aún así.

http://lxr.linux.no/linux-old+v2.2.12/arch/ppc/xmon/xmon.c#L119

Como alguien que escribe mucho código de kernel, tengo que decir que nunca he usado kgdb, y que rara vez uso kprobes, etc.

Todavía es a menudo el mejor enfoque para lanzar algunas printks estratégicas. En kernels más recientes, trace_printk es una buena forma de hacerlo sin spamming dmesg.

Procedimiento paso a paso de QEMU + GDB probado en el host Ubuntu 16.10

Para comenzar desde el principio, hice un ejemplo mínimo de QEMU + Buildroot totalmente automatizado en: https://github.com/cirosantilli/linux-kernel-module-cheat . A continuación se detallan los pasos principales.

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

Luego en el kernel de Linux:

 git checkout v4.9 make mrproper make x86_64_defconfig cat <.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 

En otro terminal, supongamos que quieres 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: 

Temas relacionados:

Ver también:

Limitaciones conocidas

  • el kernel de Linux no es compatible (y ni siquiera comstack sin parches) con -O0 : ¿cómo optimizar el kernel de Linux y comstackrlo con -O0?
  • GDB 7.11 hará estallar su memoria en algunos tipos de finalización de tabs, incluso después de la corrección de max-completions : Interrupción de finalización de tabs para binarios grandes Probablemente algún caso de esquina que no estaba cubierto en ese parche. Entonces, un ulimit -Sv 500000 es una acción inteligente antes de la depuración. Sopló específicamente cuando sys_execve file para el argumento de filename de filename de sys_execve como en: https://stackoverflow.com/a/42290593/895245

KGDB + QEMU paso a paso

KGDB es un subsistema de kernel que le permite depurar el Kernel desde un host GDB.

Mi ejemplo QEMU + Buildroot es una buena manera de probarlo sin hardware real: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/1969cd6f8d30dace81d9848c6bacbb8bad9dacd8#kgdb

Pros y contras contra otros métodos:

  • ventaja vs QEMU:
    • a menudo no tiene emulación de software para su dispositivo ya que a los proveedores de hardware no les gusta lanzar modelos de software precisos para sus dispositivos
    • hardware real mucho más rápido que QEMU
  • ventaja contra JTAG: no hay necesidad de hardware JTAG adicional, más fácil de configurar
  • desventajas frente a QEMU y JTAG: menos visibilidad y más intrusivo. KGDB depende de ciertas partes del kernel que trabajan para poder comunicarse con el host. Entonces, por ejemplo, se descompone en pánico, no se puede ver la secuencia de inicio.

Los pasos principales son:

  1. Comstack el kernel con:

     CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_INFO=y CONFIG_CONSOLE_POLL=y CONFIG_KDB_CONTINUE_CATASTROPHIC=0 CONFIG_KDB_DEFAULT_ENABLE=0x1 CONFIG_KDB_KEYBOARD=y CONFIG_KGDB=y CONFIG_KGDB_KDB=y CONFIG_KGDB_LOW_LEVEL_TRAP=y CONFIG_KGDB_SERIAL_CONSOLE=y CONFIG_KGDB_TESTS=y CONFIG_KGDB_TESTS_ON_BOOT=n CONFIG_MAGIC_SYSRQ=y CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 CONFIG_SERIAL_KGDB_NMI=n 

    La mayoría de ellos no son obligatorios, pero esto es lo que he probado.

  2. Agregue a su comando QEMU:

     -append 'kgdbwait kgdboc=ttyS0,115200' \ -serial tcp::1234,server,nowait 
  3. Ejecute GDB desde la raíz del árbol fuente del kernel de Linux con:

     gdb -ex 'file vmlinux' -ex 'target remote localhost:1234' 
  4. En GDB:

     (gdb) c 

    y el arranque debería terminar.

  5. En QEMU:

     echo g > /proc/sysrq-trigger 

    Y GDB debería romperse.

  6. Ahora que hemos terminado, puedes usar GDB como de costumbre:

     b sys_write c 

Probado en Ubuntu 14.04.

KGDB + Raspberry Pi

La misma configuración que la anterior casi funcionó en una Raspberry Pi 2, Raspbian Jessie 2016-05-27.

Solo tienes que aprender a hacer los pasos QEMU en el Pi, que son fácilmente googleables:

  • agregue las opciones de configuración y vuelva a comstackr el kernel como se explica en https://www.raspberrypi.org/documentation/linux/kernel/building.md Desafortunadamente, faltan opciones en la comstackción predeterminada del kernel, especialmente sin símbolos de depuración, por lo que la recomstackción es necesario.

  • edite cmdline.txt de la partición de arranque y agregue:

     kgdbwait kgdboc=ttyAMA0,115200 
  • conecta gdb a la serie con:

     arm-linux-gnueabihf-gdb -ex 'file vmlinux' -ex 'target remote /dev/ttyUSB0' 

    Si no está familiarizado con el número de serie, consulte esto: https://www.youtube.com/watch?v=da5Q7xL_OTo Todo lo que necesita es un adaptador económico como este . Asegúrese de obtener un shell a través de la serie para asegurarse de que funciona antes de probar KGDB.

  • hacer:

     echo g | sudo tee /proc/sysrq-trigger 

    desde dentro de una sesión SSH, ya que la serie ya está tomada por GDB.

Con esta configuración, pude poner un punto de interrupción en sys_write , pausar la ejecución del progtwig, enumerar la fuente y continuar.

Sin embargo, a veces, cuando lo hice en sys_write GDB simplemente colgó e imprimió este mensaje de error varias veces:

 Ignoring packet error, continuing... 

así que no estoy seguro de si algo está mal con mi configuración, o si esto es esperado debido a lo que está haciendo un proceso en segundo plano en la imagen más compleja de Raspbian.

También me han dicho que trate de deshabilitar el multiprocesamiento con las opciones de arranque de Linux, pero aún no lo he probado.

Modo de usuario Linux (UML)

https://en.wikipedia.org/wiki/User-mode_Linux

Otra virtualización es otro método que permite depurar el código del kernel por pasos.

UML es muy ingenioso: se implementa como un ARCH , al igual que x86 , pero en lugar de utilizar instrucciones de bajo nivel, implementa las funciones ARCH con llamadas al sistema de usuario.

¡El resultado es que puede ejecutar el código de kernel de Linux como un proceso de usuario en un host Linux!

Primero haga un rootfs y ejecútelo como se muestra en: https://unix.stackexchange.com/questions/73203/how-to-create-rootfs-for-user-mode-linux-on-fedora-18/372207#372207

El um defconfig establece CONFIG_DEBUG_INFO=y de manera predeterminada (sí, es algo de desarrollo), así que estamos bien.

En invitado:

 i=0 while true; do echo $i; i=$(($i+1)); done 

En host en otro shell:

 ps aux | grep ./linux gdb -pid "$pid" 

En GDB:

 break sys_write continue continue 

Y ahora usted controla el conteo desde GDB y puede ver el origen como se espera.

Pros:

  • totalmente contenida en el árbol principal del kernel de Linux
  • más ligero que la emulación de sistema completo de QEMU

Contras:

  • muy invasivo, ya que cambia la forma en que se comstack el kernel.

    Pero las API de nivel superior fuera de ARCH detalles de ARCH no deberían modificarse.

  • podría decirse que no es muy activo: ¿se detuvo el proyecto de modo de usuario linux (UML)?

Ver también: https://unix.stackexchange.com/questions/127829/why-would-someone-want-to-run-usermode-linux-uml

kgdb y gdb son casi inútiles para depurar el núcleo porque el código está tan optimizado que no tiene relación con la fuente original y muchos elementos virtuales están optimizados. Esto hace steppijng, por lo tanto, es imposible pasar por la fuente, el examen de variables es imposible y, por lo tanto, es casi imposible.

En realidad, es peor que inútil, en realidad te da información falsa, por lo que el código que estás viendo en el código de ejecución actual es tan desapegado.

Y no, no puedes desactivar las optimizaciones en el kernel, no comstack.

Tengo que decir que, viniendo de un entorno kernel de windows, la falta de un depurador decente es molesto, dado que hay un código basura para mantener.