Como debuggar usando GDB (Debugando código em C)
O'que é o GDB?
O GNU Debugger (mais conhecido como GDB) é um debugger que permite ao usuário visualizar "o quê está acontencedo" dentro de um programa enquanto ele executa.
O GDB pode ser usado para debuggar tanto programas feitos em C, C++, Fortran e Modula-2.
Criando um código de exemplo
# include <stdio.h>
int main()
{
int i, num, j;
printf ("Digite um número: ");
scanf ("%d", &num );
for (i=1; i<num; i++)
j=j*i;
printf("O fatorial de %d é %d!\n",num,j);
}
O código recebe um número do usuário atravês do comando scanf e calcula o fatorial do mesmo.
Porém esse código possui um erro proposital (quem sabe, sabe) que ao ser
inserido o número 6 o programa retorna "0" sendo que o certo seria retornar "720".
O fatorial de 6 é 0!
O porquê isso acontece? é isso que vamos tentar descobrir usando o GDB!
Passo 1 - Compilando o código
Para poder usar o GDB no seu código é necessário usar o argumento "-g" na hora de compilar, esse argumento permite o compilador coletar informações que serão essenciais para o processo de debugging. (Segue abaixo um exemplo)
$ cc -g fatorial.c -o fatorial
Passo 2 - Inicialize o GDB
Inicialize o GDB com o código abaixo:
$ gdb fatorial.c
Caso você não tenha o GDB instalado no seu sistema, basta usar o seguinte comando:
$ sudo apt install gdb
Passo 3 - Definindo um "breakpoint"
Um breakpoint é basicamente um sinal que vai definir onde o seu código deve parar enquanto estiver executando, isso vai evitar que o seu código acabe passe direto da parte que você quer examinar.
Para definir um novo breakpoint é bem simples, basta usar o comando "break" (é possível usar apenas "b" como abreviação para "break"):
(gdb) break número_da_linha
No nosso caso, como eu quero examinar o looping do código, vou definir o breakpoint para a linha 9:
(gdb) break 9
Breakpoint 1 at 0x11d3: file fatorial.c, line 9.
Passo 4 - Executando o programa
Para executar o programa é usado o comando "run [args]" (argumentos podem ser usados como se estivesse executando o programa normalmente). Como no nosso caso os argumentos não se fazem necessários vou usar apenas o "run".
run
Starting program: /home/anth/Desktop/fatorial
Com o código rodando ele vai executar normalmente até chegar no primeiro breakpoint definido e exibir a seguinte mensagem:
Breakpoint 1, main () at fatorial.c:7
7 for (i=1; i<num; i++)
E é agora que você vai usar alguns comandos para fazer o debugging, assim como será explicado nos tópicos abaixo...
Passo 5 - Exibindo os valores de variáveis
Para checar o valor de alguma variável basta usar o comando "print" juntamente ao nome da variável (É possível usar apenas "p" como abreviação para "print"), como por exemplo:
(gdb) print i (p i)
$1 = 1
(gdb) print j
$2 = 3042592
(gdb) print num
$3 = 6
Como é possível ver, a variável "j" não foi inicializada corretamente. Portanto, ela irá ter por padrão um garbage value o que vai resultar em um valor inesperado na fatoração.
Para fixar o problema basta definir a variável "j" como 1, ao compilar o programa novamente e executar o problema parece estar resolvido... mas mesmo após isso algo continua fazendo com que retornado o fatorial errado.
Então... antes que eu mate todo mundo de tédio explicando passo a passo como resolver, proponho que você mesmos aplique o que aprendeu com esse post e tente descobrir o que tem de errado com esse código por si próprio. (No próximo tópico vou explicar alguns comandos extras para ajudar com a resolução do problema)
Comandos extras
Apesar de ser um tópico extra, os comandos que vão ser mencionados se mostram tão essenciais como os abordados acima.
Existem 3 tipos de operações que você pode executar no GDB após o programa ter chegado no breakpoint definido. Comandos esses são:
- 'c' ou 'continue': O código vai continuar executando até que ele atinja outro breakpoint.
- 'n' ou 'next': Será executado uma linha única de intruções, algo como pular paro o próximo passo comando a ser executado.
- 's' ou 'step': Similar ao 'next', ele irá executar instruções únicas mas com o diferencial que funções não serão tratadas como instruções únicas, fazendo assim que seja executada linha por linha.
- 'l' ou 'list': Esse comando vai exibir o código fonte do programa.
- 'help': Exibe uma tela de ajuda com alguns outros comandos que podem ser úteis.
Referências
https://linux.die.net/man/1/gdb
https://u.osu.edu/cstutorials/2018/09/28/how-to-debug-c-program-using-gdb-in-6-simple-steps/
Quem quiser dar uma força e seguir lá no GitHub agradeço também :D
https://github.com/Anthhon