bool CoreEngine::evaluateExpression(const QString &expression, DEBUG_VALUE *debugValue, QString *errorMessage) { if (debug > 1) qDebug() << Q_FUNC_INFO << expression; memset(debugValue, 0, sizeof(DEBUG_VALUE)); // Use CPP syntax, original syntax must be restored, else setting breakpoints will fail. SyntaxSetter syntaxSetter(this, CppExpressionSyntax); Q_UNUSED(syntaxSetter) ULONG errorPosition = 0; const HRESULT hr = m_cif.debugControl->EvaluateWide(reinterpret_cast<PCWSTR>(expression.utf16()), DEBUG_VALUE_INVALID, debugValue, &errorPosition); if (FAILED(hr)) { if (HRESULT_CODE(hr) == 517) { *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Expression out of scope."). arg(expression); } else { *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Error at %2: %3"). arg(expression).arg(errorPosition).arg(msgDebugEngineComResult(hr)); } return false; } return true; }
std::string msgDebugEngineComFailed(const char *func, HRESULT hr) { std::string rc = func; rc += " failed: "; rc += msgDebugEngineComResult(hr); return rc; }
HRESULT CoreEngine::waitForEvent(int timeOutMS) { const HRESULT hr = m_cif.debugControl->WaitForEvent(0, timeOutMS); if (debug) if (debug > 1 || hr != S_FALSE) qDebug() << Q_FUNC_INFO << "WaitForEvent" << timeOutMS << msgDebugEngineComResult(hr); return hr; }
bool CoreEngine::executeDebuggerCommand(const QString &command, QString *errorMessage) { // output to all clients, else we do not see anything const HRESULT hr = m_cif.debugControl->ExecuteWide(DEBUG_OUTCTL_ALL_CLIENTS, reinterpret_cast<PCWSTR>(command.utf16()), 0); if (debug) qDebug() << "executeDebuggerCommand" << command << SUCCEEDED(hr); if (FAILED(hr)) { *errorMessage = QString::fromLatin1("Unable to execute '%1': %2"). arg(command, msgDebugEngineComResult(hr)); return false; } return true; }
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; }
QString msgDebuggerCommandFailed(const QString &command, HRESULT hr) { return QString::fromLatin1("Unable to execute '%1': %2").arg(command, msgDebugEngineComResult(hr)); }
QString msgComFailed(const char *func, HRESULT hr) { return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr)); }
bool CoreEngine::startAttachDebugger(qint64 pid, bool suppressInitialBreakPoint, QString *errorMessage) { resetModuleLoadTimer(); // Need to attach invasively, otherwise, no notification signals // for for CreateProcess/ExitProcess occur. // Initial breakpoint occur: // 1) Desired: When attaching to a crashed process // 2) Undesired: When starting up a console process, in conjunction // with the 32bit Wow-engine // As of version 6.11, the flag only affects 1). 2) Still needs to be suppressed // by lookup at the state of the application (startup trap). However, // there is no startup trap when attaching to a process that has been // running for a while. (see notifyException). ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS; if (suppressInitialBreakPoint) flags |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK; const HRESULT hr = m_cif.debugClient->AttachProcess(NULL, pid, flags); if (debug) qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr; if (FAILED(hr)) { *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr)); return false; } 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; }