9

多くの場合、クラッシュを再現できるWindowsでクラッシュするC ++プログラムをデバッグする必要がありますが、コード内のどの命令シーケンスがクラッシュを引き起こしたかを判断するのは困難です(たとえば、クラッシュするスレッドのメモリを上書きする別のスレッド)。その場合、コールスタックでさえ役に立ちません。通常、私はソースコードのセクションをコメントアウトすることでクラッシュの原因を絞り込むことに頼っていますが、これは非常に面倒です。

クラッシュの直前にすべてのスレッドで実行された最後の数行のソースコード行またはマシンコード命令をレポートまたは再生できるWindows用のツールを知っている人はいますか?つまり、gdbの逆デバッグ機能や、MutekのBugTrapper(現在は使用できません)のようなものです。リリースされた安定したツールを探しています(SoftwareVerifyの「BugValidator」とHexrayのIDA Pro 6.3 Trace Replayerを知っていますが、どちらもまだクローズドベータプログラムです)。

私がすでに試したのはWinDbgトレースコマンドwtta @$raですが、どちらのコマンドにも数秒後に自動的に停止するという欠点があります。クラッシュが発生するまで実行され、実行中のプログラムのすべてのスレッドをトレースするトレースコマンドが必要です。

注: gflags、pageheap、Memory Validator、Purifyなど、特定の問題を修正するために設計されたデバッグツールを探していません。命令レベルでトレースまたは再生するためのリリースされた安定したツールを探しています

4

6 に答える 6

9

直面した場合は、 gflagsGFlagsおよびPageHeapanother thread overwriting memory of the crashing thread )を使用すると便利です。クラッシュする前に実行された数行を通知する代わりに、アルゴリズムが正しく割り当てられたメモリブロックを上書きした場所を正確に通知します。

最初に、このタイプのチェックをアクティブにします。

gflags /p /enable your_app.exe /fullまた
gflags /p /enable your_app.exe /full /backwards

正しくアクティブ化されていることを確認してください
gflags /p

アプリケーションを実行し、ダンプファイルを収集します

次に、gflagsによるチェックを無効にします。

gflags /p /disable your_app.exe


アップデート1

It does not immediately detect problems like *p = 0; where p is an invalid pointer
少なくともいくつかの問題が検出されました。
例えば:

#include <stdio.h>
int main(int argc, char *argv[])
{
  int *p = new int;
  printf("1) p=%p\n",p);
  *p = 1;
  delete p;
  printf("2) p=%p\n",p);
  *p = 2;
  printf("Done\n");
  return 0;    
}

gflagsを有効にして実行すると、ダンプファイルが取得され、問題が正しく識別されます。

STACK_TEXT:  
0018ff44 00401215 00000001 03e5dfb8 03dfdf48 mem_alloc_3!main+0x5b [c:\src\tests\test.cpp\mem_alloc\mem_alloc\mem_alloc.3.cpp @ 11]
0018ff88 75f8339a 7efde000 0018ffd4 77bb9ef2 mem_alloc_3!__tmainCRTStartup+0x10f [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 586]
0018ff94 77bb9ef2 7efde000 2558d82c 00000000 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77bb9ec5 004013bc 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 004013bc 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:  
     7:   printf("1) p=%p\n",p);
     8:   *p = 1;
     9:   delete p;
    10:   printf("2) p=%p\n",p);
>   11:   *p = 2;
    12:   printf("Done\n");
    13:   return 0;
    14: 
    15: }


アップデート2

@fmunkertからの別の例:

#include <stdio.h>

int main()
{

        int *p = new int;  
        printf("1) p=%p\n",p);  
        *p = 1;  
        p++;
        printf("2) p=%p\n",p);
        *p =  2;   // <==== Illegal memory access
        printf("Done\n");  
        return 0;

}

gflags /p /enable mem_alloc.3.exe /full /unaligned

STACK_TEXT:  
0018ff44 00401205 00000001 0505ffbe 04ffdf44 mem_alloc_3!main+0x52 [c:\src\tests\test.cpp\mem_alloc\mem_alloc\mem_alloc.3.cpp @ 12]
0018ff88 75f8339a 7efde000 0018ffd4 77bb9ef2 mem_alloc_3!__tmainCRTStartup+0x10f [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 586]
0018ff94 77bb9ef2 7efde000 2577c47c 00000000 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77bb9ec5 004013ac 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 004013ac 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:  
     8:         printf("1) p=%p\n",p);  
     9:         *p = 1;  
    10:         p++;
    11:         printf("2) p=%p\n",p);
>   12:         *p =  2;   // <==== Illegal memory access
    13:         printf("Done\n");  
    14:         return 0;
    15: 
    16: }

残念ながら、/ unalignedオプションを使用すると、プログラムが正しく動作しない可能性があります(Pageheap.exeの使用方法)。

一部のプログラムは、8バイトのアラインメントについて想定しており、/unalignedパラメーターで正しく機能しなくなります。Microsoft Internet Explorerは、そのようなプログラムの1つです。

于 2012-06-06T11:05:39.240 に答える
5

解決策を見つけました。VMwareWorkstationとVisualStudio2010を使用した「リプレイデバッグ」です。セットアップには多くの時間がかかりますが、時間の経過とともに逆方向にデバッグできるVisual StudioC++デバッガーが提供されます。これは、リプレイデバッグがどのように機能するかを示すビデオです:http://blogs.vmware.com/workstation/2010/01/replay-debugging-try-it-today.html

このソリューションの欠点は、VMwareが最新のVMwareバージョンでリプレイデバッグを中止したように見えることです。さらに、特定のプロセッサタイプのみが再生をサポートしているようです。サポートされているプロセッサの包括的なリストは見つかりませんでした。3台のPCで再生機能をテストしました。Corei7200では再生が機能しませんでした。再生は、Core26700およびCore2Q9650で機能しました。

VMwareが将来のVMwareWorkstationバージョンでリプレイデバッグを再検討し、再び導入することを心から望んでいます。これにより、デバッグに新しい次元が実際に追加されるからです。

興味のある方のために、リプレイデバッグ用の環境を設定する方法について説明します。

