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 "debuggerengine.h"
27 
28 #include "debuggerinternalconstants.h"
29 #include "debuggeractions.h"
30 #include "debuggercore.h"
31 #include "debuggerdialogs.h"
32 #include "debuggericons.h"
33 #include "debuggerruncontrol.h"
34 #include "debuggertooltipmanager.h"
35 
36 #include "analyzer/analyzermanager.h"
37 #include "breakhandler.h"
38 #include "disassembleragent.h"
39 #include "localsandexpressionswindow.h"
40 #include "logwindow.h"
41 #include "debuggermainwindow.h"
42 #include "enginemanager.h"
43 #include "memoryagent.h"
44 #include "moduleshandler.h"
45 #include "registerhandler.h"
46 #include "peripheralregisterhandler.h"
47 #include "sourcefileshandler.h"
48 #include "sourceutils.h"
49 #include "stackhandler.h"
50 #include "stackwindow.h"
51 #include "terminal.h"
52 #include "threadshandler.h"
53 #include "watchhandler.h"
54 #include "watchutils.h"
55 #include "watchwindow.h"
56 #include "debugger/shared/peutils.h"
57 #include "console/console.h"
58 
59 #include <coreplugin/actionmanager/actionmanager.h>
60 #include <coreplugin/editormanager/editormanager.h>
61 #include <coreplugin/editormanager/ieditor.h>
62 #include <coreplugin/icore.h>
63 #include <coreplugin/idocument.h>
64 #include <coreplugin/messagebox.h>
65 #include <coreplugin/modemanager.h>
66 #include <coreplugin/progressmanager/progressmanager.h>
67 #include <coreplugin/progressmanager/futureprogress.h>
68 
69 #include <projectexplorer/projectexplorer.h>
70 #include <projectexplorer/taskhub.h>
71 
72 #include <texteditor/texteditor.h>
73 #include <texteditor/texteditorsettings.h>
74 #include <texteditor/fontsettings.h>
75 
76 #include <utils/basetreeview.h>
77 #include <utils/macroexpander.h>
78 #include <utils/processhandle.h>
79 #include <utils/qtcassert.h>
80 #include <utils/qtcprocess.h>
81 #include <utils/styledbar.h>
82 #include <utils/utilsicons.h>
83 
84 #include <QApplication>
85 #include <QComboBox>
86 #include <QDebug>
87 #include <QDir>
88 #include <QDockWidget>
89 #include <QFileInfo>
90 #include <QHeaderView>
91 #include <QTextBlock>
92 #include <QTimer>
93 #include <QToolButton>
94 
95 #include <QJsonArray>
96 #include <QJsonDocument>
97 #include <QJsonObject>
98 #include <QJsonValue>
99 
100 using namespace Core;
101 using namespace Debugger::Internal;
102 using namespace ProjectExplorer;
103 using namespace TextEditor;
104 using namespace Utils;
105 
106 //#define WITH_BENCHMARK
107 #ifdef WITH_BENCHMARK
108 #include <valgrind/callgrind.h>
109 #endif
110 
111 namespace Debugger {
112 
operator <<(QDebug d,DebuggerState state)113 QDebug operator<<(QDebug d, DebuggerState state)
114 {
115     //return d << DebuggerEngine::stateName(state) << '(' << int(state) << ')';
116     return d << DebuggerEngine::stateName(state);
117 }
118 
operator <<(QDebug str,const DebuggerRunParameters & sp)119 QDebug operator<<(QDebug str, const DebuggerRunParameters &sp)
120 {
121     QDebug nospace = str.nospace();
122     nospace << "executable=" << sp.inferior.executable
123             << " coreFile=" << sp.coreFile
124             << " processArgs=" << sp.inferior.commandLineArguments
125             << " inferior environment=<" << sp.inferior.environment.size() << " variables>"
126             << " debugger environment=<" << sp.debugger.environment.size() << " variables>"
127             << " workingDir=" << sp.inferior.workingDirectory
128             << " attachPID=" << sp.attachPID.pid()
129             << " remoteChannel=" << sp.remoteChannel
130             << " abi=" << sp.toolChainAbi.toString() << '\n';
131     return str;
132 }
133 
134 namespace Internal {
135 
debuggerActionsEnabledHelper(DebuggerState state)136 static bool debuggerActionsEnabledHelper(DebuggerState state)
137 {
138     switch (state) {
139     case InferiorRunOk:
140     case InferiorUnrunnable:
141     case InferiorStopOk:
142         return true;
143     case InferiorStopRequested:
144     case InferiorRunRequested:
145     case InferiorRunFailed:
146     case DebuggerNotReady:
147     case EngineSetupRequested:
148     case EngineSetupFailed:
149     case EngineRunRequested:
150     case EngineRunFailed:
151     case InferiorStopFailed:
152     case InferiorShutdownRequested:
153     case InferiorShutdownFinished:
154     case EngineShutdownRequested:
155     case EngineShutdownFinished:
156     case DebuggerFinished:
157         return false;
158     }
159     return false;
160 }
161 
Location(const StackFrame & frame,bool marker)162 Location::Location(const StackFrame &frame, bool marker)
163 {
164     m_fileName = Utils::FilePath::fromString(frame.file);
165     m_lineNumber = frame.line;
166     m_needsMarker = marker;
167     m_functionName = frame.function;
168     m_hasDebugInfo = frame.isUsable();
169     m_address = frame.address;
170     m_from = frame.module;
171 }
172 
173 
LocationMark(DebuggerEngine * engine,const FilePath & file,int line)174 LocationMark::LocationMark(DebuggerEngine *engine, const FilePath &file, int line)
175     : TextMark(file, line, Constants::TEXT_MARK_CATEGORY_LOCATION), m_engine(engine)
176 {
177     setPriority(TextMark::HighPriority);
178     updateIcon();
179 }
180 
updateIcon()181 void LocationMark::updateIcon()
182 {
183     const Icon *icon = &Icons::WATCHPOINT;
184     if (m_engine && EngineManager::currentEngine() == m_engine)
185         icon = m_engine->isReverseDebugging() ? &Icons::REVERSE_LOCATION : &Icons::LOCATION;
186     setIcon(icon->icon());
187     updateMarker();
188 }
189 
isDraggable() const190 bool LocationMark::isDraggable() const
191 {
192     return m_engine && m_engine->hasCapability(JumpToLineCapability);
193 }
194 
dragToLine(int line)195 void LocationMark::dragToLine(int line)
196 {
197     if (m_engine) {
198         if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
199             ContextData location = getLocationContext(textEditor->textDocument(), line);
200             if (location.isValid())
201                 m_engine->executeJumpToLine(location);
202         }
203     }
204 }
205 
206 //////////////////////////////////////////////////////////////////////
207 //
208 // MemoryAgentSet
209 //
210 //////////////////////////////////////////////////////////////////////
211 
212 class MemoryAgentSet
213 {
214 public:
~MemoryAgentSet()215     ~MemoryAgentSet()
216     {
217         qDeleteAll(m_agents);
218         m_agents.clear();
219     }
220 
221     // Called by engine to create a new view.
createBinEditor(const MemoryViewSetupData & data,DebuggerEngine * engine)222     void createBinEditor(const MemoryViewSetupData &data, DebuggerEngine *engine)
223     {
224         auto agent = new MemoryAgent(data, engine);
225         if (agent->isUsable()) {
226             m_agents.push_back(agent);
227         } else {
228             delete agent;
229             AsynchronousMessageBox::warning(
230                         DebuggerEngine::tr("No Memory Viewer Available"),
231                         DebuggerEngine::tr("The memory contents cannot be shown as no viewer plugin "
232                                            "for binary data has been loaded."));
233         }
234     }
235 
236     // On stack frame completed and on request.
updateContents()237     void updateContents()
238     {
239         for (MemoryAgent *agent : m_agents) {
240             if (agent)
241                 agent->updateContents();
242         }
243     }
244 
handleDebuggerFinished()245     void handleDebuggerFinished()
246     {
247         for (MemoryAgent *agent : m_agents) {
248             if (agent)
249                 agent->setFinished(); // Prevent triggering updates, etc.
250         }
251     }
252 
253 private:
254     std::vector<MemoryAgent *> m_agents;
255 };
256 
257 
258 
259 //////////////////////////////////////////////////////////////////////
260 //
261 // DebuggerEnginePrivate
262 //
263 //////////////////////////////////////////////////////////////////////
264 
265 class DebuggerEnginePrivate : public QObject
266 {
267     Q_OBJECT
268 
269 public:
DebuggerEnginePrivate(DebuggerEngine * engine)270     DebuggerEnginePrivate(DebuggerEngine *engine)
271         : m_engine(engine),
272           m_breakHandler(engine),
273           m_modulesHandler(engine),
274           m_registerHandler(engine),
275           m_peripheralRegisterHandler(engine),
276           m_sourceFilesHandler(engine),
277           m_stackHandler(engine),
278           m_threadsHandler(engine),
279           m_watchHandler(engine),
280           m_disassemblerAgent(engine),
281           m_toolTipManager(engine)
282     {
283         m_debuggerName = DebuggerEngine::tr("Debugger");
284 
285         m_logWindow = new LogWindow(m_engine); // Needed before start()
286         m_logWindow->setObjectName("Debugger.Dock.Output");
287 
288         connect(&debuggerSettings()->enableReverseDebugging, &BaseAspect::changed, this, [this] {
289             updateState();
290             if (m_companionEngine)
291                 m_companionEngine->d->updateState();
292         });
293         static int contextCount = 0;
294         m_context = Context(Id("Debugger.Engine.").withSuffix(++contextCount));
295 
296         ActionManager::registerAction(&m_continueAction, Constants::CONTINUE, m_context);
297         ActionManager::registerAction(&m_exitAction, Constants::STOP, m_context);
298         ActionManager::registerAction(&m_interruptAction, Constants::INTERRUPT, m_context);
299         ActionManager::registerAction(&m_abortAction, Constants::ABORT, m_context);
300         ActionManager::registerAction(&m_stepOverAction, Constants::NEXT, m_context);
301         ActionManager::registerAction(&m_stepIntoAction, Constants::STEP, m_context);
302         ActionManager::registerAction(&m_stepOutAction, Constants::STEPOUT, m_context);
303         ActionManager::registerAction(&m_runToLineAction, Constants::RUNTOLINE, m_context);
304         ActionManager::registerAction(&m_runToSelectedFunctionAction, Constants::RUNTOSELECTEDFUNCTION, m_context);
305         ActionManager::registerAction(&m_jumpToLineAction, Constants::JUMPTOLINE, m_context);
306         ActionManager::registerAction(&m_returnFromFunctionAction, Constants::RETURNFROMFUNCTION, m_context);
307         ActionManager::registerAction(&m_detachAction, Constants::DETACH, m_context);
308         ActionManager::registerAction(&m_resetAction, Constants::RESET, m_context);
309         ActionManager::registerAction(&m_watchAction, Constants::WATCH, m_context);
310         ActionManager::registerAction(&m_operateByInstructionAction, Constants::OPERATE_BY_INSTRUCTION, m_context);
311         ActionManager::registerAction(&m_openMemoryEditorAction, Constants::OPEN_MEMORY_EDITOR, m_context);
312         ActionManager::registerAction(&m_frameUpAction, Constants::FRAME_UP, m_context);
313         ActionManager::registerAction(&m_frameDownAction, Constants::FRAME_DOWN, m_context);
314     }
315 
~DebuggerEnginePrivate()316     ~DebuggerEnginePrivate()
317     {
318         ActionManager::unregisterAction(&m_continueAction, Constants::CONTINUE);
319         ActionManager::unregisterAction(&m_exitAction, Constants::STOP);
320         ActionManager::unregisterAction(&m_interruptAction, Constants::INTERRUPT);
321         ActionManager::unregisterAction(&m_abortAction, Constants::ABORT);
322         ActionManager::unregisterAction(&m_stepOverAction, Constants::NEXT);
323         ActionManager::unregisterAction(&m_stepIntoAction, Constants::STEP);
324         ActionManager::unregisterAction(&m_stepOutAction, Constants::STEPOUT);
325         ActionManager::unregisterAction(&m_runToLineAction, Constants::RUNTOLINE);
326         ActionManager::unregisterAction(&m_runToSelectedFunctionAction, Constants::RUNTOSELECTEDFUNCTION);
327         ActionManager::unregisterAction(&m_jumpToLineAction, Constants::JUMPTOLINE);
328         ActionManager::unregisterAction(&m_returnFromFunctionAction, Constants::RETURNFROMFUNCTION);
329         ActionManager::unregisterAction(&m_detachAction, Constants::DETACH);
330         ActionManager::unregisterAction(&m_resetAction, Constants::RESET);
331         ActionManager::unregisterAction(&m_watchAction, Constants::WATCH);
332         ActionManager::unregisterAction(&m_operateByInstructionAction, Constants::OPERATE_BY_INSTRUCTION);
333         ActionManager::unregisterAction(&m_openMemoryEditorAction, Constants::OPEN_MEMORY_EDITOR);
334         ActionManager::unregisterAction(&m_frameUpAction, Constants::FRAME_UP);
335         ActionManager::unregisterAction(&m_frameDownAction, Constants::FRAME_DOWN);
336         destroyPerspective();
337 
338         delete m_logWindow;
339         delete m_breakWindow;
340         delete m_returnWindow;
341         delete m_localsWindow;
342         delete m_watchersWindow;
343         delete m_inspectorWindow;
344         delete m_registerWindow;
345         delete m_peripheralRegisterWindow;
346         delete m_modulesWindow;
347         delete m_sourceFilesWindow;
348         delete m_stackWindow;
349         delete m_threadsWindow;
350 
351         delete m_breakView;
352         delete m_returnView;
353         delete m_localsView;
354         delete m_watchersView;
355         delete m_inspectorView;
356         delete m_registerView;
357         delete m_peripheralRegisterView;
358         delete m_modulesView;
359         delete m_sourceFilesView;
360         delete m_stackView;
361         delete m_threadsView;
362     }
363 
updateActionToolTips()364     void updateActionToolTips()
365     {
366         // update tooltips that are visible on the button in the mode selector
367         const QString displayName = m_engine->displayName();
368         m_continueAction.setToolTip(tr("Continue %1").arg(displayName));
369         m_interruptAction.setToolTip(tr("Interrupt %1").arg(displayName));
370     }
371 
372     void setupViews();
373 
destroyPerspective()374     void destroyPerspective()
375     {
376         if (!m_perspective)
377             return;
378 
379         Perspective *perspective = m_perspective;
380         m_perspective = nullptr;
381 
382         EngineManager::unregisterEngine(m_engine);
383 
384         // This triggers activity in the EngineManager which
385         // recognizes the rampdown by the m_perpective == nullptr above.
386         perspective->destroy();
387 
388         // disconnect the follow font size connection
389         TextEditorSettings::instance()->disconnect(this);
390 
391         delete perspective;
392     }
393 
updateReturnViewHeader(int section,int,int newSize)394     void updateReturnViewHeader(int section, int, int newSize)
395     {
396         if (m_perspective && m_returnView && m_returnView->header())
397             m_returnView->header()->resizeSection(section, newSize);
398     }
399 
doShutdownEngine()400     void doShutdownEngine()
401     {
402         m_engine->setState(EngineShutdownRequested);
403         m_engine->startDying();
404         m_engine->showMessage("CALL: SHUTDOWN ENGINE");
405         m_engine->shutdownEngine();
406     }
407 
doShutdownInferior()408     void doShutdownInferior()
409     {
410         m_engine->setState(InferiorShutdownRequested);
411         //QTC_ASSERT(isMasterEngine(), return);
412         resetLocation();
413         m_engine->showMessage("CALL: SHUTDOWN INFERIOR");
414         m_engine->shutdownInferior();
415     }
416 
doFinishDebugger()417     void doFinishDebugger()
418     {
419         QTC_ASSERT(m_state == EngineShutdownFinished, qDebug() << m_state);
420         resetLocation();
421         m_progress.setProgressValue(1000);
422         m_progress.reportFinished();
423         m_modulesHandler.removeAll();
424         m_stackHandler.removeAll();
425         m_threadsHandler.removeAll();
426         m_watchHandler.cleanup();
427         m_engine->showMessage(tr("Debugger finished."), StatusBar);
428         m_engine->setState(DebuggerFinished); // Also destroys views.
429         if (debuggerSettings()->switchModeOnExit.value())
430             EngineManager::deactivateDebugMode();
431     }
432 
scheduleResetLocation()433     void scheduleResetLocation()
434     {
435         m_stackHandler.scheduleResetLocation();
436         m_watchHandler.scheduleResetLocation();
437         m_disassemblerAgent.scheduleResetLocation();
438         m_locationTimer.setSingleShot(true);
439         m_locationTimer.start(80);
440     }
441 
resetLocation()442     void resetLocation()
443     {
444         m_lookupRequests.clear();
445         m_locationTimer.stop();
446         m_locationMark.reset();
447         m_stackHandler.resetLocation();
448         m_disassemblerAgent.resetLocation();
449         m_toolTipManager.resetLocation();
450         m_breakHandler.resetLocation();
451     }
452 
453 public:
454     void setInitialActionStates();
455     void setBusyCursor(bool on);
456     void cleanupViews();
457     void updateState();
458     void updateReverseActions();
459 
460     DebuggerEngine *m_engine = nullptr; // Not owned.
461     QString m_runId;
462     QString m_debuggerName;
463     QPointer<Perspective> m_perspective;
464     DebuggerRunParameters m_runParameters;
465     IDevice::ConstPtr m_device;
466 
467     QPointer<DebuggerEngine> m_companionEngine;
468     bool m_isPrimaryEngine = true;
469 
470     // The current state.
471     DebuggerState m_state = DebuggerNotReady;
472 
473 //    Terminal m_terminal;
474     ProcessHandle m_inferiorPid;
475 
476     BreakHandler m_breakHandler;
477     ModulesHandler m_modulesHandler;
478     RegisterHandler m_registerHandler;
479     PeripheralRegisterHandler m_peripheralRegisterHandler;
480     SourceFilesHandler m_sourceFilesHandler;
481     StackHandler m_stackHandler;
482     ThreadsHandler m_threadsHandler;
483     WatchHandler m_watchHandler;
484     QFutureInterface<void> m_progress;
485 
486     DisassemblerAgent m_disassemblerAgent;
487     MemoryAgentSet m_memoryAgents;
488     QScopedPointer<LocationMark> m_locationMark;
489     QTimer m_locationTimer;
490 
491     QString m_qtNamespace;
492 
493     // Safety net to avoid infinite lookups.
494     QSet<QString> m_lookupRequests; // FIXME: Integrate properly.
495     QPointer<QWidget> m_alertBox;
496 
497     QPointer<BaseTreeView> m_breakView;
498     QPointer<BaseTreeView> m_returnView;
499     QPointer<BaseTreeView> m_localsView;
500     QPointer<BaseTreeView> m_watchersView;
501     QPointer<WatchTreeView> m_inspectorView;
502     QPointer<BaseTreeView> m_registerView;
503     QPointer<BaseTreeView> m_peripheralRegisterView;
504     QPointer<BaseTreeView> m_modulesView;
505     QPointer<BaseTreeView> m_sourceFilesView;
506     QPointer<BaseTreeView> m_stackView;
507     QPointer<BaseTreeView> m_threadsView;
508     QPointer<QWidget> m_breakWindow;
509     QPointer<QWidget> m_returnWindow;
510     QPointer<QWidget> m_localsWindow;
511     QPointer<QWidget> m_watchersWindow;
512     QPointer<QWidget> m_inspectorWindow;
513     QPointer<QWidget> m_registerWindow;
514     QPointer<QWidget> m_peripheralRegisterWindow;
515     QPointer<QWidget> m_modulesWindow;
516     QPointer<QWidget> m_sourceFilesWindow;
517     QPointer<QWidget> m_stackWindow;
518     QPointer<QWidget> m_threadsWindow;
519     QPointer<LogWindow> m_logWindow;
520     QPointer<LocalsAndInspectorWindow> m_localsAndInspectorWindow;
521 
522     QPointer<QLabel> m_threadLabel;
523 
524     bool m_busy = false;
525     bool m_isDying = false;
526 
527     QAction m_detachAction;
528     OptionalAction m_continueAction{tr("Continue")};
529     QAction m_exitAction{tr("Stop Debugger")}; // On application output button if "Stop" is possible
530     OptionalAction m_interruptAction{tr("Interrupt")}; // On the fat debug button if "Pause" is possible
531     QAction m_abortAction{tr("Abort Debugging")};
532     QAction m_stepIntoAction{tr("Step Into")};
533     QAction m_stepOutAction{tr("Step Out")};
534     QAction m_runToLineAction{tr("Run to Line")}; // In the debug menu
535     QAction m_runToSelectedFunctionAction{tr("Run to Selected Function")};
536     QAction m_jumpToLineAction{tr("Jump to Line")};
537     QAction m_frameUpAction{QCoreApplication::translate("Debugger::Internal::DebuggerPluginPrivate",
538                                                         "Move to Calling Frame")};
539     QAction m_frameDownAction{QCoreApplication::translate("Debugger::Internal::DebuggerPluginPrivate",
540                                                           "Move to Called Frame")};
541     QAction m_openMemoryEditorAction{QCoreApplication::translate("Debugger::Internal::DebuggerPluginPrivate",
542                                                                  "Memory...")};
543     // In the Debug menu.
544     QAction m_returnFromFunctionAction{tr("Immediately Return From Inner Function")};
545     QAction m_stepOverAction{tr("Step Over")};
546     QAction m_watchAction{tr("Add Expression Evaluator")};
547     QAction m_breakAction{tr("Toggle Breakpoint")};
548     QAction m_resetAction{tr("Restart Debugging")};
549     OptionalAction m_operateByInstructionAction{tr("Operate by Instruction")};
550     QAction m_recordForReverseOperationAction{tr("Record Information to Allow Reversal of Direction")};
551     OptionalAction m_operateInReverseDirectionAction{tr("Reverse Direction")};
552     OptionalAction m_snapshotAction{tr("Take Snapshot of Process State")};
553 
554     QPointer<TerminalRunner> m_terminalRunner;
555     DebuggerToolTipManager m_toolTipManager;
556     Context m_context;
557 };
558 
setupViews()559 void DebuggerEnginePrivate::setupViews()
560 {
561     const DebuggerRunParameters &rp = m_runParameters;
562     const QString engineId = EngineManager::registerEngine(m_engine);
563 
564     QTC_CHECK(!m_perspective);
565 
566     const QString perspectiveId = "Debugger.Perspective." + m_runId + '.' + m_debuggerName;
567     const QString settingsId = "Debugger.Perspective." + m_debuggerName;
568 
569     m_perspective = new Perspective(perspectiveId,
570                                     m_engine->displayName(),
571                                     Debugger::Constants::PRESET_PERSPECTIVE_ID,
572                                     settingsId);
573 
574     m_progress.setProgressRange(0, 1000);
575     FutureProgress *fp = ProgressManager::addTask(m_progress.future(),
576         tr("Launching Debugger"), "Debugger.Launcher");
577     connect(fp, &FutureProgress::canceled, m_engine, &DebuggerEngine::quitDebugger);
578     fp->setKeepOnFinish(FutureProgress::HideOnFinish);
579     m_progress.reportStarted();
580 
581     m_inferiorPid = rp.attachPID.isValid() ? rp.attachPID : ProcessHandle();
582 //    if (m_inferiorPid.isValid())
583 //        m_runControl->setApplicationProcessHandle(m_inferiorPid);
584 
585     m_operateByInstructionAction.setEnabled(true);
586     m_operateByInstructionAction.setVisible(m_engine->hasCapability(DisassemblerCapability));
587     m_operateByInstructionAction.setIcon(Debugger::Icons::SINGLE_INSTRUCTION_MODE.icon());
588     m_operateByInstructionAction.setCheckable(true);
589     m_operateByInstructionAction.setChecked(false);
590     m_operateByInstructionAction.setToolTip("<p>" + tr("Switches the debugger to instruction-wise "
591         "operation mode. In this mode, stepping operates on single "
592         "instructions and the source location view also shows the "
593         "disassembled instructions."));
594     m_operateByInstructionAction.setIconVisibleInMenu(false);
595     connect(&m_operateByInstructionAction, &QAction::triggered,
596             m_engine, &DebuggerEngine::operateByInstructionTriggered);
597 
598     m_frameDownAction.setEnabled(true);
599     connect(&m_frameDownAction, &QAction::triggered,
600             m_engine, &DebuggerEngine::handleFrameDown);
601 
602     m_frameUpAction.setEnabled(true);
603     connect(&m_frameUpAction, &QAction::triggered,
604             m_engine, &DebuggerEngine::handleFrameUp);
605 
606     m_openMemoryEditorAction.setEnabled(true);
607     m_openMemoryEditorAction.setVisible(m_engine->hasCapability(ShowMemoryCapability));
608     connect(&m_openMemoryEditorAction, &QAction::triggered,
609             m_engine, &DebuggerEngine::openMemoryEditor);
610 
611     QTC_ASSERT(m_state == DebuggerNotReady || m_state == DebuggerFinished, qDebug() << m_state);
612     m_progress.setProgressValue(200);
613 
614 //    m_terminal.setup();
615 //    if (m_terminal.isUsable()) {
616 //        connect(&m_terminal, &Terminal::stdOutReady, [this](const QString &msg) {
617 //            m_engine->showMessage(msg, Utils::StdOutFormatSameLine);
618 //        });
619 //        connect(&m_terminal, &Terminal::stdErrReady, [this](const QString &msg) {
620 //            m_engine->showMessage(msg, Utils::StdErrFormatSameLine);
621 //        });
622 //        connect(&m_terminal, &Terminal::error, [this](const QString &msg) {
623 //            m_engine->showMessage(msg, Utils::ErrorMessageFormat);
624 //        });
625 //    }
626 
627     connect(&m_locationTimer, &QTimer::timeout,
628             this, &DebuggerEnginePrivate::resetLocation);
629 
630     QSettings *settings = ICore::settings();
631 
632     m_modulesView = new BaseTreeView;
633     m_modulesView->setModel(m_modulesHandler.model());
634     m_modulesView->setSortingEnabled(true);
635     m_modulesView->setSettings(settings, "Debugger.ModulesView");
636     m_modulesView->enableColumnHiding();
637     connect(m_modulesView, &BaseTreeView::aboutToShow,
638             m_engine, &DebuggerEngine::reloadModules,
639             Qt::QueuedConnection);
640     m_modulesWindow = addSearch(m_modulesView);
641     m_modulesWindow->setObjectName("Debugger.Dock.Modules." + engineId);
642     m_modulesWindow->setWindowTitle(tr("&Modules"));
643 
644     m_registerView = new BaseTreeView;
645     m_registerView->setModel(m_registerHandler.model());
646     m_registerView->setRootIsDecorated(true);
647     m_registerView->setSettings(settings, "Debugger.RegisterView");
648     m_registerView->enableColumnHiding();
649     connect(m_registerView, &BaseTreeView::aboutToShow,
650             m_engine, &DebuggerEngine::reloadRegisters,
651             Qt::QueuedConnection);
652     m_registerWindow = addSearch(m_registerView);
653     m_registerWindow->setObjectName("Debugger.Dock.Register." + engineId);
654     m_registerWindow->setWindowTitle(tr("Reg&isters"));
655 
656     m_peripheralRegisterView = new BaseTreeView;
657     m_peripheralRegisterView->setModel(m_peripheralRegisterHandler.model());
658     m_peripheralRegisterView->setRootIsDecorated(true);
659     m_peripheralRegisterView->setSettings(settings, "Debugger.PeripheralRegisterView");
660     m_peripheralRegisterView->enableColumnHiding();
661     connect(m_peripheralRegisterView, &BaseTreeView::aboutToShow,
662             m_engine, &DebuggerEngine::reloadPeripheralRegisters,
663             Qt::QueuedConnection);
664     m_peripheralRegisterWindow = addSearch(m_peripheralRegisterView);
665     m_peripheralRegisterWindow->setObjectName("Debugger.Dock.PeripheralRegister." + engineId);
666     m_peripheralRegisterWindow->setWindowTitle(tr("Peripheral Reg&isters"));
667 
668     m_stackView = new StackTreeView;
669     m_stackView->setModel(m_stackHandler.model());
670     m_stackView->setSettings(settings, "Debugger.StackView");
671     m_stackView->setIconSize(QSize(10, 10));
672     m_stackView->enableColumnHiding();
673     m_stackWindow = addSearch(m_stackView);
674     m_stackWindow->setObjectName("Debugger.Dock.Stack." + engineId);
675     m_stackWindow->setWindowTitle(tr("&Stack"));
676 
677     m_sourceFilesView = new BaseTreeView;
678     m_sourceFilesView->setModel(m_sourceFilesHandler.model());
679     m_sourceFilesView->setSortingEnabled(true);
680     m_sourceFilesView->setSettings(settings, "Debugger.SourceFilesView");
681     m_sourceFilesView->enableColumnHiding();
682     connect(m_sourceFilesView, &BaseTreeView::aboutToShow,
683             m_engine, &DebuggerEngine::reloadSourceFiles,
684             Qt::QueuedConnection);
685     m_sourceFilesWindow = addSearch(m_sourceFilesView);
686     m_sourceFilesWindow->setObjectName("Debugger.Dock.SourceFiles." + engineId);
687     m_sourceFilesWindow->setWindowTitle(tr("Source Files"));
688 
689     m_threadsView = new BaseTreeView;
690     m_threadsView->setModel(m_threadsHandler.model());
691     m_threadsView->setSortingEnabled(true);
692     m_threadsView->setSettings(settings, "Debugger.ThreadsView");
693     m_threadsView->setIconSize(QSize(10, 10));
694     m_threadsView->setSpanColumn(ThreadData::FunctionColumn);
695     m_threadsView->enableColumnHiding();
696     m_threadsWindow = addSearch(m_threadsView);
697     m_threadsWindow->setObjectName("Debugger.Dock.Threads." + engineId);
698     m_threadsWindow->setWindowTitle(tr("&Threads"));
699 
700     m_returnView = new WatchTreeView{ReturnType};
701     m_returnView->setModel(m_watchHandler.model());
702     m_returnWindow = addSearch(m_returnView);
703     m_returnWindow->setObjectName("CppDebugReturn");
704     m_returnWindow->setWindowTitle(tr("Locals"));
705     m_returnWindow->setVisible(false);
706 
707     m_localsView = new WatchTreeView{LocalsType};
708     m_localsView->setModel(m_watchHandler.model());
709     m_localsView->setSettings(settings, "Debugger.LocalsView");
710     m_localsWindow = addSearch(m_localsView);
711     m_localsWindow->setObjectName("Debugger.Dock.Locals." + engineId);
712     m_localsWindow->setWindowTitle(tr("Locals"));
713 
714     m_inspectorView = new WatchTreeView{InspectType};
715     m_inspectorView->setModel(m_watchHandler.model());
716     m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view.
717     m_inspectorWindow = addSearch(m_inspectorView);
718     m_inspectorWindow->setObjectName("Debugger.Dock.Inspector." + engineId);
719     m_inspectorWindow->setWindowTitle(tr("Locals"));
720 
721     m_watchersView = new WatchTreeView{WatchersType};
722     m_watchersView->setModel(m_watchHandler.model());
723     m_watchersView->setSettings(settings, "Debugger.WatchersView");
724     m_watchersWindow = addSearch(m_watchersView);
725     m_watchersWindow->setObjectName("Debugger.Dock.Watchers." + engineId);
726     m_watchersWindow->setWindowTitle(tr("&Expressions"));
727 
728     m_localsAndInspectorWindow = new LocalsAndInspectorWindow(
729                 m_localsWindow, m_inspectorWindow, m_returnWindow);
730     m_localsAndInspectorWindow->setObjectName("Debugger.Dock.LocalsAndInspector." + engineId);
731     m_localsAndInspectorWindow->setWindowTitle(m_localsWindow->windowTitle());
732 
733     // Locals
734     connect(m_localsView->header(), &QHeaderView::sectionResized,
735             this, &DebuggerEnginePrivate::updateReturnViewHeader, Qt::QueuedConnection);
736 
737     m_breakView = new BaseTreeView;
738     m_breakView->setIconSize(QSize(10, 10));
739     m_breakView->setWindowIcon(Icons::BREAKPOINTS.icon());
740     m_breakView->setSelectionMode(QAbstractItemView::ExtendedSelection);
741     m_breakView->setSpanColumn(BreakpointFunctionColumn);
742     m_breakView->setSettings(settings, "Debugger.BreakWindow");
743     m_breakView->setModel(m_breakHandler.model());
744     m_breakView->setRootIsDecorated(true);
745     m_breakView->enableColumnHiding();
746     m_breakWindow = addSearch(m_breakView);
747     m_breakWindow->setObjectName("Debugger.Dock.Break." + engineId);
748     m_breakWindow->setWindowTitle(tr("&Breakpoints"));
749 
750     m_perspective->useSubPerspectiveSwitcher(EngineManager::engineChooser());
751 
752     m_perspective->addToolBarAction(&m_continueAction);
753     m_perspective->addToolBarAction(&m_interruptAction);
754 
755     m_perspective->addToolBarAction(&m_exitAction);
756     m_perspective->addToolBarAction(&m_stepOverAction);
757     m_perspective->addToolBarAction(&m_stepIntoAction);
758     m_perspective->addToolBarAction(&m_stepOutAction);
759     m_perspective->addToolBarAction(&m_resetAction);
760     m_perspective->addToolBarAction(&m_operateByInstructionAction);
761 
762     connect(&m_detachAction, &QAction::triggered, m_engine, &DebuggerEngine::handleExecDetach);
763 
764     m_continueAction.setIcon(Icons::DEBUG_CONTINUE_SMALL_TOOLBAR.icon());
765     connect(&m_continueAction, &QAction::triggered,
766             m_engine, &DebuggerEngine::handleExecContinue);
767 
768     m_exitAction.setIcon(Icons::DEBUG_EXIT_SMALL_TOOLBAR.icon());
769     connect(&m_exitAction, &QAction::triggered,
770             m_engine, &DebuggerEngine::requestRunControlStop);
771 
772     m_interruptAction.setIcon(Icons::DEBUG_INTERRUPT_SMALL_TOOLBAR.icon());
773     connect(&m_interruptAction, &QAction::triggered,
774             m_engine, &DebuggerEngine::handleExecInterrupt);
775 
776     m_abortAction.setToolTip(tr("Aborts debugging and resets the debugger to the initial state."));
777     connect(&m_abortAction, &QAction::triggered,
778             m_engine, &DebuggerEngine::abortDebugger);
779 
780     m_resetAction.setToolTip(tr("Restarts the debugging session."));
781     m_resetAction.setIcon(Icons::RESTART_TOOLBAR.icon());
782     connect(&m_resetAction, &QAction::triggered,
783             m_engine, &DebuggerEngine::handleReset);
784 
785     m_stepOverAction.setIcon(Icons::STEP_OVER_TOOLBAR.icon());
786     connect(&m_stepOverAction, &QAction::triggered,
787             m_engine, &DebuggerEngine::handleExecStepOver);
788 
789     m_stepIntoAction.setIcon(Icons::STEP_INTO_TOOLBAR.icon());
790     connect(&m_stepIntoAction, &QAction::triggered,
791             m_engine, &DebuggerEngine::handleExecStepIn);
792 
793     m_stepOutAction.setIcon(Icons::STEP_OUT_TOOLBAR.icon());
794     connect(&m_stepOutAction, &QAction::triggered,
795             m_engine, &DebuggerEngine::handleExecStepOut);
796 
797     connect(&m_runToLineAction, &QAction::triggered,
798             m_engine, &DebuggerEngine::handleExecRunToLine);
799 
800     connect(&m_runToSelectedFunctionAction, &QAction::triggered,
801             m_engine, &DebuggerEngine::handleExecRunToSelectedFunction);
802 
803     connect(&m_returnFromFunctionAction, &QAction::triggered,
804             m_engine, &DebuggerEngine::handleExecReturn);
805 
806     connect(&m_jumpToLineAction, &QAction::triggered,
807             m_engine, &DebuggerEngine::handleExecJumpToLine);
808 
809     connect(&m_watchAction, &QAction::triggered,
810             m_engine, &DebuggerEngine::handleAddToWatchWindow);
811 
812     m_perspective->addToolBarAction(&m_recordForReverseOperationAction);
813     connect(&m_recordForReverseOperationAction, &QAction::triggered,
814             m_engine, &DebuggerEngine::handleRecordReverse);
815 
816     m_perspective->addToolBarAction(&m_operateInReverseDirectionAction);
817     connect(&m_operateInReverseDirectionAction, &QAction::triggered,
818             m_engine, &DebuggerEngine::handleReverseDirection);
819 
820     m_perspective->addToolBarAction(&m_snapshotAction);
821     connect(&m_snapshotAction, &QAction::triggered,
822             m_engine, &DebuggerEngine::createSnapshot);
823 
824     m_perspective->addToolbarSeparator();
825 
826     m_threadLabel = new QLabel(tr("Threads:"));
827     m_perspective->addToolBarWidget(m_threadLabel);
828     m_perspective->addToolBarWidget(m_threadsHandler.threadSwitcher());
829 
830     connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged,
831             this, [this](const FontSettings &settings) {
832         if (!debuggerSettings()->fontSizeFollowsEditor.value())
833             return;
834         const qreal size = settings.fontZoom() * settings.fontSize() / 100.;
835         QFont font = m_breakWindow->font();
836         font.setPointSizeF(size);
837         m_breakWindow->setFont(font);
838         m_logWindow->setFont(font);
839         m_localsWindow->setFont(font);
840         m_modulesWindow->setFont(font);
841         //m_consoleWindow->setFont(font);
842         m_registerWindow->setFont(font);
843         m_peripheralRegisterWindow->setFont(font);
844         m_returnWindow->setFont(font);
845         m_sourceFilesWindow->setFont(font);
846         m_stackWindow->setFont(font);
847         m_threadsWindow->setFont(font);
848         m_watchersWindow->setFont(font);
849         m_inspectorWindow->setFont(font);
850     });
851 
852     m_perspective->addWindow(m_stackWindow, Perspective::SplitVertical, nullptr);
853     m_perspective->addWindow(m_breakWindow, Perspective::SplitHorizontal, m_stackWindow);
854     m_perspective->addWindow(m_threadsWindow, Perspective::AddToTab, m_breakWindow);
855     m_perspective->addWindow(m_modulesWindow, Perspective::AddToTab, m_threadsWindow, false);
856     m_perspective->addWindow(m_sourceFilesWindow, Perspective::AddToTab, m_modulesWindow, false);
857     m_perspective->addWindow(m_localsAndInspectorWindow, Perspective::AddToTab, nullptr, true, Qt::RightDockWidgetArea);
858     m_perspective->addWindow(m_watchersWindow, Perspective::SplitVertical, m_localsAndInspectorWindow, true, Qt::RightDockWidgetArea);
859     m_perspective->addWindow(m_registerWindow, Perspective::AddToTab, m_localsAndInspectorWindow, false, Qt::RightDockWidgetArea);
860     m_perspective->addWindow(m_peripheralRegisterWindow, Perspective::AddToTab, m_localsAndInspectorWindow, false, Qt::RightDockWidgetArea);
861     m_perspective->addWindow(m_logWindow, Perspective::AddToTab, nullptr, false, Qt::TopDockWidgetArea);
862 
863     m_perspective->select();
864     m_watchHandler.loadSessionDataForEngine();
865 }
866 
867 //////////////////////////////////////////////////////////////////////
868 //
869 // DebuggerEngine
870 //
871 //////////////////////////////////////////////////////////////////////
872 
DebuggerEngine()873 DebuggerEngine::DebuggerEngine()
874   : d(new DebuggerEnginePrivate(this))
875 {
876 }
877 
~DebuggerEngine()878 DebuggerEngine::~DebuggerEngine()
879 {
880 //    EngineManager::unregisterEngine(this);
881     delete d;
882 }
883 
setDebuggerName(const QString & name)884 void DebuggerEngine::setDebuggerName(const QString &name)
885 {
886     d->m_debuggerName = name;
887     d->updateActionToolTips();
888 }
889 
debuggerName() const890 QString DebuggerEngine::debuggerName() const
891 {
892     return d->m_debuggerName;
893 }
894 
stateName(int s)895 QString DebuggerEngine::stateName(int s)
896 {
897 #    define SN(x) case x: return QLatin1String(#x);
898     switch (s) {
899         SN(DebuggerNotReady)
900         SN(EngineSetupRequested)
901         SN(EngineSetupFailed)
902         SN(EngineRunFailed)
903         SN(EngineRunRequested)
904         SN(InferiorRunRequested)
905         SN(InferiorRunOk)
906         SN(InferiorRunFailed)
907         SN(InferiorUnrunnable)
908         SN(InferiorStopRequested)
909         SN(InferiorStopOk)
910         SN(InferiorStopFailed)
911         SN(InferiorShutdownRequested)
912         SN(InferiorShutdownFinished)
913         SN(EngineShutdownRequested)
914         SN(EngineShutdownFinished)
915         SN(DebuggerFinished)
916     }
917     return QLatin1String("<unknown>");
918 #    undef SN
919 }
920 
notifyExitCode(int code)921 void DebuggerEngine::notifyExitCode(int code)
922 {
923     d->m_runParameters.exitCode = code;
924 }
925 
showStatusMessage(const QString & msg,int timeout) const926 void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
927 {
928     showMessage(msg, StatusBar, timeout);
929 }
930 
updateLocalsWindow(bool showReturn)931 void DebuggerEngine::updateLocalsWindow(bool showReturn)
932 {
933     d->m_returnWindow->setVisible(showReturn);
934     d->m_localsView->resizeColumns();
935 }
936 
isRegistersWindowVisible() const937 bool DebuggerEngine::isRegistersWindowVisible() const
938 {
939     return d->m_registerWindow->isVisible();
940 }
941 
isPeripheralRegistersWindowVisible() const942 bool DebuggerEngine::isPeripheralRegistersWindowVisible() const
943 {
944     return d->m_peripheralRegisterWindow->isVisible();
945 }
946 
isModulesWindowVisible() const947 bool DebuggerEngine::isModulesWindowVisible() const
948 {
949     return d->m_modulesWindow->isVisible();
950 }
951 
frameUp()952 void DebuggerEngine::frameUp()
953 {
954     int currentIndex = stackHandler()->currentIndex();
955     activateFrame(qMin(currentIndex + 1, stackHandler()->stackSize() - 1));
956 }
957 
frameDown()958 void DebuggerEngine::frameDown()
959 {
960     int currentIndex = stackHandler()->currentIndex();
961     activateFrame(qMax(currentIndex - 1, 0));
962 }
963 
doUpdateLocals(const UpdateParameters &)964 void DebuggerEngine::doUpdateLocals(const UpdateParameters &)
965 {
966 }
967 
modulesHandler() const968 ModulesHandler *DebuggerEngine::modulesHandler() const
969 {
970     return &d->m_modulesHandler;
971 }
972 
registerHandler() const973 RegisterHandler *DebuggerEngine::registerHandler() const
974 {
975     return &d->m_registerHandler;
976 }
977 
peripheralRegisterHandler() const978 PeripheralRegisterHandler *DebuggerEngine::peripheralRegisterHandler() const
979 {
980     return &d->m_peripheralRegisterHandler;
981 }
982 
stackHandler() const983 StackHandler *DebuggerEngine::stackHandler() const
984 {
985     return &d->m_stackHandler;
986 }
987 
threadsHandler() const988 ThreadsHandler *DebuggerEngine::threadsHandler() const
989 {
990     return &d->m_threadsHandler;
991 }
992 
watchHandler() const993 WatchHandler *DebuggerEngine::watchHandler() const
994 {
995     return &d->m_watchHandler;
996 }
997 
sourceFilesHandler() const998 SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
999 {
1000     return &d->m_sourceFilesHandler;
1001 }
1002 
breakHandler() const1003 BreakHandler *DebuggerEngine::breakHandler() const
1004 {
1005     return &d->m_breakHandler;
1006 }
1007 
logWindow() const1008 LogWindow *DebuggerEngine::logWindow() const
1009 {
1010     return d->m_logWindow;
1011 }
1012 
disassemblerAgent() const1013 DisassemblerAgent *DebuggerEngine::disassemblerAgent() const
1014 {
1015     return &d->m_disassemblerAgent;
1016 }
1017 
fetchMemory(MemoryAgent *,quint64 addr,quint64 length)1018 void DebuggerEngine::fetchMemory(MemoryAgent *, quint64 addr, quint64 length)
1019 {
1020     Q_UNUSED(addr)
1021     Q_UNUSED(length)
1022 }
1023 
changeMemory(MemoryAgent *,quint64 addr,const QByteArray & data)1024 void DebuggerEngine::changeMemory(MemoryAgent *, quint64 addr, const QByteArray &data)
1025 {
1026     Q_UNUSED(addr)
1027     Q_UNUSED(data)
1028 }
1029 
setRegisterValue(const QString & name,const QString & value)1030 void DebuggerEngine::setRegisterValue(const QString &name, const QString &value)
1031 {
1032     Q_UNUSED(name)
1033     Q_UNUSED(value)
1034 }
1035 
setPeripheralRegisterValue(quint64 address,quint64 value)1036 void DebuggerEngine::setPeripheralRegisterValue(quint64 address, quint64 value)
1037 {
1038     Q_UNUSED(address)
1039     Q_UNUSED(value)
1040 }
1041 
setRunParameters(const DebuggerRunParameters & runParameters)1042 void DebuggerEngine::setRunParameters(const DebuggerRunParameters &runParameters)
1043 {
1044     d->m_runParameters = runParameters;
1045     d->updateActionToolTips();
1046 }
1047 
setRunId(const QString & id)1048 void DebuggerEngine::setRunId(const QString &id)
1049 {
1050     d->m_runId = id;
1051 }
1052 
setRunTool(DebuggerRunTool * runTool)1053 void DebuggerEngine::setRunTool(DebuggerRunTool *runTool)
1054 {
1055     RunControl *runControl = runTool->runControl();
1056     d->m_device = runControl->device();
1057     if (!d->m_device)
1058         d->m_device = d->m_runParameters.inferior.device;
1059     d->m_terminalRunner = runTool->terminalRunner();
1060 
1061     validateRunParameters(d->m_runParameters);
1062 
1063     d->setupViews();
1064 }
1065 
start()1066 void DebuggerEngine::start()
1067 {
1068     d->m_watchHandler.resetWatchers();
1069     d->setInitialActionStates();
1070     setState(EngineSetupRequested);
1071     showMessage("CALL: SETUP ENGINE");
1072     setupEngine();
1073 }
1074 
resetLocation()1075 void DebuggerEngine::resetLocation()
1076 {
1077     // Do it after some delay to avoid flicker.
1078     d->scheduleResetLocation();
1079 }
1080 
gotoLocation(const Location & loc)1081 void DebuggerEngine::gotoLocation(const Location &loc)
1082 {
1083      d->resetLocation();
1084 
1085     if (loc.canBeDisassembled()
1086             && ((hasCapability(OperateByInstructionCapability) && operatesByInstruction())
1087                 || !loc.hasDebugInfo()) )
1088     {
1089         d->m_disassemblerAgent.setLocation(loc);
1090         return;
1091     }
1092 
1093     if (loc.fileName().isEmpty()) {
1094         showMessage("CANNOT GO TO THIS LOCATION");
1095         return;
1096     }
1097     const QString file = loc.fileName().toString();
1098     const int line = loc.lineNumber();
1099     bool newEditor = false;
1100     IEditor *editor = EditorManager::openEditor(file,
1101                                                 Id(),
1102                                                 EditorManager::IgnoreNavigationHistory
1103                                                     | EditorManager::DoNotSwitchToDesignMode
1104                                                     | EditorManager::SwitchSplitIfAlreadyVisible,
1105                                                 &newEditor);
1106     QTC_ASSERT(editor, return); // Unreadable file?
1107 
1108     editor->gotoLine(line, 0, !debuggerSettings()->stationaryEditorWhileStepping.value());
1109 
1110     if (newEditor)
1111         editor->document()->setProperty(Constants::OPENED_BY_DEBUGGER, true);
1112 
1113     if (loc.needsMarker()) {
1114         d->m_locationMark.reset(new LocationMark(this, loc.fileName(), line));
1115         d->m_locationMark->setToolTip(tr("Current debugger location of %1").arg(displayName()));
1116     }
1117 
1118     d->m_breakHandler.setLocation(loc);
1119     d->m_watchHandler.setLocation(loc);
1120 }
1121 
gotoCurrentLocation()1122 void DebuggerEngine::gotoCurrentLocation()
1123 {
1124     if (d->m_state == InferiorStopOk || d->m_state == InferiorUnrunnable) {
1125         int top = stackHandler()->currentIndex();
1126         if (top >= 0)
1127             gotoLocation(stackHandler()->currentFrame());
1128     }
1129 }
1130 
runParameters() const1131 const DebuggerRunParameters &DebuggerEngine::runParameters() const
1132 {
1133     return d->m_runParameters;
1134 }
1135 
device() const1136 IDevice::ConstPtr DebuggerEngine::device() const
1137 {
1138     return d->m_device;
1139 }
1140 
companionEngine() const1141 DebuggerEngine *DebuggerEngine::companionEngine() const
1142 {
1143     return d->m_companionEngine;
1144 }
1145 
state() const1146 DebuggerState DebuggerEngine::state() const
1147 {
1148     return d->m_state;
1149 }
1150 
abortDebugger()1151 void DebuggerEngine::abortDebugger()
1152 {
1153     resetLocation();
1154     if (!d->m_isDying) {
1155         // Be friendly the first time. This will change targetState().
1156         showMessage("ABORTING DEBUGGER. FIRST TIME.");
1157         quitDebugger();
1158     } else {
1159         // We already tried. Try harder.
1160         showMessage("ABORTING DEBUGGER. SECOND TIME.");
1161         abortDebuggerProcess();
1162         emit requestRunControlFinish();
1163     }
1164 }
1165 
updateUi(bool isCurrentEngine)1166 void DebuggerEngine::updateUi(bool isCurrentEngine)
1167 {
1168     updateState();
1169     if (isCurrentEngine) {
1170         gotoCurrentLocation();
1171     } else {
1172         d->m_locationMark.reset();
1173         d->m_disassemblerAgent.resetLocation();
1174     }
1175 }
1176 
isAllowedTransition(DebuggerState from,DebuggerState to)1177 static bool isAllowedTransition(DebuggerState from, DebuggerState to)
1178 {
1179     switch (from) {
1180     case DebuggerNotReady:
1181         return to == EngineSetupRequested;
1182 
1183     case EngineSetupRequested:
1184         return to == EngineRunRequested
1185             || to == EngineSetupFailed
1186             || to == EngineShutdownRequested;
1187     case EngineSetupFailed:
1188         // In is the engine's task to go into a proper "Shutdown"
1189         // state before calling notifyEngineSetupFailed
1190         return to == DebuggerFinished;
1191 
1192     case EngineRunRequested:
1193         return to == EngineRunFailed
1194             || to == InferiorRunRequested
1195             || to == InferiorRunOk
1196             || to == InferiorStopOk
1197             || to == InferiorUnrunnable;
1198     case EngineRunFailed:
1199         return to == EngineShutdownRequested;
1200 
1201     case InferiorRunRequested:
1202         return to == InferiorRunOk || to == InferiorRunFailed;
1203     case InferiorRunFailed:
1204         return to == InferiorStopOk;
1205     case InferiorRunOk:
1206         return to == InferiorStopRequested
1207             || to == InferiorStopOk             // A spontaneous stop.
1208             || to == InferiorShutdownFinished;  // A spontaneous exit.
1209 
1210     case InferiorStopRequested:
1211         return to == InferiorStopOk || to == InferiorStopFailed;
1212     case InferiorStopOk:
1213         return to == InferiorRunRequested || to == InferiorShutdownRequested
1214             || to == InferiorStopOk || to == InferiorShutdownFinished;
1215     case InferiorStopFailed:
1216         return to == EngineShutdownRequested;
1217 
1218     case InferiorUnrunnable:
1219         return to == InferiorShutdownRequested;
1220     case InferiorShutdownRequested:
1221         return to == InferiorShutdownFinished;
1222     case InferiorShutdownFinished:
1223         return to == EngineShutdownRequested;
1224 
1225     case EngineShutdownRequested:
1226         return to == EngineShutdownFinished;
1227     case EngineShutdownFinished:
1228         return to == DebuggerFinished;
1229 
1230     case DebuggerFinished:
1231         return to == EngineSetupRequested; // Happens on restart.
1232     }
1233 
1234     qDebug() << "UNKNOWN DEBUGGER STATE:" << from;
1235     return false;
1236 }
1237 
notifyEngineSetupFailed()1238 void DebuggerEngine::notifyEngineSetupFailed()
1239 {
1240     showMessage("NOTE: ENGINE SETUP FAILED");
1241     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
1242     setState(EngineSetupFailed);
1243     if (d->m_isPrimaryEngine) {
1244         showMessage(tr("Debugging has failed."), NormalMessageFormat);
1245         d->m_progress.setProgressValue(900);
1246         d->m_progress.reportCanceled();
1247         d->m_progress.reportFinished();
1248     }
1249 
1250     setState(DebuggerFinished);
1251 }
1252 
notifyEngineSetupOk()1253 void DebuggerEngine::notifyEngineSetupOk()
1254 {
1255 //#ifdef WITH_BENCHMARK
1256 //    CALLGRIND_START_INSTRUMENTATION;
1257 //#endif
1258     showMessage("NOTE: ENGINE SETUP OK");
1259     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
1260     setState(EngineRunRequested);
1261     showMessage("CALL: RUN ENGINE");
1262     d->m_progress.setProgressValue(300);
1263 }
1264 
notifyEngineRunOkAndInferiorUnrunnable()1265 void DebuggerEngine::notifyEngineRunOkAndInferiorUnrunnable()
1266 {
1267     showMessage("NOTE: INFERIOR UNRUNNABLE");
1268     d->m_progress.setProgressValue(1000);
1269     d->m_progress.reportFinished();
1270     QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
1271     showStatusMessage(tr("Loading finished."));
1272     setState(InferiorUnrunnable);
1273 }
1274 
notifyEngineRunFailed()1275 void DebuggerEngine::notifyEngineRunFailed()
1276 {
1277     showMessage("NOTE: ENGINE RUN FAILED");
1278     QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
1279     d->m_progress.setProgressValue(900);
1280     d->m_progress.reportCanceled();
1281     d->m_progress.reportFinished();
1282     showStatusMessage(tr("Run failed."));
1283     setState(EngineRunFailed);
1284     d->doShutdownEngine();
1285 }
1286 
notifyEngineRunAndInferiorRunOk()1287 void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
1288 {
1289     showMessage("NOTE: ENGINE RUN AND INFERIOR RUN OK");
1290     d->m_progress.setProgressValue(1000);
1291     d->m_progress.reportFinished();
1292     QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
1293     showStatusMessage(tr("Running."));
1294     setState(InferiorRunOk);
1295 }
1296 
notifyEngineRunAndInferiorStopOk()1297 void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
1298 {
1299     showMessage("NOTE: ENGINE RUN AND INFERIOR STOP OK");
1300     d->m_progress.setProgressValue(1000);
1301     d->m_progress.reportFinished();
1302     QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
1303     showStatusMessage(tr("Stopped."));
1304     setState(InferiorStopOk);
1305 }
1306 
notifyInferiorRunRequested()1307 void DebuggerEngine::notifyInferiorRunRequested()
1308 {
1309     showMessage("NOTE: INFERIOR RUN REQUESTED");
1310     QTC_ASSERT(state() == InferiorStopOk, qDebug() << this << state());
1311     showStatusMessage(tr("Run requested..."));
1312     setState(InferiorRunRequested);
1313 }
1314 
notifyInferiorRunOk()1315 void DebuggerEngine::notifyInferiorRunOk()
1316 {
1317     if (state() == InferiorRunOk) {
1318         showMessage("NOTE: INFERIOR RUN OK - REPEATED.");
1319         return;
1320     }
1321     showMessage("NOTE: INFERIOR RUN OK");
1322     showStatusMessage(tr("Running."));
1323     // Transition from StopRequested can happen in remotegdbadapter.
1324     QTC_ASSERT(state() == InferiorRunRequested
1325         || state() == InferiorStopOk
1326         || state() == InferiorStopRequested, qDebug() << this << state());
1327     setState(InferiorRunOk);
1328 }
1329 
notifyInferiorRunFailed()1330 void DebuggerEngine::notifyInferiorRunFailed()
1331 {
1332     showMessage("NOTE: INFERIOR RUN FAILED");
1333     QTC_ASSERT(state() == InferiorRunRequested, qDebug() << this << state());
1334     setState(InferiorRunFailed);
1335     setState(InferiorStopOk);
1336     if (isDying())
1337         d->doShutdownInferior();
1338 }
1339 
notifyInferiorStopOk()1340 void DebuggerEngine::notifyInferiorStopOk()
1341 {
1342     showMessage("NOTE: INFERIOR STOP OK");
1343     // Ignore spurious notifications after we are set to die.
1344     if (isDying()) {
1345         showMessage("NOTE: ... WHILE DYING. ");
1346         // Forward state to "StopOk" if needed.
1347         if (state() == InferiorStopRequested
1348                 || state() == InferiorRunRequested
1349                 || state() == InferiorRunOk) {
1350             showMessage("NOTE: ... FORWARDING TO 'STOP OK'. ");
1351             setState(InferiorStopOk);
1352         }
1353         if (state() == InferiorStopOk || state() == InferiorStopFailed)
1354             d->doShutdownInferior();
1355         showMessage("NOTE: ... IGNORING STOP MESSAGE");
1356         return;
1357     }
1358     QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
1359     showMessage(tr("Stopped."), StatusBar);
1360     setState(InferiorStopOk);
1361 }
1362 
notifyInferiorSpontaneousStop()1363 void DebuggerEngine::notifyInferiorSpontaneousStop()
1364 {
1365     showMessage("NOTE: INFERIOR SPONTANEOUS STOP");
1366     QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());
1367     d->m_perspective->select();
1368     showMessage(tr("Stopped."), StatusBar);
1369     setState(InferiorStopOk);
1370     if (debuggerSettings()->raiseOnInterrupt.value())
1371         ICore::raiseWindow(DebuggerMainWindow::instance());
1372 }
1373 
notifyInferiorStopFailed()1374 void DebuggerEngine::notifyInferiorStopFailed()
1375 {
1376     showMessage("NOTE: INFERIOR STOP FAILED");
1377     QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
1378     setState(InferiorStopFailed);
1379     d->doShutdownEngine();
1380 }
1381 
setInitialActionStates()1382 void DebuggerEnginePrivate::setInitialActionStates()
1383 {
1384     m_returnWindow->setVisible(false);
1385     setBusyCursor(false);
1386 
1387     m_recordForReverseOperationAction.setCheckable(true);
1388     m_recordForReverseOperationAction.setChecked(false);
1389     m_recordForReverseOperationAction.setIcon(Icons::RECORD_OFF.icon());
1390     m_recordForReverseOperationAction.setToolTip(QString("<html><head/><body><p>%1</p><p>"
1391                                                          "<b>%2</b>%3</p></body></html>").arg(
1392                          tr("Record information to enable stepping backwards."),
1393                          tr("Note: "),
1394                          tr("This feature is very slow and unstable on the GDB side. "
1395                             "It exhibits unpredictable behavior when going backwards over system "
1396                             "calls and is very likely to destroy your debugging session.")));
1397 
1398     m_operateInReverseDirectionAction.setCheckable(true);
1399     m_operateInReverseDirectionAction.setChecked(false);
1400     m_operateInReverseDirectionAction.setIcon(Icons::DIRECTION_FORWARD.icon());
1401 
1402     m_snapshotAction.setIcon(Utils::Icons::SNAPSHOT_TOOLBAR.icon());
1403 
1404     m_detachAction.setEnabled(false);
1405 
1406     m_watchAction.setEnabled(true);
1407     m_breakAction.setEnabled(false);
1408     m_snapshotAction.setEnabled(false);
1409     m_operateByInstructionAction.setEnabled(false);
1410 
1411     m_exitAction.setEnabled(false);
1412     m_abortAction.setEnabled(false);
1413     m_resetAction.setEnabled(false);
1414 
1415     m_interruptAction.setEnabled(false);
1416     m_continueAction.setEnabled(false);
1417 
1418     m_stepIntoAction.setEnabled(true);
1419     m_stepOutAction.setEnabled(false);
1420     m_runToLineAction.setEnabled(false);
1421     m_runToLineAction.setVisible(false);
1422     m_runToSelectedFunctionAction.setEnabled(true);
1423     m_returnFromFunctionAction.setEnabled(false);
1424     m_jumpToLineAction.setEnabled(false);
1425     m_jumpToLineAction.setVisible(false);
1426     m_stepOverAction.setEnabled(true);
1427 
1428     debuggerSettings()->autoDerefPointers.setEnabled(true);
1429     debuggerSettings()->expandStack.setEnabled(false);
1430 
1431     m_threadLabel->setEnabled(false);
1432 }
1433 
updateState()1434 void DebuggerEnginePrivate::updateState()
1435 {
1436     // Can happen in mixed debugging.
1437     if (!m_threadLabel)
1438         return;
1439     QTC_ASSERT(m_threadLabel, return);
1440 
1441     const DebuggerState state = m_state;
1442     const bool companionPreventsAction = m_engine->companionPreventsActions();
1443 
1444     // Fixme: hint tr("Debugger is Busy");
1445     // Exactly one of m_interuptAction and m_continueAction should be
1446     // visible, possibly disabled.
1447     if (state == DebuggerNotReady) {
1448         // Happens when companion starts, otherwise this should not happen.
1449         //QTC_CHECK(m_companionEngine);
1450         m_interruptAction.setVisible(true);
1451         m_interruptAction.setEnabled(false);
1452         m_continueAction.setVisible(false);
1453         m_continueAction.setEnabled(false);
1454         m_stepOverAction.setEnabled(true);
1455         m_stepIntoAction.setEnabled(true);
1456         m_stepOutAction.setEnabled(false);
1457         m_exitAction.setEnabled(false);
1458     } else if (state == InferiorStopOk) {
1459         // F5 continues, Shift-F5 kills. It is "continuable".
1460         m_interruptAction.setVisible(false);
1461         m_interruptAction.setEnabled(false);
1462         m_continueAction.setVisible(true);
1463         m_continueAction.setEnabled(!companionPreventsAction);
1464         m_stepOverAction.setEnabled(!companionPreventsAction);
1465         m_stepIntoAction.setEnabled(!companionPreventsAction);
1466         m_stepOutAction.setEnabled(!companionPreventsAction);
1467         m_exitAction.setEnabled(true);
1468         m_localsAndInspectorWindow->setShowLocals(true);
1469     } else if (state == InferiorRunOk) {
1470         // Shift-F5 interrupts. It is also "interruptible".
1471         m_interruptAction.setVisible(true);
1472         m_interruptAction.setEnabled(!companionPreventsAction);
1473         m_continueAction.setVisible(false);
1474         m_continueAction.setEnabled(false);
1475         m_stepOverAction.setEnabled(false);
1476         m_stepIntoAction.setEnabled(false);
1477         m_stepOutAction.setEnabled(false);
1478         m_exitAction.setEnabled(true);
1479         m_localsAndInspectorWindow->setShowLocals(false);
1480     } else if (state == DebuggerFinished) {
1481         // We don't want to do anything anymore.
1482         m_interruptAction.setVisible(true);
1483         m_interruptAction.setEnabled(false);
1484         m_continueAction.setVisible(false);
1485         m_continueAction.setEnabled(false);
1486         m_stepOverAction.setEnabled(false);
1487         m_stepIntoAction.setEnabled(false);
1488         m_stepOutAction.setEnabled(false);
1489         m_exitAction.setEnabled(false);
1490         setBusyCursor(false);
1491         cleanupViews();
1492     } else if (state == InferiorUnrunnable) {
1493         // We don't want to do anything anymore.
1494         m_interruptAction.setVisible(true);
1495         m_interruptAction.setEnabled(false);
1496         m_continueAction.setVisible(false);
1497         m_continueAction.setEnabled(false);
1498         m_stepOverAction.setEnabled(false);
1499         m_stepIntoAction.setEnabled(false);
1500         m_stepOutAction.setEnabled(false);
1501         m_exitAction.setEnabled(true);
1502         // show locals in core dumps
1503         m_localsAndInspectorWindow->setShowLocals(true);
1504     } else {
1505         // Everything else is "undisturbable".
1506         m_interruptAction.setVisible(true);
1507         m_interruptAction.setEnabled(false);
1508         m_continueAction.setVisible(false);
1509         m_continueAction.setEnabled(false);
1510         m_stepOverAction.setEnabled(false);
1511         m_stepIntoAction.setEnabled(false);
1512         m_stepOutAction.setEnabled(false);
1513         m_exitAction.setEnabled(false);
1514     }
1515 
1516     const bool threadsEnabled = state == InferiorStopOk || state == InferiorUnrunnable;
1517     m_threadsHandler.threadSwitcher()->setEnabled(threadsEnabled);
1518     m_threadLabel->setEnabled(threadsEnabled);
1519 
1520     const bool isCore = m_engine->runParameters().startMode == AttachToCore;
1521     const bool stopped = state == InferiorStopOk;
1522     const bool detachable = stopped && !isCore;
1523     m_detachAction.setEnabled(detachable);
1524 
1525     updateReverseActions();
1526 
1527     const bool canSnapshot = m_engine->hasCapability(SnapshotCapability);
1528     m_snapshotAction.setVisible(canSnapshot);
1529     m_snapshotAction.setEnabled(stopped && !isCore);
1530 
1531     m_watchAction.setEnabled(true);
1532     m_breakAction.setEnabled(true);
1533 
1534     const bool canOperateByInstruction = m_engine->hasCapability(OperateByInstructionCapability);
1535     m_operateByInstructionAction.setVisible(canOperateByInstruction);
1536     m_operateByInstructionAction.setEnabled(canOperateByInstruction && (stopped || isCore));
1537 
1538     m_abortAction.setEnabled(state != DebuggerNotReady
1539                                       && state != DebuggerFinished);
1540     m_resetAction.setEnabled((stopped || state == DebuggerNotReady)
1541                               && m_engine->hasCapability(ResetInferiorCapability));
1542 
1543     m_stepIntoAction.setEnabled(stopped || state == DebuggerNotReady);
1544     m_stepIntoAction.setToolTip(QString());
1545 
1546     m_stepOverAction.setEnabled(stopped || state == DebuggerNotReady);
1547     m_stepOverAction.setToolTip(QString());
1548 
1549     m_stepOutAction.setEnabled(stopped);
1550 
1551     const bool canRunToLine = m_engine->hasCapability(RunToLineCapability);
1552     m_runToLineAction.setVisible(canRunToLine);
1553     m_runToLineAction.setEnabled(stopped && canRunToLine);
1554 
1555     m_runToSelectedFunctionAction.setEnabled(stopped);
1556 
1557     const bool canReturnFromFunction = m_engine->hasCapability(ReturnFromFunctionCapability);
1558     m_returnFromFunctionAction.setVisible(canReturnFromFunction);
1559     m_returnFromFunctionAction.setEnabled(stopped && canReturnFromFunction);
1560 
1561     const bool canJump = m_engine->hasCapability(JumpToLineCapability);
1562     m_jumpToLineAction.setVisible(canJump);
1563     m_jumpToLineAction.setEnabled(stopped && canJump);
1564 
1565     const bool actionsEnabled = m_engine->debuggerActionsEnabled();
1566     const bool canDeref = actionsEnabled && m_engine->hasCapability(AutoDerefPointersCapability);
1567     debuggerSettings()->autoDerefPointers.setEnabled(canDeref);
1568     debuggerSettings()->autoDerefPointers.setEnabled(true);
1569     debuggerSettings()->expandStack.setEnabled(actionsEnabled);
1570 
1571     const bool notbusy = state == InferiorStopOk
1572         || state == DebuggerNotReady
1573         || state == DebuggerFinished
1574         || state == InferiorUnrunnable;
1575     setBusyCursor(!notbusy);
1576 }
1577 
updateReverseActions()1578 void DebuggerEnginePrivate::updateReverseActions()
1579 {
1580     const bool stopped = m_state == InferiorStopOk;
1581     const bool reverseEnabled = debuggerSettings()->enableReverseDebugging.value();
1582     const bool canReverse = reverseEnabled && m_engine->hasCapability(ReverseSteppingCapability);
1583     const bool doesRecord = m_recordForReverseOperationAction.isChecked();
1584 
1585     m_recordForReverseOperationAction.setVisible(canReverse);
1586     m_recordForReverseOperationAction.setEnabled(canReverse && stopped);
1587     m_recordForReverseOperationAction.setIcon(doesRecord
1588                                               ? Icons::RECORD_ON.icon()
1589                                               : Icons::RECORD_OFF.icon());
1590 
1591     m_operateInReverseDirectionAction.setVisible(canReverse);
1592     m_operateInReverseDirectionAction.setEnabled(canReverse && stopped && doesRecord);
1593     m_operateInReverseDirectionAction.setIcon(Icons::DIRECTION_BACKWARD.icon());
1594     m_operateInReverseDirectionAction.setText(DebuggerEngine::tr("Operate in Reverse Direction"));
1595 }
1596 
cleanupViews()1597 void DebuggerEnginePrivate::cleanupViews()
1598 {
1599     const bool closeSource = debuggerSettings()->closeSourceBuffersOnExit.value();
1600     const bool closeMemory = debuggerSettings()->closeMemoryBuffersOnExit.value();
1601 
1602     QList<IDocument *> toClose;
1603     foreach (IDocument *document, DocumentModel::openedDocuments()) {
1604         const bool isMemory = document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool();
1605         if (document->property(Constants::OPENED_BY_DEBUGGER).toBool()) {
1606             bool keepIt = true;
1607             if (document->isModified())
1608                 keepIt = true;
1609             else if (document->filePath().toString().contains("qeventdispatcher"))
1610                 keepIt = false;
1611             else if (isMemory)
1612                 keepIt = !closeMemory;
1613             else
1614                 keepIt = !closeSource;
1615 
1616             if (keepIt)
1617                 document->setProperty(Constants::OPENED_BY_DEBUGGER, false);
1618             else
1619                 toClose.append(document);
1620         }
1621     }
1622     EditorManager::closeDocuments(toClose);
1623 }
1624 
setBusyCursor(bool busy)1625 void DebuggerEnginePrivate::setBusyCursor(bool busy)
1626 {
1627     //STATE_DEBUG("BUSY FROM: " << m_busy << " TO: " << busy);
1628     if (m_isDying)
1629         return;
1630     if (busy == m_busy)
1631         return;
1632     m_busy = busy;
1633     const QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
1634     m_breakWindow->setCursor(cursor);
1635     //m_consoleWindow->setCursor(cursor);
1636     m_localsWindow->setCursor(cursor);
1637     m_modulesWindow->setCursor(cursor);
1638     m_logWindow->setCursor(cursor);
1639     m_registerWindow->setCursor(cursor);
1640     m_peripheralRegisterWindow->setCursor(cursor);
1641     m_returnWindow->setCursor(cursor);
1642     m_sourceFilesWindow->setCursor(cursor);
1643     m_stackWindow->setCursor(cursor);
1644     m_threadsWindow->setCursor(cursor);
1645     m_watchersWindow->setCursor(cursor);
1646 }
1647 
notifyInferiorShutdownFinished()1648 void DebuggerEngine::notifyInferiorShutdownFinished()
1649 {
1650     showMessage("INFERIOR FINISHED SHUT DOWN");
1651     QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
1652     setState(InferiorShutdownFinished);
1653     d->doShutdownEngine();
1654 }
1655 
notifyInferiorIll()1656 void DebuggerEngine::notifyInferiorIll()
1657 {
1658     showMessage("NOTE: INFERIOR ILL");
1659     // This can be issued in almost any state. The inferior could still be
1660     // alive as some previous notifications might have been bogus.
1661     startDying();
1662     if (state() == InferiorRunRequested) {
1663         // We asked for running, but did not see a response.
1664         // Assume the inferior is dead.
1665         // FIXME: Use timeout?
1666         setState(InferiorRunFailed);
1667         setState(InferiorStopOk);
1668     }
1669     d->doShutdownInferior();
1670 }
1671 
notifyEngineShutdownFinished()1672 void DebuggerEngine::notifyEngineShutdownFinished()
1673 {
1674     showMessage("NOTE: ENGINE SHUTDOWN FINISHED");
1675     QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << this << state());
1676     setState(EngineShutdownFinished);
1677     d->doFinishDebugger();
1678 }
1679 
notifyEngineIll()1680 void DebuggerEngine::notifyEngineIll()
1681 {
1682 //#ifdef WITH_BENCHMARK
1683 //    CALLGRIND_STOP_INSTRUMENTATION;
1684 //    CALLGRIND_DUMP_STATS;
1685 //#endif
1686     showMessage("NOTE: ENGINE ILL ******");
1687     startDying();
1688     switch (state()) {
1689         case InferiorRunRequested:
1690         case InferiorRunOk:
1691             // The engine does not look overly ill right now, so attempt to
1692             // properly interrupt at least once. If that fails, we are on the
1693             // shutdown path due to d->m_targetState anyways.
1694             setState(InferiorStopRequested, true);
1695             showMessage("ATTEMPT TO INTERRUPT INFERIOR");
1696             interruptInferior();
1697             break;
1698         case InferiorStopRequested:
1699             notifyInferiorStopFailed();
1700             break;
1701         case InferiorStopOk:
1702             showMessage("FORWARDING STATE TO InferiorShutdownFinished");
1703             setState(InferiorShutdownFinished, true);
1704             d->doShutdownEngine();
1705             break;
1706         default:
1707             d->doShutdownEngine();
1708             break;
1709     }
1710 }
1711 
notifyEngineSpontaneousShutdown()1712 void DebuggerEngine::notifyEngineSpontaneousShutdown()
1713 {
1714 #ifdef WITH_BENCHMARK
1715     CALLGRIND_STOP_INSTRUMENTATION;
1716     CALLGRIND_DUMP_STATS;
1717 #endif
1718     showMessage("NOTE: ENGINE SPONTANEOUS SHUTDOWN");
1719     setState(EngineShutdownFinished, true);
1720     d->doFinishDebugger();
1721 }
1722 
notifyInferiorExited()1723 void DebuggerEngine::notifyInferiorExited()
1724 {
1725 #ifdef WITH_BENCHMARK
1726     CALLGRIND_STOP_INSTRUMENTATION;
1727     CALLGRIND_DUMP_STATS;
1728 #endif
1729     showMessage("NOTE: INFERIOR EXITED");
1730     d->resetLocation();
1731     setState(InferiorShutdownFinished);
1732     d->doShutdownEngine();
1733 }
1734 
updateState()1735 void DebuggerEngine::updateState()
1736 {
1737     d->updateState();
1738 }
1739 
inspectorView()1740 WatchTreeView *DebuggerEngine::inspectorView()
1741 {
1742     return d->m_inspectorView;
1743 }
1744 
showMessage(const QString & msg,int channel,int timeout) const1745 void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
1746 {
1747     //qDebug() << "PLUGIN OUTPUT: " << channel << msg;
1748     QTC_ASSERT(d->m_logWindow, qDebug() << "MSG: " << msg; return);
1749     switch (channel) {
1750         case StatusBar:
1751             d->m_logWindow->showInput(LogMisc, msg);
1752             d->m_logWindow->showOutput(LogMisc, msg);
1753             DebuggerMainWindow::showStatusMessage(msg, timeout);
1754             break;
1755         case LogMiscInput:
1756             d->m_logWindow->showInput(LogMisc, msg);
1757             d->m_logWindow->showOutput(LogMisc, msg);
1758             break;
1759         case LogInput:
1760             d->m_logWindow->showInput(LogInput, msg);
1761             d->m_logWindow->showOutput(LogInput, msg);
1762             break;
1763         case LogError:
1764             d->m_logWindow->showInput(LogError, "ERROR: " + msg);
1765             d->m_logWindow->showOutput(LogError, "ERROR: " + msg);
1766             break;
1767         case AppOutput:
1768         case AppStuff:
1769             d->m_logWindow->showOutput(channel, msg);
1770             emit appendMessageRequested(msg, StdOutFormat, false);
1771             break;
1772         case AppError:
1773             d->m_logWindow->showOutput(channel, msg);
1774             emit appendMessageRequested(msg, StdErrFormat, false);
1775             break;
1776         default:
1777             d->m_logWindow->showOutput(channel, msg);
1778             break;
1779     }
1780 }
1781 
notifyDebuggerProcessFinished(int exitCode,QProcess::ExitStatus exitStatus,const QString & backendName)1782 void DebuggerEngine::notifyDebuggerProcessFinished(int exitCode,
1783     QProcess::ExitStatus exitStatus, const QString &backendName)
1784 {
1785     showMessage(QString("%1 PROCESS FINISHED, status %2, exit code %3 (0x%4)")
1786                     .arg(backendName)
1787                     .arg(exitStatus)
1788                     .arg(exitCode)
1789                     .arg(QString::number(exitCode, 16)));
1790 
1791     switch (state()) {
1792     case DebuggerFinished:
1793         // Nothing to do.
1794         break;
1795     case EngineShutdownRequested:
1796     case InferiorShutdownRequested:
1797         notifyEngineShutdownFinished();
1798         break;
1799     case InferiorRunOk:
1800         // This could either be a real gdb/lldb crash or a quickly exited inferior
1801         // in the terminal adapter. In this case the stub proc will die soon,
1802         // too, so there's no need to act here.
1803         showMessage(QString("The %1 process exited somewhat unexpectedly.").arg(backendName));
1804         notifyEngineSpontaneousShutdown();
1805         break;
1806     default: {
1807         // Initiate shutdown sequence
1808         notifyInferiorIll();
1809         const QString msg = exitStatus == QProcess::CrashExit ?
1810                 tr("The %1 process terminated.") :
1811                 tr("The %2 process terminated unexpectedly (exit code %1).").arg(exitCode);
1812         AsynchronousMessageBox::critical(tr("Unexpected %1 Exit").arg(backendName),
1813                                          msg.arg(backendName));
1814         break;
1815     }
1816     }
1817 }
1818 
msgStateChanged(DebuggerState oldState,DebuggerState newState,bool forced)1819 static QString msgStateChanged(DebuggerState oldState, DebuggerState newState, bool forced)
1820 {
1821     QString result;
1822     QTextStream str(&result);
1823     str << "State changed";
1824     if (forced)
1825         str << " BY FORCE";
1826     str << " from " << DebuggerEngine::stateName(oldState) << '(' << oldState
1827         << ") to " << DebuggerEngine::stateName(newState) << '(' << newState << ')';
1828     return result;
1829 }
1830 
setState(DebuggerState state,bool forced)1831 void DebuggerEngine::setState(DebuggerState state, bool forced)
1832 {
1833     const QString msg = msgStateChanged(d->m_state, state, forced);
1834 
1835     DebuggerState oldState = d->m_state;
1836     d->m_state = state;
1837 
1838     if (!forced && !isAllowedTransition(oldState, state))
1839         qDebug() << "*** UNEXPECTED STATE TRANSITION: " << this << msg;
1840 
1841     if (state == EngineRunRequested) {
1842         emit engineStarted();
1843         if (d->m_perspective)
1844             d->m_perspective->select();
1845     }
1846 
1847     showMessage(msg, LogDebug);
1848 
1849     d->updateState();
1850     if (d->m_companionEngine)
1851         d->m_companionEngine->d->updateState();
1852 
1853     if (oldState != d->m_state)
1854         emit EngineManager::instance()->engineStateChanged(this);
1855 
1856     if (state == DebuggerFinished) {
1857         d->setBusyCursor(false);
1858 
1859         // Give up ownership on claimed breakpoints.
1860         d->m_breakHandler.releaseAllBreakpoints();
1861         d->m_toolTipManager.deregisterEngine();
1862         d->m_memoryAgents.handleDebuggerFinished();
1863 
1864         d->destroyPerspective();
1865         emit engineFinished();
1866     }
1867 }
1868 
isPrimaryEngine() const1869 bool DebuggerEngine::isPrimaryEngine() const
1870 {
1871     return d->m_isPrimaryEngine;
1872 }
1873 
canDisplayTooltip() const1874 bool DebuggerEngine::canDisplayTooltip() const
1875 {
1876     return state() == InferiorStopOk;
1877 }
1878 
expand(const QString & string) const1879 QString DebuggerEngine::expand(const QString &string) const
1880 {
1881     return runParameters().macroExpander->expand(string);
1882 }
1883 
nativeStartupCommands() const1884 QString DebuggerEngine::nativeStartupCommands() const
1885 {
1886     QStringList lines = debuggerSettings()->gdbStartupCommands.value().split('\n');
1887     lines += runParameters().additionalStartupCommands.split('\n');
1888 
1889     lines = Utils::filtered(lines, [](const QString line) {
1890         const QString trimmed = line.trimmed();
1891         return !trimmed.isEmpty() && !trimmed.startsWith('#');
1892     });
1893 
1894     return lines.join('\n');
1895 }
1896 
perspective() const1897 Perspective *DebuggerEngine::perspective() const
1898 {
1899     return d->m_perspective;
1900 }
1901 
updateMarkers()1902 void DebuggerEngine::updateMarkers()
1903 {
1904     if (d->m_locationMark)
1905         d->m_locationMark->updateIcon();
1906 
1907     d->m_disassemblerAgent.updateLocationMarker();
1908 }
1909 
updateToolTips()1910 void DebuggerEngine::updateToolTips()
1911 {
1912     d->m_toolTipManager.updateToolTips();
1913 }
1914 
toolTipManager()1915 DebuggerToolTipManager *DebuggerEngine::toolTipManager()
1916 {
1917     return &d->m_toolTipManager;
1918 }
1919 
operatesByInstruction() const1920 bool DebuggerEngine::operatesByInstruction() const
1921 {
1922     return d->m_operateByInstructionAction.isChecked();
1923 }
1924 
debuggerActionsEnabled() const1925 bool DebuggerEngine::debuggerActionsEnabled() const
1926 {
1927     return debuggerActionsEnabledHelper(d->m_state);
1928 }
1929 
operateByInstructionTriggered(bool on)1930 void DebuggerEngine::operateByInstructionTriggered(bool on)
1931 {
1932     // Go to source only if we have the file.
1933     //    if (DebuggerEngine *cppEngine = m_engine->cppEngine()) {
1934     d->m_stackHandler.rootItem()->updateAll();
1935     if (d->m_stackHandler.currentIndex() >= 0) {
1936         const StackFrame frame = d->m_stackHandler.currentFrame();
1937         if (on || frame.isUsable())
1938             gotoLocation(Location(frame, true));
1939     }
1940     //    }
1941 }
1942 
companionPreventsActions() const1943 bool DebuggerEngine::companionPreventsActions() const
1944 {
1945     return false;
1946 }
1947 
notifyInferiorPid(const ProcessHandle & pid)1948 void DebuggerEngine::notifyInferiorPid(const ProcessHandle &pid)
1949 {
1950     if (d->m_inferiorPid == pid)
1951         return;
1952     d->m_inferiorPid = pid;
1953     if (pid.isValid()) {
1954         showMessage(tr("Taking notice of pid %1").arg(pid.pid()));
1955         DebuggerStartMode sm = runParameters().startMode;
1956         if (sm == StartInternal || sm == StartExternal || sm == AttachToLocalProcess)
1957             d->m_inferiorPid.activate();
1958     }
1959 }
1960 
inferiorPid() const1961 qint64 DebuggerEngine::inferiorPid() const
1962 {
1963     return d->m_inferiorPid.pid();
1964 }
1965 
isReverseDebugging() const1966 bool DebuggerEngine::isReverseDebugging() const
1967 {
1968     return d->m_operateInReverseDirectionAction.isChecked();
1969 }
1970 
handleBeginOfRecordingReached()1971 void DebuggerEngine::handleBeginOfRecordingReached()
1972 {
1973     showStatusMessage(tr("Reverse-execution history exhausted. Going forward again."));
1974     d->m_operateInReverseDirectionAction.setChecked(false);
1975     d->updateReverseActions();
1976 }
1977 
handleRecordingFailed()1978 void DebuggerEngine::handleRecordingFailed()
1979 {
1980     showStatusMessage(tr("Reverse-execution recording failed."));
1981     d->m_operateInReverseDirectionAction.setChecked(false);
1982     d->m_recordForReverseOperationAction.setChecked(false);
1983     d->updateReverseActions();
1984     executeRecordReverse(false);
1985 }
1986 
1987 // Called by DebuggerRunControl.
quitDebugger()1988 void DebuggerEngine::quitDebugger()
1989 {
1990     showMessage(QString("QUIT DEBUGGER REQUESTED IN STATE %1").arg(state()));
1991     startDying();
1992     switch (state()) {
1993     case InferiorStopOk:
1994     case InferiorStopFailed:
1995     case InferiorUnrunnable:
1996         d->doShutdownInferior();
1997         break;
1998     case InferiorRunOk:
1999         setState(InferiorStopRequested);
2000         showMessage(tr("Attempting to interrupt."), StatusBar);
2001         interruptInferior();
2002         break;
2003     case EngineSetupRequested:
2004         notifyEngineSetupFailed();
2005         break;
2006     case EngineRunRequested:
2007         notifyEngineRunFailed();
2008         break;
2009     case EngineShutdownRequested:
2010     case InferiorShutdownRequested:
2011         break;
2012     case EngineRunFailed:
2013     case DebuggerFinished:
2014     case InferiorShutdownFinished:
2015         break;
2016     default:
2017         // FIXME: We should disable the actions connected to that.
2018         notifyInferiorIll();
2019         break;
2020     }
2021 }
2022 
requestInterruptInferior()2023 void DebuggerEngine::requestInterruptInferior()
2024 {
2025     QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());
2026     setState(InferiorStopRequested);
2027     showMessage("CALL: INTERRUPT INFERIOR");
2028     showMessage(tr("Attempting to interrupt."), StatusBar);
2029     interruptInferior();
2030 }
2031 
progressPing()2032 void DebuggerEngine::progressPing()
2033 {
2034     int progress = qMin(d->m_progress.progressValue() + 2, 800);
2035     d->m_progress.setProgressValue(progress);
2036 }
2037 
setCompanionEngine(DebuggerEngine * engine)2038 void DebuggerEngine::setCompanionEngine(DebuggerEngine *engine)
2039 {
2040     d->m_companionEngine = engine;
2041 }
2042 
setSecondaryEngine()2043 void DebuggerEngine::setSecondaryEngine()
2044 {
2045     d->m_isPrimaryEngine = false;
2046 }
2047 
terminal() const2048 TerminalRunner *DebuggerEngine::terminal() const
2049 {
2050     return d->m_terminalRunner;
2051 }
2052 
selectWatchData(const QString &)2053 void DebuggerEngine::selectWatchData(const QString &)
2054 {
2055 }
2056 
watchPoint(const QPoint & pnt)2057 void DebuggerEngine::watchPoint(const QPoint &pnt)
2058 {
2059     DebuggerCommand cmd("watchPoint", NeedsFullStop);
2060     cmd.arg("x", pnt.x());
2061     cmd.arg("y", pnt.y());
2062     cmd.callback = [this](const DebuggerResponse &response) {
2063         qulonglong addr = response.data["selected"].toAddress();
2064         if (addr == 0)
2065             showMessage(tr("Could not find a widget."), StatusBar);
2066         // Add the watcher entry nevertheless, as that's the place where
2067         // the user expects visual feedback.
2068         watchHandler()->watchExpression(response.data["expr"].data(), QString(), true);
2069     };
2070     runCommand(cmd);
2071 }
2072 
runCommand(const DebuggerCommand &)2073 void DebuggerEngine::runCommand(const DebuggerCommand &)
2074 {
2075     // Overridden in the engines that use the interface.
2076     QTC_CHECK(false);
2077 }
2078 
fetchDisassembler(DisassemblerAgent *)2079 void DebuggerEngine::fetchDisassembler(DisassemblerAgent *)
2080 {
2081 }
2082 
activateFrame(int)2083 void DebuggerEngine::activateFrame(int)
2084 {
2085 }
2086 
reloadModules()2087 void DebuggerEngine::reloadModules()
2088 {
2089 }
2090 
examineModules()2091 void DebuggerEngine::examineModules()
2092 {
2093 }
2094 
loadSymbols(const QString &)2095 void DebuggerEngine::loadSymbols(const QString &)
2096 {
2097 }
2098 
loadAllSymbols()2099 void DebuggerEngine::loadAllSymbols()
2100 {
2101 }
2102 
loadSymbolsForStack()2103 void DebuggerEngine::loadSymbolsForStack()
2104 {
2105 }
2106 
requestModuleSymbols(const QString &)2107 void DebuggerEngine::requestModuleSymbols(const QString &)
2108 {
2109 }
2110 
requestModuleSections(const QString &)2111 void DebuggerEngine::requestModuleSections(const QString &)
2112 {
2113 }
2114 
reloadRegisters()2115 void DebuggerEngine::reloadRegisters()
2116 {
2117 }
2118 
reloadPeripheralRegisters()2119 void DebuggerEngine::reloadPeripheralRegisters()
2120 {
2121 }
2122 
reloadSourceFiles()2123 void DebuggerEngine::reloadSourceFiles()
2124 {
2125 }
2126 
reloadFullStack()2127 void DebuggerEngine::reloadFullStack()
2128 {
2129 }
2130 
loadAdditionalQmlStack()2131 void DebuggerEngine::loadAdditionalQmlStack()
2132 {
2133 }
2134 
reloadDebuggingHelpers()2135 void DebuggerEngine::reloadDebuggingHelpers()
2136 {
2137 }
2138 
addOptionPages(QList<IOptionsPage * > *) const2139 void DebuggerEngine::addOptionPages(QList<IOptionsPage*> *) const
2140 {
2141 }
2142 
qtNamespace() const2143 QString DebuggerEngine::qtNamespace() const
2144 {
2145     return d->m_qtNamespace;
2146 }
2147 
setQtNamespace(const QString & ns)2148 void DebuggerEngine::setQtNamespace(const QString &ns)
2149 {
2150     d->m_qtNamespace = ns;
2151 }
2152 
createSnapshot()2153 void DebuggerEngine::createSnapshot()
2154 {
2155 }
2156 
updateLocals()2157 void DebuggerEngine::updateLocals()
2158 {
2159     // if the engine is not running - do nothing
2160     if (state() == DebuggerState::DebuggerFinished || state() == DebuggerState::DebuggerNotReady)
2161         return;
2162 
2163     watchHandler()->resetValueCache();
2164     doUpdateLocals(UpdateParameters());
2165 }
2166 
debuggerContext() const2167 Context DebuggerEngine::debuggerContext() const
2168 {
2169     return d->m_context;
2170 }
2171 
updateAll()2172 void DebuggerEngine::updateAll()
2173 {
2174 }
2175 
displayName() const2176 QString DebuggerEngine::displayName() const
2177 {
2178     //: e.g. LLDB for "myproject", shows up i
2179     return tr("%1 for \"%2\"").arg(d->m_debuggerName, runParameters().displayName);
2180 }
2181 
insertBreakpoint(const Breakpoint & bp)2182 void DebuggerEngine::insertBreakpoint(const Breakpoint &bp)
2183 {
2184     QTC_ASSERT(bp, return);
2185     BreakpointState state = bp->state();
2186     QTC_ASSERT(state == BreakpointInsertionRequested,
2187                qDebug() << bp->modelId() << this << state);
2188     QTC_CHECK(false);
2189 }
2190 
removeBreakpoint(const Breakpoint & bp)2191 void DebuggerEngine::removeBreakpoint(const Breakpoint &bp)
2192 {
2193     QTC_ASSERT(bp, return);
2194     BreakpointState state = bp->state();
2195     QTC_ASSERT(state == BreakpointRemoveRequested,
2196                qDebug() << bp->responseId() << this << state);
2197     QTC_CHECK(false);
2198 }
2199 
updateBreakpoint(const Breakpoint & bp)2200 void DebuggerEngine::updateBreakpoint(const Breakpoint &bp)
2201 {
2202     QTC_ASSERT(bp, return);
2203     BreakpointState state = bp->state();
2204     QTC_ASSERT(state == BreakpointUpdateRequested,
2205                qDebug() << bp->responseId() << this << state);
2206     QTC_CHECK(false);
2207 }
2208 
enableSubBreakpoint(const SubBreakpoint & sbp,bool)2209 void DebuggerEngine::enableSubBreakpoint(const SubBreakpoint &sbp, bool)
2210 {
2211     QTC_ASSERT(sbp, return);
2212     QTC_CHECK(false);
2213 }
2214 
assignValueInDebugger(WatchItem *,const QString &,const QVariant &)2215 void DebuggerEngine::assignValueInDebugger(WatchItem *,
2216     const QString &, const QVariant &)
2217 {
2218 }
2219 
handleRecordReverse(bool record)2220 void DebuggerEngine::handleRecordReverse(bool record)
2221 {
2222     executeRecordReverse(record);
2223     d->updateReverseActions();
2224 }
2225 
handleReverseDirection(bool reverse)2226 void DebuggerEngine::handleReverseDirection(bool reverse)
2227 {
2228     executeReverse(reverse);
2229     updateMarkers();
2230     d->updateReverseActions();
2231 }
2232 
executeDebuggerCommand(const QString &)2233 void DebuggerEngine::executeDebuggerCommand(const QString &)
2234 {
2235     showMessage(tr("This debugger cannot handle user input."), StatusBar);
2236 }
2237 
isDying() const2238 bool DebuggerEngine::isDying() const
2239 {
2240     return d->m_isDying;
2241 }
2242 
msgStopped(const QString & reason)2243 QString DebuggerEngine::msgStopped(const QString &reason)
2244 {
2245     return reason.isEmpty() ? tr("Stopped.") : tr("Stopped: \"%1\".").arg(reason);
2246 }
2247 
msgStoppedBySignal(const QString & meaning,const QString & name)2248 QString DebuggerEngine::msgStoppedBySignal(const QString &meaning,
2249     const QString &name)
2250 {
2251     return tr("Stopped: %1 (Signal %2).").arg(meaning, name);
2252 }
2253 
msgStoppedByException(const QString & description,const QString & threadId)2254 QString DebuggerEngine::msgStoppedByException(const QString &description,
2255     const QString &threadId)
2256 {
2257     return tr("Stopped in thread %1 by: %2.").arg(threadId, description);
2258 }
2259 
msgInterrupted()2260 QString DebuggerEngine::msgInterrupted()
2261 {
2262     return tr("Interrupted.");
2263 }
2264 
showStoppedBySignalMessageBox(QString meaning,QString name)2265 bool DebuggerEngine::showStoppedBySignalMessageBox(QString meaning, QString name)
2266 {
2267     if (d->m_alertBox)
2268         return false;
2269 
2270     if (name.isEmpty())
2271         name = ' ' + tr("<Unknown>", "name") + ' ';
2272     if (meaning.isEmpty())
2273         meaning = ' ' + tr("<Unknown>", "meaning") + ' ';
2274     const QString msg = tr("<p>The inferior stopped because it received a "
2275                            "signal from the operating system.<p>"
2276                            "<table><tr><td>Signal name : </td><td>%1</td></tr>"
2277                            "<tr><td>Signal meaning : </td><td>%2</td></tr></table>")
2278             .arg(name, meaning);
2279 
2280     d->m_alertBox = AsynchronousMessageBox::information(tr("Signal Received"), msg);
2281     return true;
2282 }
2283 
showStoppedByExceptionMessageBox(const QString & description)2284 void DebuggerEngine::showStoppedByExceptionMessageBox(const QString &description)
2285 {
2286     const QString msg =
2287         tr("<p>The inferior stopped because it triggered an exception.<p>%1").
2288                          arg(description);
2289     AsynchronousMessageBox::information(tr("Exception Triggered"), msg);
2290 }
2291 
openMemoryView(const MemoryViewSetupData & data)2292 void DebuggerEngine::openMemoryView(const MemoryViewSetupData &data)
2293 {
2294     d->m_memoryAgents.createBinEditor(data, this);
2295 }
2296 
updateMemoryViews()2297 void DebuggerEngine::updateMemoryViews()
2298 {
2299     d->m_memoryAgents.updateContents();
2300 }
2301 
openDisassemblerView(const Location & location)2302 void DebuggerEngine::openDisassemblerView(const Location &location)
2303 {
2304     DisassemblerAgent *agent = new DisassemblerAgent(this);
2305     agent->setLocation(location);
2306 }
2307 
raiseWatchersWindow()2308 void DebuggerEngine::raiseWatchersWindow()
2309 {
2310     if (d->m_watchersView && d->m_watchersWindow) {
2311         auto currentPerspective = DebuggerMainWindow::currentPerspective();
2312         QTC_ASSERT(currentPerspective, return);
2313         // if a companion engine has taken over - do not raise the watchers
2314         if (currentPerspective->name() != d->m_engine->displayName())
2315             return;
2316 
2317         if (auto dock = qobject_cast<QDockWidget *>(d->m_watchersWindow->parentWidget())) {
2318             if (QAction *act = dock->toggleViewAction()) {
2319                 if (!act->isChecked())
2320                     QTimer::singleShot(1, act, [act] { act->trigger(); });
2321                 dock->raise();
2322             }
2323         }
2324     }
2325 }
2326 
openMemoryEditor()2327 void DebuggerEngine::openMemoryEditor()
2328 {
2329     AddressDialog dialog;
2330     if (dialog.exec() != QDialog::Accepted)
2331         return;
2332     MemoryViewSetupData data;
2333     data.startAddress = dialog.address();
2334     openMemoryView(data);
2335 }
2336 
updateLocalsView(const GdbMi & all)2337 void DebuggerEngine::updateLocalsView(const GdbMi &all)
2338 {
2339     WatchHandler *handler = watchHandler();
2340 
2341     const GdbMi typeInfo = all["typeinfo"];
2342     handler->recordTypeInfo(typeInfo);
2343 
2344     const GdbMi data = all["data"];
2345     handler->insertItems(data);
2346 
2347     const GdbMi ns = all["qtnamespace"];
2348     if (ns.isValid()) {
2349         setQtNamespace(ns.data());
2350         showMessage("FOUND NAMESPACED QT: " + ns.data());
2351     }
2352 
2353     static int count = 0;
2354     showMessage(QString("<Rebuild Watchmodel %1 @ %2 >")
2355                 .arg(++count).arg(LogWindow::logTimeStamp()), LogMiscInput);
2356     showMessage(tr("Finished retrieving data."), 400, StatusBar);
2357 
2358     d->m_toolTipManager.updateToolTips();
2359 
2360     const bool partial = all["partial"].toInt();
2361     if (!partial)
2362         updateMemoryViews();
2363 }
2364 
canHandleToolTip(const DebuggerToolTipContext & context) const2365 bool DebuggerEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
2366 {
2367     return state() == InferiorStopOk && context.isCppEditor;
2368 }
2369 
updateItem(const QString & iname)2370 void DebuggerEngine::updateItem(const QString &iname)
2371 {
2372     if (d->m_lookupRequests.contains(iname)) {
2373         showMessage(QString("IGNORING REPEATED REQUEST TO EXPAND " + iname));
2374         WatchHandler *handler = watchHandler();
2375         WatchItem *item = handler->findItem(iname);
2376         QTC_CHECK(item);
2377         WatchModelBase *model = handler->model();
2378         QTC_CHECK(model);
2379         if (item && !item->wantsChildren) {
2380             updateToolTips();
2381             return;
2382         }
2383         if (item && !model->hasChildren(model->indexForItem(item))) {
2384             handler->notifyUpdateStarted(UpdateParameters(iname));
2385             item->setValue(decodeData({}, "notaccessible"));
2386             item->setHasChildren(false);
2387             item->outdated = false;
2388             item->update();
2389             handler->notifyUpdateFinished();
2390             return;
2391         }
2392         // We could legitimately end up here after expanding + closing + re-expaning an item.
2393     }
2394     d->m_lookupRequests.insert(iname);
2395 
2396     UpdateParameters params;
2397     params.partialVariable = iname;
2398     doUpdateLocals(params);
2399 }
2400 
updateWatchData(const QString & iname)2401 void DebuggerEngine::updateWatchData(const QString &iname)
2402 {
2403     // This is used in cases where re-evaluation is ok for the same iname
2404     // e.g. when changing the expression in a watcher.
2405     UpdateParameters params;
2406     params.partialVariable = iname;
2407     doUpdateLocals(params);
2408 }
2409 
expandItem(const QString & iname)2410 void DebuggerEngine::expandItem(const QString &iname)
2411 {
2412     updateItem(iname);
2413 }
2414 
handleExecDetach()2415 void DebuggerEngine::handleExecDetach()
2416 {
2417     resetLocation();
2418     detachDebugger();
2419 }
2420 
handleExecContinue()2421 void DebuggerEngine::handleExecContinue()
2422 {
2423     resetLocation();
2424     continueInferior();
2425 }
2426 
handleExecInterrupt()2427 void DebuggerEngine::handleExecInterrupt()
2428 {
2429     resetLocation();
2430     requestInterruptInferior();
2431 }
2432 
handleReset()2433 void DebuggerEngine::handleReset()
2434 {
2435     resetLocation();
2436     resetInferior();
2437 }
2438 
handleExecStepIn()2439 void DebuggerEngine::handleExecStepIn()
2440 {
2441     resetLocation();
2442     executeStepIn(operatesByInstruction());
2443 }
2444 
handleExecStepOver()2445 void DebuggerEngine::handleExecStepOver()
2446 {
2447     resetLocation();
2448     executeStepOver(operatesByInstruction());
2449 }
2450 
handleExecStepOut()2451 void DebuggerEngine::handleExecStepOut()
2452 {
2453     resetLocation();
2454     executeStepOut();
2455 }
2456 
handleExecReturn()2457 void DebuggerEngine::handleExecReturn()
2458 {
2459     resetLocation();
2460     executeReturn();
2461 }
2462 
handleExecJumpToLine()2463 void DebuggerEngine::handleExecJumpToLine()
2464 {
2465     resetLocation();
2466     if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
2467         ContextData location = getLocationContext(textEditor->textDocument(),
2468                                                   textEditor->currentLine());
2469         if (location.isValid())
2470             executeJumpToLine(location);
2471     }
2472 }
2473 
handleExecRunToLine()2474 void DebuggerEngine::handleExecRunToLine()
2475 {
2476     resetLocation();
2477     if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
2478         ContextData location = getLocationContext(textEditor->textDocument(),
2479                                                   textEditor->currentLine());
2480         if (location.isValid())
2481             executeRunToLine(location);
2482     }
2483 }
2484 
handleExecRunToSelectedFunction()2485 void DebuggerEngine::handleExecRunToSelectedFunction()
2486 {
2487     BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
2488     QTC_ASSERT(textEditor, return);
2489     QTextCursor cursor = textEditor->textCursor();
2490     QString functionName = cursor.selectedText();
2491     if (functionName.isEmpty()) {
2492         const QTextBlock block = cursor.block();
2493         const QString line = block.text();
2494         foreach (const QString &str, line.trimmed().split('(')) {
2495             QString a;
2496             for (int i = str.size(); --i >= 0; ) {
2497                 if (!str.at(i).isLetterOrNumber())
2498                     break;
2499                 a = str.at(i) + a;
2500             }
2501             if (!a.isEmpty()) {
2502                 functionName = a;
2503                 break;
2504             }
2505         }
2506     }
2507 
2508     if (functionName.isEmpty()) {
2509         showMessage(tr("No function selected."), StatusBar);
2510     } else {
2511         showMessage(tr("Running to function \"%1\".").arg(functionName), StatusBar);
2512         resetLocation();
2513         executeRunToFunction(functionName);
2514     }
2515 }
2516 
handleAddToWatchWindow()2517 void DebuggerEngine::handleAddToWatchWindow()
2518 {
2519     // Requires a selection, but that's the only case we want anyway.
2520     BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
2521     if (!textEditor)
2522         return;
2523     QTextCursor tc = textEditor->textCursor();
2524     QString exp;
2525     if (tc.hasSelection()) {
2526         exp = tc.selectedText();
2527     } else {
2528         int line, column;
2529         exp = cppExpressionAt(textEditor->editorWidget(), tc.position(), &line, &column);
2530     }
2531     if (hasCapability(WatchComplexExpressionsCapability))
2532         exp = removeObviousSideEffects(exp);
2533     else
2534         exp = fixCppExpression(exp);
2535     exp = exp.trimmed();
2536     if (exp.isEmpty()) {
2537         // Happens e.g. when trying to evaluate 'char' or 'return'.
2538         AsynchronousMessageBox::warning(tr("Warning"),
2539                                         tr("Select a valid expression to evaluate."));
2540         return;
2541     }
2542     watchHandler()->watchVariable(exp);
2543 }
2544 
handleFrameDown()2545 void DebuggerEngine::handleFrameDown()
2546 {
2547     frameDown();
2548 }
2549 
handleFrameUp()2550 void DebuggerEngine::handleFrameUp()
2551 {
2552     frameUp();
2553 }
2554 
checkState(DebuggerState state,const char * file,int line)2555 void DebuggerEngine::checkState(DebuggerState state, const char *file, int line)
2556 {
2557     const DebuggerState current = d->m_state;
2558     if (current == state)
2559         return;
2560 
2561     QString msg = QString("UNEXPECTED STATE: %1  WANTED: %2 IN %3:%4")
2562                 .arg(stateName(current)).arg(stateName(state)).arg(QLatin1String(file)).arg(line);
2563 
2564     showMessage(msg, LogError);
2565     qDebug("%s", qPrintable(msg));
2566 }
2567 
isNativeMixedEnabled() const2568 bool DebuggerEngine::isNativeMixedEnabled() const
2569 {
2570     return d->m_runParameters.isNativeMixedDebugging();
2571 }
2572 
isNativeMixedActive() const2573 bool DebuggerEngine::isNativeMixedActive() const
2574 {
2575     return isNativeMixedEnabled(); //&& boolSetting(OperateNativeMixed);
2576 }
2577 
isNativeMixedActiveFrame() const2578 bool DebuggerEngine::isNativeMixedActiveFrame() const
2579 {
2580     if (!isNativeMixedActive())
2581         return false;
2582     if (stackHandler()->rowCount() == 0)
2583         return false;
2584     StackFrame frame = stackHandler()->frameAt(0);
2585     return frame.language == QmlLanguage;
2586 }
2587 
startDying() const2588 void DebuggerEngine::startDying() const
2589 {
2590     d->m_isDying = true;
2591 }
2592 
runId() const2593 QString DebuggerEngine::runId() const
2594 {
2595     return d->m_runId;
2596 }
2597 
isCppDebugging() const2598 bool DebuggerRunParameters::isCppDebugging() const
2599 {
2600     return cppEngineType == GdbEngineType
2601         || cppEngineType == LldbEngineType
2602         || cppEngineType == CdbEngineType
2603         || cppEngineType == UvscEngineType;
2604 }
2605 
isNativeMixedDebugging() const2606 bool DebuggerRunParameters::isNativeMixedDebugging() const
2607 {
2608     return nativeMixedEnabled && isCppDebugging() && isQmlDebugging;
2609 }
2610 
formatStartParameters() const2611 QString DebuggerEngine::formatStartParameters() const
2612 {
2613     const DebuggerRunParameters &sp = d->m_runParameters;
2614     QString rc;
2615     QTextStream str(&rc);
2616     str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode
2617         << "\nABI: " << sp.toolChainAbi.toString() << '\n';
2618     str << "Languages: ";
2619     if (sp.isCppDebugging())
2620         str << "c++ ";
2621     if (sp.isQmlDebugging)
2622         str << "qml";
2623     str << '\n';
2624     if (!sp.inferior.executable.isEmpty()) {
2625         str << "Executable: " << sp.inferior.commandLine().toUserOutput();
2626         if (d->m_terminalRunner)
2627             str << " [terminal]";
2628         str << '\n';
2629         if (!sp.inferior.workingDirectory.isEmpty())
2630             str << "Directory: " << QDir::toNativeSeparators(sp.inferior.workingDirectory)
2631                 << '\n';
2632     }
2633     if (!sp.debugger.executable.isEmpty())
2634         str << "Debugger: " << sp.debugger.executable.toUserOutput() << '\n';
2635     if (!sp.coreFile.isEmpty())
2636         str << "Core: " << QDir::toNativeSeparators(sp.coreFile) << '\n';
2637     if (sp.attachPID.isValid())
2638         str << "PID: " << sp.attachPID.pid() << ' ' << sp.crashParameter << '\n';
2639     if (!sp.projectSourceDirectory.isEmpty()) {
2640         str << "Project: " << sp.projectSourceDirectory.toUserOutput() << '\n';
2641         str << "Additional Search Directories:";
2642         for (const FilePath &dir : sp.additionalSearchDirectories)
2643             str << ' ' << dir;
2644         str << '\n';
2645     }
2646     if (!sp.remoteChannel.isEmpty())
2647         str << "Remote: " << sp.remoteChannel << '\n';
2648     if (!sp.qmlServer.host().isEmpty())
2649         str << "QML server: " << sp.qmlServer.host() << ':' << sp.qmlServer.port() << '\n';
2650     str << "Sysroot: " << sp.sysRoot << '\n';
2651     str << "Debug Source Location: " << sp.debugSourceLocation.join(':') << '\n';
2652     return rc;
2653 }
2654 
createNewDock(QWidget * widget)2655 static void createNewDock(QWidget *widget)
2656 {
2657     auto dockWidget = new QDockWidget;
2658     dockWidget->setWidget(widget);
2659     dockWidget->setWindowTitle(widget->windowTitle());
2660     dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
2661     dockWidget->show();
2662 }
2663 
showModuleSymbols(const QString & moduleName,const Symbols & symbols)2664 void DebuggerEngine::showModuleSymbols(const QString &moduleName, const Symbols &symbols)
2665 {
2666     auto w = new QTreeWidget;
2667     w->setUniformRowHeights(true);
2668     w->setColumnCount(5);
2669     w->setRootIsDecorated(false);
2670     w->setAlternatingRowColors(true);
2671     w->setSortingEnabled(true);
2672     w->setObjectName("Symbols." + moduleName);
2673     QStringList header;
2674     header.append(tr("Symbol"));
2675     header.append(tr("Address"));
2676     header.append(tr("Code"));
2677     header.append(tr("Section"));
2678     header.append(tr("Name"));
2679     w->setHeaderLabels(header);
2680     w->setWindowTitle(tr("Symbols in \"%1\"").arg(moduleName));
2681     for (const Symbol &s : symbols) {
2682         auto it = new QTreeWidgetItem;
2683         it->setData(0, Qt::DisplayRole, s.name);
2684         it->setData(1, Qt::DisplayRole, s.address);
2685         it->setData(2, Qt::DisplayRole, s.state);
2686         it->setData(3, Qt::DisplayRole, s.section);
2687         it->setData(4, Qt::DisplayRole, s.demangled);
2688         w->addTopLevelItem(it);
2689     }
2690     createNewDock(w);
2691 }
2692 
showModuleSections(const QString & moduleName,const Sections & sections)2693 void DebuggerEngine::showModuleSections(const QString &moduleName, const Sections &sections)
2694 {
2695     auto w = new QTreeWidget;
2696     w->setUniformRowHeights(true);
2697     w->setColumnCount(5);
2698     w->setRootIsDecorated(false);
2699     w->setAlternatingRowColors(true);
2700     w->setSortingEnabled(true);
2701     w->setObjectName("Sections." + moduleName);
2702     QStringList header;
2703     header.append(tr("Name"));
2704     header.append(tr("From"));
2705     header.append(tr("To"));
2706     header.append(tr("Address"));
2707     header.append(tr("Flags"));
2708     w->setHeaderLabels(header);
2709     w->setWindowTitle(tr("Sections in \"%1\"").arg(moduleName));
2710     for (const Section &s : sections) {
2711         auto it = new QTreeWidgetItem;
2712         it->setData(0, Qt::DisplayRole, s.name);
2713         it->setData(1, Qt::DisplayRole, s.from);
2714         it->setData(2, Qt::DisplayRole, s.to);
2715         it->setData(3, Qt::DisplayRole, s.address);
2716         it->setData(4, Qt::DisplayRole, s.flags);
2717         w->addTopLevelItem(it);
2718     }
2719     createNewDock(w);
2720 }
2721 
2722 // CppDebuggerEngine
2723 
languageContext() const2724 Context CppDebuggerEngine::languageContext() const
2725 {
2726     return Context(Constants::C_CPPDEBUGGER);
2727 }
2728 
validateRunParameters(DebuggerRunParameters & rp)2729 void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
2730 {
2731     const bool warnOnRelease = debuggerSettings()->warnOnReleaseBuilds.value()
2732                                && rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor;
2733     bool warnOnInappropriateDebugger = false;
2734     QString detailedWarning;
2735     switch (rp.toolChainAbi.binaryFormat()) {
2736     case Abi::PEFormat: {
2737         QString preferredDebugger;
2738         if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) {
2739             if (rp.cppEngineType == CdbEngineType)
2740                 preferredDebugger = "GDB";
2741         } else if (rp.cppEngineType != CdbEngineType) {
2742             // osFlavor() is MSVC, so the recommended debugger is CDB
2743             preferredDebugger = "CDB";
2744         }
2745         if (!preferredDebugger.isEmpty()) {
2746             warnOnInappropriateDebugger = true;
2747             detailedWarning = DebuggerEngine::tr(
2748                         "The inferior is in the Portable Executable format.\n"
2749                         "Selecting %1 as debugger would improve the debugging "
2750                         "experience for this binary format.").arg(preferredDebugger);
2751             break;
2752         }
2753         if (warnOnRelease
2754                 && rp.cppEngineType == CdbEngineType
2755                 && rp.startMode != AttachToRemoteServer) {
2756             QTC_ASSERT(!rp.symbolFile.isEmpty(), return);
2757             if (!rp.symbolFile.exists() && !rp.symbolFile.endsWith(".exe"))
2758                 rp.symbolFile = rp.symbolFile.stringAppended(".exe");
2759             QString errorMessage;
2760             QStringList rc;
2761             if (getPDBFiles(rp.symbolFile.toString(), &rc, &errorMessage) && !rc.isEmpty())
2762                 return;
2763             if (!errorMessage.isEmpty()) {
2764                 detailedWarning.append('\n');
2765                 detailedWarning.append(errorMessage);
2766             }
2767         } else {
2768             return;
2769         }
2770         break;
2771     }
2772     case Abi::ElfFormat: {
2773         if (rp.cppEngineType == CdbEngineType) {
2774             warnOnInappropriateDebugger = true;
2775             detailedWarning = DebuggerEngine::tr(
2776                         "The inferior is in the ELF format.\n"
2777                         "Selecting GDB or LLDB as debugger would improve the debugging "
2778                         "experience for this binary format.");
2779             break;
2780         }
2781 
2782         Utils::ElfReader reader(rp.symbolFile.toString());
2783         const ElfData elfData = reader.readHeaders();
2784         const QString error = reader.errorString();
2785 
2786         showMessage("EXAMINING " + rp.symbolFile.toString(), LogDebug);
2787         QByteArray msg = "ELF SECTIONS: ";
2788 
2789         static const QList<QByteArray> interesting = {
2790             ".debug_info",
2791             ".debug_abbrev",
2792             ".debug_line",
2793             ".debug_str",
2794             ".debug_loc",
2795             ".debug_range",
2796             ".gdb_index",
2797             ".note.gnu.build-id",
2798             ".gnu.hash",
2799             ".gnu_debuglink"
2800         };
2801 
2802         QSet<QByteArray> seen;
2803         for (const ElfSectionHeader &header : elfData.sectionHeaders) {
2804             msg.append(header.name);
2805             msg.append(' ');
2806             if (interesting.contains(header.name))
2807                 seen.insert(header.name);
2808         }
2809         showMessage(QString::fromUtf8(msg), LogDebug);
2810 
2811         if (!error.isEmpty()) {
2812             showMessage("ERROR WHILE READING ELF SECTIONS: " + error, LogDebug);
2813             return;
2814         }
2815 
2816         if (elfData.sectionHeaders.isEmpty()) {
2817             showMessage("NO SECTION HEADERS FOUND. IS THIS AN EXECUTABLE?", LogDebug);
2818             return;
2819         }
2820 
2821         // Note: .note.gnu.build-id also appears in regular release builds.
2822         // bool hasBuildId = elfData.indexOf(".note.gnu.build-id") >= 0;
2823         bool hasEmbeddedInfo = elfData.indexOf(".debug_info") >= 0;
2824         bool hasLink = elfData.indexOf(".gnu_debuglink") >= 0;
2825         if (hasEmbeddedInfo) {
2826             const SourcePathMap sourcePathMap = debuggerSettings()->sourcePathMap.value();
2827             QList<QPair<QRegularExpression, QString>> globalRegExpSourceMap;
2828             globalRegExpSourceMap.reserve(sourcePathMap.size());
2829             for (auto it = sourcePathMap.begin(), end = sourcePathMap.end(); it != end; ++it) {
2830                 if (it.key().startsWith('(')) {
2831                     const QString expanded = Utils::globalMacroExpander()->expand(it.value());
2832                     if (!expanded.isEmpty())
2833                         globalRegExpSourceMap.push_back(
2834                             qMakePair(QRegularExpression(it.key()), expanded));
2835                 }
2836             }
2837             if (globalRegExpSourceMap.isEmpty())
2838                 return;
2839             if (QSharedPointer<Utils::ElfMapper> mapper = reader.readSection(".debug_str")) {
2840                 const char *str = mapper->start;
2841                 const char *limit = str + mapper->fdlen;
2842                 bool found = false;
2843                 while (str < limit) {
2844                     const QString string = QString::fromUtf8(str);
2845                     for (auto pair : qAsConst(globalRegExpSourceMap)) {
2846                         const QRegularExpressionMatch match = pair.first.match(string);
2847                         if (match.hasMatch()) {
2848                             rp.sourcePathMap.insert(string.left(match.capturedStart()) + match.captured(1),
2849                                                     pair.second);
2850                             found = true;
2851                             break;
2852                         }
2853                     }
2854                     if (found)
2855                         break;
2856 
2857                     const int len = int(strlen(str));
2858                     if (len == 0)
2859                         break;
2860                     str += len + 1;
2861                 }
2862             }
2863         }
2864         if (hasEmbeddedInfo || hasLink)
2865             return;
2866 
2867         for (const QByteArray &name : qAsConst(interesting)) {
2868             const QString found = seen.contains(name) ? DebuggerEngine::tr("Found.")
2869                                                       : DebuggerEngine::tr("Not found.");
2870             detailedWarning.append('\n' + DebuggerEngine::tr("Section %1: %2").arg(QString::fromUtf8(name)).arg(found));
2871         }
2872         break;
2873     }
2874     default:
2875         return;
2876     }
2877     if (warnOnInappropriateDebugger) {
2878         AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"),
2879                 DebuggerEngine::tr("The selected debugger may be inappropriate for the inferior.\n"
2880                    "Examining symbols and setting breakpoints by file name and line number "
2881                    "may fail.\n")
2882                + '\n' + detailedWarning);
2883     } else if (warnOnRelease) {
2884         AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"),
2885                DebuggerEngine::tr("This does not seem to be a \"Debug\" build.\n"
2886                   "Setting breakpoints by file name and line number may fail.")
2887                + '\n' + detailedWarning);
2888     }
2889 }
2890 
2891 } // namespace Internal
2892 } // namespace Debugger
2893 
2894 #include "debuggerengine.moc"
2895