debuggerplugin.cpp 122 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"

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

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

72
#include <coreplugin/actionmanager/actionmanager.h>
73
#include <coreplugin/actionmanager/actioncontainer.h>
74
#include <coreplugin/actionmanager/command.h>
Daniel Teske's avatar
Daniel Teske committed
75
#include <coreplugin/find/itemviewfind.h>
76
#include <coreplugin/imode.h>
77
#include <coreplugin/coreicons.h>
con's avatar
con committed
78
#include <coreplugin/icore.h>
79
#include <coreplugin/messagebox.h>
80
#include <coreplugin/messagemanager.h>
con's avatar
con committed
81
#include <coreplugin/modemanager.h>
82 83
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/documentmodel.h>
hjk's avatar
hjk committed
84

con's avatar
con committed
85
#include <cppeditor/cppeditorconstants.h>
86
#include <cpptools/cppmodelmanager.h>
hjk's avatar
hjk committed
87

88
#include <extensionsystem/invoker.h>
89

90
#include <projectexplorer/buildmanager.h>
91
#include <projectexplorer/taskhub.h>
92
#include <projectexplorer/toolchain.h>
93
#include <projectexplorer/devicesupport/deviceprocesslist.h>
94
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
95
#include <projectexplorer/projectexplorer.h>
96
#include <projectexplorer/projectexplorericons.h>
97
#include <projectexplorer/projecttree.h>
98 99
#include <projectexplorer/projectexplorersettings.h>
#include <projectexplorer/project.h>
100
#include <projectexplorer/runnables.h>
con's avatar
con committed
101
#include <projectexplorer/session.h>
102
#include <projectexplorer/target.h>
103

104
#include <texteditor/texteditor.h>
105
#include <texteditor/textdocument.h>
106
#include <texteditor/fontsettings.h>
107
#include <texteditor/texteditorsettings.h>
hjk's avatar
hjk committed
108

109
#include <utils/basetreeview.h>
110
#include <utils/hostosinfo.h>
Eike Ziller's avatar
Eike Ziller committed
111
#include <utils/mimetypes/mimedatabase.h>
112
#include <utils/proxyaction.h>
113 114
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
115
#include <utils/statuslabel.h>
116
#include <utils/styledbar.h>
hjk's avatar
hjk committed
117
#include <utils/winutils.h>
con's avatar
con committed
118

Campbell Barton's avatar
Campbell Barton committed
119
#include <QApplication>
hjk's avatar
hjk committed
120
#include <QCheckBox>
121
#include <QComboBox>
122 123
#include <QDockWidget>
#include <QFileDialog>
hjk's avatar
hjk committed
124 125
#include <QHBoxLayout>
#include <QHeaderView>
hjk's avatar
hjk committed
126
#include <QInputDialog>
127 128 129
#include <QMessageBox>
#include <QTextBlock>
#include <QToolButton>
hjk's avatar
hjk committed
130
#include <QtPlugin>
131
#include <QTreeWidget>
132
#include <QVBoxLayout>
133
#include <QMenu>
134

hjk's avatar
hjk committed
135
#ifdef WITH_TESTS
136 137 138
#include <QTest>
#include <QSignalSpy>
#include <QTestEventLoop>
139 140 141 142

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

145 146
#endif // WITH_TESTS

147 148
#include <climits>

149 150 151 152 153
#define DEBUG_STATE 1
#ifdef DEBUG_STATE
//#   define STATE_DEBUG(s)
//    do { QString msg; QTextStream ts(&msg); ts << s;
//      showMessage(msg, LogDebug); } while (0)
154
#   define STATE_DEBUG(s) do { qDebug() << s; } while (0)
155 156 157 158
#else
#   define STATE_DEBUG(s)
#endif

159 160 161 162 163 164 165 166
/*!
    \namespace Debugger
    Debugger plugin namespace
*/

/*!
    \namespace Debugger::Internal
    Internal namespace of the Debugger plugin
167
    \internal
168 169 170 171 172
*/

