c++ - ver - ¿Hay alguna manera de establecer un punto de interrupción en gdb que sea condicional en la pila de llamadas?
puntos de interrupcion establecidos pero no enlazados aun (6)
Estoy depurando C ++ en gdb 7.1 en Linux.
Tengo una función a()
que se llama en muchos lugares en el código. Quiero establecer un punto de interrupción en él, pero solo si fue llamado desde b()
. ¿Hay alguna forma de hacerlo?
¿Hay alguna forma de hacerlo solo si b()
fue llamado desde c()
, y así ad infinitum?
He probado esto en gdb 7.6 que ya está disponible pero no funciona en gdb 7.2 y probablemente en gdb 7.1:
Así que esto es main.cpp:
int a()
{
int p = 0;
p = p +1;
return p;
}
int b()
{
return a();
}
int c()
{
return a();
}
int main()
{
c();
b();
a();
return 0;
}
Entonces g ++ -g main.cpp
Este es my_check.py:
class MyBreakpoint (gdb.Breakpoint):
def stop (self):
if gdb.selected_frame().older().name()=="b":
gdb.execute("bt")
return True
else:
return False
MyBreakpoint("a")
Y así es como funciona:
4>gdb -q -x my_check.py ./a.out
Reading symbols from /home/a.out...done.
Breakpoint 1 at 0x400540: file main.cpp, line 3.
(gdb) r
Starting program: /home/a.out
#0 a () at main.cpp:3
#1 0x0000000000400559 in b () at main.cpp:10
#2 0x0000000000400574 in main () at main.cpp:21
Breakpoint 1, a () at main.cpp:3
3 int p = 0;
(gdb) c
Continuing.
[Inferior 1 (process 16739) exited normally]
(gdb) quit
La necesidad que describe surge con mucha frecuencia, generalmente en el contexto de que se llama mucho a some_utility_fn
, pero solo está interesado en la llamada que proviene de some_other_fn
.
Probablemente podría escribir toda esta interacción utilizando el nuevo soporte Python incorporado en GDB desde el tronco CVS.
Sin Python, está limitado en lo que puede hacer, pero la técnica habitual es tener un punto de interrupción deshabilitado en a()
, y habilitarlo desde un comando, asociado a un punto de interrupción en b()
.
Aquí hay un ejemplo:
int a(int x)
{
return x + 1;
}
int b()
{
return a(1);
}
int call_a_lots()
{
int i, sum = 0;
for (i = 0; i < 100; i++)
sum += a(i);
}
int main()
{
call_a_lots();
return b();
}
gcc -g t.c
gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) break a
Breakpoint 1 at 0x4004cb: file t.c, line 3.
(gdb) disable 1
(gdb) break b
Breakpoint 2 at 0x4004d7: file t.c, line 8.
(gdb) command 2
>silent
>enable 1
>continue
>end
(gdb) run
Breakpoint 1, a (x=1) at t.c:3
3 return x + 1;
(gdb) bt
#0 a (x=1) at t.c:3
#1 0x00000000004004e1 in b () at t.c:8
#2 0x000000000040052c in main () at t.c:21
(gdb) q
Voila: nos detuvimos en a()
llamado desde b()
, ignorando las 100 llamadas anteriores a a()
.
No estoy seguro de cómo hacerlo por gdb.
Pero puedes declarar variable global como:
bool call_a = false;
y cuando b llamando a
call_a = true;
a();
y establezca call_a en falso cuando otra función llame a () o después de su punto de interrupción
luego usa el punto de ruptura de la condición
break [line-number] if call_a == true
Una fácil para el brazo es:
Establezca el punto de interrupción en la función que le interesa.
break a
Adjunte un comando gdb a ese punto de interrupción.
command 1
up 1
if $lr == 0x12345678
echo match /n
down 1
else
echo no match /n
echo $lr /n
down 1
cont
end
end
Cada vez que llega a la función a (), el comando abre temporalmente un marco de pila y actualiza el registro de enlace. El valor de registro de enlace de las personas que llaman puede usarse luego continuar cuando la persona que llama no es la ruta de ejecución que necesita.
Disfrutar.
Una solución más simple que las secuencias de comandos de Python es usar un punto de interrupción temporal .
Se parece a esto:
b ParentFunction
command 1
tb FunctionImInterestedIn
c
end
Cada vez que ParentFunction
a ParentFunction
, establecerá un punto de interrupción único en la función que realmente le interesa, y luego continuará ejecutándose (presumiblemente hasta que llegue a ese punto de interrupción).
Ya que romperá exactamente una vez en FunctionImInterestedIn
, esto no funcionará si se llama a FunctionImInterestedIn
varias veces en el contexto de ParentFunction
y desea interrumpir cada invocación.
gdb puede manejar esto directamente ahora sin necesidad de Python. Solo haz esto:
b a if $_caller_is("b")