KGDB
Co to jest?
- Patch, który trzeba zaaplikować do jądra, aby umożliwić opcje debuggowania.
- Linux source level debugger - debuggowanie z poziomu kodu.
- informacje o kodzie źródłowym są wyświetlane poprzez gdb od momentu od kiedy jądro wejdzie do KGDB .
- Umożliwia debuggowanie jądra w sposób podobny do debuggowania aplikacji.
- Wymaga użycia dwóch maszyn:
- development - z zainstalowanym gdb
- Jądro które chcemy zdebuggowac uruchamiamy na maszynie target
- Odpluskwiamy przy użyciu gdb z maszyny development.
- Maszyny połączone są przez porty szeregowe.
Możliwości
- Śledzenie wykonania kodu jądra instrukcja po instrukcji
- kod w assemblerze - nieczytelne i trudny do zroumienia
- kod w C (funkcje l, n i s) - największa zaleta KGDB. Kod jest prawie taki jak go napisaliśmy (optymalizacje wprowadzają delikatne zmiany).
- Breakpointy ustawiane na zmiennych, instrukcjach i rejestrach
- Obserwowanie wartości zmiennych i rejestrów czasie wykonania programu
- Modyfikowanie w locie wartości w pamięci i zmiennych
- Oglądanie stosu wywołań funkcji systemowych
- Obsługa wątków - śledzienie, przełaczanie się
- komenda gdb info threads zwraca listę watków działających na debuggowanym jądrze.
- Pokazuje również funkcje i kod źródłowy przy wykonywaniu którego są te wątki. Użytkownik może dowolnie przełączać
się między wątkami i śledzić ich wykonanie.
- kompletny stan wątku dają komendy backtrace i info registers. Komendy operują na wątku ustawionym przez komendę set thread.
- Wsparcie dla systemów wieloprocesorowych
- kiedy jeden z procesorów wchodzi do KGDB, KGDB zmusza do tego również pozostałe.
- kiedy wszystkie są już w KGDB, kontaktuje się ono z GDB i pozwala egzaminować stan jądra poprzez GDB.
- normalnie kiedy procesor blokuje przerwania przez długi czas, wywołany jest nmi-watchdog, co powoduje kernel panic.
- gdy uruchomiony jest KGDB, nmi-watchdog zamiast wywolania kernel panic wchodzi do KGDB, zezwalając na analizę jądra w czasie gdy właczył sie nmi-watchdog
- Wyświetlanie informacji konsolowych poprzez gdb
- jeśli opcja jest uruchomiona, KGDB wypisuje komunikaty z konsoli w GDB, a GDB wyświetla je na tą konsolę na której działa.
- ponieważ maszyny target i developement mogą dzielić ten sam monitor oraz klawiaturę (np: VMware), funkcjonalność ta pozwala zaoszczędzić kłopotu z przełączaniem monitora do maszyny target, zawsze kiedy tylko wyświetlane są komunikaty jądra.
- Debuggowanie modułów
- należy mieć zainstalowane gdbmod na maszynie development
Dodatkowe funkcjonalności
- Early Param
- Niektóre wersje KGDB (począwszy od Linux 2.6.8-rc1) używają opcji early_param by rozpocząć oczekiwanie na połączenie ze zdalnym GDB o wiele wcześniej
- GDB detach and reattach
- Jest możliwość "odłączenia" gdb od działającego jądra w każdej chwili oraz ponownego odpalenia gdb z już działającym linuxem.
- Support for Ethernet
- Umożliwa komunikację na lini gdb - KGDB poprzez Ethernet, a nie port szeregowy. Wciąż nie do konca stabilne, ale prace rozwojowe trwają ;-)
- Support for different processor architectures
- KGDB umożliwa debuggowanie na procesorach z rodzin: i386, powerpc, x86_64, mips oraz ia64.
Pomocne linki:
Instalacja
Ponieważ większość osób nie dysponuje dwoma komputerami, oraz kablem szerogowym RS-232, więc przedstawię instalację
KGDB na dwóch wirtualnych maszynach (VMware pod Windows). Większość kroków które tu opiszemy należy powtórzyć przy każdej instalacji tego debuggera. Jeśli ktoś chciałby zainstalować KGDB pod linuksem (wtedy wystarczy tylko jedna wirtualna maszyna) to zachęcam do obejrzenia jednego z linków. Proces ten został tam dosyć szczegółowo omówiony (zwłaszcza konfiguracja portu szeregowego).
Instalacja zostanie opisana na przykładzie KGDB w wersji 2.4 (najnowsza w chwili obecnej), jądra 2.6.15.6 (w tej chwili nie ma jeszcze wersji KGDB dla jądra 2.6.17) oraz architektury i386.
- Uruchamiamy VMware, tworzymy 2 wirutalne maszyny, oraz instalujemy na nich preferowaną przez nas dystrybucję linuxa. Teraz startujemy wirtualna maszynę która będzie spełniać zadania maszyny development.
- Ściągamy odpowiednie źródła linuxa oraz rozpakowujemy je:
cd /usr/src
wget "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.15.6.tar.bz2"
tar -jxvf linux-2.6.15.6.tar.bz2
- Ściągamy patche KGDB oraz aplikujemy je:
cd /usr/src
wget "http://kgdb.linsyssoft.com/downloads/kgdb-2/linux-2.6.15.5-kgdb-2.4.tar.bz2"
tar -jxvf linux-2.6.15.5-kgdb-2.4.tar.bz2
cd linux-2.6.15.6
patch -p1 < ../linux-2.6.15.5-kgdb-2.4/core-lite.patch
patch -p1 < ../linux-2.6.15.5-kgdb-2.4/core.patch
patch -p1 < ../linux-2.6.15.5-kgdb-2.4/i386-lite.patch
patch -p1 < ../linux-2.6.15.5-kgdb-2.4/i386.patch
patch -p1 < ../linux-2.6.15.5-kgdb-2.4/8250.patch
- Zaznaczamy w menuconfigu odpowiednie opcje. Wszystkie je można znaleźć w zakładce Kernel Hacking:
- Koniecznie musimy zaznaczyć opcje Compile the kernel with frame pointers oraz Compile the kernel with debug info
- Opcja Console messages through gdb była omówiona wyżej
- Przy Simple selection of KGDB serial port wybieramy *
- Numer portu szeregowego ustawiamy na 0
- Kompilujemy jądro naszym ulubionym sposobem np:
cd /usr/src/linux-2.6.15.6
make
po czym cierpliwie czekamy, aż jądro które chcemy zdebuggować będzie gotowe.
- Gdy kompilacja zakończy sie pomyślnie powinny nam powstać pliki vmlinux i arch/i386/boot/bzImage Ten drugi plik należy teraz przenieść na maszynę target. Można to zrobić np stawiając serwer ssh i używając scp.
cd /usr/src/linux-2.6.15.6
scp arch/i386/boot/bzImage adres_maszyny_target:/boot/bzImage-bugged
- Uruchamiamy maszynę target i dodajemy nowy wpis do gruba (ewentualnie lilo)
vim /boot/grub/menu.lst
nowa pozycja powinna wyglądać tak (z dokładnością do preferowanych nazw):
title Kernel 2.6.15.6-bugged
root (hd0,2)
kernel /boot/bzImage-bugged root=/dev/hda3 ro kgdbwait
boot
-
Dodajemy nowy port szeregowy do maszyny target. Konfigurujemy go by łączył się z named pipe o nazwie \\.\pipe\com_1. Z zaawansowanych opcji wybieramy: "yield CPU on poll".
-
Ściągamy i instalujemy program "Named Pipe TCP Proxy". Patrz linki ;-)
-
Uruchamiamy proxy i ustanawiamy nowe połączenie pomiędzy portem lokalnym na naszym komputerze domowym (np. 8222) oraz \\.\pipe\com_1. Koniecznie należy zaznaczyć opcję enable non-local systems access.
Uruchomienie
- Uruchamiamy maszynę target i z menu gruba wybieramy Kernel 2.6.15.6-bugged. System powinien się zatrzymać po wypisaniu kilku komunikatów
- Na maszynie development uruchamiamy gdb:
cd /usr/src/linux-2.6.15.6
gdb vmlinux
- Nawiązujemy połączenie z drugą maszyną:
target remote ip:port_number
, gdzie ip - to adres pod jakim VMware widzi Windows (u mnie 192.168.80.1), a port_number to numer portu który wybraliśmy w "Named Pipe TCP Proxy".
- Jeśli wszystko się udało powinniśmy mieć już kontrolę nad jądrem na maszynie target. Możemy kazać mu dalej się uruchamiać wpisując:
continue
Debuggowanie
Przykład użycia KGDB do debuggowania jądra przedstawia poniższy screen cast:
Na filmie debian_2 to maszyna
development natomiast debian_IDE to maszyna
target. Pokazuje on kolejno proces uruchomienia obu wirtualnych maszyn. Breakpoint zostanie ustawiony na funkcji
do_execve, która jest wywoływana przy uruchomianiu programów przez użytkownika.
W celu demonstracji breakpointa zostanie wywolane polecenie
ls. Następnie zostanie pokazane użycie dobrze wszystkim znanym poleceń gdb do śledzenia kodu jądra. Miłego oglądania ;-)