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

In Chrome 92 abbiamo introdotto Memory Inspector, uno strumento per l'ispezione dei buffer di memoria lineari. In questo articolo, illustreremo come abbiamo migliorato l'ispettore per il debug di C/C++ e i problemi tecnici riscontrati lungo il percorso.

Di seguito sono riportati alcuni post del blog pertinenti per chi non ha familiarità con il debug di C/C++ e con Memory Inspector:

Introduzione

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

Il riconoscimento dei byte dell'oggetto nella memoria di WebAssembly circostante è stato un problema. Devi conoscere le dimensioni dell'oggetto e contare i byte a partire dall'inizio. Nello screenshot seguente, viene selezionato il primo byte di un array int32 di 10 elementi, ma non è chiaro quali altri byte appartengono all'array. Non sarebbe bello se potessi riconoscere immediatamente tutti i byte che appartengono all'oggetto?

Screenshot dello strumento di controllo della memoria originale con un singolo byte evidenziato

Evidenziazione degli oggetti in Controllo memoria

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

Screenshot dello strumento di controllo della memoria aggiornato con un array evidenziato in modo vivace

Guarda il video qui sotto per vedere Controllo memoria in azione. Quando mostri l'array x in Memory Inspector, la memoria evidenziata viene visualizzata nel visualizzatore di memoria insieme a un nuovo chip subito 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 al di fuori dell'oggetto che ispezioni, l'evidenziazione viene sfocata per evitare di distrarti. Per riorientarlo, fai di nuovo clic su uno dei byte dell'oggetto o sul chip.

Il supporto per l'evidenziazione degli oggetti non è limitato agli array. Puoi anche ispezionare struct, oggetti e puntatori. Queste modifiche rendono l'esplorazione della memoria delle tue app C/C++ più facile che mai.

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 demo.
  • Segui le istruzioni riportate nella pagina.

Esempio di debug

In questa sezione, diamo un'occhiata a un bug dei giocattoli per spiegare come utilizzare Memory Inspector per il debug di C/C++. Nell'esempio di codice riportato di seguito, un programmatore crea un array di numeri interi e decide di utilizzare l'aritmetica del puntatore 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 in Memory Inspector e nota che l'array numbers contiene solo i numeri interi 1, 2, 3 e 4, come previsto.

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

Dopodiché mostrano la variabile lastNumber nel riquadro Ambito e notano che il puntatore punta a un numero intero esterno all'array. Grazie a queste conoscenze, il programmatore si rende conto di aver sbagliato nel calcolo dell'offset del puntatore alla riga 8. Dovrebbe essere ptr + arraySize - 1.

Screenshot dello strumento di controllo della memoria aperto che mostra la memoria evidenziata verso la quale punta un puntatore chiamato &quot;lastNumber&quot;. La memoria evidenziata si trova subito dopo l&#39;ultimo byte dell&#39;array evidenziato in precedenza.

Sebbene questo sia un esempio di giocattolo, illustra come l'evidenziazione degli oggetti trasmette in modo efficace le dimensioni e la posizione degli oggetti in memoria, il che può aiutarti a capire meglio cosa sta succedendo nella memoria della tua app C/C++.

In che modo DevTools individua gli aspetti da evidenziare

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

Per sfruttare al meglio il debug C/C++ in DevTools, sono necessari due aspetti:

  • L'estensione DWARF C/C++ installata in Chrome
  • File sorgente C/C++ compilati in WebAssembly con l'ultimo compilatore Emscripten, 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 da C/C++ a WebAssembly, puoi compilare le app create in C o C++ come WebAssembly ed eseguirle nel browser.

Durante la compilazione, emscripten incorpora i dati di debug DWARF nel tuo programma binario. A livello generale, questi dati aiutano l'estensione a capire quali variabili WebAssembly corrispondono alle tue variabili C/C++ e altro ancora. In questo modo, DevTools può mostrarti le variabili C++ nonostante la V8 stia effettivamente eseguendo WebAssembly. Se sei curioso, consulta questo post del blog per un esempio dei dati di debug DWARF.

Cosa accade realmente quando riveli lastNumber? Non appena fai clic sull'icona della memoria, DevTools controlla quale variabile vuoi esaminare. Quindi, interroga l'estensione sul tipo di dati e sulla località di lastNumber. Non appena l'estensione risponde con queste informazioni, Memory Inspector è in grado di visualizzare la porzione di memoria pertinente e, conoscendone il tipo, può anche mostrarti le dimensioni dell'oggetto.

Se guardi lastNumber nell'esempio precedente, potresti notare che abbiamo ispezionato lastNumber: int *, ma il chip in Memory Inspector indica *lastNumber: int, che cosa indica? La funzionalità di controllo utilizza il deriferimento del puntatore in stile C++ per indicare il tipo di oggetto mostrato. Se esamini un puntatore, lo strumento di controllo ti mostrerà a cosa punta.

Evidenziazioni persistenti nei passaggi del debugger

Quando individui un oggetto in Memory Inspector e passi con il debugger, questo strumento persiste l'evidenziazione se ritiene che sia ancora applicabile. Inizialmente non avevamo questa funzionalità nella nostra roadmap, ma ci siamo presto resi conto che comprometteva l'esperienza di debug. Immagina di dover controllare di nuovo l'array dopo ogni passaggio, come nel video seguente.

Quando il debugger raggiunge un nuovo punto di interruzione, Memory Inspector esegue di nuovo una query nella versione 8 e sull'estensione per la variabile associata all'evidenziazione precedente. Quindi confronta le posizioni e i tipi degli oggetti. Se corrispondono, l'evidenziazione rimane. Nel video sopra è presente una scrittura del ciclo for nell'array x. Queste operazioni non cambiano il tipo o la posizione dell'array, quindi rimane evidenziato.

Potresti chiederti come vengono influenzati i cursori. Se hai un puntatore evidenziato e lo riassegni a un altro oggetto, la posizione precedente e quella nuova degli oggetti evidenziati saranno diverse e l'evidenziazione scompare. Poiché l'oggetto appena puntato può trovarsi ovunque nella memoria di WebAssembly e probabilmente avrà poca relazione con la posizione di memoria precedente, la rimozione dell'evidenziazione è più chiara rispetto al passaggio 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 ha descritto i miglioramenti che abbiamo apportato a Memory Inspector per il debug di C/C++. Ci auguriamo che le nuove funzionalità semplifichino il debug della memoria delle tue app C/C++. Se hai suggerimenti per migliorarla ulteriormente, faccelo sapere segnalando un bug.

Passaggi successivi

Per scoprire di più, vedi: