conteúdo das partes 3 e 4
This commit is contained in:
parent
e7e8e524df
commit
f4062e59b7
6 changed files with 435 additions and 0 deletions
111
mods/03/README.org
Normal file
111
mods/03/README.org
Normal file
|
@ -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
|
290
mods/04/README.org
Normal file
290
mods/04/README.org
Normal file
|
@ -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 <a>: 0x000000000000000a
|
||||||
|
(gdb) x/1gx &b
|
||||||
|
0x402008 <b>: 0x0000000000000014
|
||||||
|
(gdb) x/1gx &resultado
|
||||||
|
0x402010 <resultado>: 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 <resultado>: 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 <stdio.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
3
mods/04/asm/.gdb_history
Normal file
3
mods/04/asm/.gdb_history
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
b _start
|
||||||
|
r
|
||||||
|
k
|
16
mods/04/asm/soma.asm
Normal file
16
mods/04/asm/soma.asm
Normal file
|
@ -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
|
2
mods/04/c/.gdb_history
Normal file
2
mods/04/c/.gdb_history
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
b soma
|
||||||
|
r
|
13
mods/04/c/soma.c
Normal file
13
mods/04/c/soma.c
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue