Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: Piotr Szawdyński
Inne materiały

Podstawowe polecenia do debugowania aplikacji

[lekcja] Rozdział 4. Niniejszy rozdział opisuje podstawowe polecenia, służące do debugowania aplikacji.

Wprowadzenie do debugowania aplikacji za pomocą GDB

Rozpoczynając przygodę debugowania własnej aplikacji warto mieć świadomość jakie istnieją polecenia, służące do śledzenia przebiegu działania aplikacji. Przedstawianie wszystkich możliwości GDB w ramach jednego rozdziału oczywiście nie ma sensu, dlatego też niniejszy rozdział będzie zawierał tylko te polecenia, które uznałem za najważniejsze dla początkującego użytkownika debuggera GDB. Polecenia te zostały zamieszczone w tabeli poniżej. Pierwsza kolumna w tabeli zawiera pełną nazwę polecenia. W drugiej umieściłem skróconą nazwę polecenia, którą zapewne będziesz używał znacznie chętniej podczas pracy z GDB. Ostatnia kolumna tabeli zawiera krótki opis zastosowania polecenia. W dalszej części niniejszego rozdziału zostaną omówione poszczególne polecenia wraz z przykładami ich użycia.
PolecenieSkrótZastosowanie
runrUruchamia aplikację, która ma być debugowana.
<CTRL+C><brak>Kombinacja klawiszy, która wstrzymuje debugowanie, umożliwiając jednocześnie wprowadzanie kolejnych poleceń debuggerowi GDB.
nextiniWykonaj jedną instrukcję i wstrzymaj debugowanie.
nextnKontynuuj wykonywanie kodu aż do napotkania następnego wiersza w bieżącej ramce na stosie i wstrzymaj debugowanie. Polecenie wykorzystuje się do omijania debugowania wywoływanych funkcji w analizowanym kodzie. W przypadku, gdy nie ma więcej linii kodu w bieżącej ramce na stosie, polecenie zatrzyma debugowanie na następnym poleceniu z ramki, jaka będzie się znajdowała aktualnie na szczycie stosu.
stepsKontynuuj wykonywanie kodu aż do napotkania innego wiersza w kodzie, po czym wstrzymaj debugowanie. Polecenie głównie wykorzystuje się do wchodzenia do nowej ramki na stosie, która pojawia się w wyniku wywołania metody/funkcji.
finishfinishKontynuuj wykonywanie kodu aż do zakończenia wykonywania funkcji/metody, a następnie wstrzymaj debugowanie. W praktyce oznacza to, że kontynuowane jest debugowanie aż do zdjęcia ze stosu ramki, która w chwili wpisania polecenia znajdowała się na szczycie stosu.
continuecKontynuuje wykonywanie aplikacji aż do napotkania jakiegoś breakpointa lub aż do ręcznego wstrzymania debugowania.
breakbWstawia breakpointa na określonym wierszu w pliku lub na określonej funkcji/metodzie.
info breakpointsinfo brWyświetla listę aktualnie postawionych breakpointów.
deletedKasuje wskazane breakpointy. W przypadku podania polecenia bez parametrów, polecenie skasuje wszystkie postawione breakpointy.
disabledisWyłącza wskazanego breakpointa, ale go nie kasuje.
enableenaWłącza wskazanego breakpointa, który był uprzednio wyłączony.
backtracebtWyświetla callstack-a. Innymi słowy wyświetla ramki, jakie znajdują się na stosie oraz wartości z jakimi ramki zostały wywołane.
printpWyświetla wartość podanej zmiennej.
info sharedlibraryinfo sharedlibraryWyświetla listę bibliotek z których korzysta aplikacja, dostarczając jednocześnie informacji o bibliotekach do których GDB wczytał symbole debugowe.

Uruchamianie aplikacji z poziomu GDB

Polecenie służące do uruchamiania aplikacji z poziomu GDB zostało przedstawione w rozdziale » Kurs GDBUruchomienie lokalnego debugowania aplikacji lekcja. Przykłady uruchamiania zostały przedstawione poniżej.

Parametry aplikacji określane po uruchomieniu GDB

