情報
要求されたトピックは次のとおりです。しかし、このトピックはこのライブラリには含まれていません。

シンボルを使用したデバッグ

Desktop and Graphics Technology (DGT)、ソフトウェア開発エンジニア主任

Andy Glaister 著

2007 年 8 月

ここでは、デバッグ プロセスでシンボルを最大限に活用する方法について概説します。Microsoft シンボル サーバーの使い方、および独自のプライベート シンボル サーバーを設定して使用する方法についても説明します。ここで紹介するベスト プラクティスに従うことで、問題をデバッグする能力が高まり、問題に関連するシンボルと実行可能ファイルがすべて自分のコンピューター上にない場合にも対応できるようになります。

シンボル

デバッグにはさまざまな種類のシンボルを使用できます。これには、CodeView シンボル、COFF、DBG、SYM、PDB のほか、バイナリ ファイル エクスポート テーブルから生成されるエクスポート シンボルも含まれます。このホワイト ペーパーでは、最新の推奨形式である VS.NET および PDB 形式のシンボルのみを取り上げます。Visual Studio を使用してコンパイルされたプロジェクトには、既定でこの 2 種類のシンボルが生成されます。

リリースの実行可能ファイルに PDB ファイルを生成しても最適化には影響しません。また、生成されるファイルのサイズが大幅に変わることもありません。通常、唯一の違いはパスであり、PDB ファイルの名前が実行可能ファイルに埋め込まれます。このため、PDB ファイルを実行可能ファイルと共に出荷しない場合でも、常に PDB ファイルを作成するようにしてください。

/Zi または /ZI (PDB 情報生成) コンパイラー スイッチを /DEBUG (デバッグ情報生成) リンカー スイッチと共に使用してプロジェクトを構築すると、PDB ファイルが生成されます。コンパイラーで生成された PDB ファイルは、実行可能ファイルと同じディレクトリに配置された単一の PDB ファイルに結合され、そのファイルに書き込まれます。

既定では、PDB ファイルに次の情報が格納されます。

  • パブリック シンボル (通常はすべての関数と静的でグローバルな変数)

  • 実行可能ファイル内のコード セクションを担うオブジェクト ファイルのリスト

  • フレーム ポインター最適化情報 (FPO)

  • ローカル変数およびデータ構造体の名前と型情報

  • ソース ファイルおよび行番号の情報

PDB ファイルの情報を使って実行可能ファイルをリバース エンジニアリングされることが心配である場合は、/PDBSTRIPPED:filename リンカー オプションを使用してストリップ PDB ファイルを作成することもできます。プライベート情報を取り除きたい PDB ファイルがある場合は、Windows 用デバッグ ツールに含まれている pdbcopy というツールを使用できます。

ストリップ PDB ファイルに既定で含まれる情報は次のとおりです。

  • パブリック シンボル (通常は非静的関数とグローバル変数のみ)

  • 実行可能ファイル内のコード セクションを担うオブジェクト ファイルのリスト

  • フレーム ポインター最適化情報 (FPO)

これは、確実なデバッグを行うために最低限必要な情報です。最小限の情報しかないと、元のソース コードに関する追加情報を取得することが難しくなります。ストリップ PDB ファイルと通常の PDB ファイルの両方が生成されるので、必要なデバッグ機能が限られているユーザーにはストリップ バージョンを提供し、完全な PDB は機密扱いにすることができます。/PDBSTRIPPED を使用すると小さい方の PDB ファイルが生成されるので、広く配布するビルドを生成する際には正しい PDB ファイルを使用するようにしてください。一般的なプロジェクトの場合、通常の PDB のサイズは数メガバイトですが、ストリップ バージョンの PDB のサイズはわずか数百キロバイトです。

シンボルを使ったデバッグ

クラッシュしたアプリケーションをデバッグしているときに、クラッシュに至るまでのスタック上の関数をデバッガーが表示しようとします。PDB ファイルがないと、デバッガーはスタックに格納されている関数名、そのパラメーター、またはローカル変数を解決できません。32 ビットの実行可能ファイルをデバッグする場合は、シンボルがないと確実なスタック トレースすら得られないことがあります。スタック上の Raw 値を参照し、どの値がリターン アドレスかを判断できる場合もありますが、この値を関数参照やデータと区別することは容易ではありません。

現在のスタック上の関数がフレーム ポインターなし (/Oy) の最適化を使用してコンパイルされている場合にシンボルが存在しないと、デバッガーは現在の関数を呼び出した関数を確実に特定できません。これは、PDB に含まれているフレーム ポインター最適化 (FPO) 情報がないと、デバッガーがフレーム ポインター レジスタ (EBP) を使用して以前に保存されたフレーム ポインターや、親関数のリターン アドレスをポイントできないからです。この場合、デバッガーは推測を行います。この推測が正しいこともあります。ただし、多くの場合この推測は間違いであり、誤解につながりかねません。次の例のような、シンボルが見つからない、または読み込まれていないことを通知する警告が表示された場合、それ以降はスタックを信用しないでください。

SWPerfTest.exe!TextFunction(... ...)    Line 59    C++d3dx9d.dll!008829b5()[Frames below may be incorrect and/or missing, no symbols loaded for d3dx9d.dll]SWPerfTest.exe!main(int argc=, const char * * argv=)  Line 328 + 0x12 bytes     C++SWPerfTest.exe!__mainCRTStartup() Line 716 + 0x17 bytes    Ckernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytesntdll.dll!__RtlUserThreadStart@8() + 0x27 bytes

多くの場合、シンボルなしでもデバッグは続行できます。これは、正確なシンボルがある場所で問題が発生しており、コール スタックで関数を調べる必要がないからです。コール スタック内のライブラリに PDB がない場合でも、フレーム ポインターを使用してコンパイルされていれば、デバッガーは親関数を正しく推測できます。Windows XP Service Pack 2 以降は、デバッグの精度を高めるために、Windows のすべての DLL と実行可能ファイルが FPO を無効にしてコンパイルされるようになりました。FPO を無効にすると、パフォーマンスにほとんど影響を与えずに、サンプリング プロファイラーが実行時にスタックを参照できるようになります。Windows XP SP2 より前のバージョンの Windows で正確なデバッグとプロファイリングを行うには、オペレーティング システムのすべてのバイナリに、FPO 情報を含んだ対応するシンボル ファイルが必要です。

64 ビット ネイティブの実行可能ファイルをデバッグする場合は、シンボル ファイルなしで有効なスタック トレースを生成できます。これは、x64 オペレーティング システムとコンパイラがシンボル ファイルを必要としないように設計されているためです。ただし、関数名、呼び出しパラメーター、およびローカル変数を取得するには、シンボル ファイルが必要です。

ただし、シンボルがないとデバッグが非常に難しくなる場合もあります。たとえば、PDB ファイルを作成したプログラムをデバッグする場合に、シンボルのない DLL 内の関数からのコールバックでクラッシュが発生すると、スタックをデコードできないためにコールバックを行った関数を特定できません。この状況は、サードパーティ ライブラリを使用している場合、PDB が提供されていない場合、または古いオペレーティング システム コンポーネントで PDB を利用できない場合に頻繁に発生します。コールバックは、多くの場合、メッセージの受け渡し、列挙、メモリー割り当て、例外処理で発生します。正確なスタックがない状態でこのような関数をデバッグするのは非常に面倒です。

別のコンピューターで生成されたミニダンプ、または自分が所有していないコードでのクラッシュを記録したミニダンプを確実にデバッグするには、ミニダンプで参照されている実行可能ファイルのすべてのシンボルとバイナリにアクセスできることが重要です。シンボルとバイナリがシンボル サーバーにある場合は、デバッガーが自動的にそれらを取得します。ミニダンプの詳細については、ホワイト ペーパー「クラッシュ ダンプの分析」を参照してください。

必要なシンボルの取得