/*!
    \class Debugger::DebuggerEngine

173
    \brief The DebuggerEngine class is the base class of a debugger engine.
174

Leena Miettinen's avatar
Leena Miettinen committed
175
    \note The Debugger process itself and any helper processes like
176 177
    gdbserver are referred to as 'Engine', whereas the debugged process
    is referred to as 'Inferior'.
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 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

    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}            +        +                                       +
           +             +        +                                       +
276
            +            +        +                                       +
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
             +           +        +                                       +
            InferiorShutdownOk InferiorShutdownFailed                     +
                      *          *                                        +
                  EngineShutdownRequested                                 +
                            +                                             +
           (calls *Engine->shutdownEngine())  <+-+-+-+-+-+-+-+-+-+-+-+-+-+'
                         |        |
                         |        |
                    {notify-   {notify-
                     Engine-    Engine-
                  ShutdownOk}  ShutdownFailed}
                         +       +
            EngineShutdownOk  EngineShutdownFailed
                         *       *
                     DebuggerFinished

\endcode */
hjk's avatar
hjk committed
294

295 296 297
/* 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
298

299 300 301 302 303 304
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" ];
305
sg1:   InferiorSetupRequested -> InferiorSetupOk [ label="notifyInferiorSetupOk", style="dashed" ];
306
sg1:   InferiorSetupRequested -> InferiorSetupFailed [ label="notifyInferiorFailed", style="dashed" ];
307
sg1:   InferiorSetupOk -> EngineRunRequested
308 309 310 311 312 313 314 315 316 317 318 319 320 321
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
322 323
sg1:   InferiorStopOk -> InferiorShutdownRequested [ label="Close event" ];
sg1:   InferiorUnrunnable -> InferiorShutdownRequested [ label="Close event" ];
324 325
sg1:   InferiorShutdownRequested -> InferiorShutdownOk [ label= "Engine::shutdownInferior\nnotifyInferiorShutdownOk", style="dashed" ];
sg1:   InferiorShutdownRequested -> InferiorShutdownFailed [ label="Engine::shutdownInferior\nnotifyInferiorShutdownFailed", style="dashed" ];
326 327
sg1:   InferiorExited -> InferiorExitOk [ label="notifyInferiorExited", style="dashed"];
sg1:   InferiorExitOk -> InferiorShutdownOk
328 329 330 331 332 333 334 335
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
336
// Additional signalling:    {notifyInferiorIll}   {notifyEngineIll}
hjk's avatar
hjk committed
337 338


339 340
/*!
    \class Debugger::Internal::GdbEngine
341 342
    \brief The GdbEngine class implements Debugger::Engine driving a GDB
    executable.
343 344 345

    GdbEngine specific startup. All happens in EngineSetupRequested state:

Leena Miettinen's avatar
Leena Miettinen committed
346 347
    \list
        \li Transitions marked by '---' are done in the individual adapters.
348

Leena Miettinen's avatar
Leena Miettinen committed
349 350
        \li Transitions marked by '+-+' are done in the GdbEngine.
    \endlist
351 352 353 354 355 356 357 358 359 360 361 362 363

    \code
                  GdbEngine::setupEngine()
                          +
            (calls *Adapter->startAdapter())
                          |      |
                          |      `---> handleAdapterStartFailed()
                          |                   +
                          |             {notifyEngineSetupFailed}
                          |
                 handleAdapterStarted()
                          +
                 {notifyEngineSetupOk}
364 365 366



367 368 369 370 371 372 373 374 375 376 377
                GdbEngine::setupInferior()
                          +
            (calls *Adapter->prepareInferior())
                          |      |
                          |      `---> handlePrepareInferiorFailed()
                          |                   +
                          |             {notifyInferiorSetupFailed}
                          |
                handleInferiorPrepared()
                          +
                {notifyInferiorSetupOk}
378

379
\endcode */
380

con's avatar
con committed
381
using namespace Core;
hjk's avatar
hjk committed
382
using namespace Debugger::Constants;
383
using namespace Debugger::Internal;
384
using namespace ExtensionSystem;
con's avatar
con committed
385
using namespace ProjectExplorer;
hjk's avatar
hjk committed
386
using namespace TextEditor;
387
using namespace Utils;
con's avatar
con committed
388

