[英]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
翻譯:
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.