シンボルの検証

シンボルの問題はさまざまな形で現れる可能性があります。 たとえば、スタックトレースが正しくない情報を示したり、スタック内の関数名を特定できなかったりする場合があります。 または、デバッガー コマンドがモジュール、関数、変数、構造体、またはデータ型の名前を理解できなかった可能性があります。

デバッガーがシンボルを正しく読み込んでいないと疑われる場合は、この問題を調査するためにいくつかの手順を実行できます。

まず、lm (読み込まれたモジュールの一覧表示) コマンドを使用して、読み込まれたモジュールのリストをシンボルの情報と共に表示します。 このコマンドの最も便利な形式は次のとおりです。

0:000> lml 

WinDbg を使用している場合は、Debug | Modules メニュー コマンドを使用して、この情報を表示できます。

これらの表示で見られるメモや略語に特に注意してください。 これらの解釈については、「シンボル ステータスの略語」を参照してください。

適切なシンボル ファイルが表示されない場合は、まず、シンボル パスを確認します。

0:000> .sympath
Current Symbol Path is: d:\MyInstallation\i386\symbols\retail

シンボル パスが間違っている場合は、修正してください。 カーネルデバッガーを使用している場合は、ローカルの %WINDIR% がシンボル パスに含まれていないことを確認してください。

次に、.reload (モジュールの再読み込み) コマンドを使用してシンボルを再読み込みします。

0:000> .reload ModuleName 

シンボル パスが正しい場合は、ノイズ モードをアクティブにして、dbghelp がどのシンボル ファイルを読み込んでいるかを確認できるようにする必要があります。 次に、モジュールを再読み込みします。 ノイズ モードをアクティブにする方法については、「シンボル オプションの設定」を参照してください。

Microsoft Windows のシンボルのノイズ モードでの再読み込みの例を次に示します。

kd> !sym noisy
kd> .reload nt
 1: Kernel Version 2081 MP Checked
 2: Kernel base = 0x80400000 PsLoadedModuleList = 0x80506fa0
 3: DBGHELP: FindExecutableImageEx-> Looking for D:\MyInstallation\i386\ntkrnlmp.exe...mismatched timestamp
 4: DBGHELP: No image file available for ntkrnlmp.exe
 5: DBGHELP: FindDebugInfoFileEx-> Looking for
 6: d:\MyInstallation\i386\symbols\retail\symbols\exe\ntkrnlmp.dbg... no file
 7: DBGHELP: FindDebugInfoFileEx-> Looking for
 8: d:\MyInstallation\i386\symbols\retail\symbols\exe\ntkrnlmp.pdb... no file
 9: DBGHELP: FindDebugInfoFileEx-> Looking for d:\MyInstallation\i386\symbols\retail\exe\ntkrnlmp.dbg... OK
10: DBGHELP: LocatePDB-> Looking for d:\MyInstallation\i386\symbols\retail\exe\ntkrnlmp.pdb... OK
11: *** WARNING: symbols checksum and timestamp is wrong 0x0036a4ea 0x00361a83 for ntkrnlmp.exe

シンボル ハンドラーは、まず、読み込もうとしているモジュールに一致するイメージを検索します (3 行目と 4 行目)。 イメージ自体は必ずしも必要というわけではありませんが、正しくないイメージが存在すると、シンボル ハンドラーが失敗することがよくあります。 これらの行は、デバッガーが D:\My Installation\i386\ntkrnlmp.exe でイメージを見つけたが、日時スタンプが一致しなかったことを示しています。 日時スタンプが一致しないため、検索は続行されます。 次に、デバッガーは読み込まれたイメージに一致する .dbg ファイルと .pdb ファイルを検索します。 これらは 6 行目から 10 行目にあります。 11 行目は、シンボルが読み込まれたにもかかわらず、イメージの日時スタンプが一致しなかった (つまり、シンボルが間違っていた) ことを示しています。

シンボル検索で致命的なエラーが発生した場合は、次の形式のメッセージが表示されます。

ImgHlpFindDebugInfo(00000000, module.dll, c:\MyDir;c:\SomeDir, 0823345, 0) failed

このエラーは、ファイル システムの障害、ネットワーク エラー、.dbg ファイルの破損などが原因である可能性があります。

シンボルの読み込みエラーの診断

ノイズ モードでは、デバッガーはシンボル ファイルを読み込めないときにエラー コードを出力することがあります。 .dbg ファイルに関連するエラー コードのリストは winerror.h にあります。 .pdb エラー コードは別のソースから取得され、最も一般的なエラーは平文の英語テキストで出力されます。

winerror.h にあるエラー コードで .dbg ファイルに関連する一般的なものは次のとおりです。

0xB
ERROR_BAD_FORMAT

0x3
ERROR_PATH_NOT_FOUND

