попробуйте / поймайте с __debugbreak ()

Я работаю с сторонней 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) или хотя бы изменить поведение?

2

Решение

Точки останова генерируют 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),

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]