conteúdo das partes 4 e 5

This commit is contained in:
Blau Araujo 2025-04-28 13:08:08 -03:00
parent 325a77ae6c
commit 5e33085491
9 changed files with 341 additions and 0 deletions

View file

@ -4,6 +4,11 @@
* 4. Aplicações em baixo e alto nível * 4. Aplicações em baixo e alto nível
** Objetivo
Conhecer os recursos do GDB que podem auxiliar no desenvolvimento e
depuração de programas em assembly e em C/C++.
** O GDB e a programação em baixo nível ** O GDB e a programação em baixo nível
O GDB permite observar e controlar a execução de programas no nível mais próximo O GDB permite observar e controlar a execução de programas no nível mais próximo

231
mods/05/README.org Normal file
View file

@ -0,0 +1,231 @@
#+title: Curso prático de introdução ao GDB
#+author: Blau Araujo
#+email: blau@debxp.org
* 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=):
#+begin_src 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;
}
#+end_src
Compilação:
#+begin_example
:~$ gcc -g -o segfault segfault.c
$ gdb ./segfault
Reading symbols from ./segfault...
#+end_example
*** Processo de depuração
Verificar o que acontece ao executar:
#+begin_example
(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
#+end_example
Matando o processo:
#+begin_example
(gdb) k
[Inferior 1 (process 1034793) killed]
#+end_example
Definindo =main= como ponto de parada e executando:
#+begin_example
(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;
#+end_example
Listando variáveis locais antes e após a inicialização do ponteiro =p=:
#+begin_example
(gdb) i locals
p = 0x7fffffffdf40
(gdb) n
5 *p = 42; // ERRO: tentativa de escrever em um ponteiro nulo
(gdb) i locals
p = 0x0
#+end_example
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=):
#+begin_src 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;
}
#+end_src
Compilação e teste:
#+begin_example
:~$ gcc -g -o notinit notinit.c
:~$ ./notinit
Digite um número: (teclar CTRL+D) Depois de 32765 vem 32766
#+end_example
*** Processo de depuração
Basta executar o programa passo a passo examinando o valor da variável =a=:
#+begin_example
:~$ 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]
#+end_example
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=):
#+begin_src 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;
}
#+end_src
Compilação e teste:
#+begin_example
:~$ gcc -g -o iloop iloop.c
:~$ ./iloop
i = 0
i = 0
i = 0
i = 0
i = 0
i = 0
i = 0
i = 0
^C
#+end_example
*** Processo de depuração
#+begin_example
$ 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
#+end_example
Fica claro que o valor de nunca foi alterado, porque ~2 × 0 = 0~!

View file

@ -0,0 +1,72 @@
r
q
r
q
r
bt
b main
l
b 5
r
info locals
k
r
info locals
c
del
l
b main
info locals
n
info locals
c
b main
del breakpoints
i breakpoints
b main
r
bt
i locals
n
i locals
info registers
q
b main
p a
r
p a
k
q
b main
p a
r
p a
n
n
p a
n
c
k
q
b main
r
n
n
p i
n
p i
c
k
del breakpoints
q
b main
r
n
p i
n
n
p 1
p i
n
p i
q

BIN
mods/05/exemplos/iloop Executable file

Binary file not shown.

12
mods/05/exemplos/iloop.c Normal file
View file

@ -0,0 +1,12 @@
#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;
}

BIN
mods/05/exemplos/notinit Executable file

Binary file not shown.

View file

@ -0,0 +1,13 @@
#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;
}

BIN
mods/05/exemplos/segfault Executable file

Binary file not shown.

View file

@ -0,0 +1,8 @@
#include <stdio.h>
int main() {
int *p = NULL; // NULL = (void *)0 - Ponteiro nulo
*p = 42; // ERRO: tentativa de escrever em um ponteiro nulo
printf("%d\n", *p);
return 0;
}