2010-07-22 9 views
10

Tengo un ligero problema con algunas estructuras en un módulo kernel que estoy construyendo, así que pensé que sería bueno si hubiera una forma fácil de imprimir las estructuras y sus valores, y debajo hay un pequeño ejemplo de lo que es Quiero decir.Linux C: volcado fácil/'bonito'/impresión de estructuras (como en gdb) - ¿del código fuente?

Digamos que tenemos el simple ejemplo C de la siguiente manera (dado en forma de un comando de bash):

FN=mtest 

cat > $FN.c <<EOF 
#include <stdio.h> //printf 
#include <stdlib.h> //calloc 

struct person 
{ 
int age; 
int height; 
}; 

static struct person *johndoe; 

main() 
{ 

johndoe = (struct person *)calloc(1, sizeof(struct person)); 
johndoe->age = 6; 

asm("int3"); //breakpoint for gdb 

printf("Hello World - age: %d\n", johndoe->age); 

free(johndoe); 
} 
EOF 

gcc -g -O0 $FN.c -o $FN 

# just a run command for gdb 
cat > ./gdbcmds <<EOF 
run 
EOF 

gdb --command=./gdbcmds ./$FN 

 

Si corremos este ejemplo, el programa se compile y BGF ejecutar y parará automáticamente en el punto de interrupción. Aquí podemos hacer lo siguiente:

Program received signal SIGTRAP, Trace/breakpoint trap. 
main() at mtest.c:20 
20 printf("Hello World - age: %d\n", johndoe->age); 
(gdb) p johndoe 
$1 = (struct person *) 0x804b008 
(gdb) p (struct person)*0x804b008 
$2 = {age = 6, height = 0} 
(gdb) c 
Continuing. 
Hello World - age: 6 

Program exited with code 0300. 
(gdb) q 

 

Como se muestra, en GDB podemos salidas impresas (volcar?) El valor del puntero estructura johndoe como {age = 6, height = 0} ... me gustaría hacer lo mismo , pero directamente desde un programa C; dicen como en el siguiente ejemplo:

#include <stdio.h> //printf 
#include <stdlib.h> //calloc 
#include <whatever.h> //for imaginary printout_struct 

struct person 
{ 
int age; 
int height; 
}; 

static struct person *johndoe; 
static char report[255]; 

main() 
{ 

johndoe = (struct person *)calloc(1, sizeof(struct person)); 
johndoe->age = 6; 

printout_struct(johndoe, report); //imaginary command 

printf("Hello World - age: %d\nreport: %s", johndoe->age, report); 

free(johndoe); 
} 

 

cual daría lugar a una salida como:

Hello World - age: 6 
$2 = {age = 6, height = 0} 

 

Así que mi pregunta es - lo hace en función de esa imaginaria printout_struct existen - o hay otro enfoque para hacer una impresión como esta posible?

Gracias de antemano por cualquier ayuda,
¡Salud!

Respuesta

12

Solo quería decir: gracias por todas sus buenas e increíblemente rápidas respuestas, me ayudó mucho a entender el problema (¡por qué no hay una función tan 'nativa' en C)!

(y lo siento por responder a mi propia pregunta - haciendo que, a fin de no distorsionar el post original, y ser capaz de formato de código)

Mientras mira más he conseguido encontrar:

que ilustran la tri ck con llamar gdb con el pid del proceso en sí, y por lo que modifica la función dumpstack encuentra allí, para obtener el siguiente código:

FN=mtest 

cat > $FN.c <<EOF 
#include <stdio.h> //printf 
#include <stdlib.h> //calloc, system 

extern const char *__progname; 

struct person 
{ 
    int age; 
    int height; 
}; 

static struct person *johndoe; 
static char report[255]; 

static void printout_struct(void* invar, char* structname){ 
    /* dumpstack(void) Got this routine from http://www.whitefang.com/unix/faq_toc.html 
    ** Section 6.5. Modified to redirect to file to prevent clutter 
    */ 
    /* This needs to be changed... */ 
    char dbx[160]; 

    sprintf(dbx, "echo 'p (struct %s)*%p\n' > gdbcmds", structname, invar); 
    system(dbx); 

    sprintf(dbx, "echo 'where\ndetach' | gdb -batch --command=gdbcmds %s %d > struct.dump", __progname, getpid()); 
    system(dbx); 

    sprintf(dbx, "cat struct.dump"); 
    system(dbx); 

    return; 
} 

