No Chrome 92, introduzimos o Inspetor de memória, uma ferramenta para inspecionar buffers de memória linear. Neste artigo, vamos falar sobre como melhoramos o Inspector para depuração de C/C++ e os desafios técnicos encontrados ao longo do caminho.
Estas são algumas postagens relevantes do blog se você é iniciante na depuração de C/C++ e no Memory Inspector:
- Interessado na depuração de memória profunda? Consulte Introdução ao Inspetor de memória.
- Quer uma introdução ao pacote completo de ferramentas de depuração de C/C++? Consulte Como depurar o WASM com ferramentas modernas e Como depurar o WebAssembly mais rápido.
Introdução
O Memory Inspector oferece opções de depuração mais eficientes para buffers de memória linear. No caso de C/C++, você pode inspecionar objetos de memória C/C++ na memória do WebAssembly.
Reconhecer os bytes do objeto entre a memória do WebAssembly foi um problema. Você precisa saber o tamanho do objeto e contar os bytes desde o início. Na captura de tela abaixo, o primeiro byte de uma matriz int32
de 10 elementos está selecionado, mas não está imediatamente claro quais outros bytes pertencem à matriz. Não seria ótimo se você pudesse reconhecer instantaneamente todos os bytes que pertencem ao objeto?
Destaque de objeto no Inspetor de memória
A partir do Chrome 107, o Inspetor de memória destaca todos os bytes de um objeto de memória C/C++. Isso ajuda a diferenciá-los da memória ao redor.
Assista o vídeo abaixo para conferir o Memory Inspector em ação. À medida que você revela a matriz x
no Inspetor de memória, a memória destacada aparece no Memory Viewer junto com um novo ícone logo acima dela. Esse ícone lembra o nome e o tipo da memória destacada. Clique no ícone para acessar a memória do objeto. Se você passar o cursor sobre o ícone, um ícone de cruz vai aparecer. Clique nele para remover o destaque.
Quando você seleciona um byte fora do objeto inspecionado, o destaque desfoca para evitar distrair você. Para mudar o foco novamente, clique novamente em qualquer um dos bytes do objeto ou no ícone.
O suporte ao destaque de objetos não se limita a matrizes. Também é possível inspecionar structs, objetos e ponteiros. Essas mudanças facilitam ainda mais a exploração da memória dos seus apps C/C++.
Quer testar? Será necessário:
- Ter o Chrome 107 ou mais recente.
- Instale a extensão DWARF do C/C++.
- Ative a depuração DWARF no DevTools > Configurações > Experimentos > Depuração WebAssemble: ativar o suporte a DWARF.
- Abra esta página de demonstração.
- Siga as instruções na página.
Exemplo de depuração
Nesta seção, vamos dar uma olhada em um bug para ilustrar como você pode usar o Memory Inspector para depuração de C/C++. No exemplo de código abaixo, um programador cria uma matriz de números inteiros e decide usar a aritmética de ponteiro para selecionar o último elemento. Infelizmente, o programador cometeu um erro no cálculo do ponteiro e agora, em vez de exibir o último elemento, o programa exibe valores sem sentido.
#include <iostream>
int main()
{
int numbers[] = {1, 2, 3, 4};
int *ptr = numbers;
int arraySize = sizeof(numbers)/sizeof(int);
int* lastNumber = ptr + arraySize; // Can you notice the bug here?
std::cout <<../ *lastNumber <<../ '\n';
return 0;
}
O programador usa o Memory Inspector para depurar o problema. Acompanhe esta demonstração. Primeiro, eles inspecionam a matriz no Memory Inspector e verificam que a matriz numbers
contém apenas os números inteiros 1
, 2
, 3
e 4
, como esperado.
Em seguida, ela revela a variável lastNumber
do painel Scope e percebe que o ponteiro aponta para um número inteiro fora da matriz. Com esse conhecimento, o programador percebe que contou errado o deslocamento do ponteiro na linha 8. O valor deveria ser ptr + arraySize - 1
.
Embora esse seja um exemplo de brinquedo, ele ilustra como o destaque de objeto transmite efetivamente o tamanho e a posição dos objetos de memória, o que pode ajudar você a entender melhor o que está acontecendo na memória do seu aplicativo C/C++.
Como o DevTools descobre o que destacar
Nesta seção, vamos analisar o ecossistema de ferramentas que permitem a depuração de C/C++. Especificamente, você vai aprender como o DevTools, o V8, a extensão C/C++ DWARF e o Emscripten tornam possível a depuração de C/C++ no Chrome.
Para aproveitar ao máximo a depuração de C/C++ no DevTools, você precisa de duas coisas:
- A extensão C/C++ DWARF instalada no Chrome
- Arquivos de origem C/C++ compilados para WebAssembly com o compilador Emscripten mais recente, conforme instruído nesta postagem do blog.
Mas por quê? O V8, mecanismo do JavaScript e do WebAssembly do Chrome, não sabe como executar C ou C++. Graças ao Emscripten, um compilador C/C++ para WebAssembly, é possível compilar apps criados em C ou C++ como WebAssembly e executá-los no navegador.
Durante a compilação, o emscripten incorporará dados de depuração do DWARF ao binário. De modo geral, esses dados ajudam a extensão a descobrir quais variáveis do WebAssembly correspondem às variáveis C/C++ e muito mais. Dessa forma, o DevTools pode mostrar suas variáveis C++ mesmo que o V8 realmente execute o WebAssembly. Se quiser saber mais, confira esta postagem do blog (em inglês) para ver um exemplo de dados de depuração do DWARF.
O que acontece quando você revela o lastNumber
? Assim que você clica no ícone de memória, o DevTools verifica qual variável você quer inspecionar. Em seguida, ele consulta a extensão no tipo de dados e local de lastNumber
. Assim que a extensão responder com essa informação, o Memory Inspector poderá exibir a fração relevante de memória e saber o tipo dela, também poderá mostrar o tamanho do objeto.
Se você olhar para lastNumber
no exemplo anterior, vai notar que inspecionamos lastNumber: int *
, mas o chip no Memory Inspector diz *lastNumber: int
. O que está acontecendo? O inspetor usa a desreferenciamento de ponteiro no estilo C++ para indicar o tipo de objeto mostrado a você. Se você inspecionar um ponteiro, o inspetor mostrará para que ele aponta.
Como manter destaques em etapas do depurador
Quando você revela um objeto no Inspetor de memória e avança com o depurador, o Inspetor mantém o destaque se ele achar que ele ainda é relevante. Inicialmente, não tínhamos esse recurso no nosso plano, mas percebemos rapidamente que isso comprometia sua experiência de depuração. Imagine ter que inspecionar a matriz novamente após cada etapa, como no vídeo abaixo.
Quando o depurador atinge um novo ponto de interrupção, o Memory Inspector consulta novamente o V8 e a extensão da variável associada ao destaque anterior. Em seguida, ela compara os locais e tipos dos objetos. Se forem iguais, o destaque persiste. No vídeo acima, há um loop for que grava na matriz x
. Essas operações não mudam o tipo ou a posição da matriz, portanto, ela permanece destacada.
Você pode se perguntar como isso afeta os ponteiros. Se você tiver um ponteiro destacado e reatribuí-lo a outro objeto, as posições antiga e nova dos objetos destacados serão diferentes, e o destaque desaparecerá. Como o objeto recém-apontado pode estar em qualquer lugar na memória do WebAssembly e provavelmente terá pouca relação com o local de memória anterior, remover o destaque é mais claro do que pular para um novo local de memória. Para destacar o ponteiro novamente, clique no ícone de memória dele no painel Escopo.
Conclusão
Este artigo descreve nossas melhorias no Inspetor de memória para depuração de C/C++. Esperamos que os novos recursos simplifiquem a depuração da memória dos seus apps C/C++. Se você tiver sugestões para melhorar ainda mais, registre um bug.
O que vem em seguida?
Para saber mais, veja: