2012-10-28 9 views

Odpowiedz

27

"?" oznacza, że ​​informacje o tym wpisie stosu prawdopodobnie nie są wiarygodne.

Mechanizm wyjściowy stosu (zobacz implementację dump_trace() function) nie był w stanie dowieść, że znaleziony adres jest poprawnym adresem zwrotnym w stosie wywołań.

"?" samo jest wyprowadzane przez printk_stack_address().

Pozycja stosu może być ważna lub nie. Czasami można po prostu go pominąć. Pomocne może być zbadanie dezasemblacji zaangażowanego modułu, aby sprawdzić, która funkcja jest wywoływana pod adresem ClearFunctionName+0x88 (lub, na x86, bezpośrednio przed tą pozycją).

chodzi o niezawodność

Na x86, gdy dump_stack() jest wywoływana funkcja faktycznie bada stos jest print_context_stack() zdefiniowany w arch/x86/kernel/dumpstack.c. Rzuć okiem na jego kod, spróbuję wyjaśnić to poniżej.

Zakładam, że funkcje rozwijania stosów DWARF2 nie są dostępne w systemie Linux (najprawdopodobniej nie są, jeśli nie jest to OpenSUSE lub SLES). W tym przypadku wydaje się, że print_context_stack() wykonuje następujące czynności.

Rozpoczyna się od adresu (zmienna "stos" w kodzie), który jest gwarantowany jako adres położenia stosu. W rzeczywistości jest to adres zmiennej lokalnej w dump_stack().

Funkcja wielokrotnie zwiększa ten adres (while (valid_stack_ptr ...) { ... stack++}) i sprawdza, czy wskazuje na adres w kodzie jądra (if (__kernel_text_address(addr)) ...). W ten sposób próbuje znaleźć adresy zwrotne funkcji wciśnięte na stos, gdy te funkcje zostały wywołane.

Oczywiście nie każda niepodpisana długa wartość, która wygląda jak adres zwrotny, jest w rzeczywistości adresem zwrotnym. Funkcja próbuje to sprawdzić. Jeśli w kodzie jądra używane są wskaźniki klatek (% ebp /% rbp używane są do tego, jeśli ustawiono CONFIG_FRAME_POINTER), mogą one służyć do przechodzenia między ramkami stosów funkcji. Adres zwrotny dla funkcji leży tuż nad wskaźnikiem ramki (to jest %ebp/%rbp + sizeof(unsigned long)). print_context_stack sprawdza dokładnie to.

Jeśli istnieje ramka stosu, dla której wartość "stos" wskazuje na adres zwrotny, wartość jest uważana za niezawodny wpis stosu. ops->address zostanie wywołany z numerem reliable == 1, w końcu zadzwoni pod numer printk_stack_address(), a wartość zostanie wyprowadzona jako niezawodny wpis stosu wywołań. W przeciwnym razie adres będzie uznany za niewiarygodny. Mimo to będzie to wyjście, ale z "?" przedawnione.

[Uwaga] Jeżeli informacje o wskaźniku ramki nie są dostępne (np. Jak było domyślnie w systemie Debian 6), wszystkie wpisy stosu wywołań będą oznaczone jako niewiarygodne z tego powodu.

Systemy z obsługą rozwijania DWARF2 (i zestawem CONFIG_STACK_UNWIND) to zupełnie inna historia.

+0

Świetna odpowiedź - brakuje jej jednej rzeczy, aby była kompletna (i jestem nieco zakłopotany poziomem pośredniej w kodzie arch) - co sprawia, że ​​wejście jest niewiarygodne? – qdot

+0

Edytowałem swoją odpowiedź. Mam nadzieję, że moje wyjaśnienie nie jest zbyt mylące. – Eugene

+0

Jak się tam dostać :) Twoja odpowiedź faktycznie potwierdza niektóre z moich podejrzeń co do sposobu działania - podać trochę informacji podstawowych, próbuję zaktualizować binarne blob + opakowanie jak sterownik - więc kernel jest w rzeczywistości moją własną kompilacją ... Powodem, dla którego się zdezorientowałem i chciałem wyjaśnić, jest to, że niektóre funkcje w funkcjach funkcji BLOB przechowują w zmiennych lokalnych, wyrzucając cały system. Zakończ całą "całą historię" - szczególnie, jak to działa, gdy głównym jądrem jest DWARF2, ale część modułu nie jest. – qdot