No Chrome 92, lançamos o Inspetor de memória, uma ferramenta para inspecionar buffers de memória linear. Neste artigo, vamos discutir como melhoramos o Inspector para depuração C/C++ e os desafios técnicos encontrados.
Estas são algumas postagens relevantes do blog para iniciantes na depuração de C/C++ e no Memory Inspector (link em inglês):
- Você tem interesse em depuração profunda de memória? Consulte Apresentação do 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 rapidamente.
Introdução
O Inspetor de memória oferece opções de depuração mais eficientes para buffers de memória linear. No caso do C/C++, você pode inspecionar objetos de memória C/C++ na memória WebAssembly.
Reconhecer os bytes do seu objeto na memória do WebAssembly era 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 fica imediatamente claro quais outros bytes pertencem à matriz. Não seria ótimo se você pudesse reconhecer instantaneamente todos os bytes que pertencem ao objeto?
Objeto em destaque 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 você a diferenciá-los da memória ao redor.
Assista o vídeo abaixo para conferir o Inspetor de memória em ação. Ao revelar a matriz x
no Inspetor de memória, a memória destacada aparece no visualizador de memória com um novo chip 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, clique novamente nos 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 a navegação pela memória dos seus apps C/C++.
Quer tentar? Você precisará:
- ter o Chrome 107 ou mais recente;
- Instale a extensão DWARF do C/C++.
- Ative a depuração DWARF em DevTools > Settings > Experiments > WebAssemble Debugging: ativar suporte DWARF.
- Abra esta página de demonstração.
- Siga as instruções na página.
Exemplo de depuração
Nesta seção, vamos analisar um bug de brinquedo para ilustrar como usar o Memory Inspector para depuração C/C++. No exemplo de código abaixo, um programador cria uma matriz de números inteiros e decide usar a aritmética do ponteiro para selecionar o último elemento. Infelizmente, o programador cometeu um erro no cálculo do ponteiro e, em vez de mostrar o último elemento, o programa mostra 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 consulta o Inspetor de memória para depurar o problema. Acompanhe esta demonstração. Primeiro, eles inspecionam a matriz no Inspetor de memória e percebem que a matriz numbers
contém apenas os números inteiros 1
, 2
, 3
e 4
, conforme esperado.
Em seguida, ele revela a variável lastNumber
do painel Scope e percebe que o ponteiro aponta para um número inteiro fora da matriz. Equipado com esse conhecimento, o programador percebe que errou na contagem do deslocamento do ponteiro na linha 8. Deveria ser ptr + arraySize - 1
.
Embora seja um exemplo de brinquedo, ele ilustra como o destaque de objetos 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 app C/C++.
Como o DevTools define o que destacar
Nesta seção, vamos conhecer o ecossistema de ferramentas que permite a depuração C/C++. Especificamente, você aprenderá como o DevTools, o V8, a extensão DWARF do C/C++ e o Emscripten possibilitam a depuração C/C++ no Chrome.
Para aproveitar todo o potencial da depuração C/C++ no DevTools, você precisa de duas coisas:
- A extensão DWARF do C/C++ instalada no Chrome
- Arquivos de origem C/C++ compilados para o WebAssembly com o compilador Emscripten mais recente, conforme instruído nesta postagem do blog.
Mas por quê? O V8 , o mecanismo JavaScript e WebAssembly do Chrome, não sabe executar C ou C++. Graças ao Emscripten, um compilador de C/C++ para WebAssembly, você pode compilar apps criados em C ou C++ como WebAssembly e executá-los no navegador.
Durante a compilação, o emscripten incorpora 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 suas variáveis C/C++ e muito mais. Dessa forma, o DevTools pode mostrar suas variáveis C++ mesmo que o V8 esteja executando o WebAssembly. Caso tenha curiosidade, confira esta postagem do blog para um exemplo de dados de depuração DWARF.
O que acontece quando você revela o lastNumber
? Assim que você clicar no ícone de memória, o DevTools verificará qual variável você quer inspecionar. Em seguida, ela consulta a extensão sobre o tipo de dados e o local de lastNumber
. Assim que a extensão responder com essas informações, o Memory Inspector poderá mostrar a fração de memória relevante e saber o tipo, além de mostrar o tamanho do objeto.
Se você analisar lastNumber
no exemplo anterior, vai notar que inspecionamos lastNumber: int *
, mas o ícone no Inspetor de memória 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 vai mostrar para que ele aponta.
Destaques persistentes nas etapas do depurador
Quando você revela um objeto no Inspetor de memória e entra no depurador, o inspetor mantém o destaque se ele achar que ele ainda é aplicável. Inicialmente, não tínhamos esse recurso em nosso roteiro, mas rapidamente percebemos que isso comprometeria sua experiência de depuração. Imagine ter que inspecionar novamente a matriz após cada etapa, como no vídeo abaixo.
Quando o depurador atinge um novo ponto de interrupção, o Inspetor de memória consulta novamente o V8 e a extensão para a variável associada ao destaque anterior. Em seguida, ele compara os locais e tipos dos objetos. Se eles forem correspondentes, o destaque vai persistir. No vídeo acima, há um loop for gravado na matriz x
. Essas operações não alteram o tipo ou a posição da matriz, por isso ela permanece destacada.
Você pode se perguntar como isso afeta os ponteiros. Se você tiver um ponteiro destacado e reatribuí-lo a um objeto diferente, as posições antiga e nova dos objetos destacados serão diferentes, e o destaque desaparecerá. Como o objeto recém-pontilhado pode residir em qualquer lugar da memória do WebAssembly e provavelmente terá pouca relação com o local da memória anterior, remover o destaque é mais claro do que pular para um novo local da memória. É possível destacar o ponteiro novamente clicando no ícone de memória no painel Scope.
Conclusão
Este artigo descreveu nossas melhorias no Inspetor de memória para depuração 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: