Alguma vez você já quis inserir breakpoints do GDB no código C?
int main() {
printf("Hello,\n");
EMBED_BREAKPOINT;
printf("world!\n");
EMBED_BREAKPOINT;
return 0;
}
Uma maneira é inserir diretamente a instrução do breakpoint do seu CPU. Em x86:
#define EMBED_BREAKPOINT asm volatile ("int3;")
Há pelo menos dois problemas com essa abordagem:
- Eles não são breakpoints do GDB reais. Você não pode desativá-los, contar quantas vezes foram atingidos etc.
- Se você executar o programa fora GDB, a instrução de breakpoint irá travar o seu processo.
Aqui está um pequeno hack que resolve os dois problemas:
#define EMBED_BREAKPOINT \
asm("0:" \
".pushsection embed-breakpoints;" \
".quad 0b;" \
".popsection;")
Colocamos um label no fluxo de instruções e salvamos o seu endereço na seção linker embed-breakpoints.
Então, precisamos converter esses endereços em comandos breakpoint do GDB. Escrevi uma ferramenta que faz isso, como um wrapper para o comando gdb. Veja como ela funciona, no nosso exemplo inicial:
$ gcc -g -o example example.c
$ ./gdb-with-breakpoints ./example
Reading symbols from example...done.
Breakpoint 1 at 0x4004f2: file example.c, line 8.
Breakpoint 2 at 0x4004fc: file example.c, line 10.
(gdb) run
Starting program: example
Hello,
Breakpoint 1, main () at example.c:8
8 printf("world!\n");
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004004f2 in main at example.c:8
breakpoint already hit 1 time
2 breakpoint keep y 0x00000000004004fc in main at example.c:10
Se rodarmos o programa normalmente, ou em GDB sem o wrapper, os argumentos EMBED_BREAKPOINT nada farão. Os endereços de breakpoint sequer são carregados na memória, porque a seção de embed-breakpoints não está marcada como alocável.
Você pode encontrar todo o código no GitHub sob uma licença BSD. Eu fiz apenas testes mínimos, mas espero que seja uma ferramenta de depuração útil para alguém.
Não estou certo sobre a decisão de escrever o wrapper GDB em C usando BFD. Cheguei a considerar Haskell e elf, ou Python e a nova biblioteca pyelftools. Provavelmente seja possível fazer alguma coisa mais legal usando a API GDB para Python, que foi adicionada alguns anos atrás.
Este código depende da GNU toolchain: ele usa extensões GNU C, sintaxe do GNU assembler e BFD. O wrapper GDB usa o sistema de arquivos proc do Linux, para que ele possa passar para GDB um arquivo temporário que já foi desvinculado. Você poderá portá-lo para outros sistemas UNIX, mudando apenas a manipulação de arquivos temporários. Ele deverá funcionar em uma variedade de arquiteturas CPU, mas testei apenas em x86 de 32 e 64 bits.
?
Texto original disponível em http://mainisusuallyafunction.blogspot.ca/2012/01/embedding-gdb-breakpoints-in-c-source.html