0x35
ERROR_BAD_NETPATH

ネットワーク エラーが原因でシンボル ファイルを読み込めない可能性があります。 ERROR_BAD_FORMAT または ERROR_BAD_NETPATH が表示され、ネットワーク上の別のコンピューターからシンボルを読み込んでいる場合は、シンボル ファイルをホスト コンピューターにコピーし、そのパスをシンボル パスに追加してみてください。 その後、シンボルを再読み込みしてみてください。

検索パスとシンボルの確認

「c:\MyDir;c:\SomeDir」をシンボル パスとします。 デバッグ情報はどこで検索すべきでしょうか。

Windows の無料ビルドなど、バイナリからデバッグ情報が削除されている場合は、まず、次の場所で .dbg ファイルを検索します。

c:\MyDir\symbols\exe\ntoskrnl.dbg
c:\SomeDir\symbols\exe\ntoskrnl.dbg
c:\MyDir\exe\ntoskrnl.dbg
c:\SomeDir\exe\ntoskrnl.dbg
c:\MyDir\ntoskrnl.dbg
c:\SomeDir\ntoskrnl.dbg
current-working-directory\ntoskrnl.dbg

次に、以下の場所で .pdb ファイルを検索します。

c:\MyDir\symbols\exe\ntoskrnl.pdb
c:\MyDir\exe\ntoskrnl.pdb
c:\MyDir\ntoskrnl.pdb
c:\SomeDir\symbols\exe\ntoskrnl.pdb
c:\SomeDir\exe\ntoskrnl.pdb
c:\SomeDir\ntoskrnl.pdb
current-working-directory\ntoskrnl.pdb

.dbg ファイルの検索では、デバッガーが MyDir ディレクトリと SomeDir ディレクトリを交互に検索しますが、.pdb 検索では、そのように検索しません。

Windows XP 以降のバージョンの Windows では、.dbg シンボル ファイルは使用されません。 詳細については、「シンボルとシンボル ファイル」を参照してください。

ビルドの不一致

頻繁に更新されるコンピューターでのデバッグの失敗で最も一般的な問題の 1 つは、異なるビルドのシンボルの不一致です。 この問題の一般的な原因は 3 つあります。間違ったビルドのシンボルを指定していること、対応するシンボルのないプライベート ビルドのバイナリを使用していること、マルチプロセッサのコンピューターでユニプロセッサのハードウェア抽象化レベル (HAL) とカーネル シンボルを使用していることです。 最初の 2 つの問題は、バイナリとシンボルを一致させるだけで、3 つ目の問題は、hal*.dbg と ntkrnlmp.dbg の名前を hal.dbg と ntoskrnl.dbg に変更することで修正できます。

ターゲット コンピューターにインストールされている Windows のビルドを調べるには、vertarget (ターゲット コンピューターのバージョンの表示) コマンドを使用します。

kd> vertarget 
Windows XP Kernel Version 2505 UP Free x86 compatible
Built by: 2505.main.010626-1514
Kernel base = 0x804d0000 PsLoadedModuleList = 0x80548748
Debug session time: Mon Jul 02 14:41:11 2001
System Uptime: 0 days 0:04:53 

シンボルのテスト

シンボルのテストはより難しくなります。 デバッガーのスタック トレースを検証し、デバッグ出力が正しいかどうかを確認する必要があります。 ここで 1 つの例を試してみます。

kd> u videoprt!videoportfindadapter2
Loading symbols for 0xf2860000     videoprt.sys ->   videoprt.sys

VIDEOPRT!VideoPortFindAdapter2:
f2856f42 55               push    ebp
f2856f43 8bec             mov     ebp,esp
f2856f45 81ecb8010000     sub     esp,0x1b8
f2856f4b 8b4518           mov     eax,[ebp+0x18]
f2856f4e 53               push    ebx
f2856f4f 8365f400         and     dword ptr [ebp-0xc],0x
f2856f53 8065ff00         and     byte ptr [ebp-0x1],0x0
f2856f57 56               push    esi

u コマンドは、videoprt.sys 内の videoportfindadapter 文字列をアンアセンブルします。 デバッガーでシンボルが正しいことは、pushmov などの一般的なスタック コマンドがスタックに表示されていることからわかります。 ほとんどの関数は、ベース ポインター (ebp) またはスタック ポインター (esp) を使用した add、sub、または push 操作から始まります。

シンボルが正しく機能していない場合、通常、そのことはすぐにわかります。 この例では、Glintmp.sys にシンボルがありません。Glintmp の横に関数が一覧表示されていないことからわかります。

