"?" 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.
Ś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
Edytowałem swoją odpowiedź. Mam nadzieję, że moje wyjaśnienie nie jest zbyt mylące. – Eugene
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