GDB ma nową wersję, która obsługuje odwrotne debugowanie (patrz http://www.gnu.org/software/gdb/news/reversible.html ). Zacząłem się zastanawiać, jak to działa.
Wydaje mi się, że aby uruchomić debugowanie wsteczne, musisz przechowywać cały stan maszyny, w tym pamięć dla każdego kroku. Spowodowałoby to niewiarygodnie wolne działanie, nie wspominając o zużyciu dużej ilości pamięci. Jak rozwiązuje się te problemy?
reverse-debugging
Nathan Fellman
źródło
źródło
Odpowiedzi:
Jestem opiekunem gdb i jednym z autorów nowego odwrotnego debugowania. Chętnie porozmawiam o tym, jak to działa. Jak spekulowało kilka osób, musisz zapisać wystarczający stan komputera, aby móc go później przywrócić. Istnieje wiele schematów, z których jednym jest po prostu zapisywanie rejestrów lub lokalizacji pamięci, które są modyfikowane przez każdą instrukcję maszynową. Następnie, aby „cofnąć” tę instrukcję, po prostu przywróć dane w tych rejestrach lub komórkach pamięci.
Tak, jest drogi, ale nowoczesne procesory są tak szybkie, że kiedy i tak jesteś interaktywny (wykonujesz kroki lub punkty przerwania), tak naprawdę nie zauważysz tego tak bardzo.
źródło
next
istep
wpisanie poleceń, czy też na cofnięcie dowolnej liczby instrukcji? Na przykład, jeśli ustawię punkt przerwania w instrukcji i pozwolę mu działać do tego czasu, czy mogę wrócić do poprzedniej instrukcji, mimo że ją przeskoczyłem?Pamiętaj, że nie możesz zapomnieć o użyciu symulatorów, maszyn wirtualnych i rejestratorów sprzętowych w celu wykonania odwrotnego wykonania.
Innym rozwiązaniem, które można wdrożyć, jest śledzenie wykonywania na sprzęcie fizycznym, tak jak robią to GreenHills i Lauterbach w ich debugerach sprzętowych. Na podstawie tego stałego śladu działania każdej instrukcji można przejść do dowolnego punktu w śladzie, usuwając po kolei efekty każdej instrukcji. Zauważ, że zakłada to, że możesz prześledzić wszystkie rzeczy, które wpływają na stan widoczny w debugerze.
Innym sposobem jest użycie metody punkt kontrolny + ponowne wykonanie, która jest używana przez VmWare Workstation 6.5 i Virtutech Simics 3.0 (i nowsze) i która wydaje się pochodzić z Visual Studio 2010. Tutaj używasz maszyny wirtualnej lub symulatora uzyskać poziom pośredni w wykonywaniu systemu. Regularnie zrzucasz cały stan na dysk lub do pamięci, a następnie polegasz na tym, że symulator jest w stanie deterministycznie ponownie wykonać dokładnie tę samą ścieżkę programu.
Upraszczając, działa to w ten sposób: powiedz, że jesteś w czasie T podczas wykonywania systemu. Aby przejść do czasu T-1, podnieś punkt kontrolny z punktu t <T, a następnie wykonaj (Tt-1) cykle, aby zakończyć jeden cykl przed miejscem, w którym byłeś. Może to działać bardzo dobrze i mieć zastosowanie nawet do obciążeń, które wykonują operacje we / wy dysku, składają się z kodu na poziomie jądra i wykonują pracę sterownika urządzenia. Kluczem jest posiadanie symulatora, który zawiera cały system docelowy ze wszystkimi jego procesorami, urządzeniami, pamięcią i IO. Aby uzyskać więcej informacji, zobacz listę dyskusyjną gdb i dyskusję po niej na liście dyskusyjnej gdb. Sam używam tego podejścia dość regularnie do debugowania skomplikowanego kodu, szczególnie w sterownikach urządzeń i wczesnych uruchomieniach systemu operacyjnego.
Innym źródłem informacji jest biała księga firmy Virtutech na temat punktów kontrolnych (którą napisałem w pełnej jawności).
źródło
Podczas sesji EclipseCon zapytaliśmy również, jak oni to robią z Chronon Debugger for Java. Ten nie pozwala faktycznie cofnąć się, ale może odtworzyć nagrane wykonanie programu w taki sposób, że to on czuje się jak odwrotnej debugowania. (Główna różnica polega na tym, że nie można zmienić uruchomionego programu w debugerze Chronon, podczas gdy można to zrobić w większości innych debuggerów Java).
Jeśli dobrze to zrozumiałem, manipuluje kodem bajtowym uruchomionego programu tak, że każda zmiana stanu wewnętrznego programu jest rejestrowana. Stany zewnętrzne nie muszą być dodatkowo rejestrowane. Jeśli wpływają w jakiś sposób na twój program, to musisz mieć wewnętrzną zmienną pasującą do tego stanu zewnętrznego (a zatem ta wewnętrzna zmienna jest wystarczająca).
W czasie odtwarzania mogą następnie w zasadzie odtworzyć każdy stan uruchomionego programu na podstawie zarejestrowanych zmian stanu.
Co ciekawe, zmiany stanu są znacznie mniejsze, niż można by się spodziewać na pierwszy rzut oka. Więc jeśli masz warunkową instrukcję „if”, możesz pomyśleć, że potrzebujesz co najmniej jednego bitu, aby zarejestrować, czy program przyjął instrukcję then, czy else. W wielu przypadkach można nawet tego uniknąć, na przykład w przypadku, gdy te różne gałęzie zawierają wartość zwracaną. Wtedy wystarczy tylko zanotować wartość zwracaną (która i tak byłaby potrzebna) i przeliczyć decyzję o wykonywanej gałęzi z samej wartości zwracanej.
źródło
Chociaż to pytanie jest stare, większość odpowiedzi jest również i tak jak odwrotne debugowaniepozostaje interesującym tematem, zamieszczam odpowiedź z 2015 roku. Rozdziały 1 i 2 mojej pracy magisterskiej, Łączenie debugowania wstecznego i programowania na żywo z myśleniem wizualnym w programowaniu komputerowym , obejmują niektóre historyczne podejścia do odwrotnego debugowania (szczególnie skoncentrowane na podejściu do tworzenia migawek (lub punktów kontrolnych) i odtwarzania) oraz wyjaśnia różnicę między tym a wszechwiedzącym debugowaniem:
źródło
mozilla
rr
jest solidniejszą alternatywą dla odwrotnego debugowania GDBhttps://github.com/mozilla/rr
Wbudowany zapis i odtwarzanie GDB ma poważne ograniczenia, np. Brak obsługi instrukcji AVX: odwrotne debugowanie gdb kończy się niepowodzeniem z komunikatem „Rekord procesu nie obsługuje instrukcji 0xf0d pod adresem”
Zalety rr:
rr osiąga to, najpierw uruchamiając program w sposób, który rejestruje to, co się wydarzyło przy każdym niedeterministycznym zdarzeniu, takim jak zmiana wątku.
Następnie podczas drugiego przebiegu powtórki używa tego pliku śledzenia, który jest zaskakująco mały, do rekonstrukcji dokładnie tego, co wydarzyło się w pierwotnym niedeterministycznym przebiegu, ale w sposób deterministyczny, do przodu lub do tyłu.
rr został pierwotnie opracowany przez Mozillę, aby pomóc im odtworzyć błędy synchronizacji, które pojawiły się podczas ich nocnych testów następnego dnia. Ale aspekt odwrotnego debugowania jest również fundamentalny w przypadku błędu, który pojawia się tylko godzinami w trakcie wykonywania, ponieważ często chcesz cofnąć się, aby zbadać, jaki poprzedni stan doprowadził do późniejszej awarii.
Poniższy przykład prezentuje niektóre z jego cech, szczególnie te
reverse-next
,reverse-step
ireverse-continue
poleceń.Zainstaluj na Ubuntu 18.04:
Program testowy:
skompiluj i uruchom:
Teraz jesteś w sesji GDB i możesz poprawnie odwrócić debugowanie:
Podczas debugowania złożonego oprogramowania prawdopodobnie dojdziesz do punktu awarii, a następnie wpadniesz w głęboką ramkę. W takim przypadku nie zapominaj, że
reverse-next
w przypadku wyższych klatek musisz najpierw:do tej klatki, zwykłe robienie tego
up
nie wystarczy.Moim zdaniem najpoważniejsze ograniczenia rr to:
UndoDB to komercyjna alternatywa dla rr: https://undo.io Oba są oparte na śledzeniu / odtwarzaniu, ale nie jestem pewien, jak się porównują pod względem funkcji i wydajności.
źródło
Nathan Fellman napisał:
Możesz cofnąć dowolną liczbę instrukcji. Nie jesteś ograniczony na przykład do zatrzymywania się tylko w punktach, w których zatrzymałeś się, gdy jechałeś do przodu. Możesz ustawić nowy punkt przerwania i cofnąć się do niego.
Tak. O ile włączyłeś tryb nagrywania przed biegiem do punktu przerwania.
źródło
Oto jak działa inny odwrotny debugger o nazwie ODB. Wyciąg:
Domyślam się, że gdb działa w ten sam sposób.
źródło
Odwrotne debugowanie oznacza, że możesz uruchomić program wstecz, co jest bardzo przydatne do wyśledzenia przyczyny problemu.
Nie musisz przechowywać pełnego stanu maszyny dla każdego kroku, tylko zmiany. Prawdopodobnie nadal jest dość drogi.
źródło