web-dev-qa-db-ja.com

カーネルoopsでアドレスを解釈する方法

私が書いたLinuxデバイスドライバーにカーネルoopsがあります。どの行がおっとの原因であるかを判断したいと思います。次の出力がありますが、解釈方法がわかりません。

Write_func + 0x63の命令でコードがクラッシュしたということですか? EIPの値を自分の関数に関連付けるにはどうすればよいですか?バックスラッシュの後の値はどういう意味ですか?

[10991.880354] BUG: unable to handle kernel NULL pointer dereference at   (null)
[10991.880359] IP: [<c06969d4>] iret_exc+0x7d0/0xa59
[10991.880365] *pdpt = 000000002258a001 *pde = 0000000000000000
[10991.880368] Oops: 0002 [#1] PREEMPT SMP
[10991.880371] last sysfs file: /sys/devices/platform/coretemp.3/temp1_input
[10991.880374] Modules linked in: nfs lockd fscache nfs_acl auth_rpcgss sunrpc   hdrdmod(F) coretemp(F) af_packet Fuse edd cpufreq_conservative cpufreq_userspace cpufreq_powersave acpi_cpufreq mperf microcode dm_mod ppdev sg og3 ghes i2c_i801 igb hed pcspkr iTCO_wdt dca iTCO_vendor_support parport_pc floppy parport ext4 jbd2 crc16 i915 drm_kms_helper drm i2c_algo_bit video button fan processor thermal thermal_sys [last unloaded: preloadtrace]
[10991.880400]
[10991.880402] Pid: 4487, comm: python Tainted: GF           2.6.37.1-1.2-desktop #1 To be filled by O.E.M. To be filled by O.E.M./To be filled by O.E.M.
[10991.880408] EIP: 0060:[<c06969d4>] EFLAGS: 00210246 CPU: 0
[10991.880411] EIP is at iret_exc+0x7d0/0xa59
[10991.880413] EAX: 00000000 EBX: 00000000 ECX: 0000018c EDX: b7837000
[10991.880415] ESI: b7837000 EDI: 00000000 EBP: b7837000 ESP: e2a81ee0
[10991.880417]  DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[10991.880420] Process python (pid: 4487, ti=e2a80000 task=df940530 task.ti=e2a80000)
[10991.880422] Stack:
[10991.880423]  00000000 0000018c 00000000 0000018c e5e903dc e4616353 00000009 df99735c
[10991.880428]  df900a7c df900a7c b7837000 df80ad80 df99735c 00000009 e46182a4 e2a81f70
[10991.880433]  e28cd800 e09fc840 e28cd800 fffffffb e09fc888 c03718c1 e4618290 0000018c
[10991.880438] Call Trace:
[10991.882006] Inexact backtrace:
[10991.882006]
[10991.882012]  [<e4616353>] ? write_func+0x63/0x160 [mymod]
[10991.882017]  [<c03718c1>] ? proc_file_write+0x71/0xa0
[10991.882020]  [<c0371850>] ? proc_file_write+0x0/0xa0
[10991.882023]  [<c036c971>] ? proc_reg_write+0x61/0x90
[10991.882026]  [<c036c910>] ? proc_reg_write+0x0/0x90
[10991.882031]  [<c0323060>] ? vfs_write+0xa0/0x160
[10991.882034]  [<c03243c6>] ? fget_light+0x96/0xb0
[10991.882037]  [<c0323331>] ? sys_write+0x41/0x70
[10991.882040]  [<c0202f0c>] ? sysenter_do_call+0x12/0x22
[10991.882044]  [<c069007b>] ? _lock_kernel+0xab/0x180
[10991.882046] Code: f3 aa 58 59 e9 5a f9 d7 ff 8d 0c 88 e9 12 fa d7 ff 01 d9 e9 7b fa d7 ff 8d 0c 8b e9 73 fa d7 ff 01 d9 eb 03 8d 0c 8b 51 50 31 c0 <f3> aa 58 59 e9 cf fa d7 ff 01 d9 e9 38 fb d7 ff 8d 0c 8b e9 30
[10991.882069] EIP: [<c06969d4>] iret_exc+0x7d0/0xa59 SS:ESP 0068:e2a81ee0
[10991.882072] CR2: 0000000000000000 
[10991.889660] ---[ end trace 26fe339b54b2ea3e ]---
18
Hans Then

必要な情報はすべてそこにあります。

[10991.880354] BUG: unable to handle kernel NULL pointer dereference at   (null)

それが理由です。

[10991.880359] IP: [<c06969d4>] iret_exc+0x7d0/0xa59

これが故障時の命令ポインタです。すぐにこれに戻ります。

[10991.880365] *pdpt = 000000002258a001 *pde = 0000000000000000

これらは物理ページテーブルエントリです。記述子テーブル、およびページ記述子エントリ。当然、後者はNULLポインターであるため、NULLです。上記の値が役立つことはめったにありません(物理メモリマッピングが必要な場合のみ)

[10991.880368] Oops: 0002 [#1] PREEMPT SMP

それがおっとコードです。 PREEMPT SMPは、カーネルがプリエンプティブであり、UPではなくSMP用にコンパイルされていることを示しています。これは、バグが何らかの競合状態などに起因する場合に重要です。

[10991.880371] last sysfs file: /sys/devices/platform/coretemp.3/temp1_input

それは必ずしも犯人ではありませんが、しばしば犯人です。 sysファイルはさまざまなカーネルモジュールによってエクスポートされ、多くの場合、sysファイルのI/O操作によってモジュールコードの実行に問題が発生します。

[10991.880374] Modules linked in: ... [last unloaded: preloadtrace]

カーネルは、どのモジュールが原因であるかを必ずしも認識していないので、それらすべてを提供します。また、最近アンロードされたモジュールがクリーンアップされず、カーネルにいくつかの残留物(タイマーやコールバックなど)が残った可能性があります。これは、おっとやパニックの典型的なケースです。したがって、カーネルは最後にアンロードされたものも報告します。

[10991.880402] Pid: 4487, comm: python Tainted: GF           2.6.37.1-1.2-desktop #1 To be filled by O.E.M. To be filled by O.E.M./To be filled by O.E.M.

障害のあるスレッドがユーザーモードスレッドの場合は、PIDとコマンドラインを取得します。 「汚染された」フラグは、カーネルの障害ではないことを示すカーネルの言い方です(カーネルソースはオープンで「純粋」です。「汚染」は冒とく的な非GPLモジュールなどに由来します。

[10991.880408] EIP: 0060:[<c06969d4>] EFLAGS: 00210246 CPU: 0
[10991.880411] EIP is at iret_exc+0x7d0/0xa59

これにより、直接およびシンボル+オフセット形式の両方で、障害のある命令ポインタが得られます。スラッシュの後の部分は関数のサイズです。

[10991.880413] EAX: 00000000 EBX: 00000000 ECX: 0000018c EDX: b7837000
[10991.880415] ESI: b7837000 EDI: 00000000 EBP: b7837000 ESP: e2a81ee0
[10991.880417]  DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068

レジスタはここに示されています。 NULLはおそらくEAXです。

[10991.880420] Process python (pid: 4487, ti=e2a80000 task=df940530 task.ti=e2a80000)
[10991.880422] Stack:
[10991.880423]  00000000 0000018c 00000000 0000018c e5e903dc e4616353 00000009 df99735c
[10991.880428]  df900a7c df900a7c b7837000 df80ad80 df99735c 00000009 e46182a4 e2a81f70
[10991.880433]  e28cd800 e09fc840 e28cd800 fffffffb e09fc888 c03718c1 e4618290 0000018c

スタックポインタ付近が表示されます。カーネルはこれらの値が何を意味するのかわかりませんが、$ rspを表示するgdbから得られる出力と同じです。したがって、それらが何であるかを理解するのはあなた次第です。 (たとえば、c03718c1はカーネルの戻りアドレスである可能性が高いので、/ proc/kallsymsにアクセスして把握するか、トレースにあることを信頼してください)。これは、それまでのすべてのデータがスタックフレームであることを示しています。

これで、スタック呼び出しトレースがあるので、フラグメントをまとめることができます。

[10991.880423]  00000000 0000018c 00000000 0000018c e5e903dc e4616353 --> back to write_func

[            ]  ..................................................... 00000009 df99735c
[10991.880428]  df900a7c df900a7c b7837000 df80ad80 df99735c 00000009 e46182a4 e2a81f70
[10991.880433]  e28cd800 e09fc840 e28cd800 fffffffb e09fc888 c03718c1  --> back to proc_file_write

[10991.882046] Code: f3 aa 58 59 e9 5a f9 d7 ff 8d 0c 88 e9 12 fa d7 ff 01 d9 e9 7b fa d7 ff 8d 0c 8b e9 73 fa d7 ff 01 d9 eb 03 8d 0c 8b 51 50 31 c0 <f3> aa 58 59 e9 cf fa d7 ff 01 d9 e9 38 fb d7 ff 8d 0c 8b e9 30

繰り返しになりますが、カーネルは逆アセンブルできません(おっと、パニックになる可能性がありますので、休憩してください!)。ただし、gdbを使用してこれらの値を逆アセンブルできます。

だから今、あなたはすべてを知っています。実際に独自のモジュールを逆アセンブルして、write_funcのどこでNULLポインターが逆参照されているかを正確に把握できます。 (おそらくそれを何らかの関数への引数として渡しているでしょう)。

28
Technologeeks