summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/qtcreator/debugger/lldbbridge.py20
-rw-r--r--src/plugins/debugger/lldb/lldbengine.cpp6
-rw-r--r--src/plugins/ios/iosdebugsupport.cpp19
-rw-r--r--src/plugins/ios/iosdebugsupport.h3
-rw-r--r--src/plugins/ios/iosrunner.cpp10
-rw-r--r--src/plugins/ios/iosrunner.h6
-rw-r--r--src/plugins/ios/iostoolhandler.cpp338
-rw-r--r--src/plugins/ios/iostoolhandler.h6
-rw-r--r--src/tools/iostool/iosdevicemanager.cpp15
-rw-r--r--src/tools/iostool/iostool.pro2
-rw-r--r--src/tools/iostool/iostool.qbs1
-rw-r--r--src/tools/iostool/main.cpp272
12 files changed, 279 insertions, 419 deletions
diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py
index 92e039dd2c..765af26686 100644
--- a/share/qtcreator/debugger/lldbbridge.py
+++ b/share/qtcreator/debugger/lldbbridge.py
@@ -650,6 +650,7 @@ class Dumper(DumperBase):
self.processArgs_ = args.get('processArgs', '')
self.attachPid_ = args.get('attachPid', 0)
self.sysRoot_ = args.get('sysRoot', '')
+ self.remoteChannel_ = args.get('remoteChannel', '')
if len(self.sysRoot_)>0:
self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
@@ -670,15 +671,28 @@ class Dumper(DumperBase):
if self.attachPid_ > 0:
attachInfo = lldb.SBAttachInfo(self.attachPid_)
self.process = self.target.Attach(attachInfo, error)
+ if not err.Success():
+ self.report('state="inferiorrunfailed"')
+ return
+ self.report('pid="%s"' % self.process.GetProcessID())
+ self.report('state="enginerunandinferiorstopok"')
+ elif len(self.remoteChannel_) > 0:
+ err = lldb.SBError()
+ self.process = self.target.ConnectRemote(
+ self.debugger.GetListener(),
+ self.remoteChannel_, None, error)
+ self.report('state="enginerunandinferiorstopok"')
else:
launchInfo = lldb.SBLaunchInfo(self.processArgs_.split(' '))
launchInfo.SetWorkingDirectory(os.getcwd())
environmentList = [key + "=" + value for key,value in os.environ.items()]
launchInfo.SetEnvironmentEntries(environmentList, False)
self.process = self.target.Launch(launchInfo, error)
-
- self.report('pid="%s"' % self.process.GetProcessID())
- self.report('state="enginerunandinferiorrunok"')
+ if not err.Success():
+ self.report('state="inferiorrunfailed"')
+ return
+ self.report('pid="%s"' % self.process.GetProcessID())
+ self.report('state="enginerunandinferiorrunok"')
event = lldb.SBEvent()
while True:
diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp
index fc0a937ae5..fa8aea082a 100644
--- a/src/plugins/debugger/lldb/lldbengine.cpp
+++ b/src/plugins/debugger/lldb/lldbengine.cpp
@@ -182,7 +182,8 @@ void LldbEngine::setupInferior()
cmd.arg("attachPid", ((sp.startMode == AttachCrashedExternal || sp.startMode == AttachExternal)
? sp.attachPID : 0));
cmd.arg("sysRoot", sp.sysRoot);
- cmd.arg("remoteChannel", ((sp.startMode == AttachToRemoteProcess || sp.startMode == AttachToRemoteServer)
+ cmd.arg("remoteChannel", ((sp.startMode == AttachToRemoteProcess
+ || sp.startMode == AttachToRemoteServer)
? sp.remoteChannel : QString()));
runCommand(cmd);
@@ -1132,10 +1133,9 @@ void LldbEngine::notifyEngineRemoteSetupDone(int portOrPid, int qmlPort)
} else {
QString &rc = startParameters().remoteChannel;
const int sepIndex = rc.lastIndexOf(QLatin1Char(':'));
- if (sepIndex != -1) {
+ if (sepIndex != -1)
rc.replace(sepIndex + 1, rc.count() - sepIndex - 1,
QString::number(portOrPid));
- }
}
}
startLldb();
diff --git a/src/plugins/ios/iosdebugsupport.cpp b/src/plugins/ios/iosdebugsupport.cpp
index f4d6befda8..6ce8ee49e6 100644
--- a/src/plugins/ios/iosdebugsupport.cpp
+++ b/src/plugins/ios/iosdebugsupport.cpp
@@ -92,6 +92,7 @@ RunControl *IosDebugSupport::createDebugRunControl(IosRunConfiguration *runConfi
if (ToolChain *tc = ToolChainKitInformation::toolChain(kit))
params.toolChainAbi = tc->targetAbi();
params.executable = runConfig->exePath().toString();
+ params.remoteChannel = QLatin1String("connect://localhost:0");
}
if (aspect->useQmlDebugger()) {
params.languages |= QmlLanguage;
@@ -116,7 +117,7 @@ IosDebugSupport::IosDebugSupport(IosRunConfiguration *runConfig,
DebuggerRunControl *runControl)
: QObject(runControl), m_runControl(runControl),
m_runner(new IosRunner(this, runConfig, true)),
- m_gdbServerFd(0), m_qmlPort(0)
+ m_qmlPort(0)
{
connect(m_runControl->engine(), SIGNAL(requestRemoteSetup()),
@@ -124,8 +125,8 @@ IosDebugSupport::IosDebugSupport(IosRunConfiguration *runConfig,
connect(m_runControl, SIGNAL(finished()),
m_runner, SLOT(stop()));
- connect(m_runner, SIGNAL(gotGdbSocket(int)),
- SLOT(handleGdbServerFd(int)));
+ connect(m_runner, SIGNAL(gotGdbserverPort(int)),
+ SLOT(handleGdbServerPort(int)));
connect(m_runner, SIGNAL(gotInferiorPid(Q_PID)),
SLOT(handleGotInferiorPid(Q_PID)));
connect(m_runner, SIGNAL(finished(bool)),
@@ -139,18 +140,12 @@ IosDebugSupport::IosDebugSupport(IosRunConfiguration *runConfig,
IosDebugSupport::~IosDebugSupport()
{
- if (m_gdbServerFd > 0)
- close(m_gdbServerFd);
}
-void IosDebugSupport::handleGdbServerFd(int gdbServerFd)
+void IosDebugSupport::handleGdbServerPort(int gdbServerPort)
{
- if (m_gdbServerFd > 0) {
- close(m_gdbServerFd);
- m_gdbServerFd = 0;
- }
- if (gdbServerFd > 0) {
- m_runControl->engine()->notifyEngineRemoteSetupDone(m_gdbServerFd, m_qmlPort);
+ if (gdbServerPort > 0) {
+ m_runControl->engine()->notifyEngineRemoteSetupDone(gdbServerPort, m_qmlPort);
} else {
m_runControl->engine()->notifyEngineRemoteSetupFailed(
tr("Could not get debug server file descriptor."));
diff --git a/src/plugins/ios/iosdebugsupport.h b/src/plugins/ios/iosdebugsupport.h
index 59b223fd5e..0367179839 100644
--- a/src/plugins/ios/iosdebugsupport.h
+++ b/src/plugins/ios/iosdebugsupport.h
@@ -54,7 +54,7 @@ public:
~IosDebugSupport();
private slots:
- void handleGdbServerFd(int gdbServerFd);
+ void handleGdbServerPort(int gdbServerFd);
void handleGotInferiorPid(Q_PID);
void handleRemoteProcessFinished(bool cleanEnd);
@@ -66,7 +66,6 @@ private:
IosRunner * const m_runner;
const QString m_dumperLib;
- int m_gdbServerFd;
int m_qmlPort;
};
diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp
index 64749552ff..002ae8fb70 100644
--- a/src/plugins/ios/iosrunner.cpp
+++ b/src/plugins/ios/iosrunner.cpp
@@ -110,8 +110,8 @@ void IosRunner::start()
SLOT(handleDidStartApp(Ios::IosToolHandler*,QString,QString,Ios::IosToolHandler::OpStatus)));
connect(m_toolHandler, SIGNAL(errorMsg(Ios::IosToolHandler*,QString)),
SLOT(handleErrorMsg(Ios::IosToolHandler*,QString)));
- connect(m_toolHandler, SIGNAL(gotGdbserverSocket(Ios::IosToolHandler*,QString,QString,int)),
- SLOT(handleGotGdbserverSocket(Ios::IosToolHandler*,QString,QString,int)));
+ connect(m_toolHandler, SIGNAL(gotGdbserverPort(Ios::IosToolHandler*,QString,QString,int)),
+ SLOT(handleGotGdbserverPort(Ios::IosToolHandler*,QString,QString,int)));
connect(m_toolHandler, SIGNAL(gotInferiorPid(Ios::IosToolHandler*,QString,QString,Q_PID)),
SLOT(handleGotInferiorPid(Ios::IosToolHandler*,QString,QString,Q_PID)));
connect(m_toolHandler, SIGNAL(toolExited(Ios::IosToolHandler*,int)),
@@ -140,12 +140,12 @@ void IosRunner::handleDidStartApp(IosToolHandler *handler, const QString &bundle
emit didStartApp(status);
}
-void IosRunner::handleGotGdbserverSocket(IosToolHandler *handler, const QString &bundlePath,
- const QString &deviceId, int gdbFd)
+void IosRunner::handleGotGdbserverPort(IosToolHandler *handler, const QString &bundlePath,
+ const QString &deviceId, int gdbPort)
{
Q_UNUSED(bundlePath); Q_UNUSED(deviceId);
if (m_toolHandler == handler)
- emit gotGdbserverSocket(gdbFd);
+ emit gotGdbserverPort(gdbPort);
}
void IosRunner::handleGotInferiorPid(IosToolHandler *handler, const QString &bundlePath,
diff --git a/src/plugins/ios/iosrunner.h b/src/plugins/ios/iosrunner.h
index 76f1ed1c89..2e2e777ece 100644
--- a/src/plugins/ios/iosrunner.h
+++ b/src/plugins/ios/iosrunner.h
@@ -64,7 +64,7 @@ public slots:
signals:
void didStartApp(Ios::IosToolHandler::OpStatus status);
- void gotGdbserverSocket(int gdbFd);
+ void gotGdbserverPort(int gdbPort);
void gotInferiorPid(Q_PID pid);
void appOutput(const QString &output);
void errorMsg(const QString &msg);
@@ -74,8 +74,8 @@ private slots:
void warnAboutDeployFail();
void handleDidStartApp(Ios::IosToolHandler *handler, const QString &bundlePath,
const QString &deviceId, Ios::IosToolHandler::OpStatus status);
- void handleGotGdbserverSocket(Ios::IosToolHandler *handler, const QString &bundlePath,
- const QString &deviceId, int gdbFd);
+ void handleGotGdbserverPort(Ios::IosToolHandler *handler, const QString &bundlePath,
+ const QString &deviceId, int gdbPort);
void handleGotInferiorPid(Ios::IosToolHandler *handler, const QString &bundlePath,
const QString &deviceId, Q_PID pid);
void handleAppOutput(Ios::IosToolHandler *handler, const QString &output);
diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp
index c5d15c62e1..4152a045fc 100644
--- a/src/plugins/ios/iostoolhandler.cpp
+++ b/src/plugins/ios/iostoolhandler.cpp
@@ -43,16 +43,7 @@
#include <QScopedArrayPointer>
#include <QProcessEnvironment>
-#if defined(Q_OS_UNIX)
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#else
-#include <WinSock2.h>
-#endif
#include <string.h>
-#include <fcntl.h>
#include <errno.h>
static const bool debugToolHandler = false;
@@ -61,21 +52,6 @@ namespace Ios {
namespace Internal {
-class MyProcess: public QProcess
-{
- Q_OBJECT
-public:
- explicit MyProcess(QObject *parent = 0);
- ~MyProcess();
- int processOutputSocket();
- QSocketNotifier *notifier();
-protected:
- virtual void setupChildProcess();
-private:
- int m_sockets[2];
- QSocketNotifier *m_notifier;
-};
-
struct ParserState {
enum Kind {
Msg,
@@ -86,6 +62,7 @@ struct ParserState {
AppOutput,
AppStarted,
InferiorPid,
+ GdbServerPort,
Item,
Status,
AppTransfer,
@@ -107,6 +84,7 @@ struct ParserState {
case Value:
case Status:
case InferiorPid:
+ case GdbServerPort:
return true;
case QueryResult:
case AppOutput:
@@ -131,7 +109,6 @@ public:
NonStarted,
Starting,
StartedInferior,
- XmlEndSeenNotProcessed,
XmlEndProcessed,
Stopped
};
@@ -161,7 +138,7 @@ public:
IosToolHandler::OpStatus status);
void didStartApp(const QString &bundlePath, const QString &deviceId,
IosToolHandler::OpStatus status);
- void gotGdbserverSocket(const QString &bundlePath, const QString &deviceId, int gdbFd);
+ void gotGdbserverPort(const QString &bundlePath, const QString &deviceId, int gdbPort);
void gotInferiorPid(const QString &bundlePath, const QString &deviceId, Q_PID pid);
void deviceInfo(const QString &deviceId, const IosToolHandler::Dict &info);
void appOutput(const QString &output);
@@ -170,14 +147,13 @@ public:
// slots
void subprocessError(QProcess::ProcessError error);
void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
- void subprocessHasData(int socket);
+ void subprocessHasData();
virtual bool expectsFileDescriptor() = 0;
protected:
- int checkForXmlEnd();
void processXml();
IosToolHandler *q;
- MyProcess process;
+ QProcess process;
QXmlStreamReader outputParser;
QString deviceId;
QString bundlePath;
@@ -186,8 +162,6 @@ protected:
Op op;
IosToolHandler::DeviceType devType;
static const int lookaheadSize = 67;
- QByteArray buffer;
- QByteArray currentData;
int iBegin, iEnd, gdbSocket;
QList<ParserState> stack;
};
@@ -220,66 +194,9 @@ private:
void addDeviceArguments(QStringList &args) const;
};
-#if defined(Q_OS_UNIX)
-MyProcess::MyProcess(QObject *parent) : QProcess(parent)
-{
- if (socketpair(PF_UNIX, SOCK_STREAM, 0, &m_sockets[0]) == -1) {
- qDebug() << "IosToolHandler socketpair failed ";
- }
- m_notifier = new QSocketNotifier(m_sockets[0], QSocketNotifier::Read, this);
-}
-
-MyProcess::~MyProcess()
-{
- ::close(m_sockets[0]);
- ::close(m_sockets[1]);
-}
-
-int MyProcess::processOutputSocket()
-{
- return m_sockets[0];
-}
-
-QSocketNotifier *MyProcess::notifier()
-{
- return m_notifier;
-}
-
-void MyProcess::setupChildProcess()
-{
- if (dup2(m_sockets[1], 1) == -1) { // use the unix socket as stdout
- qDebug() << "IosToolHandler dup2 call failed";
- emit finished(-1, QProcess::CrashExit);
- exit(-1);
- }
-}
-#else
-MyProcess::MyProcess(QObject *parent) : QProcess(parent)
-{
-}
-
-MyProcess::~MyProcess()
-{
-}
-
-int MyProcess::processOutputSocket()
-{
- return 0;
-}
-
-QSocketNotifier *MyProcess::notifier()
-{
- return m_notifier;
-}
-
-void MyProcess::setupChildProcess()
-{
-}
-#endif
-
IosToolHandlerPrivate::IosToolHandlerPrivate(IosToolHandler::DeviceType devType,
Ios::IosToolHandler *q) :
- q(q), state(NonStarted), devType(devType), buffer(4*lookaheadSize, 0), iBegin(0), iEnd(0),
+ q(q), state(NonStarted), devType(devType), iBegin(0), iEnd(0),
gdbSocket(-1)
{
QProcessEnvironment env(QProcessEnvironment::systemEnvironment());
@@ -287,17 +204,11 @@ IosToolHandlerPrivate::IosToolHandlerPrivate(IosToolHandler::DeviceType devType,
if (k.startsWith(QLatin1String("DYLD_")))
env.remove(k);
process.setProcessEnvironment(env);
- QObject::connect(process.notifier(), SIGNAL(activated(int)), q, SLOT(subprocessHasData(int)));
+ QObject::connect(&process, SIGNAL(readyReadStandardOutput()), q, SLOT(subprocessHasData()));
QObject::connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)),
q, SLOT(subprocessFinished(int,QProcess::ExitStatus)));
QObject::connect(&process, SIGNAL(error(QProcess::ProcessError)),
q, SLOT(subprocessError(QProcess::ProcessError)));
-#if defined(Q_OS_UNIX)
- int accessFlags = fcntl(process.processOutputSocket(), F_GETFL);
- if (fcntl(process.processOutputSocket(), F_SETFL, accessFlags | O_NONBLOCK) == -1)
- qDebug() << "IosToolHandler fcntl F_SETFL failed to set non blocking mode"
- << qt_error_string(errno);
-#endif
}
bool IosToolHandlerPrivate::isRunning()
@@ -320,9 +231,6 @@ void IosToolHandlerPrivate::stop()
if (debugToolHandler)
qDebug() << "IosToolHandlerPrivate::stop";
if (process.state() != QProcess::NotRunning) {
-#if defined(Q_OS_UNIX)
- close(process.processOutputSocket());
-#endif
process.close();
process.kill();
if (debugToolHandler)
@@ -353,10 +261,10 @@ void IosToolHandlerPrivate::didStartApp(const QString &bundlePath, const QString
emit q->didStartApp(q, bundlePath, deviceId, status);
}
-void IosToolHandlerPrivate::gotGdbserverSocket(const QString &bundlePath, const QString &deviceId,
- int gdbFd)
+void IosToolHandlerPrivate::gotGdbserverPort(const QString &bundlePath,
+ const QString &deviceId, int gdbPort)
{
- emit q->gotGdbserverSocket(q, bundlePath, deviceId, gdbFd);
+ emit q->gotGdbserverPort(q, bundlePath, deviceId, gdbPort);
}
void IosToolHandlerPrivate::gotInferiorPid(const QString &bundlePath, const QString &deviceId,
@@ -408,7 +316,6 @@ void IosToolHandlerPrivate::subprocessError(QProcess::ProcessError error)
}
// pass
case StartedInferior:
- case XmlEndSeenNotProcessed:
errorMsg(IosToolHandler::tr("Subprocess Error %1").arg(error));
toolExited(-1);
break;
@@ -421,7 +328,7 @@ void IosToolHandlerPrivate::subprocessError(QProcess::ProcessError error)
void IosToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
// process potentially pending data
- subprocessHasData(process.processOutputSocket());
+ subprocessHasData();
switch (state) {
case NonStarted:
qDebug() << "subprocessFinished() when state was NonStarted";
@@ -442,7 +349,6 @@ void IosToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatu
}
// pass
case StartedInferior:
- case XmlEndSeenNotProcessed:
case XmlEndProcessed:
toolExited((exitStatus == QProcess::CrashExit && exitCode == 0) ? -1 : exitCode);
break;
@@ -453,106 +359,6 @@ void IosToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatu
}
}
-#if defined(Q_OS_UNIX)
-#ifndef CMSG_SPACE
-size_t CMSG_SPACE(size_t len) {
- msghdr msg;
- cmsghdr cmsg;
- msg.msg_control = &cmsg;
- msg.msg_controllen = ~socklen_t(0); /* To maximize the chance that CMSG_NXTHDR won't return NULL */
- cmsg.cmsg_len = CMSG_LEN(len);
- return reinterpret_cast<unsigned char *>(CMSG_NXTHDR(&msg, &cmsg)) - reinterpret_cast<unsigned char *>(&cmsg);
-}
-#endif
-
-int recv_fd(int socket)
-{
- int sent_fd;
- char message_buffer[1];
-
- iovec io_vector[1];
- memset(&io_vector[0], 0, sizeof(iovec));
- /* setup a place to fill in message contents */
- io_vector[0].iov_base = message_buffer;
- io_vector[0].iov_len = 1;
-
- msghdr socket_message;
- memset(&socket_message, 0, sizeof(struct msghdr));
- socket_message.msg_iov = io_vector;
- socket_message.msg_iovlen = 1;
-
- /* provide space for the ancillary data */
- size_t dimAncillaryEl = CMSG_SPACE(sizeof(int));
- QScopedArrayPointer<char> ancillary_element_buffer(new char[dimAncillaryEl]);
- memset(ancillary_element_buffer.data(), 0, dimAncillaryEl);
- socket_message.msg_control = ancillary_element_buffer.data();
- socket_message.msg_controllen = dimAncillaryEl;
-
- int flags = 0;
-#ifdef MSG_CMSG_CLOEXEC
- flags = MSG_CMSG_CLOEXEC;
-#endif
- if (recvmsg(socket, &socket_message, flags) < 0)
- return -1;
-
- if (message_buffer[0] != '.') {
- qDebug() << "IosToolHandler, unexpected inband data when receiving socket";
- return -1;
- }
-
- if ((socket_message.msg_flags & MSG_CTRUNC) == MSG_CTRUNC) {
- qDebug() << "IosToolHandler, not provide enough space for the ancillary element array";
- return -1;
- }
-
- /* iterate ancillary elements */
- cmsghdr *control_message = NULL;
- for (control_message = CMSG_FIRSTHDR(&socket_message);
- control_message != NULL;
- control_message = CMSG_NXTHDR(&socket_message, control_message)) {
- if ( (control_message->cmsg_level == SOL_SOCKET) &&
- (control_message->cmsg_type == SCM_RIGHTS) ) {
- sent_fd = *((int *) CMSG_DATA(control_message));
- // aknowledge fd
- send(socket, "x", 1, 0);
- return sent_fd;
- }
- }
-
- return -1;
-}
-#else
-int recv_fd(int socket)
-{
- Q_UNUSED(socket);
- return -1;
-}
-#endif
-
-int IosToolHandlerPrivate::checkForXmlEnd()
-{
- const char *xmlEnd = "</query_result>";
- int lenXmlEnd = 15;
- int i = 0, j = 0;
- while (i < lenXmlEnd && j < iEnd) {
- if (buffer.at(j) != xmlEnd[i]) {
- if (i == 0) {
- ++j;
- if (j + lenXmlEnd > iEnd)
- break;
- } else {
- i = 0;
- }
- } else {
- ++i;
- ++j;
- }
- }
- if (i == lenXmlEnd)
- return j;
- return -1;
-}
-
void IosToolHandlerPrivate::processXml()
{
while (!outputParser.atEnd()) {
@@ -630,6 +436,8 @@ void IosToolHandlerPrivate::processXml()
stack.append(ParserState(ParserState::DeviceInfo));
} else if (elName == QLatin1String("inferior_pid")) {
stack.append(ParserState(ParserState::InferiorPid));
+ } else if (elName == QLatin1String("gdb_server_port")) {
+ stack.append(ParserState(ParserState::GdbServerPort));
} else {
qDebug() << "unexpected element " << elName;
}
@@ -679,6 +487,9 @@ void IosToolHandlerPrivate::processXml()
case ParserState::InferiorPid:
gotInferiorPid(bundlePath, deviceId, Q_PID(p.chars.toInt()));
break;
+ case ParserState::GdbServerPort:
+ gotGdbserverPort(bundlePath, deviceId, p.chars.toInt());
+ break;
}
break;
}
@@ -716,11 +527,10 @@ void IosToolHandlerPrivate::processXml()
}
}
-void IosToolHandlerPrivate::subprocessHasData(int socket)
+void IosToolHandlerPrivate::subprocessHasData()
{
if (debugToolHandler)
qDebug() << "subprocessHasData, state:" << state;
- process.notifier()->setEnabled(false);
while (true) {
switch (state) {
case NonStarted:
@@ -730,114 +540,30 @@ void IosToolHandlerPrivate::subprocessHasData(int socket)
case StartedInferior:
// read some data
{
- if (iEnd + lookaheadSize > buffer.size()) {
- memmove(buffer.data(), buffer.data() + (iEnd - lookaheadSize), lookaheadSize);
- iBegin = lookaheadSize;
- iEnd = iBegin;
- } else {
- iBegin = iEnd;
- }
- currentData.clear();
- qptrdiff reallyRead = recv(socket, buffer.data() + iBegin, lookaheadSize, 0);
- if (reallyRead == 0) { // eof
- stop();
- return;
- }
- if (reallyRead == -1) {
- if (errno == EAGAIN) { // read all so far
- if (debugToolHandler)
- qDebug() << "read all for now";
- process.notifier()->setEnabled(true);
- return;
- }
- if (errno == EINTR)
- continue;
- qDebug() << "IosToolHandlerPrivate::subprocessHasData " << qt_error_string(errno);
- stop();
- return;
- }
- iEnd = iBegin + reallyRead;
- int xmlEnd = checkForXmlEnd();
- if (xmlEnd != -1) {
- state = XmlEndSeenNotProcessed;
- currentData = buffer.mid(iBegin, xmlEnd - iBegin);
- } else {
- currentData = buffer.mid(iBegin, reallyRead);
- }
- if (debugToolHandler)
- qDebug() << "subprocessHasData read " << currentData;
- outputParser.addData(currentData);
- processXml();
- break;
- }
- case XmlEndSeenNotProcessed:
- qDebug() << "IosToolHandler unexpected state in subprocessHasData: XmlEndSeenNotProcessed";
- // pass
- case XmlEndProcessed:
- {
- // check for sent fd
- if (!expectsFileDescriptor()) {
- stop();
- return;
- }
- int lenToRead = lookaheadSize;
- int spacerStart = iBegin + currentData.size();
- while (spacerStart < iEnd && buffer.at(spacerStart) != 'n')
- ++spacerStart;
- if (iEnd - (iBegin + currentData.size()) < lenToRead) {
- int lastXmlSize = currentData.size();
- if (iBegin > 0) {
- memmove(buffer.data(), buffer.data() + iBegin, iEnd - iBegin);
- iEnd -= iBegin;
- iBegin = 0;
- spacerStart -= iBegin;
- currentData = buffer.mid(0, lastXmlSize); // remove this??
- }
- qptrdiff toRead = lookaheadSize - (iEnd - spacerStart);
- qptrdiff reallyRead = recv(socket, buffer.data() + iEnd, toRead, 0);
- if (reallyRead == 0) { // eof
+ char buf[200];
+ while (true) {
+ qint64 rRead = process.read(buf, sizeof(buf));
+ if (rRead == -1) {
stop();
return;
}
- if (reallyRead == -1) {
- if (errno == EAGAIN) { // read all so far
- if (debugToolHandler)
- qDebug() << "read all for now2";
- process.notifier()->setEnabled(true);
- return;
- }
- if (errno == EINTR)
- continue;
- if (debugToolHandler)
- qDebug() << "IosToolHandlerPrivate::subprocessHasData " << qt_error_string(errno);
- stop();
+ if (rRead == 0) {
+ qDebug() << "read 0";
return;
}
- iEnd += reallyRead;
- if (reallyRead != toRead)
- continue;
- if (spacerStart < iEnd && buffer.at(spacerStart) != 'N') {
- ++spacerStart;
- while (spacerStart < iEnd && buffer.at(spacerStart) != 'N')
- ++spacerStart;
- continue;
- }
+ if (debugToolHandler)
+ qDebug() << "subprocessHasData read " << QByteArray(buf, rRead);
+ outputParser.addData(QByteArray(buf, rRead));
+ processXml();
}
- if (buffer.at(iEnd-1) != 'd') {
- qDebug() << "IosToolHandler: bad alignment of spacer: " << buffer.mid(iBegin, iEnd - iBegin);
- return;
- }
- gdbSocket = recv_fd(socket);
- qDebug() << "IosToolHandler: receivedSocket";
- gotGdbserverSocket(bundlePath, deviceId, gdbSocket);
+ }
+ case XmlEndProcessed:
stop();
return;
- }
case Stopped:
return;
}
}
- process.notifier()->setEnabled(true);
}
// IosDeviceToolHandlerPrivate
@@ -1048,11 +774,9 @@ void IosToolHandler::subprocessFinished(int exitCode, QProcess::ExitStatus exitS
d->subprocessFinished(exitCode, exitStatus);
}
-void IosToolHandler::subprocessHasData(int socket)
+void IosToolHandler::subprocessHasData()
{
- d->subprocessHasData(socket);
+ d->subprocessHasData();
}
} // namespace Ios
-
-#include "iostoolhandler.moc"
diff --git a/src/plugins/ios/iostoolhandler.h b/src/plugins/ios/iostoolhandler.h
index 8d4f5c0b96..11c4a56e75 100644
--- a/src/plugins/ios/iostoolhandler.h
+++ b/src/plugins/ios/iostoolhandler.h
@@ -83,8 +83,8 @@ signals:
const QString &deviceId, Ios::IosToolHandler::OpStatus status);
void didStartApp(Ios::IosToolHandler *handler, const QString &bundlePath,
const QString &deviceId, Ios::IosToolHandler::OpStatus status);
- void gotGdbserverSocket(Ios::IosToolHandler *handler, const QString &bundlePath,
- const QString &deviceId, int gdbFd);
+ void gotGdbserverPort(Ios::IosToolHandler *handler, const QString &bundlePath,
+ const QString &deviceId, int gdbPort);
void gotInferiorPid(Ios::IosToolHandler *handler, const QString &bundlePath,
const QString &deviceId, Q_PID pid);
void deviceInfo(Ios::IosToolHandler *handler, const QString &deviceId,
@@ -98,7 +98,7 @@ public slots:
private slots:
void subprocessError(QProcess::ProcessError error);
void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
- void subprocessHasData(int socket);
+ void subprocessHasData();
private:
friend class Ios::Internal::IosToolHandlerPrivate;
Ios::Internal::IosToolHandlerPrivate *d;
diff --git a/src/tools/iostool/iosdevicemanager.cpp b/src/tools/iostool/iosdevicemanager.cpp
index cee55b6501..2e3db289d2 100644
--- a/src/tools/iostool/iosdevicemanager.cpp
+++ b/src/tools/iostool/iosdevicemanager.cpp
@@ -275,9 +275,10 @@ public:
AMDeviceRef device;
int progressBase;
int unexpectedChars;
+ bool aknowledge;
private:
bool checkRead(qptrdiff nRead, int &maxRetry);
- int handleChar(QByteArray &res, char c, int status);
+ int handleChar(int sock, QByteArray &res, char c, int status);
};
// ------- IosManagerPrivate interface --------
@@ -709,7 +710,7 @@ int IosDeviceManagerPrivate::processGdbServer(int fd)
// ------- ConnectSession implementation --------
CommandSession::CommandSession(const QString &deviceId) : deviceId(deviceId), device(0),
- progressBase(0), unexpectedChars(0)
+ progressBase(0), unexpectedChars(0), aknowledge(true)
{ }
CommandSession::~CommandSession() { }
@@ -876,7 +877,7 @@ bool CommandSession::checkRead(qptrdiff nRead, int &maxRetry)
return true;
}
-int CommandSession::handleChar(QByteArray &res, char c, int status)
+int CommandSession::handleChar(int fd, QByteArray &res, char c, int status)
{
switch (status) {
case 0:
@@ -911,6 +912,8 @@ int CommandSession::handleChar(QByteArray &res, char c, int status)
++unexpectedChars;
}
}
+ if (status == 3 && aknowledge)
+ writeAll(fd, "+", 1);
return status + 1;
case 4:
addError(QString::fromLatin1("gone past end in readGdbReply"));
@@ -940,7 +943,7 @@ QByteArray CommandSession::readGdbReply(ServiceSocket fd)
qDebug() << "gdbReply read " << buf;
}
for (qptrdiff i = 0; i< nRead; ++i)
- status = handleChar(res, buf[i], status);
+ status = handleChar(fd, res, buf[i], status);
toRead = 4 - status;
}
if (status != 4) {
@@ -1095,8 +1098,8 @@ bool AppOpSession::runApp()
// gdbServer protocol, see http://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol
// and the lldb handling of that (with apple specific stuff)
// http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp
- failure = !sendGdbCommand(gdbFd, "QStartNoAckMode"); // avoid and send required aknowledgements?
- if (!failure) failure = !expectGdbOkReply(gdbFd);
+ //failure = !sendGdbCommand(gdbFd, "QStartNoAckMode"); // avoid and send required aknowledgements?
+ //if (!failure) failure = !expectGdbOkReply(gdbFd);
if (!failure) failure = !sendGdbCommand(gdbFd, "QEnvironmentHexEncoded:"); // send the environment with a series of these commands...
if (!failure) failure = !sendGdbCommand(gdbFd, "QSetDisableASLR:1"); // avoid address randomization to debug
if (!failure) failure = !expectGdbOkReply(gdbFd);
diff --git a/src/tools/iostool/iostool.pro b/src/tools/iostool/iostool.pro
index 2870efaee2..e33e105a84 100644
--- a/src/tools/iostool/iostool.pro
+++ b/src/tools/iostool/iostool.pro
@@ -1,7 +1,7 @@
TARGET = iostool
QT += core
-QT += gui xml
+QT += gui xml network
CONFIG += console
diff --git a/src/tools/iostool/iostool.qbs b/src/tools/iostool/iostool.qbs
index c05359c68f..abb95f0975 100644
--- a/src/tools/iostool/iostool.qbs
+++ b/src/tools/iostool/iostool.qbs
@@ -7,6 +7,7 @@ QtcTool {
Depends { name: "Qt.widgets" }
Depends { name: "Qt.xml" }
+ Depends { name: "Qt.network" }
Depends { name: "app_version_header" }
files: [
diff --git a/src/tools/iostool/main.cpp b/src/tools/iostool/main.cpp
index 9acc5a71a2..3a38b6f389 100644
--- a/src/tools/iostool/main.cpp
+++ b/src/tools/iostool/main.cpp
@@ -38,26 +38,34 @@
#include <QFile>
#include <QMapIterator>
#include <QScopedArrayPointer>
+#include <QTcpServer>
+#include <QSocketNotifier>
+#include <QTcpSocket>
#include "iosdevicemanager.h"
#include <sys/types.h>
+#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+static const bool debugGdbEchoServer = false;
class IosTool: public QObject {
Q_OBJECT
public:
IosTool(QObject *parent = 0);
+ virtual ~IosTool();
void run(const QStringList &args);
void doExit(int errorCode = 0);
void writeMsg(const char *msg);
void writeMsg(const QString &msg);
void stopXml(int errorCode);
-public slots:
+private slots:
void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress,
const QString &info);
void didTransferApp(const QString &bundlePath, const QString &deviceId,
@@ -67,15 +75,27 @@ public slots:
void deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &info);
void appOutput(const QString &output);
void errorMsg(const QString &msg);
+ void handleNewConnection();
+ void handleGdbServerSocketHasData(int socket);
+ void handleCreatorHasData();
+ void handleCreatorHasError(QAbstractSocket::SocketError error);
private:
+ bool startServer();
+ void stopGdbServer(int errorCode = 0);
+
int maxProgress;
int opLeft;
bool debug;
+ bool ipv6;
bool inAppOutput;
bool splitAppOutput; // as QXmlStreamReader reports the text attributes atomically it is better to split
Ios::IosDeviceManager::AppOp appOp;
QFile outFile;
QXmlStreamWriter out;
+ int gdbFileDescriptor;
+ QTcpSocket *creatorSocket;
+ QSocketNotifier *gdbServerNotifier;
+ QTcpServer gdbServer;
};
IosTool::IosTool(QObject *parent):
@@ -83,11 +103,15 @@ IosTool::IosTool(QObject *parent):
maxProgress(0),
opLeft(0),
debug(false),
+ ipv6(false),
inAppOutput(false),
splitAppOutput(true),
appOp(Ios::IosDeviceManager::Install),
outFile(),
- out(&outFile)
+ out(&outFile),
+ gdbFileDescriptor(-1),
+ creatorSocket(0),
+ gdbServerNotifier(0)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
outFile.open(stdout, QIODevice::WriteOnly, QFile::DontCloseHandle);
@@ -98,6 +122,12 @@ IosTool::IosTool(QObject *parent):
out.setCodec("UTF-8");
}
+IosTool::~IosTool()
+{
+ delete creatorSocket; // not strictly required
+ delete gdbServerNotifier; // not strictly required
+}
+
void IosTool::run(const QStringList &args)
{
Ios::IosDeviceManager *manager = Ios::IosDeviceManager::instance();
@@ -128,6 +158,8 @@ void IosTool::run(const QStringList &args)
appOp = Ios::IosDeviceManager::AppOp(appOp | Ios::IosDeviceManager::Install);
} else if (arg == QLatin1String("-run")) {
appOp = Ios::IosDeviceManager::AppOp(appOp | Ios::IosDeviceManager::Run);
+ } else if (arg == QLatin1String("-ipv6")) {
+ ipv6 = true;
} else if (arg == QLatin1String("-debug")) {
appOp = Ios::IosDeviceManager::AppOp(appOp | Ios::IosDeviceManager::Run);
debug = true;
@@ -229,68 +261,6 @@ void IosTool::isTransferringApp(const QString &bundlePath, const QString &device
outFile.flush();
}
-#ifndef CMSG_SPACE
-size_t CMSG_SPACE(size_t len) {
- msghdr msg;
- cmsghdr cmsg;
- msg.msg_control = &cmsg;
- msg.msg_controllen = ~socklen_t(0); /* To maximize the chance that CMSG_NXTHDR won't return NULL */
- cmsg.cmsg_len = CMSG_LEN(len);
- return reinterpret_cast<unsigned char *>(CMSG_NXTHDR(&msg, &cmsg)) - reinterpret_cast<unsigned char *>(&cmsg);
-}
-#endif
-
-int send_fd(int socket, int fd_to_send)
-{
- /* storage space needed for an ancillary element with a paylod of length is CMSG_SPACE(sizeof(length)) */
- size_t dimAncillaryBuffer = CMSG_SPACE(sizeof(int));
- QScopedArrayPointer<char> ancillary_element_buffer(new char[dimAncillaryBuffer]);
- int available_ancillary_element_buffer_space;
-
- /* at least one vector of one byte must be sent */
- char message_buffer[1];
- message_buffer[0] = '.';
- iovec io_vector[1];
-
- io_vector[0].iov_base = message_buffer;
- io_vector[0].iov_len = 1;
-
- /* initialize socket message */
- msghdr socket_message;
- memset(&socket_message, 0, sizeof(msghdr));
- socket_message.msg_iov = io_vector;
- socket_message.msg_iovlen = 1;
-
- /* provide space for the ancillary data */
- available_ancillary_element_buffer_space = dimAncillaryBuffer;
- memset(ancillary_element_buffer.data(), 0, available_ancillary_element_buffer_space);
- socket_message.msg_control = ancillary_element_buffer.data();
- socket_message.msg_controllen = available_ancillary_element_buffer_space;
-
- /* initialize a single ancillary data element for fd passing */
- cmsghdr *control_message = NULL;
- control_message = CMSG_FIRSTHDR(&socket_message);
- control_message->cmsg_level = SOL_SOCKET;
- control_message->cmsg_type = SCM_RIGHTS;
- control_message->cmsg_len = CMSG_LEN(sizeof(int));
- *((int *) CMSG_DATA(control_message)) = fd_to_send;
-
- qptrdiff res = sendmsg(socket, &socket_message, 0);
- while (true) {
- qptrdiff nRead = recv(socket, &message_buffer[0], 1, MSG_WAITALL);
- if (nRead == -1) {
- if (errno == EINTR)
- continue;
- qDebug() << "wait in send_fd failed " << qt_error_string(errno);
- sleep(4);
- return res;
- }
- if (nRead == 1)
- break;
- }
- return res;
-}
-
void IosTool::didTransferApp(const QString &bundlePath, const QString &deviceId,
Ios::IosDeviceManager::OpStatus status)
{
@@ -326,7 +296,7 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
QLatin1String("FAILURE"));
//out.writeCharacters(QString()); // trigger a complete closing of the empty element
outFile.flush();
- if (appOp == Ios::IosDeviceManager::Install) {
+ if (status != Ios::IosDeviceManager::Success || appOp == Ios::IosDeviceManager::Install) {
doExit();
return;
}
@@ -341,14 +311,14 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
return;
}
if (debug) {
- stopXml(0);
- // these are 67 characters, this is used as read size on the other side...
- const char *msg = "Now sending the gdbserver socket, will need a unix socket to succeed";
- outFile.write(msg, strlen(msg));
+ gdbFileDescriptor=gdbFd;
+ if (!startServer()) {
+ doExit(-4);
+ return;
+ }
+ out.writeTextElement(QLatin1String("gdb_server_port"),
+ QString::number(gdbServer.serverPort()));
outFile.flush();
- int sent = send_fd(1, gdbFd);
- sleep(1);
- QCoreApplication::exit(sent == -1);
} else {
if (!splitAppOutput) {
out.writeStartElement(QLatin1String("app_output"));
@@ -410,6 +380,160 @@ void IosTool::errorMsg(const QString &msg)
writeMsg(msg + QLatin1Char('\n'));
}
+void IosTool::handleNewConnection()
+{
+ if (creatorSocket) {
+ gdbServer.close();
+ QTcpSocket *s = gdbServer.nextPendingConnection();
+ delete s;
+ return;
+ }
+ creatorSocket = gdbServer.nextPendingConnection();
+ connect(creatorSocket, SIGNAL(readyRead()), SLOT(handleCreatorHasData()));
+ connect(creatorSocket, SIGNAL(error(QAbstractSocket::SocketError)),
+ SLOT(handleCreatorHasError(QAbstractSocket::SocketError)));
+ gdbServerNotifier = new QSocketNotifier(gdbFileDescriptor, QSocketNotifier::Read, this);
+ connect(gdbServerNotifier, SIGNAL(activated(int)), SLOT(handleGdbServerSocketHasData(int)));
+ gdbServer.close();
+}
+
+void IosTool::handleGdbServerSocketHasData(int socket)
+{
+ gdbServerNotifier->setEnabled(false);
+ char buf[255];
+ while (true) {
+ qptrdiff rRead = read(socket, &buf, sizeof(buf)-1);
+ if (rRead == -1) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN) {
+ gdbServerNotifier->setEnabled(true);
+ return;
+ }
+ errorMsg(qt_error_string(errno));
+ close(socket);
+ stopGdbServer(-1);
+ return;
+ }
+ if (rRead == 0) {
+ stopGdbServer(0);
+ return;
+ }
+ if (debugGdbEchoServer) {
+ writeMsg("gdbServerReplies:");
+ buf[rRead] = 0;
+ writeMsg(buf);
+ }
+ qint64 pos = 0;
+ while (true) {
+ qint64 writtenNow = creatorSocket->write(buf + int(pos), rRead);
+ if (writtenNow == -1) {
+ writeMsg(creatorSocket->errorString());
+ stopGdbServer(-1);
+ return;
+ }
+ if (writtenNow < rRead) {
+ pos += writtenNow;
+ rRead -= qptrdiff(writtenNow);
+ } else {
+ break;
+ }
+ }
+ }
+}
+
+void IosTool::stopGdbServer(int errorCode)
+{
+ if (debugGdbEchoServer)
+ writeMsg("gdbServerStops");
+ if (!creatorSocket)
+ return;
+ if (gdbFileDescriptor > 0) {
+ ::close(gdbFileDescriptor);
+ gdbFileDescriptor = -1;
+ if (gdbServerNotifier)
+ delete gdbServerNotifier;
+ }
+ if (creatorSocket->isOpen())
+ creatorSocket->close();
+ delete creatorSocket;
+ doExit(errorCode);
+}
+
+void IosTool::handleCreatorHasData()
+{
+ char buf[255];
+ while (true) {
+ qint64 toRead = creatorSocket->bytesAvailable();
+ if (qint64(sizeof(buf)-1) < toRead)
+ toRead = sizeof(buf)-1;
+ qint64 rRead = creatorSocket->read(buf, toRead);
+ if (rRead == -1) {
+ errorMsg(creatorSocket->errorString());
+ stopGdbServer();
+ return;
+ }
+ if (rRead == 0) {
+ if (!creatorSocket->isOpen())
+ stopGdbServer();
+ return;
+ }
+ int pos = 0;
+ int irep = 0;
+ if (debugGdbEchoServer) {
+ writeMsg("sendToGdbServer:");
+ buf[rRead] = 0;
+ writeMsg(buf);
+ }
+ while (true) {
+ qptrdiff written = write(gdbFileDescriptor, buf + pos, rRead);
+ if (written == -1) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN) {
+ if (++irep > 10) {
+ sleep(1);
+ irep = 0;
+ }
+ continue;
+ }
+ errorMsg(creatorSocket->errorString());
+ stopGdbServer();
+ return;
+ }
+ if (written == 0) {
+ stopGdbServer();
+ return;
+ }
+ if (written < rRead) {
+ pos += written;
+ rRead -= written;
+ } else {
+ break;
+ }
+ }
+ }
+}
+
+void IosTool::handleCreatorHasError(QAbstractSocket::SocketError error)
+{
+ errorMsg(tr("Ios Debugging connection to creator failed with error %1").arg(error));
+ stopGdbServer();
+}
+
+bool IosTool::startServer()
+{
+ if (gdbFileDescriptor <= 0 || gdbServer.isListening() || creatorSocket != 0)
+ return false;
+ fcntl(gdbFileDescriptor, F_SETFL, fcntl(gdbFileDescriptor, F_GETFL, 0) | O_NONBLOCK);
+ gdbServer.setMaxPendingConnections(1);
+ connect(&gdbServer, SIGNAL(newConnection()), SLOT(handleNewConnection()));
+ if (ipv6)
+ return gdbServer.listen(QHostAddress(QHostAddress::LocalHostIPv6), 0);
+ else
+ return gdbServer.listen(QHostAddress(QHostAddress::LocalHost), 0);
+}
+
int main(int argc, char *argv[])
{