kd> kb
Loading symbols for 0xf28d0000     videoprt.sys ->   videoprt.sys
Loading symbols for 0xf9cdd000      glintmp.sys ->   glintmp.sys
*** ERROR: Symbols could not be loaded for glintmp.sys
ChildEBP RetAddr  Args to Child
f29bf1b0 8045b5fa 00000001 0000a100 00000030 ntoskrnl!RtlpBreakWithStatusInstruction
f29bf1b0 8044904e 00000001 0000a100 00000030 ntoskrnl!KeUpdateSystemTime+0x13e
f29bf234 f28d1955 f9b7d000 ffafb2dc f9b7d000 ntoskrnl!READ_REGISTER_ULONG+0x6
f29bf248 f9cde411 f9b7d000 f29bf2b0 f9ba0060 VIDEOPRT!VideoPortReadRegisterUlong+0x27
00000002 00000000 00000000 00000000 00000000 glintMP+0x1411 [No function listed.] 

このスタック トレースに対して間違ったビルド シンボルが読み込まれました。 最初の 2 つの呼び出しに対して関数が一覧表示されていないことからわかります。 このスタック トレースは、win32k.sys が矩形を描画する際の問題のようです。

1: kd> 
1: kd> kb                      [Local        9:50 AM]
Loading symbols for 0xf22b0000       agpcpq.sys ->   agpcpq.sys
*** WARNING: symbols checksum is wrong 0x0000735a 0x00000000 for agpcpq.sys
*** ERROR: Symbols could not be loaded for agpcpq.sys
Loading symbols for 0xa0000000       win32k.sys ->   win32k.sys
*** WARNING: symbols checksum is wrong 0x00191a41 0x001995a9 for win32k.sys
ChildEBP RetAddr  Args to Child
be682b18 f22b372b 82707128 f21c1ffc 826a70f8 agpCPQ+0x125b [No function listed.]
be682b4c a0140dd4 826a72f0 e11410a8 a0139605 agpCPQ+0x372b [No function listed.]
be682b80 a00f5646 e1145100 e1cee560 e1cee560 win32k!vPatCpyRect1_6x6+0x20b
00000001 00000000 00000000 00000000 00000000 win32k!RemoteRedrawRectangle+0x32 

正しいスタック トレースを次に示します。 問題は実際には AGP440.sys にあります。 スタック トレースに最初に現れる項目が通常、問題の原因です。 win32k.sys の矩形描画エラーがなくなっています。

1: kd> kb                      [Local        9:49 AM]
ChildEBP RetAddr  Args to Child
be682b18 f22b372b 82707128 f21c1ffc 826a70f8 agpCPQ!AgpReleaseMemory+0x88
be682b30 f20a385c 82703638 e183ec68 00000000 agpCPQ!AgpInterfaceReleaseMemory+0x8b
be682b4c a0140dd4 826a72f0 e11410a8 a0139605 VIDEOPRT!AgpReleasePhysical+0x44
be682b58 a0139605 e1cee560 e11410a8 a00e5f0a win32k!OsAGPFree+0x14
be682b64 a00e5f0a e1cee560 e11410a8 e1cee560 win32k!AGPFree+0xd
be682b80 a00f5646 e1145100 e1cee560 e1cee560 win32k!HeapVidMemFini+0x49
be682b9c a00f5c20 e1cee008 e1cee008 be682c0c win32k!vDdDisableDriver+0x3a
be682bac a00da510 e1cee008 00000000 be682c0c win32k!vDdDisableDirectDraw+0x2d
be682bc4 a00da787 00000000 e1843df8 e1843de8 win32k!PDEVOBJ__vDisableSurface+0x27
be682bec a00d59fb 00000000 e1843de8 00000000 win32k!PDEVOBJ__vUnreferencePdev+0x204
be682c04 a00d7421 e1cee008 82566a98 00000001 win32k!DrvDestroyMDEV+0x30
be682ce0 a00a9e7f e1843e10 e184a008 00000000 win32k!DrvChangeDisplaySettings+0x8b3
be682d20 a008b543 00000000 00000000 00000000 win32k!xxxUserChangeDisplaySettings+0x106
be682d48 8045d119 00000000 00000000 00000000 win32k!NtUserChangeDisplaySettings+0x48
be682d48 77e63660 00000000 00000000 00000000 ntkrnlmp!KiSystemService+0xc9 

便利なコマンドと拡張機能

次のコマンドと拡張機能はシンボルの問題を追跡するのに役立つ場合があります。

lm (読み込まれたモジュールの一覧表示)
すべてのモジュールを一覧表示し、これらのモジュール内のすべてのシンボルの読み込みステータスを示します。

!dh image-header-base
image-header-base で始まる読み込まれたイメージのヘッダー情報を表示します。

.reload /n
すべてのカーネル シンボルを再読み込みします。

