我正在使用在某些情况下运行__debugbreak()的第三方C ++ DLL,并且在执行此操作之前不检查IsDebuggerPresent()。当场景发生在调试器外部时(例如,运行应用程序的最终用户),这会导致我的应用程序“崩溃”。我想抓住这个并自己处理它,或者至少忽略它。
我实际上已经有一个未处理的异常过滤器来将SEH转换为C ++异常一段时间,所以它有点奇怪,它无法正常工作。
::SetUnhandledExceptionFilter(OnUnhandledException);
我一直在做一些直接测试,标准的__try / __除了工作,所以我可以将每个调用包装到DLL作为后备,但似乎是如果__try / __除了工作,那么:: SetUnhandledExceptionFilter ()也应该有效。
__try
{
__debugbreak();
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf("caught");
}
try / catch(...)不起作用。
try
{
__debugbreak();
}
catch (...)
{
printf("caught");
}
_set_se_translator()也无效。
在https://msdn.microsoft.com/en-us/library/ms679297(VS.85).aspx的MSDN文档中,它声明它应该作为结构化异常运行。我意识到这是DebugBreak()的文档,但我也测试了它,并且遇到了同样的问题,即使是“catch(...)”。
我正在和/ EHa一起编译。
如何捕获__debugbreak(asm INT 3),或者至少改变行为?
答案 0 :(得分: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);
}
这样,将跳过断点指令int 3
,并执行下一条指令。此外,如果附加了调试器,它将为您处理EXCEPTION_BREAKPOINT
。
但是,如果您真的想要展开堆栈,则必须使用__except(GetExceptionCode() == EXCEPTION_BREAKPOINT ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
。