% ./mystery
a
b
c
%
Pode-se emitir o sinal STOP
para um programa e, em seguida, CONT
para continuá-lo; o código TCL a seguir aguarda que b
apareça na saída e, nesse ponto, interrompe o processo, que deve permanecer parado até que o usuário digite uma linha para que expect_user
atue (no mínimo, uma nova linha).
#!/usr/bin/env expect
spawn -noecho ./mystery
set spid [exp_pid]
expect -ex b { exec kill -STOP $spid; send_user "STOP\n" }
expect_user -re . { exec kill -CONT $spid }
expect eof
Isso, é claro, tem todos os tipos de problemas, como se mystery
fosse executado muito rapidamente, ou se a saída estivesse em buffer, etc. Eu tive que diminuir o C e desligar o buffer para que funcionasse:
% cat mystery.c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
setvbuf(stdout, (char *) NULL, _IONBF, (size_t) 0);
printf("a\n");
sleep(1);
printf("b\n");
sleep(1);
printf("c\n");
return 0;
}
Um programa C pode ser melhor controlado, executando-o em um depurador como gdb
; os pontos de interrupção seriam uma maneira muito mais precisa de interromper a execução em um ponto exato no código do que reagir a E / S. A depuração de símbolos ajudará, mas não é necessária:
% gdb mystery
Reading symbols from mystery...(no debugging symbols found)...done.
(gdb) quit
% otool -dtv mystery | grep callq
0000000100000f26 callq 0x100000f70
0000000100000f32 callq 0x100000f6a
0000000100000f3c callq 0x100000f76
0000000100000f48 callq 0x100000f6a
0000000100000f52 callq 0x100000f76
0000000100000f5e callq 0x100000f6a
Então, isso é realmente em um Mac (a desmontagem varia de acordo com a plataforma). As chamadas acima são setvbuf
, printf
e sleep
com o endereço inicial
% otool -dtv mystery | sed 3q
mystery:
_main:
0000000100000f06 pushq %rbp
% perl -E 'say 0x0000000100000f52 - 0x0000000100000f06'
76
% gdb mystery
Reading symbols from mystery...(no debugging symbols found)...done.
(gdb) b *main + 76
Breakpoint 1 at 0x100000f52
(gdb) r
Starting program: /Users/jhqdoe/tmp/mystery
a
b
Breakpoint 1, 0x0000000100000f52 in main ()
(gdb)
E então você pode fazer o que for necessário e continuar o programa conforme desejado.
Outra ideia seria usar LD_PRELOAD
para ajustar a forma como o programa se comporta, assumindo, é claro, que a opção mais sensata - recompilar o programa da origem - não é possível. Ainda outra opção seria corrigir o binário C para se comportar como desejado .