conteúdo das partes 4 e 5
This commit is contained in:
parent
325a77ae6c
commit
5e33085491
9 changed files with 341 additions and 0 deletions
|
@ -4,6 +4,11 @@
|
|||
|
||||
* 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 permite observar e controlar a execução de programas no nível mais próximo
|
||||
|
|
231
mods/05/README.org
Normal file
231
mods/05/README.org
Normal 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~!
|
||||
|
72
mods/05/exemplos/.gdb_history
Normal file
72
mods/05/exemplos/.gdb_history
Normal 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
BIN
mods/05/exemplos/iloop
Executable file
Binary file not shown.
12
mods/05/exemplos/iloop.c
Normal file
12
mods/05/exemplos/iloop.c
Normal 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
BIN
mods/05/exemplos/notinit
Executable file
Binary file not shown.
13
mods/05/exemplos/notinit.c
Normal file
13
mods/05/exemplos/notinit.c
Normal 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
BIN
mods/05/exemplos/segfault
Executable file
Binary file not shown.
8
mods/05/exemplos/segfault.c
Normal file
8
mods/05/exemplos/segfault.c
Normal 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;
|
||||
}
|
Loading…
Add table
Reference in a new issue