hjk's avatar
hjk committed
389 390 391
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
392 393

namespace Debugger {
394 395
namespace Internal {

396 397 398 399 400 401 402 403 404 405 406
struct TestCallBack
{
    TestCallBack() : receiver(0), slot(0) {}
    TestCallBack(QObject *ob, const char *s) : receiver(ob), slot(s) {}

    QObject *receiver;
    const char *slot;
    QVariant cookie;
};


407 408 409
} // namespace Internal
} // namespace Debugger

410 411
Q_DECLARE_METATYPE(Debugger::Internal::TestCallBack)

412 413 414
namespace Debugger {
namespace Internal {

415
void addCdbOptionPages(QList<IOptionsPage*> *opts);
416
void addGdbOptionPages(QList<IOptionsPage*> *opts);
417
QObject *createDebuggerRunControlFactory(QObject *parent);
418

419 420 421 422 423 424 425
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

426
static void setProxyAction(ProxyAction *proxy, Id id)
427
{
hjk's avatar
hjk committed
428
    proxy->setAction(ActionManager::command(id)->action());
429 430
}

431
static QToolButton *toolButton(Id id)
432
{
hjk's avatar
hjk committed
433
    return toolButton(ActionManager::command(id)->action());
434 435
}

436 437 438 439 440 441 442 443 444
///////////////////////////////////////////////////////////////////////
//
// DummyEngine
//
///////////////////////////////////////////////////////////////////////

class DummyEngine : public DebuggerEngine
{
public:
445
    DummyEngine() : DebuggerEngine(DebuggerRunParameters()) {}
446 447 448 449 450 451 452
    ~DummyEngine() {}

    void setupEngine() {}
    void setupInferior() {}
    void runEngine() {}
    void shutdownEngine() {}
    void shutdownInferior() {}
453
    bool hasCapability(unsigned cap) const;
454
    bool acceptsBreakpoint(Breakpoint) const { return false; }
455
    bool acceptsDebuggerCommands() const { return false; }
hjk's avatar
hjk committed
456
    void selectThread(ThreadId) {}
457 458
};

459
bool DummyEngine::hasCapability(unsigned cap) const
460 461
{
    // This can only be a first approximation of what to expect when running.
462
    Project *project = ProjectTree::currentProject();
463 464 465 466 467 468 469 470
    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:
471
    if (activeRc->extraAspect<Debugger::DebuggerRunConfigurationAspect>()->useCppDebugger())
472
        return cap & (WatchpointByAddressCapability
473 474
               | BreakConditionCapability
               | TracePointCapability
475
               | OperateByInstructionCapability);
476 477

    // This is a Qml or unknown engine.
478
    return cap & AddWatcherCapability;
479 480
}

481 482 483 484 485 486
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

487
class DebugMode : public IMode
hjk's avatar
hjk committed
488 489
{
public:
490 491 492
    DebugMode()
    {
        setObjectName(QLatin1String("DebugMode"));
493
        setContext(Context(C_DEBUGMODE, CC::C_NAVIGATION_PANE));
494
        setDisplayName(DebuggerPlugin::tr("Debug"));
495 496
        setIcon(Utils::Icon::modeIcon(Icons::MODE_DEBUGGER_CLASSIC,
                                      Icons::MODE_DEBUGGER_FLAT, Icons::MODE_DEBUGGER_FLAT_ACTIVE));
497
        setPriority(85);
498
        setId(MODE_DEBUG);
499
    }
hjk's avatar
hjk committed
500

hjk's avatar
hjk committed
501 502 503 504
    ~DebugMode()
    {
        delete m_widget;
    }
505
};
hjk's avatar
hjk committed
506

507 508 509 510 511 512
///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

513
static QWidget *addSearch(BaseTreeView *treeView, const QString &title,
514
    const char *objectName)
515
{
hjk's avatar
hjk committed
516
    QAction *act = action(UseAlternatingRowColors);
517
    treeView->setAlternatingRowColors(act->isChecked());
518 519
    QObject::connect(act, &QAction::toggled,
                     treeView, &BaseTreeView::setAlternatingRowColorsHelper);
520

Daniel Teske's avatar
Daniel Teske committed
521
    QWidget *widget = ItemViewFind::createSearchableWrapper(treeView);
522 523 524 525 526
    widget->setObjectName(QLatin1String(objectName));
    widget->setWindowTitle(title);
    return widget;
}

527
static std::function<bool(const Kit *)> cdbMatcher(char wordWidth = 0)
528
{
529
    return [wordWidth](const Kit *k) -> bool {
530 531
        if (DebuggerKitInformation::engineType(k) != CdbEngineType
            || !DebuggerKitInformation::isValidDebugger(k)) {
532
            return false;
533
        }
534
        if (wordWidth) {
535
            const ToolChain *tc = ToolChainKitInformation::toolChain(k);
536
            return tc && wordWidth == tc->targetAbi().wordWidth();
537
        }
538
        return true;
539 540
    };
}
541

542 543 544 545 546 547 548
// Find a CDB kit for debugging unknown processes.
// On a 64bit OS, prefer a 64bit debugger.
static Kit *findUniversalCdbKit()
{
    if (Utils::is64BitWindowsSystem()) {
        if (Kit *cdb64Kit = KitManager::find(cdbMatcher(64)))
            return cdb64Kit;
549
    }
550 551
    return KitManager::find(cdbMatcher());
}
552

553 554
///////////////////////////////////////////////////////////////////////
//
555
// DebuggerPluginPrivate
556 557
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
558

559
static DebuggerPluginPrivate *dd = 0;
con's avatar
con committed
560

561 562 563 564 565 566 567 568 569 570 571 572 573 574
/*!
    \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.
*/

575
class DebuggerPluginPrivate : public QObject
576 577
{
    Q_OBJECT
578

579 580
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
581
    ~DebuggerPluginPrivate();
582

583
    bool initialize(const QStringList &arguments, QString *errorMessage);
584 585 586
    void extensionsInitialized();
    void aboutToShutdown();

587
    void connectEngine(DebuggerEngine *engine);
hjk's avatar
hjk committed
588
    void disconnectEngine() { connectEngine(0); }
589
    DebuggerEngine *dummyEngine();
590

hjk's avatar
hjk committed
591
    void setThreadBoxContents(const QStringList &list, int index)
592 593 594 595 596 597 598 599
    {
        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);
    }
600 601

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

603 604 605 606 607 608
    void writeSettings()
    {
        m_debuggerSettings->writeSettings();
        m_mainWindow->writeSettings();
    }

609 610
    void selectThread(int index)
    {
hjk's avatar
hjk committed
611 612
        ThreadId id = m_currentEngine->threadsHandler()->threadAt(index);
        m_currentEngine->selectThread(id);
613
    }
614

615
    void breakpointSetMarginActionTriggered(bool isMessageOnly, const ContextData &data)
616
    {
617
        QString message;
618
        if (isMessageOnly) {
619
            if (data.type == LocationByAddress) {
620 621 622 623
                //: Message tracepoint: Address hit.
                message = tr("0x%1 hit").arg(data.address, 0, 16);
            } else {
                //: Message tracepoint: %1 file, %2 line %3 function hit.
624
                message = tr("%1:%2 %3() hit").arg(FileName::fromString(data.fileName).fileName()).
625 626 627 628 629
                        arg(data.lineNumber).
                        arg(cppFunctionAt(data.fileName, data.lineNumber));
            }
            QInputDialog dialog; // Create wide input dialog.
            dialog.setWindowFlags(dialog.windowFlags()
hjk's avatar
hjk committed
630
              & ~(Qt::WindowContextHelpButtonHint|Qt::MSWindowsFixedSizeDialogHint));
631 632 633 634 635 636 637 638
            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();
        }
639
        toggleBreakpoint(data, message);
640
    }
641

642
    void updateWatchersHeader(int section, int, int newSize)
643
    {
644 645
        m_watchersView->header()->resizeSection(section, newSize);
        m_returnView->header()->resizeSection(section, newSize);
646
    }
647

648
    void sourceFilesDockToggled(bool on)
649
    {
650
        if (on && m_currentEngine->state() == InferiorStopOk)
651 652 653
            m_currentEngine->reloadSourceFiles();
    }

654
    void modulesDockToggled(bool on)
655
    {
656
        if (on && m_currentEngine->state() == InferiorStopOk)
657 658
            m_currentEngine->reloadModules();
    }
659

hjk's avatar
hjk committed
660
    void registerDockToggled(bool on)
661
    {
662
        if (on && m_currentEngine->state() == InferiorStopOk)
663 664
            m_currentEngine->reloadRegisters();
    }
665

666 667
    void synchronizeBreakpoints()
    {
668
        showMessage(QLatin1String("ATTEMPT SYNC"), LogDebug);
669
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
670
            if (DebuggerEngine *engine = m_snapshotHandler->at(i))
671 672 673 674
                engine->attemptBreakpointSynchronization();
        }
    }

675 676
    void editorOpened(IEditor *editor);
    void updateBreakMenuItem(IEditor *editor);
677
    void setBusyCursor(bool busy);
678 679 680
    void requestMark(TextEditorWidget *widget, int lineNumber,
                     TextMarkRequestKind kind);
    void requestContextMenu(TextEditorWidget *widget,
681
                            int lineNumber, QMenu *menu);
682

683 684
    void activatePreviousMode();
    void activateDebugMode();
685 686
    void toggleBreakpointHelper();
    void toggleBreakpoint(const ContextData &location, const QString &tracePointMessage = QString());
687
    void onModeChanged(IMode *mode);
688
    void onCoreAboutToOpen();
689
    void updateDebugWithoutDeployMenu();
690

691
    void startAndDebugApplication();
692
    void startRemoteCdbSession();
693
    void startRemoteServerAndAttachToProcess();
694
    void attachToRemoteServer();
hjk's avatar
hjk committed
695
    void attachToRunningApplication();
696
    void attachToUnstartedApplicationDialog();
697
    void attachToQmlPort();
hjk's avatar
hjk committed
698
    Q_SLOT void runScheduled();
699
    void attachCore();
700

701
    void enableReverseDebuggingTriggered(const QVariant &value);
702
    void showStatusMessage(const QString &msg, int timeout = -1);
703

704 705
    void runControlStarted(DebuggerEngine *engine);
    void runControlFinished(DebuggerEngine *engine);
706
    void remoteCommand(const QStringList &options);
707

708
    void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
709 710 711

