C语言 如何在内核模块代码中包含 C 回溯?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5863122/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:33:13  来源:igfitidea点击:

How to include C backtrace in a kernel module code?

clinux-device-driverkernelbacktrace

提问by ndasusers

So I am trying to find out what kernel processes are calling some functions in a block driver. I thought including backtrace() in the C library would make it easy. But I am having trouble to load the backtrace.

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

I copied this example function to show the backtrace:

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

http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/063/6391/6391l1.html

http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/063/6391/6391l1.html

All attempts to compile have error in one place or another that a file cannot be found or that the functions are not defined.

所有编译尝试都在一处或另一处出现错误,即找不到文件或未定义函数。

Here is what comes closest.

这是最接近的。

In the Makefile I put the compiler directives:

在 Makefile 中,我放置了编译器指令:

 -rdynamic -I/usr/include 

If I leave out the second one, -I/usr/include, then the compiler reports it cannot find the required header execinfo.h.

如果我省略了第二个 -I/usr/include,那么编译器会报告它找不到所需的头文件 execinfo.h。

Next, in the code where I want to do the backtrace I have copied the function from the example:

接下来,在我想要进行回溯的代码中,我从示例中复制了函数:

//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

I have put the call to this function later on, in a block driver function where the first sign of the error happens. Simply:

我稍后在块驱动程序函数中调用了此函数,在该函数中出现了错误的第一个迹象。简单地:

show_stackframe();

So when I compile it, the following errors:

所以当我编译它时,出现以下错误:

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!

Note: block26.c is the file I am hoping to get the backtrace from.

注意:block26.c 是我希望从中获取回溯的文件。

Is there an obvious reason why the backtrace and backtrace_symbols remain undefined when it is compiled into the .ko modules?

当 backtrace 和 backtrace_symbols 被编译到 .ko 模块中时,是否有明显的原因?

I am guessing it because I use the compiler include execinfo.h which is residing on the computer and not being loaded to the module.

我猜是因为我使用编译器 include execinfo.h 它驻留在计算机上并且没有加载到模块中。

It is my uneducated guess to say the least.

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

Can anyone offer a help to get the backtrace functions loading up in the module?

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

Thanks for looking at this inquiry.

感谢您查看此查询。

I am working on debian. When I take out the function and such, the module compiles fine and almost works perfectly.

我在 debian 上工作。当我取出函数等时,模块编译得很好,几乎可以完美运行。

From ndasusers

来自 ndasusers

回答by jmkeyes

To print the stack contents and a backtrace to the kernel log, use the dump_stack()function in your kernel module. It's declared in linux/kernel.hin the include folder in the kernel source directory.

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

回答by Eugene

If you need to save the stack trace and process its elements somehow, save_stack_trace()or dump_trace()might be also an option. These functions are declared in <linux/stacktrace.h>and <asm/stacktrace.h>, respectively.

如果您需要保存堆栈跟踪并以某种方式处理其元素,save_stack_trace()或者dump_trace()也可能是一个选项。这些函数分别在<linux/stacktrace.h>和中声明<asm/stacktrace.h>

It is not as easy to use these as dump_stack()but if you need more flexibility, they may be helpful.

使用这些并不容易,dump_stack()但如果您需要更大的灵活性,它们可能会有所帮助。

Here is how save_stack_trace()can be used (replace HOW_MANY_ENTRIES_TO_STOREwith the value that suits your needs, 16-32 is usually more than enough):

以下是如何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);

Now stack_entriesarray contains the appropriate call addresses. The number of elements filled is nr_entries.

现在stack_entries数组包含适当的调用地址。填充的元素数为nr_entries

One more thing to point out. If it is desirable not to output the stack entries that belong to the implementation of save_stack_trace(), dump_trace()or dump_stack()themselves (on different systems, the number of such entries may vary), the following trick can be applied if you use save_stack_trace(). You can use __builtin_return_address(0)as an "anchor" entry and process only the entries "not lower" than that.

还有一件事要指出。如果希望不输出属于的执行堆栈条目save_stack_trace()dump_trace()dump_stack()本身(在不同的系统中,这样的条目的数量可以变化),下面特技可以如果使用被应用save_stack_trace()。您可以将其__builtin_return_address(0)用作“锚”条目并仅处理“不低于”该条目的条目。

回答by cnst

I know this question is about Linux, but since it's the first result for "backtrace kernel", here's a few more solutions:

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



DragonFly BSD

蜻蜓 BSD

It's print_backtrace(int count)from /sys/sys/systm.h. It's implemented in /sys/kern/kern_debug.cand/or /sys/platform/pc64/x86_64/db_trace.c. It can be found by searching for panic, which is implemented in /sys/kern/kern_shutdown.c, and calls print_backtrace(6)if DDBis defined and trace_on_panicis set, which are both defaults.

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)ifDDB已定义和trace_on_panic已设置,这两个都是默认值。



FreeBSD

FreeBSD

It's kdb_backtrace(void)from /sys/sys/kdb.h. Likewise, it's easy to find by looking into what the panicimplementation calls when trace_on_panicis true.

kdb_backtrace(void)来自/sys/sys/kdb.h. 同样,通过查看panic实现调用 whentrace_on_panic为 true很容易找到。



OpenBSD

开放式BSD

Going the panicroute, it appears to be db_stack_dump(), implemented in /sys/ddb/db_output.c. The only header mention is /sys/ddb/db_output.h.

走这panic条路线,它似乎是db_stack_dump()/sys/ddb/db_output.c. 唯一提到的标题是/sys/ddb/db_output.h.

回答by SHASHI BHUSAN

dump_stack()is function can be used to print your stack and thus can be used to backtrack . while using it be carefull that don't put it in repetitive path like loops or packet receive function it can fill your dmesg buffer can cause crash in embedded device (having less memory and cpu).

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

This function is declared in linux/kernel.h.

该函数在 linux/kernel.h.