23
Visual C++ 6.0 デバッグ テクニック Developer Product Marketing Visual C++ Product Manager Tatsuhiko Tanaka Microsoft,KK

[1999/06/10] VCDC Plus 1999 Jun / Visual C++ 6.0 デバッグ テクニック

Embed Size (px)

Citation preview

Visual C++ 6.0

デバッグ

テクニック

Developer Product Marketing

Visual C++ Product Manager

Tatsuhiko Tanaka

Microsoft,KK

Agenda

ステップイン回避

ブレークポイント

タイミングコード

エディット・コンティニュー

マルチスレッドデバッグ

モジュール一覧

その他

注意:アンドキュメント情報について

Visual C++ 6.0のみで有効

文書化されていない

テストされていない

テクニカルサポートなし

次バージョンに組み込まれるとは限らない

正常に動作する保証なし

ステップイン回避

特定のコードへのステップインを回避

例えば、コンストラクタやオペレータ、必要のないモジュールなどへのステップインを回避可能

autoexp.datを編集

[ExecutionControl]セクションを追加

次のような行を追加

functionname=NoStepInto

アンドキュメント情報

ステップイン回避

MFCでの例[ExecutionControl]

CString::CString=NoStepInto

CString::operator==NoStepInto

関数名で指定

ユーザ関数も指定可能

統合開発環境の起動時に情報を読み込む

アンドキュメント情報

システムへのブレークポイント

Windows NTのみ(Windows 9xでは禁じられている)

DLLを特定する

lib¥win32api.csv の中からブレークポイントを設定するAPIが含まれるDLLを探す

完全な名前を特定する

デバッグ情報なし:dumpbin /exports name.dll | findstr CreateFile (オプションの変更が必要)

デバッグ情報あり:dumpbin /symbols name.dbg | findstr CreateFile

システムへのブレークポイント

ブレークポイントを {,,dllname} function に設定する

例: デバッグ情報なし デバッグ情報あり

{,,kernel32.dll} CreateFileA _CreateFileA@28

{,,user32.dll} MessageBoxA _MessageBoxA@16

引数の値によってブレークさせる場合

ブレークポイントを上記のように設定する

引数の位置によるスタックのオフセットを計算する

ブレークの条件を以下のように設定する

例: dw esp + 0x8 == 0xffffffff

データ ブレークポイント

一般的な例1:0x12345678が変更されたときに停止する場合

*(long *)0x12345678, length = 1

一般的な例2:m_memberが変更されたときに停止する場合

コードのエミュレーションを行うので、遅くなる

遅くならないためには、m_menberのアドレスを取得して使用する

*(long *)<m_memberのアドレス>

カウント ブレークポイント

もし15回目のコールで問題が発生する場合、ブレークポイントのスキップカウントを 15 - 1 に設定する

もし回数がわからない場合は、以下の方法で回数を特定する

スキップカウントに大きな数値を入れる

例:10000 (C)

アプリケーションを問題が発生するまで実行する

スキップカウントの残数を控える (X)

スキップカウントに C - X - 1 を入れて再実行する

タイミングコード

擬似レジスタ@clk

ウオッチウィンドウに @clk を追加し、ゼロに初期化する

ステップするごとに掛かった時間をナノセコンド単位で表示する

アセンブラレベルのステップでは正確ではない

デバッガ自体のオーバーヘッドがあるため

アンドキュメント情報

エディット・コンティニュー

デバッグ中にソースの修正が可能

リビルド、リスタートの必要なし

デバッグ時間の大幅な短縮

/ZI コンパイラスイッチにより使用可能

デフォルトでオン

デバッグ命令を実行したときに自動的に起動

実行、ステップインなどの命令で起動する

オプションで自動起動をオフにできる

エディット・コンティニュー

エディット・コンティニュー診断メッセージ

エディット・コンティニューの際に表示される情報のレベルをレジストリによって変更可能

以下のレジストリを変更HKEY_CURRENT_USER¥Software¥Microsoft¥DevStudio¥6.0¥Debug¥ENCTraceLevel

レベル 診断情報

0 フィードバックなし

1 メッセージ、エラー

2 メッセージ、エラー、警告 (デフォルト)

3 トレース情報、メッセージ、エラー、警告

エディット・コンティニュー

テクニック

Alt + F10 で実行中のアプリケーションに適用

アプリケーションのブレークを行う必要なし

外部プロジェクトのコードの変更

外部のプロジェクトに対して、プロジェクトを読み込まなくてもエディット・コンティニューを適用可能

[次に実行するステートメント]の併用

EIPを変更させることにより、通過してしまったコードを再検証可能

エディット・コンティニュー

エディットコンティニューの制限

リソースファイルの変更

読取専用ファイルの変更

最適化されたソースコードの変更

例外処理ブロックの変更

新しいデータ型の追加、またはデータ型の変更

関数の削除、または関数プロトタイプの変更

グローバルまたはスタティックコードの変更

50ファイル以上のコンパイルが必要となる場合

新しいソースファイルの追加 など

マルチスレッドデバッグ

自分がどのスレッドかを知る方法

Thread ID は、

Windows NT 4.0の場合:dw @tib + 0x24

Windows 9xの場合:FS レジスタ

マルチスレッドデバッグ

スレッド名の設定と表示

後述のSetThreadName()を使用することにより、スレッドに名前を付けることが可能

名前は最大9文字まで

名前はスレッドダイアログに表示される

アンドキュメント情報

マルチスレッドデバッグSetThreadName

Usage:

SetThreadName(DWORD ThreadID, const char *szName, DWORD dwReserved);

dwReservedにはゼロを設定する

任意のスレッドに設定可能

最後の設定した名前が有効になる

アンドキュメント情報

typedef struct tagTHREADNAME_INFO

{

DWORD dwType; // must be 0x1000

LPCSTR szName; // pointer to name

DWORD dwThreadID; // thread ID

DWORD dwFlags; // reserved for future use, must be zero

}THREADNAME_INFO;

void SetThreadName(DWORD dwThread, LPCSTR szThreadName, DWORD dwFlags)

{

THREADNAME_INFO info;

info.dwType = 0x1000;

info.szName = szThreadName;

info.dwThreadID = dwThread;

info.dwFlags = dwFlags;

__try

{

RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info);

}

__except(EXCEPTION_CONTINUE_EXECUTION)

{

}

}

マルチスレッドデバッグSetThreadName.cpp アンドキュメント情

モジュール一覧

[デバッグ|モジュール]でダイアログ表示

現在の実行中のモジュールを表示する

Orderをクリックすることにより、読み込まれた順に表示可能 (デフォルト)

クラッシュ時のアドレスから、モジュールを特定可能

どのDLLでクラッシュしているかを容易に知ることができる

ウオッチ変数の書式指定記号

ウオッチウィンドウでカンマのあとに指定記号 形式 例

d 符号付10進整数 1234

s 文字列 "Hello world"

su Unicode文字列 "Hello world"

hr HRESULTまたは S_OK

Win32エラーコード

wc ウィンドウクラスフラグ WC_DEFAULTCHAR

wm Windowsメッセージ番号 WM_CLOSE

エラー情報の取得

擬似レジスタ@err

現在のスレッドの最新エラーコードを表示

ウオッチウィンドウで使用可能

GetLastError関数が返す値と同じ

修飾子 hr を指定することによりエラーメッセージを表示

リリースビルドで動かない場合(デバッグビルドでは動作する)

/GZ オプションを使用

ローカル変数の自動初期化 (0xCC の書き込み)

関数ポインタコールスタックの正当性チェック

コールスタックの正当性チェック

Questions&

Answers