gpt4 book ai didi

c++ - 在 Windbg 中,我可以在抛出特定 C++ 异常时跳过中断吗?

转载 作者:搜寻专家 更新时间:2023-10-31 01:02:55 25 4
gpt4 key购买 nike

在 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    ...

So the exception itself is sitting at 0027f770 in this example, as you can see from the .exr output next to pExceptionObject. And you can see that value on the stack at 0027f6dc, or offset from the top of the stack by 0x18, so @esp+18. Let's see what the debugger tells us about that location.

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

这个命令说:开始于 @esp+18 , dump 一个 pointer 大小的值,然后将在那里找到的值也取消引用为 pointer,并写下任何的名称与第二个地址匹配的符号。在本例中,它找到了 foo_exception 的 vtable类(class)。这告诉我们地址为 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 , 将条件从 == 更改为至 != .

要记住的是,有时异常会作为指针而不是值抛出,这意味着您还需要一个 poi() @esp周围表达的一部分。您将能够分辨出来,因为当您使用 .exr 转储异常记录时, Type将是 class foo_expression * .这完全取决于抛出异常的代码而不是异常类型本身,因此您可能需要定制您的 .if -情况的条件。

最后,如果你想中断或跳过几种异常类型,这是可行的。我会建议 writing a script用链式 .if , .elsif命令和设置 sxe自动命令 $$><path\to\script .在一行中做大量的 if-condition 链接可能很难阅读和正确,尤其是在额外的转义时。脚本不需要额外的转义。这是一个小例子:

.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 命令后跟任何其他命令。但它仍然运行良好)

关于c++ - 在 Windbg 中,我可以在抛出特定 C++ 异常时跳过中断吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26306009/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com