如何在内核模块代码中包含C backtrace?

时间:2011-05-02 22:21:51

标签: c linux-device-driver kernel backtrace

所以我试图找出哪些内核进程正在调用块驱动程序中的某些函数。我认为在C库中包含backtrace()可以让它变得简单。但是我无法加载回溯。

我复制了这个示例函数来显示回溯:

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模块时,是否有明显的原因可以保持未定义?

我猜它是因为我使用编译器包含execinfo.h,它驻留在计算机上而不是加载到模块中。

至少可以说,这是我没有受过教育的猜测。

任何人都可以提供帮助,以便在模块中加载回溯功能吗?

感谢您查看此查询。

我正在研究debian。当我取出这样的功能时,模块编译得很好并且几乎完美地工作。

来自ndasusers

4 个答案:

答案 0 :(得分:48)

要将堆栈内容和回溯打印到内核日志,请使用内核模块中的dump_stack()函数。它在linux/kernel.h中在内核源目录的include文件夹中声明。

答案 1 :(得分:19)

如果您需要保存堆栈跟踪并以某种方式处理其元素,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)作为“锚点”条目,并仅处理“不低于”的条目。

答案 2 :(得分:0)

我知道这个问题是关于Linux的,但由于它是&#34;回溯内核&#34;的第一个结果,这里还有一些解决方案:

DragonFly BSD

来自/sys/sys/systm.hprint_backtrace(int count)。它已在中实施 /sys/kern/kern_debug.c和/或/sys/platform/pc64/x86_64/db_trace.c。可以通过搜索在/sys/kern/kern_shutdown.c中实施的panic来找到它,如果定义了print_backtrace(6)并且设置了DDB则调用trace_on_panic,这两者都是默认值。

的FreeBSD

来自/sys/sys/kdb.hkdb_backtrace(void)。同样,通过查看trace_on_panic实现在{{1}}为真时调用的内容,可以轻松找到它。

的OpenBSD

转到panic路线,似乎是panic。唯一标题提及是db_stack_dump(), implemented in /sys/ddb/db_output.c

答案 3 :(得分:0)

dump_stack()函数可用于打印堆栈,因此可用于回溯。使用它时要小心,不要把它放在像循环或数据包接收功能这样的重复路径中,它可以填满你的dmesg缓冲区,可能导致嵌入式设备崩溃(内存和cpu较少)。

此功能在linux/kernel.h中声明。