あいまいなブレークポイントの解決
デバッガー エンジンのバージョン 10.0.25310.1001 以降では、あいまいなブレークポイント解決がサポートされるようになりました。
あいまいなブレークポイントにより、ブレークポイント式が複数の場所に解決される特定のシナリオで、デバッガーがブレークポイントを設定できます。 たとえば、これは次の場合に起こります。
- 関数の複数のオーバーロード。
- ブレークポイント式に一致する複数のシンボルがある。
- 同じシンボル名が複数の場所に使用されている。
- シンボルがインライン化されている。
- ソース ウィンドウで複数のインスタンス化を使用してテンプレート関数にブレークポイントが設定されている。
有効にすると、デバッガーは、特定のブレークポイント式に一致する各シンボルにブレークポイントを設定します。 デバッガーは、特定の条件が満たされた場合にシンボルの一致もフィルター処理します。
ブレークポイントの使用に関する一般的な情報については、「ブレークポイントの使用」を参照してください。
あいまいなブレークポイントの解決の有効化
既定では、あいまいなブレークポイントは無効になっています。 デバッガー セッションでこれを有効にするには、WinDbg コンソールで次のコマンドを実行します。
dx @$debuggerRootNamespace.Debugger.Settings.EngineInitialization.ResolveAmbiguousBreakpoints = true;
あいまいなブレークポイントの設定がアクティブであることを確認するには:
0:010> dx @$debuggerRootNamespace.Debugger.Settings.EngineInitialization.ResolveAmbiguousBreakpoints
@$debuggerRootNamespace.Debugger.Settings.EngineInitialization.ResolveAmbiguousBreakpoints : true
dx コマンドの使用方法の詳細については、「dx (デバッガー オブジェクト モデル式の表示)」を参照してください。
この機能を無効にするには、上記の値を false
に設定します。 設定がセッション間で保持されるようにするには、必ず File -> Settings -> Debugger Settings
をクリックして、 Persist engine settings across debugger sessions
チェック ボックスをオンにしてください。
1 つのブレークポイントに適用される使用方法
あいまいなブレークポイント式の解決は、ブレークポイント コマンドを実行してデバッガーに 1 つのブレークポイントを設定する場合にのみ適用されます。 つまり、 bm
コマンドを使用して複数のブレークポイントを設定すると、通常どおりに動作し続けます。 この機能を有効にしてコマンドを実行すると、1 つのブレークポイントに対して新しいブレークポイント動作が発生します。
ブレークポイント コマンドに関する一般的な情報については、「bp、bu、bm (ブレークポイントの設定)」を参照してください。
階層ブレークポイント
階層ブレークポイントは、あいまいなブレークポイント式を複数のブレークポイントに解決した結果を表します。 式の結果、ブレークポイントの設定に使用される 2 つ以上の一致が発生した場合は、ブレークポイントの設定を制御する別のブレークポイントが作成されます。 このオーバーライド ブレークポイントである階層ブレークポイントは、通常のブレークポイントと同様に有効にする/無効にする、クリアするおよび一覧表示することができ、所有するブレークポイントに対して同じ操作を実行する機能が追加されています。
たとえば、コマンド bp foo!bar
が実行され、シンボル bar
に対して 2 つの一致が発生した場合、2 つの一致を制御する階層ブレークポイントが作成されます。 階層が有効/無効にされている場合やクリアされている場合も、一致したブレークポイントになります。
.bpcmds (ブレークポイント コマンドの表示) には、各ブレークポイントを設定するために実行できるブレークポイント コマンドが一覧表示されます。 階層ブレークポイントが所有するブレークポイントには、アドレスにブレークポイントを設定する有効な bp コマンドが引き続き一覧表示されます。 階層ブレークポイントも出力に一覧表示され、1 つのブレークポイントだけではなく、一連のブレークポイント全体を再作成するために使用できるコマンドが表示されます。
あいまいなシンボル
シンボル名にブレークポイントを設定すると、シンボルが次の場合に次の動作が発生します。
オーバーロード: シンボルに一致する各オーバーロードにはブレークポイントが必要です。
テンプレート関数:
式にすべてのテンプレート パラメーターが指定されている場合 (例:
bp foo!bar<int>
)、テンプレート関数の特定の実装にブレークポイントが設定されます。式に型の実装が指定されていない場合 (例:
bp foo!bar
)、ブレークポイントは設定されません。 この場合は、bm
を使用してテンプレート関数にブレークポイントを設定する必要があります。部分的なテンプレートの指定はデバッガーでサポートされていないため、その場合はブレークポイントは設定されません。
インライン関数: インライン化された各場所にブレークポイントがあります
デバッガーによるより多くの評価を必要とする演算子またはオフセットがシンボル式に含まれている場合、複数のブレークポイントは設定されないことに注意してください。 たとえば、シンボル foo
が複数の場所に解決され、式 foo+5
が評価される場合、デバッガーはブレークポイントを設定するすべての場所の解決を試みるわけではありません。
ブレークポイントのコード例
次のようなコード スニペットがあるものとします。
class BikeCatalog
{
public:
void GetNumberOfBikes()
{
std::cout << "There are 42 bikes." << std::endl;
}
int GetNumberOfBikes(int num)
{
std::cout << "There are " << num << " bikes." << std::endl;
return num;
}
};
コマンド bu BikeCatalog::GetNumberOfBikes
を呼び出すと、オーバーロードごとに 1 つずつ、2 つのブレークポイントが作成されます。 ブレークポイントを一覧表示すると、次の出力が生成されます。
0:000> bl
2 e Disable Clear <hierarchical breakpoint> 0001 (0001) 0:**** {BikeCatalog!BikeCatalog::GetNumberOfBikes}
0 e Disable Clear 00007ff6`c6f52200 [C:\BikeCatalog\BikeCatalog.cpp @ 13] 0001 (0001) 0:**** BikeCatalog!BikeCatalog::GetNumberOfBikes
1 e Disable Clear 00007ff6`c6f522a0 [C:\BikeCatalog\BikeCatalog.cpp @ 9] 0001 (0001) 0:**** BikeCatalog!BikeCatalog::GetNumberOfBikes
あいまいなソース行
ソース行にブレークポイントを設定すると、ソース行が次の場合に次の動作が発生します。
- コンパイラ最適化関数: コンパイラの最適化のために行が複数の場所に分割されている場合、指定した行に対応する関数内の最も低い場所にブレークポイントが設定されます。
- インライン関数: 指定された行がインライン化の一部として最適化されていない限り、呼び出しサイトごとにブレークポイントが設定されます。
- 複数の場所に解決: 上記の条件が満たされていない場合は、次の条件を持つアドレスごとにブレークポイントが設定されます。
- 式のソース行に一致する N 個のアドレスのセットがあり、これらの N 個のアドレスのサブセット M に式のソース行からのソース行の変位がゼロの場合、 M アドレスのみがブレークポイントを持ちます。
- 式のソース行からのソース行の変位がゼロの N 個のアドレスのセットにアドレスがない場合、すべての N 個のアドレスにブレークポイントが設定されます。
シンボル インデックスに基づくフィルター処理
各シンボルには、一意のシンボル インデックスが必要です。 シンボルの構造の詳細については、「SYMBOL_INFO 構造」を参照してください。
デバッガーはシンボル インデックスを使用して、ソース行の変位がゼロの複数のアドレスが発生した場合に重複する一致がフィルター処理されるようにします。
テンプレート関数とオーバーロードされた関数の例
テンプレート関数
テンプレート関数の定義のソース行にブレークポイントを設定すると、テンプレート関数の実装ごとにブレークポイントが作成されます。 BikeCatalog.cpp
の 19 行目に次のテンプレート関数があるものとします。
template <class T>
void RegisterBike(T id)
{
std::cout << "Registered bike " << id << std::endl;
}
その使用方法:
catalog.RegisterBike("gravel bike");
catalog.RegisterBike(1234);
コマンド bp `BikeCatalog.cpp:19`
を呼び出すと、ファイルの後半で使用されるテンプレート関数の実装に解決される 2 つのブレークポイントが設定されます。 代わりに、ユーザーが関数に 1 つのブレークポイントを設定する場合は、テンプレート関数の実装の特定のソース行にブレークポイントを設定するか、適切な型情報 (例: bp BikeCatalog::RegisterBike<int>
) を使用してテンプレート関数のシンボルにブレークポイントを設定する必要があります。
ブレークポイントを一覧表示すると、次の出力が表示されます。
0:000> bl
2 e Disable Clear <hierarchical breakpoint> 0001 (0001) 0:**** {BikeCatalog!BikeCatalog::RegisterBike<int>}
0 e Disable Clear 00007ff7`6b691dd0 [C:\BikeCatalog\BikeCatalog.cpp @ 20] 0001 (0001) 0:**** BikeCatalog!BikeCatalog::RegisterBike<int>
1 e Disable Clear 00007ff7`6b691e60 [C:\BikeCatalog\BikeCatalog.cpp @ 20] 0001 (0001) 0:**** BikeCatalog!BikeCatalog::RegisterBike<char const *>
オーバーロードされた関数
オーバーロードされた関数の定義のソース行にブレークポイントを設定すると、オーバーロードされた関数のその定義に対するブレークポイントは 1 つだけになります。 5 行目から始まる最初の行で、上記のコード スニペットを再利用します。
class BikeCatalog
{
public:
void GetNumberOfBikes()
{
std::cout << "There are 42 bikes." << std::endl;
}
int GetNumberOfBikes(int num)
{
std::cout << "There are " << num << " bikes." << std::endl;
return num;
}
};
コマンド bp `BikeCatalog.cpp:9`
を呼び出すと、 GetNumberOfBikes
の void
実装の行に 1 つのブレークポイントが設定されます。 ブレークポイントを一覧表示すると、次の出力が表示されます。
0:000> bl
0 e Disable Clear 00007ff7`6b691ec0 [C:\BikeCatalog\BikeCatalog.cpp @ 9] 0001 (0001) 0:**** BikeCatalog!BikeCatalog::GetNumberOfBikes
インライン関数
インライン関数の呼び出しサイトのソース行にブレークポイントを設定すると、同じ関数に別の呼び出しサイトが存在する場合でも、その特定の呼び出しサイトにブレークポイントが 1 つだけ発生します。
複数の階層ブレークポイント
階層ブレークポイントは、次の場合を除き、セット内のすべてのブレークポイントを所有します。
セット内のブレークポイントがクリアされる
- 階層ブレークポイントがクリアされます。
- この階層ブレークポイントのセットにブレークポイントを含む別の階層ブレークポイントが作成されます。
これについて考えるもう 1 つの方法は、ブレークポイントに階層ブレークポイント所有者が 1 つだけ存在することがあり、最新のブレークポイント コマンドによってブレークポイント リストの状態が決まるということです。
さらに、階層ブレークポイントは別の階層ブレークポイントを所有することはできません。
既存のブレークポイントを組み込む
ブレークポイント A が単独で存在し、あいまいなブレークポイント式が解決されてブレークポイント A、 B が作成された場合、 A は B で設定された新しいブレークポイントに含まれます。
階層ブレークポイント セットの交差を組み込む
階層ブレークポイント A がブレークポイント B、 C を所有し、あいまいなブレークポイント式が解決されてブレークポイントが作成される場合:
B、 C、 D: ブレークポイント B、 C は新しい階層ブレークポイント グループをブレークポイント D に結合させ、階層ブレークポイント A はクリアされます。
C、 D または B、 D: ブレークポイントの 1 つは新しい階層ブレークポイント グループをブレークポイント D に結合させ、階層ブレークポイント A は新しいグループに参加していない残りの 1 つのブレークポイントと共に存在し続けます。