Pular para o conteúdo principal

Integração com a Interface de Compilação JIT do GDB

A integração com a Interface de Compilação JIT do GDB permite que o V8 forneça ao GDB informações de símbolos e depuração para o código nativo emitido pelo runtime do V8.

Quando a Interface de Compilação JIT do GDB está desativada, um backtrace típico no GDB contém frames marcados com ??. Esses frames correspondem a código gerado dinamicamente:

#8  0x08281674 in v8::internal::Runtime_SetProperty (args=...) at src/runtime.cc:3758
#9 0xf5cae28e in ?? ()
#10 0xf5cc3a0a in ?? ()
#11 0xf5cc38f4 in ?? ()
#12 0xf5cbef19 in ?? ()
#13 0xf5cb09a2 in ?? ()
#14 0x0809e0a5 in v8::internal::Invoke (construct=false, func=..., receiver=..., argc=0, args=0x0,
has_pending_exception=0xffffd46f) at src/execution.cc:97

No entanto, habilitar a Interface de Compilação JIT do GDB permite que o GDB produza um rastreamento de pilha mais informativo:

#6  0x082857fc in v8::internal::Runtime_SetProperty (args=...) at src/runtime.cc:3758
#7 0xf5cae28e in ?? ()
#8 0xf5cc3a0a in loop () at test.js:6
#9 0xf5cc38f4 in test.js () at test.js:13
#10 0xf5cbef19 in ?? ()
#11 0xf5cb09a2 in ?? ()
#12 0x0809e1f9 in v8::internal::Invoke (construct=false, func=..., receiver=..., argc=0, args=0x0,
has_pending_exception=0xffffd44f) at src/execution.cc:97

Os frames ainda desconhecidos pelo GDB correspondem ao código nativo sem informações de origem. Consulte limitações conhecidas para mais detalhes.

A Interface de Compilação JIT do GDB está especificada na documentação do GDB: https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html

Pré-requisitos

  • V8 v3.0.9 ou mais recente
  • GDB 7.0 ou mais recente
  • Sistema operacional Linux
  • CPU com arquitetura compatível com Intel (ia32 ou x64)

Habilitando a Interface de Compilação JIT do GDB

Por padrão, a Interface de Compilação JIT do GDB está atualmente excluída da compilação e desabilitada em tempo de execução. Para habilitá-la:

  1. Compile a biblioteca V8 com ENABLE_GDB_JIT_INTERFACE definido. Se você estiver usando scons para compilar o V8, execute-o com gdbjit=on.
  2. Passe a flag --gdbjit ao iniciar o V8.

Para verificar se você habilitou a integração do JIT do GDB corretamente, tente definir um ponto de interrupção em __jit_debug_register_code. Essa função é chamada para notificar o GDB sobre novos objetos de código.

Limitações conhecidas

  • No lado do GDB, a Interface JIT atualmente (a partir do GDB 7.2) não lida com o registro de objetos de código de maneira muito eficiente. Cada novo registro leva mais tempo: com 500 objetos registrados, cada novo registro leva mais de 50ms; com 1000 objetos registrados, leva mais de 300 ms. Este problema foi relatado aos desenvolvedores do GDB, mas atualmente não há solução disponível. Para reduzir a pressão no GDB, a implementação atual da integração JIT do GDB opera em dois modos: padrão e completo (habilitado pela flag --gdbjit-full). No modo padrão, o V8 notifica o GDB apenas sobre objetos de código que possuem informações de origem anexadas (isso geralmente inclui todos os scripts do usuário). No modo completo, o GDB é notificado sobre todos os objetos de código gerados (stubs, ICs, trampolins).

  • No x64, o GDB é incapaz de desenrolar corretamente a pilha sem a seção .eh_frame (Problema 1053)

  • O GDB não é notificado sobre o código desserializado do snapshot (Problema 1054)

  • Apenas o sistema operacional Linux em CPUs compatíveis com Intel é suportado. Para diferentes sistemas operacionais, ou um cabeçalho ELF diferente deve ser gerado, ou um formato de objeto completamente diferente deve ser usado.

  • Habilitar a interface JIT do GDB desativa o GC compactador. Isso é feito para reduzir a pressão no GDB, já que desregistrar e registrar cada objeto de código movido acarretará uma sobrecarga considerável.

  • A integração JIT do GDB fornece apenas informações de origem aproximadas. Não fornece nenhuma informação sobre variáveis locais, argumentos de funções, layout da pilha, etc. Não permite executar passo a passo o código JavaScript ou definir um ponto de interrupção em uma linha específica. No entanto, é possível definir um ponto de interrupção em uma função pelo seu nome.