debuggerplugin.cpp 142 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8 9 10 11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
con's avatar
con committed
23
**
hjk's avatar
hjk committed
24
****************************************************************************/
hjk's avatar
hjk committed
25

con's avatar
con committed
26 27
#include "debuggerplugin.h"

28
#include "debuggermainwindow.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
29
#include "debuggerstartparameters.h"
30
#include "debuggeractions.h"
31
#include "debuggerinternalconstants.h"
32
#include "debuggercore.h"
33
#include "debuggerkitconfigwidget.h"
34 35
#include "debuggerdialogs.h"
#include "debuggerengine.h"
36
#include "debuggericons.h"
37
#include "debuggeritem.h"
38
#include "debuggeritemmanager.h"
39
#include "debuggermainwindow.h"
40
#include "debuggerrunconfigurationaspect.h"
41
#include "debuggerruncontrol.h"
42
#include "debuggerstringutils.h"
43
#include "debuggeroptionspage.h"
Tobias Hunger's avatar
Tobias Hunger committed
44
#include "debuggerkitinformation.h"
45
#include "memoryagent.h"
46
#include "breakhandler.h"
47
#include "breakwindow.h"
48
#include "disassemblerlines.h"
49
#include "logwindow.h"
50
#include "moduleswindow.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
51
#include "moduleshandler.h"
52 53
#include "registerwindow.h"
#include "snapshotwindow.h"
hjk's avatar
hjk committed
54
#include "stackhandler.h"
55 56 57
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
hjk's avatar
hjk committed
58
#include "watchhandler.h"
59
#include "watchwindow.h"
hjk's avatar
hjk committed
60
#include "watchutils.h"
61
#include "unstartedappwatcherdialog.h"
62
#include "debuggertooltipmanager.h"
63
#include "localsandexpressionswindow.h"
64
#include "loadcoredialog.h"
65
#include "sourceutils.h"
hjk's avatar
hjk committed
66 67
#include "shared/hostutils.h"
#include "console/console.h"
68

69 70
#include "snapshothandler.h"
#include "threadshandler.h"
71
#include "commonoptionspage.h"
72
#include "gdb/startgdbserverdialog.h"
con's avatar
con committed
73

hjk's avatar
hjk committed
74
#include "analyzer/analyzerconstants.h"
75
#include "analyzer/analyzericons.h"
hjk's avatar
hjk committed
76
#include "analyzer/analyzermanager.h"
77 78
#include "analyzer/analyzerruncontrol.h"
#include "analyzer/analyzerstartparameters.h"
hjk's avatar
hjk committed
79

80
#include <coreplugin/actionmanager/actioncontainer.h>
81
#include <coreplugin/actionmanager/actionmanager.h>
82
#include <coreplugin/actionmanager/command.h>
83
#include <coreplugin/coreconstants.h>
84
#include <coreplugin/coreicons.h>
85 86 87
#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/find/itemviewfind.h>
con's avatar
con committed
88
#include <coreplugin/icore.h>
89
#include <coreplugin/imode.h>
90
#include <coreplugin/messagebox.h>
91
#include <coreplugin/messagemanager.h>
con's avatar
con committed
92
#include <coreplugin/modemanager.h>
93
#include <coreplugin/modemanager.h>
94 95 96
#include <coreplugin/navigationwidget.h>
#include <coreplugin/outputpane.h>
#include <coreplugin/rightpane.h>
hjk's avatar
hjk committed
97

con's avatar
con committed
98
#include <cppeditor/cppeditorconstants.h>
99
#include <cpptools/cppmodelmanager.h>
hjk's avatar
hjk committed
100

101
#include <projectexplorer/buildconfiguration.h>
102
#include <projectexplorer/buildmanager.h>
103
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
104 105
#include <projectexplorer/devicesupport/deviceprocesslist.h>
#include <projectexplorer/project.h>
106
#include <projectexplorer/projectexplorer.h>
107
#include <projectexplorer/projectexplorericons.h>
108
#include <projectexplorer/projectexplorersettings.h>
109
#include <projectexplorer/projecttree.h>
110
#include <projectexplorer/runconfiguration.h>
111
#include <projectexplorer/runnables.h>
con's avatar
con committed
112
#include <projectexplorer/session.h>
113
#include <projectexplorer/target.h>
114 115
#include <projectexplorer/taskhub.h>
#include <projectexplorer/toolchain.h>
116

117
#include <texteditor/texteditor.h>
118
#include <texteditor/textdocument.h>
119
#include <texteditor/fontsettings.h>
120
#include <texteditor/texteditorsettings.h>
hjk's avatar
hjk committed
121

