A estrada até agora
Há um ano, o Chrome anunciou o suporte inicial. para depuração nativa do WebAssembly no Chrome DevTools.
Demonstramos o suporte básico e falamos sobre oportunidades de uso de informações do DWARF em vez de mapas de origem abertos para nós no futuro:
- Como resolver nomes de variáveis
- Tipos de impressão com estilo
- Avaliação de expressões nos idiomas de origem
- …e muito mais!
Hoje, estamos felizes em mostrar que os recursos prometidos ganham vida e o progresso feito pelas equipes de Emscripten e Chrome DevTools em especial para apps em C e C++.
Antes de começarmos, tenha em mente que esta ainda é uma versão Beta da nova experiência, você precisa usar a versão mais recente de todas as ferramentas por sua conta e risco. Se você encontrar algum problema, informe-o para https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Vamos começar com o mesmo exemplo simples de C da última vez:
#include <stdlib.h>
void assert_less(int x, int y) {
if (x >= y) {
abort();
}
}
int main() {
assert_less(10, 20);
assert_less(30, 20);
}
Para compilá-lo, usamos a versão mais recente do Emscripten (em inglês).
e transmitir uma flag -g
, assim como na postagem original, para incluir instruções
informações:
emcc -g temp.c -o temp.html
Agora podemos exibir a página gerada de um servidor HTTP localhost (por exemplo, com serve), e abra-o na versão mais recente do Chrome Canary.
Desta vez, também vamos precisar de uma extensão auxiliar que se integre às Ferramentas do desenvolvedor do Chrome e ajude a entender todas as informações de depuração codificadas no arquivo WebAssembly. Instale a extensão neste link: goo.gle/wasm-debugging-extension
Além disso, ative a depuração do WebAssembly no DevTools Experimentos. Abra o Chrome DevTools, clique no ícone de engrenagem (⚙) no canto superior direito do painel do DevTools, acesse o painel Experiments e marque WebAssembly Debugging: Enable DWARF support.
Quando você fechar as Configurações, o DevTools vai sugerir a atualização automática para aplicar configurações, vamos fazer isso. É isso por hoje.
Agora podemos voltar para o painel Origens e ativar a opção Pausar no exceções (ícone ⏸), marque Pausar em exceções capturadas e atualize a página. O DevTools vai ser pausado em uma exceção:
Por padrão, ele para em um código de cola gerado pelo Emscripten, mas à
direita, você pode ver uma visualização Call Stack que representa o stacktrace do
erro e pode navegar até a linha C original que invocou
abort
:
Na visualização Escopo, você vai encontrar os nomes originais
e valores de variáveis no código C/C++, e não precisar mais descobrir
o que significa nomes distorcidos como $localN
e como eles se relacionam com o
o código-fonte criado por você.
Isso se aplica não apenas a valores primitivos, como números inteiros, mas também a tipos compostos, como estruturas, classes, matrizes etc.
Suporte a tipos avançados
Vejamos um exemplo mais complicado para mostrar esses casos. Isso vamos desenhar um fractal de Mandelbrot com seguinte código C++:
#include <SDL2/SDL.h>
#include <complex>
int main() {
// Init SDL.
int width = 600, height = 600;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window;
SDL_Renderer* renderer;
SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_OPENGL, &window,
&renderer);
// Generate a palette with random colors.
enum { MAX_ITER_COUNT = 256 };
SDL_Color palette[MAX_ITER_COUNT];
srand(time(0));
for (int i = 0; i < MAX_ITER_COUNT; ++i) {
palette[i] = {
.r = (uint8_t)rand(),
.g = (uint8_t)rand(),
.b = (uint8_t)rand(),
.a = 255,
};
}
// Calculate and draw the Mandelbrot set.
std::complex<double> center(0.5, 0.5);
double scale = 4.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
std::complex<double> point((double)x / width, (double)y / height);
std::complex<double> c = (point - center) * scale;
std::complex<double> z(0, 0);
int i = 0;
for (; i < MAX_ITER_COUNT - 1; i++) {
z = z * z + c;
if (abs(z) > 2.0)
break;
}
SDL_Color color = palette[i];
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(renderer, x, y);
}
}
// Render everything we've drawn to the canvas.
SDL_RenderPresent(renderer);
// SDL_Quit();
}
Este aplicativo ainda é bem pequeno, ele é um de código aberto com 50 linhas de código, mas dessa vez também APIs externas, como a biblioteca SDL para gráficos, bem como números complexos do biblioteca C++ padrão.
Vou compilá-lo com a mesma flag -g
acima para incluir
informações de depuração. Também vou pedir que o Emscripten forneça os
e permitem memória dimensionada arbitrariamente:
emcc -g mandelbrot.cc -o mandelbrot.html \ -s USE_SDL=2 \ -s ALLOW_MEMORY_GROWTH=1
Quando abro a página gerada no navegador, vejo a bela forma fractal com algumas cores aleatórias:
Quando abro o DevTools, novamente, vejo o arquivo C++ original. Isso momento, porém, não temos um erro no código (uau!), então vamos definir algum ponto de interrupção no início do nosso código.
Quando a página for recarregada novamente, o depurador será pausado dentro da Fonte C++:
Já podemos ver todas as variáveis à direita, mas apenas width
e height
são inicializados no momento, então não há muito o que
ser inspecionado.
Vamos definir outro ponto de interrupção dentro do loop principal de Mandelbrot e retomar a execução para avançar um pouco.
Nesse ponto, o palette
foi preenchido com algumas cores aleatórias,
e podemos expandir a matriz e as estruturas
SDL_Color
individuais e inspecionar os componentes para verificar se
tudo está certo. Por exemplo, o canal "alpha" está sempre definido
como opacidade total. Da mesma forma, podemos expandir e verificar
partes imaginárias do número complexo armazenado na variável center
.
Se você quer acessar uma propriedade aninhada em muitos níveis que seria difícil de acessar navegar pela visualização Escopo, use o Console da avaliação. No entanto, expressões C++ mais complexas ainda não são compatíveis.
Vamos retomar a execução algumas vezes e conferir como o x
interno está
mudando também. Para isso, basta olhar novamente na visualização Escopo, adicionar
o nome da variável à lista de observação, avaliá-la no console ou
passar o cursor sobre a variável no código-fonte:
A partir daqui, podemos inserir ou ignorar instruções C++ e observar como outras variáveis também estão mudando:
Ok, isso tudo funciona muito bem quando uma informação de depuração está disponível, mas e se quisermos depurar um código que não foi criado com o comando opções?
Depuração de WebAssembly bruto
Por exemplo, pedimos ao Emscripten para fornecer uma biblioteca SDL pré-criada para
em vez de compilá-los nós mesmos da fonte, pelo menos
não há como o depurador encontrar fontes associadas.
Vamos entrar novamente para acessar o SDL_RenderDrawColor
:
Estamos de volta à experiência de depuração bruta do WebAssembly.
Isso pode parecer um pouco assustador e não é algo com que a maioria dos desenvolvedores da Web precisa lidar, mas, às vezes, você pode querer depurar uma biblioteca criada sem informações de depuração, seja porque é uma biblioteca de 3o que você não tem controle ou porque você encontra um desses bugs que ocorre apenas na produção.
Para ajudar nesses casos, também fizemos algumas melhorias na experiência básica de depuração.
Primeiro, se você já usou a depuração bruta do WebAssembly, talvez
perceba que toda a desmontagem agora é mostrada em um único arquivo. Não
é mais necessário adivinhar qual função uma entrada Sources wasm-53834e3e/
wasm-53834e3e-7
possivelmente corresponde.
Novo esquema de geração de nomes
Também melhoramos os nomes na visualização de desmontagem. Antes, os e-mails eram exibidos apenas índices numéricos ou, no caso de funções, nenhum nome.
Agora estamos gerando nomes de forma semelhante a outras ferramentas de desmontagem,
usando dicas da seção de nome do WebAssembly,
caminhos de importação/exportação e, por fim, se tudo mais falhar, gerando
com base no tipo e no índice do item, como $func123
. Você pode
veja como, na captura de tela acima, isso já ajuda a obter um pouco
stack traces e desmontagem mais legíveis.
Quando não há informações de tipo disponíveis, pode ser difícil inspecionar qualquer valor além dos primitivos. Por exemplo, os ponteiros aparecem como números inteiros normais, sem nenhuma maneira de saber o que está armazenado neles na memória.
Inspeção da memória
Antes, só era possível expandir o objeto de memória do WebAssembly, representado por env.memory
na visualização Escopo, para procurar
bytes individuais. Isso funcionou em alguns cenários triviais, mas não foi
muito conveniente para expandir e não permitiam reinterpretar dados
em formatos diferentes de valores de bytes. Também adicionamos um novo recurso para ajudar
com isso: um inspetor de memória linear.
Se você clicar com o botão direito do mouse em env.memory
,
chamada Inspecionar memória:
Ao clicar, um Memory Inspector será aberto. Nele, é possível inspecionar a memória do WebAssembly em visualizações hexadecimais e ASCII, navegar até endereços específicos e interpretar os dados em diferentes formatos:
Cenários avançados e ressalvas
Como criar o perfil do código WebAssembly
Quando você abre o DevTools, o código do WebAssembly é "rebaixado" para uma
versão não otimizada para permitir a depuração. Essa versão é muito mais lenta,
Isso significa que você não pode confiar em console.time
, performance.now
e outros métodos para medir a velocidade do código enquanto o DevTools
aberto, pois os números obtidos não representam o desempenho real
de verdade.
Em vez disso, use o painel Performance do DevTools. que vai executar o código na velocidade máxima e detalhamento do tempo gasto em diferentes funções:
Como alternativa, é possível executar o aplicativo com o DevTools fechado. abra-os ao terminar para inspecionar o console.
Vamos melhorar os cenários de criação de perfil no futuro, mas, por enquanto, é importante considerar isso. Para saber mais sobre o WebAssembly de classificação de níveis, confira nossos documentos sobre o pipeline de compilação do WebAssembly.
Criar e depurar em diferentes máquinas (incluindo Docker / host)
Ao criar em um Docker, em uma máquina virtual ou em um servidor de build remoto, é provável que você encontre situações em que os caminhos para os arquivos de origem usados durante o build não correspondem aos caminhos no seu sistema de arquivos em que o Chrome DevTools está sendo executado. Nesse caso, os arquivos aparecerão Sources, mas falha ao carregar.
Para corrigir esse problema, implementamos uma funcionalidade de mapeamento de caminho nas opções de extensão do C/C++. Você pode usá-lo para remapear caminhos arbitrários e ajudar o DevTools a localizar fontes.
Por exemplo, se o projeto na sua máquina host estiver em um caminho
C:\src\my_project
, mas foi criado dentro de um contêiner do Docker em que
esse caminho foi representado como /mnt/c/src/my_project
, será possível remapear
durante a depuração especificando esses caminhos como prefixos:
O primeiro prefixo correspondente "vence". Se você conhece outras linguagens de programação
depuradores, essa opção é semelhante ao comando set substitute-path
no GDB ou em uma configuração target.source-map
no LLDB.
Como depurar builds otimizados
Como em qualquer outro idioma, a depuração funciona melhor se as otimizações estiverem desativadas. As otimizações podem funcionar em linha umas nas outras, reordenar ou remover partes dele completamente, e tudo isso tem pode confundir o depurador e, consequentemente, você como usuário.
Se você não se importar com uma experiência de depuração mais limitada e ainda quiser
depurar um build otimizado, a maioria das otimizações vai funcionar como
esperado, exceto a in-line de função. Planejamos resolver as questões restantes
problemas no futuro, mas, por enquanto, use -fno-inline
para
desativá-la ao compilar com qualquer otimização de nível -O
, por exemplo:
emcc -g temp.c -o temp.html \ -O3 -fno-inline
Separar as informações de depuração
As informações de depuração preservam muitos detalhes sobre o código, tipos, variáveis, funções, escopos e locais definidos, tudo o que pode ser útil para o depurador. Como resultado, muitas vezes pode ser maior do que o próprio código.
Para acelerar o carregamento e a compilação do módulo WebAssembly, divida essas informações de depuração em um arquivo WebAssembly separado. Para fazer isso no Emscripten, transmita uma flag -gseparate-dwarf=…
com
o nome de arquivo desejado:
emcc -g temp.c -o temp.html \ -gseparate-dwarf=temp.debug.wasm
Nesse caso, o aplicativo principal armazena apenas um nome de arquivo
temp.debug.wasm
, e a extensão auxiliar pode localizá-lo e
carregá-lo quando você abrir o DevTools.
Quando combinado com otimizações, como a descrita acima, esse recurso pode ser usado para enviar builds de produção quase otimizados do aplicativo e, mais tarde, depurá-los com um arquivo local. Nesse caso, também vamos precisar substituir o URL armazenado para ajudar a extensão a encontrar o arquivo secundário, por exemplo:
emcc -g temp.c -o temp.html \ -O3 -fno-inline \ -gseparate-dwarf=temp.debug.wasm \ -s SEPARATE_DWARF_URL=file://[local path to temp.debug.wasm]
Continua depois…
Ufa, foram muitos recursos novos!
Com todas essas novas integrações, o Chrome DevTools se torna um depurador viável e poderoso, não apenas para JavaScript, mas também para apps C e C++, tornando mais fácil do que nunca criar apps, desenvolvidos em várias tecnologias, e levá-los a uma Web compartilhada e multiplataforma.
No entanto, nossa jornada ainda não terminou. Algumas das coisas que trabalhando daqui para frente:
- Limpar os pontos problemáticos na experiência de depuração.
- Adição de suporte a formatadores de tipo personalizados.
- Estamos trabalhando em melhorias na criação de perfis para apps do WebAssembly.
- Adição de suporte à cobertura de código para facilitar a localização códigos não utilizados.
- Melhoria do suporte a expressões na avaliação do console.
- Adição do suporte a mais idiomas.
- … e mais!
Enquanto isso, ajude a melhorar o produto testando a versão Beta atual no seu próprio código e informando os problemas encontrados em https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Fazer o download dos canais de visualização
Use o Chrome Canary, Dev ou Beta como seu navegador de desenvolvimento padrão. Esses canais de visualização dão acesso aos recursos mais recentes das Ferramentas do desenvolvedor, permitem testar APIs avançadas da plataforma Web e encontrar problemas no seu site antes dos usuários.
Como entrar em contato com a equipe do Chrome DevTools
Use as opções a seguir para discutir os novos recursos e mudanças na postagem ou qualquer outro assunto relacionado ao DevTools.
- Envie uma sugestão ou feedback pelo site crbug.com.
- Informe um problema do DevTools usando Mais opções > Ajuda > Relate problemas no DevTools no DevTools.
- Envie um tweet em @ChromeDevTools.
- Deixe comentários nos vídeos Novidades do DevTools no YouTube ou Dicas do DevTools no YouTube.