diff --git a/mods/04/README.org b/mods/04/README.org index b07a541..9a2668b 100644 --- a/mods/04/README.org +++ b/mods/04/README.org @@ -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 diff --git a/mods/05/README.org b/mods/05/README.org new file mode 100644 index 0000000..4d4a1dd --- /dev/null +++ b/mods/05/README.org @@ -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 + +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 + +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 + +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~! + diff --git a/mods/05/exemplos/.gdb_history b/mods/05/exemplos/.gdb_history new file mode 100644 index 0000000..1cf4b08 --- /dev/null +++ b/mods/05/exemplos/.gdb_history @@ -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 diff --git a/mods/05/exemplos/iloop b/mods/05/exemplos/iloop new file mode 100755 index 0000000..09b4599 Binary files /dev/null and b/mods/05/exemplos/iloop differ diff --git a/mods/05/exemplos/iloop.c b/mods/05/exemplos/iloop.c new file mode 100644 index 0000000..a80a563 --- /dev/null +++ b/mods/05/exemplos/iloop.c @@ -0,0 +1,12 @@ +#include + +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; +} diff --git a/mods/05/exemplos/notinit b/mods/05/exemplos/notinit new file mode 100755 index 0000000..d984d03 Binary files /dev/null and b/mods/05/exemplos/notinit differ diff --git a/mods/05/exemplos/notinit.c b/mods/05/exemplos/notinit.c new file mode 100644 index 0000000..f812b7e --- /dev/null +++ b/mods/05/exemplos/notinit.c @@ -0,0 +1,13 @@ +#include + +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; +} diff --git a/mods/05/exemplos/segfault b/mods/05/exemplos/segfault new file mode 100755 index 0000000..812cb73 Binary files /dev/null and b/mods/05/exemplos/segfault differ diff --git a/mods/05/exemplos/segfault.c b/mods/05/exemplos/segfault.c new file mode 100644 index 0000000..e1adedc --- /dev/null +++ b/mods/05/exemplos/segfault.c @@ -0,0 +1,8 @@ +#include + +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; +}