W Chrome 92 wprowadziliśmy inspektora pamięci, czyli narzędzie do sprawdzania liniowych buforów pamięci. W tym artykule omówimy ulepszenia, które wprowadziliśmy w narzędzie Inspekcja na potrzeby debugowania w językach C/C++, oraz problemy techniczne, z którymi się przy tym spotkaliśmy.
Jeśli dopiero zaczynasz debugować w C/C++ i używać Menedżera pamięci, przeczytaj te przydatne posty na blogu:
- Interesuje Cię szczegółowe debugowanie pamięci? Zobacz Wprowadzenie do narzędzia do inspekcji pamięci.
- Chcesz zapoznać się z pełnym zestawem narzędzi do debugowania C/C++? Zobacz artykuły Debugowanie WASM za pomocą nowoczesnych narzędzi i Szybsze debugowanie WebAssembly.
Wprowadzenie
Inspektor pamięci udostępnia bardziej zaawansowane opcje debugowania dla liniowych buforów pamięci. W przypadku C/C++ możesz sprawdzić obiekty pamięci C/C++ w pamięci WebAssembly.
Rozpoznawanie bajtów obiektu wśród pamięci WebAssembly było problemem. Musisz znać rozmiar obiektu i zliczać bajty od jego początku. Na poniższym zrzucie ekranu wybrany jest pierwszy bajt 10-elementowej tablicy int32
, ale nie jest od razu jasne, które inne bajty do niej należą. Czy nie byłoby miło, gdyby można było od razu rozpoznać wszystkie bajty należące do obiektu?
Podświetlanie obiektów w narzędziu do inspekcji pamięci
Począwszy od Chrome 107, inspektor pamięci wyróżnia wszystkie bajty obiektu pamięci C/C++. Dzięki temu można je odróżnić od pamięci sąsiadującej.
Obejrzyj poniższy film, aby zobaczyć, jak działa Memory Inspector. Gdy ujawnisz tablicę x
w narzędzie do inspekcji pamięci, w przeglądarce pamięci pojawi się wyróżniona pamięć wraz z nowym elementem graficznym tuż nad nią. Ten element przypomina nazwę i typ wyróżnionej pamięci. Kliknij chip, aby przejść do pamięci obiektu. Jeśli najedziesz kursorem na element, pojawi się ikona krzyżyka. Kliknij ją, aby usunąć wyróżnienie.
Gdy wybierzesz bajt poza sprawdzanym obiektem, podświetlenie zostanie rozmyte, aby nie rozpraszać. Aby ponownie ustawić ostrość, kliknij dowolny bajt obiektu lub ponownie kliknij chip.
Podświetlenie obiektów nie jest ograniczone do tablic. Możesz też sprawdzać struktury, obiekty i wskaźniki. Dzięki tym zmianom eksplorowanie pamięci aplikacji C/C++ jest teraz łatwiejsze niż kiedykolwiek wcześniej.
Chcesz spróbować? Musisz:
- mieć przeglądarkę Chrome w wersji 107 lub nowszej,
- Zainstaluj rozszerzenie DWARF dla C/C++.
- Włącz debugowanie DWARF w Narzędzia deweloperskie >
Ustawienia > Eksperymenty > Debugowanie WebAssembly: włącz obsługę DWARF.
- Otwórz tę stronę demonstracyjną.
- Postępuj zgodnie z instrukcjami wyświetlanymi na stronie.
Przykład debugowania
W tej sekcji przyjrzymy się błądowi demonstracyjnemu, aby pokazać, jak można używać Menedżera pamięci do debugowania kodu C/C++. W przykładowym kodzie poniżej programista tworzy tablicę liczb całkowitych i decyduje się użyć arytmetyki wskaźnika, aby wybrać ostatni element. Niestety programista popełnił błąd przy obliczaniu wskaźnika i teraz zamiast drukowania ostatniego elementu program drukuje 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 korzysta z kontrolera pamięci, aby debugować problem. Możesz śledzić to demonstracja. Najpierw sprawdzają tablicę w inspektorze pamięci i widzi, że tablica numbers
zawiera tylko liczby całkowite 1
, 2
, 3
i 4
, zgodnie z oczekiwaniami.
Następnie ujawniają zmienną lastNumber
w panelu Zakres i zauważają, że wskaźnik wskazuje na liczbę całkowitą spoza tablicy. Dzięki tej wiedzy programista zdaje sobie sprawę, że w wierszu 8 błędnie policzył przesunięcie wskaźnika. Powinien być to ptr + arraySize - 1
.
Chociaż jest to przykładowa aplikacja, pokazuje ona, jak podświetlenie obiektu skutecznie przekazuje rozmiar i położenie obiektów pamięci, co może pomóc w lepszym zrozumieniu tego, co dzieje się w pamięci aplikacji C/C++.
Jak Narzędzia deweloperskie określają, co wyróżnić
W tej sekcji przyjrzymy się ekosystemowi narzędzi do debugowania kodu C/C++. W szczególności dowiesz się, jak Debugowanie w Chrome umożliwia debugowanie w języku C/C++ za pomocą Narzędzi deweloperskich, V8, rozszerzenia C/C++ DWARF i Emscripten.
Aby w pełni wykorzystać możliwości debugowania kodu C/C++ w Narzędziach deweloperskich, musisz mieć:
- rozszerzenie DWARF w C/C++ zainstalowane w Chrome,
- pliki źródłowe C/C++, skompilowane do WebAssembly za pomocą najnowszego kompilatora Emscripten zgodnie z instrukcjami podanymi w tym poście na blogu;
Ale dlaczego? V8, czyli silnik JavaScriptu i WebAssembly w Chrome, nie wie, jak wykonać kod w języku C ani C++. Dzięki Emscriptenowi, czyli kompilatorowi C/C++, możesz kompilować aplikacje napisane w C lub C++ jako WebAssembly i uruchamiać je w przeglądarce.
Podczas kompilacji emscripten umieszcza dane debugowania DWARF w pliku binarnym. Ogólnie rzecz biorąc, te dane pomagają rozszerzeniu ustalić, które zmienne WebAssembly odpowiadają Twoim zmiennym C/C++ i nie tylko. Dzięki temu DevTools może wyświetlać zmienne C++, mimo że V8 faktycznie uruchamia WebAssembly. Jeśli chcesz się dowiedzieć więcej, przeczytaj ten post na blogu, w którym znajdziesz przykład danych debugowania DWARF.
Co się dzieje, gdy odsłonisz lastNumber
? Gdy klikniesz ikonę pamięci, Narzędzia dla programistów sprawdzą, którą zmienną chcesz sprawdzić. Następnie wysyła zapytanie do rozszerzenia o typ danych i lokalizację lastNumber
. Gdy rozszerzenie odpowie z tymi informacjami, Memory Inspector może wyświetlić odpowiedni fragment pamięci. Wiedząc, jaki jest typ obiektu, może też wyświetlić jego rozmiar.
Jeśli spojrzysz na lastNumber
w poprzednim przykładzie, możesz zauważyć, że skontrolowaliśmy lastNumber: int *
, ale na chipie w Memory Inspector widać *lastNumber: int
. Co się stało? Inspektor używa odwołania do wskaźnika w stylu C++, aby wskazać typ wyświetlanego obiektu. Jeśli skontrolujesz wskaźnik, zobaczysz, na co wskazuje.
Utrwalanie wyróżnień w krokach w debugerze
Gdy ujawnisz obiekt w Narzędzie do inspekcji pamięci i przejdziesz do debugera, Narzędzie do inspekcji zachowa podświetlenie, jeśli uzna, że nadal jest ono przydatne. Początkowo nie było to uwzględnione w planach, ale szybko zdaliśmy sobie sprawę, że utrudnia to debugowanie. Wyobraź sobie, że po każdym kroku musisz ponownie sprawdzić tablicę, tak jak w tym filmie poniżej.
Gdy debuger dotrze do nowego punktu przerwania, Memory Inspector ponownie wysyła zapytanie do V8 i do rozszerzenia o zmienną powiązaną z poprzednim wyróżnieniem. Następnie porównuje lokalizacje i typy obiektów. Jeśli pasują, wyróżnienie pozostanie. W tym filmie występuje pętla for, która zapisuje dane do tablicy x
. Te operacje nie zmieniają typu ani pozycji tablicy, więc pozostaje ona podświetlona.
Zastanawiasz się pewnie, jak to wpływa na wskaźniki. Jeśli masz podświetlony wskaźnik i przypiszesz go do innego obiektu, stare i nowe położenie podświetlonych obiektów będą się różnić, a podświetlenie zniknie. Ponieważ nowo wskazany obiekt może znajdować się w dowolnym miejscu pamięci WebAssembly i prawdopodobnie nie będzie miał wiele wspólnego z poprzednim miejscem w pamięci, usunięcie podświetlenia jest prostsze niż przejście do nowego miejsca w pamięci. Możesz ponownie wyróżnić wskaźnik, klikając ikonę pamięci w panelu Zakres.
Podsumowanie
W tym artykule opisaliśmy ulepszenia narzędzia Memory Inspector na potrzeby debugowania kodu C/C++. Mamy nadzieję, że nowe funkcje ułatwią debugowanie pamięci w Twoich aplikacjach C/C++. Jeśli masz sugestie dotyczące dalszego ulepszania tej funkcji, zgłoś błąd.
Co dalej?
Więcej informacji znajdziesz w tych artykułach: