#+title: Curso prático de introdução ao GDB #+author: Blau Araujo #+email: blau@debxp.org * 3. Formato ELF 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 no binário 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