Memory Inspector für C/C++-Debugging erweitern

In Chrome 92 haben wir den Memory Inspector eingeführt, ein Tool zur Überprüfung linearer Speicherpuffer. In diesem Artikel erfahren Sie, wie wir den Inspector für das C/C++-Debugging verbessert haben und welche technischen Herausforderungen dabei auftreten.

Im Folgenden finden Sie einige relevante Blogposts für neue Nutzer des C/C++-Debugging und des Memory Inspector:

Einführung

Der Memory Inspector bietet leistungsfähigere Debugging-Optionen für lineare Arbeitsspeicherpuffer. Bei C/C++ können Sie C/C++-Speicherobjekte im WebAssembly-Speicher prüfen.

Die Erkennung der Bytes Ihres Objekts im umgebenden WebAssembly-Speicher war ein Problem. Sie müssen die Größe des Objekts kennen und die Anzahl der Bytes ab dem Start des Objekts berücksichtigen. Im folgenden Screenshot ist das erste Byte eines int32-Arrays mit 10 Elementen ausgewählt. Es ist jedoch nicht sofort klar, welche anderen Byte zum Array gehören. Wäre es nicht schön, wenn Sie sofort alle Bytes erkennen könnten, die zum Objekt gehören?

Screenshot des ursprünglichen Memory Inspector mit einem einzelnen hervorgehobenen Byte

Objekthervorhebung im Memory Inspector

Ab Chrome 107 werden im Memory Inspector alle Byte eines C/C++-Speicherobjekts hervorgehoben. So können Sie sie von der umgebenden Erinnerung unterscheiden.

Screenshot des aktualisierten Memory Inspector mit einem leuchtend hervorgehobenen Array

Im Video unten sehen Sie den Memory Inspector in Aktion. Wenn Sie das Array x im Arbeitsspeicher-Prüftool anzeigen, wird in der Arbeitsspeicheranzeige der markierte Arbeitsspeicher zusammen mit einem neuen Chip direkt darüber angezeigt. Dieser Chip erinnert Sie an den Namen und den Typ der markierten Erinnerung. Klicken Sie auf den Chip, um zum Arbeitsspeicher des Objekts zu gelangen. Wenn Sie die Maus über den Chip bewegen, erscheint ein Kreuz. Klicken Sie darauf, um die Markierung zu entfernen.

Wenn Sie ein Byte außerhalb des zu prüfenden Objekts auswählen, wird die Markierung unscharf gestellt, um Ablenkungen zu vermeiden. Wenn Sie den Fokus wieder auf das Objekt legen möchten, klicken Sie noch einmal auf einen der Bytes des Objekts oder auf den Chip.

Die Unterstützung für die Objekthervorhebung ist nicht auf Arrays beschränkt. Sie können auch Strukturen, Objekte und Zeiger überprüfen. Dank dieser Änderungen können Sie den Arbeitsspeicher Ihrer C/C++ Apps jetzt noch einfacher nutzen.

Möchten Sie es ausprobieren? Erforderliche Schritte:

  • Sie verwenden Chrome 107 oder höher.
  • Installieren Sie die DWARF-Erweiterung für C/C++.
  • DWARF-Debugging in den DevTools aktivieren > Einstellungen. Einstellungen > Tests > WebAssemble-Debugging: DWARF-Unterstützung aktivieren
  • Öffnen Sie diese Demoseite.
  • Folgen Sie der Anleitung auf der Seite.

Debugging-Beispiel

In diesem Abschnitt wird anhand eines Spielzeugfehlers veranschaulicht, wie Sie den Memory Inspector für das C/C++-Debugging verwenden können. Im folgenden Codebeispiel erstellt ein Programmierer ein Ganzzahl-Array und entscheidet sich, das letzte Element mithilfe der Pointerarithmetik auszuwählen. Leider hat der Programmierer einen Fehler bei der Zeigerberechnung gemacht und jetzt gibt das Programm nicht das letzte Element aus, sondern druckt unsinnige Werte aus.

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

Der Programmierer wendet sich an den Memory Inspector, um das Problem zu beheben. In dieser Demo zeigen wir dir, wie es geht. Zuerst überprüft er das Array im Memory Inspector und stellt fest, dass das numbers-Array wie erwartet nur die Ganzzahlen 1, 2, 3 und 4 enthält.

Screenshot des geöffneten Memory Inspector mit einem überprüften int32-Array. Alle Array-Elemente sind markiert.

Als Nächstes wird die Variable lastNumber im Bereich Scope (Umfang) angezeigt. Der Zeiger zeigt auf eine Ganzzahl außerhalb des Arrays. Mit diesem Wissen erkennt der Programmierer, dass er den Zeigeroffset in Zeile 8 falsch gezählt hat. Es sollte ptr + arraySize - 1 sein.

Screenshot des geöffneten Arbeitsspeicher-Inspektors mit hervorgehobenem Arbeitsspeicher, auf den ein Zeiger mit dem Namen „lastNumber“ verweist. Der hervorgehobene Arbeitsspeicher liegt direkt nach dem letzten Byte des zuvor hervorgehobenen Arrays.

Dies ist zwar ein Spielzeugbeispiel, aber es zeigt, wie die Objekthervorhebung die Größe und Position von Speicherobjekten effektiv vermittelt, was Ihnen helfen kann, besser zu verstehen, was im Speicher Ihrer C/C++ App vor sich geht.

So ermittelt die Entwicklertools, was hervorgehoben werden sollte

In diesem Abschnitt sehen wir uns die Tools an, mit denen das C/C++-Debugging möglich ist. Sie erfahren, wie die Entwicklertools, V8, die C/C++ DWARF-Erweiterung und Emscripten das Debugging in Chrome in Chrome ermöglichen.

Um die volle Leistung des C/C++-Debugging in den Entwicklertools nutzen zu können, benötigen Sie zwei Dinge:

  • In Chrome installierte DWARF-Erweiterung für C/C++
  • C/C++-Quelldateien, die mit dem neuesten Emscripten-Compiler gemäß der Anleitung in diesem Blogpost in WebAssembly kompiliert wurden

Aber warum? V8, die JavaScript- und WebAssembly-Engine von Chrome, kann C oder C++ nicht ausführen. Mit Emscripten, einem C/C++-zu-WebAssembly-Compiler, können Sie in C oder C++ geschriebene Apps als WebAssembly kompilieren und im Browser ausführen.

Während der Kompilierung bettet emscripten DWARF-Debug-Daten in Ihr Binärprogramm ein. Diese Daten helfen der Erweiterung unter anderem, herauszufinden, welche WebAssembly-Variablen Ihren C/C++-Variablen entsprechen. Auf diese Weise können Ihnen DevTools Ihre C++-Variablen anzeigen, obwohl V8 tatsächlich WebAssembly ausführt. In diesem Blogpost finden Sie ein Beispiel für DWARF-Debugdaten.

Was passiert also, wenn du die lastNumber aufdeckst? Sobald Sie auf das Speichersymbol klicken, prüft die Entwicklertools, welche Variable Sie untersuchen möchten. Anschließend wird die Erweiterung über den Datentyp und den Speicherort von lastNumber abgefragt. Sobald die Erweiterung mit diesen Informationen antwortet, kann der Speicher-Inspector den entsprechenden Speicherbereich anzeigen und anhand des Typs auch die Größe des Objekts.

Wenn Sie sich lastNumber im vorherigen Beispiel ansehen, stellen Sie möglicherweise fest, dass wir lastNumber: int * geprüft haben, aber der Chip im Memory Inspector *lastNumber: int lautet. Woran liegt das? Der Inspector verwendet die C++-Methode zur Dereferenzierung von Pointern, um den Typ des angezeigten Objekts anzugeben. Wenn Sie einen Verweis prüfen, sehen Sie im Inspektor, worauf er verweist.

Highlights für Debuggerschritte beibehalten

Wenn Sie im Memory Inspector ein Objekt aufdecken und den Debugger verwenden, wird die Markierung beibehalten, sofern sie der Meinung ist, dass sie noch anwendbar ist. Anfangs war diese Funktion noch nicht in unserer Roadmap enthalten, aber wir haben schnell festgestellt, dass dies Ihre Debugging-Erfahrung kompromittiert. Stellen Sie sich vor, Sie müssen das Array nach jedem Schritt wie im folgenden Video noch einmal überprüfen.

Wenn der Debugger einen neuen Haltepunkt erreicht, fragt der Speicher-Inspektor noch einmal V8 und die Erweiterung nach der Variablen ab, die mit dem vorherigen Highlight verknüpft ist. Anschließend werden die Positionen und Typen der Objekte verglichen. Wenn sie übereinstimmen, bleibt die Markierung erhalten. Im obigen Video wird mit einer For-Schleife in das Array x geschrieben. Diese Vorgänge ändern weder den Typ noch die Position des Arrays, sodass es weiterhin hervorgehoben bleibt.

Sie fragen sich vielleicht, wie sich das auf Zeiger auswirkt. Wenn Sie einen markierten Cursor haben und ihn einem anderen Objekt zuweisen, unterscheiden sich die alte und die neue Position der markierten Objekte und die Markierung verschwindet. Da das neu aufgelöste Objekt überall im WebAssembly-Speicher abgelegt werden kann und wahrscheinlich wenig Bezug zum vorherigen Speicherort hat, ist es übersichtlicher, die Markierung zu entfernen, als zu einem neuen Speicherort zu springen. Sie können den Zeiger noch einmal markieren, indem Sie im Bereich Scope (Bereich) auf das Speichersymbol klicken.

Fazit

In diesem Artikel werden unsere Verbesserungen am Memory Inspector für die Fehlerbehebung in C/C++ beschrieben. Wir hoffen, dass die neuen Funktionen das Debuggen des Arbeitsspeichers Ihrer C/C++-Anwendungen vereinfachen. Wenn du Verbesserungsvorschläge hast, kannst du den Programmfehler melden.

Weiteres Vorgehen

Weitere Informationen erhalten Sie unter: