No Chrome 92, apresentamos o Memory Inspector, 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 de blog relevantes se você não conhece a depuração de C/C++ e o Memory Inspector (link em inglês):
- Tem interesse em 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 C/C++? Consulte Como depurar o WASM com ferramentas modernas e Como depurar o WebAssembly mais rápido.
Introdução
O Inspetor de memória oferece opções de depuração mais eficientes para buffers de memória linear. No caso de C/C++, é possível inspecionar objetos de memória C/C++ na memória do WebAssembly.
Reconhecer os bytes do seu objeto entre a memória do WebAssembly ao redor era um ponto problemático. Você precisa saber o tamanho do objeto e contar os bytes a partir do início dele. 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 reconhecer instantaneamente todos os bytes que pertencem ao objeto?
Destaque de objeto no Inspetor de memória
A partir do Chrome 107, o Memory Inspector 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 mostra 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 que está inspecionando, o destaque é desfocado para evitar distrações. Para mudar o foco novamente, clique novamente em qualquer um dos bytes do objeto ou no ícone.
O suporte para destaque de objetos não é limitado a matrizes. Também é possível inspecionar structs, objetos e ponteiros. Com essas mudanças, ficou mais fácil analisar a memória dos seus apps C/C++.
Quer testar? Será necessário:
- Ter o Chrome 107 ou mais recente.
- Instale a extensão C/C++ DWARF.
- Ative a depuração DWARF em Ferramentas do desenvolvedor > Configurações > Experimentos > Depuração de WebAssembly: Ativar 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 analisar um bug de brinquedo para ilustrar como usar o Memory Inspector na 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. Confira 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, eles revelam a variável lastNumber
no painel Escopo e notam 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 seja um exemplo simples, ele ilustra como o destaque de objetos transmite de forma eficaz o tamanho e a posição dos objetos de memória, o que pode ajudar a entender melhor o que está acontecendo na memória do app 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 toda a capacidade da 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 JavaScript e WebAssembly do Chrome, não sabe 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 vai incorporar dados de depuração DWARF ao seu 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 você tiver curiosidade, confira esta postagem do blog para conferir um exemplo de dados de depuração 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, 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 parte relevante da memória e, sabendo o tipo, 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 desreferenciação de ponteiro no estilo C++ para indicar o tipo do objeto mostrado. Se você inspecionar um ponteiro, o inspetor vai mostrar para onde ele aponta.
Persistência de destaques nas 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, então 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: