2011-05-02 18 views
23

Así que estoy tratando de averiguar qué procesos del núcleo están llamando a algunas funciones en un controlador de bloque. Pensé que incluir backtrace() en la biblioteca de C lo haría más fácil. Pero estoy teniendo problemas para cargar la traza inversa.¿Cómo incluir C backtrace en un código de módulo kernel?

Copié esta función ejemplo para mostrar la traza inversa:

http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/063/6391/6391l1.html

Todos los intentos para compilar tiene error en uno u otro lugar que un archivo no se puede encontrar o que las funciones no están definidos.

Esto es lo que viene más cerca.

En el Makefile puse las directivas del compilador:

-rdynamic -I/usr/include 

Si dejo a cabo la segunda, -I/usr/include, el compilador informa de que no puede encontrar el execinfo.h cabecera requerida.

A continuación, en el código donde yo quiero hacer la traza He copiado 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 en el que el el primer signo del error ocurre. Simplemente:

show_stackframe(); 

Así que cuando compilo, los siguientes errores:

[email protected]:~/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 Tengo la esperanza de obtener la traza de.

¿Hay alguna razón obvia por la que backtrace y backtrace_symbols permanezcan indefinidos cuando se compilan 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 conjetura inculta por decir lo menos.

¿Alguien puede ayudar a que las funciones de seguimiento se carguen en el módulo?

Gracias por mirar esta investigación.

Estoy trabajando en Debian. Cuando saco la función y tal, el módulo compila bien y casi funciona perfectamente.

De ndasusers

+2

No estoy tan seguro de que deba incluir bibliotecas como esta en el código del módulo kernel. ¿Has intentado simplemente usar gdb y establecer un punto de ruptura? [1] [1]: http://www.xml.com/ldd/chapter/book/ch04.html#t5 – zdav

+0

¡Oh, ratas! Tenía miedo de escuchar algo así. Este parece un capítulo útil al que me has vinculado. Gracias por eso. – ndasusers

+0

A diferencia de los programas de espacio de usuario, el kernel no está vinculado a la biblioteca C estándar (ni a ninguna otra biblioteca, para el caso). http://kernelnewbies.org/FAQ/LibraryFunctionsInKernel – jschmier

Respuesta

42

para imprimir el contenido de la pila y una traza inversa a la de registro del núcleo, utilice la función dump_stack() en su módulo del núcleo. Se declara en linux/kernel.h en la carpeta de inclusión en el directorio de origen del kernel.

+1

Gracias. Esto es lo que esperaba hacer con la traza inversa. ahora solo necesito una nueva publicación para ayudar a leerla. – ndasusers

+0

Los valores que se muestran están en dos bloques: el primero es el contenido bruto de la pila que se muestra por dirección, y el segundo muestra cada cuadro de pila como una traza inversa regular. – jmkeyes

19

Si necesita guardar el seguimiento de pila y procesar sus elementos de alguna manera, save_stack_trace() o dump_trace() también pueden ser una opción. Estas funciones se declaran en <linux/stacktrace.h> y <asm/stacktrace.h>, respectivamente.

No es tan fácil de usar como dump_stack(), pero si necesita más flexibilidad, pueden ser útiles.

Aquí es cómo save_stack_trace() se puede utilizar (HOW_MANY_ENTRIES_TO_STORE reemplazar con el valor que se adapte a sus necesidades, 16-32 suele ser 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 stack_entries matriz contiene las direcciones de llamadas apropiadas. La cantidad de elementos ocupados es nr_entries.

Una cosa más para señalar. Si no desea 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 entradas puede variar), se puede aplicar el siguiente truco si usa save_stack_trace(). Puede usar __builtin_return_address(0) como una entrada de "ancla" y procesar solo las entradas "no menores" que esa.

+0

+1 por una gran publicación. – jmkeyes

+0

Gracias por ayudarme. No usé este truco, pero podría.El stack_dump mostró todo lo que imaginé. – ndasusers

+0

Puedo encontrar direcciones con este método, pero estas direcciones no parecen coincidir con ninguna dirección en 'System.map'. Entonces, ¿cómo puedo convertir esa dirección en un nombre de función? –

0

Sé que esta pregunta es acerca de Linux, pero ya que es el primer resultado de "kernel traza inversa", aquí está un poco más soluciones:


DragonFly BSD

Es print_backtrace(int count) de /sys/sys/systm.h. Está implementado en /sys/kern/kern_debug.c y/o /sys/platform/pc64/x86_64/db_trace.c. Se puede encontrar buscando 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, que son ambos valores predeterminados.


FreeBSD

Es kdb_backtrace(void) de /sys/sys/kdb.h. Del mismo modo, es fácil de encontrar al ver en qué llama la implementación panic cuando trace_on_panic es verdadero.


OpenBSD

Entrar en la vía panic, que parece ser db_stack_dump(), implemented in /sys/ddb/db_output.c. La única mención del encabezado es /sys/ddb/db_output.h.

Cuestiones relacionadas