Michał Matczuk Tomasz Dziedzicki i Piotr Wygodzki
Debugowanie Jądra
Printk() - Coś co naprawdę ma sens ...
Co to jest?
Funkcja printk() działa niemal identycznie, jak funkcja printf() z biblioteki
dostępnej przy programowaniu przestrzeni użytkownika. Tak więc jest to funkcja
wypisująca sformatowany ciąg znakowy. Nie jest jednak do końca taka zwyczajna.
Przykład
printk(KERN_DEBUG "Nazwa pliku = %s", filename);
printk(KERN_WARNING "Minister zdrowia ostrzega: palenie tytoniu powoduje choroby
płuc.\n");
printk("Nie został określony poziom rejestrowania.\n");
Priorytety
KERN_EMERG
| < 0>
| Sytuacja awaryjna |
KERN_ALERT
| < 1>
| Problem wymagający natychmiastowej interwencji |
KERN_CRIT
| < 2>
| Sytuacja krytyczna |
KERN_ERR
| < 3>
| Błąd |
KERN_WARNING
| < 4>
| Ostrzeżenie |
KERN_NOTICE
| < 5>
| Sytuacja normalna, warta odnotowania |
KERN_INFO
| < 6>
| Informacja |
KERN_DEBUG
| < 7>
| Komunikat diagnostyczny |
Jak to jest?
Za pobieranie komunikatów jądra z bufora odpowiedzialny jest demon przestrzeni
użytkownika klogd. Demon ten zapisuje komunikaty do systemowego pliku dziennika,
korzystając przy tym z pomocy demona syslogd. klogd w celu odczytywania komunikatów
korzysta z pliku /proc/kmsg (bądź też z systemowego wywołania syslog()). klog
budzi się, gdy przychodzi nowy komunikat i przekazuje go do demona syslogd.
Ważne pliki
/var/log/messages
/etc/syslog.conf
Przydatne Makra
BUG()
BUG_ON()
panic()
dump_stack()
Linux/arch/v850/kernel/bug.c
void __bug ()
{
printk (KERN_CRIT "kernel BUG at PC 0x%x (SP ~0x%x)!\n",
ret_addr() - 4, /* - 4 for `jarl' */
stack_addr());
machine_halt ();
}
http://lisa.cs.uni-potsdam.de/lxr/source/
ltrace czyli Krzysztof
Gibas i problemy z kde
Problem ze startowaniem KDE. Zwrócony błąd:
"_KDE_IceTransSocketCreateListener: failed to bind listener
_KDE_IceTransSocketUNIXCreateListener: ...SocketCreateListener() failed
_KDE_IceTransMakeAllCOTSServerListeners: failed to create listener for local
Cannot establish any listening sockets DCOPServer self-test failed."
ROZWIAZANIE=
strace -f -F -o ~/dcop-strace.txt dcopserver
27207 mkdir("/tmp/.ICE-unix", 0777) = -1 EEXIST (File exists)
27207 lstat64("/tmp/.ICE-unix", {st_mode=S_IFDIR|S_ISVTX|0755, st_size=4096,
...}) = 0
27207 unlink("/tmp/.ICE-unix/dcop27207-1066844596") = -1 ENOENT (No such file
or directory)
27207 bind(3, {sin_family=AF_UNIX, path="/tmp/.ICE-unix/dcop27207-1066844596"},
38) = -1 EACCES (Permission denied)
27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "SocketCreateListener: failed to "..., 46) = 46
27207 close(3) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "SocketUNIXCreateListener: ...Soc"..., 59) = 59
27207 umask(0) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "MakeAllCOTSServerListeners: fail"..., 64) = 64
27207 write(2, "Cannot establish any listening s"..., 39) = 39
ltrace = wywolania funkcji
bibliotecznych
KDB (Built-in kernel debugger for Linux)
Debugger'y - czy naprawdę
potrzebne?
Linus Torvalds:
I don't like debuggers. Never have, probably never will. I use gdb all the time,
but I tend to use it not as a debugger, but as a disassembler on steroids that
you can program.
None of the arguments for a kernel debugger has touched me in the least. And
trust me, over the years I've heard quite a lot of them. In the end, they tend
to boil down to basically: It would be so much easier to do development, and
we'd be able to add new things faster.
And quite frankly, I don't care. I don't think kernel development should be
"easy". I do not condone single-stepping through code to find the bug. I do
not think that extra visibility into the system is necessarily a good thing.
Jak widać nie wszyscy sądzą, że są one niezbędne, niemniej naszym zdaniem warto
sprawdzić, czy nie ułatwią nam one choćby pracy nad projektami z laboratorium.
KDB - Co to właściwie
jest?
Patch na jądro.
Mało inwazyjny - możliwa kompilacja bez frame pointers.
Możemy testować jądro na tej maszynie, na której je odplamy.
Mało użyteczny - brak możliwości debugowania z poziomu kodu (jedynie assembler).
KDB - Możliwości
Breakpointy.
Możliwość wykonywania instrukcja po instrukcji.
Podglądanie rejestrów i komórek pamięci.
Zmiana zawartości rejestrów lub komórek pamięci.
Podgląd stosu aktualnego procesu, procesu o danym PID.
Deasemblacja instrukcji.
KDB - miłe złego początki,
czyli nieco o instalacji.
Instalacja:
- Pobieramy kod jądra i rozpakowujemy.
wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.13.tar.bz2
tar -jxvf linux-2.6.17.13.tar.bz2
- Pobieramy patch-e i rozpakowujemy je poleceniem bunzip
nazwa_patcha.bz2
wget ftp://oss.sgi.com/www/projects/kdb/download/v4.4/kdb-v4.4-2.6.17-common-1.bz2
wget ftp://oss.sgi.com/www/projects/kdb/download/v4.4/kdb-v4.4-2.6.17-i386-1.bz2
- Ładujemy patch-e w folderze z rozpakowanymi źródłami (zakładamy
że patche są folder wyżej)
patch -p1 < ../kdb-v4.2-2.6.17-common-1
patch -p1 < ../kdb-v4.2-2.6.17-i386-1
- Kopiujemy jakiegoś działającego configa (np tego z /boot)
do folderu ze źródłami i zapisujemy go jako plik .config
- Wykonujemy polecenie make menuconfig, zaznaczając w kernel
hacking opcje:
Built-in Kernel Debugger support - wymagane
Compile the kernel with framepointers - nie wymagane, nieco inwazyjne, ale
wspiera debuggowanie (lepsze śledzenie stosu)
KDB off by default - opcjonalne, wtedy aby przywołać kdb musimy wykonać
polecenie:
echo "1" > /proc/sys/kernel/kdb aby ustawić odpowiednią flagę
umożliwiającą uruchomienie kdb
- Możemy ręcznie przywołać KDB naciskając Ctrl-Pause .
Zostanie wyświetlony prompt KDB i możemy korzystać jego dobrodziejstw. Każdorazowo
przy kernel panic kdb zostanie przywołane automatycznie.
Trochę praktyki...
KGDB (Kernel Debugging with remote GDB)
Co to właściwie jest?
- Potrzebne są dwie maszyny połączone przez port szeregowy.
Target Machine: Musi miec jadro skompilowane z patchami niezbędnymi
do oblugi KGDB.
Development Machine: Musi mieć zainstalowane GDB.
- Debugowanie z poziomu kodu.
- Konieczna kompilacja z frame pointers - jest więc nieco
inwazyjny.
Możliwości:
- Debugowanie z poziomu kodu. Możliwość wykonania kodu jądra
instukcja po instrukcji.
- Breakpointy (na zmiennych, instrukcjach, rejestrach)
- Podgląd wartości zmiennych, rejestrów.
- Modyfikowanie w locie wartości zmiennych, rejestrów.
- Możliwość przekierowania informacji konsolowych na zdalną
konsolę.
- Wsparcie dla mechanizmu wątków.
- Wsparcie dla debugowania modułów.
- Wsparcie dla architektur wieloprocesorowych.
- Wygodny debug - wszystkie możliwości gdb, a to już chyba
wszyscy znamy.
Przypadatne linki:
UML Czyli User-Mode-Linux
Wiemy dobrze z poprzedniej prezentacji czym zajmuje się wirtualizacja. Dziś spróbuję
zapoznać was bliżej ze specyficzną maszyną wirtualną - UML. Oraz postaram się
pokazać jak UML może nam pomóc
Co różni UML od innych wirtualizacji?
O UML mówi się
czasem: Wirtualny System Operacyjny
VVware - pełna wirtualizacja sprzętowa ["dowolny"
OS]
UML - "port of Linux to Linux" oparty na Linuxowych wywołaniach systemowych
Przewaga UML nad innymi
podejściami do wirtualizacji
Najbardziej odczuwalna
różnica - Prędkość
Łatwość zmiany urządzeń i interfejsów
[./linux ubd0=rootfs.debian ubd1=swapfs.debian con0=fd:0,fd:1
eth0=tuntap,FE:FD,78:DD:AG:CC
uml-debby mem=512M ... szczegóły w dalszej części]
Wiele instancji UML może korzystać z tych samych plików [root_fs]
Można zagnieżdżać instancje UML w sobie
Można zainstalować dowolną dystrybucje Linux'a
Dobra izolacja
UML działa jako zestaw procesów w przestrzeni Użytkownika [poziom
izolacji procesów]
Gdzie jest UML...
[Xen
- VMware - .... - UML - ... - chroot]
Wirtualizacja i wsparcie
dla sprzętu
UML wymaga wirtualnego sprzętu i jest dostarczany
ze sterownikami
- konsoli
- wirtualnego systemu plików [VFS]
- sieci
- specjalnego urządzenia pozwalającego na zarządzanie UML'em
Baśń o 2 jądrach
Do działania UML
potrzebujemy 2 jąder
- Jądro gościa (guest kernel)
- Jądro gospodarza (host kernel)
UML działa w jednym z trybów TTmode lub
SKASmode.
Potencjalnie każde jądro (>2.2) powinno
móc obsłużyć UML w trybie TT lub SKAS0
tryb SKAS3 wymaga nałożenia łaty
na jądro gospodarza (host kernel)
Jak to działa [Design]
i czym się różni tryb SKAS od trybu TT
UML jest zaprojektowany
jako przeniesienie (port) jądra Linuxa na specjalną platformę um.
UML(guest kernel) jest uruchamiany pod kontrolą jądra systemu(host kernel) jako
proces użytkownika.
UML korzysta z jądra systemu(host kernel) tylko
do emulowania wirtualnego sprzętu.
UML ma swój własny scheduler,
pamięć wirtualną i w pełni sam zarządza swoimi procesami.
[w szczególności jeśli system(host
kernel) działa na jądrze
2.4 a UML(guest kernel) jest w
wersji 2.6 to procesy gościa szeregowane są
w O(1) tzn. system przydziela UMLowi procesor
ale dalej UML szereuje swoje procesy sam]
TT - Tracing Thread ... przeszłość
Każdy proces w jądrze UML jest jednocześnie procesem w systemie nadrzędnym
Jest specjalny wątek nazywany wątkiem śledzącym (tracing
thread) który wyłapuje
żądania systemowe i przekierowuje je do jądra UML.
Każdy proces gościa ma ma kod jądra w swojej przestrzeni adresowej i domyślnie
jest zapisywalny.
[bezpieczeństwo / prędkość]
SKAS - Single Kernel Address Space
Jądra mają oddzielną przestrzeń adresową
procesy gościa wyglądaja(przestrzeń adresowa) tak jak wyglądałyby nanormalnej
maszynie
Są 4 procesy UML widoczne z poziomu hosta
FILOZOFIA: CELEM SKAS JEST POSIADANIE 1
PROCESU KTÓRY PRZEŁĄCZA SIĘ MIĘDZY WIELOMA PRZESTRZENIAMI ADRESOWYMI TAK BY
NIE TRZYMAC CZEKAJĄCYCH PROCESÓW NA LISCIE PROCESÓW HOSTA
wzięte z [1]
wzięte z [1]
UML w
praktyce
zbudujemy jądro gościa ze źródeł:
$ cd ~/
ściągamy jądro
$ wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.13.tar.bz2
$ mkdir UML
$ cd UML
$ tar zfx ../linux-2.6.17.13.tar.bz2
$ ls -al
drwxr-xr-x 19 miami users
4096 Nov 4 12:05 linux-2.6.17.13
$ cd linux-2.6.17.13
$ make defconfig ARCH=um
$ make menuconfig ARCH=um
musimy ustawić flagi CONFIG_DEBUGSYM
oraz CONFIG_PT_PROXY
to spowoduje kompilację jądra z opcja -g
tak by można było używać gdb.
w tym celu:
następnie wybieramy opcje jak poniżej [wybór z górką]
wychodzimy zapisując zmiany
$ make linux ARCH=um
$ make modules ARCH=um
$ make modules_install ARCH=um
INSTALL_MOD_PATH=/tmp
$
strip linux
$ ls -al
...
drwxr-xr-x 4
miami users 8192 Nov 4 12:13 kernel
drwxr-xr-x 5
miami users 4096 Nov 4 12:16 lib
-rwxr-xr-x 2 miami users
1733692 Nov 4 12:28 linux
drwxr-xr-x 2
miami users 4096 Nov 4 12:13 mm
drwxr-xr-x 36 miami
users 4096 Nov 4 12:16 net
drwxr-xr-x 8
miami users 4096 Nov 4 12:12 scripts
drwxr-xr-x 4
miami users 4096 Nov 4 12:14 security
drwxr-xr-x 16 miami
users 4096 Nov 4 12:16 sound
drwxr-xr-x 2
miami users 4096 Nov 4 12:12 usr
-rwxr-xr-x 2 miami users
1733692 Nov 4 12:28 vmlinux
linux i vmlinux
są twardymi połączeniami (hard link) do tego samego pliku.
Spróbujmy uruchomić
$ ./linux
Checking that ptrace can
change system call numbers...OK
Checking syscall emulation
patch for ptrace...OK
Checking advanced syscall
emulation patch for ptrace...OK
Checking for tmpfs mount
on /dev/shm...OK
Checking PROT_EXEC mmap in
/dev/shm/...OK
Checking for the skas3
patch in the host:
- /proc/mm...not found
- PTRACE_FAULTINFO...not found
- PTRACE_LDT...not found
UML running in SKAS0
mode
...
Failed to open 'root_fs',
errno = 2
VFS: Cannot open root device "98:0" or
unknown-block(98,0)
Please append a correct "root=" boot option
Kernel panic - not syncing: VFS: Unable
to mount root fs on unknown-block(98,0)
Oprócz jądra potrzebujemy jeszcze do działania
- części "GNU" naszego systemu.
Gdy uruchamiany ./linux
szuka pliku root_fs
w lokalnym katalogu, w tym pliku
oczekuje znaleźć obraz sytemu plików ext2 zawierający
narzędzia.
istnieje wiele gotowych root_fs
do ściągnięcia
[http://sourceforge.net/project/showfiles.php?group_id=429&package_id=472]
oraz narzędzi ułatwiających tworzenie własnych
systemów plików.
My posłużymy się gotowym slacwarem 8.1
[http://mirror.usermodelinux.de/root_fs_slack8.1.bz2]
$ cd ~/
$ wget http://mirror.usermodelinux.de/root_fs_slack8.1.bz2
$ mv root_fs_slack8.1.bz2 uml/root_fs.bz2
$ cd uml
$ bzip2 -fd root_fs.bz2
$ mkdir mnt
$ ls -al
total 205832
drwxr-xr-x 4
miami users 61 Nov 4 13:11 .
drwxr-xr-x 52 miami
users 4096 Nov 4 12:41 ..
drwxr-xr-x 20 miami
users 4096 Nov 4 12:28 linux-2.6.17.13
drwxr-xr-x 2
miami users 6 Nov 4 13:11
mnt
-rw-r--r-- 1 miami users 210763776
Nov 4 12:52 root_fs
zobaczmy co kryje się w tym pliku
$ mount root_fs mnt/ -o
loop
$ cd mnt
$ ls
bin dev home lost+found
proc sbin usr
boot etc lib mnt
root tmp var
zgodnie z oczekiwaniami to co zwykle w kożeniu
systemu plików.
UWAGA!!
$ ls dev/ubd*
dev/ubd0 dev/ubd1
dev/ubd2
to są urządzenia (uml block device) na które
uml przypisuje obraz z pliku root_fs
$ cat
etc/fstab
#/dev/ubd0
/ ext2
defaults
1 1
/dev/ubd/0
/ ext2
defaults
1 1
none
/dev/pts devpts gid=5,mode=620
0 0
none
/proc proc defaults
0 0
zwróćmy uwagę na komentarz
w pliku fstab i na nazwy urządzeń.
Jeśli pozostawimy ten komentarz system nie zadziała poprawnie
fsck [file system check] będzie zgloszał błąd podczas startu
usuwamy komentarz i odmontowujemy wolumin
$ vim etc/fstab
$ cd ../
$ umount mnt
uruchamiamy UML [skutecznie]
$ cd linux-2.6.17.13
$ ./linux ubd0=../root_fs
udało sie...
UML przy starcie otwiera 3 okna xterm [3
konsole] oraz czwartą w okienku w którym został uruchomiony.
Możemy się zalogować
$ Login: root
$ Password: root
By wyjść wydajemy komendę halt
4 rzeczy które mogą sie nieudać [bardzo
skończony podzbiór]
niechce się skompilować
- ściągnij uml-patch-2.6.patch.bz2
[dla odpowiedniego jądra] z [7] [folder guest]
- cd linux-2.6.x.y
- bzcat uml-patch-2.6.patch.bz2 | patch
-p1
- odpowiednie opcje kompilacji
- make defconfig ARCH=um
- domyslne ustawienia
- make clean - czysci
- make mrproper - przywraca początkowy [nie usuwa łatek]
[kasuje .config]
nieładuje root_fs
nieotwierają się konsole [w xterm]
- być moze brakuje programu port-helper
- można go ściągnąć z [6]
- skompilowac i umiescic w /user/bin
Opcje uruchamiania
$ ./linux
mem=size[ K | M | G
]
mem=300M
ethn=interface configuration
ubd<n><flags>=filename
<flags> = {readonly
= r;
O_SYNC = s;
data = d;
shared = c}
ubd0=../root_fs
mode=skas0
mode=tt
debug
Debugowanie w trybie tt
Koncepcja polega na tym że przy starcie uruchamiany jest dodatkowy terminal
z gdb
z którego możemy kontrolowac system.
Niestety tryb tt niedlugo zniknie. Nizaleca się stosowania.
W jądrze jest oznaczony jako Deprecated.
Przy uruchmianiu powoduje segfault.
Debugowanie
modułów przy pomocy umlgdb
skrypt umlgdb jest częścią pakietu umltools którego składniki ściągamy z [6]
chmod 700 umlgdb
musimy zedytować treść skryptu:
set MODULE_PATHS {
"md5" "/tmp/crypto/md5.ko"
"sha1" "/tmp/crypto/sha1.ko"
"<nazwa>" "<adres>"
}
żeby uruchomić umlgdb potrzebujemy pakietu except
./umlgdb
******** GDB pid is 14931 ********
Start UML as: ./linux <kernel
switches> debug gdb-pid=14931
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".
następnie na
innej konsoli uruchamiamy
./linux
mode=tt debug gdb-pid=14931
...segfault
Debugowanie w trybie
SKAS
jak zwykły program
r
- run
n -
next
c - continue
b - break
p - print
i - info
l - list
$ gdb linux
gdb> b schedule
Breakpoint 1 at 0xa020d039: file thread_info.h, line
50.
gdb> handle
SIGSEGV pass nostop noprint
gdb> handle
SIGUSR1 pass nostop noprint
gdb> r
ubd0=root_fs
Breakpoint 1, schedule () at thread_info.h:50
50
ti = (struct thread_info *) (((unsigned long) &ti) & ~mask);
gdb> l
45 /* how to get the thread information struct from
C */
46 static inline struct thread_info *current_thread_info(void)
47 {
48
struct thread_info *ti;
49
unsigned long mask = THREAD_SIZE - 1;
50
ti = (struct thread_info *) (((unsigned long) &ti) & ~mask);
51
return ti;
52 }
53
54 /* thread information allocation */
gdb> i registers
eax
0x1 0x1
ecx
0x0 0x0
edx
0xa025ce00 0xa025ce00
ebx
0x0 0x0
esp
0xa025bbac 0xa025bbac
ebp
0xa025bc04 0xa025bc04
esi
0x0 0x0
edi
0xa0019638 0xa0019638
eip
0xa020d039 0xa020d039 <schedule+9>
eflags
0x296 0x296
cs
0x73 0x73
ss
0x7b 0x7b
ds
0x7b 0x7b
es
0x7b 0x7b
fs
0x0 0x0
gs
0x33 0x33
gdb> i
"info" must be followed by the name of an info command.
List of info subcommands:
info address -- Describe where symbol SYM is stored
info all-registers -- List of all registers and their
contents
info args -- Argument variables of current stack frame
info auxv -- Display the inferior's auxiliary vector
info breakpoints -- Status of user-settable breakpoints
info catch -- Exceptions that can be caught in the
current stack frame
info classes -- All Objective-C classes
info common -- Print out the values contained in a
Fortran COMMON block
info copying -- Conditions for redistributing copies
of GDB
info dcache -- Print information on the dcache performance
info display -- Expressions to display when program
stops
info extensions -- All filename extensions associated
with a source language
info files -- Names of targets and files being debugged
info float -- Print the status of the floating point
unit
info frame -- All about selected stack frame
info functions -- All function names
info handle -- What debugger does when program gets
various signals
info line -- Core addresses of the code for a source
line
info locals -- Local variables of current stack frame
info macro -- Show the definition of MACRO
info mem -- Memory region attributes
info proc -- Show /proc process information about any
running process
info program -- Execution status of the program
info registers -- List of integer registers and their
contents
info scope -- List the variables local to a scope
info selectors -- All Objective-C selectors
info set -- Show all GDB settings
info sharedlibrary -- Status of loaded shared object
libraries
info signals -- What debugger does when program gets
various signals
info source -- Information about the current source
file
info sources -- Source files in the program
info stack -- Backtrace of the stack
info symbol -- Describe what symbol is at location
ADDR
info target -- Names of targets and files being debugged
info terminal -- Print inferior's saved terminal status
info threads -- IDs of currently known threads
info tracepoints -- Status of tracepoints
info types -- All type names
info variables -- All global and static variable names
info vector -- Print the status of the vector unit
info warranty -- Various kinds of warranty you do not
have
info watchpoints -- Synonym for ``info breakpoints''
info win -- List of all displayed windows
Type "help info" followed by info subcommand name for
full documentation.
Command name abbreviations are allowed if unambiguous.
gdb> quit
bibliografia:
[0]http://user-mode-linux.sourceforge.net/sdotm.html
[1]Dike
Jeff - User Mode Linux, Prentice Hall April 12, 2006
[2]http://user-mode-linux.sourceforge.net
[3]http://user-mode-linux.sourceforge.net/UserModeLinux-HOWTO.html
[4]http://www.user-mode-linux.org/~blaisorblade/howtoapply.html
[5]http://www.redhat.com/magazine/001nov04/features/usermode/
[6]http://www.user-mode-linux.org/cvs/tools/
[7]http://www.user-mode-linux.org/~blaisorblade/patches/