使用__debugbreak()尝试/捕获

Den*_*s P 2 c++ winapi exception-handling exception

我正在使用在某些情况下运行__debugbreak()的第三方C++ DLL,并且在执行此操作之前不检查IsDebuggerPresent().当场景发生在调试器外部时(例如,运行应用程序的最终用户),这会导致我的应用程序"崩溃".我想抓住这个并自己处理它,或者至少忽略它.

我实际上已经有一个未处理的异常过滤器来将SEH转换为C++异常一段时间,所以它有点奇怪,它不起作用.

::SetUnhandledExceptionFilter(OnUnhandledException);
Run Code Online (Sandbox Code Playgroud)

我一直在做一些直接测试,标准__try/__除了工作,所以我可以将每个调用包装成DLL作为后备,但似乎是如果__try/__除了工作,那么:: SetUnhandledExceptionFilter()应该也工作.

    __try
    {
        __debugbreak();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("caught");
    }
Run Code Online (Sandbox Code Playgroud)

try/catch(...)不起作用.

    try
    {
        __debugbreak();
    }
    catch (...)
    {
        printf("caught");
    }
Run Code Online (Sandbox Code Playgroud)

_set_se_translator()也不起作用.

从https://msdn.microsoft.com/en-us/library/ms679297(VS.85).aspx上的MSDN文档中可以看出它应该作为结构化异常.我意识到这是DebugBreak()的文档,但我也测试过它,并且遇到了同样的问题,即使是"catch(...)".

我正在和/ EHa一起编译.

如何捕获__debugbreak(asm INT 3),或者至少改变行为?

Had*_*ais 5

断点生成EXCEPTION_BREAKPOINT结构化异常.您无法使用try/catch来捕获它,因为它无法转换为C++异常,无论/ EHa开关或_set_se_translator.EXCEPTION_BREAKPOINT是一个特例.

首先,您应该知道catch块和__except块仅在展开堆栈后执行.这意味着在处理程序块之后继续执行,而不是在调用之后执行__debugbreak().因此,如果您只是想跳过,EXCEPTION_BREAKPOINT同时在int 3指令后继续执行.您应该使用向量异常处理程序.这是一个例子:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

这样,int 3将跳过断点指令,并执行下一条指令.此外,如果附加了调试器,它将EXCEPTION_BREAKPOINT为您处理.

但是,如果你真的想要展开堆栈,你必须使用__except(GetExceptionCode() == EXCEPTION_BREAKPOINT ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH).