web-dev-qa-db-ja.com

カーネルモジュールのaddr2line

カーネルモジュールをデバッグしようとしています。メモリリークがあるのではないかと思います。それを確認するために、カーネルとモジュールのメモリリークデバッグを有効にしてビルドを準備しました。そして、私はそれからいくつかの警告を受けました:

[11839.429168] slab error in verify_redzone_free(): cache `size-64': memory outside object was overwritten
[11839.438659] [<c005575c>] (unwind_backtrace+0x0/0x164) from [<c0116ca0>] (kfree+0x278/0x4d8)
[11839.447357] [<c0116ca0>] (kfree+0x278/0x4d8) from [<bf083f48>] (some_function+0x18/0x1c [my_module])
[11839.457214] [<bf083f48>] (some_function+0x18/0x1c [my_module]) from [<bf08762c>] (some_function+0x174/0x718 [my_module])
[11839.470184] [<bf08762c>] (some_function+0x174/0x718 [my_module]) from [<bf0a56b8>] (some_function+0x12c/0x16c [my_module])
[11839.483917] [<bf0a56b8>] (some_function+0x12c/0x16c [my_module]) from [<bf085790>] (some_function+0x8/0x10 [my_module])
[11839.496368] [<bf085790>] (some_function+0x8/0x10 [my_module]) from [<bf07b74c>] (some_function+0x358/0x6d4 [my_module])
[11839.507476] [<bf07b74c>] (some_function+0x358/0x6d4 [my_module]) from [<c00a60f8>] (worker_thread+0x1e8/0x284)
[11839.517211] [<c00a60f8>] (worker_thread+0x1e8/0x284) from [<c00a9edc>] (kthread+0x78/0x80)
[11839.525543] [<c00a9edc>] (kthread+0x78/0x80) from [<c004f8fc>] (kernel_thread_exit+0x0/0x8)

カーネルを指すアドレスを変換するのに問題はありません。

$ addr2line -f -e vmlinux.kmeml c0116ca0
verify_redzone_free
/[...]/kernel/mm/slab.c:2922

しかし、アドレスがmy_moduleからのものである場合、それはできません。

$ addr2line -f -e vmlinux.kmeml bf0a56b8
??
??:0

私もモジュールファイルで試していました:

$ addr2line -f -e my_module.ko bf0a56b8
??
??:0

このアドレスをファイルと行番号に変換するにはどうすればよいですか?

26
Adam

モジュールはデバッグ情報が含まれて構築されていると思います。その場合は、gdbまたはobjdumpを使用して、各アドレスが属するソースファイルと行を見つけることができます。このようなもの:

$ gdb "$(modinfo -n my_module)"
(gdb) list *(some_function+0x12c)

Gdbは、ソースファイルの名前とその中の行を通知します。

Objdumpでも同様のことができますが、少し難しいです。まず、モジュールを分解します。

objdump -dSlr my_module.ko > my_module.disasm

-Sオプションを指定して呼び出されると、objdumpは、必要に応じて、結果のリストにソース行を含めます。

これで、リストをsome_functionのコードまでスクロールダウンし、関数の先頭からオフセット0x12cにある命令を見つけることができます。ソースラインはその上に表示されます。

編集:

多くの実験の結果、addr2lineは実際にカーネルモジュールに使用できますが、eu-addr2line(elfutilsの同様のツール)の方が信頼性が高いようです。つまり、addr2lineが誤ったソース行を出力することがありますが、eu-add2lineは正しく機能しました。

eu-addr2lineを使用するには、libdwおよびlibeblライブラリがelfutilsと一緒にまだインストールされていない場合、それらをインストールする必要がある場合があります。

使用法はaddr2lineの使用法と似ています。

eu-addr2line -f -e <path_to_the_module> -j <section_name> <offset_in_section>

カーネルモジュールのデバッグ情報が別のファイルに保存されている場合(これは、主要なLinuxディストリビューションによって提供されるカーネルの場合によくあることです)、そのファイルへのパスは<path_to_the_module>として使用する必要があります。

28
Eugene

確かに、カーネルではなくカーネルモジュールでaddr2lineを実行する必要がありますが、ひねりがあります-

カーネルモジュールファイルは相対アドレスを使用します。クラッシュアドレスは実際には次のもので構成されています。

モジュール内のオフセット+モジュールのロードアドレスはメモリです。

したがって、必要なことは、cat/proc/modulesを実行して、カーネルmoduelロードアドレスが最初にメモリであることを確認し、そのアドレスがどのモジュールに属しているかを確認することです。わからない場合は、クラッシュアドレスからモジュールロードアドレスを減算します。それをaddr2lineにフィードします

幸運を

8
gby