forked from qt-creator/qt-creator
ios: device debugging
switched to using a relay server Change-Id: Ic3ddb48b818fa43894314f7fbaf9d7780fc01ade Reviewed-by: hjk <hjk121@nokiamail.com> Reviewed-by: Fawzi Mohamed <fawzi.mohamed@digia.com>
This commit is contained in:
@@ -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:
|
||||
|
@@ -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();
|
||||
|
@@ -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."));
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
char buf[200];
|
||||
while (true) {
|
||||
qint64 rRead = process.read(buf, sizeof(buf));
|
||||
if (rRead == -1) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
qDebug() << "IosToolHandlerPrivate::subprocessHasData " << qt_error_string(errno);
|
||||
stop();
|
||||
return;
|
||||
if (rRead == 0) {
|
||||
qDebug() << "read 0";
|
||||
return;
|
||||
}
|
||||
if (debugToolHandler)
|
||||
qDebug() << "subprocessHasData read " << QByteArray(buf, rRead);
|
||||
outputParser.addData(QByteArray(buf, rRead));
|
||||
processXml();
|
||||
}
|
||||
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
|
||||
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();
|
||||
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 (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);
|
||||
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"
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
TARGET = iostool
|
||||
|
||||
QT += core
|
||||
QT += gui xml
|
||||
QT += gui xml network
|
||||
|
||||
CONFIG += console
|
||||
|
||||
|
@@ -7,6 +7,7 @@ QtcTool {
|
||||
|
||||
Depends { name: "Qt.widgets" }
|
||||
Depends { name: "Qt.xml" }
|
||||
Depends { name: "Qt.network" }
|
||||
Depends { name: "app_version_header" }
|
||||
|
||||
files: [
|
||||
|
@@ -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[])
|
||||
{
|
||||
|
Reference in New Issue
Block a user