    void dumpLog();
    void cleanupViews();
712
    void setInitialState();
713

714
    void fontSettingsChanged(const FontSettings &settings);
715 716

    void updateState(DebuggerEngine *engine);
717
    void onCurrentProjectChanged(Project *project);
718 719 720 721

    void sessionLoaded();
    void aboutToUnloadSession();
    void aboutToSaveSession();
722

723
    void coreShutdown();
724

hjk's avatar
hjk committed
725 726
#ifdef WITH_TESTS
public slots:
727
    void testLoadProject(const QString &proFile, const TestCallBack &cb);
728
    void testProjectLoaded(Project *project);
729 730
    void testProjectEvaluated();
    void testProjectBuilt(bool success);
731 732 733
    void testUnloadProject();
    void testFinished();

734
    void testRunProject(const DebuggerRunParameters &sp, const TestCallBack &cb);
hjk's avatar
hjk committed
735
    void testRunControlFinished();
736

hjk's avatar
hjk committed
737 738 739
//    void testStateMachine1();
//    void testStateMachine2();
//    void testStateMachine3();
740

741 742
    void testBenchmark1();

743
public:
hjk's avatar
hjk committed
744
    Project *m_testProject;
745 746 747
    bool m_testSuccess;
    QList<TestCallBack> m_testCallbacks;

hjk's avatar
hjk committed
748 749
#endif

hjk's avatar
hjk committed
750
public slots:
751
    void updateDebugActions();
752 753 754

