Executando verificação de segurança...
2

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

Carregando publicação patrocinada...