sirve - ¿Depuración del kernel de Linux en vivo, cómo se hace y qué herramientas se usan?
que es linux (10)
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 bloqueo. Estos registros pueden analizarse más a fondo para determinar la causa raíz del bloqueo. Recursos con respecto a LKCD
- http://www-01.ibm.com/support/knowledgecenter/linuxonibm/liaax/lkcd.pdf
- https://www.novell.com/coolsolutions/feature/15284.html
- https://www.novell.com/support/kb/doc.php?id=3044267
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 pila y otros. Recursos con respecto al núcleo Ups
- https://www.kernel.org/doc/Documentation/oops-tracing.txt
- http://madwifi-project.org/wiki/DevDocs/KernelOops
- https://wiki.ubuntu.com/DebuggingKernelOops
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 pila) que se ejecuta cuando el control alcanza el punto dado. Recursos relacionados con Dynamic Probe enumerados a continuación
- http://www-01.ibm.com/support/knowledgecenter/linuxonibm/liaax/dprobesltt.pdf
- http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.107.6212&rep=rep1&type=pdf
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
- http://elinux.org/Linux_Trace_Toolkit
- http://www.linuxjournal.com/article/3829
- http://multivax.blogspot.com/2010/11/introduction-to-linux-tracing-toolkit.html
MEMWATCH es una herramienta de detección de errores de memoria de código abierto. Funciona al definir MEMWATCH en la declaración de gcc y al agregar un archivo de encabezado a nuestro código. A través de esto podemos rastrear fugas de memoria 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 programació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 dinámico 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 pila. 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 programa.
- http://www.ellexus.com/getting-started-with-ltrace-how-does-it-do-that/?doing_wp_cron=1425295977.1327838897705078125000
- http://developerblog.redhat.com/2014/07/10/ltrace-for-rhel-6-and-7/
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
- http://www.drdobbs.com/open-source/linux-kernel-debugging/184406318
- http://elinux.org/KDB
- http://dev.man-online.org/man1/kdb/
- https://www.kernel.org/pub/linux/kernel/people/jwessel/kdb/usingKDB.html
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 pila 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
¿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 against 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.
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.
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.
En realidad, la broma es que Linux ha tenido un depurador en núcleo desde 2.2.12, xmon
, pero solo para la arquitectura 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
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:
- No afectan el sistema, es decir, cuando se golpea una ubicación, simplemente excede el código, no detiene todo el kernel.
- 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.
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
compilado con información de depuración (puede echar un vistazo a this 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 reprogramació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:
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 compila.
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.
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:
Compila 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.
Agregue a su comando QEMU:
-append ''kgdbwait kgdboc=ttyS0,115200'' / -serial tcp::1234,server,nowait
Ejecute GDB desde la raíz del árbol fuente del kernel de Linux con:
gdb -ex ''file vmlinux'' -ex ''target remote localhost:1234''
En GDB:
(gdb) c
y el arranque debería terminar.
En QEMU:
echo g > /proc/sysrq-trigger
Y GDB debería romperse.
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 compilar el kernel como se explica en https://www.raspberrypi.org/documentation/linux/kernel/building.md Desafortunadamente, faltan opciones en la compilación predeterminada del kernel, especialmente sin símbolos de depuración, por lo que la recompilació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 programa, 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 compila el kernel.
Pero las API de nivel superior fuera de
ARCH
detalles deARCH
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
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:
- 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.9
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
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: 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
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
- ¿Cómo depurar el kernel de Linux con GDB y QEMU?
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