Spis treści
|
Czego potrzeba do poprawienia buga?
1.Bug. Dobrze znany konkretny bug. (ang. bug - błąd w programie)
2.Kernel zawierający wspomnianego buga.
3.Odrobinę szczęścia.
Notka:
- Błąd którego maożemy sprowokować to więcej niż 50% sukcesu
- Wszystkie przykłady kodu pochodzą z wersji jądra 2.6.17.13(i386)
Funkcja printk()
printk() to bardzo użyteczna funkcja, podobna do printf(). Ta funkcja działa wszędzie i w każdym czasie (oprócz wczesnej fazy bootowania jądra gdy konsola nie jest jeszcze zainicjalizowana). Używa poziomów logowania (ang. loglevels) do powiadamiania konsoli o ważności poszczególnych wiadomości. Oto pełna lista poziomów:
1.KERN_EMERG <— najważniejsze (czyli praktycznie zawsze wyświetlane)
2.KERN_ALERT
3.KERN_CRIT
4.KERN_ERR
5.KERN_WARNING <— (standardowo dopiero ten poziom jest wyświetlany)
6.KERN_NOTICE
7.KERN_INFO
8.KERN_DEBUG <— najmniej ważne (standardowo nie wyświetlane)
Konsola wyświetli wiadomości jedynie z poziomem wyższym niż console_loglevel. Domyślnie printk używa DEFAULT_MESSAGE_LOGLEVEL==KERN_WARNING (może to ulec zmianie w przyszłości).
printk() używa cyklicznego bufora do zarządzania wiadomościami. Następnie klogd odczytuje wiadomości (używając /proc/kmsg) z bufora i przekazuje je do syslogd, który zapisuje je do pliku /var/log/messages. (Możesz konfigurować syslogd przez edytowanie pliku /etc/syslog.conf).
Przykłady:
printk(loglevel „messages”); Uwaga między wiadomością a poziomem logowania nie ma przecinka !!!
Źródło: Linux/arch/mips/sgi-ip27/ip27-berr.c
20 #if 1
321 printk("FIXME: disabling master aborts\n");
322 csrs->POx_MSK_HEI.csr &= ~(3UL << 14);
323 #endif
Błąd oops
Oops jest raportem buga zgłaszanym przez jądro. Gdy pojawia się błąd oops jądro wyświetli zawartość rejestrów i tzw. "back trace". Błąd oops nie musi oznaczać uszkodzenia systemu, a czasem system potrafi sam rozwiązać problem. Gdy system nie potrafi poradzić sobie z problemem, wyświetli komunikat kernel panic i przestanie działać. "Back trace" domyślnie będzie zawierał adresy wywołanych funkcji. Jeśli wkompilowałeś w jądro opcję CONFIG_KALLSYMS, błąd oops zostanie przetłumaczony i wyświetli nazwy funkcji, które go spowodowały. W serii jąder 2.4 możesz użyć ksymoops plik_z_treścią_oops.txt, w celu określenia nazw fukncji.
Dodatkowe opcje przy kompilacji
Te opcje są bardzo przydatne podczas debugowania jądra:
CONFIG_PREEMPT=y
CONFIG_DEBUG_KERNEL=y
CONFIG_KALLSYMS=y
CONFIG_SPINLOCK_SLEEP=y
CONFIG_MAGIC_SYSRQ=y
Powodowanie błędu oraz wyświetlanie dodatkowych informacji
Czasem możesz chcieć zobaczyć informacje oopsa na temat jakiegoś błędu. Użyj BUG() BUG_ON():
if(bad_thing)
BUG();
lub BUG_ON(bad_thing);
Przykłady:
Źródło: Linux/arch/arm/plat-omap/dma.c
732 if (omap_dma_in_1510_mode()) {
733 printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
734 BUG();
735 return;
736 }
1221 BUG_ON(lcd_dma.active);
1.Czasem możesz chcieć zobaczyć informacje z oops i zaraz zatrzymać system. Użyj panic(): if(terrible_error)
panic(„var = %ld \n”, var);
2.Czasem możesz chcieć zobaczyć stos. Użyj: dump_stack();
if(debug_check)
dump_stack();
Przykłady:
Źródło: Linux/arch/cris/arch-v32/kernel/dma.c
40 if (options & DMA_PANIC_ON_ERROR)
41 panic("request_dma error!");
Źródło: Linux/drivers/scsi/hosts.c
398 if (!sht->detect) {
399 printk(KERN_WARNING "scsi_register() called on new-style "
400 "template for driver %s\n", sht->name);
401 dump_stack();
402 }
Magic SysRq Key
Jeżeli ustawiłeś CONFIG_MAGIC_SYSRQ=y lub wpiszesz 'echo 1 > /proc/sys/kernel/sysrq', możesz używać SysRq Key (na PPC lub i386) 'Alt+PrintScreen'.
1.SysRq+b Restartuje komputer
2.SysRq+e Wysyła SIGTERM do wszystkich zadań (poza init!!!)
3.SysRq+h Pomoc
4.SysRq+l wysyła SIGKILL do wszystkich zadań (poza init!!!)
5.SysRq+k Zabija wszystkie zadania uruchomione z tej konsoli
6.SysRq+l wysyła SIGTKILL do wszystkich zadań (poza init!!!)
7.SysRq+m Obraz pamięci procesu zapisywany w sytuacji awaryjnej na dysku(http://en.wikipedia.org/wiki/Core_Dump) i wyświetla go w konsoli.
8.SysRq+o zatrzymuje system i wyłącza go
9.SysRq+p Wyświetla rejestry procesora w konsoli
10.SysRq+r Zmienia klawiaturę z RAW na XLATE
11.SysRq+s Zapisuje brudne bufory na twardym dysku
12.SysRq+t Pokazuje informacje o obecnym zadaniu w konsoli
13.SysRq+u Odmontowanie wszystkich plików systemowych i ponowne zamontowanie w trybie tylko do odczytu
Zauważ, że każdy (nawet niepowołany) użytkownik może używać powyższych kombinacji i mogę one nie działać odpowiednio na niestabilnym systemie.
Jak używać debuggerów?
Zanim zaczną o nich opowiadać musisz wiedzieć jedną rzecz. Linus nie daje pozwolenia na używanie debuggerów, ponieważ nie zawsze pokazuję prawdziwe informacje.
gdb
gdb vmlinux /proc/kcore <—> vmlinux to skompresowany obraz jądra (poszukaj go w głównym katalogu źródeł kernela) /proc/kcore pozwala gdb obserwować pamięć Linuksa
http://sourceware.org/gdb/current/onlinedocs/gdb_toc.html <— dokumentacja dla gdb
+ prosty w użyciu
- nie możesz dokonywać zmian w danych działającego jądra
kgdb
kgdb jest paczem dla jądra pozwalającą Ci na połączenie dwóch komputerów, jeden z kgdb i drugi z gdb
+ możesz modyfikować dane i zmienne
- musisz skonfigurować połączenie
http://kgdb.linsyssoft.com/
kdb
kdb jest jest podobny do kgdb ale wszystko odbywa się na jednym komputerze.
Różne sztuczki które umilają życie
Powiązanie kodu z wartością UID
Wykonywanie eksperymentalnego kodu można powiązać z UID'em użytkownika:
if(current->uid == 7777) {
/* eksperymentalny kod */
}else {
/* start stabilny kod */
Kod eksperymentalny uaktywni się[++ będzie dostępny++] tylko dla użytkownika o UID = 7777. Reszta użytkowników może spać spokojne ;) .
Prowadzenie statystyk
Czasami gdy do analizy danego błędu jest potrzebna wiedza o częstotliwości występowania jakiegoś zdarzenia wystarczy zadeklarować zmienną (typ int zwykle wystarczy) i zwiększać ją przy każdym zdarzeniu. A dane przesyłać do jakiegoś pliku w /proc lub przez wywołanie systemowe, w ostateczności możne przeglądać jego wartość przez debuggera. Trzeba jednak pamiętać, że aby w środowisku wieloprocesorowym/wielowątkowym zapewnić odpowiednią ochronę zmiennych liczników.
Przeszukiwanie binarne
Służy do szukania wersji kernela w której pojawił się błąd. Bierzemy 2 wersje z błędem i bez błędu (np.2.6.8 <- bez błędu i 2.6.19 <- z błędem) i wybieramy kernela który znajduję się po środku (czyli 2.6.13) i sprawdzamy czy i w nim występuje błąd. Jeżeli nie to błąd pojawił się w nowsze połówce (od 2.6.13) jeżeli jednak środkowa wersja posiada błąd to błąd pojawił się w starszej połówce (od 2.6.8 do 2.6.13). Po otrzymaniu połówki znowu bierzemy środkowy element (dla 2.6.8 i 2.6.13 będzie to 2.6.10) i znowu sprawdzamy czy jest to wersja z błędem czy bez. I tak w kółko aż znajdziemy to pierwszą błędną wersję.
Gdy wszystko się sypnie
Nikt nie lubi bugów. Więc gdy spędzasz godziny/dni na poprawianiu bugów, możesz wysłać krótki i opisowy e-mail zawierający wszystkie informacje, które udało Ci się zebrać i wysłać je do LKML. Powodzenia w polowaniu na bugi!