Visual Studio およびその他の Microsoft のデバッガー (WinDbg など) は、一般にユーザーがアプリケーションの構築とデバッグを自分のコンピューターで行う場合にのみ機能するように設定されています。自分が作成した実行可能ファイルを他のユーザーに渡す必要がある場合、コンピューターに DLL または .exe ファイルの複数のバージョンがある場合、あるいは Windows やその他のライブラリ (DirectX など) を使用するアプリケーションを正確にデバッグしたい場合は、デバッガーがシンボルを検索して読み込むしくみを理解する必要があります。デバッガーは、ユーザーが指定したシンボル検索パス (Visual Studio の Options\Debugging\Symbols) または _NT_SYMBOL_PATH 環境変数のいずれかを使用します。通常、デバッガーは対応する PDB を次の場所で検索します。

  • DLL または実行可能ファイル内で指定された場所。

    DLL または実行可能ファイルを自分のコンピューター上で構築した場合は、既定で、リンカーによって関連する PDB ファイルの完全パスとファイル名がその DLL または実行可能ファイル内に挿入されます。デバッグ時は、デバッガーがまず DLL または実行可能ファイル内で指定された場所にシンボル ファイルがあるかどうかを確認します。この場合、自分のコンピューター上でコンパイルしたコードに常にシンボルを提供できるので便利です。

  • DLL または実行可能ファイルと同じフォルダー内にある PDB。

  • ローカルのシンボル キャッシュ フォルダー。

  • ローカルのネットワーク ファイル共有シンボル サーバー。

  • インターネット上のシンボル サーバー (Microsoft シンボル サーバーなど)。

正確なデバッグに必要なすべての PDB が揃っていることを確認するには、Windows 用デバッグ ツールをインストールします。32 ビット版と 64 ビット版は、http://www.microsoft.com/whdc/devtools/debugging/default.mspx にあります。

このパッケージと共にインストールされる便利なツールが symchk.exe です。このツールは、見つからないシンボルまたは間違ったシンボルを明らかにします。このツールには、多数のコマンド ライン オプションがあります。このうち、特に有用で使用頻度の高い 2 つのオプションを以下で説明します。

同じフォルダー内の DLL または .exe ファイルと PDB が対応しているかどうかのチェック

"c:\Program Files\Debugging Tools for Windows\symchk" testing.dll /s .SYMCHK: FAILED files = 0SYMCHK: PASSED + IGNORED files = 1

/s . オプションを指定すると、symchk で現在のフォルダーでのみシンボルが検索され、シンボル サーバーは検索されません。

一連のフォルダー内にあるすべての DLL と実行可能ファイルに対応する PDB があるかどうかのチェック

"c:\Program Files\Debugging Tools for Windows\symchk" *.* /r

/r オプションを指定すると、symchk でフォルダーが再帰的にスキャンされて、すべての実行可能ファイルに対応する PDB があるかがチェックされます。/s オプションを指定しなければ、symchk で現在の _NT_SYMBOL_PATH を使用してプライベート サーバーまたはローカル サーバー上、あるいは Microsoft シンボル サーバー上でシンボルが検索されます。symchk ツールでは、実行可能ファイル (.exe、.dll など) のシンボルのみが検索されます。ワイルドカードを使用して非実行可能ファイルのシンボルを検索することはできません。

symchk のしくみ

リンカーは、.dll、実行可能ファイル、および PDB ファイルを生成する際に、各ファイルに同じ GUID を格納します。各ツールでは、この GUID を使用して、指定された PDB ファイルが DLL または実行可能ファイルに対応するかどうかを判断します。リソース エディターまたはコピー防止エンコードで DLL や実行可能ファイルを変更したり、そのバージョン情報を変更したりすると、GUID が更新され、デバッガーが PDB ファイルを読み込めなくなります。このため、リンカーによって作成された DLL または実行可能ファイルは操作しないようにすることが非常に重要です。

VS.NET 付属の DUMPBIN ユーティリティを使用して、検索されるシンボル パスを表示し、指定された DLL または実行可能ファイルに対応するシンボル ファイルがあるかどうかを確認することもできます。次に例を示します。

DUMPBIN /PDBPATH:VERBOSE filename.exe

シンボル サーバー

シンボル サーバーは、実行可能ファイルとシンボル ファイルの複数のバージョンを格納するリポジトリです。このサーバーには、シンボル ファイル自体、または関連するシンボル ファイルへのポインターのいずれかが格納されています。デバッガーはシンボル サーバーの使い方を認識しており、シンボル サーバーを使用して見つからないシンボルや不明なシンボルを検索します。

