簡體   English   中英

在Windbg中,拋出特定的C ++異常時可以跳過中斷嗎?

[英]In Windbg, can I skip breaking when specific C++ exceptions are thrown?

在Visual Studio中,通過“調試”>“異常...”中的對話框,可以將特定的C ++異常類型設置為中斷或跳過。 在Windbg中,使用sxe eh啟用破壞C ++異常的功能全有或全無。

有什么方法可以跳過對特定C ++異常類型的破壞嗎? 反過來說,有沒有辦法打破特定類型呢?

注意:這個答案是特定於32位的,因為我還沒有做太多的64位調試。 我不知道有多少適用於64位。

假設以下代碼:

class foo_exception : public std::exception {};

void throw_foo()
{
    throw foo_exception();
}

並假設您已為C ++異常打開了突發機會異常: sxe eh

現在,當調試器中斷時,您的異常記錄將位於堆棧的頂部。 因此,如果您只想查看類型是什么,則可以顯示異常記錄信息:

0:000> .exr @esp
ExceptionAddress: 751dc42d (KERNELBASE!RaiseException+0x00000058)
   ExceptionCode: e06d7363 (C++ EH exception)
  ExceptionFlags: 00000001
NumberParameters: 3
   Parameter[0]: 19930520
   Parameter[1]: 0027f770
   Parameter[2]: 0122ada0
  pExceptionObject: 0027f770
  _s_ThrowInfo    : 0122ada0
  Type            : class foo_exception
  Type            : class std::exception

看一下當前堆棧,您可以看到這些東西所在的位置:

0027f6c4  e06d7363
    0027f6c8  00000001
    0027f6cc  00000000
    0027f6d0  751dc42d KERNELBASE!RaiseException+0x58
    0027f6d4  00000003
    0027f6d8  19930520
    0027f6dc  0027f770
    0027f6e0  0122ada0 langD!_TI2?AVfoo_exception
    ...

因此,在此示例中,異常本身位於0027f770 ,如pExceptionObject旁邊的.exr輸出pExceptionObject 並且您可以在堆棧上看到該值0027f6dc ,或者從堆棧頂部偏移0x18,即@esp+18 讓我們看看調試器告訴我們有關該位置的信息。

0:000> dpp @esp+18 L1
0027f6dc  0027f770 01225ffc langD!foo_exception::`vftable'

該命令表示:起始於@esp+18 ,d UMP一個p ointer尺寸值,然后DEREF發現有作為p ointer,太值,並寫匹配第二地址的任何符號的名稱。 在這種情況下,它找到了foo_exception類的vtable。 這告訴我們地址0027f770的對象是foo_exception 而且我們可以使用該信息為條件斷點創建表達式。

我們需要一種直接獲取vtable地址的方法,如下所示:

@!"langD!foo_exception::`vftable'"

由於反引號和撇號,我們必須引用它。 我們還需要提取所需的堆棧值:

poi(poi(@esp+18))

poi運算符獲取一個地址,並返回存儲在那里的指針大小的值。 第一次評估將堆棧地址轉換為對象地址,第二次評估將對象地址轉換為vtable地址,我們需要進行比較。 整個條件如下所示:

@!"langD!foo_exception::`vftable'" == poi(poi(@esp+18))

現在,我們可以確定它是否是foo_exception ,我們可以通過設置一個命令來在調試程序因C ++異常而中斷時自動運行來跳過中斷它們:

sxe -c".if ( @!\"langD!foo_exception::`vftable'\" == poi(poi(@esp+18)) ) {gc}" eh

翻譯:

  • 打破C ++異常的第一次機會,並運行以下命令:
  • foo_exception vtable地址與@esp+18處的對象的vtable地址進行比較
  • 如果它們相同,則發出gc命令,如果到達該命令時調試器正在運行,它將繼續運行
  • (不要忘記轉義內部引號)

如果你想只有打破了foo_exception ,病情從變化==!=

需要記住的是,有時會將異常作為指針而不是按值拋出,這意味着在表達式的@esp部分周圍還需要一個poi() 您將能夠知道,因為當您使用.exr轉儲異常記錄時, Type將為class foo_expression * 這完全取決於引發異常的代碼,而不是引發異常類型本身的代碼,因此您可能需要為.if定制.if-條件。

最后,如果您想中斷或跳過幾種異常類型,則可行。 我建議使用鏈接的.if.elsif命令編寫腳本.elsif sxe自動命令設置為$$><path\\to\\script 在一條線上執行大量的if條件鏈接可能很難閱讀和正確處理,尤其是在進行額外轉義時。 腳本不需要多余的轉義。 這是一個小例子:

.if ( @!"langD!foo_exception::`vftable'" == poi(poi(@esp+0x18)) )
{
    $$ skip foo_exceptions
    gc
}
.elsif ( @!"langD!bar_exception::`vftable'" == poi(poi(@esp+0x18)) )
{
    $$ dump the exception to see the error message, then continue running
    dt poi(@esp+18) langD!bar_exception
    gc
}
.elsif ( @!"langD!baz_exception::`vftable'" == poi(poi(@esp+0x18)) )
{
    $$ show the top 10 frames of the stack and then break (because we don't `gc`)
    kc 10
}

(注意:Windbg每次運行時都會抱怨腳本錯誤,因為它不喜歡gc命令后跟其他任何命令。但是它仍然可以正常運行)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM