KGDB jest programem umożliwiającym debugging jądra linuxowego na innym komputerze.
W naszym układzie 1 komputer pełni rolę maszyny deweloperskiej (development machine), a drugi maszyny testowej (test machine).
- Maszyna testowa - na niej działa debugowane jądro, dalej będzie nazywana kam
- Maszyna deweloperska - na niej działa GDB, dalej będzie nazywana stargate
1.2.1 Stworzenie działającego łącza przez kabel nullmodem
Po połączeniu komputerów testujemy:
root@stargate:~# touch test.txt
root@stargate:~# echo Plik testowy linia 1 >> test.txt
root@stargate:~# echo Plik testowy linia 2 >> test.txt
root@stargate:~# stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
root@kam:~# stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
root@kam:~# cat /dev/ttyS0
Tutaj maszyna kam zaczyna czekać na dane z kabla szeregowego.
root@stargate:~# cat test.txt > /dev/ttyS0
root@stargate:~# echo lol > /dev/ttyS0
Po wpisaniu powyższych komend otrzymamy na maszynie kam:
Plik testowy linia 1
Plik testowy linia 2
lol
Pojawienie się tych napisów świadczy nam o udanym połączeniu.
Oczekiwanie na kolejne dane można przerwać za pomocą CTRL+C
1.2.2 Przygotowanie źródeł jądra i KGDB
KGDB jest łatką na jądro, umożliwiającą debugging za pomocą GDB.
Uwaga: Poniższy przykład instalacji KGDB jest przeprowadzany poprzez kompilację testowanego jądra na maszynie kam, jednak lepszym pomysłem byłoby kompilowanie na maszynie stargate, a następnie skopiowanie jądra na kam, gdyż kod źródłowy i utworzone pliki będą potrzebne na tej maszynie do pracy GDB.
Jądro, na którym prezentowane są przykłady, to 2.6.17.13.
Zakładamy, że jego źródła są zainstalowane w usr/src/linux-2.6.17.13/ oraz istnieje dowiązanie symboliczne do tego katalogu /usr/src/linux
KGDB dla tej wersji jądra można pobrać z repozytorium CVS:
root@kam:~#cvs -d:pserver:anonymous@kgdb.cvs.sourceforge.net:/cvsroot/kgdb login
root@kam:~#cvs -z3 -d:pserver:anonymous@kgdb.cvs.sourceforge.net:/cvsroot/kgdb co -r linux2_6_17 .
Po wykonaniu tych komend w bieżącym katalogu pojawią się katalogi cvs i kgdb-2.
W celu zainstalowania KGDB, wykonujemy poniższe polecenia:
root@kam:~#cp -r kgdb-2 /usr/src/
root@kam:~#cd /usr/src/linux-2.6.17.13
root@kam:~# for p in $(grep patch ../kgdb-2/series);do patch -p1 -si ../kgdb-2/$p;done
1.2.3 Konfiguracja i kompilacja jądra
root@kam:~#make mrproper
root@kam:~#make menuconfig
KGDB spowodowało pojawienie się kilku dodatkowych opcji.
Wchodzimy do
Kernel hacking
Zaznaczamy
Kernel debugging
W tym momencie pojawia się opcja
KGDB: kernel debugging with remote gdb, którą zaznaczamy.
Pojawiło nam się kilka dodatkowych opcji:
KGDB: Console messages through gdb - jeśli zaznaczymy tą opcję, to komunikaty jądra zamiast na swoją konsolę trafiają na konsolę GDB.
Method for KGDB communication - należy wybrać jedną z opcji:
- KGDB: Use only kernel modules for I/O
- KGDB: On generic serial port (8250) - KGDB łączy się z GDB przez port szeregowy
- KGDB: On ethernet - in kernel - KGDB łączy się z GDB przez interfejs sieciowy za pomocą protokołu UDP. Interfejs sieciowy musi wspierać NETPOLL API
KGDB: On Ethernet - moduł umożliwiający komunikację z GDB poprzez interfejs sieciowy.
Simple selection of KGDB serial port - ogranicza wprowadzane parametry portu do prędkości przesyłu i numeru portu.
Debug serial port baud rate - prędkość przesyłu danych przez port.
Serial port number for KGDB - numer portu szeregowego, na którym chcemy się połączyć.
Po zakończeniu konfiguracji można skompilować jądro:
root@kam:~#make bzImage && make modules
Jądro po kompilacji powinno znajdować się zarówno na maszynie testowej jak i tej z GDB.
Na maszynie testowej instalujemy nowe jądro i dodajemy do programu rozruchowego.
Jeśli podczas startu systemu jądro ma się zatrzymać i czekać na połączenie GDB, to przekazujemy mu parametr
kgdbwait.
Aby z maszyny
stargate podłączyć się do debugowanego na
kam jądra wykonujemy:
root@stargate:/usr/src/linux-2.6.17.13# cd /usr/src/linux-2.6.17.13
root@stargate:/usr/src/linux-2.6.17.13# stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
root@stargate:/usr/src/linux-2.6.17.13# gdb vmlinux
GNU gdb 6.5
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i486-slackware-linux"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) target remote /dev/ttyS0
Remote debugging using /dev/ttyS0
breakpoint () at kernel/kgdb.c:1691
1691 atomic_set(&kgdb_setting_breakpoint, 0);
warning: shared library handler failed to enable breakpoint
(gdb)
W tym momencie jesteśmy gotowi do przystąpienia do debuggingu jądra
1.3.1 Krótkie wprowadzenie do GDB
Skoro korzystamy tutaj z GDB, to warto podać parę informacji na temat jego poleceń.
- continue - (skrót - c) jądro kontynuuje pracę od miejsca, w którym się zatrzymało. Wciśnięcie CTRL+C na maszynie z GDB powoduje zatrzymanie wykonania
- info breakpoints - wypisuje nam informacje o ustawionych punktach przerwań
- break plik : linia lub break funkcja- (skrót - b) ustawia punkt przerwania w zadanym pliku w zadanej linii lub na zadanej funkcji. Brak podania linii lub pliku powoduje zastąpienie ich odpowiednio bieżącym plikiem lub numerem linii
- disable n - usuwa punkt przerwania o numerze n
- list plik : linia lub list plik : funkcja - (skrót - l) powoduje wypisanie kodu wokół linii/funkcji w danym pliku. Brak podania pliku i linii - patrz wyżej
- step n - (skrót - l) odpowiednik step into znanego z wielu debuggerów, czyli jeśli w aktualnej linii jest funkcja, to wchodzimy do niej, a jeśli nie, to wykonujemy linię. n oznacza ile razy wykonać polecenie
- next n - (skrót - n) odpowiednik step over znanego z wielu debuggerów, czyli wykonujemy linię (jeśli linia zawiera wywołanie funkcji, to wykonujemy funkcję bez wchodzenia do niej). n oznacza ile razy wykonać polecenie
- backtrace - (skrót - bt) - wyświetla stos wywołań
- print zmienna - (skrót - p) - wyświetla wartość zmiennej
- set var zmienna=wyrażenie - ustawia wartość zmiennej na wartość wyrażenia
1.3.2 Przykładowa sesja z GDB
(gdb) step 4
[New thread 32768]
90 status |= action->flags;
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
breakpoint () at kernel/kgdb.c:1691
1691 atomic_set(&kgdb_setting_breakpoint, 0);
(gdb) step 3
handle_IRQ_event (irq=4, regs=0xc02c5fa8, action=0xdff56440) at kernel/irq/handle.c:89
89 if (ret == IRQ_HANDLED)
(gdb) list
84 if (!(action->flags & SA_INTERRUPT))
85 local_irq_enable();
86
87 do {
88 ret = action->handler(irq, action->dev_id, regs);
89 if (ret == IRQ_HANDLED)
90 status |= action->flags;
91 retval |= ret;
92 action = action->next;
93 } while (action);
(gdb) break 92
Breakpoint 1 at 0xc0129dd2: file kernel/irq/handle.c, line 92.
(gdb) c
Continuing.
Breakpoint 1, handle_IRQ_event (irq=0, regs=0xc02c5f38, action=0xc027f360) at kernel/irq/handle.c:92
92 action = action->next;
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0xc0129dd2 in handle_IRQ_event at kernel/irq/handle.c:92
breakpoint already hit 1 time
(gdb) disable 1
(gdb) break
Note: breakpoint 1 (disabled) also set at pc 0xc0129dd2.
Breakpoint 2 at 0xc0129dd2: file kernel/irq/handle.c, line 92.
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep n 0xc0129dd2 in handle_IRQ_event at kernel/irq/handle.c:92
breakpoint already hit 1 time
2 breakpoint keep y 0xc0129dd2 in handle_IRQ_event at kernel/irq/handle.c:92
(gdb) re
refresh remote restart restore return reverse-search
(gdb) delete
breakpoints checkpoint display mem tracepoints
(gdb) help delete
Delete some breakpoints or auto-display expressions.
Arguments are breakpoint numbers with spaces in between.
To delete all breakpoints, give no argument.
Also a prefix command for deletion of other GDB objects.
The "unset" command is also an alias for "delete".
List of delete subcommands:
delete breakpoints -- Delete some breakpoints or auto-display expressions
delete checkpoint -- Delete a fork/checkpoint (experimental)
delete display -- Cancel some expressions to be displayed when program stops
delete mem -- Delete memory region
delete tracepoints -- Delete specified tracepoints
Type "help delete" followed by delete subcommand name for full documentation.
Command name abbreviations are allowed if unambiguous.
(gdb) help delete breakpoints
Delete some breakpoints or auto-display expressions.
Arguments are breakpoint numbers with spaces in between.
To delete all breakpoints, give no argument.
This command may be abbreviated "delete".
(gdb) delete breakpoints 1
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y 0xc0129dd2 in handle_IRQ_event at kernel/irq/handle.c:92
(gdb) bt
#0 handle_IRQ_event (irq=0, regs=0xc02c5f38, action=0xc027f360) at kernel/irq/handle.c:92
#1 0xc0129e4d in __do_IRQ (irq=0, regs=0xc02c5f38) at kernel/irq/handle.c:173
#2 0xc010417c in do_IRQ (regs=0xc02c5f38) at arch/i386/kernel/irq.c:108
#3 0xc0102b16 in common_interrupt () at include/asm/current.h:9
#4 0xdff56440 in ?? ()
#5 0x00000000 in ?? ()
(gdb) l 92
87 do {
88 ret = action->handler(irq, action->dev_id, regs);
89 if (ret == IRQ_HANDLED)
90 status |= action->flags;
91 retval |= ret;
92 action = action->next;
93 } while (action);
94
95 if (status & SA_SAMPLE_RANDOM)
96 add_interrupt_randomness(irq);
(gdb) print retval
$1 = 0
(gdb) print action
$2 = (struct irqaction *) 0xc027f360
(gdb)quit
The program is running. Exit anyway? (y or n) y
root@stargate:/usr/src/linux-2.6.17.13#
Zwykły GDB nie umożliwia niestety debugowania modułów ładowanych do jądra. Problem ten rozwiązuje specjalnie zmodyfikowany GDB, którego można pobrać ze strony
http://kgdb.linsyssoft.com/downloads/gdbmod-2.4.bz2
Po rozpakowaniu i skopiowaniu go do /usr/src/linux-2.6.17.13/ możemy zobaczyć go w akcji:
root@stargate:/usr/src/linux-2.6.17.13# ./gdbmod-2.4 vmlinux
GNU gdb 6.4
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) target remote /dev/ttyS0
Remote debugging using /dev/ttyS0
breakpoint () at kernel/kgdb.c:1691
1691 atomic_set(&kgdb_setting_breakpoint, 0);
(gdb) set solib-search-path /usr/src/linux-2.6.17.13/drivers/scsi
(gdb) c
Continuing.
[New thread 2113]
[New thread 32768]
Program received signal SIGTRAP, Trace/breakpoint trap.
breakpoint () at kernel/kgdb.c:1691
1691 atomic_set(&kgdb_setting_breakpoint, 0);
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0xe0ee5000 0xe0eec6d4 Yes /usr/src/linux-2.6.17.13/drivers/scsi/scsi_mod.ko
(gdb) c
Continuing.
[New thread 2121]
Program received signal SIGTRAP, Trace/breakpoint trap.
breakpoint () at kernel/kgdb.c:1691
1691 atomic_set(&kgdb_setting_breakpoint, 0);
(gdb) info sharedlibrary
No shared libraries loaded at this time.
(gdb) quit
The program is running. Exit anyway? (y or n) y
root@stargate:/usr/src/linux-2.6.17.13#