Estensione di Memory Inspector per il debug C/C++

In Chrome 92 abbiamo introdotto Memory Inspector, uno strumento per ispezionare i buffer di memoria lineare. In questo articolo illustreremo in che modo abbiamo migliorato l'Inspector per il debug C/C++ e le sfide tecniche incontrate durante il percorso.

Di seguito sono riportati alcuni post del blog pertinenti se non hai mai utilizzato il debug C/C++ e l'Controllo memoria:

Introduzione

Lo strumento Memory Inspector offre opzioni di debug più efficaci per i buffer di memoria lineari. Nel caso di C/C++, puoi ispezionare gli oggetti di memoria C/C++ nella memoria WebAssembly.

Riconoscere i byte dell'oggetto tra la memoria WebAssembly circostante era un problema. Devi conoscere le dimensioni dell'oggetto e conteggiare i byte dall'inizio dell'oggetto. Nello screenshot seguente viene selezionato il primo byte di un array int32 a 10 elementi, ma non è immediatamente chiaro quali altri byte appartengono all'array. Non sarebbe bello poter riconoscere immediatamente tutti i byte che appartengono all'oggetto?

Screenshot della funzionalità di controllo della memoria originale con un singolo byte evidenziato

Evidenziazione degli oggetti in Controllo memoria

A partire da Chrome 107, lo strumento Memory Inspector evidenzia tutti i byte di un oggetto di memoria C/C++. In questo modo puoi distinguerli dalla memoria circostante.

Screenshot dell'ispettore della memoria aggiornato con un array evidenziato in modo vivace

Guarda il video qui sotto per vedere Memory Inspector in azione. Quando riveli l'array x in Controllo memoria, nel visualizzatore memoria viene mostrata la memoria evidenziata insieme a un nuovo chip al di sopra. Questo chip ti ricorda il nome e il tipo della memoria evidenziata. Fai clic sul chip per passare alla memoria dell'oggetto. Se passi il mouse sopra il chip, viene visualizzata un'icona a forma di croce. Fai clic sull'icona per rimuovere l'evidenziazione.

Quando selezioni un byte all'esterno dell'oggetto ispezionato, l'evidenziazione viene sfocata per evitare di distrarti. Per rimettere a fuoco, fai di nuovo clic su uno dei byte dell'oggetto o sul chip.

Il supporto dell'evidenziazione degli oggetti non è limitato agli array. Puoi anche ispezionare strutture, oggetti e puntatori. Grazie a queste modifiche, esplorare la memoria delle app C/C++ non è mai stato così facile.

Vuoi provare? Dovrai:

  • Avere Chrome 107 o versioni successive.
  • Installa l'estensione DWARF C/C++.
  • Attiva il debug DWARF in DevTools > Impostazioni. Impostazioni > Esperimenti > Debug WebAssemble: attiva il supporto DWARF.
  • Apri questa pagina dimostrativa.
  • Segui le istruzioni riportate nella pagina.

Esempio di debug

In questa sezione esamineremo un bug di prova per illustrare come utilizzare Memory Inspector per il debug di C/C++. Nell'esempio di codice riportato di seguito, un programmatore crea un array di interi e decide di utilizzare l'aritmetica dei puntatori per selezionare l'ultimo elemento. Sfortunatamente, il programmatore ha commesso un errore nel calcolo del puntatore e ora, invece di stampare l'ultimo elemento, il programma stampa valori senza senso.

#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;
}

Il programmatore utilizza Memory Inspector per eseguire il debug del problema. Puoi seguire questa demo. Innanzitutto, ispeziona l'array nell'strumento di ispezione della memoria e vede che l'array numbers contiene solo gli interi 1, 2, 3 e 4, come previsto.

Screenshot dell&#39;ispettore della memoria aperto con un array int32 ispezionato. Tutti gli elementi dell&#39;array sono evidenziati.

Successivamente, mostrano la variabile lastNumber dal riquadro Ambito e notano che il cursore punta a un numero intero esterno all'array. Con queste informazioni, il programmatore si rende conto di aver conteggiato erroneamente l'offset del puntatore nella riga 8. Doveva essere ptr + arraySize - 1.

Screenshot della funzionalità di controllo della memoria aperta che mostra la memoria evidenziata a cui punta un puntatore denominato &quot;lastNumber&quot;. La memoria evidenziata si trova subito dopo l&#39;ultimo byte dell&#39;array precedentemente evidenziato.

