OSDN Git Service

lldb: move away from local sockets to stdio coms
authorArvid Ephraim Picciani <arvid.picciani@nokia.com>
Mon, 29 Nov 2010 16:02:01 +0000 (17:02 +0100)
committerArvid Ephraim Picciani <arvid.picciani@nokia.com>
Mon, 29 Nov 2010 16:07:30 +0000 (17:07 +0100)
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
src/plugins/debugger/lldb/guest/lldbengineguest.cpp
src/plugins/debugger/lldb/guest/lldbengineguest.h
src/plugins/debugger/lldb/guest/main.cpp
src/plugins/debugger/lldb/ipcengineguest.cpp
src/plugins/debugger/lldb/ipcengineguest.h
src/plugins/debugger/lldb/ipcenginehost.cpp
src/plugins/debugger/lldb/ipcenginehost.h
src/plugins/debugger/lldb/lldbenginehost.cpp
src/plugins/debugger/lldb/lldbenginehost.h

index 8502422..5ba3a1f 100644 (file)
@@ -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())
index 2a590e3..0283a6a 100644 (file)
@@ -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) {
index d8d06a6..df94e41 100644 (file)
@@ -70,6 +70,7 @@ public:
     explicit LldbEngineGuest();
     ~LldbEngineGuest();
 
+    void nuke();
     void setupEngine();
     void setupInferior(const QString &executable, const QStringList &arguments,
             const QStringList &environment);
index 8d79ae4..4239152 100644 (file)
 #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"
index 4b89545..68dc624 100644 (file)
@@ -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:
             {
index 126ecc1..525f36f 100644 (file)
@@ -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;
index 70ba0e4..f14dbb7 100644 (file)
@@ -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);
index ae1da03..224e363 100644 (file)
@@ -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:
index 34a01b4..49a6ff1 100644 (file)
@@ -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)
index c8d4a60..2e5c185 100644 (file)
@@ -47,9 +47,11 @@ public:
 
 private:
     QProcess *m_guestProcess;
-
+protected:
+    void nuke();
 private slots:
     void finished(int, QProcess::ExitStatus);
+    void stderrReady();
 };
 
 } // namespace Internal