私は何年にもわたって多くのゲーム プロジェクトでミニダンプを使用してきましたが、有効なコール スタックを持つ可能性は約 50% のようです。コールスタックを改善するにはどうすればよいですか?
最新の dbghelp.dll を exe ディレクトリに入れてみました。それはいくつかを助けるようです。
Visual Studio 2008 または 2010 はどちらが優れていますか? (私はまだ VS 2005 を使用しています)。
私が使用するコードは、このサンプルのようになります。
ダンプで見つかったコール スタックの精度を向上させるためにできることの 1 つは、Visual Studio 以外のデバッガーを使用することです。具体的には、WinDbg または dbgeng.dll にある "Windows デバッガー" デバッグ エンジンを使用する別のツールを使用します ( Visual Studio が使用する "Visual Studio Debugger" デバッグ エンジンに)。
私たちの経験では、WinDbg は、Visual Studio が使用できない、または非常に不正確なコール スタックを生成するのと同じダンプから適切なコール スタックを生成する点で 100% 信頼性があります。私が知る限り、未処理の例外がクラッシュの原因である場合、WinDbgは例外 callstack を再構築/回復するトリッキーなプロセスを自動的に実行しますが、Visual Studio は実行しません (または実行できませんか?)。2 つのデバッガーは、スタックの解釈に異なるヒューリスティックを使用します。
WinDbg は最初は気が遠くなる可能性があるため、WinDbg を簡単にする方法、または直接使用する必要を回避する方法についてのクイック ガイドを次に示します。
良いコールスタックを抽出するための単なる人間のガイド
これらは、「最も速い/最も簡単」から「最も遅い/最も解釈が難しい」の順に並べられています。
これは、一般的な問題の多くの分析を自動化するあまり知られていないツールであり、プログラマー以外や顧客に提供するのに十分簡単です。これは高速で、ほぼ確実であり、受信したクラッシュ ダンプをすばやく分析するための「頼りになる」ツールになっています。
数秒から数分後、問題の分析、関連するすべてのスレッドに関する情報、完全なコール スタックなどを含む素敵な .mhtml ファイルが出力されます。すべてハイパーリンクされており、使いやすいです。
DebugDiag は、可能ではあるが WinDbg では困難な、より複雑な分析の一部を自動化します (アプリケーション内の 350 のスレッドのどれがデッドロックの原因であるかを追跡するなど)。
注: セキュリティ上の理由から、Chrome では .mhtml ファイルをダウンロードしたり開いたりすることはできません。そのため、使用するには Internet Explorer または Microsoft Edge で開く必要があります。これは煩わしいので、DebugDiag チーム (dbgdiag@microsoft.com) に形式をプレーンな HTML に変更するよう要求しました。
!analyze -v
キーを押します。しばらくすると、WinDbg はクラッシュ コール スタックを吐き出し、問題の原因を推定します。デッドロックを分析している場合は、試すことができます!analyze -v -hang
。WinDbg は、関連する依存関係チェーンを表示することがよくあります。
この時点で、必要な情報がすべて揃っている可能性があります。ただし、Visual Studio デバッガーでプロセスの状態を調べたい場合は、次の追加の手順を実行できます。
注: 上記のすべてでは、正しいシンボル サーバー パスを構成する必要があります。そうしないと、コール スタックでシンボルを解決できません。_NT_SYMBOL_PATH 環境変数を設定して、Visual Studio、WinDbg、および DebugDiag で自動的に使用できるようにすることをお勧めします。
コールスタックに何が欠けていますか? 有効な関数名 (つまり、CFoo:Bar() ではなく 0x8732ae00) に解決されないアドレスがたくさんありますか? その場合、必要なのは、.PDB をデバッガーが見つけられる場所に配置するか、シンボル サーバーをセットアップして、モジュール ペインの右クリック コンテキスト メニューで [シンボル パス] を設定することです。
誰かが新しい Perforce チェンジリストをチェックインするたびに、すべてのバイナリからすべての .PDB を保存します。これにより、オフィス内の誰かまたは小売店の顧客からダンプが返されたときに、彼らがいたゲームのバージョンに対応する .PDB が得られます。ランニング。シンボル サーバーとパスを設定したら、.mdmp をダブルクリックするだけで、いつでも機能します。
または、関数が 1 つしかないように見えるコール スタックがありますか? 0x8538cf00 のように、スタック内でそれより上には何もありませんか? もしそうなら、あなたのクラッシュは実際にはスタック自体が壊れています。バックチェーンのリターン アドレスが上書きされた場合、当然、デバッガーはそれらを解決できなくなります。
また、ミニダンプを実際に発行するスレッドが、クラッシュの原因となった例外をスローしたスレッドではない場合もあります。[スレッド] ウィンドウを調べて、他のスレッドの 1 つに問題のあるコードが含まれているかどうかを確認します。
「リリース」ビルド (つまり、すべての最適化フラグをオンにしてコンパイルしたビルド) をデバッグしている場合は、デバッガーがローカル変数やその他のデータを見つけるのに苦労するという事実に対処する必要があります。これは、最適化をオンにするということは、コンパイラがデータをレジスタに保持し、計算を折りたたむことを可能にし、一般的に、データが実際にスタックに書き込まれないようにするさまざまなことを行うことを意味するためです。これが問題である場合は、逆アセンブリ ウィンドウを開いて手動でデータを追跡するか、デバッグ バイナリを再構築して問題を再現し、問題を確認する必要があります。
スタック ダンプが必要な場合は、フレーム ポインターの最適化をオフにします。フレーム ポインタは、スタックフレームを明示的に定義するために使用されます。それらがないと、デバッガーは各フレームの位置を推測する必要があります。
私はミニダンプを使用せず、スタックを「手動」でログファイルにダンプします ( www.ddj.com/cpp/185300443および Windows x64 でスタック フレームをログに記録する方法 を参照)。
あなたと同じような動作に遭遇します。有効な呼び出しスタックがある場合とない場合があります。まれに、スタックが実際に破損している可能性があります。すべてのケースの 1/3 では、インストールされた Exception ハンドラがまったく呼び出されません! Windowsの構造化された例外処理の問題だと思います。