1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "debuggermainwindow.h"
27 #include "debuggerruncontrol.h"
28 #include "terminal.h"
29 
30 #include "analyzer/analyzermanager.h"
31 #include "console/console.h"
32 #include "debuggeractions.h"
33 #include "debuggercore.h"
34 #include "debuggerengine.h"
35 #include "debuggerinternalconstants.h"
36 #include "debuggerkitinformation.h"
37 #include "debuggerplugin.h"
38 #include "debuggerrunconfigurationaspect.h"
39 #include "breakhandler.h"
40 #include "enginemanager.h"
41 #include "shared/peutils.h"
42 
43 #include <projectexplorer/buildconfiguration.h>
44 #include <projectexplorer/devicesupport/deviceprocessesdialog.h>
45 #include <projectexplorer/devicesupport/deviceprocesslist.h>
46 #include <projectexplorer/environmentaspect.h> // For the environment
47 #include <projectexplorer/project.h>
48 #include <projectexplorer/projectexplorer.h>
49 #include <projectexplorer/projectexplorericons.h>
50 #include <projectexplorer/runconfigurationaspects.h>
51 #include <projectexplorer/session.h>
52 #include <projectexplorer/target.h>
53 #include <projectexplorer/taskhub.h>
54 #include <projectexplorer/toolchain.h>
55 
56 #include <utils/algorithm.h>
57 #include <utils/checkablemessagebox.h>
58 #include <utils/fileutils.h>
59 #include <utils/portlist.h>
60 #include <utils/qtcassert.h>
61 #include <utils/qtcprocess.h>
62 #include <utils/temporarydirectory.h>
63 #include <utils/temporaryfile.h>
64 #include <utils/url.h>
65 #include <utils/winutils.h>
66 
67 #include <coreplugin/icontext.h>
68 #include <coreplugin/icore.h>
69 #include <coreplugin/coreconstants.h>
70 #include <coreplugin/messagebox.h>
71 
72 #include <qmldebug/qmldebugcommandlinearguments.h>
73 
74 #include <qtsupport/qtkitinformation.h>
75 
76 #include <ssh/sshconnection.h>
77 
78 #include <QTcpServer>
79 #include <QTimer>
80 
81 using namespace Core;
82 using namespace Debugger::Internal;
83 using namespace ProjectExplorer;
84 using namespace Utils;
85 
86 enum { debug = 0 };
87 
88 namespace Debugger {
89 namespace Internal {
90 
91 DebuggerEngine *createCdbEngine();
92 DebuggerEngine *createGdbEngine();
93 DebuggerEngine *createPdbEngine();
94 DebuggerEngine *createQmlEngine();
95 DebuggerEngine *createLldbEngine();
96 DebuggerEngine *createUvscEngine();
97 
98 class CoreUnpacker final : public RunWorker
99 {
100 public:
CoreUnpacker(RunControl * runControl,const QString & coreFileName)101     CoreUnpacker(RunControl *runControl, const QString &coreFileName)
102         : RunWorker(runControl), m_coreFileName(coreFileName)
103     {}
104 
coreFileName() const105     QString coreFileName() const { return m_tempCoreFileName; }
106 
107 private:
~CoreUnpacker()108     ~CoreUnpacker() final
109     {
110         m_coreUnpackProcess.blockSignals(true);
111         m_coreUnpackProcess.terminate();
112         m_coreUnpackProcess.deleteLater();
113         if (m_tempCoreFile.isOpen())
114             m_tempCoreFile.close();
115 
116         QFile::remove(m_tempCoreFileName);
117     }
118 
start()119     void start() final
120     {
121         {
122             Utils::TemporaryFile tmp("tmpcore-XXXXXX");
123             tmp.open();
124             m_tempCoreFileName = tmp.fileName();
125         }
126 
127         m_coreUnpackProcess.setWorkingDirectory(TemporaryDirectory::masterDirectoryPath());
128         connect(&m_coreUnpackProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
129                 this, &CoreUnpacker::reportStarted);
130 
131         const QString msg = DebuggerRunTool::tr("Unpacking core file to %1");
132         appendMessage(msg.arg(m_tempCoreFileName), LogMessageFormat);
133 
134         if (m_coreFileName.endsWith(".lzo")) {
135             m_coreUnpackProcess.start("lzop", {"-o", m_tempCoreFileName, "-x", m_coreFileName});
136             return;
137         }
138 
139         if (m_coreFileName.endsWith(".gz")) {
140             appendMessage(msg.arg(m_tempCoreFileName), LogMessageFormat);
141             m_tempCoreFile.setFileName(m_tempCoreFileName);
142             m_tempCoreFile.open(QFile::WriteOnly);
143             connect(&m_coreUnpackProcess, &QProcess::readyRead, this, [this] {
144                 m_tempCoreFile.write(m_coreUnpackProcess.readAll());
145             });
146             m_coreUnpackProcess.start("gzip", {"-c", "-d", m_coreFileName});
147             return;
148         }
149 
150         QTC_CHECK(false);
151         reportFailure("Unknown file extension in " + m_coreFileName);
152     }
153 
154     QFile m_tempCoreFile;
155     QString m_coreFileName;
156     QString m_tempCoreFileName;
157     QProcess m_coreUnpackProcess;
158 };
159 
160 class DebuggerRunToolPrivate
161 {
162 public:
163     bool useTerminal = false;
164     QPointer<CoreUnpacker> coreUnpacker;
165     QPointer<DebugServerPortsGatherer> portsGatherer;
166     bool addQmlServerInferiorCommandLineArgumentIfNeeded = false;
167     TerminalRunner *terminalRunner = nullptr;
168     int snapshotCounter = 0;
169     int engineStartsNeeded = 0;
170     int engineStopsNeeded = 0;
171     QString runId;
172 };
173 
174 } // namespace Internal
175 
176 static bool breakOnMainNextTime = false;
177 
setBreakOnMainNextTime()178 void DebuggerRunTool::setBreakOnMainNextTime()
179 {
180     breakOnMainNextTime = true;
181 }
182 
setStartMode(DebuggerStartMode startMode)183 void DebuggerRunTool::setStartMode(DebuggerStartMode startMode)
184 {
185     if (startMode == AttachToQmlServer) {
186         m_runParameters.startMode = AttachToRemoteProcess;
187         m_runParameters.cppEngineType = NoEngineType;
188         m_runParameters.isQmlDebugging = true;
189         m_runParameters.closeMode = KillAtClose;
190 
191         // FIXME: This is horribly wrong.
192         // get files from all the projects in the session
193         QList<Project *> projects = SessionManager::projects();
194         if (Project *startupProject = SessionManager::startupProject()) {
195             // startup project first
196             projects.removeOne(startupProject);
197             projects.insert(0, startupProject);
198         }
199         foreach (Project *project, projects)
200             m_runParameters.projectSourceFiles.append(project->files(Project::SourceFiles));
201         if (!projects.isEmpty())
202             m_runParameters.projectSourceDirectory = projects.first()->projectDirectory();
203 
204     } else {
205         m_runParameters.startMode = startMode;
206     }
207 }
208 
setCloseMode(DebuggerCloseMode closeMode)209 void DebuggerRunTool::setCloseMode(DebuggerCloseMode closeMode)
210 {
211     m_runParameters.closeMode = closeMode;
212 }
213 
setAttachPid(ProcessHandle pid)214 void DebuggerRunTool::setAttachPid(ProcessHandle pid)
215 {
216     m_runParameters.attachPID = pid;
217 }
218 
setAttachPid(qint64 pid)219 void DebuggerRunTool::setAttachPid(qint64 pid)
220 {
221     m_runParameters.attachPID = ProcessHandle(pid);
222 }
223 
setSysRoot(const Utils::FilePath & sysRoot)224 void DebuggerRunTool::setSysRoot(const Utils::FilePath &sysRoot)
225 {
226     m_runParameters.sysRoot = sysRoot;
227 }
228 
setSymbolFile(const FilePath & symbolFile)229 void DebuggerRunTool::setSymbolFile(const FilePath &symbolFile)
230 {
231     if (symbolFile.isEmpty())
232         reportFailure(tr("Cannot debug: Local executable is not set."));
233     m_runParameters.symbolFile = symbolFile;
234 }
235 
setLldbPlatform(const QString & platform)236 void DebuggerRunTool::setLldbPlatform(const QString &platform)
237 {
238     m_runParameters.platform = platform;
239 }
240 
setRemoteChannel(const QString & channel)241 void DebuggerRunTool::setRemoteChannel(const QString &channel)
242 {
243     m_runParameters.remoteChannel = channel;
244 }
245 
setRemoteChannel(const QUrl & url)246 void DebuggerRunTool::setRemoteChannel(const QUrl &url)
247 {
248     m_runParameters.remoteChannel = QString("%1:%2").arg(url.host()).arg(url.port());
249 }
250 
remoteChannel() const251 QString DebuggerRunTool::remoteChannel() const
252 {
253     return m_runParameters.remoteChannel;
254 }
255 
setRemoteChannel(const QString & host,int port)256 void DebuggerRunTool::setRemoteChannel(const QString &host, int port)
257 {
258     m_runParameters.remoteChannel = QString("%1:%2").arg(host).arg(port);
259 }
260 
setUseExtendedRemote(bool on)261 void DebuggerRunTool::setUseExtendedRemote(bool on)
262 {
263     m_runParameters.useExtendedRemote = on;
264 }
265 
setUseContinueInsteadOfRun(bool on)266 void DebuggerRunTool::setUseContinueInsteadOfRun(bool on)
267 {
268     m_runParameters.useContinueInsteadOfRun = on;
269 }
270 
setUseTargetAsync(bool on)271 void DebuggerRunTool::setUseTargetAsync(bool on)
272 {
273     m_runParameters.useTargetAsync = on;
274 }
275 
setContinueAfterAttach(bool on)276 void DebuggerRunTool::setContinueAfterAttach(bool on)
277 {
278     m_runParameters.continueAfterAttach = on;
279 }
280 
setSkipExecutableValidation(bool on)281 void DebuggerRunTool::setSkipExecutableValidation(bool on)
282 {
283     m_runParameters.skipExecutableValidation = on;
284 }
285 
setUseCtrlCStub(bool on)286 void DebuggerRunTool::setUseCtrlCStub(bool on)
287 {
288     m_runParameters.useCtrlCStub = on;
289 }
290 
setBreakOnMain(bool on)291 void DebuggerRunTool::setBreakOnMain(bool on)
292 {
293     m_runParameters.breakOnMain = on;
294 }
295 
setUseTerminal(bool on)296 void DebuggerRunTool::setUseTerminal(bool on)
297 {
298     // CDB has a built-in console that might be preferred by some.
299     bool useCdbConsole = m_runParameters.cppEngineType == CdbEngineType
300             && (m_runParameters.startMode == StartInternal
301                 || m_runParameters.startMode == StartExternal)
302             && debuggerSettings()->useCdbConsole.value();
303 
304     if (on && !d->terminalRunner && !useCdbConsole) {
305         d->terminalRunner =
306             new TerminalRunner(runControl(), [this] { return m_runParameters.inferior; });
307         d->terminalRunner->setRunAsRoot(m_runParameters.runAsRoot);
308         addStartDependency(d->terminalRunner);
309     }
310     if (!on && d->terminalRunner) {
311         QTC_CHECK(false); // User code can only switch from no terminal to one terminal.
312     }
313 }
314 
setRunAsRoot(bool on)315 void DebuggerRunTool::setRunAsRoot(bool on)
316 {
317     m_runParameters.runAsRoot = on;
318     if (d->terminalRunner)
319         d->terminalRunner->setRunAsRoot(on);
320 }
321 
setCommandsAfterConnect(const QString & commands)322 void DebuggerRunTool::setCommandsAfterConnect(const QString &commands)
323 {
324     m_runParameters.commandsAfterConnect = commands;
325 }
326 
setCommandsForReset(const QString & commands)327 void DebuggerRunTool::setCommandsForReset(const QString &commands)
328 {
329     m_runParameters.commandsForReset = commands;
330 }
331 
setDebugInfoLocation(const QString & debugInfoLocation)332 void DebuggerRunTool::setDebugInfoLocation(const QString &debugInfoLocation)
333 {
334     m_runParameters.debugInfoLocation = debugInfoLocation;
335 }
336 
qmlServer() const337 QUrl DebuggerRunTool::qmlServer() const
338 {
339     return m_runParameters.qmlServer;
340 }
341 
setQmlServer(const QUrl & qmlServer)342 void DebuggerRunTool::setQmlServer(const QUrl &qmlServer)
343 {
344     m_runParameters.qmlServer = qmlServer;
345 }
346 
setIosPlatform(const QString & platform)347 void DebuggerRunTool::setIosPlatform(const QString &platform)
348 {
349     m_runParameters.platform = platform;
350 }
351 
setDeviceSymbolsRoot(const QString & deviceSymbolsRoot)352 void DebuggerRunTool::setDeviceSymbolsRoot(const QString &deviceSymbolsRoot)
353 {
354     m_runParameters.deviceSymbolsRoot = deviceSymbolsRoot;
355 }
356 
setTestCase(int testCase)357 void DebuggerRunTool::setTestCase(int testCase)
358 {
359     m_runParameters.testCase = testCase;
360 }
361 
setOverrideStartScript(const QString & script)362 void DebuggerRunTool::setOverrideStartScript(const QString &script)
363 {
364     m_runParameters.overrideStartScript = script;
365 }
366 
setAbi(const Abi & abi)367 void DebuggerRunTool::setAbi(const Abi &abi)
368 {
369     m_runParameters.toolChainAbi = abi;
370 }
371 
setInferior(const Runnable & runnable)372 void DebuggerRunTool::setInferior(const Runnable &runnable)
373 {
374     m_runParameters.inferior = runnable;
375 }
376 
setInferiorExecutable(const FilePath & executable)377 void DebuggerRunTool::setInferiorExecutable(const FilePath &executable)
378 {
379     m_runParameters.inferior.executable = executable;
380 }
381 
setInferiorEnvironment(const Utils::Environment & env)382 void DebuggerRunTool::setInferiorEnvironment(const Utils::Environment &env)
383 {
384     m_runParameters.inferior.environment = env;
385 }
386 
setInferiorDevice(IDevice::ConstPtr device)387 void DebuggerRunTool::setInferiorDevice(IDevice::ConstPtr device)
388 {
389     m_runParameters.inferior.device = device;
390 }
391 
setRunControlName(const QString & name)392 void DebuggerRunTool::setRunControlName(const QString &name)
393 {
394     m_runParameters.displayName = name;
395 }
396 
setStartMessage(const QString & msg)397 void DebuggerRunTool::setStartMessage(const QString &msg)
398 {
399     m_runParameters.startMessage = msg;
400 }
401 
setCoreFileName(const QString & coreFile,bool isSnapshot)402 void DebuggerRunTool::setCoreFileName(const QString &coreFile, bool isSnapshot)
403 {
404     if (coreFile.endsWith(".gz") || coreFile.endsWith(".lzo")) {
405         d->coreUnpacker = new CoreUnpacker(runControl(), coreFile);
406         addStartDependency(d->coreUnpacker);
407     }
408 
409     m_runParameters.coreFile = coreFile;
410     m_runParameters.isSnapshot = isSnapshot;
411 }
412 
addQmlServerInferiorCommandLineArgumentIfNeeded()413 void DebuggerRunTool::addQmlServerInferiorCommandLineArgumentIfNeeded()
414 {
415     d->addQmlServerInferiorCommandLineArgumentIfNeeded = true;
416 }
417 
modifyDebuggerEnvironment(const EnvironmentItems & items)418 void DebuggerRunTool::modifyDebuggerEnvironment(const EnvironmentItems &items)
419 {
420     m_runParameters.debugger.environment.modify(items);
421 }
422 
setCrashParameter(const QString & event)423 void DebuggerRunTool::setCrashParameter(const QString &event)
424 {
425     m_runParameters.crashParameter = event;
426 }
427 
addExpectedSignal(const QString & signal)428 void DebuggerRunTool::addExpectedSignal(const QString &signal)
429 {
430     m_runParameters.expectedSignals.append(signal);
431 }
432 
addSearchDirectory(const Utils::FilePath & dir)433 void DebuggerRunTool::addSearchDirectory(const Utils::FilePath &dir)
434 {
435     m_runParameters.additionalSearchDirectories.append(dir);
436 }
437 
start()438 void DebuggerRunTool::start()
439 {
440     TaskHub::clearTasks(Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO);
441     TaskHub::clearTasks(Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
442 
443     if (d->portsGatherer) {
444         setRemoteChannel(d->portsGatherer->gdbServer());
445         setQmlServer(d->portsGatherer->qmlServer());
446         if (d->addQmlServerInferiorCommandLineArgumentIfNeeded
447                 && m_runParameters.isQmlDebugging
448                 && m_runParameters.isCppDebugging()) {
449 
450             int qmlServerPort = m_runParameters.qmlServer.port();
451             QTC_ASSERT(qmlServerPort > 0, reportFailure(); return);
452             QString mode = QString("port:%1").arg(qmlServerPort);
453 
454             CommandLine cmd{m_runParameters.inferior.executable};
455             cmd.addArg(qmlDebugCommandLineArguments(QmlDebug::QmlDebuggerServices, mode, true));
456             cmd.addArgs(m_runParameters.inferior.commandLineArguments, CommandLine::Raw);
457 
458             m_runParameters.inferior.setCommandLine(cmd);
459         }
460     }
461 
462     // User canceled input dialog asking for executable when working on library project.
463     if (m_runParameters.startMode == StartInternal
464             && m_runParameters.inferior.executable.isEmpty()
465             && m_runParameters.interpreter.isEmpty()) {
466         reportFailure(tr("No executable specified."));
467         return;
468     }
469 
470     // QML and/or mixed are not prepared for it.
471     setSupportsReRunning(!m_runParameters.isQmlDebugging);
472 
473     // FIXME: Disabled due to Android. Make Android device report available ports instead.
474 //    int portsUsed = portsUsedByDebugger();
475 //    if (portsUsed > device()->freePorts().count()) {
476 //        reportFailure(tr("Cannot debug: Not enough free ports available."));
477 //        return;
478 //    }
479 
480     if (d->coreUnpacker)
481         m_runParameters.coreFile = d->coreUnpacker->coreFileName();
482 
483     if (!fixupParameters())
484         return;
485 
486     if (m_runParameters.cppEngineType == CdbEngineType
487             && Utils::is64BitWindowsBinary(m_runParameters.inferior.executable.toString())
488             && !Utils::is64BitWindowsBinary(m_runParameters.debugger.executable.toString())) {
489         reportFailure(
490             DebuggerPlugin::tr(
491                 "%1 is a 64 bit executable which can not be debugged by a 32 bit Debugger.\n"
492                 "Please select a 64 bit Debugger in the kit settings for this kit.")
493                 .arg(m_runParameters.inferior.executable.toUserOutput()));
494         return;
495     }
496 
497     Utils::globalMacroExpander()->registerFileVariables(
498                 "DebuggedExecutable", tr("Debugged executable"),
499                 [this] { return m_runParameters.inferior.executable; }
500     );
501 
502     runControl()->setDisplayName(m_runParameters.displayName);
503 
504     if (!m_engine) {
505         if (m_runParameters.isCppDebugging()) {
506             switch (m_runParameters.cppEngineType) {
507             case GdbEngineType:
508                 m_engine = createGdbEngine();
509                 break;
510             case CdbEngineType:
511                 if (!HostOsInfo::isWindowsHost()) {
512                     reportFailure(tr("Unsupported CDB host system."));
513                     return;
514                 }
515                 m_engine = createCdbEngine();
516                 break;
517             case LldbEngineType:
518                 m_engine = createLldbEngine();
519                 break;
520             case PdbEngineType: // FIXME: Yes, Python counts as C++...
521                 QTC_CHECK(false); // Called from DebuggerRunTool constructor already.
522 //                m_engine = createPdbEngine();
523                 break;
524             case UvscEngineType:
525                 m_engine = createUvscEngine();
526                 break;
527             default:
528                 if (!m_runParameters.isQmlDebugging) {
529                     reportFailure(DebuggerPlugin::tr("Unable to create a debugging engine. "
530                                                      "Please select a Debugger Setting from the Run page of the project mode."));
531                     return;
532                 }
533                 // Can happen for pure Qml.
534                 break;
535             }
536         }
537 
538         if (m_runParameters.isQmlDebugging) {
539             if (m_engine) {
540                 m_engine2 = createQmlEngine();
541             } else {
542                 m_engine = createQmlEngine();
543             }
544         }
545     }
546 
547     if (!m_engine) {
548         reportFailure(DebuggerPlugin::tr("Unable to create a debugging engine."));
549         return;
550     }
551 
552     m_engine->setRunParameters(m_runParameters);
553     m_engine->setRunId(d->runId);
554     m_engine->setRunTool(this);
555     m_engine->setCompanionEngine(m_engine2);
556     connect(m_engine, &DebuggerEngine::requestRunControlFinish,
557             runControl(), &RunControl::initiateFinish);
558     connect(m_engine, &DebuggerEngine::requestRunControlStop,
559             runControl(), &RunControl::initiateStop);
560     connect(m_engine, &DebuggerEngine::engineStarted,
561             this, [this] { handleEngineStarted(m_engine); });
562     connect(m_engine, &DebuggerEngine::engineFinished,
563             this, [this] { handleEngineFinished(m_engine); });
564     connect(m_engine, &DebuggerEngine::appendMessageRequested,
565             this, &DebuggerRunTool::appendMessage);
566     ++d->engineStartsNeeded;
567     ++d->engineStopsNeeded;
568 
569     connect(m_engine, &DebuggerEngine::attachToCoreRequested, this, [this](const QString &coreFile) {
570         auto runConfig = runControl()->runConfiguration();
571         QTC_ASSERT(runConfig, return);
572         auto rc = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE);
573         rc->setRunConfiguration(runConfig);
574         auto name = QString(tr("%1 - Snapshot %2").arg(runControl()->displayName()).arg(++d->snapshotCounter));
575         auto debugger = new DebuggerRunTool(rc);
576         debugger->setStartMode(AttachToCore);
577         debugger->setRunControlName(name);
578         debugger->setCoreFileName(coreFile, true);
579         debugger->startRunControl();
580     });
581 
582     if (m_engine2) {
583         m_engine2->setRunParameters(m_runParameters);
584         m_engine2->setRunId(d->runId);
585         m_engine2->setRunTool(this);
586         m_engine2->setCompanionEngine(m_engine);
587         m_engine2->setSecondaryEngine();
588         connect(m_engine2, &DebuggerEngine::requestRunControlFinish,
589                 runControl(), &RunControl::initiateFinish);
590         connect(m_engine2, &DebuggerEngine::requestRunControlStop,
591                 runControl(), &RunControl::initiateStop);
592         connect(m_engine2, &DebuggerEngine::engineStarted,
593                 this, [this] { handleEngineStarted(m_engine2); });
594         connect(m_engine2, &DebuggerEngine::engineFinished,
595                 this, [this] { handleEngineFinished(m_engine2); });
596         connect(m_engine2, &DebuggerEngine::appendMessageRequested,
597                 this, &DebuggerRunTool::appendMessage);
598         ++d->engineStartsNeeded;
599         ++d->engineStopsNeeded;
600     }
601 
602     if (m_runParameters.startMode == StartInternal) {
603         QStringList unhandledIds;
604         bool hasQmlBreakpoints = false;
605         for (const GlobalBreakpoint &gbp : BreakpointManager::globalBreakpoints()) {
606             if (gbp->isEnabled()) {
607                 const BreakpointParameters &bp = gbp->requestedParameters();
608                 hasQmlBreakpoints = hasQmlBreakpoints || bp.isQmlFileAndLineBreakpoint();
609                 if (!m_engine->acceptsBreakpoint(bp)) {
610                     if (!m_engine2 || !m_engine2->acceptsBreakpoint(bp))
611                         unhandledIds.append(gbp->displayName());
612                 }
613             }
614         }
615         if (!unhandledIds.isEmpty()) {
616             QString warningMessage =
617                     DebuggerPlugin::tr("Some breakpoints cannot be handled by the debugger "
618                                        "languages currently active, and will be ignored.<p>"
619                                        "Affected are breakpoints %1")
620                     .arg(unhandledIds.join(", "));
621 
622             if (hasQmlBreakpoints) {
623                 warningMessage += "<p>" +
624                     DebuggerPlugin::tr("QML debugging needs to be enabled both in the Build "
625                                        "and the Run settings.");
626             }
627 
628             showMessage(warningMessage, LogWarning);
629 
630             static bool checked = true;
631             if (checked)
632                 CheckableMessageBox::information(Core::ICore::dialogParent(),
633                                                  tr("Debugger"),
634                                                  warningMessage,
635                                                  tr("&Show this message again."),
636                                                  &checked, QDialogButtonBox::Ok);
637         }
638     }
639 
640     appendMessage(tr("Debugging %1 ...").arg(m_runParameters.inferior.commandLine().toUserOutput()),
641                   NormalMessageFormat);
642     QString debuggerName = m_engine->objectName();
643     if (m_engine2)
644         debuggerName += ' ' + m_engine2->objectName();
645 
646     const QString message = tr("Starting debugger \"%1\" for ABI \"%2\"...")
647             .arg(debuggerName).arg(m_runParameters.toolChainAbi.toString());
648     DebuggerMainWindow::showStatusMessage(message, 10000);
649 
650     showMessage(m_engine->formatStartParameters(), LogDebug);
651     showMessage(DebuggerSettings::dump(), LogDebug);
652 
653     if (m_engine2)
654         m_engine2->start();
655     m_engine->start();
656 }
657 
stop()658 void DebuggerRunTool::stop()
659 {
660     QTC_ASSERT(m_engine, reportStopped(); return);
661     if (m_engine2)
662         m_engine2->quitDebugger();
663     m_engine->quitDebugger();
664 }
665 
handleEngineStarted(DebuggerEngine * engine)666 void DebuggerRunTool::handleEngineStarted(DebuggerEngine *engine)
667 {
668     // Correct:
669 //    if (--d->engineStartsNeeded == 0) {
670 //        EngineManager::activateDebugMode();
671 //        reportStarted();
672 //    }
673 
674     // Feels better, as the QML Engine might attach late or not at all.
675     if (engine == m_engine) {
676         EngineManager::activateDebugMode();
677         reportStarted();
678     }
679 }
680 
handleEngineFinished(DebuggerEngine * engine)681 void DebuggerRunTool::handleEngineFinished(DebuggerEngine *engine)
682 {
683     engine->prepareForRestart();
684     if (--d->engineStopsNeeded == 0) {
685         QString cmd = m_runParameters.inferior.commandLine().toUserOutput();
686         QString msg = engine->runParameters().exitCode // Main engine.
687             ? tr("Debugging of %1 has finished with exit code %2.")
688                 .arg(cmd).arg(engine->runParameters().exitCode.value())
689             : tr("Debugging of %1 has finished.").arg(cmd);
690         appendMessage(msg, NormalMessageFormat);
691         reportStopped();
692     }
693 }
694 
isCppDebugging() const695 bool DebuggerRunTool::isCppDebugging() const
696 {
697     return m_runParameters.isCppDebugging();
698 }
699 
isQmlDebugging() const700 bool DebuggerRunTool::isQmlDebugging() const
701 {
702     return m_runParameters.isQmlDebugging;
703 }
704 
portsUsedByDebugger() const705 int DebuggerRunTool::portsUsedByDebugger() const
706 {
707     return isCppDebugging() + isQmlDebugging();
708 }
709 
setUsePortsGatherer(bool useCpp,bool useQml)710 void DebuggerRunTool::setUsePortsGatherer(bool useCpp, bool useQml)
711 {
712     QTC_ASSERT(!d->portsGatherer, reportFailure(); return);
713     d->portsGatherer = new DebugServerPortsGatherer(runControl());
714     d->portsGatherer->setUseGdbServer(useCpp);
715     d->portsGatherer->setUseQmlServer(useQml);
716     addStartDependency(d->portsGatherer);
717 }
718 
portsGatherer() const719 DebugServerPortsGatherer *DebuggerRunTool::portsGatherer() const
720 {
721     return d->portsGatherer;
722 }
723 
setSolibSearchPath(const QStringList & list)724 void DebuggerRunTool::setSolibSearchPath(const QStringList &list)
725 {
726     m_runParameters.solibSearchPath = list;
727 }
728 
fixupParameters()729 bool DebuggerRunTool::fixupParameters()
730 {
731     DebuggerRunParameters &rp = m_runParameters;
732     if (rp.symbolFile.isEmpty())
733         rp.symbolFile = rp.inferior.executable;
734 
735     // Copy over DYLD_IMAGE_SUFFIX etc
736     for (const auto &var :
737          QStringList({"DYLD_IMAGE_SUFFIX", "DYLD_LIBRARY_PATH", "DYLD_FRAMEWORK_PATH"}))
738         if (rp.inferior.environment.hasKey(var))
739             rp.debugger.environment.set(var, rp.inferior.environment.expandedValueForKey(var));
740 
741     // validate debugger if C++ debugging is enabled
742     if (rp.isCppDebugging() && !rp.validationErrors.isEmpty()) {
743         reportFailure(rp.validationErrors.join('\n'));
744         return false;
745     }
746 
747     if (rp.isQmlDebugging) {
748         if (device() && device()->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
749             if (rp.qmlServer.port() <= 0) {
750                 rp.qmlServer = Utils::urlFromLocalHostAndFreePort();
751                 if (rp.qmlServer.port() <= 0) {
752                     reportFailure(DebuggerPlugin::tr("Not enough free ports for QML debugging."));
753                     return false;
754                 }
755             }
756             // Makes sure that all bindings go through the JavaScript engine, so that
757             // breakpoints are actually hit!
758             const QString optimizerKey = "QML_DISABLE_OPTIMIZER";
759             if (!rp.inferior.environment.hasKey(optimizerKey))
760                 rp.inferior.environment.set(optimizerKey, "1");
761         }
762     }
763 
764     if (!debuggerSettings()->autoEnrichParameters.value()) {
765         const QString sysroot = rp.sysRoot.toString();
766         if (rp.debugInfoLocation.isEmpty())
767             rp.debugInfoLocation = sysroot + "/usr/lib/debug";
768         if (rp.debugSourceLocation.isEmpty()) {
769             QString base = sysroot + "/usr/src/debug/";
770             rp.debugSourceLocation.append(base + "qt5base/src/corelib");
771             rp.debugSourceLocation.append(base + "qt5base/src/gui");
772             rp.debugSourceLocation.append(base + "qt5base/src/network");
773         }
774     }
775 
776     if (rp.isQmlDebugging) {
777         QmlDebug::QmlDebugServicesPreset service;
778         if (rp.isCppDebugging()) {
779             if (rp.nativeMixedEnabled) {
780                 service = QmlDebug::QmlNativeDebuggerServices;
781             } else {
782                 service = QmlDebug::QmlDebuggerServices;
783             }
784         } else {
785             service = QmlDebug::QmlDebuggerServices;
786         }
787         if (rp.startMode != AttachToLocalProcess && rp.startMode != AttachToCrashedProcess) {
788             QString qmlarg = rp.isCppDebugging() && rp.nativeMixedEnabled
789                     ? QmlDebug::qmlDebugNativeArguments(service, false)
790                     : QmlDebug::qmlDebugTcpArguments(service, rp.qmlServer);
791             ProcessArgs::addArg(&rp.inferior.commandLineArguments, qmlarg);
792         }
793     }
794 
795     if (rp.startMode == NoStartMode)
796         rp.startMode = StartInternal;
797 
798     if (breakOnMainNextTime) {
799         rp.breakOnMain = true;
800         breakOnMainNextTime = false;
801     }
802 
803     if (HostOsInfo::isWindowsHost()) {
804         ProcessArgs::SplitError perr;
805         rp.inferior.commandLineArguments =
806                 ProcessArgs::prepareArgs(rp.inferior.commandLineArguments, &perr,
807                                          HostOsInfo::hostOs(), nullptr,
808                                          &rp.inferior.workingDirectory).toWindowsArgs();
809         if (perr != ProcessArgs::SplitOk) {
810             // perr == BadQuoting is never returned on Windows
811             // FIXME? QTCREATORBUG-2809
812             reportFailure(DebuggerPlugin::tr("Debugging complex command lines "
813                                              "is currently not supported on Windows."));
814             return false;
815         }
816     }
817 
818     if (rp.isNativeMixedDebugging())
819         rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1");
820 
821     if (debuggerSettings()->forceLoggingToConsole.value())
822         rp.inferior.environment.set("QT_LOGGING_TO_CONSOLE", "1");
823 
824     return true;
825 }
826 
terminalRunner() const827 Internal::TerminalRunner *DebuggerRunTool::terminalRunner() const
828 {
829     return d->terminalRunner;
830 }
831 
cppEngineType() const832 DebuggerEngineType DebuggerRunTool::cppEngineType() const
833 {
834     return m_runParameters.cppEngineType;
835 }
836 
DebuggerRunTool(RunControl * runControl,AllowTerminal allowTerminal)837 DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerminal)
838     : RunWorker(runControl), d(new DebuggerRunToolPrivate)
839 {
840     setId("DebuggerRunTool");
841 
842     static int toolRunCount = 0;
843 
844     // Reset once all are gone.
845     if (EngineManager::engines().isEmpty())
846         toolRunCount = 0;
847 
848     d->runId = QString::number(++toolRunCount);
849 
850     runControl->setIcon(ProjectExplorer::Icons::DEBUG_START_SMALL_TOOLBAR);
851     runControl->setPromptToStop([](bool *optionalPrompt) {
852         return RunControl::showPromptToStopDialog(
853             DebuggerRunTool::tr("Close Debugging Session"),
854             DebuggerRunTool::tr("A debugging session is still in progress. "
855                                 "Terminating the session in the current"
856                                 " state can leave the target in an inconsistent state."
857                                 " Would you still like to terminate it?"),
858                 QString(), QString(), optionalPrompt);
859     });
860 
861     m_runParameters.displayName = runControl->displayName();
862 
863     if (auto symbolsAspect = runControl->aspect<SymbolFileAspect>())
864         m_runParameters.symbolFile = symbolsAspect->filePath();
865     if (auto terminalAspect = runControl->aspect<TerminalAspect>())
866         m_runParameters.useTerminal = terminalAspect->useTerminal();
867     if (auto runAsRootAspect = runControl->aspect<RunAsRootAspect>())
868         m_runParameters.runAsRoot = runAsRootAspect->value();
869 
870     Kit *kit = runControl->kit();
871     QTC_ASSERT(kit, return);
872 
873     m_runParameters.sysRoot = SysRootKitAspect::sysRoot(kit);
874     m_runParameters.macroExpander = kit->macroExpander();
875     m_runParameters.debugger = DebuggerKitAspect::runnable(kit);
876     m_runParameters.cppEngineType = DebuggerKitAspect::engineType(kit);
877 
878     if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit))
879         m_runParameters.qtPackageSourceLocation = qtVersion->qtPackageSourcePath().toString();
880 
881     if (auto aspect = runControl->aspect<DebuggerRunConfigurationAspect>()) {
882         if (!aspect->useCppDebugger())
883             m_runParameters.cppEngineType = NoEngineType;
884         m_runParameters.isQmlDebugging = aspect->useQmlDebugger();
885         m_runParameters.multiProcess = aspect->useMultiProcess();
886         m_runParameters.additionalStartupCommands = aspect->overrideStartup();
887     }
888 
889     m_runParameters.inferior = runnable();
890     // Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...)
891     m_runParameters.inferior.workingDirectory =
892             FileUtils::normalizePathName(m_runParameters.inferior.workingDirectory);
893     setUseTerminal(allowTerminal == DoAllowTerminal && m_runParameters.useTerminal);
894 
895     const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH");
896     if (!envBinary.isEmpty())
897         m_runParameters.debugger.executable = FilePath::fromString(QString::fromLocal8Bit(envBinary));
898 
899     if (Project *project = runControl->project()) {
900         m_runParameters.projectSourceDirectory = project->projectDirectory();
901         m_runParameters.projectSourceFiles = project->files(Project::SourceFiles);
902     }
903 
904     m_runParameters.toolChainAbi = ToolChainKitAspect::targetAbi(kit);
905 
906     bool ok = false;
907     const int nativeMixedOverride = qEnvironmentVariableIntValue("QTC_DEBUGGER_NATIVE_MIXED", &ok);
908     if (ok)
909         m_runParameters.nativeMixedEnabled = bool(nativeMixedOverride);
910 
911     // This will only be shown in some cases, but we don't want to access
912     // the kit at that time anymore.
913     const Tasks tasks = DebuggerKitAspect::validateDebugger(kit);
914     for (const Task &t : tasks) {
915         if (t.type != Task::Warning)
916             m_runParameters.validationErrors.append(t.description());
917     }
918 
919     RunConfiguration *runConfig = runControl->runConfiguration();
920     if (runConfig && runConfig->property("supportsDebugger").toBool()) {
921         const QString mainScript = runConfig->property("mainScript").toString();
922         const QString interpreter = runConfig->property("interpreter").toString();
923         if (!interpreter.isEmpty() && mainScript.endsWith(".py")) {
924             m_runParameters.mainScript = mainScript;
925             m_runParameters.interpreter = interpreter;
926             const QString args = runConfig->property("arguments").toString();
927             if (!args.isEmpty()) {
928                 if (!m_runParameters.inferior.commandLineArguments.isEmpty())
929                     m_runParameters.inferior.commandLineArguments.append(' ');
930                 m_runParameters.inferior.commandLineArguments.append(args);
931             }
932             m_engine = createPdbEngine();
933         }
934     }
935 }
936 
startRunControl()937 void DebuggerRunTool::startRunControl()
938 {
939     ProjectExplorerPlugin::startRunControl(runControl());
940 }
941 
addSolibSearchDir(const QString & str)942 void DebuggerRunTool::addSolibSearchDir(const QString &str)
943 {
944     QString path = str;
945     path.replace("%{sysroot}", m_runParameters.sysRoot.toString());
946     m_runParameters.solibSearchPath.append(path);
947 }
948 
~DebuggerRunTool()949 DebuggerRunTool::~DebuggerRunTool()
950 {
951     if (m_runParameters.isSnapshot && !m_runParameters.coreFile.isEmpty())
952         QFile::remove(m_runParameters.coreFile);
953 
954     delete m_engine2;
955     m_engine2 = nullptr;
956     delete m_engine;
957     m_engine = nullptr;
958 
959     delete d;
960 }
961 
showMessage(const QString & msg,int channel,int timeout)962 void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout)
963 {
964     if (channel == ConsoleOutput)
965         debuggerConsole()->printItem(ConsoleItem::DefaultType, msg);
966 
967     QTC_ASSERT(m_engine, qDebug() << msg; return);
968 
969     m_engine->showMessage(msg, channel, timeout);
970     if (m_engine2)
971         m_engine->showMessage(msg, channel, timeout);
972     switch (channel) {
973     case AppOutput:
974         appendMessage(msg, StdOutFormat);
975         break;
976     case AppError:
977         appendMessage(msg, StdErrFormat);
978         break;
979     case AppStuff:
980         appendMessage(msg, DebugFormat);
981         break;
982     default:
983         break;
984     }
985 }
986 
987 ////////////////////////////////////////////////////////////////////////
988 //
989 // Externally visible helper.
990 //
991 ////////////////////////////////////////////////////////////////////////
992 
993 // GdbServerPortGatherer
994 
DebugServerPortsGatherer(RunControl * runControl)995 DebugServerPortsGatherer::DebugServerPortsGatherer(RunControl *runControl)
996     : ChannelProvider(runControl, 2)
997 {
998     setId("DebugServerPortsGatherer");
999 }
1000 
1001 DebugServerPortsGatherer::~DebugServerPortsGatherer() = default;
1002 
gdbServer() const1003 QUrl DebugServerPortsGatherer::gdbServer() const
1004 {
1005     return channel(0);
1006 }
1007 
qmlServer() const1008 QUrl DebugServerPortsGatherer::qmlServer() const
1009 {
1010     return channel(1);
1011 }
1012 
1013 // DebugServerRunner
1014 
DebugServerRunner(RunControl * runControl,DebugServerPortsGatherer * portsGatherer)1015 DebugServerRunner::DebugServerRunner(RunControl *runControl, DebugServerPortsGatherer *portsGatherer)
1016    : SimpleTargetRunner(runControl)
1017 {
1018     setId("DebugServerRunner");
1019     const Runnable mainRunnable = runControl->runnable();
1020     addStartDependency(portsGatherer);
1021 
1022     QTC_ASSERT(portsGatherer, reportFailure(); return);
1023 
1024     setStarter([this, runControl, mainRunnable, portsGatherer] {
1025         QTC_ASSERT(portsGatherer, reportFailure(); return);
1026 
1027         Runnable debugServer;
1028         debugServer.environment = mainRunnable.environment;
1029         debugServer.workingDirectory = mainRunnable.workingDirectory;
1030 
1031         QStringList args = ProcessArgs::splitArgs(mainRunnable.commandLineArguments, OsTypeLinux);
1032 
1033         const bool isQmlDebugging = portsGatherer->useQmlServer();
1034         const bool isCppDebugging = portsGatherer->useGdbServer();
1035 
1036         if (isQmlDebugging) {
1037             args.prepend(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices,
1038                                                         portsGatherer->qmlServer()));
1039         }
1040         if (isQmlDebugging && !isCppDebugging) {
1041             debugServer.executable = mainRunnable.executable; // FIXME: Case should not happen?
1042         } else {
1043             debugServer.executable = FilePath::fromString(runControl->device()->debugServerPath());
1044             if (debugServer.executable.isEmpty())
1045                 debugServer.executable = FilePath::fromString("gdbserver");
1046             args.clear();
1047             if (debugServer.executable.toString().contains("lldb-server")) {
1048                 args.append("platform");
1049                 args.append("--listen");
1050                 args.append(QString("*:%1").arg(portsGatherer->gdbServer().port()));
1051                 args.append("--server");
1052             } else {
1053                 // Something resembling gdbserver
1054                 if (m_useMulti)
1055                     args.append("--multi");
1056                 if (m_pid.isValid())
1057                     args.append("--attach");
1058                 args.append(QString(":%1").arg(portsGatherer->gdbServer().port()));
1059                 if (m_pid.isValid())
1060                     args.append(QString::number(m_pid.pid()));
1061             }
1062         }
1063         debugServer.commandLineArguments = ProcessArgs::joinArgs(args, OsTypeLinux);
1064 
1065         doStart(debugServer, runControl->device());
1066     });
1067 }
1068 
1069 DebugServerRunner::~DebugServerRunner() = default;
1070 
setUseMulti(bool on)1071 void DebugServerRunner::setUseMulti(bool on)
1072 {
1073     m_useMulti = on;
1074 }
1075 
setAttachPid(ProcessHandle pid)1076 void DebugServerRunner::setAttachPid(ProcessHandle pid)
1077 {
1078     m_pid = pid;
1079 }
1080 
1081 } // namespace Debugger
1082