Аппаратная точка останова WINAPI - PullRequest
12 голосов
/ 05 января 2012

В настоящее время я выполняю последнюю задачу для небольшой среды отладки, а именно HW Breakpoints.До сих пор я ссылался на эту статью: http://www.codeproject.com/KB/debug/hardwarebreakpoint.aspx и книгу о написании отладчика.

До сих пор я получил две функции для установки точки останова HW:

void debuglib::breakpoints::hw_bp() {
    HANDLE helper = 0;

    CONTEXT co;
    CURRENTCONTEXT(co);

    helper = ::CreateThread(0,0,threadfunc,reinterpret_cast<void*>(co.Eip),0,0);

    DWORD status = ::WaitForSingleObject(helper,INFINITE);


    if (status != WAIT_OBJECT_0) { 
            ::MessageBoxA(0, "Helper thread didn't exit cleanly", "HWBreakpoint", MB_OK);
    }

    ::CloseHandle(helper);
}

static DWORD WINAPI debuglib::breakpoints::threadfunc(void* param) {

    DWORD suspendcnt = ::SuspendThread(debuglib::process::thread());
    if(suspendcnt) {
        return 0;
    }

    CONTEXT co;
    ::ZeroMemory(&co,sizeof(co));
    co.ContextFlags = CONTEXT_DEBUG_REGISTERS;

    BOOL ok = ::GetThreadContext(debuglib::process::thread(),&co);

    if(!ok) {
        return 0;
    }

    DWORD freeDr = 0;
    DWORD condition = debuglib::breakpoints::TRIGGER::CODE;
    DWORD length = debuglib::breakpoints::SIZE::SIZE_1;

    co.Dr0 = reinterpret_cast<DWORD>(param);

    co.Dr7 = co.Dr7 | 1 << (freeDr*2);
    co.Dr7 = co.Dr7 | condition << ((freeDr*4)+16);
    co.Dr7 = co.Dr7 | length << ((freeDr*4)+18);

    co.ContextFlags = CONTEXT_DEBUG_REGISTERS;
    ok = ::SetThreadContext(debuglib::process::thread(), &co);

    co.ContextFlags = CONTEXT_DEBUG_REGISTERS;
    ::GetThreadContext(debuglib::process::thread(),&co);

    suspendcnt = ::ResumeThread(debuglib::process::thread());
    if(suspendcnt == 0xFFFFFFFF) {
        return 0;
    }

    return 1;
 }

Итак, сначала я создаю вспомогательный поток, так как я отлаживаю текущий поток.В функции обратного вызова вспомогательного потока я приостанавливаю основной поток.После этого я читаю текущие значения DR основного потока (на данный момент это не актуально, так как я всегда использую DR0, после этого я проверю, какие регистры свободны и используют до 4 BP).Впоследствии я использовал адрес возврата вызывающей функции (EIP) в качестве адреса для разрыва в DR0 и установил соответствующие флаги в DR7.

В конце я возобновляю основной поток и закрываю дескриптор помощника.поток, как он закончен.

С этим кодом у меня возникла следующая проблема:

Если я выполняю программу в режиме отладки, программы останавливаются по правильному адресу, но я больше ничего не могу сделать,так как флаг INT1 установлен, я полагаю, и отладчик VS не может двигаться дальше ни на шаг?

Если я запускаю программу без отладки, она просто вылетает.Я пытался использовать __try, __except, как в упомянутом проекте (http://www.codeproject.com/KB/debug/hardwarebreakpoint.aspx), но это тоже не работает.

Я ценю и помогаю, или сообщаю, что я делаю неправильно и как решить эту проблему.

1 Ответ

1 голос
/ 16 марта 2012

Я не думаю, что это хорошая идея, чтобы попытаться сделать саму программу отладочной.Почему бы не использовать встроенный в Windows API разработки отладчика?

Dev Center - Desktop> Обучение> Справка> Диагностика> Отладка и обработка ошибок> Базовая отладка> Справочник по отладке> Функции отладки: http://msdn.microsoft.com/en-us/library/windows/desktop/ms679303%28v=vs.85%29.aspx

На аппаратном обеспечении x86 одноступенчатый режим включается путем установки флага прерывания в флагах.Процессор сгенерирует исключение точки останова после выполнения одной инструкции.Я думаю, что происходит, когда отладчик визуальной студии меняет этот бит флагов, мешая тому, что вы пытаетесь сделать.

Попробуйте запустить вашу программу вне визуальной студии (без отладчика).Это работает так, как ожидалось?

...