How to include C backtrace in a kernel module code?
Asked Answered
B

4

29

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.

I copied this example function to show the backtrace:

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:

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

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.

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

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.

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.

From ndasusers

Boraginaceous answered 2/5, 2011 at 22:21 Comment(4)
I'm not so sure you are suppose to include libraries like this in kernel module code. Have you tried just using gdb and setting a break point? [1] [1]: xml.com/ldd/chapter/book/ch04.html#t5Diaphysis
Oh Rats! I was scared to hear something like that. This looks like useful chapter that you have linked me to though. Thanks for that.Boraginaceous
Unlike user-space programs, the kernel is not linked against the standard C library (or any other library, for that matter). kernelnewbies.org/FAQ/LibraryFunctionsInKernelTubby
Now that I understand, it makes complete sense. How can a kernel be expected to use many libraries that may not even exist on a system.Boraginaceous
C
52

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.h in the include folder in the kernel source directory.

Counterfeit answered 3/5, 2011 at 6:34 Comment(2)
Thank you.This is the thing I expected to do with the c backtrace. now I just need a new post to help read it.Boraginaceous
The values displayed are in two blocks: the first is the raw contents of the stack shown by address, and the second shows each stack frame like a regular backtrace.Counterfeit
W
23

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.

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

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

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_entries array contains the appropriate call addresses. The number of elements filled is 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.

Worry answered 3/5, 2011 at 12:47 Comment(3)
Thank you for helping. I did not use this trick, but I might. The stack_dump showed about all I imagined.Boraginaceous
I am able to find addresses with this method, but these addresses don't seem to match any address in System.map. So, how can I turn such an address into a function name?Erythroblast
@RenéNyffenegger: KASLR is active, I suppose (CONFIG_RANDOMIZE_BASE=y). This might be the reason the real addresses are different from what is in System.map. If /proc/kallsyms is available in your system, you can find the addresses there. Or, if you call save_stack_trace from your module, you can use printk with %pS specifier there to resolve the function names and offsets. Again, KALLSYMS should be enabled in the kernel for this to work.Worry
Z
3

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).

This function is declared in linux/kernel.h .

Zambrano answered 13/4, 2018 at 19:40 Comment(0)
B
2

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


DragonFly BSD

It's print_backtrace(int count) from /sys/sys/systm.h. It's implemented in /sys/kern/kern_debug.c and/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 DDB is defined and trace_on_panic is set, which are both defaults.


FreeBSD

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


OpenBSD

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

Bronze answered 25/2, 2018 at 2:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.