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); }
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; }
// 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; }
bool CoreEngine::terminateProcesses(QString *appendableErrorMessage) { const HRESULT hr = m_cif.debugClient->TerminateProcesses(); if (FAILED(hr)) { appendError(msgComFailed("TerminateProcesses", hr), appendableErrorMessage); return false; } return true; }
CoreEngine::CodeLevel CoreEngine::codeLevel() const { ULONG currentCodeLevel = DEBUG_LEVEL_ASSEMBLY; HRESULT hr = m_cif.debugControl->GetCodeLevel(¤tCodeLevel); if (FAILED(hr)) { qWarning("Cannot determine code level: %s", qPrintable(msgComFailed("GetCodeLevel", hr))); } return currentCodeLevel == DEBUG_LEVEL_ASSEMBLY ? CodeLevelAssembly : CodeLevelSource; }
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; }
bool CoreEngine::detachCurrentProcess(QString *appendableErrorMessage) { const HRESULT hr = m_cif.debugClient->DetachCurrentProcess(); if (FAILED(hr)) { appendError(msgComFailed("DetachCurrentProcess", hr), appendableErrorMessage); return false; } return true; }
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; }
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); }
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; }
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; }
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; }
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; }
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; }
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 }
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); }
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; }
// 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; }
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; }
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; }
// 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; }
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; }
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; }
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; }
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; }
// 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; }