简体   繁体   English

使用__debugbreak()尝试/捕获

[英]try/catch with __debugbreak()

I am working with a 3rd party C++ DLL that is running __debugbreak() in some scenario, and is not checking IsDebuggerPresent() before doing so. 我正在使用在某些情况下正在运行__debugbreak()的第三方C ++ DLL,并且在这样做之前未检查IsDebuggerPresent()。 This results in my application "crashing" when that scenario happens outside of a debugger (eg end user running the application). 当这种情况发生在调试器之外时(例如,运行该应用程序的最终用户),这导致我的应用程序“崩溃”。 I would like to catch this and deal with it myself, or at least ignore it. 我想自己抓住它,或者至少忽略它。

I actually have had an unhandled exception filter in place to translate SEH to C++ exceptions for a while, so it's a little strange that it's not working. 实际上,我有一个未处理的异常过滤器,可以将SEH转换为C ++异常一段时间,所以它不起作用有点奇怪。

::SetUnhandledExceptionFilter(OnUnhandledException);

I've been doing some direct testing, and the standard __try/__except works, so I could wrap every call into the DLL with this as a fallback, but seems to be that if __try/__except works, then ::SetUnhandledExceptionFilter() should also work. 我一直在进行一些直接测试,并且标准的__try / __ except可以工作,因此我可以将每次调用都包装到DLL中,以作为备用,但似乎是如果__try / __ except可以工作,则:: SetUnhandledExceptionFilter()应该可以也可以。

    __try
    {
        __debugbreak();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("caught");
    }

try/catch(...) does not work. try / catch(...)不起作用。

    try
    {
        __debugbreak();
    }
    catch (...)
    {
        printf("caught");
    }

_set_se_translator() isn't working either. _set_se_translator()也不起作用。

From the MSDN documentation at https://msdn.microsoft.com/en-us/library/ms679297(VS.85).aspx it states that it should function as a structured exception. https://msdn.microsoft.com/zh-cn/library/ms679297(VS.85).aspx上的MSDN文档中,它声明它应作为结构化异常起作用。 I realize that is the documentation for DebugBreak() but I have tested with that as well and have the same problem, even with "catch(...)". 我意识到这是DebugBreak()的文档,但是我也对此进行了测试,即使遇到“ catch(...)”,也存在相同的问题。

I am compiling with /EHa. 我正在使用/ EHa进行编译。

How can I catch the __debugbreak (asm INT 3), or at least change the behavior? 如何捕获__debugbreak(asm INT 3),或者至少更改行为?

Breakpoints generate the EXCEPTION_BREAKPOINT structured exception. 断点生成EXCEPTION_BREAKPOINT结构化异常。 You cannot use try/catch to catch it because it doesn't get translated to a C++ exception, irrespective of the /EHa switch or _set_se_translator . 您不能使用try / catch来捕获它,因为无论/ EHa开关还是_set_se_translator ,它都不会转换为C ++异常。 EXCEPTION_BREAKPOINT is a special exception. EXCEPTION_BREAKPOINT是一个特殊的例外。

First, you should know that catch blocks and __except blocks execute only after unwinding the stack. 首先,您应该知道catch块和__except块仅在展开堆栈后才执行。 This means that execution continues after the handler block, NOT after the call to __debugbreak() . 这意味着执行将在处理程序块之后继续执行,而不是在调用__debugbreak()之后继续执行。 So if you just want to skip EXCEPTION_BREAKPOINT while at the same time continue execution after the int 3 instruction. 因此,如果您只想跳过EXCEPTION_BREAKPOINT而同时在int 3指令之后继续执行。 You should use a vectored exception handler. 您应该使用向量异常处理程序。 Here is an example: 这是一个例子:

// VEH is supported only on Windows XP+ and Windows Server 2003+
#define _WIN32_WINNT 0x05020000

#include <windows.h>
#include <stdio.h>

//AddVectoredExceptionHandler constants:
//CALL_FIRST means call this exception handler first;
//CALL_LAST means call this exception handler last
#define CALL_FIRST 1  
#define CALL_LAST 0

LONG WINAPI
VectoredHandlerBreakPoint(
struct _EXCEPTION_POINTERS *ExceptionInfo
    )
{
    if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
    {
        /*

        If a debugger is attached, this will never be executed.

        */

        printf("BreakPoint at 0x%x skipped.\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);

        PCONTEXT Context = ExceptionInfo->ContextRecord;

        // The breakpoint instruction is 0xCC (int 3), just one byte in size.
        // Advance to the next instruction. Otherwise, this handler will just be called ad infinitum.
#ifdef _AMD64_
        Context->Rip++;
#else
        Context->Eip++;
#endif    
        // Continue execution from the instruction at Context->Rip/Eip.
        return EXCEPTION_CONTINUE_EXECUTION;
    }

    // IT's not a break intruction. Continue searching for an exception handler.
    return EXCEPTION_CONTINUE_SEARCH;
}

void main()
{
    // Register the vectored exception handler once.
    PVOID hVeh = AddVectoredExceptionHandler(CALL_FIRST, VectoredHandlerBreakPoint);

    if (!hVeh)
    {
        // AddVectoredExceptionHandler failed.
        // Practically, this never happens.
    }

    DebugBreak();

    // Unregister the handler.
    if (hVeh)
        RemoveVectoredExceptionHandler(hVeh);
}

In this way, the breakpoint instruction int 3 will just be skipped and the next instruction will be executed. 这样,断点指令int 3将被跳过,而下一条指令将被执行。 Also if a debugger is attached, it will handle EXCEPTION_BREAKPOINT for you. 另外,如果连接了调试器,它将为您处理EXCEPTION_BREAKPOINT

However, if you really want to unwind the stack, you have to use __except(GetExceptionCode() == EXCEPTION_BREAKPOINT ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) . 但是,如果您真的想展开堆栈,则必须使用__except(GetExceptionCode() == EXCEPTION_BREAKPOINT ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM