Debugging com GDB
1. Introdução ao GDB
O GDB (GNU Debugger) é uma ferramenta essencial para depuração de programas escritos em Linguagem C. Ele permite que você execute o código passo a passo, inspecione variáveis, analise a pilha de chamadas e identifique a origem de erros como segmentation faults e loops infinitos.
Para instalar o GDB em sistemas Linux:
sudo apt-get install gdb # Debian/Ubuntu
sudo yum install gdb # CentOS/RHEL
Verifique a instalação:
gdb --version
Para que o GDB funcione corretamente, compile seu programa com a flag -g, que adiciona informações de depuração ao executável:
gcc -g -o programa programa.c
2. Comandos Essenciais do GDB
Inicie o GDB carregando seu executável:
gdb ./programa
Dentro do GDB, os comandos básicos são:
(gdb) run # Executa o programa
(gdb) break main # Define breakpoint na função main
(gdb) next # Avança para próxima linha (sem entrar em funções)
(gdb) step # Avança para próxima linha (entrando em funções)
(gdb) continue # Continua execução até próximo breakpoint
(gdb) print var # Exibe valor de uma variável
(gdb) display var # Exibe valor automaticamente a cada parada
(gdb) info locals # Mostra todas as variáveis locais
Exemplo prático:
#include <stdio.h>
int main() {
int a = 10, b = 20;
int soma = a + b;
printf("Soma: %d\n", soma);
return 0;
}
Depuração:
(gdb) break 5
(gdb) run
(gdb) print a
$1 = 10
(gdb) next
(gdb) print soma
$2 = 30
3. Trabalhando com Breakpoints e Watchpoints
Breakpoints podem ser definidos por linha, função ou arquivo:
(gdb) break 10 # Linha 10 do arquivo atual
(gdb) break main # Função main
(gdb) break programa.c:15 # Linha 15 do arquivo programa.c
(gdb) info breakpoints # Lista breakpoints
(gdb) delete 1 # Remove breakpoint 1
(gdb) disable 2 # Desabilita breakpoint 2
Watchpoints monitoram variáveis:
(gdb) watch variavel # Para quando variável for modificada
(gdb) rwatch variavel # Para quando variável for lida
Exemplo com vetor:
#include <stdio.h>
int main() {
int vetor[5] = {0};
for (int i = 0; i < 5; i++) {
vetor[i] = i * 2;
}
return 0;
}
(gdb) break main
(gdb) run
(gdb) watch vetor[2]
(gdb) continue
4. Análise de Pilha e Frame
Quando ocorre um erro, o comando backtrace mostra a sequência de chamadas de função:
#include <stdio.h>
void funcao2() {
int x = 10 / 0; // Erro proposital
}
void funcao1() {
funcao2();
}
int main() {
funcao1();
return 0;
}
Depuração:
(gdb) run
Program received signal SIGFPE, Arithmetic exception.
(gdb) backtrace
#0 0x... in funcao2 () at programa.c:4
#1 0x... in funcao1 () at programa.c:8
#2 0x... in main () at programa.c:12
(gdb) frame 1
(gdb) info args
(gdb) up
(gdb) down
5. Depuração de Ponteiros e Memória
Para verificar endereços de memória:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = malloc(sizeof(int));
*ptr = 42;
printf("%d\n", *ptr);
free(ptr);
return 0;
}
(gdb) break main
(gdb) run
(gdb) print ptr
$1 = (int *) 0x5555555592a0
(gdb) print &ptr
$2 = (int **) 0x7fffffffe3e0
(gdb) x/4x ptr # Examina 4 words de memória no endereço de ptr
0x5555555592a0: 0x0000002a 0x00000000 0x00000000 0x00000000
Para debug de segmentation fault:
#include <stdio.h>
int main() {
int *ptr = NULL;
*ptr = 10; // Segmentation fault
return 0;
}
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
(gdb) backtrace
(gdb) info registers
(gdb) print ptr
$1 = (int *) 0x0
6. Técnicas Avançadas de Depuração
Breakpoints condicionais:
(gdb) break 15 if i == 5
(gdb) break funcao if valor > 100
Comandos automáticos em breakpoints:
(gdb) break 20
(gdb) commands
> print "Breakpoint atingido"
> print x
> continue
> end
Depuração de core dumps:
ulimit -c unlimited # Permite core dumps
./programa # Executa até crash
gdb ./programa core # Analisa o core dump
7. Depuração de Recursão e Estruturas de Dados
Para funções recursivas:
#include <stdio.h>
int fatorial(int n) {
if (n <= 1) return 1;
return n * fatorial(n - 1);
}
int main() {
printf("%d\n", fatorial(5));
return 0;
}
(gdb) break fatorial if n == 3
(gdb) run
(gdb) backtrace
#0 fatorial (n=3) at programa.c:4
#1 fatorial (n=4) at programa.c:5
#2 fatorial (n=5) at programa.c:5
#3 main () at programa.c:9
Para listas encadeadas:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int valor;
struct Node *prox;
};
int main() {
struct Node *head = malloc(sizeof(struct Node));
head->valor = 1;
head->prox = malloc(sizeof(struct Node));
head->prox->valor = 2;
head->prox->prox = NULL;
return 0;
}
(gdb) print head
$1 = (struct Node *) 0x5555555592a0
(gdb) print head->valor
$2 = 1
(gdb) print head->prox->valor
$3 = 2
8. Dicas Finais e Fluxo de Trabalho
Crie um arquivo .gdbinit no diretório home para personalizar o GDB:
set print pretty on
set pagination off
set confirm off
define h
info functions
end
Combine GDB com outras ferramentas:
valgrind --leak-check=full ./programa # Detecta vazamentos de memória
strace -o saida.txt ./programa # Monitora chamadas de sistema
Checklist prático:
- Compile com
-g -O0para evitar otimizações que dificultam a depuração - Use breakpoints estratégicos antes de áreas suspeitas
- Verifique variáveis com
printapós cada operação crítica - Analise o backtrace imediatamente após um crash
- Teste com entradas mínimas para isolar o problema
- Documente suas sessões com logs do GDB
Referências
- GDB Documentation - Official GNU Manual — Documentação completa e oficial do GDB com todos os comandos e opções.
- Beej's Quick Guide to GDB — Guia prático e direto para iniciantes em depuração com GDB em C.
- Debugging with GDB - Tutorialspoint — Tutorial passo a passo cobrindo desde instalação até técnicas avançadas.
- GDB Cheat Sheet - Darkdust.net — Folha de consulta rápida com os comandos mais usados do GDB.
- An Introduction to GDB - MIT CSAIL — Material introdutório do MIT sobre depuração com GDB focado em programas C.
- Using GDB for C Debugging - OpenClassrooms — Curso interativo sobre depuração de programas C com GDB.
- Core Dump Analysis with GDB - IBM Developer — Artigo técnico sobre análise de core dumps usando GDB em ambientes Linux.