gdb-pratico/mods/05
2025-04-28 13:08:08 -03:00
..
exemplos conteúdo das partes 4 e 5 2025-04-28 13:08:08 -03:00
README.org conteúdo das partes 4 e 5 2025-04-28 13:08:08 -03:00

Curso prático de introdução ao GDB

5. Casos de uso

Objetivo

Demonstrar o uso do GDB para localizar e solucionar bugs comuns, como:

  • Falha de segmentação;
  • Variável não inicializada;
  • Loop infinito;
  • Índice de vetor inválido;
  • Parâmetro incorreto na chamada de uma função;
  • Registradores incorretos em uma chamada de sistema;
  • Desalinhamento da pilha;
  • Erro de empilhamento e desempilhamento de registros;
  • Estouro de buffer;
  • Estouro de pilha;
  • Vazamento de memória.

Falha de segmentação

Acesso inválido à memória causado por um ponteiro não inicializado.

Código (segfault.c):

#include <stdio.h>

int main() {
    int *p = NULL;
    *p = 42;  // ERRO: tentativa de escrever em um ponteiro nulo
    printf("%d\n", *p);
    return 0;
}

Compilação:

:~$ gcc -g -o segfault segfault.c
$ gdb ./segfault
Reading symbols from ./segfault...

Processo de depuração

Verificar o que acontece ao executar:

(gdb) r
Starting program: /home/blau/git/gdb-pratico/mods/05/exemplos/segfault
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x000055555555514d in main () at segfault.c:5
5	    *p = 42;  // ERRO: tentativa de escrever em um ponteiro nulo

Matando o processo:

(gdb) k
[Inferior 1 (process 1034793) killed]

Definindo main como ponto de parada e executando:

(gdb) b main
Breakpoint 5 at 0x555555555141: file segfault.c, line 4.
(gdb) r
Starting program: /home/blau/git/gdb-pratico/mods/05/exemplos/segfault
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 5, main () at segfault.c:4
4	    int *p = NULL;

Listando variáveis locais antes e após a inicialização do ponteiro p:

(gdb) i locals
p = 0x7fffffffdf40
(gdb) n
5	    *p = 42;  // ERRO: tentativa de escrever em um ponteiro nulo
(gdb) i locals
p = 0x0

O endereço de memória no ponteiro é claramente nulo (0x0)!

Variável não inicializada

Uso de uma variável antes da atribuição de um valor (seu valor é lixo de memória).

Código do exemplo (notinit.c):

#include <stdio.h>

int main(void) {

    int a;  // PROBLEMA: Variável não inicializada!

    printf("Digite um número: ");
    scanf("%d", &a);  // Se scanf falhar, o valor de a será lixo!
    
    printf("Depois de %d vem %d\n", a, a + 1);

    return 0;
}

Compilação e teste:

:~$ gcc -g -o notinit notinit.c
:~$ ./notinit
Digite um número: (teclar CTRL+D) Depois de 32765 vem 32766

Processo de depuração

Basta executar o programa passo a passo examinando o valor da variável a:

:~$ gdb ./notinit
Reading symbols from ./notinit...
(gdb) b main
Breakpoint 1 at 0x1151: file notinit.c, line 7.
(gdb) r
Starting program: /home/blau/git/gdb-pratico/mods/05/exemplos/notinit
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main () at notinit.c:7
7	    printf("Digite um número: ");
(gdb) p a
$1 = 32767
(gdb) n
8	    scanf("%d", &a);  // Se scanf falhar, o valor de a será lixo!
(gdb) n
Digite um número: 10	    printf("Depois de %d vem %d\n", a, a + 1);
(gdb) p a
$2 = 32767
(gdb) n
Depois de 32767 vem 32768
12	    return 0;
(gdb) c
Continuing.
[Inferior 1 (process 1039355) exited normally]

Com o erro na execução de scanf (simulado com o atalho CTRL+D), o valor da variável não inicializada continuou sendo lixo de memória (32767).

Loop infinito

Uma condição de parada incorreta faz com que as repetições não tenham fim.

Código de exemplo (iloop.c):

#include <stdio.h>

int main() {
    int i = 0;

    // A condição de parada nunca será atendida!
    while (i < 100) { 
        printf("i = %d\n", i);
        i *= 2;  // Sempre zero!
    }
    return 0;
}

Compilação e teste:

:~$ gcc -g -o iloop iloop.c
:~$ ./iloop
i = 0
i = 0
i = 0
i = 0
i = 0
i = 0
i = 0
i = 0
^C

Processo de depuração

$ gdb ./iloop
Reading symbols from ./iloop...
(gdb) b main
Breakpoint 1 at 0x1141: file iloop.c, line 4.
(gdb) r
Starting program: /home/blau/git/gdb-pratico/mods/05/exemplos/iloop
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main () at iloop.c:4
4	    int i = 0;
(gdb) n
7	    while (i < 100) {
(gdb) p i
$1 = 0
(gdb) n
8	        printf("i = %d\n", i);
(gdb) n
i = 0
9	        i *= 2;  // Sempre zero!
(gdb) p i
$2 = 0
(gdb) n
7	    while (i < 100) {
(gdb) p i
$3 = 0

Fica claro que o valor de nunca foi alterado, porque 2 × 0 = 0!