.reload [image-name]
(CDB または WinDbg のみ) イメージ image-name のシンボルを再読み込みします。 image-name を指定しない場合、すべてのイメージのシンボルを再読み込みします。 (シンボル パスを変更した後は、シンボルを再読み込みする必要があります。)

!sym noisy
シンボルの読み込みに対して詳細モードをオンにします。 これは、モジュールの読み込みに関する情報を得るために使用できます。 詳細については、「シンボル オプションの設定」を参照してください。

.sympath [new-symbol-path]
新しいシンボル パスを設定したり、現在のシンボル パスを表示したりします。 詳細については、「シンボル パス」を参照してください。

カーネル シンボルは正しいが、完全なスタックを取得できない場合は、次のコマンドも役立つことがあります。

X *!
これにより、シンボルが現在読み込まれているモジュールが一覧表示されます。 これは、カーネル シンボルが正しい場合に役立ちます。

.reload /user
これにより、すべてのユーザー モード シンボルを再読み込みしようとします。 カーネル デバッグの実行時に、あるプロセスが実行中にシンボルが読み込まれ、後で別のプロセスで中断が発生した場合、このようなシンボルの再読み込みが必要になります。 この場合、このコマンドを実行しない限り、新しいプロセスのユーザー モード シンボルは読み込まれません。

X wdmaud!*start\*
これにより、wdmaud モジュールのシンボルのうち、名前に「start」文字列が含まれるもののみが一覧表示されます。 これには、wdmaud のすべてのシンボルを再読み込みするが、「start」を含むシンボルのみを一覧表示するという利点があります。 (したがって、シンボルのリストは短くなるものの、「start」を含むシンボルが常にあるため、読み込みが行われたかどうかの検証が必要になります。)

シンボルを検証するためのもう 1 つの便利な手法は、コードをアンアセンブルすることです。 ほとんどの関数は、ベース ポインター (ebp) またはスタック ポインター (esp または sp) を使用した add、sub、または push 操作から始まります。 スタック上のいくつかの関数を (オフセットゼロから) アンアセンブル (U コマンドを使用) して、シンボルを確認してみてください。

ネットワークとポートの問題

シンボル ファイルやデバッガーへの接続中に問題が発生します。 問題が発生した場合に留意すべき点がいくつかあります。

  • デバッグ ケーブルがテスト システムのどの COM ポートに接続されているかを特定します。

  • テストシステムの boot.ini 設定を確認します。 /debug スイッチを検索し、ボー レートと COM ポートの設定を確認します。

  • シンボル ファイルがネットワーク経由でアクセスされる場合、ネットワークの問題がデバッグの妨げになることがあります。

  • 同じ名前の .dll および .sys ファイル (mga64.sys と mga64.dll など) がシンボル ツリーの適切なディレクトリに分けられていない場合、デバッガーを混乱させることになります。

  • カーネル デバッガーでは、ビルド シンボル ファイルをプライベート シンボル ファイルに置き換えることが常に適切であるとは限りません。 シンボル パスを再確認し、問題のあるシンボルに対して .reloadFileName を実行してください。 !dlls コマンドが便利な場合があります。

質問と誤解

Q: シンボルは正常に読み込まれましたが、スタックが間違っているようです。 デバッガーが壊れているのでしょうか?

A: 必ずしもそうとは限りません。 問題の原因として最も考えられるのは、シンボルが正しくないことです。 このセクションで説明している手順を実行して、有効なシンボルが読み込まれているかどうかを特定してください。 一部の処理が機能するからといって、有効なシンボルがあるとは考えないでください。 たとえば、正しくないシンボルを使用して dd nt!ntbuildnumber または u nt!KeInitializeProcess を実行できる可能性は十分にあります。 上記で説明している手順を使用して、それらが正しいことを確認してください。

Q: 正しくないシンボルでもデバッガーは動作しますか?

A: 場合によります。 多くの場合、厳密に一致しないシンボルを使用しても問題ありません。 たとえば、以前の Windows ビルドのシンボルでも場合によっては機能することがよくありますが、いつ機能し、いつ機能しないかについての規則はありません。

Q: カーネル デバッガーで停止しているユーザー モード プロセスのシンボルを表示したいと考えています。 できますか?

A: ほとんどの場合はできます。 このシナリオのサポートは不十分です。なぜなら、カーネル デバッガーは各プロセスのモジュール読み込みを追跡するのに十分な情報を保持していないためです。しかし、合理的な回避策があります。 ユーザー モード モジュールのシンボルを読み込むには、.reload -user コマンドを実行します。 これにより、現在のコンテキストのユーザー モード モジュールが読み込まれます。

Q: 次のメッセージはどういう意味ですか?

*** WARNING: symbols checksum and timestamp is wrong 0x0036d6bf 0x0036ab55 for ntkrnlmp.exe

A: ntkrnlmp.exe のシンボルが間違っていることを意味します。