gdb-pratico/mods/04/README.org

296 lines
6.9 KiB
Org Mode
Raw Normal View History

2025-04-26 11:45:42 -03:00
#+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
2025-04-28 13:08:08 -03:00
** Objetivo
Conhecer os recursos do GDB que podem auxiliar no desenvolvimento e
depuração de programas em assembly e em C/C++.
2025-04-26 11:45:42 -03:00
** 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