Usando a extensão libheap para GDB na análise de heap

Esta extensão foi desenvolvida para Python 3, mas o ambiente GDB em uso possuía Python 2 integrado. Para resolver essa incompatibilidade, seria necessário recompilar o GDB com a opção --with-python, apontadno para o interpretador Python 3 correto.

Ao tentar utilizar o comando heapls, observa-se que parte das funcionalidades operou, porém com erros ao ler certos endereços de memória:

(gdb) heapls
Obtendo base do heap a partir de proc
           ENDEREÇO          TAMANHO          STATUS
sbrk_base  0x104f000
chunk      0x104f000        0x20            (em uso)
chunk      0x104f020        0x240           (em uso)
chunk      0x104f260        0x240           (em uso)
chunk      0x104f4a0        0x20b60         [!] Não foi possível ler o endereço 0x1070000
(F) FD 0x0 BK 0x0 [!] Não foi possível ler o endereço 0x1070000
(LC)
[!] Não foi possível ler o endereço 0x1070000
chunk      0x1070000        0x0             [!] Não foi possível ler o endereço 0x1070000
[!] Não foi possível ler o endereço 0x1070000
Exceção Python <type> int() argument must be a string or a number, not 'NoneType':
(F) FD Erro ocorrido no comando Python: int() argument must be a string or a number, not 'NoneType'</type>

Ao executar o comando básico heap, a saída indicou a ausência de arenas:

(gdb) heap
[!] Nenhuma arena encontrada em 0x7fae7992f780

Essa mensagem é gerada pelo script heap.py, especificamente neste bloco:

if (len(arg) == 0) and (ar_ptr.next == 0):
    print_error("Nenhuma arena encontrada em {:#x}".format(ar_ptr.address))
    return

Para diagnóstico, adicionei instruções de impressão no código, revelando que o endereço da arena principal (main_arena) era reconhecido, mas a estrutura malloc_state não era interpretada corretamente. Investigações adicionais mostraram que o atributo debugger refere-se a um objeto gdb.frame.

Ao inspecionar main_arena diretamente no GDB, seu campo next não pôde ser acessado via Python, porém, o valor hexadecimal correspondente foi obtido manualmente. Navegando manualmente pela lista encadeada de arenas através de seus ponteiros next, identificaram-se três estruturas, correlacionando com o número de alocações no programa em teste.

Verificou-se posteriormente que a versão do glibc configurada no arquivo libheap.cfg (2.27) diferia da versão efetivamente utilizada (2.17). Após a alteração da configuração para refletir a versão correta (2.17), o comando heap passou a listar as arenas corretamente:

(gdb) heap
Arena(s) encontrada(s):
  arena @ 0x7fae7992f780
  arena @ 0x7fae6c000020
  arena @ 0x7fae74000020

O comando mstats também passou a fornecer estatísticas detalhadas de alocação para cada arena, como system bytes e in use bytes.

Investigando a necessidade da variável thread_arena mencionada no código de heapls.py, constatou-se que este símbolo não está presente no contexto de depuração atual, mesmo após a troca entre threads. Isso sugere uma possível necessidade de compilação ou carregamento específico de símbolos de depuração relacionados a threads.

Referência: Documentação da API Python do GDB.

Tags: gdb libheap Python heap análise-de-memória

Publicado em 6-1 17:30 por Thomas