122 123
#include <utils/algorithm.h>
#include <utils/appmainwindow.h>
124
#include <utils/basetreeview.h>
125
#include <utils/checkablemessagebox.h>
126
#include <utils/fancymainwindow.h>
127
#include <utils/hostosinfo.h>
Eike Ziller's avatar
Eike Ziller committed
128
#include <utils/mimetypes/mimedatabase.h>
129
#include <utils/proxyaction.h>
130 131
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
132
#include <utils/statuslabel.h>
133
#include <utils/styledbar.h>
hjk's avatar
hjk committed
134
#include <utils/winutils.h>
con's avatar
con committed
135

136
#include <QAction>
Campbell Barton's avatar
Campbell Barton committed
137
#include <QApplication>
hjk's avatar
hjk committed
138
#include <QCheckBox>
139
#include <QComboBox>
140
#include <QDebug>
141 142
#include <QDialog>
#include <QDialogButtonBox>
143 144
#include <QDockWidget>
#include <QFileDialog>
hjk's avatar
hjk committed
145 146
#include <QHBoxLayout>
#include <QHeaderView>
hjk's avatar
hjk committed
147
#include <QInputDialog>
148
#include <QMenu>
149
#include <QMessageBox>
150 151 152
#include <QPointer>
#include <QPushButton>
#include <QSettings>
153
#include <QStackedWidget>
154 155 156
#include <QTextBlock>
#include <QToolButton>
#include <QTreeWidget>
157
#include <QVBoxLayout>
158
#include <QVariant>
159
#include <QtPlugin>
160

hjk's avatar
hjk committed
161
#ifdef WITH_TESTS
162 163 164 165

#include <cpptools/cpptoolstestcase.h>
#include <cpptools/projectinfo.h>

166 167
#include <utils/executeondestruction.h>

168 169 170
#include <QTest>
#include <QSignalSpy>
#include <QTestEventLoop>
171 172 173 174

//#define WITH_BENCHMARK
#ifdef WITH_BENCHMARK
#include <valgrind/callgrind.h>
hjk's avatar
hjk committed
175 176
#endif

177 178
#endif // WITH_TESTS

179 180
#include <climits>

181 182 183 184 185
#define DEBUG_STATE 1
#ifdef DEBUG_STATE
//#   define STATE_DEBUG(s)
//    do { QString msg; QTextStream ts(&msg); ts << s;
//      showMessage(msg, LogDebug); } while (0)
186
#   define STATE_DEBUG(s) do { qDebug() << s; } while (0)
187 188 189 190
#else
#   define STATE_DEBUG(s)
#endif

191 192 193 194 195 196 197 198
/*!
    \namespace Debugger
    Debugger plugin namespace
*/

/*!
    \namespace Debugger::Internal
    Internal namespace of the Debugger plugin
199
    \internal
200 201 202 203 204
*/

/*!
    \class Debugger::DebuggerEngine

205
    \brief The DebuggerEngine class is the base class of a debugger engine.
206

Leena Miettinen's avatar
Leena Miettinen committed
207
    \note The Debugger process itself and any helper processes like
208 209
    gdbserver are referred to as 'Engine', whereas the debugged process
    is referred to as 'Inferior'.
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307

    Transitions marked by '---' are done in the individual engines.
    Transitions marked by '+-+' are done in the base DebuggerEngine.
    Transitions marked by '*' are done asynchronously.

    The GdbEngine->setupEngine() function is described in more detail below.

    The engines are responsible for local roll-back to the last
    acknowledged state before calling notify*Failed. I.e. before calling
    notifyEngineSetupFailed() any process started during setupEngine()
    so far must be terminated.
    \code

                        DebuggerNotReady
                         progressmanager/progressmanager.cpp      +
                      EngineSetupRequested
                               +
                  (calls *Engine->setupEngine())
                            |      |
                            |      |
                       {notify-  {notify-
                        Engine-   Engine-
                        SetupOk}  SetupFailed}
                            +      +
                            +      `+-+-+> EngineSetupFailed
                            +                   +
                            +    [calls RunControl->startFailed]
                            +                   +
                            +             DebuggerFinished
                            v
                      EngineSetupOk
                            +
             [calls RunControl->StartSuccessful]
                            +
                  InferiorSetupRequested
                            +
             (calls *Engine->setupInferior())
                         |       |
                         |       |
                    {notify-   {notify-
                     Inferior- Inferior-
                     SetupOk}  SetupFailed}
                         +       +
                         +       ` +-+-> InferiorSetupFailed +-+-+-+-+-+->.
                         +                                                +
                  InferiorSetupOk                                         +
                         +                                                +
                  EngineRunRequested                                      +
                         +                                                +
                 (calls *Engine->runEngine())                             +
               /       |            |        \                            +
             /         |            |          \                          +
            | (core)   | (attach)   |           |                         +
            |          |            |           |                         +
      {notify-    {notifyER&- {notifyER&-  {notify-                       +
      Inferior-     Inferior-   Inferior-  EngineRun-                     +
     Unrunnable}     StopOk}     RunOk}     Failed}                       +
           +           +            +           +                         +
   InferiorUnrunnable  +     InferiorRunOk      +                         +
                       +                        +                         +
                InferiorStopOk            EngineRunFailed                 +
                                                +                         v
                                                 `-+-+-+-+-+-+-+-+-+-+-+>-+
                                                                          +
                                                                          +
                       #Interrupt@InferiorRunOk#                          +
                                  +                                       +
                          InferiorStopRequested                           +
  #SpontaneousStop                +                                       +
   @InferiorRunOk#         (calls *Engine->                               +
          +               interruptInferior())                            +
      {notify-               |          |                                 +
     Spontaneous-       {notify-    {notify-                              +
      Inferior-          Inferior-   Inferior-                            +
       StopOk}           StopOk}    StopFailed}                           +
           +              +             +                                 +
            +            +              +                                 +
            InferiorStopOk              +                                 +
                  +                     +                                 +
                  +                    +                                  +
                  +                   +                                   +
        #Stop@InferiorUnrunnable#    +                                    +
          #Creator Close Event#     +                                     +
                       +           +                                      +
                InferiorShutdownRequested                                 +
                            +                                             +
           (calls *Engine->shutdownInferior())                            +
                         |        |                                       +
                    {notify-   {notify-                                   +
                     Inferior- Inferior-                                  +
                  ShutdownOk}  ShutdownFailed}                            +
                         +        +                                       +
                         +        +                                       +
  #Inferior exited#      +        +                                       +
         |               +        +                                       +
   {notifyInferior-      +        +                                       +
      Exited}            +        +                                       +
           +             +        +                                       +
308
            +            +        +                                       +
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
             +           +        +                                       +
            InferiorShutdownOk InferiorShutdownFailed                     +
                      *          *                                        +
                  EngineShutdownRequested                                 +
                            +                                             +
           (calls *Engine->shutdownEngine())  <+-+-+-+-+-+-+-+-+-+-+-+-+-+'
                         |        |
                         |        |
                    {notify-   {notify-
                     Engine-    Engine-
                  ShutdownOk}  ShutdownFailed}
                         +       +
            EngineShutdownOk  EngineShutdownFailed
                         *       *
                     DebuggerFinished

\endcode */
hjk's avatar
hjk committed
326

327 328 329
/* Here is a matching graph as a GraphViz graph. View it using
 * \code
grep "^sg1:" debuggerplugin.cpp | cut -c5- | dot -osg1.ps -Tps && gv sg1.ps
330

331 332 333 334 335 336
sg1: digraph DebuggerStates {
sg1:   DebuggerNotReady -> EngineSetupRequested
sg1:   EngineSetupRequested -> EngineSetupOk [ label="notifyEngineSetupOk", style="dashed" ];
sg1:   EngineSetupRequested -> EngineSetupFailed [ label= "notifyEngineSetupFailed", style="dashed"];
sg1:   EngineSetupFailed -> DebuggerFinished [ label= "RunControl::StartFailed" ];
sg1:   EngineSetupOk -> InferiorSetupRequested [ label= "RunControl::StartSuccessful" ];
337
sg1:   InferiorSetupRequested -> InferiorSetupOk [ label="notifyInferiorSetupOk", style="dashed" ];
338
sg1:   InferiorSetupRequested -> InferiorSetupFailed [ label="notifyInferiorFailed", style="dashed" ];
339
sg1:   InferiorSetupOk -> EngineRunRequested
340 341 342 343 344 345 346 347 348 349 350 351 352 353
sg1:   InferiorSetupFailed -> EngineShutdownRequested
sg1:   EngineRunRequested -> InferiorUnrunnable [ label="notifyInferiorUnrunnable", style="dashed" ];
sg1:   EngineRunRequested -> InferiorStopOk [ label="notifyEngineRunAndInferiorStopOk", style="dashed" ];
sg1:   EngineRunRequested -> InferiorRunOk [ label="notifyEngineRunAndInferiorRunOk", style="dashed" ];
sg1:   EngineRunRequested -> EngineRunFailed [ label="notifyEngineRunFailed", style="dashed" ];
sg1:   EngineRunFailed -> EngineShutdownRequested
sg1:   InferiorRunOk -> InferiorStopOk [ label="SpontaneousStop\nnotifyInferiorSpontaneousStop", style="dashed" ];
sg1:   InferiorRunOk -> InferiorStopRequested [ label="User stop\nEngine::interruptInferior", style="dashed"];
sg1:   InferiorStopRequested -> InferiorStopOk [ label="notifyInferiorStopOk", style="dashed" ];
sg1:   InferiorStopRequested -> InferiorShutdownRequested  [ label="notifyInferiorStopFailed", style="dashed" ];
sg1:   InferiorStopOk -> InferiorRunRequested [ label="User\nEngine::continueInferior" ];
sg1:   InferiorRunRequested -> InferiorRunOk [ label="notifyInferiorRunOk", style="dashed"];
sg1:   InferiorRunRequested -> InferiorRunFailed [ label="notifyInferiorRunFailed", style="dashed"];
sg1:   InferiorRunFailed -> InferiorStopOk
354 355
sg1:   InferiorStopOk -> InferiorShutdownRequested [ label="Close event" ];
sg1:   InferiorUnrunnable -> InferiorShutdownRequested [ label="Close event" ];
356 357
sg1:   InferiorShutdownRequested -> InferiorShutdownOk [ label= "Engine::shutdownInferior\nnotifyInferiorShutdownOk", style="dashed" ];
sg1:   InferiorShutdownRequested -> InferiorShutdownFailed [ label="Engine::shutdownInferior\nnotifyInferiorShutdownFailed", style="dashed" ];
358 359
sg1:   InferiorExited -> InferiorExitOk [ label="notifyInferiorExited", style="dashed"];
sg1:   InferiorExitOk -> InferiorShutdownOk
360 361 362 363 364 365 366 367
sg1:   InferiorShutdownOk -> EngineShutdownRequested
sg1:   InferiorShutdownFailed -> EngineShutdownRequested
sg1:   EngineShutdownRequested -> EngineShutdownOk [ label="Engine::shutdownEngine\nnotifyEngineShutdownOk", style="dashed" ];
sg1:   EngineShutdownRequested -> EngineShutdownFailed  [ label="Engine::shutdownEngine\nnotifyEngineShutdownFailed", style="dashed" ];
sg1:   EngineShutdownOk -> DebuggerFinished  [ style = "dotted" ];
sg1:   EngineShutdownFailed  -> DebuggerFinished [ style = "dotted" ];
sg1: }
* \endcode */
hjk's avatar
hjk committed
368
// Additional signalling:    {notifyInferiorIll}   {notifyEngineIll}
hjk's avatar
hjk committed
369 370


371 372
/*!
    \class Debugger::Internal::GdbEngine
373 374
    \brief The GdbEngine class implements Debugger::Engine driving a GDB
    executable.
375 376 377

    GdbEngine specific startup. All happens in EngineSetupRequested state:

Leena Miettinen's avatar
Leena Miettinen committed
378 379
    \list
        \li Transitions marked by '---' are done in the individual adapters.
380

Leena Miettinen's avatar
Leena Miettinen committed
381 382
        \li Transitions marked by '+-+' are done in the GdbEngine.
    \endlist
383 384 385 386 387 388 389 390 391 392 393 394 395

    \code
                  GdbEngine::setupEngine()
                          +
            (calls *Adapter->startAdapter())
                          |      |
                          |      `---> handleAdapterStartFailed()
                          |                   +
                          |             {notifyEngineSetupFailed}
                          |
                 handleAdapterStarted()
                          +
                 {notifyEngineSetupOk}
396 397 398



399 400 401 402 403 404 405 406 407 408 409
                GdbEngine::setupInferior()
                          +
            (calls *Adapter->prepareInferior())
                          |      |
                          |      `---> handlePrepareInferiorFailed()
                          |                   +
                          |             {notifyInferiorSetupFailed}
                          |
                handleInferiorPrepared()
                          +
                {notifyInferiorSetupOk}
410

411
\endcode */
412

con's avatar
con committed
413
using namespace Core;
414
using namespace Core::Constants;
hjk's avatar
hjk committed
415
using namespace Debugger::Constants;
416
using namespace Debugger::Internal;
417
using namespace ExtensionSystem;
con's avatar
con committed
418
using namespace ProjectExplorer;
hjk's avatar
hjk committed
419
using namespace TextEditor;
420
using namespace Utils;
con's avatar
con committed
421

hjk's avatar
hjk committed
422 423 424
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
425
namespace Debugger {
426 427
namespace Internal {

428
void addCdbOptionPages(QList<IOptionsPage*> *opts);
429
void addGdbOptionPages(QList<IOptionsPage*> *opts);
430
QObject *createDebuggerRunControlFactory(QObject *parent);
431

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
static QIcon visibleStartIcon(Id id, bool toolBarStyle)
{
    if (id == Id(Constants::DEBUG)) {
        const static QIcon sidebarIcon =
                Icon::sideBarIcon(ProjectExplorer::Icons::DEBUG_START, ProjectExplorer::Icons::DEBUG_START_FLAT);
        const static QIcon icon =
                Icon::combinedIcon({ProjectExplorer::Icons::DEBUG_START_SMALL.icon(), sidebarIcon});
        const static QIcon iconToolBar =
                Icon::combinedIcon({ProjectExplorer::Icons::DEBUG_START_SMALL_TOOLBAR.icon(), sidebarIcon});
        return toolBarStyle ? iconToolBar : icon;
    } else if (id == Id(Constants::CONTINUE)) {
        const static QIcon sidebarIcon =
                Icon::sideBarIcon(Icons::CONTINUE, Icons::CONTINUE_FLAT);
        const static QIcon icon =
                Icon::combinedIcon({Icons::DEBUG_CONTINUE_SMALL.icon(), sidebarIcon});
        const static QIcon iconToolBar =
                Icon::combinedIcon({Icons::DEBUG_CONTINUE_SMALL_TOOLBAR.icon(), sidebarIcon});
        return toolBarStyle ? iconToolBar : icon;
    } else if (id == Id(Constants::INTERRUPT)) {
        const static QIcon sidebarIcon =
                Icon::sideBarIcon(Icons::INTERRUPT, Icons::INTERRUPT_FLAT);
        const static QIcon icon =
                Icon::combinedIcon({Icons::DEBUG_INTERRUPT_SMALL.icon(), sidebarIcon});
        const static QIcon iconToolBar =
                Icon::combinedIcon({Icons::DEBUG_INTERRUPT_SMALL_TOOLBAR.icon(), sidebarIcon});
        return toolBarStyle ? iconToolBar : icon;
    }
    return QIcon();
}

462
static void setProxyAction(ProxyAction *proxy, Id id)
463
{
hjk's avatar
hjk committed
464
    proxy->setAction(ActionManager::command(id)->action());
465
    proxy->setIcon(visibleStartIcon(id, true));
466 467
}

468 469 470 471 472 473 474 475 476
///////////////////////////////////////////////////////////////////////
//
// DummyEngine
//
///////////////////////////////////////////////////////////////////////

class DummyEngine : public DebuggerEngine
{
public:
477
    DummyEngine() : DebuggerEngine(DebuggerRunParameters()) {}
478 479 480 481 482 483 484 485 486 487 488
    ~DummyEngine() override {}

    void setupEngine() override {}
    void setupInferior() override {}
    void runEngine() override {}
    void shutdownEngine() override {}
    void shutdownInferior() override {}
    bool hasCapability(unsigned cap) const override;
    bool acceptsBreakpoint(Breakpoint) const override { return false; }
    bool acceptsDebuggerCommands() const override { return false; }
    void selectThread(ThreadId) override {}
489 490
};

491
bool DummyEngine::hasCapability(unsigned cap) const
492 493
{
    // This can only be a first approximation of what to expect when running.
494
    Project *project = ProjectTree::currentProject();
495 496 497 498 499 500 501 502
    if (!project)
        return 0;
    Target *target = project->activeTarget();
    QTC_ASSERT(target, return 0);
    RunConfiguration *activeRc = target->activeRunConfiguration();
    QTC_ASSERT(activeRc, return 0);

    // This is a non-started Cdb or Gdb engine:
503
    if (activeRc->extraAspect<Debugger::DebuggerRunConfigurationAspect>()->useCppDebugger())
504
        return cap & (WatchpointByAddressCapability
505 506
               | BreakConditionCapability
               | TracePointCapability
507
               | OperateByInstructionCapability);
508 509

    // This is a Qml or unknown engine.
510
    return cap & AddWatcherCapability;
511 512
}

513 514 515 516 517 518
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

519 520 521
class DebugModeContext : public IContext
{
public:
522
    DebugModeContext(QWidget *modeWindow)
523 524
    {
        setContext(Context(CC::C_EDITORMANAGER));
525
        setWidget(modeWindow);
526 527 528 529
        ICore::addContextObject(this);
    }
};

530
class DebugMode : public IMode
hjk's avatar
hjk committed
531 532
{
public:
533
    DebugMode()
534 535
    {
        setObjectName(QLatin1String("DebugMode"));
536
        setContext(Context(C_DEBUGMODE, CC::C_NAVIGATION_PANE));
537
        setDisplayName(DebuggerPlugin::tr("Debug"));
538 539
        setIcon(Utils::Icon::modeIcon(Icons::MODE_DEBUGGER_CLASSIC,
                                      Icons::MODE_DEBUGGER_FLAT, Icons::MODE_DEBUGGER_FLAT_ACTIVE));
540
        setPriority(85);
541
        setId(MODE_DEBUG);
542
    }
543
};
hjk's avatar
hjk committed
544

545 546 547 548 549 550
///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

551
static QWidget *addSearch(BaseTreeView *treeView, const QString &title,
552
    const char *objectName)
553
{
hjk's avatar
hjk committed
554
    QAction *act = action(UseAlternatingRowColors);
555
    treeView->setAlternatingRowColors(act->isChecked());
556 557
    QObject::connect(act, &QAction::toggled,
                     treeView, &BaseTreeView::setAlternatingRowColorsHelper);
558

Daniel Teske's avatar
Daniel Teske committed
559
    QWidget *widget = ItemViewFind::createSearchableWrapper(treeView);
560 561 562 563 564
    widget->setObjectName(QLatin1String(objectName));
    widget->setWindowTitle(title);
    return widget;
}

565
static std::function<bool(const Kit *)> cdbMatcher(char wordWidth = 0)
566
{
567
    return [wordWidth](const Kit *k) -> bool {
568 569
        if (DebuggerKitInformation::engineType(k) != CdbEngineType
            || !DebuggerKitInformation::isValidDebugger(k)) {
570
            return false;
571
        }
572
        if (wordWidth) {
573
            const ToolChain *tc = ToolChainKitInformation::toolChain(k);
574
            return tc && wordWidth == tc->targetAbi().wordWidth();
575
        }
576
        return true;
577 578
    };
}
579

580 581 582 583 584
// Find a CDB kit for debugging unknown processes.
// On a 64bit OS, prefer a 64bit debugger.
static Kit *findUniversalCdbKit()
{
    if (Utils::is64BitWindowsSystem()) {
Tobias Hunger's avatar
Tobias Hunger committed
585
        if (Kit *cdb64Kit = KitManager::find(KitMatcher(cdbMatcher(64))))
586
            return cdb64Kit;
587
    }
Tobias Hunger's avatar
Tobias Hunger committed
588
    return KitManager::find(KitMatcher(cdbMatcher()));
589
}
590

591 592
///////////////////////////////////////////////////////////////////////
//
593
// DebuggerPluginPrivate
594 595
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
596

597
static DebuggerPluginPrivate *dd = 0;
con's avatar
con committed
598

599 600 601 602
//class DockWidgetEventFilter : public QObject
//{
//public:
//    DockWidgetEventFilter() {}
603

604 605 606
//private:
//    bool eventFilter(QObject *obj, QEvent *event) override;
//};
607

608 609 610 611 612 613 614 615 616 617 618 619 620 621
/*!
    \class Debugger::Internal::DebuggerCore

    This is the "internal" interface of the debugger plugin that's
    used by debugger views and debugger engines. The interface is
    implemented in DebuggerPluginPrivate.
*/

/*!
    \class Debugger::Internal::DebuggerPluginPrivate

    Implementation of DebuggerCore.
*/

622
class DebuggerPluginPrivate : public QObject
623 624
{
    Q_OBJECT
625

626 627
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
628
    ~DebuggerPluginPrivate();
629

630
    bool initialize(const QStringList &arguments, QString *errorMessage);
631 632 633
    void extensionsInitialized();
    void aboutToShutdown();

634
    void connectEngine(DebuggerEngine *engine);
hjk's avatar
hjk committed
635
    void disconnectEngine() { connectEngine(0); }
636
    DebuggerEngine *dummyEngine();
637

hjk's avatar
hjk committed
638
    void setThreadBoxContents(const QStringList &list, int index)
639 640 641 642 643 644 645 646
    {
        const bool state = m_threadBox->blockSignals(true);
        m_threadBox->clear();
        foreach (const QString &item, list)
            m_threadBox->addItem(item);
        m_threadBox->setCurrentIndex(index);
        m_threadBox->blockSignals(state);
    }
647 648

    DebuggerRunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process, bool contAfterAttach);
649

650 651 652
    void writeSettings()
    {
        m_debuggerSettings->writeSettings();
653
//        writeWindowSettings();
654 655
    }

656 657
    void selectThread(int index)
    {
hjk's avatar
hjk committed
658 659
        ThreadId id = m_currentEngine->threadsHandler()->threadAt(index);
        m_currentEngine->selectThread(id);
660
    }
661

662
    void breakpointSetMarginActionTriggered(bool isMessageOnly, const ContextData &data)
663
    {
664
        QString message;
665
        if (isMessageOnly) {
666
            if (data.type == LocationByAddress) {
667 668 669 670
                //: Message tracepoint: Address hit.
                message = tr("0x%1 hit").arg(data.address, 0, 16);
            } else {
                //: Message tracepoint: %1 file, %2 line %3 function hit.
671
                message = tr("%1:%2 %3() hit").arg(FileName::fromString(data.fileName).fileName()).
672 673 674 675 676
                        arg(data.lineNumber).
                        arg(cppFunctionAt(data.fileName, data.lineNumber));
            }
            QInputDialog dialog; // Create wide input dialog.
            dialog.setWindowFlags(dialog.windowFlags()
hjk's avatar
hjk committed
677
              & ~(Qt::WindowContextHelpButtonHint|Qt::MSWindowsFixedSizeDialogHint));
678 679 680 681 682 683 684 685
            dialog.resize(600, dialog.height());
            dialog.setWindowTitle(tr("Add Message Tracepoint"));
            dialog.setLabelText (tr("Message:"));
            dialog.setTextValue(message);
            if (dialog.exec() != QDialog::Accepted || dialog.textValue().isEmpty())
                return;
            message = dialog.textValue();
        }
686
        toggleBreakpoint(data, message);
687
    }
688

689
    void updateWatchersHeader(int section, int, int newSize)
690
    {
691 692 693
        if (m_shuttingDown)
            return;

694 695
        m_watchersView->header()->resizeSection(section, newSize);
        m_returnView->header()->resizeSection(section, newSize);
696
    }
697

698 699
    void synchronizeBreakpoints()
    {
700
        showMessage(QLatin1String("ATTEMPT SYNC"), LogDebug);
701
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
702
            if (DebuggerEngine *engine = m_snapshotHandler->at(i))
703 704 705 706
                engine->attemptBreakpointSynchronization();
        }
    }

707 708
    void editorOpened(IEditor *editor);
    void updateBreakMenuItem(IEditor *editor);
709
    void setBusyCursor(bool busy);
710 711 712
    void requestMark(TextEditorWidget *widget, int lineNumber,
                     TextMarkRequestKind kind);
    void requestContextMenu(TextEditorWidget *widget,
713
                            int lineNumber, QMenu *menu);
714

715 716
    void activatePreviousMode();
    void activateDebugMode();
717 718
    void toggleBreakpointHelper();
    void toggleBreakpoint(const ContextData &location, const QString &tracePointMessage = QString());
hjk's avatar
hjk committed
719
    void onModeChanged(Id mode);
720
    void updateDebugWithoutDeployMenu();
721

722
    void startAndDebugApplication();
723
    void startRemoteCdbSession();
724
    void startRemoteServerAndAttachToProcess();
725
    void attachToRemoteServer();
hjk's avatar
hjk committed
726
    void attachToRunningApplication();
727
    void attachToUnstartedApplicationDialog();
728
    void attachToQmlPort();
729
    void runScheduled();
730
    void attachCore();
731

732
    void enableReverseDebuggingTriggered(const QVariant &value);
733
    void showStatusMessage(const QString &msg, int timeout = -1);
734

735 736
    void runControlStarted(DebuggerEngine *engine);
    void runControlFinished(DebuggerEngine *engine);
737
    void remoteCommand(const QStringList &options);
738

739
    void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
740 741 742

    void dumpLog();
    void cleanupViews();
743
    void setInitialState();
744

745
    void fontSettingsChanged(const FontSettings &settings);
746 747

    void updateState(DebuggerEngine *engine);
748
    void onCurrentProjectChanged(Project *project);
749 750 751 752

    void sessionLoaded();
    void aboutToUnloadSession();
    void aboutToSaveSession();
753

754
    void coreShutdown();
755

756
public:
757
    void updateDebugActions();
758 759 760

    void handleExecDetach()
    {
761
        currentEngine()->resetLocation();
762 763 764 765 766
        currentEngine()->detachDebugger();
    }

    void handleExecContinue()
    {
767
        currentEngine()->resetLocation();
768 769 770 771 772
        currentEngine()->continueInferior();
    }

    void handleExecInterrupt()
    {
773
        currentEngine()->resetLocation();
774 775 776
        currentEngine()->requestInterruptInferior();
    }

777
    void handleAbort()
778
    {
779
        currentEngine()->resetLocation();
780
        currentEngine()->abortDebugger();
781
    }
hjk's avatar
hjk committed
782

783 784 785 786 787 788
    void handleReset()
    {
        currentEngine()->resetLocation();
        currentEngine()->resetInferior();
    }

hjk's avatar
hjk committed
789 790
    void handleExecStep()
    {
791
        if (currentEngine()->state() == DebuggerNotReady) {
792
            ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN);
793 794 795 796 797 798 799
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeStepI();
            else
                currentEngine()->executeStep();
        }
hjk's avatar
hjk committed
800 801 802 803
    }

    void handleExecNext()
    {
804
        if (currentEngine()->state() == DebuggerNotReady) {
805
            ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN);
806 807 808 809 810 811 812
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeNextI();
            else
                currentEngine()->executeNext();
        }
hjk's avatar
hjk committed
813 814
    }

815 816
    void handleExecStepOut()
    {
817
        currentEngine()->resetLocation();
818 819 820 821 822
        currentEngine()->executeStepOut();
    }

    void handleExecReturn()
    {
823
        currentEngine()->resetLocation();
824 825
        currentEngine()->executeReturn();
    }
hjk's avatar
hjk committed
826 827 828

    void handleExecJumpToLine()
    {
829
        currentEngine()->resetLocation();
830 831 832 833 834 835
        if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
            ContextData location = getLocationContext(textEditor->textDocument(),
                                                      textEditor->currentLine());
            if (location.isValid())
                currentEngine()->executeJumpToLine(location);
        }
hjk's avatar
hjk committed
836 837 838 839
    }

    void handleExecRunToLine()
    {
840
        currentEngine()->resetLocation();
841 842 843 844 845 846
        if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
            ContextData location = getLocationContext(textEditor->textDocument(),
                                                      textEditor->currentLine());
            if (location.isValid())
                currentEngine()->executeRunToLine(location);
        }
hjk's avatar
hjk committed
847 848
    }

849
    void handleExecRunToSelectedFunction()
hjk's avatar
hjk committed
850
    {
851
        BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
852
        QTC_ASSERT(textEditor, return);
853
        QTextCursor cursor = textEditor->textCursor();
854 855 856 857
        QString functionName = cursor.selectedText();
        if (functionName.isEmpty()) {
            const QTextBlock block = cursor.block();
            const QString line = block.text();
858
            foreach (const QString &str, line.trimmed().split(QLatin1Char('('))) {
859 860 861 862 863 864 865 866 867 868 869 870 871
                QString a;
                for (int i = str.size(); --i >= 0; ) {
                    if (!str.at(i).isLetterOrNumber())
                        break;
                    a = str.at(i) + a;
                }
                if (!a.isEmpty()) {
                    functionName = a;
                    break;
                }
            }
        }

872 873 874 875 876 877
        if (functionName.isEmpty()) {
            showStatusMessage(tr("No function selected."));
        } else {
            showStatusMessage(tr("Running to function \"%1\".")
                .arg(functionName));
            currentEngine()->resetLocation();
878
            currentEngine()->executeRunToFunction(functionName);
879
        }
hjk's avatar
hjk committed
880 881 882 883 884
    }

    void handleAddToWatchWindow()
    {
        // Requires a selection, but that's the only case we want anyway.
885
        BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
hjk's avatar
hjk committed
886 887
        if (!textEditor)
            return;
888
        QTextCursor tc = textEditor->textCursor();
hjk's avatar
hjk committed
889 890 891 892 893
        QString exp;
        if (tc.hasSelection()) {
            exp = tc.selectedText();
        } else {
            int line, column;
894
            exp = cppExpressionAt(textEditor->editorWidget(), tc.position(), &line, &column);
hjk's avatar
hjk committed
895
        }
896 897 898 899
        if (currentEngine()->hasCapability(WatchComplexExpressionsCapability))
            exp = removeObviousSideEffects(exp);
        else
            exp = fixCppExpression(exp);
900
        exp = exp.trimmed();
hjk's avatar
hjk committed
901 902
        if (exp.isEmpty())
            return;
903
        currentEngine()->watchHandler()->watchVariable(exp);
hjk's avatar
hjk committed
904 905 906 907
    }

    void handleExecExit()
    {
908
        currentEngine()->exitDebugger();
hjk's avatar
hjk committed
909 910 911 912 913 914 915 916 917 918 919 920
    }

    void handleFrameDown()
    {
        currentEngine()->frameDown();
    }

    void handleFrameUp()
    {
        currentEngine()->frameUp();
    }

921
    void handleOperateByInstructionTriggered(bool operateByInstructionTriggered)
hjk's avatar
hjk committed
922
    {
923
        // Go to source only if we have the file.
924 925 926 927 928 929
        if (DebuggerEngine *cppEngine = currentEngine()->cppEngine()) {
            if (cppEngine->stackHandler()->currentIndex() >= 0) {
                const StackFrame frame = cppEngine->stackHandler()->currentFrame();
                if (operateByInstructionTriggered || frame.isUsable())
                    cppEngine->gotoLocation(Location(frame, true));
            }
930
        }
hjk's avatar
hjk committed
931 932
    }

933 934
    void showMessage(const QString &msg, int channel, int timeout = -1);

935
    bool parseArgument(QStringList::const_iterator &it,
936 937
        const QStringList::const_iterator &cend, QString *errorMessage);
    bool parseArguments(const QStringList &args, QString *errorMessage);
938
    void parseCommandLineArguments();
939