Rozszerzanie narzędzia Memory Investor na potrzeby debugowania C/C++

W Chrome 92 wprowadziliśmy Inspektor pamięci – narzędzie do sprawdzania liniowych buforów pamięci. W tym artykule omówimy ulepszenia w Inspektorze do debugowania w języku C/C++ oraz napotkane problemy techniczne.

Oto kilka przydatnych postów na blogu, jeśli dopiero zaczynasz korzystać z debugowania w C/C++ i narzędzia Memory Inspector:

Wprowadzenie

Inspektor pamięci udostępnia zaawansowane opcje debugowania liniowych buforów pamięci. W języku C/C++ możesz sprawdzać obiekty pamięci w języku C/C++ w pamięci WebAssembly.

Rozpoznawanie bajtów obiektu w otaczającej pamięci WebAssembly było kłopotliwe. Od początku musisz znać rozmiar obiektu i liczbę bajtów. Na zrzucie ekranu poniżej zaznaczono pierwszy bajt 10-elementowej tablicy int32, ale nie wiadomo od razu, które pozostałe bajty należą do tablicy. Czy nie byłoby miło, gdyby można było od razu rozpoznać wszystkie bajty należące do obiektu?

Zrzut ekranu oryginalnego inspektora pamięci z 1 zaznaczonym bajtem

Wyróżnianie obiektów w inspektorze pamięci

Od Chrome 107 Inspektor pamięci wyróżnia wszystkie bajty obiektu pamięci w języku C/C++. Pomoże Ci to odróżnić je od otaczającej pamięci.

Zrzut ekranu przedstawiający zaktualizowany inspektor pamięci z jasno podświetloną tablicą

Obejrzyj film poniżej, by zobaczyć, jak działa Inspektor pamięci. Gdy odkryjesz tablicę x w narzędziu Memory Inspector, w przeglądarce pamięci pojawi się podświetlona pamięć, a tuż nad nią nowy element. Ten element przypomina nazwę i typ zaznaczonego wspomnienia. Kliknij element, aby przejść do pamięci obiektu. Gdy najedziesz kursorem na element, pojawi się ikona krzyżyka. Kliknij ją, aby usunąć wyróżnienie.

Gdy zaznaczysz bajt poza sprawdzanym obiektem, wyróżnienie zostanie pomniejszone, aby nie rozpraszać uwagi. Aby ponownie ustawić ostrość, kliknij ponownie dowolny bajt obiektu lub element.

Obsługa wyróżniania obiektów nie jest ograniczona do tablic. Możesz też przeglądać obiekty struct, obiekty i wskaźniki. Dzięki tym zmianom korzystanie z pamięci aplikacji w języku C/C++ jest łatwiejsze niż kiedykolwiek wcześniej.

Chcesz spróbować? Wykonaj te czynności:

  • mieć Chrome w wersji 107 lub nowszej.
  • Zainstaluj rozszerzenie DWARF C/C++.
  • Włącz debugowanie DWARF w DevTools. Ustawienia. Ustawienia > Eksperymenty > Debugowanie WebAssemble: włącz obsługę plików DWARF.
  • Otwórz tę stronę demonstracyjną.
  • Postępuj zgodnie z instrukcjami na stronie.

Przykład debugowania

W tej sekcji przyjrzymy się bliżej zabawce, by pokazać, jak można użyć narzędzia Memory Inspector do debugowania w języku C/C++. W poniższym przykładowym kodzie programista tworzy tablicę całkowitą i postanawia użyć arytmetyki wskaźnika, aby wybrać ostatni element. Niestety programista popełnił błąd w obliczaniu wskaźnika i teraz zamiast drukowania ostatniego elementu, program wydrukuje bezsensowne wartości.

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

Programista używa inspektora pamięci, aby debugować problem. Możesz śledzić tę prezentację. Najpierw sprawdzają tablicę w inspektorze pamięci i zauważają, że tablica numbers zawiera tylko liczby całkowite 1, 2, 3 i 4 zgodnie z oczekiwaniami.

Zrzut ekranu z otwartym inspektorem pamięci ze sprawdzoną tablicą int32. Wszystkie elementy tablicy są zaznaczone.

Następnie wyświetla zmienną lastNumber w panelu Zakres i zauważa, że wskaźnik wskazuje liczbę całkowitą poza tablicą. Dzięki tej wiedzy deweloper uświadamia sobie, że błędnie policzył przesunięcie wskaźnika w linii 8. Powinna być ptr + arraySize - 1.

Zrzut ekranu przedstawiający otwarty inspektor pamięci z zaznaczoną pamięcią wskazaną przez wskaźnik o nazwie „lastNumber”. Podświetlona pamięć znajduje się zaraz po ostatnim bajcie wcześniej podświetlonej tablicy.

