Exemplo n.º 1
0
bool CoreEngine::dissassemble(ULONG64 offset,
                              unsigned long beforeLines,
                              unsigned long afterLines,
                              QString *target,
                              QString *errorMessage)
{
    const ULONG flags = DEBUG_DISASM_MATCHING_SYMBOLS|DEBUG_DISASM_SOURCE_LINE_NUMBER|DEBUG_DISASM_SOURCE_FILE_NAME;
    // Catch the output by temporarily setting another handler.
    // We use the method that outputs to the output handler as it
    // conveniently provides the 'beforeLines' context (stepping back
    // in assembler code). We build a complete string first as line breaks
    // may occur in-between messages.
    QSharedPointer<StringOutputHandler> outputHandler(new StringOutputHandler);
    OutputRedirector redir(this, outputHandler);
    // For some reason, we need to output to "all clients"
    const HRESULT hr =  m_cif.debugControl->OutputDisassemblyLines(DEBUG_OUTCTL_ALL_CLIENTS,
                                                                   beforeLines, beforeLines + afterLines,
                                                                   offset, flags, 0, 0, 0, 0);
    if (FAILED(hr)) {
        *errorMessage= QString::fromLatin1("Unable to dissamble at 0x%1: %2").
                       arg(offset, 0, 16).arg(msgComFailed("OutputDisassemblyLines", hr));
        return false;
    }
    *target = outputHandler->result();
    return true;
}
void QWinThumbnailToolBarPrivate::_q_updateToolbar()
{
    updateScheduled = false;
    if (!pTbList || !window)
        return;
    THUMBBUTTON buttons[windowsLimitedThumbbarSize];
    initButtons(buttons);
    const int thumbbarSize = qMin(buttonList.size(), windowsLimitedThumbbarSize);
    // filling from the right fixes some strange bug which makes last button bg look like first btn bg
    for (int i = (windowsLimitedThumbbarSize - thumbbarSize); i < windowsLimitedThumbbarSize; i++) {
        QWinThumbnailToolButton *button = buttonList.at(i - (windowsLimitedThumbbarSize - thumbbarSize));
        buttons[i].dwFlags = static_cast<THUMBBUTTONFLAGS>(makeNativeButtonFlags(button));
        buttons[i].dwMask  = static_cast<THUMBBUTTONMASK>(makeButtonMask(button));
        if (!button->icon().isNull()) {;
            buttons[i].hIcon = QtWin::toHICON(button->icon().pixmap(GetSystemMetrics(SM_CXSMICON)));
            if (!buttons[i].hIcon)
                buttons[i].hIcon = (HICON)LoadImage(0, IDI_APPLICATION, IMAGE_ICON, SM_CXSMICON, SM_CYSMICON, LR_SHARED);
        }
        if (!button->toolTip().isEmpty()) {
            buttons[i].szTip[button->toolTip().left(sizeof(buttons[i].szTip)/sizeof(buttons[i].szTip[0]) - 1).toWCharArray(buttons[i].szTip)] = 0;
        }
    }
    HRESULT hresult = pTbList->ThumbBarUpdateButtons(reinterpret_cast<HWND>(window->winId()), windowsLimitedThumbbarSize, buttons);
    if (FAILED(hresult))
        qWarning() << msgComFailed("ThumbBarUpdateButtons", hresult);
    freeButtonResources(buttons);
}
Exemplo n.º 3
0
ULONG CoreEngine::executionStatus() const
{
    ULONG ex = DEBUG_STATUS_NO_CHANGE;
    const HRESULT hr = m_cif.debugControl->GetExecutionStatus(&ex);
    if (FAILED(hr))
        qWarning("Cannot determine execution status: %s", qPrintable(msgComFailed("GetExecutionStatus", hr)));
    return ex;
}
Exemplo n.º 4
0
// Those should not fail
CoreEngine::ExpressionSyntax CoreEngine::expressionSyntax() const
{
    ULONG expressionSyntax = DEBUG_EXPR_MASM;
    const HRESULT hr = m_cif.debugControl->GetExpressionSyntax(&expressionSyntax);
    if (FAILED(hr))
        qWarning("Unable to retrieve expression syntax: %s", qPrintable(msgComFailed("GetExpressionSyntax", hr)));
    return expressionSyntax == DEBUG_EXPR_MASM ? AssemblerExpressionSyntax : CppExpressionSyntax;
}
Exemplo n.º 5
0
bool CoreEngine::terminateProcesses(QString *appendableErrorMessage)
{
    const HRESULT hr = m_cif.debugClient->TerminateProcesses();
    if (FAILED(hr)) {
        appendError(msgComFailed("TerminateProcesses", hr), appendableErrorMessage);
        return false;
    }
    return true;
}
Exemplo n.º 6
0
CoreEngine::CodeLevel CoreEngine::codeLevel() const
{
    ULONG currentCodeLevel = DEBUG_LEVEL_ASSEMBLY;
    HRESULT hr = m_cif.debugControl->GetCodeLevel(&currentCodeLevel);
    if (FAILED(hr)) {
        qWarning("Cannot determine code level: %s", qPrintable(msgComFailed("GetCodeLevel", hr)));
    }
    return currentCodeLevel == DEBUG_LEVEL_ASSEMBLY ? CodeLevelAssembly : CodeLevelSource;
}
Exemplo n.º 7
0
bool CoreEngine::endSession(QString *appendableErrorMessage)
{
    const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE);
    if (FAILED(hr)) {
        appendError(msgComFailed("EndSession", hr), appendableErrorMessage);
        return false;
    }
    return true;
}
Exemplo n.º 8
0
bool CoreEngine::detachCurrentProcess(QString *appendableErrorMessage)
{
    const HRESULT hr = m_cif.debugClient->DetachCurrentProcess();
    if (FAILED(hr)) {
        appendError(msgComFailed("DetachCurrentProcess", hr), appendableErrorMessage);
        return false;
    }
    return true;
}
Exemplo n.º 9
0
bool CoreEngine::setInterrupt(QString *errorMessage)
{
    const HRESULT hr = interfaces().debugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT);
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2").
                        arg(getInterruptTimeOutSecs(interfaces().debugControl)).arg(msgComFailed("SetInterrupt", hr));
        return false;
    }
    return true;
}
Exemplo n.º 10
0
bool CoreEngine::setExecutionStatus(ULONG ex, QString *errorMessage)
{
    const HRESULT hr = m_cif.debugControl->SetExecutionStatus(ex);
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Cannot set execution status to %1: %2")
                        .arg(QLatin1String(msgExecutionStatusString(ex)), msgComFailed("SetExecutionStatus", hr));
        return false;
    }
    return true;
}
void QWinThumbnailToolBarPrivate::clearToolbar()
{
    if (!pTbList || !window)
        return;
    THUMBBUTTON buttons[windowsLimitedThumbbarSize];
    initButtons(buttons);
    HRESULT hresult = pTbList->ThumbBarUpdateButtons(reinterpret_cast<HWND>(window->winId()), windowsLimitedThumbbarSize, buttons);
    if (FAILED(hresult))
        qWarning() << msgComFailed("ThumbBarUpdateButtons", hresult);
}
Exemplo n.º 12
0
bool CoreEngine::setSymbolPaths(const QStringList &s, QString *errorMessage)
{
    const HRESULT hr = m_cif.debugSymbols->SetSymbolPathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16()));
    if (FAILED(hr)) {
        if (errorMessage)
            *errorMessage = msgComFailed("SetSymbolPathWide", hr);
        return false;
    }
    return true;
}
Exemplo n.º 13
0
bool CDBBreakPoint::getBreakPointCount(IDebugControl4* debugControl, ULONG *count, QString *errorMessage /* = 0*/)
{
    const HRESULT hr = debugControl->GetNumberBreakpoints(count);
    if (FAILED(hr)) {
        if (errorMessage)
            *errorMessage = QString::fromLatin1("Cannot determine breakpoint count: %1").
                            arg(msgComFailed("GetNumberBreakpoints", hr));
        return false;
    }
    return true;
}
Exemplo n.º 14
0
CoreEngine::CodeLevel CoreEngine::setCodeLevel(CodeLevel cl)
{
    const CodeLevel old = codeLevel();
    if (old != cl) {
        if (debug)
            qDebug() << "Setting code level" << cl;
        const HRESULT hr = m_cif.debugControl->SetCodeLevel(cl == CodeLevelAssembly ? DEBUG_LEVEL_ASSEMBLY : DEBUG_LEVEL_SOURCE);
        if (FAILED(hr))
            qWarning("Unable to set code level: %s", qPrintable(msgComFailed("SetCodeLevel", hr)));
    }
    return old;
}
Exemplo n.º 15
0
CoreEngine::ExpressionSyntax CoreEngine::setExpressionSyntax(ExpressionSyntax es)
{
    const ExpressionSyntax old = expressionSyntax();
    if (old != es) {
        if (debug)
            qDebug() << "Setting expression syntax" << es;
        const HRESULT hr = m_cif.debugControl->SetExpressionSyntax(es == AssemblerExpressionSyntax ? DEBUG_EXPR_MASM : DEBUG_EXPR_CPLUSPLUS);
        if (FAILED(hr))
            qWarning("Unable to set expression syntax: %s", qPrintable(msgComFailed("SetExpressionSyntax", hr)));
    }
    return old;
}
Exemplo n.º 16
0
bool CoreEngine::startDebuggerWithExecutable(const QString &workingDirectory,
                                             const QString &filename,
                                             const QStringList &args,
                                             const QStringList &envList,
                                             QString *errorMessage)
{
    resetModuleLoadTimer();
    DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
    memset(&dbgopts, 0, sizeof(dbgopts));
    dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;

    // Set image path
    const QFileInfo fi(filename);
    QString imagePath = QDir::toNativeSeparators(fi.absolutePath());
    if (!m_baseImagePath.isEmpty()) {
        imagePath += QLatin1Char(';');
        imagePath += m_baseImagePath;
    }
    HRESULT hr = m_cif.debugSymbols->SetImagePathWide(reinterpret_cast<PCWSTR>(imagePath.utf16()));
    if (FAILED(hr)) {
        *errorMessage = tr("Unable to set the image path to %1: %2").arg(imagePath, msgComFailed("SetImagePathWide", hr));
        return false;
    }

    if (debug)
        qDebug() << Q_FUNC_INFO <<'\n' << filename << imagePath;

    const QString cmd = Utils::AbstractProcess::createWinCommandline(filename, args);
    if (debug)
        qDebug() << "Starting " << cmd;
    PCWSTR env = 0;
    QByteArray envData;
    if (!envList.empty()) {
        envData = Utils::AbstractProcess::createWinEnvironment(Utils::AbstractProcess::fixWinEnvironment(envList));
        env = reinterpret_cast<PCWSTR>(envData.data());
    }
    // The working directory cannot be empty.
    PCWSTR workingDirC = 0;
    const QString workingDirN = workingDirectory.isEmpty() ? QString() : QDir::toNativeSeparators(workingDirectory);
    if (!workingDirN.isEmpty())
        workingDirC = (PCWSTR)workingDirN.utf16();
    hr = m_cif.debugClient->CreateProcess2Wide(NULL,
                                               reinterpret_cast<PWSTR>(const_cast<ushort *>(cmd.utf16())),
                                               &dbgopts, sizeof(dbgopts),
                                               workingDirC, env);
    if (FAILED(hr)) {
        *errorMessage = tr("Unable to create a process '%1': %2").arg(cmd, msgDebugEngineComResult(hr));
        return false;
    }
    return true;
}
Exemplo n.º 17
0
bool CoreEngine::setVerboseSymbolLoading(bool newValue)
{
    ULONG opts;
    HRESULT hr = m_cif.debugSymbols->GetSymbolOptions(&opts);
    if (FAILED(hr)) {
        qWarning("%s", qPrintable(msgComFailed("GetSymbolOptions", hr)));
        return false;
    }
    const bool isVerbose = (opts & SYMOPT_DEBUG);
    if (isVerbose == newValue)
        return true;
    if (newValue) {
        opts |= SYMOPT_DEBUG;
    } else {
        opts &= ~SYMOPT_DEBUG;
    }
    hr = m_cif.debugSymbols->SetSymbolOptions(opts);
    if (FAILED(hr)) {
        qWarning("%s", qPrintable(msgComFailed("SetSymbolOptions", hr)));
        return false;
    }
    return true;
}
void QWinThumbnailToolBarPrivate::initToolbar()
{
#if !defined(_MSC_VER) || _MSC_VER >= 1600
    if (!pTbList || !window)
        return;
    THUMBBUTTON buttons[windowsLimitedThumbbarSize];
    initButtons(buttons);
    HRESULT hresult = pTbList->ThumbBarAddButtons(reinterpret_cast<HWND>(window->winId()), windowsLimitedThumbbarSize, buttons);
    if (FAILED(hresult))
        qWarning() << msgComFailed("ThumbBarAddButtons", hresult);
#else
    // ITaskbarList3::ThumbBarAddButtons() has a different signature in SDK 6.X
    Q_UNIMPLEMENTED();
#endif
}
Exemplo n.º 19
0
bool CDBBreakPoint::add(IDebugControl4* debugControl, QString *errorMessage) const
{
    IDebugBreakpoint2* ibp = 0;
    const HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Unable to add breakpoint: %1").
                        arg(msgComFailed("AddBreakpoint2", hr));
        return false;
    }
    if (!ibp) {
        *errorMessage = QString::fromLatin1("Unable to add breakpoint: <Unknown error>");
        return false;
    }
    return apply(ibp, errorMessage);
}
Exemplo n.º 20
0
bool CDBBreakPoint::add(CIDebugControl* debugControl,
                        QString *errorMessage,
                        unsigned long *id,
                        quint64 *address) const
{
    IDebugBreakpoint2* ibp = 0;
    if (address)
        *address = 0;
    if (id)
        *id = 0;
    HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
    if (FAILED(hr)) {
        *errorMessage = msgCannotAddBreakPoint(msgComFailed("AddBreakpoint2", hr));
        return false;
    }
    if (!ibp) {
        *errorMessage = msgCannotAddBreakPoint(QLatin1String("<Unknown error>"));
        return false;
    }
    if (!apply(ibp, errorMessage))
        return false;
    // GetOffset can fail when attaching to remote processes, ignore return
    if (address) {
        hr = ibp->GetOffset(address);
        if (FAILED(hr))
            *address = 0;
    }
    if (id) {
        hr = ibp->GetId(id);
        if (FAILED(hr)) {
            *errorMessage = msgCannotAddBreakPoint(msgComFailed("GetId", hr));
            return false;
        }
    }
    return true;
}
Exemplo n.º 21
0
// Alloc an AscII string in debuggee
bool CoreEngine::createDebuggeeAscIIString(const QString &s,
                                           ULONG64 *address,
                                           QString *errorMessage)
{
    QByteArray sAsciiData = s.toLocal8Bit();
    sAsciiData += '\0';
    if (!allocDebuggeeMemory(sAsciiData.size(), address, errorMessage))
        return false;
    const HRESULT hr = m_cif.debugDataSpaces->WriteVirtual(*address, sAsciiData.data(), sAsciiData.size(), 0);
    if (FAILED(hr)) {
        *errorMessage= msgComFailed("WriteVirtual", hr);
        return false;
    }
    return true;
}
Exemplo n.º 22
0
quint64 CoreEngine::getSourceLineAddress(const QString &file,
                                         int line,
                                         QString *errorMessage) const
{
    ULONG64 rc = 0;
    const HRESULT hr = m_cif.debugSymbols->GetOffsetByLineWide(line,
                                                               (wchar_t*)(file.utf16()),
                                                               &rc);
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Unable to determine address of %1:%2 : %3").
                        arg(file).arg(line).arg(msgComFailed("GetOffsetByLine", hr));
        return 0;
    }
    return rc;
}
Exemplo n.º 23
0
bool CDBBreakPoint::apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const
{
    const QString expr = expression();
    if (debugCDB)
        qDebug() << Q_FUNC_INFO << *this << expr;
    const HRESULT hr = ibp->SetOffsetExpressionWide(expr.utf16());
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Unable to set breakpoint '%1' : %2").
                        arg(expr, msgComFailed("SetOffsetExpressionWide", hr));
        return false;
    }
    // Pass Count is ignoreCount + 1
    ibp->SetPassCount(ignoreCount + 1u);
    ibp->AddFlags(DEBUG_BREAKPOINT_ENABLED);
    return true;
}
Exemplo n.º 24
0
// Write to debuggee memory in chunks
bool CoreEngine::writeToDebuggee(const QByteArray &buffer, quint64 address, QString *errorMessage)
{
    char *ptr = const_cast<char*>(buffer.data());
    ULONG bytesToWrite = buffer.size();
    while (bytesToWrite > 0) {
        ULONG bytesWritten = 0;
        const HRESULT hr = m_cif.debugDataSpaces->WriteVirtual(address, ptr, bytesToWrite, &bytesWritten);
        if (FAILED(hr)) {
            *errorMessage = msgComFailed("WriteVirtual", hr);
            return false;
        }
        bytesToWrite -= bytesWritten;
        ptr += bytesWritten;
    }
    return true;
}
Exemplo n.º 25
0
bool CDBBreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
{
    const QString expr = expression();
    if (debugCDB)
        qDebug() << Q_FUNC_INFO << *this << expr;
    const HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16()));
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Unable to set breakpoint '%1' : %2").
                        arg(expr, msgComFailed("SetOffsetExpressionWide", hr));
        return false;
    }
    // Pass Count is ignoreCount + 1
    ibp->SetPassCount(ignoreCount + 1u);
    ULONG flags = 0;
    if (enabled)
        flags |= DEBUG_BREAKPOINT_ENABLED;
    if (oneShot)
        flags |= DEBUG_BREAKPOINT_ONE_SHOT;
    ibp->AddFlags(flags);
    return true;
}
Exemplo n.º 26
0
bool CDBBreakPoint::retrieve(IDebugBreakpoint2 *ibp, QString *errorMessage)
{
    clear();
    WCHAR wszBuf[MAX_PATH];
    const HRESULT hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint: %1").
                        arg(msgComFailed("GetOffsetExpressionWide", hr));
        return false;
    }
    // Pass Count is ignoreCount + 1
    ibp->GetPassCount(&ignoreCount);
    if (ignoreCount)
        ignoreCount--;
    const QString expr = QString::fromUtf16(wszBuf);
    if (!parseExpression(expr)) {
        *errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr);
        return false;
    }
    return true;
}
Exemplo n.º 27
0
bool CDBBreakPoint::getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage)
{
    ULONG count = 0;
    bps->clear();
    if (!getBreakPointCount(debugControl, &count, errorMessage))
        return false;
    // retrieve one by one and parse
    for (ULONG b= 0; b < count; b++) {
        IDebugBreakpoint2 *ibp = 0;
        const HRESULT hr = debugControl->GetBreakpointByIndex2(b, &ibp);
        if (FAILED(hr)) {
            *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
                            arg(b).arg(msgComFailed("GetBreakpointByIndex2", hr));
            return false;
        }
        CDBBreakPoint bp;
        if (!bp.retrieve(ibp, errorMessage))
            return false;
        bps->push_back(bp);
    }
    return true;
}
Exemplo n.º 28
0
bool CoreEngine::init(const QString &dllEnginePath, QString *errorMessage)
{
    enum {  bufLen = 10240 };
    // Load the DLL
    DebuggerEngineLibrary lib;
    if (!lib.init(dllEnginePath, &m_dbengDLL, errorMessage))
        return false;
    // Initialize the COM interfaces
    HRESULT hr;
    hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient));
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugClient5 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }

    hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_cif.debugControl));
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugControl4 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }

    hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_cif.debugSystemObjects));
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugSystemObjects4 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }

    hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_cif.debugSymbols));
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugSymbols3 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }
    hr = m_cif.debugSymbols->SetSymbolOptions(defaultSymbolOptions);
    if (FAILED(hr)) {
        *errorMessage = msgComFailed("SetSymbolOptions", hr);
        return false;
    }

    WCHAR buf[bufLen];
    hr = m_cif.debugSymbols->GetImagePathWide(buf, bufLen, 0);
    if (FAILED(hr)) {
        *errorMessage = msgComFailed("GetImagePathWide", hr);
        return false;
    }
    m_baseImagePath = QString::fromWCharArray(buf);

    hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_cif.debugRegisters));
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }

    hr = lib.debugCreate( __uuidof(IDebugDataSpaces4), reinterpret_cast<void**>(&m_cif.debugDataSpaces));
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugDataSpaces4 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }

    if (debug)
        qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_cif.debugControl));
    return true;
}
Exemplo n.º 29
0
// Synchronize (halted) engine breakpoints with those of the BreakHandler.
bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
                                           BreakHandler *handler,
                                           QString *errorMessage)
{    
    typedef QMap<CDBBreakPoint, int> BreakPointIndexMap;
    BreakPointIndexMap breakPointIndexMap;
    // convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

    const int handlerCount = handler->size();
    for (int i=0; i < handlerCount; ++i)
        breakPointIndexMap.insert(CDBBreakPoint(*handler->at(i)), i);
    // get number of engine breakpoints
    ULONG engineCount;
    if (!getBreakPointCount(debugControl, &engineCount, errorMessage))
        return false;

    // Starting from end, check if engine breakpoints are still in handler.
    // If not->remove
    if (engineCount) {
        for (ULONG eb = engineCount - 1u; ; eb--) {
            // get engine breakpoint.
            IDebugBreakpoint2 *ibp = 0;
            HRESULT hr = debugControl->GetBreakpointByIndex2(eb, &ibp);
            if (FAILED(hr)) {
                *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
                                arg(eb).arg(msgComFailed("GetBreakpointByIndex2", hr));
                return false;
            }
            // Ignore one shot break points set by "Step out"
            ULONG flags = 0;
            hr = ibp->GetFlags(&flags);
            if (!(flags & DEBUG_BREAKPOINT_ONE_SHOT)) {
                CDBBreakPoint engineBreakPoint;
                if (!engineBreakPoint.retrieve(ibp, errorMessage))
                    return false;
                // Still in handler?
                if (!breakPointIndexMap.contains(engineBreakPoint)) {
                    if (debugCDB)
                        qDebug() << "    Removing" << engineBreakPoint;
                    hr = debugControl->RemoveBreakpoint2(ibp);
                    if (FAILED(hr)) {
                        *errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").
                                        arg(engineBreakPoint.expression(), msgComFailed("RemoveBreakpoint2", hr));
                        return false;
                    }
                } // not in handler
            } // one shot
            if (!eb)
                break;
        }
    }
    // Add pending breakpoints
    const BreakPointIndexMap::const_iterator pcend = breakPointIndexMap.constEnd();
    for (BreakPointIndexMap::const_iterator it = breakPointIndexMap.constBegin(); it != pcend; ++it) {
        const int index = it.value();
        if (handler->at(index)->pending) {
            if (debugCDB)
                qDebug() << "    Adding " << it.key();
            if (it.key().add(debugControl, errorMessage)) {
                handler->at(index)->pending = false;
            } else {
                const QString msg = QString::fromLatin1("Failed to add breakpoint '%1': %2").arg(it.key().expression(), *errorMessage);
                qWarning("%s\n", qPrintable(msg));
            }
        }
    }
    if (debugCDB > 1) {
        QList<CDBBreakPoint> bps;
        CDBBreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
        qDebug().nospace() << "### Breakpoints in engine: " << bps;
    }
    return true;
}