'?' означает, что информация об этой записи стека, вероятно, ненадежна.
Механизм вывода стека (см. реализацию функции dump_trace()) не смог доказать, что найденный адрес является действительным адресом возврата в стеке вызовов.
'?' сам выводится с помощью printk_stack_address().
Запись стека может быть действительной или нет. Иногда его можно просто пропустить. Может быть полезно исследовать дизассемблированный задействованный модуль, чтобы увидеть, какая функция вызывается в ClearFunctionName+0x88
(или, в x86, непосредственно перед этой позицией).
Надежность
В x86 при вызове dump_stack() функция, которая фактически проверяет стек, — это print_context_stack() определено в arch/x86/kernel/dumpstack.c
. Взгляните на его код, я попытаюсь объяснить его ниже.
Я предполагаю, что средства раскрутки стека DWARF2 недоступны в вашей системе Linux (скорее всего, их нет, если это не OpenSUSE или SLES). В этом случае print_context_stack()
, кажется, делает следующее.
Он начинается с адреса (переменная «стек» в коде), который гарантированно является адресом расположения стека. На самом деле это адрес локальной переменной в dump_stack()
.
Функция многократно увеличивает этот адрес (while (valid_stack_ptr ...) { ... stack++}
) и проверяет, может ли то, на что он указывает, также быть адресом в коде ядра (if (__kernel_text_address(addr)) ...
). Таким образом он пытается найти адреса возврата функций, помещаемые в стек при вызове этих функций.
Конечно, не всякое длинное значение без знака, которое выглядит как адрес возврата, на самом деле является адресом возврата. Поэтому функция пытается это проверить. Если в коде ядра используются указатели кадров (для этого используются регистры %ebp/%rbp, если установлен CONFIG_FRAME_POINTER), их можно использовать для обхода кадров стека функций. Адрес возврата для функции находится чуть выше указателя фрейма (т.е. в %ebp/%rbp + sizeof(unsigned long)
). print_context_stack проверяет именно это.
Если есть кадр стека, для которого значение 'stack' указывает на адрес возврата, это значение считается надежной записью стека. ops->address
будет вызван для него с reliable == 1
, в конечном итоге он вызовет printk_stack_address()
, и значение будет выведено как надежная запись стека вызовов. В противном случае адрес будет считаться недостоверным. Он будет выводиться в любом случае, но с '?' добавлено.
[NB] Если информация об указателе фрейма недоступна (например, как это было в Debian 6 по умолчанию), по этой причине все записи стека вызовов будут помечены как ненадежные.
Системы с поддержкой раскручивания DWARF2 (и с установленным CONFIG_STACK_UNWIND) — это совсем другая история.
person
Eugene
schedule
29.10.2012