forked from qt-creator/qt-creator
Debugger: Introduce EnginesDriver
Change-Id: I53635ea6e18d75eee7a41f958009a01708d8ec89 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -90,6 +90,50 @@ signals:
|
||||
void kickoffTerminalProcessRequested();
|
||||
};
|
||||
|
||||
class EnginesDriver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
~EnginesDriver() { clearEngines(); }
|
||||
|
||||
Result setupEngines(RunControl *runControl, const DebuggerRunParameters &rp);
|
||||
Result checkBreakpoints() const;
|
||||
QString debuggerName() const
|
||||
{
|
||||
return Utils::transform<QStringList>(m_engines, &DebuggerEngine::objectName).join(" ");
|
||||
}
|
||||
QString startParameters() const
|
||||
{
|
||||
return m_engines.isEmpty() ? QString() : m_engines.first()->formatStartParameters();
|
||||
}
|
||||
bool isRunning() const { return m_runningEngines > 0; }
|
||||
void start();
|
||||
void stop()
|
||||
{
|
||||
Utils::reverseForeach(m_engines, [](DebuggerEngine *engine) { engine->quitDebugger(); });
|
||||
}
|
||||
void showMessage(const QString &msg, int channel = LogDebug, int timeout = -1);
|
||||
|
||||
signals:
|
||||
void done(DoneResult result);
|
||||
void interruptTerminalRequested();
|
||||
void kickoffTerminalProcessRequested();
|
||||
void started();
|
||||
|
||||
private:
|
||||
void clearEngines()
|
||||
{
|
||||
qDeleteAll(m_engines);
|
||||
m_engines.clear();
|
||||
}
|
||||
|
||||
RunControl *m_runControl = nullptr;
|
||||
QList<QPointer<Internal::DebuggerEngine>> m_engines;
|
||||
int m_runningEngines = 0;
|
||||
int m_snapshotCounter = 0;
|
||||
};
|
||||
|
||||
class DebuggerRunToolPrivate
|
||||
{
|
||||
public:
|
||||
@@ -521,6 +565,137 @@ static int newRunId()
|
||||
return ++toolRunCount;
|
||||
}
|
||||
|
||||
Result EnginesDriver::setupEngines(RunControl *runControl, const DebuggerRunParameters &rp)
|
||||
{
|
||||
m_runControl = runControl;
|
||||
clearEngines();
|
||||
const auto engines = createEngines(runControl, rp);
|
||||
if (!engines)
|
||||
return Result::Error(engines.error());
|
||||
|
||||
m_engines = *engines;
|
||||
const QString runId = QString::number(newRunId());
|
||||
for (auto engine : m_engines) {
|
||||
if (engine != m_engines.first())
|
||||
engine->setSecondaryEngine();
|
||||
engine->setRunParameters(rp);
|
||||
engine->setRunId(runId);
|
||||
for (auto companion : m_engines) {
|
||||
if (companion != engine)
|
||||
engine->addCompanionEngine(companion);
|
||||
}
|
||||
engine->setDevice(m_runControl->device());
|
||||
}
|
||||
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
Result EnginesDriver::checkBreakpoints() const
|
||||
{
|
||||
QStringList unhandledIds;
|
||||
bool hasQmlBreakpoints = false;
|
||||
for (const GlobalBreakpoint &gbp : BreakpointManager::globalBreakpoints()) {
|
||||
if (gbp->isEnabled()) {
|
||||
const BreakpointParameters &bp = gbp->requestedParameters();
|
||||
hasQmlBreakpoints = hasQmlBreakpoints || bp.isQmlFileAndLineBreakpoint();
|
||||
const auto engineAcceptsBp = [bp](const DebuggerEngine *engine) {
|
||||
return engine->acceptsBreakpoint(bp);
|
||||
};
|
||||
if (!Utils::anyOf(m_engines, engineAcceptsBp))
|
||||
unhandledIds.append(gbp->displayName());
|
||||
}
|
||||
}
|
||||
|
||||
if (unhandledIds.isEmpty())
|
||||
return Result::Ok;
|
||||
|
||||
QString warningMessage = Tr::tr("Some breakpoints cannot be handled by the debugger "
|
||||
"languages currently active, and will be ignored.<p>"
|
||||
"Affected are breakpoints %1").arg(unhandledIds.join(", "));
|
||||
if (hasQmlBreakpoints) {
|
||||
warningMessage += "<p>" + Tr::tr("QML debugging needs to be enabled both in the Build "
|
||||
"and the Run settings.");
|
||||
}
|
||||
return Result::Error(warningMessage);
|
||||
}
|
||||
|
||||
void EnginesDriver::start()
|
||||
{
|
||||
const QString runId = QString::number(newRunId());
|
||||
for (auto engine : m_engines) {
|
||||
connect(engine, &DebuggerEngine::interruptTerminalRequested,
|
||||
this, &EnginesDriver::interruptTerminalRequested);
|
||||
connect(engine, &DebuggerEngine::kickoffTerminalProcessRequested,
|
||||
this, &EnginesDriver::kickoffTerminalProcessRequested);
|
||||
connect(engine, &DebuggerEngine::requestRunControlStop, m_runControl, &RunControl::initiateStop);
|
||||
|
||||
connect(engine, &DebuggerEngine::engineStarted, this, [this, engine] {
|
||||
++m_runningEngines;
|
||||
if (engine->isPrimaryEngine()) {
|
||||
EngineManager::activateDebugMode();
|
||||
emit started();
|
||||
}
|
||||
});
|
||||
|
||||
connect(engine, &DebuggerEngine::engineFinished, this, [this, engine] {
|
||||
engine->prepareForRestart();
|
||||
if (--m_runningEngines == 0) {
|
||||
const QString cmd = engine->runParameters().inferior().command.toUserOutput();
|
||||
const QString msg = engine->runParameters().exitCode() // Main engine.
|
||||
? Tr::tr("Debugging of %1 has finished with exit code %2.")
|
||||
.arg(cmd)
|
||||
.arg(*engine->runParameters().exitCode())
|
||||
: Tr::tr("Debugging of %1 has finished.").arg(cmd);
|
||||
m_runControl->postMessage(msg, NormalMessageFormat);
|
||||
emit done(engine->runParameters().exitCode() ? DoneResult::Error : DoneResult::Success);
|
||||
}
|
||||
});
|
||||
connect(engine, &DebuggerEngine::postMessageRequested, m_runControl, &RunControl::postMessage);
|
||||
|
||||
if (engine->isPrimaryEngine()) {
|
||||
connect(engine, &DebuggerEngine::attachToCoreRequested, this, [this](const QString &coreFile) {
|
||||
auto rc = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE);
|
||||
rc->copyDataFromRunControl(m_runControl);
|
||||
rc->resetDataForAttachToCore();
|
||||
auto name = QString(Tr::tr("%1 - Snapshot %2").arg(m_runControl->displayName()).arg(++m_snapshotCounter));
|
||||
auto debugger = new DebuggerRunTool(rc);
|
||||
DebuggerRunParameters &rp = debugger->runParameters();
|
||||
rp.setStartMode(AttachToCore);
|
||||
rp.setCloseMode(DetachAtClose);
|
||||
rp.setDisplayName(name);
|
||||
rp.setCoreFilePath(FilePath::fromString(coreFile));
|
||||
rp.setSnapshot(true);
|
||||
rc->start();
|
||||
});
|
||||
}
|
||||
}
|
||||
Utils::reverseForeach(m_engines, [](DebuggerEngine *engine) { engine->start(); });
|
||||
}
|
||||
|
||||
void EnginesDriver::showMessage(const QString &msg, int channel, int timeout)
|
||||
{
|
||||
if (channel == ConsoleOutput)
|
||||
debuggerConsole()->printItem(ConsoleItem::DefaultType, msg);
|
||||
|
||||
QTC_ASSERT(!m_engines.isEmpty(), qDebug() << msg; return);
|
||||
|
||||
for (auto engine : m_engines)
|
||||
engine->showMessage(msg, channel, timeout);
|
||||
switch (channel) {
|
||||
case AppOutput:
|
||||
m_runControl->postMessage(msg, StdOutFormat);
|
||||
break;
|
||||
case AppError:
|
||||
m_runControl->postMessage(msg, StdErrFormat);
|
||||
break;
|
||||
case AppStuff:
|
||||
m_runControl->postMessage(msg, DebugFormat);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerRunTool::continueAfterDebugServerStart()
|
||||
{
|
||||
const auto engines = createEngines(runControl(), runParameters());
|
||||
|
Reference in New Issue
Block a user