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

ndasusers
  • 1,131
  • 2
  • 10
  • 6
  • 2
    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]: http://www.xml.com/ldd/chapter/book/ch04.html#t5 – zdav May 02 '11 at 22:37
  • 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. – ndasusers May 02 '11 at 23:44
  • Unlike user-space programs, the kernel is not linked against the standard C library (or any other library, for that matter). http://kernelnewbies.org/FAQ/LibraryFunctionsInKernel – jschmier May 03 '11 at 18:21
  • 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. – ndasusers May 07 '11 at 04:46

4 Answers4

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.

jmkeyes
  • 3,751
  • 17
  • 20
  • 1
    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. – ndasusers May 07 '11 at 04:45
  • 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. – jmkeyes May 07 '11 at 04:55
22

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.

Eugene
  • 5,977
  • 2
  • 29
  • 46
  • Thank you for helping. I did not use this trick, but I might. The stack_dump showed about all I imagined. – ndasusers May 07 '11 at 04:48
  • 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? – René Nyffenegger Feb 27 '18 at 12:07
  • @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. – Eugene Feb 27 '18 at 15:42
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 .

SHASHI BHUSAN
  • 612
  • 6
  • 12
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.

cnst
  • 25,870
  • 6
  • 90
  • 122