Как включить C backtrace в код модуля ядра? - PullRequest
24 голосов
/ 03 мая 2011

Итак, я пытаюсь выяснить, какие процессы ядра вызывают некоторые функции в драйвере блока. Я думал, что включение 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 ]

48 голосов
/ 03 мая 2011

Чтобы напечатать содержимое стека и обратную трассировку в журнал ядра, используйте функцию dump_stack() в модуле ядра. Он объявлен в linux/kernel.h в папке include в исходном каталоге ядра.

19 голосов
/ 03 мая 2011

Если вам нужно сохранить трассировку стека и каким-либо образом обработать ее элементы, возможно, вам также подойдет 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) как «якорную» запись и обрабатывать только записи «не ниже».

0 голосов
/ 13 апреля 2018

dump_stack() - это функция, которая может использоваться для печати вашего стека и, следовательно, может использоваться для возврата. при его использовании будьте осторожны, не помещайте его в повторяющиеся пути, такие как циклы или функция приема пакетов, он может заполнить буфер dmesg и вызвать сбой во встроенном устройстве (с меньшим объемом памяти и процессором).

Эта функция объявлена ​​в linux/kernel.h.

0 голосов
/ 25 февраля 2018

Я знаю, что этот вопрос касается 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 имеет значение true.


OpenBSD

По маршруту panic это выглядит как db_stack_dump(), реализовано в /sys/ddb/db_output.c. Единственное упоминание заголовка: /sys/ddb/db_output.h.

...