diff --git a/mods/03/README.org b/mods/03/README.org new file mode 100644 index 0000000..d0fc4e6 --- /dev/null +++ b/mods/03/README.org @@ -0,0 +1,111 @@ +#+title: Curso prático de introdução ao GDB +#+author: Blau Araujo +#+email: blau@debxp.org + +* 3. Formato ELF + +** Binários ELF, símbolos e códigos-fonte + +Todo arquivo executável pelo sistema é construído em um binário segundo um +formato padrão. No GNU/Linux, esse formato é o *ELF* (/Executable and Linkable Format/), +que inclui no binário: + +- O código de máquina do programa; +- Dados de variáveis globais e estáticas; +- Dados constantes; +- Tabelas de símbolos; +- Informações de depuração (se incluídas). + +Os primeiros bytes de um arquivo ELF contém um cabeçalho com diversas +informações sobre o binário, o que nós podemos listar com o utilitário +=readelf=: + +#+begin_example +:~$ readelf -h demo +Cabeçalho ELF: + Magia: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 + Classe: ELF64 + Dados: complemento 2, little endian + Versão: 1 (actual) + OS/ABI: UNIX - System V + Versão ABI: 0 + Tipo: DYN (Position-Independent Executable file) + Máquina: Advanced Micro Devices X86-64 + Versão: 0x1 + Endereço do ponto de entrada: 0x1050 + Início dos cabeçalhos do programa: 64 (bytes no ficheiro) + Start of section headers: 14944 (bytes no ficheiro) + Bandeiras: 0x0 + Tamanho deste cabeçalho: 64 (bytes) + Tamanho dos cabeçalhos do programa:56 (bytes) + Nº de cabeçalhos do programa: 14 + Tamanho dos cabeçalhos de secção: 64 (bytes) + Nº dos cabeçalhos de secção: 37 + Índice de tabela de cadeias da secção: 36 +#+end_example + +*** Símbolos e o código-fonte + +Símbolos são nomes associados a elementos do programa, como funções e +variáveis. Quando os símbolos de depuração são incluídos no binário +(compilando com =-g=, por exemplo), o GDB é capaz de: + +- Exibir nomes legíveis, em vez de endereços de memória; +- Acompanhar o fluxo do programa com o código-fonte; +- Receber definições de /breakpoints/ por nomes de funções; +- Fazer a associação de códigos binários com as linhas do código-fonte; +- Acessar nomes de variáveis, tipos, estruturas, etc. + +Nós podemos verificar se o programa foi compilado com os símbolos de +depuração com o utilitário =file=... + +Sem a opção =-g=: + +#+begin_example +:~$ gcc -o demo demo.c +:~$ file demo +demo: ELF 64-bit LSB pie executable [...] not stripped +#+end_example + +Com a opção =-g=: + +#+begin_example +:~$ gcc -g -o demo demo.c +:~$ file demo +demo: ELF 64-bit LSB pie executable [...] with debug_info, not stripped +#+end_example + +Repare que, desta vez, nós temos a informação =with debug_info= no final +da linha. + +Nós também podemos verificar se há símbolos de depuração a partir das +informações no formato ELF: + +#+begin_example +:~$ readelf -S demo | grep debug + [28] .debug_aranges PROGBITS 0000000000000000 00003037 + [29] .debug_info PROGBITS 0000000000000000 00003067 + [30] .debug_abbrev PROGBITS 0000000000000000 00003180 + [31] .debug_line PROGBITS 0000000000000000 0000324a + [32] .debug_str PROGBITS 0000000000000000 000032ba + [33] .debug_line_str PROGBITS 0000000000000000 00003367 +#+end_example + +Mas o próprio GDB informa se há símbolos de depuração ao iniciar... + +Sem a opção =-g=: + +#+begin_example +:~$ gcc -o demo demo.c +:~$ gdb demo +Reading symbols from demo... +(No debugging symbols found in demo) +#+end_example + +Com a opção =-g=: + +#+begin_example +:~$ gcc -g -o demo demo.c +:~$ gdb demo +Reading symbols from demo... +#+end_example diff --git a/mods/04/README.org b/mods/04/README.org new file mode 100644 index 0000000..b07a541 --- /dev/null +++ b/mods/04/README.org @@ -0,0 +1,290 @@ +#+title: Curso prático de introdução ao GDB +#+author: Blau Araujo +#+email: blau@debxp.org + +* 4. Aplicações em baixo e alto 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 +da máquina, o que inclui: + +- Acompanhamento de registradores da CPU; +- Inspeção de endereços de memória brutos; +- Execução instrução por instrução em assembly (=stepi=, =nexti=); +- Observação do /stack frame/ e chamadas (=backtrace=, =info frame=); +- Controle direto de /flags/, pilha, heap e segmentos do processo. + +Isso o torna útil para: + +- Diagnóstico de /segmentation faults/; +- Estudo de chamadas de sistema; +- Reversão e engenharia de baixo nível; +- Entendimento de como o compilador transforma código em instruções. + +*** Exemplo com um programa em assembly + +Código-fonte (=soma.asm=): + +#+begin_src asm +section .data + a dq 10 + b dq 20 + resultado dq 0 + +section .text + global _start + +_start: + mov rax, [a] + add rax, [b] + mov [resultado], rax + + mov rax, 60 ; syscall: exit + xor rdi, rdi ; status 0 + syscall +#+end_src + +Montagem e link-edição: + +#+begin_example +nasm -f elf64 -g soma.asm -o soma.o +ld soma.o -o soma +#+end_example + +Abertura com o GDB: + +#+begin_example +gdb ./soma +Reading symbols from ./soma... +#+end_example + +Definindo =_start= como ponto de parada: + +#+begin_example +(gdb) b _start +Breakpoint 1 at 0x401000: file soma.asm, line 10. +#+end_example + +Listando o fonte: + +#+begin_example +(gdb) l +1 section .data +2 a dq 10 +3 b dq 20 +4 resultado dq 0 +5 +6 section .text +7 global _start +8 +9 _start: +10 mov rax, [a] +(gdb) +11 add rax, [b] +12 mov [resultado], rax +13 +14 mov rax, 60 ; syscall: exit +15 xor rdi, rdi ; status 0 +16 syscall +#+end_example + +Executando: + +#+begin_example +(gdb) r +Starting program: /home/blau/git/gdb-pratico/mods/03/asm/soma + +Breakpoint 1, _start () at soma.asm:10 +10 mov rax, [a] +#+end_example + +Observando os dados rotulados como =a=, =b= e =resultado= (assembly não tem variáveis): + +#+begin_example +(gdb) x/1gx &a +0x402000 : 0x000000000000000a +(gdb) x/1gx &b +0x402008 : 0x0000000000000014 +(gdb) x/1gx &resultado +0x402010 : 0x0000000000000000 +#+end_example + +#+begin_quote +O comando =x= exibe um conteúdo na memória e, com as opções =/1gx=, eu estou +pedindo para mostrar uma /giant word/ (=1g=), que é uma palavra de 8bytes, em +base hexadecimal (=x=). +#+end_quote + +Executando as três instruções seguintes: + +#+begin_example +(gdb) n +11 add rax, [b] +(gdb) +12 mov [resultado], rax +(gdb) +14 mov rax, 60 ; syscall: exit +#+end_example + +Observando o novo valor em =resultado=: + +#+begin_example +(gdb) x/1gx &resultado +0x402010 : 0x000000000000001e +#+end_example + +Exibindo o estado atual de todos os registradores da CPU: + +#+begin_example +(gdb) i registers +rax 0x1e 30 +rbx 0x0 0 +rcx 0x0 0 +rdx 0x0 0 +rsi 0x0 0 +rdi 0x0 0 +rbp 0x0 0x0 +rsp 0x7fffffffe020 0x7fffffffe020 +r8 0x0 0 +r9 0x0 0 +r10 0x0 0 +r11 0x0 0 +r12 0x0 0 +r13 0x0 0 +r14 0x0 0 +r15 0x0 0 +rip 0x401018 0x401018 <_start+24> +eflags 0x206 [ PF IF ] +cs 0x33 51 +ss 0x2b 43 +ds 0x0 0 +es 0x0 0 +fs 0x0 0 +gs 0x0 0 +fs_base 0x0 0 +gs_base 0x0 0 +#+end_example + +Continuando a execução até o término: + +#+begin_example +(gdb) c +Continuing. +[Inferior 1 (process 222188) exited normally] +#+end_example + +*** Notações de tamanhos de palavra + +| Tamanho | Arquitetura x86-64 | NASM / Assembly | GDB (comando =x=) | +|---------+--------------------+-----------------+-----------------| +| 1 byte | byte | =byte= | =b= | +| 2 bytes | word | =word= | =h= (/halfword/) | +| 4 bytes | doubleword | =dword= | =w= (/word/) | +| 8 bytes | quadword | =qword= | =g= (/giant word/) | + +** O GDB e a programação em C/C++ + +O GDB tem suporte avançado para C e C++, oferecendo: + +- Identificação de tipos, nomes, escopos e estruturas; +- Acesso a variáveis locais, globais e parâmetros; +- Depuração de ponteiros e aritmética de ponteiros; +- Interação com /structs/, =typedef=, =enum=, =union=, etc.; +- Acompanhamento de chamadas recursivas e /stack frames/; +- Em C++: suporte a classes, herança, /namespaces/ e /templates/. + +*** Exemplo com um programa em C + +Código-fonte (=soma.c=): + +#+begin_src c +#include + +int soma(int a, int b) { + int resultado = a + b; + return resultado; +} + +int main() { + int x = 10, y = 20; + int z = soma(x, y); + printf("Resultado: %d\n", z); + return 0; +} +#+end_src + +Compilação: + +#+begin_example +gcc -g -o soma soma.c +#+end_example + +Abrindo com o GDB e definindo o ponto de parada na função =soma=: + +#+begin_example +:~$ gdb ./soma +Reading symbols from ./soma... +(gdb) b soma +Breakpoint 1 at 0x1143: file soma.c, line 4. +#+end_example + +Iniciando a execução do programa: + +#+begin_example +(gdb) r +Starting program: /home/blau/git/gdb-pratico/mods/03/c/soma +[Thread debugging using libthread_db enabled] +Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". + +Breakpoint 1, soma (a=10, b=20) at soma.c:4 +4 int resultado = a + b; +#+end_example + +Exibindo chamadas de funções na pilha: + +#+begin_example +(gdb) backtrace +#0 soma (a=10, b=20) at soma.c:4 +#1 0x0000555555555178 in main () at somac.c:10 +#+end_example + +Executando passo a passo até a chamada da função =printf=: + +#+begin_example +(gdb) n +5 return resultado; +(gdb) n +6 } +(gdb) n +main () at soma.c:11 +11 printf("Resultado: %d\n", z); +(gdb) backtrace +#0 main () at soma.c:11 +#+end_example + +Entrando na função =printf= (=glibc=): + +#+begin_example +(gdb) s +__printf (format=0x555555556004 "Resultado: %d\n") at ./stdio-common/printf.c:28 +warning: 28 ./stdio-common/printf.c: Arquivo ou diretório inexistente +#+end_example + +Observando as chamadas de funções na pilha: + +#+begin_example +(gdb) backtrace +#0 __printf (format=0x555555556004 "Resultado: %d\n") at ./stdio-common/printf.c:28 +#1 0x0000555555555194 in main () at somac.c:11 +#+end_example + +Continuando a execução até o término: + +#+begin_example +(gdb) c +Continuing. +Resultado: 30 +[Inferior 1 (process 223980) exited normally] +#+end_example + diff --git a/mods/04/asm/.gdb_history b/mods/04/asm/.gdb_history new file mode 100644 index 0000000..57086fa --- /dev/null +++ b/mods/04/asm/.gdb_history @@ -0,0 +1,3 @@ +b _start +r +k diff --git a/mods/04/asm/soma.asm b/mods/04/asm/soma.asm new file mode 100644 index 0000000..354fc4d --- /dev/null +++ b/mods/04/asm/soma.asm @@ -0,0 +1,16 @@ +section .data + a dq 10 + b dq 20 + resultado dq 0 + +section .text +global _start + +_start: + mov rax, [a] + add rax, [b] + mov [resultado], rax + + mov rax, 60 ; syscall: exit + xor rdi, rdi ; status 0 + syscall diff --git a/mods/04/c/.gdb_history b/mods/04/c/.gdb_history new file mode 100644 index 0000000..79439a7 --- /dev/null +++ b/mods/04/c/.gdb_history @@ -0,0 +1,2 @@ +b soma +r diff --git a/mods/04/c/soma.c b/mods/04/c/soma.c new file mode 100644 index 0000000..dfe7d73 --- /dev/null +++ b/mods/04/c/soma.c @@ -0,0 +1,13 @@ +#include + +int soma(int a, int b) { + int resultado = a + b; + return resultado; +} + +int main() { + int x = 10, y = 20; + int z = soma(x, y); + printf("Resultado: %d\n", z); + return 0; +}