Commit 0ab67db5 authored by Arvid Ephraim Picciani's avatar Arvid Ephraim Picciani
Browse files

lldb: introduce dialog to start engine remotely

parent 1d5fadb1
......@@ -198,7 +198,7 @@ HistoryCompleter::HistoryCompleter(QObject *parent)
// 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();
......@@ -206,6 +206,11 @@ HistoryCompleter::HistoryCompleter(QObject *parent)
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());
......
......@@ -106,7 +106,8 @@ FORMS += attachexternaldialog.ui \
dumperoptionpage.ui \
commonoptionspage.ui \
startexternaldialog.ui \
startremotedialog.ui
startremotedialog.ui \
startremoteenginedialog.ui
RESOURCES += debugger.qrc
......
......@@ -140,7 +140,8 @@ enum DebuggerStartMode
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
......
......@@ -36,6 +36,7 @@
#include "ui_attachtcfdialog.h"
#include "ui_startexternaldialog.h"
#include "ui_startremotedialog.h"
#include "ui_startremoteenginedialog.h"
#ifdef Q_OS_WIN
# include "shared/dbgwinutils.h"
......@@ -896,5 +897,54 @@ bool AddressDialog::isValid() const
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
......@@ -45,6 +45,7 @@ class AttachExternalDialog;
class AttachTcfDialog;
class StartExternalDialog;
class StartRemoteDialog;
class StartRemoteEngineDialog;
} // namespace Ui
QT_END_NAMESPACE
......@@ -242,6 +243,23 @@ private:
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
......
......@@ -345,6 +345,7 @@ const char * const ATTACHCORE = "Debugger.AttachCore";
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";
......@@ -1005,6 +1006,7 @@ public slots:
void startExternalApplication();
void startRemoteCdbSession();
void startRemoteApplication();
void startRemoteEngine();
void attachExternalApplication();
void attachExternalApplication
(qint64 pid, const QString &binary, const QString &crashParameter);
......@@ -1307,6 +1309,7 @@ public:
QAction *m_startExternalAction;
QAction *m_startRemoteAction;
QAction *m_startRemoteCdbAction;
QAction *m_startRemoteLldbAction;
QAction *m_attachExternalAction;
QAction *m_attachCoreAction;
QAction *m_attachTcfAction;
......@@ -1716,6 +1719,10 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
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()));
......@@ -1765,6 +1772,11 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
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);
......@@ -2286,6 +2298,32 @@ void DebuggerPluginPrivate::startRemoteApplication()
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);
......
......@@ -501,11 +501,10 @@ void DebuggerRunControl::createEngine(const DebuggerStartParameters &startParams
}
}
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@ ")))
......
......@@ -58,45 +58,140 @@
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()
......@@ -108,6 +203,10 @@ 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)
{
......@@ -128,3 +227,4 @@ DebuggerEngine *createLldbEngine(const DebuggerStartParameters &startParameters)
} // namespace Internal
} // namespace Debugger
......@@ -31,12 +31,37 @@
#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
......@@ -47,9 +72,11 @@ public:
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();
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment