x86 実行可能ファイルでヒットした基本ブロックをログに記録する小さなコード カバレッジ ユーティリティを作成しました。ターゲットのソース コードやデバッグ シンボルなしで実行され、監視対象の基本ブロックが失われるだけです。
しかし、単一の実行可能イメージのカバレッジ スナップショットが繰り返される私のアプリケーションでは、これがボトルネックになりつつあります。
スピードアップを試みたので、いくつかの段階を経ました。各基本ブロックの先頭に INT3 を配置し、デバッガーとしてアタッチし、ヒットをログに記録することから始めました。次に、5 バイト (JMP REL32 のサイズ) より大きい任意のブロックにカウンターをパッチすることで、パフォーマンスを改善しようとしました。プロセス メモリ空間に小さなスタブ ('mov [blah], 1 / jmp backToTheBasicBlockWeCameFrom') を書き、それに JMP をパッチしました。例外もデバッガーの中断もないため、これにより大幅に高速化されますが、さらに高速化したいと考えています。
以下のいずれかを考えています。
1) パッチを適用したカウンターを使用してターゲット バイナリを事前にインストルメント化します (現時点では実行時にこれを行います)。PE に新しいセクションを作成し、そこにカウンターを投入し、必要なすべてのフックにパッチを適用してから、各実行後にデバッガーを使用して同じセクションからデータを読み取るだけです。これにより、ある程度の速度が向上します (私の推定では約 16%) が、小さなブロックに必要な厄介な INT3 がまだ残っており、実際にはパフォーマンスが低下します。
2) 独自の UnhandledExceptionFilter を含めるようにバイナリを計測し、上記と組み合わせて独自の int3 を処理します。これは、すべての int3 でデバッグ対象からカバレッジ ツールへのプロセス切り替えがないことを意味しますが、それでもブレークポイント例外が発生し、その後のカーネル移行が発生します。
3) Intel のハードウェア ブランチ プロファイリング命令を使用して、巧妙なことを試みます。これはかなり素晴らしいように聞こえますが、どうすればよいかわかりません.Windowsユーザーモードアプリケーションでも可能ですか? カーネル モード ドライバーがかなり簡単であれば、そこまで書くこともあるかもしれませんが、私はカーネル コーダーではなく (少し手を出します)、おそらく多くの頭痛の種になるでしょう。このアプローチを使用する他のプロジェクトはありますか? Linux カーネルにはカーネル自体を監視する機能があるようですが、特定のユーザーモード アプリケーションを監視するのは難しいと思います。
4) 市販のアプリケーションを使用します。ソースやデバッグ シンボルなしで動作し、スクリプト可能 (バッチで実行できるようにするため) である必要があり、できれば無料 (私はかなりけちです) である必要があります。ただし、有償のツールを検討する必要はありません (ツールへの支出を減らし、新しいハードウェアの購入を避けるのに十分なだけパフォーマンスを向上させることができれば、それは正当な理由になります)。
5) その他。かなり古いハードウェア (Pentium 4 っぽい) で Windows XP 上の VMWare を実行しています。JMP REL32 を 5 バイト未満にすることはできますか (そして、int3 を必要とせずに小さなブロックをキャッチできますか)?
ありがとう。