Commit 776a45df authored by Arvid Ephraim Picciani's avatar Arvid Ephraim Picciani
Browse files

lldb: move away from local sockets to stdio coms

can now pluginto any host via ssh.
define QTC_LLDB_GUEST=/some/script in the env
where script is a wrapper that does ssh, or whatever you need
parent 0ba7fd67
......@@ -460,6 +460,8 @@ static DebuggerEngineType engineForToolChain(int toolChainType)
case ProjectExplorer::ToolChain_RVCT_ARMV5_GNUPOC:
case ProjectExplorer::ToolChain_GCCE_GNUPOC:
case ProjectExplorer::ToolChain_GCC_MAEMO:
if (getenv("QTC_LLDB_GUEST"))
return LldbEngineType;
#ifdef WITH_LLDB
// lldb override
if (Core::ICore::instance()->settings()->value("LLDB/enabled").toBool())
......
......@@ -107,6 +107,12 @@ LldbEngineGuest::~LldbEngineGuest()
delete m_listener;
}
void LldbEngineGuest::nuke()
{
::exit(4);
}
void LldbEngineGuest::setupEngine()
{
DEBUG_FUNC_ENTER;
......@@ -159,8 +165,15 @@ void LldbEngineGuest::runEngine()
for (int i = 0; i < m_environment.count(); i++) {
envp[i] = m_environment[i].data();
}
lldb::SBError err;
*m_process = m_target->Launch(argp, envp, NULL, NULL, false, err);
*m_process = m_target->LaunchProcess(argp, envp, NULL, NULL, false);
if (!err.Success()) {
showMessage(QString::fromLocal8Bit(err.GetCString()));
qDebug() << err.GetCString();
notifyEngineRunFailed();
}
/*
* note, the actual string ptrs are still valid. They are in m_environment.
......@@ -170,7 +183,7 @@ void LldbEngineGuest::runEngine()
if (!m_process->IsValid())
notifyEngineRunFailed();
QTC_ASSERT(m_listener->IsValid(), qDebug()<<false);
QTC_ASSERT(m_listener->IsValid(), qDebug() << false);
m_listener->StartListeningForEvents(m_process->GetBroadcaster(), UINT32_MAX);
QMetaObject::invokeMethod(m_worker, "listen", Qt::QueuedConnection,
Q_ARG(lldb::SBListener *, m_listener));
......@@ -648,7 +661,7 @@ void LldbEngineGuest::updateThreads()
void LldbEngineGuest::lldbEvent(lldb::SBEvent *ev)
{
qDebug() << "lldbevent" << ev->GetType() <<
ev->GetDataFlavor() << m_process->GetState() << (int)state();
m_process->GetState() << (int)state();
uint32_t etype = ev->GetType();
switch (etype) {
......
......@@ -70,6 +70,7 @@ public:
explicit LldbEngineGuest();
~LldbEngineGuest();
void nuke();
void setupEngine();
void setupInferior(const QString &executable, const QStringList &arguments,
const QStringList &environment);
......
#include <QtCore/QCoreApplication>
#include <QtNetwork/QLocalSocket>
#include "lldbengineguest.h"
#include <cstdio>
#include <QSocketNotifier>
#include <QQueue>
class DiePlease: public QThread
// #define DO_STDIO_DEBUG 1
#ifdef DO_STDIO_DEBUG
#define D_STDIO0(x) qDebug(x)
#define D_STDIO1(x,a1) qDebug(x,a1)
#define D_STDIO2(x,a1,a2) qDebug(x,a1,a2)
#define D_STDIO3(x,a1,a2,a3) qDebug(x,a1,a2,a3)
#else
#define D_STDIO0(x)
#define D_STDIO1(x,a1)
#define D_STDIO2(x,a1,a2)
#define D_STDIO3(x,a1,a2,a3)
#endif
class Stdio : public QIODevice
{
virtual void run()
Q_OBJECT
public:
QSocketNotifier notify;
Stdio()
: QIODevice()
, notify(fileno(stdin), QSocketNotifier::Read)
, buckethead(0)
{
getc(stdin);
::exit(0);
setvbuf(stdin , NULL , _IONBF , 0);
setvbuf(stdout , NULL , _IONBF , 0);
setOpenMode(QIODevice::ReadWrite | QIODevice::Unbuffered);
connect(&notify, SIGNAL(activated(int)), this, SLOT(activated()));
}
virtual qint64 bytesAvailable () const
{
qint64 r = QIODevice::bytesAvailable();
foreach (const QByteArray &bucket, buckets)
r += bucket.size();
r-= buckethead;
return r;
}
virtual qint64 readData (char * data, qint64 maxSize)
{
D_STDIO1("readData %lli",maxSize);
qint64 size = maxSize;
while (size > 0) {
if (!buckets.size()) {
D_STDIO1("done prematurely with %lli", maxSize - size);
return maxSize - size;
}
QByteArray &bucket = buckets.head();
if ((size + buckethead) >= bucket.size()) {
int d = bucket.size() - buckethead;
D_STDIO3("read (over bucket) d: %i buckethead: %i bucket.size(): %i",
d, buckethead, bucket.size());
memcpy(data, bucket.data() + buckethead, d);
data += d;
size -= d;
buckets.dequeue();
buckethead = 0;
} else {
D_STDIO1("read (in bucket) size: %lli", size);
memcpy(data, bucket.data() + buckethead, size);
data += size;
buckethead += size;
size = 0;
}
}
D_STDIO1("done with %lli",(maxSize - size));
return maxSize - size;
}
virtual qint64 writeData (const char * data, qint64 maxSize)
{
return ::write(fileno(stdout), data, maxSize);
}
QQueue<QByteArray> buckets;
int buckethead;
private slots:
void activated()
{
QByteArray a;
a.resize(1000);
int ret = ::read(fileno(stdin), a.data(), 1000);
assert(ret <= 1000);
D_STDIO1("activated %i", ret);
a.resize(ret);
buckets.enqueue(a);
emit readyRead();
}
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
qDebug() << "guest engine operational";
Debugger::Internal::LldbEngineGuest lldb;
QLocalSocket s;
if (argc > 1) {
// Pure test code. This is not intended for end users.
// TODO: maybe some day we can have real unit tests for debugger engines?
setenv("LLDB_DEBUGSERVER_PATH", "/Users/aep/qt-creator/src/plugins/debugger/lldb/lldb/build/Release/LLDB.framework/Resources/debugserver", 0);
lldb.setupEngine();
QStringList env;
env.append(QLatin1String("DYLD_IMAGE_SUFFIX=_debug"));
lldb.setupInferior(argv[1], QStringList(), env);
Debugger::Internal::BreakpointParameters bp;
bp.ignoreCount = 0;
bp.lineNumber = 64;
bp.fileName = QLatin1String("main.cpp");
lldb.addBreakpoint(0, bp);
lldb.runEngine();
}else {
qDebug() << "guest connected";
s.connectToServer(QLatin1String("/tmp/qtcreator-debuggeripc"));
s.waitForConnected();
qDebug() << "guest connected";
app.connect(&s, SIGNAL(disconnected ()), &app, SLOT(quit()));
lldb.setHostDevice(&s);
}
DiePlease bla;
bla.start();
Stdio stdio;
lldb.setHostDevice(&stdio);
return app.exec();
}
......@@ -51,3 +115,5 @@ extern const unsigned char lldbVersionString[] __attribute__ ((used)) = "@(#)PRO
extern const double lldbVersionNumber __attribute__ ((used)) = (double)26.;
extern const double LLDBVersionNumber __attribute__ ((used)) = (double)26.;
}
#include "main.moc"
......@@ -126,17 +126,16 @@ void IPCEngineGuest::readyRead()
qint64 rrr = m_nextMessagePayloadSize;
QByteArray payload = m_device->read(rrr);
if (quint64(payload.size()) != m_nextMessagePayloadSize || !payload.endsWith('T')) {
showMessage(QLatin1String("IPC Error: corrupted frame"));
showMessage(tr("Fatal engine shutdown. Incompatible binary or ipc error."), LogError);
showStatusMessage(tr("Fatal engine shutdown. Incompatible binary or ipc error."));
notifyEngineIll();
qDebug("IPC Error: corrupted frame");
showMessage(QLatin1String("[guest] IPC Error: corrupted frame"), LogError);
nuke();
return;
}
payload.chop(1);
rpcCallback(m_nextMessageFunction, payload);
m_nextMessagePayloadSize = 0;
if (quint64(m_device->bytesAvailable ()) >= 3 * sizeof(quint64) * 3)
if (quint64(m_device->bytesAvailable ()) >= 3 * sizeof(quint64))
QTimer::singleShot(0, this, SLOT(readyRead()));
}
......@@ -144,10 +143,9 @@ void IPCEngineGuest::rpcCallback(quint64 f, QByteArray payload)
{
switch (f) {
default:
showMessage(QLatin1String("IPC Error: unhandled id in host to guest call"));
showMessage(tr("Fatal engine shutdown. Incompatible binary or ipc error."), LogError);
showStatusMessage(tr("Fatal engine shutdown. Incompatible binary or ipc error."));
notifyEngineIll();
qDebug("IPC Error: unhandled id in host to guest call");
showMessage(QLatin1String("IPC Error: unhandled id in host to guest call"), LogError);
nuke();
break;
case IPCEngineHost::SetupIPC:
{
......
......@@ -55,6 +55,7 @@ public:
void setLocalHost(IPCEngineHost *);
void setHostDevice(QIODevice *);
virtual void nuke() = 0;
virtual void setupEngine() = 0;
virtual void setupInferior(const QString &executeable,
const QStringList &arguments, const QStringList &environment) = 0;
......
......@@ -301,7 +301,7 @@ void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload)
showMessage(QLatin1String("IPC Error: unhandled id in guest to host call"));
showMessage(tr("Fatal engine shutdown. Incompatible binary or ipc error."), LogError);
showStatusMessage(tr("Fatal engine shutdown. Incompatible binary or ipc error."));
notifyEngineSpontaneousShutdown();
nuke();
break;
case IPCEngineGuest::NotifyEngineSetupOk:
notifyEngineSetupOk();
......@@ -604,7 +604,7 @@ void IPCEngineHost::readyRead()
if (terminator != 'T') {
showStatusMessage(tr("Fatal engine shutdown. Incompatible binary or ipc error."));
showMessage(QLatin1String("IPC Error: terminator missing"));
notifyEngineSpontaneousShutdown();
nuke();
return;
}
rpcCallback(m_nextMessageFunction, payload);
......
......@@ -112,6 +112,8 @@ public:
const WatchUpdateFlags &flags = WatchUpdateFlags());
void rpcCall(Function f, QByteArray payload = QByteArray());
protected:
virtual void nuke() = 0;
public slots:
void rpcCallback(quint64 f, QByteArray payload = QByteArray());
private slots:
......
......@@ -54,8 +54,6 @@
#include <QtCore/QFileInfo>
#include <QtCore/QThread>
#include <QtCore/QCoreApplication>
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
namespace Debugger {
namespace Internal {
......@@ -65,33 +63,31 @@ LldbEngineHost::LldbEngineHost(const DebuggerStartParameters &startParameters)
{
showMessage(QLatin1String("setting up coms"));
QLocalServer *s = new QLocalServer(this);
s->removeServer(QLatin1String("/tmp/qtcreator-debuggeripc"));
s->listen(QLatin1String("/tmp/qtcreator-debuggeripc"));
m_guestProcess = new QProcess(this);
m_guestProcess->setProcessChannelMode(QProcess::ForwardedChannels);
connect(m_guestProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
this, SLOT(finished(int, QProcess::ExitStatus)));
showStatusMessage(QLatin1String("starting qtcreator-lldb"));
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"));
showStatusMessage(QString(QLatin1String("starting %1")).arg(a));
m_guestProcess->start(a, QStringList());
m_guestProcess->setReadChannel(QProcess::StandardOutput);
if (!m_guestProcess->waitForStarted()) {
showStatusMessage(tr("qtcreator-lldb failed to start"));
notifyEngineIll();
showStatusMessage(tr("qtcreator-lldb failed to start %1").arg(m_guestProcess->error()));
notifyEngineSpontaneousShutdown();
return;
}
showMessage(QLatin1String("connecting"));
s->waitForNewConnection(-1);
QLocalSocket *f = s->nextPendingConnection();
s->close(); // wtf race in accept
showMessage(QLatin1String("connected"));
setGuestDevice(f);
setGuestDevice(m_guestProcess);
}
LldbEngineHost::~LldbEngineHost()
......@@ -103,10 +99,26 @@ LldbEngineHost::~LldbEngineHost()
m_guestProcess->kill();
}
void LldbEngineHost::finished(int, QProcess::ExitStatus)
void LldbEngineHost::nuke()
{
stderrReady();
showMessage(QLatin1String("Nuke engaged. Bug in Engine/IPC or incompatible IPC versions. "), LogError);
showStatusMessage(tr("Fatal engine shutdown. Consult debugger log for details."));
m_guestProcess->terminate();
m_guestProcess->kill();
notifyEngineSpontaneousShutdown();
}
void LldbEngineHost::finished(int, QProcess::ExitStatus status)
{
showMessage(QString(QLatin1String("guest went bye bye. exit status: %1 and code: %2"))
.arg(status).arg(m_guestProcess->exitCode()), LogError);
nuke();
}
void LldbEngineHost::stderrReady()
{
showStatusMessage(tr("lldb crashed"));
notifyEngineIll();
fprintf(stderr,"%s", m_guestProcess->readAllStandardError().data());
}
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &startParameters)
......
......@@ -47,9 +47,11 @@ public:
private:
QProcess *m_guestProcess;
protected:
void nuke();
private slots:
void finished(int, QProcess::ExitStatus);
void stderrReady();
};
} // namespace Internal
......
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