(konsola) gdb NAZWA_TWOJEJ_APLIKACJI
(gdb) run [parametr1] [parametr2] [parametr3]

Parametry aplikacji określane w chwili uruchamiania GDB

(konsola) gdb –args NAZWA_TWOJEJ_APLIKACJI [parametr1] [parametr2] [parametr3]
(gdb) run

Wstrzymywanie debugowania

Wstrzymanie debugowania w celu wprowadzenia poleceń

Jeżeli masz uruchomiony debugger GDB oraz aplikacja jest uruchomiona i aktywna (reaguje na działania użytkownika) to wprowadzanie poleceń w debuggerze jest zablokowane. Aby móc wpisywać polecenia należy wstrzymać działanie aplikacji za pomocą skrótu klawiszowego CTRL+C. Wówczas na ekranie debuggera pojawi się tzw. 'znak zachęty', który informuje użytkownika o możliwości wprowadzania poleceń do GDB. Wygląda to tak:
^C
Program received signal SIGINT, Interrupt.
0x00007ffff60aeca0 in __poll_nocancel () at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) q
A debugging session is active.
Skrót klawiszowy CTRL+C.

Wstrzymanie debugowania po wykonaniu jednej instrukcji

Jeżeli aplikacja jest już w stanie wstrzymania i masz możliwość podawania poleceń, to do dyspozycji masz wiele poleceń umożliwiających śledzenie działania programu. Aby wykonać jedną instrukcję i wstrzymać debugowanie należy użyć polecenia nexti. Przykład:
(gdb) nexti

Wstrzymanie debugowania po wykonaniu jednego wiersza instrukcji w bieżącej ramce

Jeżeli chcesz wykonać jeden wiersz kodu w bieżącej ramce (czyli w praktyce przejść do kolejnej linii kodu w aktualnie wykonywanej funkcji lub metodzie), to należy użyć polecenia next. Przykład:
(gdb) next

Wstrzymanie debugowania po napotkaniu innego wiersza kodu w dowolnej ramce

Jeżeli w aktualnie wykonywanym kodzie natrafiłeś na funkcję/metodę do której chciałbyś wejść, aby prześledzić jej działanie to wówczas powinieneś skorzystać z polecenia step. Polecenie wykonuje aplikację aż do napotkania innego wiersza w kodzie. W praktyce oznacza to, że:
  • jeżeli w bieżącym wierszu występują tylko instrukcje do wykonania (brak wywołań funkcji), to debugger zatrzyma się na następnym wierszu jaki ma zostać wykonany;
  • jeżeli w bieżącym wierszu występuje jedna lub więcej funkcji, to debugger wejdzie w pierwszą z nich i zatrzyma się przed wykonaniem pierwszej instrukcji kodu z funkcji.
Przykład:
(gdb) step

Wstrzymanie debugowania po wyjściu z bieżącej ramki

Jeżeli wszedłeś do funkcji lub metody, która Ciebie nie interesuje (bądź stwierdziłeś, że jednak nie chcesz analizować danego kodu) to do dyspozycji mamy polecenie final, które wstrzyma debugowanie aplikacji zaraz po wyjściu z bieżącej ramki (czyli zaraz po wyjściu z aktualnie analizowanej metody/funkcji).
(gdb) finish

Kontynuowanie debugowania

Jeżeli chcesz wznowić działanie aplikacji i nie masz potrzeby wprowadzania kolejnych poleceń (np. nie chcesz na chwilę obecną stawiać więcej breakpointów), to możesz użyć do tego celu polecenie continue. Polecenie continue wznawia działanie debugowanej aplikacji oraz odbiera nam prawo do wprowadzania kolejnych poleceń (aż do kolejnego wstrzymania aplikacji). Przykład:
(gdb) continue

Wstawianie breakpointa

Jeżeli chciałbyś, aby debugger monitorował kod w trakcie działania aplikacji i zatrzymał się automatycznie w chwili napotkania określonej linii kodu, to wówczas będziesz potrzebował postawić breakpointa (po polsku stosuje się określenie 'postawienia pułapki'). Do stawiania pułapki używa się polecenia breakpoint, które jako parametr może przyjmować różne wartości, takie jak:
  • nazwa_pliku:numer_wiersza - informujesz debugger, że chcesz postawić breakpointa w pliku o określonej nazwie i w określonym wierszu;
  • nazwa_funcji - informujesz debugger, że chcesz postawić breakpointa w pierwszym wierszu funkcji o określonej nazwie (ma ją sobie znaleźć w jakim pliku się znajduje);
  • przestrzen_nazw::nazwa_funcji - informujesz debugger, że chcesz postawić breakpointa w pierwszym wierszu funkcji o określonej nazwie, która znajduje się w określonej przestrzeni nazw (ma ją sobie znaleźć w jakim pliku się znajduje);
  • przestrzen_nazw::klasa::nazwa_metody - informujesz debugger, że chcesz postawić breakpointa w pierwszym wierszu określonej metody w określonej klasie, która znajduje się w określonej przestrzeni nazw (ma ją sobie znaleźć w jakim pliku się znajduje);
Sposobów do określania miejsca postawienia breakpointów jest jeszcze więcej, jednak w niniejszym rozdziale skupiłem się na absolutnych podstawach o których należy wiedzieć. Przykład:
(gdb) breakpoint nazwa_pliku.cpp:123
(gdb) breakpoint przestrzen_nazw::Klasa::metoda
(gdb) breakpoint przestrzen_nazw::funkcja

Lista breakpointów

Aby wyświetlić aktualną listę postawionych breakpointów należy użyć polecenia info breakpoints. Przykład:
(gdb) info breakpoints

Kasowanie breakpointów

Do kasowania breakpointów służy polecenie delete. Jeżeli polecenie zostanie wywołane bez argumentów, to wówczas zostaną skasowane wszystkie breakpointy. Jeżeli za poleceniem wskażemy numer breakpointa, który chcemy usunąć, to wówczas zostanie skasowany tylko ten breakpoint, który podaliśmy. Przykład:
(gdb) delete

Wyłączanie breakpointów

Jeżeli masz potrzebę wyłączenia jakiegoś breakpointa, aby debugger się na nim nie zatrzymywał, ale jednocześnie wiesz, że będziesz chciał go później przywrócić - możesz wówczas użyć polecenia disable. Polecenie disable służy do wyłączania określonego breakpointa, dzięki czemu debugger nie będzie się na nim zatrzymywał. Przykład:
(gdb) disable 1

Włączanie breakpointów

Jeżeli chesz przywrócić breakpointa, który uprzednio został wyłączony to należy użyć polecenia enable oraz jako parametr podać numer breakpointa jaki powinien zostać aktywowany. Przykład:
(gdb) enable 1

Wyświetlanie callstacka

Aby wyświetlić aktualny stos ramek należy użyć polecenia backtrace. Każda ramka opisuje jedno wywołanie funkcji/metody, więc backtrace daje Ci możliwość analizy wywołań metod jak i funkcji oraz dostarcza cennej informacji w postaci wartości z jakimi została wywołana każda funkcja/metoda w stosie ramek. W wysokopoziomowych środowiskach backtrace nazywany jest callstack-iem, czyli stosem wywołań metod i funkcji. Przykład użycia polecenia backtrace:
(gdb) backtrace

Wypisywanie wartości zmiennej

Jeżeli chcesz wypisać wartość konkretnej zmiennej jaka jest widoczna z poziomu aktywnej ramki, to wówczas należy skorzystać z polecenia print. Polecenie print przyjmuje jako parametr nazwę zmiennej, której wartość chcesz wypisać. Przykład:
(gdb) print nazwa_zmiennej

Wyświetlanie listy załadowanych bibliotek i symboli debugowych

Jeżeli chcesz się dowiedzieć jakie biblioteki są używane przez aplikację, którą debugujesz lub chcesz się dowiedzieć jakie symbole debugowe są widoczne przez GDB, to wówczas powinieneś skorzystać z polecenia info sharedlibrary. Przykład:
(gdb) info sharedlibrary
Poprzedni dokument Następny dokument
Konfiguracja GDB Wyświetlanie wartości zmiennych