¿Cómo incluir el backtrace C en un código de módulo del kernel?
linux-device-driver (4)
Para imprimir el contenido de la pila y un seguimiento hacia el registro del kernel, use la función dump_stack()
en su módulo del kernel. Se declara en linux/kernel.h
en la carpeta de inclusión en el directorio fuente del kernel.
Así que estoy tratando de averiguar qué procesos del kernel están llamando a algunas funciones en un controlador de bloque. Pensé que incluir backtrace () en la biblioteca de C lo haría fácil. Pero estoy teniendo problemas para cargar el retroceso.
Copié esta función de ejemplo para mostrar el backtrace:
http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/063/6391/6391l1.html
Todos los intentos de compilación tienen un error en un lugar u otro que indica que no se puede encontrar un archivo o que las funciones no están definidas.
Aquí es lo que se acerca más.
En el Makefile pongo las directivas del compilador:
-rdynamic -I/usr/include
Si omito el segundo, -I / usr / include, el compilador informa que no puede encontrar el encabezado execinfo.h requerido.
A continuación, en el código donde deseo realizar el seguimiento, copié la función del ejemplo:
//trying to include the c backtrace capability
#include <execinfo.h>
void show_stackframe() {
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
messages = backtrace_symbols(trace, trace_size);
printk(KERN_ERR "[bt] Execution path:/n");
for (i=0; i<trace_size; ++i)
printk(KERN_ERR "[bt] %s/n", messages[i]);
}
//backtrace function
He puesto la llamada a esta función más adelante, en una función de controlador de bloque donde ocurre el primer signo del error. Simplemente:
show_stackframe();
Así que cuando lo compilo, los siguientes errores:
user@slinux:~/2.6-32$ make -s
Invoking make againt the kernel at /lib/modules/2.6.32-5-686/build
In file included from /usr/include/features.h:346,
from /usr/include/execinfo.h:22,
from /home/linux/2.6-32/block/block26.c:49:
/usr/include/sys/cdefs.h:287:1: warning: "__always_inline" redefined
In file included from /usr/src/linux-headers-2.6.32-5-common/include/linux/compiler-gcc.h:86,
from /usr/src/linux-headers-2.6.32-5-common/include/linux/compiler.h:40,
from /usr/src/linux-headers-2.6.32-5-common/include/linux/stddef.h:4,
from /usr/src/linux-headers-2.6.32-5-common/include/linux/list.h:4,
from /usr/src/linux-headers-2.6.32-5-common/include/linux/module.h:9,
from /home/linux/2.6-32/inc/linux_ver.h:40,
from /home/linux/2.6-32/block/block26.c:32:
/usr/src/linux-headers-2.6.32-5-common/include/linux/compiler-gcc4.h:15:1: warning: this is the location of the previous definition
/home/linux/2.6-32/block/block26.c:50: warning: function declaration isn’t a prototype
WARNING: "backtrace" [/home/linux/2.6-32/ndas_block.ko] undefined!
WARNING: "backtrace_symbols" [/home/linux/2.6-32/ndas_block.ko] undefined!
Nota: block26.c es el archivo del que espero obtener el seguimiento.
¿Hay una razón obvia por la que el backtrace y el backtrace_symbols permanecen indefinidos cuando se compila en los módulos .ko?
Lo adivino porque uso el compilador incluye execinfo.h, que reside en la computadora y no se carga en el módulo.
Es mi suposición sin educación por decir lo menos.
¿Alguien puede ofrecer ayuda para que las funciones de backtrace se carguen en el módulo?
Gracias por mirar esta consulta.
Estoy trabajando en debian. Cuando saco la función y tal, el módulo compila bien y casi funciona perfectamente.
De ndasusers
Sé que esta pregunta es sobre Linux, pero ya que es el primer resultado para "kernel de retroceso", aquí hay algunas soluciones más:
DragonFly BSD
Es print_backtrace(int count)
de /sys/sys/systm.h
. Se implementa en /sys/kern/kern_debug.c
y / o /sys/platform/pc64/x86_64/db_trace.c
. Se puede encontrar buscando el panic
, que se implementa en /sys/kern/kern_shutdown.c
, y llama a print_backtrace(6)
si se define DDB
y se establece trace_on_panic
, ambos valores predeterminados.
FreeBSD
Es kdb_backtrace(void)
de /sys/sys/kdb.h
. Del mismo modo, es fácil de encontrar investigando qué llama la implementación de panic
cuando trace_on_panic
es verdadero.
OpenBSD
Siguiendo la ruta de panic
, parece ser db_stack_dump()
, implementado en /sys/ddb/db_output.c
. La única mención del encabezado es /sys/ddb/db_output.h
.
Si necesita guardar el seguimiento de la pila y procesar sus elementos de alguna manera, save_stack_trace()
o dump_trace()
también puede ser una opción. Estas funciones se declaran en <linux/stacktrace.h>
y <asm/stacktrace.h>
, respectivamente.
No es tan fácil usarlos como dump_stack()
pero si necesita más flexibilidad, pueden ser útiles.
Aquí es cómo se puede usar save_stack_trace()
(reemplace HOW_MANY_ENTRIES_TO_STORE
con el valor que se adapte a sus necesidades, 16-32 generalmente es más que suficiente):
unsigned long stack_entries[HOW_MANY_ENTRIES_TO_STORE];
struct stack_trace trace = {
.nr_entries = 0,
.entries = &stack_entries[0],
.max_entries = HOW_MANY_ENTRIES_TO_STORE,
/* How many "lower entries" to skip. */
.skip = 0
};
save_stack_trace(&trace);
Ahora la matriz stack_entries
contiene las direcciones de llamada apropiadas. El número de elementos rellenados es nr_entries
.
Una cosa más para señalar. Si es deseable no generar las entradas de la pila que pertenecen a la implementación de save_stack_trace()
, dump_trace()
o dump_stack()
(en diferentes sistemas, el número de dichas entradas puede variar), se puede aplicar el siguiente truco si utilizar save_stack_trace()
. Puede usar __builtin_return_address(0)
como una entrada "ancla" y procesar solo las entradas "no inferiores" que eso.
dump_stack()
es una función que se puede utilizar para imprimir su pila y, por lo tanto, se puede usar para retroceder. mientras lo usa, tenga cuidado de no ponerlo en la ruta repetitiva, como los bucles o la función de recepción de paquetes, ya que puede llenar su búfer dmesg, lo que puede provocar un bloqueo en el dispositivo integrado (con menos memoria y CPU).
Esta función se declara en linux/kernel.h
.