Как включить C backtrace в код модуля ядра?
Поэтому я пытаюсь выяснить, какие процессы ядра вызывают некоторые функции в драйвере блока. Я думал, что включение backtrace() в библиотеку C сделает это легко. Но у меня проблемы с загрузкой трассировки.
Я скопировал этот пример функции, чтобы показать обратную трассировку:
http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/063/6391/6391l1.html
Все попытки компиляции приводят к ошибке в том или ином месте, что файл не может быть найден или функции не определены.
Вот что ближе всего.
В Makefile я поместил директивы компилятора:
-rdynamic -I/usr/include
Если я пропущу второй, -I/usr/include, то компилятор сообщит, что не может найти требуемый заголовок execinfo.h.
Далее, в коде, где я хочу сделать обратную трассировку, я скопировал функцию из примера:
//trying to include the c backtrace capability
#include <execinfo.h>
void show_stackframe() {
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
messages = backtrace_symbols(trace, trace_size);
printk(KERN_ERR "[bt] Execution path:\n");
for (i=0; i<trace_size; ++i)
printk(KERN_ERR "[bt] %s\n", messages[i]);
}
//backtrace function
Позже я поместил вызов этой функции в функцию драйвера блока, где происходит первый признак ошибки. Просто:
show_stackframe();
Поэтому, когда я его компилирую, появляются следующие ошибки:
user@slinux:~/2.6-32$ make -s
Invoking make againt the kernel at /lib/modules/2.6.32-5-686/build
In file included from /usr/include/features.h:346,
from /usr/include/execinfo.h:22,
from /home/linux/2.6-32/block/block26.c:49:
/usr/include/sys/cdefs.h:287:1: warning: "__always_inline" redefined
In file included from /usr/src/linux-headers-2.6.32-5-common/include/linux/compiler-gcc.h:86,
from /usr/src/linux-headers-2.6.32-5-common/include/linux/compiler.h:40,
from /usr/src/linux-headers-2.6.32-5-common/include/linux/stddef.h:4,
from /usr/src/linux-headers-2.6.32-5-common/include/linux/list.h:4,
from /usr/src/linux-headers-2.6.32-5-common/include/linux/module.h:9,
from /home/linux/2.6-32/inc/linux_ver.h:40,
from /home/linux/2.6-32/block/block26.c:32:
/usr/src/linux-headers-2.6.32-5-common/include/linux/compiler-gcc4.h:15:1: warning: this is the location of the previous definition
/home/linux/2.6-32/block/block26.c:50: warning: function declaration isn’t a prototype
WARNING: "backtrace" [/home/linux/2.6-32/ndas_block.ko] undefined!
WARNING: "backtrace_symbols" [/home/linux/2.6-32/ndas_block.ko] undefined!
Примечание: block26.c - это файл, от которого я надеюсь получить обратную трассировку.
Есть ли очевидная причина, по которой backtrace и backtrace_symbols остаются неопределенными, когда они компилируются в модули.ko?
Я предполагаю это, потому что я использую компилятор include execinfo.h, который находится на компьютере и не загружается в модуль.
Это мое необразованное предположение, если не сказать больше.
Может кто-нибудь предложить помощь для загрузки функций обратного отслеживания в модуле?
Спасибо за просмотр этого запроса.
Я работаю над Debian. Когда я вынимаю функцию и тому подобное, модуль прекрасно компилируется и почти отлично работает.
От ndasusers
4 ответа
Чтобы напечатать содержимое стека и обратную трассировку в журнал ядра, используйте dump_stack()
функция в вашем модуле ядра. Это объявлено в linux/kernel.h
в папке include в исходном каталоге ядра.
Если вам нужно сохранить трассировку стека и как-то обработать его элементы, save_stack_trace()
или же dump_trace()
может быть также вариант. Эти функции объявлены в <linux/stacktrace.h>
а также <asm/stacktrace.h>
соответственно.
Это не так легко использовать, как dump_stack()
но если вам нужна большая гибкость, они могут быть полезны.
Вот как save_stack_trace()
можно использовать (заменить HOW_MANY_ENTRIES_TO_STORE
при значении, которое соответствует вашим потребностям, 16-32 обычно более чем достаточно):
unsigned long stack_entries[HOW_MANY_ENTRIES_TO_STORE];
struct stack_trace trace = {
.nr_entries = 0,
.entries = &stack_entries[0],
.max_entries = HOW_MANY_ENTRIES_TO_STORE,
/* How many "lower entries" to skip. */
.skip = 0
};
save_stack_trace(&trace);
Сейчас stack_entries
Массив содержит соответствующие адреса вызовов. Количество заполненных элементов: nr_entries
,
Еще одна вещь, чтобы указать. Если желательно не выводить записи стека, которые принадлежат реализации save_stack_trace()
, dump_trace()
или же dump_stack()
сами (в разных системах число таких записей может отличаться), если вы используете save_stack_trace()
, Ты можешь использовать __builtin_return_address(0)
в качестве "якорной" записи и обрабатывать только записи "не ниже".
dump_stack()
Функция is может использоваться для печати вашего стека и, следовательно, может использоваться для возврата. при его использовании будьте осторожны, так как не помещайте его в повторяющиеся пути, такие как циклы или функция приема пакетов, он может заполнить ваш буфер dmesg, что может привести к сбою во встроенном устройстве (с меньшим объемом памяти и процессора).
Эта функция объявлена в linux/kernel.h
,
Я знаю, что этот вопрос касается Linux, но, поскольку это первый результат для "backtrace kernel", вот еще несколько решений:
DragonFly BSD
Это print_backtrace(int count)
от /sys/sys/systm.h
, Это реализовано в /sys/kern/kern_debug.c
и / или /sys/platform/pc64/x86_64/db_trace.c
, Это можно найти, выполнив поиск panic
, который реализован в /sys/kern/kern_shutdown.c
и звонки print_backtrace(6)
если DDB
определяется и trace_on_panic
установлено, которые оба по умолчанию.
FreeBSD
Это kdb_backtrace(void)
от /sys/sys/kdb.h
, Кроме того, это легко найти, посмотрев в то, что panic
вызовы реализации, когда trace_on_panic
правда.
OpenBSD
Собираюсь panic
маршрут, кажется, db_stack_dump()
, реализованный в /sys/ddb/db_output.c
, Единственное упоминание заголовка /sys/ddb/db_output.h
,