DLL と実行可能ファイルは、Microsoft シンボル サーバーから入手することもできます。これにより、自分のコンピューター上にないオペレーティング システム ファイルについて、クラッシュをデバッグし、コードを調査することができます。デバッグに使用しているシステムに実行可能ファイルまたは DLL がない場合、これを検出したデバッガーは、自動的に Microsoft シンボル サーバーにシンボルとバイナリ ファイルのコピーを要求します。この動作は、多数のバージョンがある msvcrt.dll などのコンポーネントをデバッグする場合に、自分のコンピューターにないバージョンのコードを調査する必要があるときに便利です。また、デバッグに使用しているシステムとは別のオペレーティング システムで生成されたミニダンプをデバッグする場合にも役立ちます。

Microsoft では、すべてのオペレーティング システムおよびその他の再配布されたコンポーネント (DirectX SDK など) のすべての PDB ファイルを、外部からアクセス可能な自社のシンボル サーバー上で公開しています。このため、これらの DLL または実行可能ファイルを使用するアプリケーションは容易にデバッグできます。自分のコンピューターで構築したコンポーネントのローカル シンボルと共に、Microsoft シンボル サーバーを使用してシンボルを解決することができます。

Microsoft シンボル サーバーを使用するようにコンピューターを設定すると、すべての Microsoft シンボル ファイルにアクセスできるようになります。また、会社、チーム、あるいはネットワーク用にプライベート シンボル サーバーを設定して、作業中のプロジェクトの複数の古いバージョンを保存したり、Microsoft シンボル サーバーから使用するシンボルにローカル キャッシュを用意したりすることもできます。

シンボル サーバーを使用するには、_NT_SYMBOL_PATH 環境変数に検索パスを指定します。WinDbg、NTSD、Visual Studio を始めとするデバッガーや最近のツールは、自動的にこのパスを使用してシンボルを検索します。

デバッガーは、まずローカルにシンボルを検索します。その後に、シンボル サーバーで検索します。対応するシンボルを検出すると、デバッガーはそのシンボル ファイルをローカル キャッシュに転送します。一般的な DLL または実行可能ファイルのシンボルのサイズは、1 ~ 100 MB です。したがって、多数の DLL を含んでいるプロセスをデバッグする場合、すべてのシンボルを解決してローカル キャッシュに転送するためにある程度の時間がかかることがあります。 .

Microsoft シンボル サーバーの使用

インターネット経由で Microsoft シンボル サーバーを使用することは、ブロードバンド接続が可能な場合にのみお勧めします。そうでないと、最初にサーバーを使用するときにデバッガーの速度が極端に遅くなります。これは、数十メガバイトのシンボル ファイルをローカル コンピューターにダウンロードすることがあるからです。低速のインターネット接続のみを使用している場合は、この最初のダウンロードを夜間に実行するか、シンボル パッケージを直接ダウンロードしてインストールする方法があります。シンボル パッケージは、MSDN サブスクリプションの一部として入手できるほか、オペレーティング システムのサポート ディスクに収録されており、独立したパッケージとしても提供されています。ただし、シンボル サーバーを使用することをお勧めします。シンボル サーバーでは、修正されたファイルや更新されたファイルのシンボルを含めた最新のシンボルを入手できます。

Microsoft シンボル サーバーの場所は、http://msdl.microsoft.com/download/symbols です。

シンボル サーバーには、次のいずれかの方法でアクセスできます。

  • サーバーのアドレスを直接入力します。Visual Studio で [ツール](Tools) メニューの [オプション](Options) を選択し、[デバッグ](Debugging)[シンボル](Symbols) の順に選択します。

  • 環境変数 _NT_SYMBOL_PATH を使用します。この方法を使用することをお勧めします。

    この変数はすべてのデバッグ ツールで使用されます。また、Visual Studio でも使用され、Visual Studio の起動時に読み取られてデコードされます。したがって、この環境変数を変更したときは、Visual Studio を再起動する必要があります。

    この環境変数では、複数のシンボル サーバー (内部のプライベート シンボル サーバーなど) を指定できます。また、シンボル サーバーから内部的にまたはインターネット経由で検索したすべてのシンボルの PDB を格納するためのローカル キャッシュ ディレクトリを直接指定することもできます。

_NT_SYMBOL_PATH 変数の構文は次のとおりです。

srv*[local cache]*[private symbol server]*http://msdl.microsoft.com/download/symbols

