From 776a45df6809a58b6f0e6f8a8f8516390067348a Mon Sep 17 00:00:00 2001 From: Arvid Ephraim Picciani Date: Mon, 29 Nov 2010 17:02:01 +0100 Subject: [PATCH] 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 --- src/plugins/debugger/debuggerrunner.cpp | 2 + .../debugger/lldb/guest/lldbengineguest.cpp | 19 +++- src/plugins/debugger/lldb/guest/lldbengineguest.h | 1 + src/plugins/debugger/lldb/guest/main.cpp | 124 ++++++++++++++++----- src/plugins/debugger/lldb/ipcengineguest.cpp | 16 ++- src/plugins/debugger/lldb/ipcengineguest.h | 1 + src/plugins/debugger/lldb/ipcenginehost.cpp | 4 +- src/plugins/debugger/lldb/ipcenginehost.h | 2 + src/plugins/debugger/lldb/lldbenginehost.cpp | 50 +++++---- src/plugins/debugger/lldb/lldbenginehost.h | 4 +- 10 files changed, 160 insertions(+), 63 deletions(-) diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 8502422429..5ba3a1f2f5 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -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()) diff --git a/src/plugins/debugger/lldb/guest/lldbengineguest.cpp b/src/plugins/debugger/lldb/guest/lldbengineguest.cpp index 2a590e385c..0283a6a1f6 100644 --- a/src/plugins/debugger/lldb/guest/lldbengineguest.cpp +++ b/src/plugins/debugger/lldb/guest/lldbengineguest.cpp @@ -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()<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) { diff --git a/src/plugins/debugger/lldb/guest/lldbengineguest.h b/src/plugins/debugger/lldb/guest/lldbengineguest.h index d8d06a6411..df94e417f7 100644 --- a/src/plugins/debugger/lldb/guest/lldbengineguest.h +++ b/src/plugins/debugger/lldb/guest/lldbengineguest.h @@ -70,6 +70,7 @@ public: explicit LldbEngineGuest(); ~LldbEngineGuest(); + void nuke(); void setupEngine(); void setupInferior(const QString &executable, const QStringList &arguments, const QStringList &environment); diff --git a/src/plugins/debugger/lldb/guest/main.cpp b/src/plugins/debugger/lldb/guest/main.cpp index 8d79ae4c49..4239152fb1 100644 --- a/src/plugins/debugger/lldb/guest/main.cpp +++ b/src/plugins/debugger/lldb/guest/main.cpp @@ -1,48 +1,112 @@ #include #include #include "lldbengineguest.h" +#include +#include +#include -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(¬ify, 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 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" diff --git a/src/plugins/debugger/lldb/ipcengineguest.cpp b/src/plugins/debugger/lldb/ipcengineguest.cpp index 4b895459c2..68dc624c95 100644 --- a/src/plugins/debugger/lldb/ipcengineguest.cpp +++ b/src/plugins/debugger/lldb/ipcengineguest.cpp @@ -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: { diff --git a/src/plugins/debugger/lldb/ipcengineguest.h b/src/plugins/debugger/lldb/ipcengineguest.h index 126ecc1881..525f36fcfc 100644 --- a/src/plugins/debugger/lldb/ipcengineguest.h +++ b/src/plugins/debugger/lldb/ipcengineguest.h @@ -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; diff --git a/src/plugins/debugger/lldb/ipcenginehost.cpp b/src/plugins/debugger/lldb/ipcenginehost.cpp index 70ba0e4231..f14dbb7987 100644 --- a/src/plugins/debugger/lldb/ipcenginehost.cpp +++ b/src/plugins/debugger/lldb/ipcenginehost.cpp @@ -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); diff --git a/src/plugins/debugger/lldb/ipcenginehost.h b/src/plugins/debugger/lldb/ipcenginehost.h index ae1da033a0..224e363899 100644 --- a/src/plugins/debugger/lldb/ipcenginehost.h +++ b/src/plugins/debugger/lldb/ipcenginehost.h @@ -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: diff --git a/src/plugins/debugger/lldb/lldbenginehost.cpp b/src/plugins/debugger/lldb/lldbenginehost.cpp index 34a01b4b5d..49a6ff1269 100644 --- a/src/plugins/debugger/lldb/lldbenginehost.cpp +++ b/src/plugins/debugger/lldb/lldbenginehost.cpp @@ -54,8 +54,6 @@ #include #include #include -#include -#include 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) diff --git a/src/plugins/debugger/lldb/lldbenginehost.h b/src/plugins/debugger/lldb/lldbenginehost.h index c8d4a60d4e..2e5c18580d 100644 --- a/src/plugins/debugger/lldb/lldbenginehost.h +++ b/src/plugins/debugger/lldb/lldbenginehost.h @@ -47,9 +47,11 @@ public: private: QProcess *m_guestProcess; - +protected: + void nuke(); private slots: void finished(int, QProcess::ExitStatus); + void stderrReady(); }; } // namespace Internal -- 2.11.0