共用方式為


模棱兩可的斷點解析

在調試程式引擎的 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 的方框。

適用於單一中斷點

解析不明確的中斷點運算式僅適用於執行中斷點命令,以在偵錯工具中設定單一中斷點。 換句話說,使用 bm 命令設置多個斷點將繼續正常工作。 在啟用此功能的情況下執行命令,將導致單個斷點的新的行為模式。

如需岔斷點指令的一般資訊,請參閱 bp、bu、bm (設定岔斷點)。

階層式中斷點

階層式岔斷點代表將不明確的岔斷點運算式解析為多個岔斷點的結果。 如果運算式產生兩個或多個用於設定中斷點的相符項目,則會建立另一個中斷點以控制中斷點集。 此覆寫中斷點,也稱為階層式中斷點,可啟用、停用、清除和列出,就像一般中斷點一樣,並且新增功能以在其所擁有的中斷點上執行相同的操作。

例如,如果執行指令 bp foo!bar,並且這導致符號 bar 有兩個相符項目,則會建立一個階層式岔斷點來控制這兩個相符項目。 如果階層已啟用/停用/清除,則相符的中斷點也會隨之而來。

.bpcmds(顯示斷點命令)將列出可以運行以設置每個斷點的斷點命令。 階層式中斷點所擁有的中斷點仍會列出有效的 bp 指令,該指令會在其位址上設定中斷點。 階層式岔斷點也會列在輸出中,並顯示可用來重新建立整組岔斷點的命令,而不僅僅是單一岔斷點。

模棱兩可的符號

如果符號是,則在符號名稱上設定中斷點應該會導致下列行為:

  • 多載:符合符號的每個多載都應該有一個中斷點。

  • 一個模板函數:

    • 如果運算式已指定所有範本引數(例如 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 會建立兩個中斷點,每個多載一個中斷點。 列出中斷點會產生下列輸出:

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結構

除錯器會使用符號索引來確保在源代碼行位移為零的多個位址中篩選出重複相符項目。

範本和多載函式的範例

範本函式

在定義範本函式的原始碼行上設定中斷點,會導致範本函式的每個實作都有中斷點。 給定第 19 BikeCatalog.cpp行的以下模板函數:

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` 會設定兩個中斷點,映射至檔案中稍後使用的範本函式實作。 相反地,如果使用者想要在函數上設定單一中斷點,則必須在範本函數實作的特定原始碼行上設定中斷點,或在範本函數的符號上設定中斷點,並具有適當的類型資訊 ( bp BikeCatalog::RegisterBike<int>例如 )。

列出中斷點會產生下列輸出:

0:000> bl
     2 e Disable Clear  <hierarchical breakpoint>     0001 (0001)  0:**** {BikeCatalog!BikeCatalog::RegisterBike&lt;int&gt;}
         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 *>

多載函數

在原始碼行上設定中斷點以定義多載函數,將導致該多載函數定義上只有一個岔斷點。 重複使用上面的程式碼片段,第一行從第 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` 會在行上設定單一岔斷點,以 void 實作 GetNumberOfBikes. 列出中斷點會產生下列輸出:

0:000> bl
     0 e Disable Clear  00007ff7`6b691ec0  [C:\BikeCatalog\BikeCatalog.cpp @ 9]     0001 (0001)  0:**** BikeCatalog!BikeCatalog::GetNumberOfBikes

內聯函數

在內嵌函式的呼叫站台的原始碼行上設定中斷點,會導致該特定呼叫站台上只有一個中斷點,即使相同函式中存在另一個呼叫站台也一樣。

多個階層式中斷點

階層式中斷點將擁有其集合中的每個中斷點,除非:

已清除其集合中的中斷點

  • 層次中斷點已被清除。
  • 會建立另一個階層式斷點,其中包含此階層式斷點集合中的斷點。

另一種思考方式是,岔斷點可能只有一個階層式岔斷點擁有者,而且最新的岔斷點指令會決定岔斷點清單的狀態。

此外,階層式岔斷點不能擁有另一個階層式岔斷點。

納入預先存在的岔斷點

如果岔斷點 A 本身存在,然後解析不明確的岔斷點運算式以建立岔斷點 AB,則 A 將併入與 B 一起設定的新岔斷點中。

包含階層式中斷點集交集

如果階層式岔斷點 A 擁有岔斷點 BC ,然後解析不明確的岔斷點表示式以建立岔斷點:

  • BCD:岔斷點 BC 會與岔斷點 D 結合新的階層式岔斷點群組,且階層式岔斷點 A 將會被清除。

  • CDBD:其中一個岔斷點會與岔斷點 D 結合新的階層式岔斷點群組,而階層式岔斷點 A 會繼續存在,且未加入新群組的剩餘一個岔斷點。

另請參閱

使用斷點

斷點語法

bp, bu, bm (設定斷點)

無法解析的斷點(未解斷點)