web-dev-qa-db-ja.com

カーネルモジュールコードにCバックトレースを含める方法は?

だから私は、どのカーネルプロセスがブロックドライバーのいくつかの関数を呼び出しているのかを調べようとしています。 Cライブラリにbacktrace()を含めると簡単になると思いました。しかし、バックトレースを読み込めません。

この例の関数をコピーして、バックトレースを表示します。

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

コンパイルしようとすると、どこかでエラーが発生し、ファイルが見つからないか、関数が定義されていません。

これが最も近いものです。

Makefileにコンパイラディレクティブを追加します。

 -rdynamic -I/usr/include 

2番目の-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は、バックトレースを取得したいファイルです。

.koモジュールにコンパイルされるときにbacktraceとbacktrace_symbolsが未定義のままである明らかな理由はありますか?

私はそれを推測しているのは、コンピューターに常駐し、モジュールにロードされていないexecinfo.hを含むコンパイラーを使用しているためです。

控えめに言ってもそれは私の教育を受けていない推測です。

誰かがモジュールにバックトレース機能をロードするための助けを提供できますか?

お問い合わせいただきありがとうございます。

私はdebianに取り組んでいます。関数などを取り出すと、モジュールは正常にコンパイルされ、ほぼ完全に動作します。

Ndasusersから

24
ndasusers

スタックの内容とバックトレースをカーネルログに出力するには、カーネルモジュールでdump_stack()関数を使用します。カーネルソースディレクトリのインクルードフォルダーのlinux/kernel.hで宣言されています。

50
jmkeyes

スタックトレースを保存してその要素を何らかの方法で処理する必要がある場合は、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_です。

もう1つ指摘しておきます。 save_stack_trace()dump_trace()、またはdump_stack()自体の実装に属するスタックエントリを出力しないことが望ましい場合(異なるシステムでは、そのようなエントリの数異なる場合があります)、save_stack_trace()を使用すると、次のトリックを適用できます。 __builtin_return_address(0)を「アンカー」エントリとして使用し、それより「低くない」エントリのみを処理できます。

21
Eugene

dump_stack()は、スタックを印刷するために使用できるため、バックトラックするために使用できます。使用中は、ループやパケット受信機能などの反復的なパスに配置しないように注意してください。dmesgバッファーがいっぱいになると、組み込みデバイスでクラッシュが発生する可能性があります(メモリとCPUが少ない)。

この関数はlinux/kernel.hで宣言されています。

0
SHASHI BHUSAN

私はこの質問がLinuxに関するものであることを知っていますが、これは「バックトレースカーネル」の最初の結果なので、さらにいくつかの解決策があります。


DragonFly BSD

/sys/sys/systm.h からのprint_backtrace(int count)です。 /sys/kern/kern_debug.c/sys/platform/pc64/x86_64/db_trace.c で実装されています。これは、 /sys/kern/kern_shutdown.c に実装されているpanicを検索して見つけることができ、DDBが定義されていて、trace_on_panicが設定されている場合はprint_backtrace(6)を呼び出します。


FreeBSD

/sys/sys/kdb.h からのkdb_backtrace(void)です。同様に、trace_on_panicがtrueのときに panic 実装が何を呼び出すかを調べることで簡単に見つけることができます。


OpenBSD

panic ルートに行くと、それは db_stack_dump()のように見え、/sys/ddb/db_output.c に実装されています。ヘッダーの言及は /sys/ddb/db_output.h のみです。

0
cnst