2009-10-08 42 views
18

Me gustaría saber de dónde se imprime un determinado mensaje dentro de una aplicación enorme. La aplicación es tan grande y vieja que usa todas las formas imaginables de imprimir texto en la terminal; por ejemplo printf(), fprintf (stdout, ...) etc.¿cómo puedo poner un punto de interrupción en "algo está impreso en el terminal" en gdb?

Escribo para poner un punto de interrupción en la llamada al sistema write() pero luego estoy inundado con demasiadas paradas de punto de interrupción debido a varios archivos I/O operaciones que también usan write().

Básicamente quiero que gdb se detenga cada vez que el programa imprime algo en el terminal, pero al mismo tiempo no quiero que gdb se detenga cuando el programa escribe algo en un archivo.

+1

Véase también [¿Cómo puedo controlar lo que está siendo puesta en el buffer estándar out y break cuando se deposita una cadena específica en el pipe?] (http://stackoverflow.com/questions/8235436/how-can-i-monitor-whats-being-put-into-the-standard- out-buffer-and-break-when-a) –

+0

¿No puedes 'grep' la fuente de ese" algo "que aparece en la terminal, y luego colocar un punto de interrupción allí? – Calmarius

Respuesta

18

Use un punto de corte condicional que verifique el primer parámetro. En los sistemas x86 de 64 bits la condición sería:

(BGF) b escritura si 1 == $ RDI

en sistemas de 32 bits, es más compleja porque el parámetro está en la pila, lo que significa que necesita lanzar $ esp a un int * e indexar el parámetro fd. La pila en ese punto tiene la dirección de retorno, la longitud, el buffer y finalmente fd.

Esto varía mucho entre plataformas de hardware.

+1

Me equivoque un poco con esto y descubrí que el número FD está disponible como "* (int) ($ esp + 4)" y la longitud de la cadena como "(int) * (int) ($ esp + 12)" y finalmente los datos de cadena como "* (int) ($ esp + 8)". Así que para STDOUT se puede hacer algo como: ruptura escritura si 1 == * (int) ($ ESP + 4) comandos de impresión (int) * (int) (ESP + $ 12) x/s * (int) ($ esp + 8) final Pero cuando traté de usar esto en la práctica en una _huge_ aplicación, resultó que este método no es infalible porque no maneja redirecciones, etc. por lo que si la aplicación usa dup2() en stdout es posible que omita algunas cosas que se imprimen en stdout. – martin

+0

Aquí hay un intento un poco más refinado:

 break write commands silent if !isatty(*(int)($esp + 4)) c end echo \ntty write(), size: x/d (int)($esp + 12) echo tty write(), data: x/s *(int)($esp + 8) end 
martin

11

Con GDB 7.0, puede establecer punto de interrupción condicionada a la llamada al sistema write():

(gdb) catch syscall write 
Catchpoint 1 (syscall 'write' [4]) 
(gdb) condition 1 $ebx==1 

$ EBX contiene primer parámetro syscall - Número FD aquí

+0

Nota: 'printf' está almacenado en el búfer, por lo que puede suceder que solo vea' write' en la primera 'printf' en una segunda llamada' printf' concatenada. –

Cuestiones relacionadas