diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 777965ae18c..69d40321e9e 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -677,7 +677,10 @@ class Dumper(DumperBase): self.startMode_ = args.get('startMode', 1) self.processArgs_ = args.get('processArgs', '') self.attachPid_ = args.get('attachPid', 0) + self.sysRoot_ = args.get('sysRoot', '') + if len(self.sysRoot_)>0: + self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_) self.target = self.debugger.CreateTarget(self.executable_, None, None, True, error) self.importDumpers() @@ -695,7 +698,6 @@ class Dumper(DumperBase): if self.attachPid_ > 0: attachInfo = lldb.SBAttachInfo(self.attachPid_) self.process = self.target.Attach(attachInfo, error) - else: launchInfo = lldb.SBLaunchInfo(self.processArgs_.split(' ')) launchInfo.SetWorkingDirectory(os.getcwd()) diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 46dfd62aef8..92474bbfa8f 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -66,9 +67,6 @@ #include #include -#include - - namespace Debugger { namespace Internal { @@ -131,9 +129,16 @@ void LldbEngine::shutdownEngine() void LldbEngine::setupEngine() { QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); + if (startParameters().remoteSetupNeeded) { + notifyEngineRequestRemoteSetup(); + } else { + startLldb(); + } +} +void LldbEngine::startLldb() +{ m_lldbCmd = startParameters().debuggerCommand; - connect(&m_lldbProc, SIGNAL(error(QProcess::ProcessError)), SLOT(handleLldbError(QProcess::ProcessError))); connect(&m_lldbProc, SIGNAL(finished(int,QProcess::ExitStatus)), @@ -170,9 +175,14 @@ void LldbEngine::setupInferior() const DebuggerStartParameters &sp = startParameters(); Command cmd("setupInferior"); cmd.arg("executable", QFileInfo(sp.executable).absoluteFilePath()); - cmd.arg("startMode", sp.startMode); + cmd.arg("startMode", sp.startMode); // directly relying on this is brittle wrt. insertions, so check it here cmd.arg("processArgs", sp.processArgs); - cmd.arg("attachPid", sp.attachPID); + 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) + ? sp.remoteChannel : QString())); + runCommand(cmd); requestUpdateWatchers(); } @@ -1107,6 +1117,39 @@ DebuggerEngine *createLldbEngine(const DebuggerStartParameters &startParameters) return new LldbEngine(startParameters); } +void LldbEngine::notifyEngineRemoteSetupDone(int portOrPid, int qmlPort) +{ + QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); + DebuggerEngine::notifyEngineRemoteSetupDone(portOrPid, qmlPort); + + if (qmlPort != -1) + startParameters().qmlServerPort = qmlPort; + if (portOrPid != -1) { + if (startParameters().startMode == AttachExternal) { + startParameters().attachPID = portOrPid; + } else { + QString &rc = startParameters().remoteChannel; + const int sepIndex = rc.lastIndexOf(QLatin1Char(':')); + if (sepIndex != -1) { + rc.replace(sepIndex + 1, rc.count() - sepIndex - 1, + QString::number(portOrPid)); + } + } + } + startLldb(); +} + +void LldbEngine::notifyEngineRemoteSetupFailed(const QString &reason) +{ + QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); + DebuggerEngine::notifyEngineRemoteSetupFailed(reason); + showMessage(_("ADAPTER START FAILED")); + if (!reason.isEmpty()) { + const QString title = tr("Adapter start failed"); + Core::ICore::showWarningWithOptions(title, reason); + } + notifyEngineSetupFailed(); +} /////////////////////////////////////////////////////////////////////// // diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index aa8d4450747..c034037c1fd 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -95,6 +95,7 @@ private: void executeNextI(); void setupEngine(); + void startLldb(); void setupInferior(); void runEngine(); void shutdownInferior(); @@ -181,6 +182,9 @@ private: void handleUpdateStack(const QByteArray &response); void handleUpdateThreads(const QByteArray &response); + void notifyEngineRemoteSetupDone(int portOrPid, int qmlPort); + void notifyEngineRemoteSetupFailed(const QString &reason); + void handleChildren(const WatchData &data0, const GdbMi &item, QList *list); diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 1eaa690bc99..746fea4415e 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -312,7 +312,7 @@ void IosConfigurations::updateAutomaticKitList() //DeviceKitInformation::setDevice(newKit, device); Debugger::DebuggerItem debugger; - debugger.setCommand(pToolchain->suggestedDebugger()); + debugger.setCommand(pToolchain->suggestedDebugger()); // use lldbPath() instead? debugger.setEngineType(Debugger::LldbEngineType); debugger.setDisplayName(tr("IOS Debugger")); debugger.setAutoDetected(true); @@ -371,6 +371,11 @@ FileName IosConfigurations::developerPath() return m_instance->m_developerPath; } +FileName IosConfigurations::lldbPath() +{ + return m_instance->m_lldbPath; +} + void IosConfigurations::save() { QSettings *settings = Core::ICore::settings(); @@ -432,6 +437,18 @@ void IosConfigurations::setDeveloperPath(const FileName &devPath) m_instance->m_developerPath = devPath; m_instance->save(); updateAutomaticKitList(); + QProcess lldbInfo; + lldbInfo.start(QLatin1String("xcrun"), QStringList() << QLatin1String("--find") + << QLatin1String("lldb")); + if (!lldbInfo.waitForFinished(2000)) { + lldbInfo.kill(); + } else { + QByteArray lPath=lldbInfo.readAll(); + lPath.chop(1); + Utils::FileName lldbPath = Utils::FileName::fromString(QString::fromLocal8Bit(lPath.data(), lPath.size())); + if (lldbPath.toFileInfo().exists()) + m_instance->m_lldbPath = lldbPath; + } emit m_instance->updated(); } } diff --git a/src/plugins/ios/iosconfigurations.h b/src/plugins/ios/iosconfigurations.h index b491f8b0c01..631dc937eb2 100644 --- a/src/plugins/ios/iosconfigurations.h +++ b/src/plugins/ios/iosconfigurations.h @@ -53,6 +53,7 @@ public: static bool ignoreAllDevices(); static void setIgnoreAllDevices(bool ignoreDevices); static Utils::FileName developerPath(); + static Utils::FileName lldbPath(); signals: void updated(); @@ -68,6 +69,7 @@ private: static void setDeveloperPath(const Utils::FileName &devPath); Utils::FileName m_developerPath; + Utils::FileName m_lldbPath; bool m_ignoreAllDevices; }; diff --git a/src/plugins/ios/iosdebugsupport.cpp b/src/plugins/ios/iosdebugsupport.cpp index a2890c84ef9..d9ea84ac150 100644 --- a/src/plugins/ios/iosdebugsupport.cpp +++ b/src/plugins/ios/iosdebugsupport.cpp @@ -37,7 +37,8 @@ #include #include #include - +#include +#include #include #include #include @@ -45,6 +46,11 @@ #include #include +#include + +#include +#include +#include using namespace Debugger; using namespace ProjectExplorer; @@ -56,14 +62,46 @@ namespace Internal { RunControl *IosDebugSupport::createDebugRunControl(IosRunConfiguration *runConfig, QString *errorMessage) { - //Target *target = runConfig->target(); - //Qt4Project *project = static_cast(target->project()); + Target *target = runConfig->target(); + if (!target) + return 0; + ProjectExplorer::IDevice::ConstPtr device = DeviceKitInformation::device(target->kit()); + if (device.isNull()) + return 0; + Qt4Project *project = static_cast(target->project()); DebuggerStartParameters params; - params.startMode = AttachToRemoteServer; - //params.displayName = IosManager::packageName(target); + if (device->type() == Core::Id(Ios::Constants::IOS_DEVICE_TYPE)) + params.startMode = AttachToRemoteProcess; + else + params.startMode = AttachExternal; + params.displayName = runConfig->appName(); params.remoteSetupNeeded = true; + Debugger::DebuggerRunConfigurationAspect *aspect + = runConfig->extraAspect(); + if (aspect->useCppDebugger()) { + params.languages |= CppLanguage; + Kit *kit = target->kit(); + params.sysRoot = SysRootKitInformation::sysRoot(kit).toString(); + params.debuggerCommand = DebuggerKitInformation::debuggerCommand(kit).toString(); + if (ToolChain *tc = ToolChainKitInformation::toolChain(kit)) + params.toolChainAbi = tc->targetAbi(); + params.executable = runConfig->exePath().toString(); + } + if (aspect->useQmlDebugger()) { + params.languages |= QmlLanguage; + QTcpServer server; + QTC_ASSERT(server.listen(QHostAddress::LocalHost) + || server.listen(QHostAddress::LocalHostIPv6), return 0); + params.qmlServerAddress = server.serverAddress().toString(); + params.remoteSetupNeeded = true; + //TODO: Not sure if these are the right paths. + params.projectSourceDirectory = project->projectDirectory(); + params.projectSourceFiles = project->files(Qt4Project::ExcludeGeneratedFiles); + params.projectBuildDirectory = project->rootQt4ProjectNode()->buildDir(); + } + DebuggerRunControl * const debuggerRunControl = DebuggerPlugin::createDebugger(params, runConfig, errorMessage); new IosDebugSupport(runConfig, debuggerRunControl); @@ -74,7 +112,7 @@ IosDebugSupport::IosDebugSupport(IosRunConfiguration *runConfig, DebuggerRunControl *runControl) : QObject(runControl), m_runControl(runControl), m_runner(new IosRunner(this, runConfig, true)), - m_gdbServerPort(0), m_qmlPort(0) + m_gdbServerFd(0), m_qmlPort(0) { connect(m_runControl->engine(), SIGNAL(requestRemoteSetup()), @@ -84,6 +122,8 @@ IosDebugSupport::IosDebugSupport(IosRunConfiguration *runConfig, connect(m_runner, SIGNAL(gotGdbSocket(int)), SLOT(handleGdbServerFd(int))); + connect(m_runner, SIGNAL(gotInferiorPid(Q_PID)), + SLOT(handleGotInferiorPid(Q_PID))); connect(m_runner, SIGNAL(finished(bool)), SLOT(handleRemoteProcessFinished(bool))); @@ -93,17 +133,43 @@ IosDebugSupport::IosDebugSupport(IosRunConfiguration *runConfig, SLOT(handleRemoteOutput(QString))); } +IosDebugSupport::~IosDebugSupport() +{ + if (m_gdbServerFd > 0) + close(m_gdbServerFd); +} + void IosDebugSupport::handleGdbServerFd(int gdbServerFd) { - Q_UNUSED(gdbServerFd); - QTC_CHECK(false); // to do transfer fd to debugger - //m_runControl->engine()->notifyEngineRemoteSetupDone(gdbServerPort, qmlPort); + if (m_gdbServerFd > 0) { + close(m_gdbServerFd); + m_gdbServerFd = 0; + } + if (gdbServerFd > 0) { + m_runControl->engine()->notifyEngineRemoteSetupDone(m_gdbServerFd, m_qmlPort); + } else { + m_runControl->engine()->notifyEngineRemoteSetupFailed( + tr("Could not get debug server file descriptor.")); + } +} + +void IosDebugSupport::handleGotInferiorPid(Q_PID pid) +{ + if (pid > 0) { + //m_runControl->engine()->notifyInferiorPid(pid); + m_runControl->engine()->notifyEngineRemoteSetupDone(int(pid), m_qmlPort); + } else { + m_runControl->engine()->notifyEngineRemoteSetupFailed( + tr("Got an invalid process id.")); + } } void IosDebugSupport::handleRemoteProcessFinished(bool cleanEnd) { if (!cleanEnd && m_runControl) m_runControl->showMessage(tr("Run failed unexpectedly."), AppStuff); + //m_runControl->engine()->notifyInferiorIll(); + m_runControl->engine()->abortDebugger(); } void IosDebugSupport::handleRemoteOutput(const QString &output) diff --git a/src/plugins/ios/iosdebugsupport.h b/src/plugins/ios/iosdebugsupport.h index 7d2047bfc5c..59b223fd5e5 100644 --- a/src/plugins/ios/iosdebugsupport.h +++ b/src/plugins/ios/iosdebugsupport.h @@ -30,6 +30,7 @@ #define IOSDEBUGSUPPORT_H #include "iosrunconfiguration.h" +#include namespace Debugger { class DebuggerRunControl; } namespace ProjectExplorer { class RunControl; } @@ -50,9 +51,11 @@ public: IosDebugSupport(IosRunConfiguration *runConfig, Debugger::DebuggerRunControl *runControl); + ~IosDebugSupport(); private slots: void handleGdbServerFd(int gdbServerFd); + void handleGotInferiorPid(Q_PID); void handleRemoteProcessFinished(bool cleanEnd); void handleRemoteOutput(const QString &output); @@ -63,7 +66,7 @@ private: IosRunner * const m_runner; const QString m_dumperLib; - int m_gdbServerPort; + int m_gdbServerFd; int m_qmlPort; }; diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp index 228daffe304..aa0ab8b989f 100644 --- a/src/plugins/ios/iosprobe.cpp +++ b/src/plugins/ios/iosprobe.cpp @@ -214,6 +214,7 @@ void IosProbe::setupDefaultToolchains(const QString &devPath, const QString &xco } if (hasClang) { Platform clangProfile; + clangProfile.developerPath = Utils::FileName::fromString(devPath); clangProfile.platformKind = 0; clangProfile.name = clangFullName; clangProfile.platformPath = Utils::FileName(fInfo); @@ -231,6 +232,7 @@ void IosProbe::setupDefaultToolchains(const QString &devPath, const QString &xco } if (hasGcc) { Platform gccProfile; + gccProfile.developerPath = Utils::FileName::fromString(devPath); gccProfile.name = gccFullName; gccProfile.platformKind = 0; // use the arm-apple-darwin10-llvm-* variant and avoid the extraFlags if available??? diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index d6e455b9fc1..17edb913e3b 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #if defined(Q_OS_UNIX) #include @@ -65,6 +66,7 @@ class MyProcess: public QProcess Q_OBJECT public: explicit MyProcess(QObject *parent = 0); + ~MyProcess(); int processOutputSocket(); QSocketNotifier *notifier(); protected: @@ -224,10 +226,15 @@ MyProcess::MyProcess(QObject *parent) : QProcess(parent) if (socketpair(PF_UNIX, SOCK_STREAM, 0, &m_sockets[0]) == -1) { qDebug() << "IosToolHandler socketpair failed "; } - shutdown(m_sockets[0], SHUT_WR); 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]; @@ -245,7 +252,6 @@ void MyProcess::setupChildProcess() emit finished(-1, QProcess::CrashExit); exit(-1); } - shutdown(1, SHUT_RD); // leave open for handshake when transferring fd? } #else MyProcess::MyProcess(QObject *parent) : QProcess(parent) @@ -272,6 +278,11 @@ IosToolHandlerPrivate::IosToolHandlerPrivate(IosToolHandler::DeviceType devType, q(q), state(NonStarted), devType(devType), buffer(4*lookaheadSize, 0), iBegin(0), iEnd(0), gdbSocket(-1) { + QProcessEnvironment env(QProcessEnvironment::systemEnvironment()); + foreach (const QString &k, env.keys()) + 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(finished(int,QProcess::ExitStatus)), q, SLOT(subprocessFinished(int,QProcess::ExitStatus))); @@ -498,6 +509,8 @@ int recv_fd(int socket) 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; } } @@ -777,7 +790,7 @@ void IosToolHandlerPrivate::subprocessHasData(int socket) currentData = buffer.mid(0, lastXmlSize); // remove this?? } qptrdiff toRead = lookaheadSize - (iEnd - spacerStart); - qptrdiff reallyRead = recv(socket, buffer.data() + iBegin, toRead, 0); + qptrdiff reallyRead = recv(socket, buffer.data() + iEnd, toRead, 0); if (reallyRead == 0) { // eof stop(); return; @@ -799,14 +812,19 @@ void IosToolHandlerPrivate::subprocessHasData(int socket) iEnd += reallyRead; if (reallyRead != toRead) continue; - if (spacerStart < iEnd && buffer.at(spacerStart) != 'n') { + if (spacerStart < iEnd && buffer.at(spacerStart) != 'N') { ++spacerStart; - while (spacerStart < iEnd && buffer.at(spacerStart) != 'n') + 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; diff --git a/src/tools/3rdparty/iossim/iossim.pro b/src/tools/3rdparty/iossim/iossim.pro index 63d21886b50..cd153ea73c4 100644 --- a/src/tools/3rdparty/iossim/iossim.pro +++ b/src/tools/3rdparty/iossim/iossim.pro @@ -1,5 +1,8 @@ CONFIG += console +QT += core +QT += gui + CONFIG -= app_bundle include(../../../../qtcreator.pri) diff --git a/src/tools/3rdparty/iossim/iphonesimulator.mm b/src/tools/3rdparty/iossim/iphonesimulator.mm index c7467753147..78955216a46 100644 --- a/src/tools/3rdparty/iossim/iphonesimulator.mm +++ b/src/tools/3rdparty/iossim/iphonesimulator.mm @@ -14,8 +14,8 @@ NSString *simulatorPrefrencesName = @"com.apple.iphonesimulator"; NSString *deviceProperty = @"SimulateDevice"; -NSString *deviceIphoneRetina3_5Inch = @"iPhone (Retina 3.5-inch)"; -NSString *deviceIphoneRetina4_0Inch = @"iPhone (Retina 4-inch)"; +NSString *deviceIphoneRetina3_5Inch = @"iPhone Retina (3.5-inch)"; +NSString *deviceIphoneRetina4_0Inch = @"iPhone Retina (4-inch)"; NSString *deviceIphone = @"iPhone"; NSString *deviceIpad = @"iPad"; NSString *deviceIpadRetina = @"iPad (Retina)"; @@ -156,6 +156,7 @@ NSString *deviceIpadRetina = @"iPad (Retina)"; return; } nsprintf(@"%@", [session simulatedApplicationPID]); + fflush(stdout); pidCheckingTimer = [[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(checkPid:) userInfo:nil repeats: TRUE] retain]; } else { @@ -266,6 +267,16 @@ NSString *deviceIpadRetina = @"iPad (Retina)"; } } + + NSString *sdkVersion = [sdkRoot sdkVersion]; + NSString *appSupportDir = [NSString stringWithFormat:@"%@/Library/Application Support/iPhone Simulator/%@", + NSHomeDirectory(), sdkVersion]; + [environment addEntriesFromDictionary:@{ + @"CFFIXED_USER_HOME" : appSupportDir, + @"IPHONE_SIMULATOR_ROOT" : [sdkRoot sdkRootPath], + @"NSUnbufferedIO" : @"YES", + }]; + /* Set up the session configuration */ tClass = objc_getClass("DTiPhoneSimulatorSessionConfig"); if (tClass == nil) { @@ -275,7 +286,7 @@ NSString *deviceIpadRetina = @"iPad (Retina)"; config = [[[tClass alloc] init] autorelease]; [config setApplicationToSimulateOnStart:appSpec]; [config setSimulatedSystemRoot:sdkRoot]; - [config setSimulatedApplicationShouldWaitForDebugger:shouldStartDebugger]; + [config setSimulatedApplicationShouldWaitForDebugger:shouldWaitDebugger]; [config setSimulatedApplicationLaunchArgs:args]; [config setSimulatedApplicationLaunchEnvironment:environment]; diff --git a/src/tools/iostool/main.cpp b/src/tools/iostool/main.cpp index 9030e103f01..9acc5a71a24 100644 --- a/src/tools/iostool/main.cpp +++ b/src/tools/iostool/main.cpp @@ -45,6 +45,7 @@ #include #include #include +#include class IosTool: public QObject { @@ -274,7 +275,20 @@ int send_fd(int socket, int fd_to_send) control_message->cmsg_len = CMSG_LEN(sizeof(int)); *((int *) CMSG_DATA(control_message)) = fd_to_send; - return sendmsg(socket, &socket_message, 0); + 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, @@ -329,7 +343,7 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId, 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"; + const char *msg = "Now sending the gdbserver socket, will need a unix socket to succeed"; outFile.write(msg, strlen(msg)); outFile.flush(); int sent = send_fd(1, gdbFd);