    void handleExecDetach()
    {
755
        currentEngine()->resetLocation();
756 757 758 759 760
        currentEngine()->detachDebugger();
    }

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

    void handleExecInterrupt()
    {
767
        currentEngine()->resetLocation();
768 769 770
        currentEngine()->requestInterruptInferior();
    }

771
    void handleAbort()
772
    {
773
        currentEngine()->resetLocation();
774
        currentEngine()->abortDebugger();
775
    }
hjk's avatar
hjk committed
776

777 778 779 780 781 782
    void handleReset()
    {
        currentEngine()->resetLocation();
        currentEngine()->resetInferior();
    }

hjk's avatar
hjk committed
783 784
    void handleExecStep()
    {
785
        if (currentEngine()->state() == DebuggerNotReady) {
786
            ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN);
787 788 789 790 791 792 793
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeStepI();
            else
                currentEngine()->executeStep();
        }
hjk's avatar
hjk committed
794 795 796 797
    }

    void handleExecNext()
    {
798
        if (currentEngine()->state() == DebuggerNotReady) {
799
            ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN);
800 801 802 803 804 805 806
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeNextI();
            else
                currentEngine()->executeNext();
        }
hjk's avatar
hjk committed
807 808
    }

809 810
    void handleExecStepOut()
    {
811
        currentEngine()->resetLocation();
812 813 814 815 816
        currentEngine()->executeStepOut();
    }

    void handleExecReturn()
    {
817
        currentEngine()->resetLocation();
818 819
        currentEngine()->executeReturn();
    }
hjk's avatar
hjk committed
820 821 822

    void handleExecJumpToLine()
    {
823
        currentEngine()->resetLocation();
824 825 826 827 828 829
        if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
            ContextData location = getLocationContext(textEditor->textDocument(),
                                                      textEditor->currentLine());
            if (location.isValid())
                currentEngine()->executeJumpToLine(location);
        }
hjk's avatar
hjk committed
830 831 832 833
    }

    void handleExecRunToLine()
    {
834
        currentEngine()->resetLocation();
835 836 837 838 839 840
        if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
            ContextData location = getLocationContext(textEditor->textDocument(),
                                                      textEditor->currentLine());
            if (location.isValid())
                currentEngine()->executeRunToLine(location);
        }
hjk's avatar
hjk committed
841 842
    }

843
    void handleExecRunToSelectedFunction()
hjk's avatar
hjk committed
844
    {
845
        BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
846
        QTC_ASSERT(textEditor, return);
847
        QTextCursor cursor = textEditor->textCursor();
848 849 850 851
        QString functionName = cursor.selectedText();
        if (functionName.isEmpty()) {
            const QTextBlock block = cursor.block();
            const QString line = block.text();
852
            foreach (const QString &str, line.trimmed().split(QLatin1Char('('))) {
853 854 855 856 857 858 859 860 861 862 863 864 865
                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;
                }
            }
        }

866 867 868 869 870 871
        if (functionName.isEmpty()) {
            showStatusMessage(tr("No function selected."));
        } else {
            showStatusMessage(tr("Running to function \"%1\".")
                .arg(functionName));
            currentEngine()->resetLocation();
872
            currentEngine()->executeRunToFunction(functionName);
873
        }
hjk's avatar
hjk committed
874 875 876 877 878
    }

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

    void handleExecExit()
    {
902
        currentEngine()->exitDebugger();
hjk's avatar
hjk committed
903 904 905 906 907 908 909 910 911 912 913 914
    }

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

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

915
    void handleOperateByInstructionTriggered(bool operateByInstructionTriggered)
hjk's avatar
hjk committed
916
    {
917
        // Go to source only if we have the file.
918 919 920 921 922 923
        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));
            }
924
        }
hjk's avatar
hjk committed
925 926
    }

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

929
    bool parseArgument(QStringList::const_iterator &it,