Chociaż jest to przykład zabawki, ilustruje, jak wyróżnianie obiektów skutecznie przekazuje rozmiar i położenie obiektów pamięci, co może pomóc Ci lepiej zrozumieć, co dzieje się w pamięci aplikacji w języku C/C++.

Jak Narzędzia deweloperskie określają, co zwrócić

W tej sekcji przyjrzymy się ekosystemowi narzędzi, które umożliwiają debugowanie w języku C/C++. Dowiesz się z niego, jak za pomocą Narzędzi deweloperskich, wersji 8, rozszerzeń DWARF C/C++ i Emscripten możliwe jest debugowanie C/C++ w Chrome.

Aby w pełni wykorzystać możliwości debugowania w języku C/C++ w Narzędziach deweloperskich, potrzebujesz 2 elementów:

  • Rozszerzenie C/C++ DWARF zainstalowane w Chrome
  • Pliki źródłowe w języku C/C++ skompilowane do formatu WebAssembly za pomocą najnowszego kompilatora Emscripten zgodnie z instrukcjami podanymi w tym poście na blogu.

Ale dlaczego? V8 – mechanizm JavaScript i WebAssembly w Chrome , nie wie, jak wykonać język C lub C++. Dzięki kompilatorowi Emscripten z C/C++ do WebAssembly możesz kompilować aplikacje stworzone w C/C++ jako WebAssembly i uruchamiać je w przeglądarce.

Podczas kompilacji aplikacja emscripten umieści w pliku binarnym dane debugowania DWARF. Ogólnie dane te pomagają rozszerzeniu określić między innymi, które zmienne WebAssembly odpowiadają zmiennym C/C++. Dzięki temu Narzędzia deweloperskie mogą wyświetlać zmienne w C++, mimo że V8 faktycznie obsługuje WebAssembly. Przykładowe dane debugowania w formacie DWARF znajdziesz w tym poście na blogu.

Co więc się stanie, gdy odkryjesz lastNumber? Gdy tylko klikniesz ikonę pamięci, Narzędzia deweloperskie sprawdzą, którą zmienną chcesz zbadać. Następnie wysyła zapytanie do rozszerzenia o typ danych i lokalizację witryny lastNumber. Gdy tylko rozszerzenie poda te informacje, inspektor pamięci może wyświetlić odpowiedni fragment pamięci i znając jego typ, może też wyświetlić rozmiar obiektu.

Jeśli spojrzysz na funkcję lastNumber z wcześniejszego przykładu, możesz zauważyć, że sprawdziliśmy element lastNumber: int *, ale element inspektora pamięci ma komunikat *lastNumber: int. Co daje? Inspektor używa dereferencji wskaźnika w stylu C++, aby wskazać typ wyświetlanego obiektu. Jeśli sprawdzisz wskaźnik, inspektor pokaże, na co on wskazuje.

Zachowywanie wyróżnionych informacji dotyczących kroków debugera

Gdy odkryjesz obiekt w Inspektorze pamięci i wykonasz czynność z debugerem, zachowa on wyróżnienie, jeśli uzna, że nadal ma znaczenie. Początkowo nie uwzględnialiśmy tej funkcji w planach, ale szybko zdaliśmy sobie sprawę, że niekorzystnie wpływa ona na korzystanie z debugowania. Wyobraź sobie, że po każdym kroku trzeba ponownie sprawdzać macierz, tak jak na poniższym filmie.

Gdy debuger znajdzie nowy punkt przerwania, inspektor pamięci ponownie wysyła zapytanie do V8 i rozszerzenia do zmiennej powiązanej z poprzednim wyróżnieniem. a następnie porównuje lokalizacje i typy obiektów. Jeśli będą zgodne, wyróżnienie się nie zmieni. W filmie powyżej widać pętlę zapisu w tablicy x. Te operacje nie zmieniają typu ani pozycji tablicy, więc pozostaje ona podświetlona.

Możesz się zastanawiać, jak wpływa to na wskaźniki. Jeśli masz wyróżniony wskaźnik i przypiszesz go do innego obiektu, stare i nowe pozycje wyróżnionych obiektów będą się różnić, a podświetlenie zniknie. Ponieważ nowo wskazany obiekt może znajdować się w dowolnym miejscu w pamięci WebAssembly i prawdopodobnie będzie mieć niewielki związek z poprzednią lokalizacją pamięci, usunięcie zaznaczenia jest wygodniejsze niż przejście do nowej lokalizacji w pamięci. Możesz ponownie wyróżnić wskaźnik, klikając jego ikonę pamięci w panelu Zakres.

Podsumowanie

W tym artykule opisano ulepszenia wprowadzone w narzędziu Memory Inspector na potrzeby debugowania w języku C/C++. Mamy nadzieję, że nowe funkcje uprością debugowanie pamięci aplikacji w języku C/C++. Jeśli masz jakieś sugestie, jak ulepszyć tę funkcję, daj nam znać, zgłaszając błąd.

Co dalej?

Więcej informacji: