Nie taki GDB straszny - wprowadzenie do debuggera

Aby zacząć używać GDB (GNU Project Debugger) powinniśmy skompilować nasz kod z opcją -ggdb, co powoduje dodanie symboli dla debuggera. Podczas debuggowania nie używamy żadnych opcji optymalizacji kodu, które potencjalnie mogą mocno zmodyfikować sposób i kolejność wykonywania instrukcji.

Na początek podstawowe komendy gdb i sposób uruchamiania procesów via gdb:

Jako dwóch przykładów użyję kodu example1/example2 z artykułu o strace (który bardzo polecam - nie zawsze mamy możliwość komfortowej kompilacji i pracy z GDB, a często strace może okazać się wystarczający w diagnozowaniu problemu).

W przypadku example1.c nie zaobserwujemy żadnych problemów, program wykona się poprawnie.

Na przykładzie kodu example2.c przetestujemy szukanie błędu w programie. Program próbuje połączyć się na localhost:5000 i wysłać tam dane (*send_data):

Po uruchomieniu example2 nie zwraca żadnego błędu. Ciekawy jest natomiast kod wyjścia z programu:

Jako kod wyjścia dostajemy 141, zamiast 0 (które oznacza prawidłowe zakończenie procesu). Pójdźmy zatem dalej, kompilując example2.c z opcją -ggdb i śledząc przebieg wykonywania:

Okazuje się że w linii 33 (example2.c:33) dostajemy SIGPIPE, czyli sygnał próby zapisu do potoku, do którego pisać się nie da (w tym wypadku chodzi o niepowodzenie funkcji connect z linii 30). Wniosek: connect powinien zostać obłożony warunkiem, na przykład tak:

Na koniec należy dodać, że nigdy nie powinno się korzystać z kodu skompilowanego z opcjami debuggowania w środowisku docelowym, produkcyjnym - może to wpłynąć negatywnie na wydajność aplikacji. Dodatkowo można go strippować (komenda strip), usuwając wszystkie zbędne przy wykonywaniu informacje - co zmniejsza rozmiar pliku wykonywalnego i teoretycznie może poprawić szybkość wykonywania kodu.