Я работаю с сторонней C ++ DLL, которая в некоторых случаях выполняет __debugbreak () и не проверяет IsDebuggerPresent () перед этим. Это приводит к сбою моего приложения, когда этот сценарий происходит вне отладчика (например, конечный пользователь, выполняющий приложение). Я хотел бы поймать это и разобраться с этим сам, или, по крайней мере, игнорировать это.
У меня на самом деле был фильтр необработанных исключений, чтобы некоторое время переводить исключения SEH в C ++, поэтому немного странно, что он не работает.
::SetUnhandledExceptionFilter(OnUnhandledException);
Я проводил некоторое прямое тестирование, и стандарт __try / __, за исключением работы, поэтому я мог обернуть каждый вызов в DLL с этим как запасной вариант, но, похоже, что если __try / __ кроме работает, то также работа.
__try
{
__debugbreak();
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf("caught");
}
try / catch (…) не работает.
try
{
__debugbreak();
}
catch (...)
{
printf("caught");
}
_set_se_translator () тоже не работает.
Из документации MSDN на https://msdn.microsoft.com/en-us/library/ms679297(VS.85).aspx в нем говорится, что оно должно функционировать как структурированное исключение. Я понимаю, что это документация для DebugBreak (), но я протестировал и это, и у меня та же проблема, даже с «catch (…)».
Я компилирую с / EHa.
Как я могу поймать __debugbreak (asm INT 3) или хотя бы изменить поведение?
Точки останова генерируют 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)
,
Других решений пока нет …