[local cache] は、使用されているシンボルのキャッシュを格納するコンピューター上のディレクトリの名前 (%SYSTEMROOT%\Symbols や c:\symbols など) で置き換えます。

[private symbol server] は省略可能です。このパラメーターでは、ネットワーク上にあるシンボル サーバー、またはチーム、製品グループ、会社などで共有するシンボル サーバーを指定できます。

Microsoft シンボル サーバーのみをシンボルのローカル キャッシュと併用する場合は、インターネット経由のアクセスを高速化するために、_NT_SYMBOL_PATH を次のように設定してください。

srv*c:\symbols*http://msdl.microsoft.com/download/symbols

_NT_SYMBOL_PATH のその他のオプションについては、Microsoft Debugging Tools for Windows パッケージと共にインストールされるヘルプ ファイルを参照してください。

実行可能ファイルにシンボルがないと、シンボル サーバーを使用する場合にデバッガーの起動にかかる時間が長くなることがあります。これは、デバッガーが実行可能ファイルを読み込むたびにシンボル サーバーを照会するためです。この理由から、常にすべてのコンポーネントのシンボルを要求することをお勧めします。

すべてのコンポーネントのシンボルを要求できない場合があります。たとえば、ビデオ ドライバーの DLL がプロセス空間にあり、必要な PDB ファイルが Microsoft シンボル サーバー上にある場合などです。この場合は、デバッグ セッションを開始するときに若干の遅延が生じます。

このわずかな遅延も回避するには、デバッガーを一度実行して Microsoft シンボル サーバーからすべてのシンボルをローカルにキャッシュします。次に、_NT_SYMBOL_PATH から Microsoft シンボル サーバーを削除します。必要なすべてのシンボルのコピーを Microsoft シンボル サーバーからローカルにキャッシュしてあるので、実行可能ファイルが変更されない限り、シンボルがない実行可能ファイルのチェックではインターネット経由の照会が不要となります。

手動でのシンボルの取得

デバッガーを正しく設定していれば、必要なシンボルはローカル キャッシュまたはシンボル サーバーから自動的に読み込まれます。1 つの実行可能ファイル、または実行可能ファイルを含んだ 1 つのフォルダーのシンボルのみを取得する場合は、symchk を使用します。たとえば、Windows System フォルダー内の d3dx9_30.dll ファイルのシンボルを現在のディレクトリにダウンロードする場合は、次のコマンドを使用します。

"c:\Program Files\Debugging Tools for Windows\symchk" c:\Windows\System32\d3dx9_30.dll /oc \.

symchk ツールはほかにも多数の用途があります。詳細については、symchk /? を実行するか、Microsoft Debugging Tools for Windows のドキュメントを参照してください。

シンボル サーバーの設定

シンボル サーバーの設定は非常に簡単です。シンボル サーバーを設定すると、次のような理由で便利です。

  • 帯域幅を節約できます。つまり、会社、チーム、製品でのシンボルの解決を高速化できます。ネットワーク上のローカルのファイル共有にある内部シンボル サーバーには、Microsoft シンボル サーバーなどの外部シンボル サーバーへの参照がすべてキャッシュされます。ローカルまたは内部のシンボル サーバーには、一度に多数のユーザーが高速にアクセスできます。このため、帯域幅が節約され、シンボル要求が重複して遅延が生じることもなくなります。

  • アプリケーションの古いビルド、バージョン、または外部リリースのシンボルを格納できます。このようなビルドのシンボルを、簡単にアクセスできるシンボル サーバーに格納することで、デバッガーの使用とローカル シンボル サーバーへの接続が可能なすべてのコンピューターでこのようなビルドでのクラッシュや問題をデバッグできます。特に便利なのは、自分が構築していない実行可能ファイル、つまり他のプログラマや別のビルド コンピューターが生成したビルドによって生成されたミニダンプをデバッグする場合です。このようなビルドのシンボルがシンボル サーバーに格納されていると、確実かつ正確にデバッグできるようになります。

  • シンボルを最新の状態に保つことができます。Windows Update や DirectX SDK で変更された OS コンポーネントのように、コンポーネントが更新された場合でも、最新のシンボルを使用してデバッグすることができます。

ローカル ネットワーク上でシンボル サーバーを設定する作業は単純です。サーバーにファイル共有を作成し、この共有にアクセスしてファイルやフォルダーを作成するための完全な権限をユーザーに与えるだけです。この共有は、同時にアクセスできるユーザーの数が制限されないように、Windows Server 2003 などのサーバー オペレーティング システム上に作成する必要があります。

たとえば、\\mainserver\symbols 上にファイル共有を設定する場合は、チームのメンバーが _NT_SYMBOL_PATH を次のように設定します。

Srv*c:\symbols*\\mainserver\symbols*http://msdl.microsoft.com/download/symbols

シンボルが取得されると、c:\symbols ディレクトリ内の \\mainserver\symbols 共有ディレクトリ、および個々のキャッシュにファイルとフォルダーが作成されます。

独自のシンボル サーバーまたは Microsoft シンボル サーバーの設定と使用に関する一般的な説明は以上のとおりです。

シンボル サーバーへのシンボルの追加

シンボル サーバー共有でファイルを追加、削除、または編集するには、symstore.exe ツールを使用します。このツールは、Microsoft Debugging Tools for Windows パッケージに含まれています。シンボル サーバー、symstore ツール、およびシンボルのインデックス作成の詳細については、Debugging Tools for Windows パッケージ付属のドキュメントを参照してください。

ビルド プロセスの一環として独自のシンボル サーバーにシンボルを直接追加するか、サードパーティのライブラリまたはツールでチーム全体がシンボルを使用できるようにすることができます。シンボル サーバー ファイル共有にシンボルを追加する作業を、"シンボルのインデックス作成" と呼びます。シンボルにインデックスを作成するには、一般に 2 つの方法があります。シンボル ファイルをシンボル サーバーにコピーする方法と、シンボルの場所を指すポインターをシンボル サーバーにコピーする方法です。古いビルドを含んでいるアーカイブ フォルダーがある場合は、シンボルを複製する代わりに、共有に既にある PDB ファイルへのポインターにインデックスを作成できます。シンボルはサイズが数十メガバイトになる場合があるため、開発中にプロジェクトの全ビルドをアーカイブするために必要となる領域のサイズを事前に計画しておくことをお勧めします。シンボルへのポインターのみにインデックスを作成すると、古いビルドを削除したり、ファイル共有の名前を変更したりした場合に問題が生じることがあります。

たとえば、October 2006 DirectX SDK からシンボル サーバー ファイル共有 \\mainserver\symbols に取得したすべてのシンボルに、c:\dxsym\Extras\Symbols 内で再帰的にインデックスを作成するには、次のコマンドを使用します。

"c:\Program Files\Debugging Tools for Windows\symstore" add /f "C:\dxsym\Extras\Symbols\*.pdb"/s \\mainserver\symbols /t "October 2006 DirectX SDK " /r

シンボルを追加したトランザクションに説明を加えるには、/t "comment" パラメーターを使用します。説明を追加しておくと、シンボルに対して管理タスクを実行する際に役立ちます。

ベスト プラクティス

  • チーム、会社、または製品用に独自のシンボル サーバー ファイル共有を設定します。

  • _NT_SYMBOL_PATH は、ローカル キャッシュ、プライベート シンボル サーバー、および Microsoft シンボル サーバーをポイントするように設定します。

  • デバッガーがデバッグ中のコンポーネントのシンボルを読み込めない場合は、コンポーネントの所有者に連絡して、シンボル (少なくともストリップ PDB) を要求します。

  • ビルドが生成されるたびにプライベート シンボル サーバーでシンボルにインデックスが作成される自動ビルド システムを設定します。必ずこのプロセスで生成されたビルドを配布するようにしてください。これにより、問題をデバッグする際に常にシンボルを使用できるようになります。

  • Visual Source Safe または Perforce ベースのソース管理システムから特定のモジュールのソース コードにデバッガーが直接アクセスできるように、シンボル サーバーを設定します。ゲームのリリースされたバージョンのソース ファイル情報とシンボルにインデックスが作成されていれば、シンボル サーバーにアクセスできる開発者は、ソース ファイルのビルド環境または古いバージョンが自分の開発用コンピューターになくても、報告された問題を完全にソース レベルでデバッグできます。ソース ファイル情報にインデックスを作成できるようにシンボル サーバーを設定する方法については、ソース サーバーのドキュメントを参照してください。

コミュニティの追加

表示: