Debugger: Rework 'Attach to unstarted application' startup

Change-Id: I42c7ce8e413c850e05b02f5d6fe1b83376436c65
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
hjk
2015-02-25 16:30:23 +01:00
parent 027328059b
commit bf87fc9640
8 changed files with 72 additions and 74 deletions

View File

@@ -487,7 +487,7 @@ AttachToQmlPortDialog::AttachToQmlPortDialog(QWidget *parent)
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setWindowTitle(tr("Start Debugger")); setWindowTitle(tr("Start Debugger"));
d->kitChooser = new DebuggerKitChooser(DebuggerKitChooser::RemoteDebugging, this); d->kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging, this);
d->kitChooser->populate(); d->kitChooser->populate();
d->portSpinBox = new QSpinBox(this); d->portSpinBox = new QSpinBox(this);

View File

@@ -59,12 +59,14 @@ class StartApplicationParameters;
class StartApplicationDialogPrivate; class StartApplicationDialogPrivate;
class StartRemoteEngineDialogPrivate; class StartRemoteEngineDialogPrivate;
class DebuggerKitChooser : public ProjectExplorer::KitChooser { class DebuggerKitChooser : public ProjectExplorer::KitChooser
{
Q_OBJECT Q_OBJECT
public:
enum Mode { RemoteDebugging, LocalDebugging };
explicit DebuggerKitChooser(Mode mode = RemoteDebugging, QWidget *parent = 0); public:
enum Mode { AnyDebugging, LocalDebugging };
explicit DebuggerKitChooser(Mode mode = AnyDebugging, QWidget *parent = 0);
protected: protected:
bool kitMatches(const ProjectExplorer::Kit *k) const; bool kitMatches(const ProjectExplorer::Kit *k) const;

View File

@@ -612,7 +612,8 @@ public:
m_threadBox->setCurrentIndex(index); m_threadBox->setCurrentIndex(index);
m_threadBox->blockSignals(state); m_threadBox->blockSignals(state);
} }
DebuggerRunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process);
DebuggerRunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process, bool contAfterAttach);
void writeSettings() void writeSettings()
{ {
@@ -710,13 +711,10 @@ public:
void startAndDebugApplication(); void startAndDebugApplication();
void startRemoteCdbSession(); void startRemoteCdbSession();
void startRemoteServer(); void startRemoteServerAndAttachToProcess();
void attachToRemoteServer(); void attachToRemoteServer();
void attachToProcess(bool startServerOnly);
void attachToRunningApplication(); void attachToRunningApplication();
void attachToUnstartedApplicationDialog(); void attachToUnstartedApplicationDialog();
void attachToFoundProcess();
void continueOnAttach(Debugger::DebuggerState state);
void attachToQmlPort(); void attachToQmlPort();
Q_SLOT void runScheduled(); Q_SLOT void runScheduled();
void attachCore(); void attachCore();
@@ -1400,22 +1398,10 @@ void DebuggerPluginPrivate::attachToRemoteServer()
} }
} }
void DebuggerPluginPrivate::startRemoteServer() void DebuggerPluginPrivate::startRemoteServerAndAttachToProcess()
{ {
attachToProcess(true); auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging);
} auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent());
void DebuggerPluginPrivate::attachToRunningApplication()
{
attachToProcess(false);
}
void DebuggerPluginPrivate::attachToProcess(bool startServerOnly)
{
const DebuggerKitChooser::Mode mode = startServerOnly ?
DebuggerKitChooser::RemoteDebugging : DebuggerKitChooser::LocalDebugging;
DebuggerKitChooser *kitChooser = new DebuggerKitChooser(mode);
DeviceProcessesDialog *dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent());
dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process")); dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process"));
dlg->showAllDevices(); dlg->showAllDevices();
if (dlg->exec() == QDialog::Rejected) { if (dlg->exec() == QDialog::Rejected) {
@@ -1429,62 +1415,63 @@ void DebuggerPluginPrivate::attachToProcess(bool startServerOnly)
IDevice::ConstPtr device = DeviceKitInformation::device(kit); IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return); QTC_ASSERT(device, return);
if (device->type() != PE::DESKTOP_DEVICE_TYPE) { GdbServerStarter *starter = new GdbServerStarter(dlg, true);
GdbServerStarter *starter = new GdbServerStarter(dlg, startServerOnly); starter->run();
starter->run(); }
void DebuggerPluginPrivate::attachToRunningApplication()
{
auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::LocalDebugging);
auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent());
dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process"));
dlg->showAllDevices();
if (dlg->exec() == QDialog::Rejected) {
delete dlg;
return;
}
dlg->setAttribute(Qt::WA_DeleteOnClose);
Kit *kit = kitChooser->currentKit();
QTC_ASSERT(kit, return);
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return);
if (device->type() == PE::DESKTOP_DEVICE_TYPE) {
attachToRunningProcess(kit, dlg->currentProcess(), false);
} else { } else {
attachToRunningProcess(kit, dlg->currentProcess()); GdbServerStarter *starter = new GdbServerStarter(dlg, true);
starter->run();
} }
} }
void DebuggerPluginPrivate::attachToUnstartedApplicationDialog() void DebuggerPluginPrivate::attachToUnstartedApplicationDialog()
{ {
UnstartedAppWatcherDialog *dlg = new UnstartedAppWatcherDialog(ICore::dialogParent()); auto dlg = new UnstartedAppWatcherDialog(ICore::dialogParent());
connect(dlg, &QDialog::finished, dlg, &QObject::deleteLater); connect(dlg, &QDialog::finished, dlg, &QObject::deleteLater);
connect(dlg, &UnstartedAppWatcherDialog::processFound, this, &DebuggerPluginPrivate::attachToFoundProcess); connect(dlg, &UnstartedAppWatcherDialog::processFound, this, [this, dlg] {
DebuggerRunControl *rc = attachToRunningProcess(dlg->currentKit(),
dlg->currentProcess(),
dlg->continueOnAttach());
if (!rc)
return;
if (dlg->hideOnAttach())
connect(rc, &RunControl::finished, dlg, &UnstartedAppWatcherDialog::startWatching);
});
dlg->show(); dlg->show();
} }
void DebuggerPluginPrivate::attachToFoundProcess()
{
UnstartedAppWatcherDialog *dlg = qobject_cast<UnstartedAppWatcherDialog *>(QObject::sender());
if (!dlg)
return;
DebuggerRunControl *rc = attachToRunningProcess(dlg->currentKit(), dlg->currentProcess());
if (!rc)
return;
if (dlg->hideOnAttach())
connect(rc, &RunControl::finished, dlg, &UnstartedAppWatcherDialog::startWatching);
if (dlg->continueOnAttach()) {
connect(currentEngine(), &DebuggerEngine::stateChanged,
this, &DebuggerPluginPrivate::continueOnAttach);
}
}
void DebuggerPluginPrivate::continueOnAttach(Debugger::DebuggerState state)
{
// wait for state when we can continue
if (state != InferiorStopOk)
return;
// disconnect and continue
disconnect(currentEngine(), &DebuggerEngine::stateChanged,
this, &DebuggerPluginPrivate::continueOnAttach);
handleExecContinue();
}
DebuggerRunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, DebuggerRunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit,
DeviceProcessItem process) DeviceProcessItem process, bool contAfterAttach)
{ {
QTC_ASSERT(kit, return 0); QTC_ASSERT(kit, return 0);
IDevice::ConstPtr device = DeviceKitInformation::device(kit); IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return 0); QTC_ASSERT(device, return 0);
if (process.pid == 0) { if (process.pid == 0) {
AsynchronousMessageBox::warning(tr("Warning"), AsynchronousMessageBox::warning(tr("Warning"), tr("Cannot attach to process with PID 0"));
tr("Cannot attach to process with PID 0"));
return 0; return 0;
} }
@@ -1512,6 +1499,7 @@ DebuggerRunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit,
sp.executable = process.exe; sp.executable = process.exe;
sp.startMode = AttachExternal; sp.startMode = AttachExternal;
sp.closeMode = DetachAtClose; sp.closeMode = DetachAtClose;
sp.continueAfterAttach = contAfterAttach;
return DebuggerRunControlFactory::createAndScheduleRun(sp); return DebuggerRunControlFactory::createAndScheduleRun(sp);
} }
@@ -2648,7 +2636,7 @@ void DebuggerPluginPrivate::extensionsInitialized()
act = m_startRemoteServerAction = new QAction(this); act = m_startRemoteServerAction = new QAction(this);
act->setText(tr("Start Remote Debug Server Attached to Process...")); act->setText(tr("Start Remote Debug Server Attached to Process..."));
connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServer); connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServerAndAttachToProcess);
act = m_attachToRunningApplication = new QAction(this); act = m_attachToRunningApplication = new QAction(this);
act->setText(tr("Attach to Running Application...")); act->setText(tr("Attach to Running Application..."));

