28 de abril de 2011
He aquí algo que es un hack que estoy un poco avergonzado de publicar. Pero si usted necesita sólo un one-off, que puede hacer lo suficientemente bien como para permitirle obtener la información que desea. Realmente debe haber una mejor manera.
Se puede definir un estúpido poco gdb script que ejecuta el step
o next
comando de un determinado número de veces:
# file: step_mult.gdb
define step_mult
set $step_mult_max = 1000
if $argc >= 1
set $step_mult_max = $arg0
end
set $step_mult_count = 0
while ($step_mult_count < $step_mult_max)
set $step_mult_count = $step_mult_count + 1
printf "step #%d\n", $step_mult_count
step
end
end
(He utilizado el paso en lugar de next
por ninguna buena razón en particular; se cambie a lo que usted necesita.)
A continuación, puede ejecutar el comando (con opcional de contar), y se va a mostrar cada uno de los step
o next
muy bien.
Aquí se muestra un ejemplo de programa que va a bloquearse cuando intenta desreferenciar un puntero NULL:
#include<stdio.h>
int x[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8,9, 10
};
int* p[11];
int main()
{
int i;
for (i = 0; i < 11; ++i) {
p[i] = &x[i];
}
p[5] = 0;
for (i = 0; i < 11; ++i) {
printf( "*p[%d] == %d\n", i, *p[i]);
}
return 0;
}
He aquí un gdb de la sesión (en Windows) la depuración que se programa y el uso de la step_mult
script:
C:\temp>gdb test.exe
GNU gdb (GDB) 7.2
...
Reading symbols from C:\temp/test.exe...done.
(gdb) source c:/temp/step_mult.gdb
(gdb) start
Temporary breakpoint 1 at 0x401385: file C:\temp\test.c, line 23.
Starting program: C:\temp/test.exe
[New Thread 5396.0x1638]
Temporary breakpoint 1, main () at C:\temp\test.c:23
23 for (i = 0; i < 11; ++i) {
(gdb) step_mult 70
step #1
24 p[i] = &x[i];
step #2
23 for (i = 0; i < 11; ++i) {
step #3
24 p[i] = &x[i];
step #4
23 for (i = 0; i < 11; ++i) {
step #5
24 p[i] = &x[i];
step #6
23 for (i = 0; i < 11; ++i) {
step #7
24 p[i] = &x[i];
step #8
23 for (i = 0; i < 11; ++i) {
step #9
24 p[i] = &x[i];
step #10
23 for (i = 0; i < 11; ++i) {
step #11
24 p[i] = &x[i];
step #12
23 for (i = 0; i < 11; ++i) {
step #13
24 p[i] = &x[i];
step #14
23 for (i = 0; i < 11; ++i) {
step #15
24 p[i] = &x[i];
step #16
23 for (i = 0; i < 11; ++i) {
step #17
24 p[i] = &x[i];
step #18
23 for (i = 0; i < 11; ++i) {
step #19
24 p[i] = &x[i];
step #20
23 for (i = 0; i < 11; ++i) {
step #21
24 p[i] = &x[i];
step #22
23 for (i = 0; i < 11; ++i) {
step #23
27 p[5] = 0;
step #24
29 for (i = 0; i < 11; ++i) {
step #25
30 printf( "*p[%d] == %d\n", i, *p[i]);
step #26
*p[0] == 0
29 for (i = 0; i < 11; ++i) {
step #27
30 printf( "*p[%d] == %d\n", i, *p[i]);
step #28
*p[1] == 1
29 for (i = 0; i < 11; ++i) {
step #29
30 printf( "*p[%d] == %d\n", i, *p[i]);
step #30
*p[2] == 2
29 for (i = 0; i < 11; ++i) {
step #31
30 printf( "*p[%d] == %d\n", i, *p[i]);
step #32
*p[3] == 3
29 for (i = 0; i < 11; ++i) {
step #33
30 printf( "*p[%d] == %d\n", i, *p[i]);
step #34
*p[4] == 4
29 for (i = 0; i < 11; ++i) {
step #35
30 printf( "*p[%d] == %d\n", i, *p[i]);
step #36
Program received signal SIGSEGV, Segmentation fault.
0x004013d2 in main () at C:\temp\test.c:30
30 printf( "*p[%d] == %d\n", i, *p[i]);
step #37
Program received signal SIGSEGV, Segmentation fault.
0x004013d2 in main () at C:\temp\test.c:30
30 printf( "*p[%d] == %d\n", i, *p[i]);
step #38
Program exited with code 030000000005.
step #39
The program is not being run.
(gdb)
Lamentablemente, desde la secuencia de comandos no se detiene cuando la violación de segmento que pasa, gdb decide simplemente detener la depuración del programa, así que usted no puede hacer más útiles las consultas. Pero el registro todavía puede ser útil.
Estoy seguro de que hay numerosas maneras en que uno puede hacer el guión más inteligente. Por desgracia, no tengo idea de cómo hacer eso, y el nivel de usuario documentación para el GDB no parecen ser demasiado útil para los detalles. La mejor manera sería si el script se podría detectar la violación de segmento o de la señal que había pasado y acaba de dejar, a continuación, en lugar de depender de arbitraria en el recuento. Me imagino que el gdb/MI interfaz, o probablemente incluso las secuencias de comandos de Python interfaz puede tener un buen mecanismo, pero no sé nada acerca de aquellos.
Después de su primera ejecución, se podría utilizar el recuento de la muestra (37 en mi ejemplo) y reinicie el programa y le dan un número que está justo por debajo de donde se estrelló antes y tomar el control de forma manual.
Como he dicho, no es especialmente bonito, pero podría llegar hasta allí.