main() 
{ 

    johndoe = (struct person *)calloc(1, sizeof(struct person)); 

    johndoe->age = 6; 
    printout_struct(johndoe, "person"); 

    johndoe->age = 8; 
    printout_struct(johndoe, "person"); 

    printf("Hello World - age: %d\n:", johndoe->age); 

    free(johndoe); 
} 


EOF 

gcc -g -O0 $FN.c -o $FN 

./$FN 

  que básicamente termina mostrando lo que quería:

0x00740422 in __kernel_vsyscall() 
$1 = {age = 6, height = 0} 
0x00740422 in __kernel_vsyscall() 
$1 = {age = 8, height = 0} 
Hello World - age: 8 

 

sin embargo, no estoy seguro de que va a trabajar con los módulos del núcleo ...

Gracias de nuevo por la ayuda,
¡Salud!

EDITAR: La razón por la que no creo que funcione para los módulos kernel, es que en este caso, tenemos un programa de usuario con un ID de proceso; y simplemente llamamos al gdb desde este programa, mientras le damos instrucciones sobre nuestro PID, para que gdb pueda "adjuntarse" a nuestro proceso; luego, dado que gdb también recibe instrucciones para cargar el ejecutable con símbolos de depuración (para que 'sepa' qué es la estructura), y se le instruye acerca de la dirección donde se encuentra una variable de estructura dada, gdb puede imprimir la estructura.

Para módulos de kernel: primero, no creo que sean 'procesos' en el sentido de tener un PID único, ¡así que gdb no tendrá nada que adjuntar! De hecho, hay un depurador de kernel, kgdb que de hecho puede dividirse en un kernel en ejecución y avanzar a través del código fuente del módulo; sin embargo, necesita una segunda máquina conectada a través de una conexión serial para eso - o una máquina virtual, vea Linux Hacks: Setting up kgdb using kvm/qemu.

Por lo tanto, en cualquier caso, parece que gdb no podría inspeccionar la memoria del kernel de host actualmente en ejecución gdb se está ejecutando - pero intentaré experimentar, y si los experimentos muestran lo contrario, lo haré asegúrese de publicar :)

+1

No te disculpes por contestar tus propias preguntas, eso se fomenta aquí. – dmckee

+0

self-answering está bien en SO; en este caso, diría que sería mejor si intentas actualizar esta respuesta para hacernos saber si la solución está bien incluso en los módulos kernel. – ShinTakezou

+0

OK muchachos, gracias por eso; Me acabo de dar cuenta de la pregunta "¿Estás seguro de que quieres responder a tu pregunta?" Cuando estaba intentando publicarlo :) Además, agregué una edición de por qué creo que los módulos del kernel no funcionarán. – sdaau

1

Debe agregar metainformación que describa la estructura para que printout_struct pueda hacer su trabajo. De lo contrario, no puede adivinar nada. Pruebe con gdb eliminando cada información de depuración, y verá que no puede "hablar" sobre "edad" o lo que sea.

+0

Quiero decir, por supuesto, que la metainformación sobre la estructura debe darse como argumento para printout_struct – ShinTakezou

1

El lenguaje C no tiene metadatos, ni en tiempo de compilación ni en tiempo de ejecución. Puede haber algunas extensiones específicas del proveedor para hacer esto. Por ejemplo, doxygen creará un archivo XML con toda la información del miembro (nombre y tipo) de cada tipo de estructura en su programa, no sería demasiado difícil escribir un programa para procesar ese archivo XML y generar el código para una persona impresa (const struct person *) funciona automáticamente.

+3

Muchos (la mayoría?) compiladores proporcionan una opción "incluir símbolos de depuración" que genera exactamente tales metadatos. En el caso de 'gcc' la opción es' -g' Eso es, después de todo, donde 'gdb' obtiene la información para lograr esto ... – dmckee

+0

Indeed. Ver mi respuesta para un par de posibilidades para obtener la información. – bstpierre

0

recientemente alguien mencionado

exuberantes ctags

en StackOverflow para una tarea similar. Quizás puedas descubrirlo, pero no lo encontré de inmediato.

2

Consulte this related question para obtener información sobre las estructuras de análisis. Específicamente mi referencia allí a pstruct.

En su caso, donde quiera obtener información desde dentro de un programa en ejecución, deberá invocar una de esas herramientas externas o analizar la información de depuración desde su ejecutable y visualizarla adecuadamente.

También puede consultar libgdb, aunque parece que podría estar un poco anticuado.

Cuestiones relacionadas