Anche se si tratta di un esempio pratico, illustra come l'evidenziazione degli oggetti trasmetta in modo efficace le dimensioni e la posizione degli oggetti di memoria, il che può aiutarti a capire meglio cosa succede all'interno della memoria dell'app C/C++.

In che modo DevTools individua gli elementi da evidenziare

In questa sezione esamineremo l'ecosistema di strumenti che consente il debug di C/C++. In particolare, scoprirai come DevTools, V8, l'estensione DWARF C/C++ ed Emscripten rendono possibile il debug C/C++ in Chrome.

Per sfruttare tutto il potenziale del debug C/C++ in DevTools, hai bisogno di due cose:

  • L'estensione DWARF C/C++ installata in Chrome
  • File di origine C/C++ compilati in WebAssembly con il compilatore Emscripten più recente, come indicato in questo post del blog

Ma perché? V8, il motore JavaScript e WebAssembly di Chrome, non sa come eseguire C o C++. Grazie a Emscripten, un compilatore C/C++ in WebAssembly, puoi compilare le app create in C o C++ come WebAssembly ed eseguirle nel browser.

Durante la compilazione, emscripten incorporerà i dati di debug di DWARF nel tuo file binario. A un livello generale, questi dati aiutano l'estensione a capire quali variabili WebAssembly corrispondono alle variabili C/C++ e altro ancora. In questo modo, DevTools può mostrarti le variabili C++ nonostante V8 esegua effettivamente WebAssembly. Se vuoi saperne di più, consulta questo post del blog per un esempio di dati di debug DWARF.

Cosa succede esattamente quando riveli il lastNumber? Non appena fai clic sull'icona della memoria, DevTools controlla la variabile che vuoi ispezionare. Quindi esegue una query all'estensione sul tipo di dati e sulla località di lastNumber. Non appena l'estensione risponde con queste informazioni, Memory Inspector può visualizzare lo slice di memoria pertinente e, conoscendone il tipo, può anche mostrare le dimensioni dell'oggetto.

Se guardi lastNumber nell'esempio precedente, potresti notare che abbiamo esaminato lastNumber: int *, ma il chip in Memory Inspector indica *lastNumber: int. Cosa succede? L'ispettore utilizza il dereferenziamento del puntatore in stile C++ per indicare il tipo di oggetto visualizzato. Se ispezioni un cursore, l'ispettore ti mostrerà cosa indica.

Evidenziazioni persistenti nei passaggi del debugger

Quando mostri un oggetto nell'inspector della memoria ed esegui un passaggio con il debugger, l'inspector mantiene l'evidenziazione se ritiene che sia ancora applicabile. Inizialmente, questa funzionalità non era prevista nella nostra roadmap, ma abbiamo capito subito che comprometteva la tua esperienza di debug. Immagina di dover controllare nuovamente l'array dopo ogni passaggio, come nel seguente video.

Quando il debugger raggiunge un nuovo punto di interruzione, Memory Inspector esegue nuovamente query su V8 e sull'estensione per la variabile associata all'evidenziazione precedente. Poi confronta le posizioni e i tipi di oggetti. Se corrispondono, l'evidenziazione rimane. Nel video qui sopra, è presente un ciclo for che scrive nell'array x. Queste operazioni non modificano il tipo o la posizione dell'array, che rimane evidenziato.

Potresti chiederti come questo influisce sui puntatori. Se hai un puntatore evidenziato e lo riassegni a un oggetto diverso, la vecchia e la nuova posizione degli oggetti evidenziati differiscono e l'evidenziazione scompare. Poiché l'oggetto appena puntato può trovarsi ovunque nella memoria di WebAssembly e probabilmente avrà poca relazione con la posizione della memoria precedente, rimuovere l'evidenziazione è più chiaro che passare a una nuova posizione di memoria. Puoi evidenziare di nuovo il puntatore facendo clic sulla relativa icona della memoria nel riquadro Ambito.

Conclusione

Questo articolo descrive i nostri miglioramenti a Memory Inspector per il debug C/C++. Ci auguriamo che le nuove funzionalità semplifichino il debug della memoria delle tue app C/C++. Se hai suggerimenti per migliorarla ulteriormente, comunicacelo segnalando un bug.

Passaggi successivi

Per scoprire di più, vedi: