// make an assumption to allow pressing of the down
// key, before the first model run:
// parent is likely the lineedit
- QWidget *p = qobject_cast<QWidget*>(parent);
+ QWidget *p = qobject_cast<QWidget *>(parent);
if (p) {
p->installEventFilter(d_ptr->model);
QString objectName = p->objectName();
return;
d_ptr->model->list = d_ptr->model->settings->value(objectName).toStringList();
}
+
+ QLineEdit *l = qobject_cast<QLineEdit *>(parent);
+ if (l && d_ptr->model->list.count())
+ l->setText(d_ptr->model->list.at(0));
+
setModel(d_ptr->model);
HistoryLineDelegate *delegate = new HistoryLineDelegate;
HistoryLineView *view = new HistoryLineView(d_ptr, delegate->pixmap.width());
dumperoptionpage.ui \
commonoptionspage.ui \
startexternaldialog.ui \
- startremotedialog.ui
+ startremotedialog.ui \
+ startremoteenginedialog.ui
RESOURCES += debugger.qrc
AttachTcf, // Attach to a running Target Communication Framework agent
AttachCore, // Attach to a core file
AttachToRemote, // Start and attach to a remote process
- StartRemoteGdb // Start gdb itself remotely
+ StartRemoteGdb, // Start gdb itself remotely
+ StartRemoteEngine // Start ipc guest engine on other machine
};
enum DebuggerCapabilities
#include "ui_attachtcfdialog.h"
#include "ui_startexternaldialog.h"
#include "ui_startremotedialog.h"
+#include "ui_startremoteenginedialog.h"
#ifdef Q_OS_WIN
# include "shared/dbgwinutils.h"
return ok;
}
+///////////////////////////////////////////////////////////////////////
+//
+// StartRemoteEngineDialog
+//
+///////////////////////////////////////////////////////////////////////
+
+StartRemoteEngineDialog::StartRemoteEngineDialog(QWidget *parent) :
+ QDialog(parent) ,
+ m_ui(new Ui::StartRemoteEngineDialog)
+{
+ m_ui->setupUi(this);
+ m_ui->host->setCompleter(new HistoryCompleter(m_ui->host));
+ m_ui->username->setCompleter(new HistoryCompleter(m_ui->username));
+ m_ui->enginepath->setCompleter(new HistoryCompleter(m_ui->enginepath));
+ m_ui->inferiorpath->setCompleter(new HistoryCompleter(m_ui->inferiorpath));
+ connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+StartRemoteEngineDialog::~StartRemoteEngineDialog()
+{
+}
+
+QString StartRemoteEngineDialog::host() const
+{
+ return m_ui->host->text();
+}
+
+QString StartRemoteEngineDialog::username() const
+{
+ return m_ui->username->text();
+}
+
+QString StartRemoteEngineDialog::password() const
+{
+ return m_ui->password->text();
+}
+
+QString StartRemoteEngineDialog::inferiorPath() const
+{
+ return m_ui->inferiorpath->text();
+}
+
+QString StartRemoteEngineDialog::enginePath() const
+{
+ return m_ui->enginepath->text();
+}
+
+
} // namespace Internal
} // namespace Debugger
class AttachTcfDialog;
class StartExternalDialog;
class StartRemoteDialog;
+class StartRemoteEngineDialog;
} // namespace Ui
QT_END_NAMESPACE
QDialogButtonBox *m_box;
};
+class StartRemoteEngineDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit StartRemoteEngineDialog(QWidget *parent);
+ ~StartRemoteEngineDialog();
+ QString username() const;
+ QString host() const;
+ QString password() const;
+ QString enginePath() const;
+ QString inferiorPath() const;
+
+private:
+ Ui::StartRemoteEngineDialog *m_ui;
+};
+
} // namespace Debugger
} // namespace Internal
const char * const ATTACHTCF = "Debugger.AttachTcf";
const char * const ATTACHREMOTE = "Debugger.AttachRemote";
const char * const ATTACHREMOTECDB = "Debugger.AttachRemoteCDB";
+const char * const STARTREMOTELLDB = "Debugger.StartRemoteLLDB";
const char * const DETACH = "Debugger.Detach";
const char * const RUN_TO_LINE1 = "Debugger.RunToLine1";
void startExternalApplication();
void startRemoteCdbSession();
void startRemoteApplication();
+ void startRemoteEngine();
void attachExternalApplication();
void attachExternalApplication
(qint64 pid, const QString &binary, const QString &crashParameter);
QAction *m_startExternalAction;
QAction *m_startRemoteAction;
QAction *m_startRemoteCdbAction;
+ QAction *m_startRemoteLldbAction;
QAction *m_attachExternalAction;
QAction *m_attachCoreAction;
QAction *m_attachTcfAction;
act->setText(tr("Start and Debug External Application..."));
connect(act, SIGNAL(triggered()), SLOT(startExternalApplication()));
+ act = m_startRemoteLldbAction = new QAction(this);
+ act->setText(tr("Start and Debug External Application with External Engine..."));
+ connect(act, SIGNAL(triggered()), SLOT(startRemoteEngine()));
+
act = m_attachExternalAction = new QAction(this);
act->setText(tr("Attach to Running External Application..."));
connect(act, SIGNAL(triggered()), SLOT(attachExternalApplication()));
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, CC::G_DEFAULT_ONE);
+ cmd = am->registerAction(m_startRemoteLldbAction,
+ Constants::STARTREMOTELLDB, globalcontext);
+ cmd->setAttribute(Command::CA_Hide);
+ mstart->addAction(cmd, CC::G_DEFAULT_ONE);
+
cmd = am->registerAction(m_attachExternalAction,
Constants::ATTACHEXTERNAL, globalcontext);
cmd->setAttribute(Command::CA_Hide);
startDebugger(rc);
}
+void DebuggerPluginPrivate::startRemoteEngine()
+{
+ DebuggerStartParameters sp;
+ StartRemoteEngineDialog dlg(mainWindow());
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ sp.connParams.host = dlg.host();
+ sp.connParams.uname = dlg.username();
+ sp.connParams.pwd = dlg.password();
+
+
+ qDebug() << sp.connParams.host << sp.connParams.uname << sp.connParams.pwd;
+
+ sp.connParams.timeout = 5;
+ sp.connParams.authType = SshConnectionParameters::AuthByPwd;
+ sp.connParams.port = 22;
+ sp.connParams.proxyType = SshConnectionParameters::NoProxy;
+
+ sp.executable = dlg.inferiorPath();
+ sp.serverStartScript = dlg.enginePath();
+ sp.startMode = StartRemoteEngine;
+ if (RunControl *rc = createDebugger(sp))
+ startDebugger(rc);
+}
+
void DebuggerPluginPrivate::enableReverseDebuggingTriggered(const QVariant &value)
{
QTC_ASSERT(m_reverseToolButton, return);
}
}
- if (getenv("QTC_LLDB_GUEST")) {
+ // Fixme: unclean ipc override. Someone please have a better idea
+ if (sp.startMode == StartRemoteEngine)
+ // for now thats the only supported ipc engine
engineType = LldbEngineType;
- sp.executable = sp.processArgs;
- qDebug() << "DEBUGGING" << sp.executable;
- }
// Fixme: 1 of 3 testing hacks.
if (sp.processArgs.startsWith(__("@tcf@ ")))
namespace Debugger {
namespace Internal {
+SshIODevice::SshIODevice(Core::SshRemoteProcessRunner::Ptr r)
+ : runner(r)
+ , buckethead(0)
+{
+ setOpenMode(QIODevice::ReadWrite | QIODevice::Unbuffered);
+ connect (runner.data(), SIGNAL(processStarted()),
+ this, SLOT(processStarted()));
+ connect(runner.data(), SIGNAL(processOutputAvailable(const QByteArray &)),
+ this, SLOT(outputAvailable(const QByteArray &)));
+ connect(runner.data(), SIGNAL(processErrorOutputAvailable(const QByteArray &)),
+ this, SLOT(errorOutputAvailable(const QByteArray &)));
+}
+qint64 SshIODevice::bytesAvailable () const
+{
+ qint64 r = QIODevice::bytesAvailable();
+ foreach (const QByteArray &bucket, buckets)
+ r += bucket.size();
+ r-= buckethead;
+ return r;
+}
+qint64 SshIODevice::writeData (const char * data, qint64 maxSize)
+{
+ if (proc == 0) {
+ startupbuffer += QByteArray::fromRawData(data, maxSize);
+ return maxSize;
+ }
+ proc->sendInput(QByteArray::fromRawData(data, maxSize));
+ return maxSize;
+}
+qint64 SshIODevice::readData (char * data, qint64 maxSize)
+{
+ if (proc == 0)
+ return 0;
+ qint64 size = maxSize;
+ while (size > 0) {
+ if (!buckets.size()) {
+ return maxSize - size;
+ }
+ QByteArray &bucket = buckets.head();
+ if ((size + buckethead) >= bucket.size()) {
+ int d = bucket.size() - buckethead;
+ memcpy(data, bucket.data() + buckethead, d);
+ data += d;
+ size -= d;
+ buckets.dequeue();
+ buckethead = 0;
+ } else {
+ memcpy(data, bucket.data() + buckethead, size);
+ data += size;
+ buckethead += size;
+ size = 0;
+ }
+ }
+ return maxSize - size;
+}
+
+void SshIODevice::processStarted()
+{
+ proc = runner->process();
+ proc->sendInput(startupbuffer);
+}
+
+void SshIODevice::outputAvailable(const QByteArray &output)
+{
+ buckets.enqueue(output);
+ emit readyRead();
+}
+
+void SshIODevice::errorOutputAvailable(const QByteArray &output)
+{
+ fprintf(stderr, "%s", output.data());
+}
+
+
LldbEngineHost::LldbEngineHost(const DebuggerStartParameters &startParameters)
:IPCEngineHost(startParameters)
{
showMessage(QLatin1String("setting up coms"));
- m_guestProcess = new QProcess(this);
+ if (startParameters.startMode == StartRemoteEngine)
+ {
+ m_guestProcess = 0;
+ Core::SshRemoteProcessRunner::Ptr runner =
+ Core::SshRemoteProcessRunner::create(startParameters.connParams);
+ connect (runner.data(), SIGNAL(connectionError(Core::SshError)),
+ this, SLOT(sshConnectionError(Core::SshError)));
+ runner->run(startParameters.serverStartScript.toUtf8());
+ setGuestDevice(new SshIODevice(runner));
+ } else {
+ m_guestProcess = new QProcess(this);
- connect(m_guestProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
- this, SLOT(finished(int, QProcess::ExitStatus)));
+ connect(m_guestProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(finished(int, QProcess::ExitStatus)));
- connect(m_guestProcess, SIGNAL(readyReadStandardError()), this,
- SLOT(stderrReady()));
+ connect(m_guestProcess, SIGNAL(readyReadStandardError()), this,
+ SLOT(stderrReady()));
- QString a = Core::ICore::instance()->resourcePath() + QLatin1String("/qtcreator-lldb");
- if(getenv("QTC_LLDB_GUEST") != 0)
- a = QString::fromLocal8Bit(getenv("QTC_LLDB_GUEST"));
+ QString a = Core::ICore::instance()->resourcePath() + QLatin1String("/qtcreator-lldb");
+ if(getenv("QTC_LLDB_GUEST") != 0)
+ a = QString::fromLocal8Bit(getenv("QTC_LLDB_GUEST"));
- showStatusMessage(QString(QLatin1String("starting %1")).arg(a));
+ showStatusMessage(QString(QLatin1String("starting %1")).arg(a));
- m_guestProcess->start(a, QStringList());
- m_guestProcess->setReadChannel(QProcess::StandardOutput);
+ m_guestProcess->start(a, QStringList(), QIODevice::ReadWrite | QIODevice::Unbuffered);
+ m_guestProcess->setReadChannel(QProcess::StandardOutput);
- if (!m_guestProcess->waitForStarted()) {
- showStatusMessage(tr("qtcreator-lldb failed to start %1").arg(m_guestProcess->error()));
- notifyEngineSpontaneousShutdown();
- return;
- }
+ if (!m_guestProcess->waitForStarted()) {
+ showStatusMessage(tr("qtcreator-lldb failed to start %1").arg(m_guestProcess->error()));
+ notifyEngineSpontaneousShutdown();
+ return;
+ }
- setGuestDevice(m_guestProcess);
+ setGuestDevice(m_guestProcess);
+ }
}
LldbEngineHost::~LldbEngineHost()
{
showMessage(QLatin1String("tear down qtcreator-lldb"));
- disconnect(m_guestProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
- this, SLOT(finished (int, QProcess::ExitStatus)));
- m_guestProcess->terminate();
- m_guestProcess->kill();
+
+ if (m_guestProcess) {
+ disconnect(m_guestProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(finished (int, QProcess::ExitStatus)));
+
+
+ m_guestProcess->terminate();
+ m_guestProcess->kill();
+ }
+ if (m_ssh.data() && m_ssh->process().data()) {
+ // TODO: openssh doesn't do that
+
+ m_ssh->process()->kill();
+ }
}
void LldbEngineHost::nuke()
m_guestProcess->kill();
notifyEngineSpontaneousShutdown();
}
+void LldbEngineHost::sshConnectionError(Core::SshError e)
+{
+ showStatusMessage(tr("ssh connection error: %1").arg(e));
+}
void LldbEngineHost::finished(int, QProcess::ExitStatus status)
{
} // namespace Internal
} // namespace Debugger
+
#define DEBUGGER_LLDBENGINE_HOST_H
#include "ipcenginehost.h"
+#include <coreplugin/ssh/ssherrors.h>
+#include <coreplugin/ssh/sshconnection.h>
+#include <coreplugin/ssh/sshremoteprocess.h>
+#include <coreplugin/ssh/sshremoteprocessrunner.h>
#include <QtCore/QProcess>
+#include <QtCore/QQueue>
namespace Debugger {
namespace Internal {
+class SshIODevice : public QIODevice
+{
+Q_OBJECT
+public:
+ SshIODevice(Core::SshRemoteProcessRunner::Ptr r);
+ virtual qint64 bytesAvailable () const;
+ virtual qint64 writeData (const char * data, qint64 maxSize);
+ virtual qint64 readData (char * data, qint64 maxSize);
+private slots:
+ void processStarted();
+ void outputAvailable(const QByteArray &output);
+ void errorOutputAvailable(const QByteArray &output);
+private:
+ Core::SshRemoteProcessRunner::Ptr runner;
+ Core::SshRemoteProcess::Ptr proc;
+ int buckethead;
+ QQueue<QByteArray> buckets;
+ QByteArray startupbuffer;
+};
+
class LldbEngineHost : public IPCEngineHost
{
Q_OBJECT
private:
QProcess *m_guestProcess;
+ Core::SshRemoteProcessRunner::Ptr m_ssh;
protected:
void nuke();
private slots:
+ void sshConnectionError(Core::SshError);
void finished(int, QProcess::ExitStatus);
void stderrReady();
};