View File

@@ -54,6 +54,8 @@ private:
QObject *remoteCommand(const QStringList &options, const QStringList &arguments); QObject *remoteCommand(const QStringList &options, const QStringList &arguments);
ShutdownFlag aboutToShutdown(); ShutdownFlag aboutToShutdown();
void extensionsInitialized(); void extensionsInitialized();
// Called from AppOutputPane::attachToRunControl().
Q_SLOT void attachExternalApplication(ProjectExplorer::RunControl *rc); Q_SLOT void attachExternalApplication(ProjectExplorer::RunControl *rc);
#ifdef WITH_TESTS #ifdef WITH_TESTS

View File

@@ -89,12 +89,17 @@ void GdbAttachEngine::handleAttach(const DebuggerResponse &response)
case ResultRunning: case ResultRunning:
showMessage(_("INFERIOR ATTACHED")); showMessage(_("INFERIOR ATTACHED"));
if (state() == EngineRunRequested) { if (state() == EngineRunRequested) {
// FIXME: Really? Looks like we are always stopped already. // Happens e.g. for "Attach to unstarted application"
// We will get a '*stopped' later that we'll interpret as 'spontaneous' // We will get a '*stopped' later that we'll interpret as 'spontaneous'
// So acknowledge the current state and put a delayed 'continue' in the pipe. // So acknowledge the current state and put a delayed 'continue' in the pipe.
showMessage(msgAttachedToStoppedInferior(), StatusBar); showMessage(tr("Attached to running application"), StatusBar);
notifyEngineRunAndInferiorRunOk(); notifyEngineRunAndInferiorRunOk();
interruptInferior(); } else {
// InferiorStopOk, e.g. for "Attach to running application".
// The *stopped came in between sending the 'attach' and
// receiving its '^done'.
if (startParameters().continueAfterAttach)
continueInferiorInternal();
} }
break; break;
case ResultError: case ResultError:

View File

@@ -63,7 +63,7 @@ public:
StartGdbServerDialogPrivate() : dialog(0), kit(0) {} StartGdbServerDialogPrivate() : dialog(0), kit(0) {}
DeviceProcessesDialog *dialog; DeviceProcessesDialog *dialog;
bool startServerOnly; bool attachToServer;
DeviceProcessItem process; DeviceProcessItem process;
Kit *kit; Kit *kit;
IDevice::ConstPtr device; IDevice::ConstPtr device;
@@ -72,7 +72,7 @@ public:
SshRemoteProcessRunner runner; SshRemoteProcessRunner runner;
}; };
GdbServerStarter::GdbServerStarter(DeviceProcessesDialog *dlg, bool startServerOnly) GdbServerStarter::GdbServerStarter(DeviceProcessesDialog *dlg, bool attachAfterServerStart)
: QObject(dlg) : QObject(dlg)
{ {
d = new StartGdbServerDialogPrivate; d = new StartGdbServerDialogPrivate;
@@ -80,7 +80,7 @@ GdbServerStarter::GdbServerStarter(DeviceProcessesDialog *dlg, bool startServerO
d->kit = dlg->kitChooser()->currentKit(); d->kit = dlg->kitChooser()->currentKit();
d->process = dlg->currentProcess(); d->process = dlg->currentProcess();
d->device = DeviceKitInformation::device(d->kit); d->device = DeviceKitInformation::device(d->kit);
d->startServerOnly = startServerOnly; d->attachToServer = attachAfterServerStart;
} }
GdbServerStarter::~GdbServerStarter() GdbServerStarter::~GdbServerStarter()
@@ -167,7 +167,7 @@ void GdbServerStarter::handleProcessErrorOutput()
logMessage(tr("Port %1 is now accessible.").arg(port)); logMessage(tr("Port %1 is now accessible.").arg(port));
logMessage(tr("Server started on %1:%2") logMessage(tr("Server started on %1:%2")
.arg(d->device->sshParameters().host).arg(port)); .arg(d->device->sshParameters().host).arg(port));
if (!d->startServerOnly) if (d->attachToServer)
attach(port); attach(port);
} }
} }

View File

@@ -45,7 +45,8 @@ class GdbServerStarter : public QObject
Q_OBJECT Q_OBJECT
public: public:
GdbServerStarter(ProjectExplorer::DeviceProcessesDialog *dlg, bool startServerOnly); GdbServerStarter(ProjectExplorer::DeviceProcessesDialog *dlg,
bool attachAfterServerStart);
~GdbServerStarter(); ~GdbServerStarter();
void run(); void run();

View File

@@ -263,7 +263,7 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent)
d->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); d->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
d->kitChooser = new DebuggerKitChooser(DebuggerKitChooser::RemoteDebugging, this); d->kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging, this);
d->kitChooser->populate(); d->kitChooser->populate();
d->forceLocalCheckBox = new QCheckBox(this); d->forceLocalCheckBox = new QCheckBox(this);