以下の説明で、「ローカルデバッグ」とは、VisualStudioとVMwareが同じPCにインストールされていることを意味します。「リモートデバッグ」とは、VisualStudioとVMwareが異なるPCにインストールされていることを意味します。

  • Visual Studio 2010withSP1をホストシステムにインストールします。

  • VisualStudioがMicrosoftのシンボルサーバーを使用するように構成されていることを確認してください。([ツール]|[オプション]|[デバッグ]|[シンボル]の下)。

  • ホストシステムに「Windows用デバッグツール」をインストールします。

  • VMwareWorkstation7.1をインストールします。(バージョン8.0には、リプレイデバッグ機能が含まれていません)。これにより、プラグインもVisualStudioにインストールされます。

  • Windows XP SP3を使用してVMwareに仮想マシン(VM)をインストールします。

  • テスト対象のアプリケーションがデバッグビルドの場合は、VisualStudioデバッグDLLをVMにインストールします。(これを行う方法については、 http://msdn.microsoft.com/en-us/library/dd293568.aspxを参照してください。ただし、「リリース」ではなく「デバッグ」構成を使用してください)。

  • ホストの「Windows用デバッグツール」ディレクトリからVMに「gflags.exe」をコピーし、VMでgflags.exeを実行し、「システムレジストリ」タブで「カーネルスタックのページングを無効にする」を選択して「OK」を押します。VMを再起動します。

  • テスト対象のアプリケーションのすべてのEXEファイルとDLLファイルをVMにコピーし、アプリケーションを起動して問題を再現できることを確認します。

  • VMをシャットダウンし、スナップショットを作成します(VMware Workstationのコンテキストメニュー項目[スナップショットを作成]を使用)。

  • (リモートデバッグの場合のみ:) Visual Studio PCで次のコマンドを開始し、任意のパスコードを入力します。

    C:\ Program Files \ VMware \ VMware Workstation \ Visual Studio Integrated Debugger\dclProxy.exeホスト名

    ホスト名をPCの名前に置き換えます。

  • (リモートデバッグの場合のみ:)VMの記録を手動で作成します。つまり、VMのオペレーティングシステムにログインし、(コンテキストメニューの[記録]を使用して)記録を開始し、テスト対象のアプリケーションを実行して、問題を再現するために必要なアクションを実行します。次に、記録を停止して保存します。

  • Visual Studioを起動し、[VMware|オプション|VMでのデバッグの再生|一般]に移動して、次の値を設定します。

    • 「ローカルまたはリモート」は、ローカルデバッグの場合は「ローカル」に、リモートデバッグの場合は「リモート」に設定する必要があります。
    • 「仮想マシン」は、VMの.vmxファイルへのパスに設定する必要があります。
    • 「RemoteMachionePasscode」は、上記で使用したパスコードに設定する必要があります(リモートデバッグの場合のみ)。
    • 「RecordingtoReplay」は、以前にVMwareで作成した録音名に設定する必要があります。
    • 「ホスト実行可能検索パス」は、テスト対象のアプリケーションに必要であり、VisualStudioが正しいスタックトレースを表示するために必要なDLLを保存するディレクトリに設定する必要があります。

    「適用」を押します。

  • 「VMware|オプション|VMでのデバッグの再生|イベントの事前記録」に移動し、次の値を設定します。

    • 「記録用のベーススナップショット」:以前に作成されたスナップショットの名前。

    「OK」を押します。

  • (ローカルデバッグの場合:) Visual Studioで、[VMware|再生用の記録の作成]を選択します。これにより、VMが再起動します。VMにログインし、テスト対象のアプリケーションを実行して、問題を再現するために必要なアクションを実行します。次に、記録を停止して保存します。

  • 「VMware|リプレイデバッグの開始」を選択します。VMwareは、テスト対象のVMとアプリケーションを自動的に再起動し、記録されたアクションを再生するようになりました。アプリケーションがクラッシュするまで待ちます。その後、VisualStudioデバッガーが自動的にアクティブになります。

  • Visual Studioデバッガーで、アプリケーションがクラッシュする前にあったと思われる場所にブレークポイントを設定します。次に、「VMware|ReverseContinue」を選択します。これで、デバッガーはブレークポイントまで逆方向に実行されます。ブレークポイントに到達するまでVMが再起動および再生されるため、この操作には時間がかかる場合があります。(シナリオを記録するときにクラッシュが発生する数秒前にスナップショットを追加することで、この操作を高速化できます。リプレイのデバッグ中にスナップショットを追加できます。)

  • VMwareがVMをブレークポイントまで再生したら、「ステップオーバー」と「ステップイン」を使用してブレークポイントから進むことができます。つまり、記録されたイベントの履歴を再生して、理由を特定できるようになります。アプリケーションがクラッシュしました。

詳細情報: http: //www.replaydebugging.com/

于 2012-06-07T01:14:31.790 に答える
2

BMCのAppSightを使用してみませんか?

以前の会社で使用し(名前を覚えるのに時間がかかりました)、クラッシュなどの調査に使用しました。ISTRを実行してからソフトウェアを実行すると、発生したすべてのことがログファイルに記録されました。後で見ることができます。

それは私がそれを使用したものであるため、それは間違いなくWindowsで動作します。

それはあなたが探しているものかもしれませんか?

于 2012-06-14T11:10:35.183 に答える
2

プログラムの実行中にWinDbgをアタッチし、クラッシュまたは例外でデバッグが中断したときにミニダンプを実行します。

.dump /ma c:\mem.dmp // c:\mem.dmp could be any other location you desire

WinDbg内のコマンドラインから、アプリのgflagsを有効にします。

!gflag +ust

後でこのフラグを削除することを忘れないでください!!

次に、自動実行分析を実行できます。

!analyze -v

これにより、クラッシュの原因と思われるものがわかる場合があります。すべてのスレッドの呼び出しスタックをダンプできます。

~* kb

疑わしい点があれば、スレッドを切り替えてさらに調べることができます。

~x s

例外コンテキストレコードを検査できます。

.ecxr

キャッチブロックからコールスタックを回復する方法についての良いリンクがあります:http://blogs.msdn.com/b/slavao/archive/2005/01/30/363428.aspxそしてこれも:http:// blogs.msdn.com/b/jmstall/archive/2005/01/18/355697.aspx

ここでの主なことは、windbgを接続すると、すべてのスレッドとコールスタックの状態を検査できるはずです。また、Visual Studioでミニダンプを開くこともできます: http://msdn.microsoft.com/en-us/ library / windows / desktop / ee416349%28v = vs.85%29.aspx#Analysis_of_a_minidumpナビゲートにビジュアルスタジオを使用する場合は、windbgで同じダンプを開いて、分析用のツールとコードをナビゲートするためのビジュアルスタジオを使用できます。お役に立てれば。

于 2012-06-06T12:15:27.210 に答える
1

gdbはこの機能をすぐに提供しませんか?

使用してからしばらく経ちましたが、クラッシュするまでプログラムを実行し、デバッガーで手順を再生できたことを思い出します。

また、選択した任意の量のデータを出力でき、exeへのコマンドラインパラメータによってアクティブ化できる独自のログアプリケーションをセットアップするのは簡単です。

今すぐ設定して、発生しているクラッシュに対処するか、基本をカバーしてから、バグを修正したり、新しい機能を追加したりして拡張することができます。利点は、有用だと思うデータを正確にキャプチャでき、ノイズに圧倒されないようにログのレベルを指定できることです。

于 2012-06-12T12:57:12.743 に答える
-1

これが必要かどうかは完全にはわかりませんが、「u」は現在のスレッドの現在のIPレジスタから最後の命令を逆アセンブルします。これにより、最後に実行された命令が表示されます。通常、逆アセンブルするコードをたどることで、さまざまなレジスタの値を把握できます。ほとんどの場合、これは遅くて難しいプロセスですが、今起こったことをほぼ100%の精度で(いくつかの奇妙なハードウェアの問題や本当に奇妙なコードの問題を除いて)提供します。私は過去にこの方法を使用して、ソースコードがないときに特定のものが無効になった理由を理解しました。

windbgヘルプファイルをチェックすると、詳細情報が見つかります。

于 2012-06-15T04:06:26.780 に答える