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 C/C++-Debugging verbessert haben und welche technischen Herausforderungen dabei auftreten.

Hier sind einige relevante Blogbeiträge, wenn Sie neu im C/C++-Debugging und im Memory Inspector sind:

Einführung

Der Memory Inspector bietet Ihnen leistungsstärkere Optionen zur Fehlerbehebung für lineare Arbeitsspeicher-Puffer. Bei C/C++ können Sie C/C++-Speicherobjekte im WebAssembly-Speicher prüfen.

Es war schwierig, die Bytes des Objekts im umgebenden WebAssembly-Speicher zu erkennen. Sie müssen die Größe des Objekts kennen und die Anzahl der Bytes vom Anfang des Objekts zählen. Im folgenden Screenshot ist das erste Byte eines int32-Arrays mit 10 Elementen ausgewählt. Es ist jedoch nicht sofort ersichtlich, welche anderen Bytes 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 Speicherprüfprogramms mit einem einzelnen markierten Byte

Hervorhebung von Objekten im Arbeitsspeicher-Prüftool

Ab Chrome 107 werden im Speicher-Inspector alle Bytes eines C/C++-Speicherobjekts hervorgehoben. Dies hilft Ihnen, sie vom umgebenden Gedächtnis zu unterscheiden.

Screenshot des aktualisierten Arbeitsspeicher-Inspektors 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 des markierten Arbeitsspeichers. Klicken Sie auf den Chip, um zum Arbeitsspeicher des Objekts zu gelangen. Wenn Sie den Mauszeiger auf den Chip bewegen, wird ein Kreuzsymbol angezeigt. Klicken Sie darauf, um die Markierung aufzuheben.

Wenn Sie ein Byte außerhalb des untersuchten Objekts auswählen, wird die Hervorhebung deaktiviert, damit Sie nicht abgelenkt werden. 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 der 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? Folgende Voraussetzungen müssen erfüllt sein:

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

Debugging-Beispiel

In diesem Abschnitt sehen wir uns ein Beispiel für einen einfachen Fehler an, um zu veranschaulichen, 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. Weitere Informationen findest du in dieser Demo. Er prüft zuerst das Array im Speicher-Inspector und stellt fest, dass das Array numbers wie erwartet nur die Ganzzahlen 1, 2, 3 und 4 enthält.

Screenshot des geöffneten Arbeitsspeicher-Inspectors mit einem geprüften int32-Array Alle Array-Elemente sind markiert.

Als Nächstes blendet er die Variable lastNumber im Bereich Scope ein und stellt fest, dass der Zeiger auf eine Ganzzahl außerhalb des Arrays zeigt. 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 Memory Inspector mit dem hervorgehobenen Arbeitsspeicher, auf den ein Zeiger namens „lastNumber“ zeigt. Der hervorgehobene Arbeitsspeicher liegt direkt nach dem letzten Byte des zuvor markierten Arrays.

Obwohl dies ein einfaches Beispiel ist, veranschaulicht es, wie die Objektmarkierung die Größe und Position von Speicherobjekten effektiv vermittelt. So können Sie besser nachvollziehen, was im Arbeitsspeicher Ihrer C/C++-Anwendung passiert.

So ermittelt DevTools, was hervorgehoben werden soll

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

Damit Sie das C/C++-Debugging in den Entwicklertools voll ausschöpfen können, sind zwei Dinge erforderlich:

  • Die in Chrome installierte C/C++-DWARF-Erweiterung
  • 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 Apps, die in C oder C++ erstellt wurden, als WebAssembly kompilieren und im Browser ausführen.

Während der Kompilierung bettet emscripten DWARF-Debugdaten in Ihre Binärdatei ein. Diese Daten helfen der Erweiterung unter anderem, herauszufinden, welche WebAssembly-Variablen Ihren C/C++-Variablen entsprechen. So können Ihnen die DevTools Ihre C++-Variablen anzeigen, obwohl in V8 tatsächlich WebAssembly ausgeführt wird. 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, der Chip im Speicher-Inspector aber *lastNumber: int anzeigt. Was ist da los? 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 in Debugger-Schritten beibehalten

Wenn Sie ein Objekt im Arbeitsspeicher-Prüftool anzeigen und mit dem Debugger einen Schritt ausführen, behält das Prüftool die Markierung bei, wenn es der Meinung ist, dass sie noch relevant ist. Diese Funktion war ursprünglich nicht in unserer Roadmap enthalten, aber wir haben schnell erkannt, dass sie die Fehlerbehebung erschwert. Stellen Sie sich vor, Sie müssten das Array nach jedem Schritt noch einmal prüfen, wie im Video unten.

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 schreibt eine For-Schleife in das Array x. Diese Vorgänge ändern nicht den Typ oder die Position des Arrays, sodass es 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 sein 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 Cursor wieder hervorheben, indem Sie im Bereich Scope auf das zugehörige Speichersymbol klicken.

Fazit

In diesem Artikel wurden die Verbesserungen am Memory Inspector für das C/C++-Debugging beschrieben. Wir hoffen, dass die neuen Funktionen das Debuggen des Arbeitsspeichers Ihrer C/C++-Anwendungen vereinfachen. Wenn du Verbesserungsvorschläge hast, reiche bitte einen Fehlerbericht ein.

Weiteres Vorgehen

Weitere Informationen erhalten Sie unter: