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 §ions)
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