Debugger GDB


Voltar para lista de tutoriais

Debugar um programa é a maneira mais efetiva de se encontrar erros e avaliar o fluxo de execução do programa. Em MC202, os laboratórios são feitos em C. Em C, temos diversas rotinas de manipulação de memória, ponteiros e chamadas de funções. Em todos esses casos realizar a depuração do programa irá permitir identificar erros com facilidade.

Para debugar um programa iremos utilizar a ferramenta GDB. Com ela é possível:

Nesse tutorial, você irá aprender a instalar o GDB e debugar um programa bem simples.

Instalação

GNU/Linux

NO Ubuntu ou Debian, utilize os comandos para instalar o GDB:

user@desktop:~$ sudo apt-get update && sudo apt-get install gdb -y

Para verificar a instalação utilize:

user@desktop:~$ gdb --version

Caso a instalação foi concluída com sucesso, uma mensagem irá aparecer. A mensagem é semelhante a:

GNU gdb (Ubuntu 9.1-0ubuntu1) 9.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Mac e Windows

Você pode instalar o GDB com passos parecidos aos utilizados para instalar o compilador GCC.

Debugando um programa

Para facilitar o processo de depuração, é importante compilar o programa passando a flag -g para o GCC. Essa flag instrui o compilador a adicionar dados no binário executável contendo informações úteis e outros metadados. Por exemplo, ele insere uma tabela mapeando cada linha do código-fonte às instruções de máquina binárias correspondentes no arquivo executável. Assim, compilamos um arquivo main.c como:

user@desktop:~$ gcc -std=c99 -Wall -Werror -g main.c -o main -lm

Carregando um programa

Uma vez compilado o programa, é necessário carregá-lo no GDB utilizando o comando:

user@desktop:~$ gdb ./main

Isso abrir uma sessão interativa do GDB e já irá carregar todos os metadados do programa na memória, mas seu programa ainda não terá começado a executar. Uma mensagem como a seguinte irá aparecer:

user@desktop:~$ gdb ./main
GNU gdb (Ubuntu 9.1-0ubuntu1) 9.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...
(gdb)

Breakpoints

Os breakpoints são utilizados para parar a execução do programa imediatamente antes da execução de um determinado ponto. O comando utilizado é o break <argumento> ou b <argumento>. Um argumento pode ser o número da linha como argumento (b 10) ou o nome de uma função (b main).

Outros comandos

Além do comando de breakpoint outros comandos importantes que são comumente utilizados são:

Debugando um primeiro programa

Vamos utilizar o seguinte programa main.c nesse tutorial:

#include <stdio.h>

void escreva(int x) {
    printf("Escrevendo: %d\n", x);
}

int main(void) {
    int i = 10;

    while (i >= 0) {
        escreva(i);
        i--;
    }

    return 0;
}

Compile o programa main.c com a flag de depuração(-g):

user@desktop:~$  gcc -std=c99 -Wall -Werror -g main.c -o main -lm

Carregue o programa com o gdb:

user@desktop:~$ gdb ./main

Crie um breakpoint na função main:

(gdb) b main

Inicie a execução do programa:

(gdb) r

A execução irá parar com a seguinte mensagem:

Breakpoint 1, main () at main.c:8
8	    int i = 10;

Utilize o comando n para executar uma linha. A seguinte mensagem irá aparecer:

(gdb) n
10	    while(i >= 0) {
(gdb)

Visualize o valor da variável i:

(gdb) p i
$1 = 10
(gdb)

Imprima o valor de i em hexadecimal cada vez que o programa parar:

(gdb) display/x i

Coloque um breakpoint na linha 11:

(gdb) b 11

Continue a execução até o próximo breakpoint c:

(gdb) c
Continuando.

Breakpoint 2, main () at main.c:11
11              escreva(i);
1: /x i = 0xa

Repita o comando anterior:

(gdb) c
Continuando.

Breakpoint 2, main () at main.c:11
11              escreva(i);
1: /x i = 0x9

Remova todos os breakpoints e continue até o programa terminar:

(gdb) d
Delete all breakpoints? (y or n) y
(gdb) c
Continuing.
Escrevendo: 9
Escrevendo: 8
Escrevendo: 7
Escrevendo: 6
Escrevendo: 5
Escrevendo: 4
Escrevendo: 3
Escrevendo: 2
Escrevendo: 1
Escrevendo: 0
[Inferior 1 (process 7492) exited normally]

Finalize o gdb com o comando quit

(gdb) quit