debuggerplugin.cpp 139 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
**
10
** GNU Lesser General Public License Usage
11
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
con's avatar
con committed
30
**
31
**************************************************************************/
hjk's avatar
hjk committed
32

con's avatar
con committed
33 34
#include "debuggerplugin.h"

Friedemann Kleint's avatar
Friedemann Kleint committed
35
#include "debuggerstartparameters.h"
36
#include "debuggeractions.h"
con's avatar
con committed
37
#include "debuggerconstants.h"
38
#include "debuggerinternalconstants.h"
39
#include "debuggercore.h"
40 41
#include "debuggerdialogs.h"
#include "debuggerengine.h"
42
#include "debuggermainwindow.h"
con's avatar
con committed
43
#include "debuggerrunner.h"
44
#include "debuggerruncontrolfactory.h"
45
#include "debuggerstringutils.h"
46
#include "memoryagent.h"
47 48
#include "breakpoint.h"
#include "breakhandler.h"
49
#include "breakwindow.h"
50
#include "consolewindow.h"
51
#include "disassemblerlines.h"
52
#include "logwindow.h"
53
#include "moduleswindow.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
54
#include "moduleshandler.h"
55 56
#include "registerwindow.h"
#include "snapshotwindow.h"
hjk's avatar
hjk committed
57
#include "stackhandler.h"
58 59 60
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
hjk's avatar
hjk committed
61
#include "watchhandler.h"
62
#include "watchwindow.h"
hjk's avatar
hjk committed
63
#include "watchutils.h"
64
#include "debuggertooltipmanager.h"
65

66 67
#include "snapshothandler.h"
#include "threadshandler.h"
68
#include "commonoptionspage.h"
con's avatar
con committed
69

70
#include <coreplugin/actionmanager/actionmanager.h>
71 72
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
73
#include <coreplugin/id.h>
74
#include <coreplugin/imode.h>
con's avatar
con committed
75
#include <coreplugin/coreconstants.h>
76
#include <coreplugin/dialogs/ioptionspage.h>
con's avatar
con committed
77
#include <coreplugin/editormanager/editormanager.h>
hjk's avatar
hjk committed
78
#include <coreplugin/findplaceholder.h>
79
#include <coreplugin/icontext.h>
con's avatar
con committed
80
#include <coreplugin/icore.h>
81
#include <coreplugin/imode.h>
82
#include <coreplugin/icorelistener.h>
hjk's avatar
hjk committed
83
#include <coreplugin/minisplitter.h>
con's avatar
con committed
84
#include <coreplugin/modemanager.h>
hjk's avatar
hjk committed
85

con's avatar
con committed
86
#include <cppeditor/cppeditorconstants.h>
87
#include <cplusplus/ModelManagerInterface.h>
hjk's avatar
hjk committed
88

89
#include <extensionsystem/pluginmanager.h>
90
#include <extensionsystem/invoker.h>
91

92
#include <projectexplorer/abi.h>
hjk's avatar
hjk committed
93 94
#include <projectexplorer/applicationrunconfiguration.h>
#include <projectexplorer/buildconfiguration.h>
con's avatar
con committed
95
#include <projectexplorer/projectexplorerconstants.h>
96 97 98
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorersettings.h>
#include <projectexplorer/project.h>
con's avatar
con committed
99
#include <projectexplorer/session.h>
100
#include <projectexplorer/target.h>
101 102
#include <projectexplorer/toolchain.h>
#include <projectexplorer/toolchainmanager.h>
hjk's avatar
hjk committed
103

104
#include <qtsupport/qtsupportconstants.h>
105

hjk's avatar
hjk committed
106
#include <texteditor/basetexteditor.h>
107
#include <texteditor/fontsettings.h>
108
#include <texteditor/texteditorsettings.h>
hjk's avatar
hjk committed
109 110

#include <utils/qtcassert.h>
111
#include <utils/savedaction.h>
112
#include <utils/styledbar.h>
113
#include <utils/proxyaction.h>
114
#include <utils/statuslabel.h>
115
#include <utils/fileutils.h>
con's avatar
con committed
116

117
#include <qml/qmljsscriptconsole.h>
118

119
#include <QtCore/QTimer>
120 121
#include <QtCore/QtPlugin>
#include <QtGui/QComboBox>
122
#include <QtGui/QDockWidget>
123
#include <QtGui/QFileDialog>
hjk's avatar
hjk committed
124
#include <QtGui/QMenu>
125
#include <QtGui/QMessageBox>
126 127 128
#include <QtGui/QPushButton>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
129
#include <QtGui/QToolButton>
hjk's avatar
hjk committed
130
#include <QtGui/QTreeWidget>
131
#include <QtGui/QInputDialog>
con's avatar
con committed
132

hjk's avatar
hjk committed
133 134 135 136 137 138
#ifdef WITH_TESTS
#include <QtTest/QTest>
#include <QtTest/QSignalSpy>
#include <QtTest/QTestEventLoop>
#endif

139 140
#include <climits>

141 142 143 144 145 146 147 148 149 150
#define DEBUG_STATE 1
#ifdef DEBUG_STATE
//#   define STATE_DEBUG(s)
//    do { QString msg; QTextStream ts(&msg); ts << s;
//      showMessage(msg, LogDebug); } while (0)
#   define STATE_DEBUG(s) do { qDebug() << s; } while(0)
#else
#   define STATE_DEBUG(s)
#endif

151 152 153 154 155 156 157 158
/*!
    \namespace Debugger
    Debugger plugin namespace
*/

/*!
    \namespace Debugger::Internal
    Internal namespace of the Debugger plugin
159
    \internal
160 161 162 163 164 165 166 167
*/

/*!
    \class Debugger::DebuggerEngine

    \brief Base class of a debugger engine.

    Note: the Debugger process itself and any helper processes like
Pawel Polanski's avatar
Pawel Polanski committed
168
    gdbserver, the CODA client etc are referred to as 'Engine',
169 170 171 172 173 174 175 176 177 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 276 277 278 279 280 281 282 283 284 285
    whereas the debugged process is referred to as 'Inferior'.

    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}            +        +                                       +
           +             +        +                                       +
     InferiorExitOk      +        +                                       +
             +           +        +                                       +
            InferiorShutdownOk InferiorShutdownFailed                     +
                      *          *                                        +
                  EngineShutdownRequested                                 +
                            +                                             +
           (calls *Engine->shutdownEngine())  <+-+-+-+-+-+-+-+-+-+-+-+-+-+'
                         |        |
                         |        |
                    {notify-   {notify-
                     Engine-    Engine-
                  ShutdownOk}  ShutdownFailed}
                         +       +
            EngineShutdownOk  EngineShutdownFailed
                         *       *
                     DebuggerFinished

\endcode */
hjk's avatar
hjk committed
286

287 288 289
/* 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
290

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


331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
/*!
    \class Debugger::Internal::GdbEngine
    \brief Implementation of Debugger::Engine driving a gdb executable.

    GdbEngine specific startup. All happens in EngineSetupRequested state:

    Transitions marked by '---' are done in the individual adapters.

    Transitions marked by '+-+' are done in the GdbEngine.

    \code
                  GdbEngine::setupEngine()
                          +
            (calls *Adapter->startAdapter())
                          |      |
                          |      `---> handleAdapterStartFailed()
                          |                   +
                          |             {notifyEngineSetupFailed}
                          |
                 handleAdapterStarted()
                          +
                 {notifyEngineSetupOk}
353 354 355



356 357 358 359 360 361 362 363 364 365 366
                GdbEngine::setupInferior()
                          +
            (calls *Adapter->prepareInferior())
                          |      |
                          |      `---> handlePrepareInferiorFailed()
                          |                   +
                          |             {notifyInferiorSetupFailed}
                          |
                handleInferiorPrepared()
                          +
                {notifyInferiorSetupOk}
367

368
\endcode */
369

con's avatar
con committed
370
using namespace Core;
hjk's avatar
hjk committed
371
using namespace Debugger::Constants;
con's avatar
con committed
372
using namespace ProjectExplorer;
hjk's avatar
hjk committed
373
using namespace TextEditor;
374
using namespace ExtensionSystem;
con's avatar
con committed
375

hjk's avatar
hjk committed
376 377 378
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
379 380 381 382

namespace Debugger {
namespace Constants {

383
#ifdef Q_OS_MAC
hjk's avatar
hjk committed
384 385 386 387 388 389 390 391 392 393 394 395 396 397
const char STOP_KEY[]                     = "Shift+Ctrl+Y";
const char RESET_KEY[]                    = "Ctrl+Shift+F5";
const char STEP_KEY[]                     = "Ctrl+Shift+I";
const char STEPOUT_KEY[]                  = "Ctrl+Shift+T";
const char NEXT_KEY[]                     = "Ctrl+Shift+O";
const char REVERSE_KEY[]                  = "";
const char RUN_TO_LINE_KEY[]              = "Shift+F8";
const char RUN_TO_SELECTED_FUNCTION_KEY[] = "Ctrl+F6";
const char JUMP_TO_LINE_KEY[]             = "Ctrl+D,Ctrl+L";
const char TOGGLE_BREAK_KEY[]             = "F8";
const char BREAK_BY_FUNCTION_KEY[]        = "Ctrl+D,Ctrl+F";
const char BREAK_AT_MAIN_KEY[]            = "Ctrl+D,Ctrl+M";
const char ADD_TO_WATCH_KEY[]             = "Ctrl+D,Ctrl+W";
const char SNAPSHOT_KEY[]                 = "Ctrl+D,Ctrl+S";
con's avatar
con committed
398
#else
hjk's avatar
hjk committed
399 400 401 402 403 404
const char STOP_KEY[]                     = "Shift+F5";
const char RESET_KEY[]                    = "Ctrl+Shift+F5";
const char STEP_KEY[]                     = "F11";
const char STEPOUT_KEY[]                  = "Shift+F11";
const char NEXT_KEY[]                     = "F10";
const char REVERSE_KEY[]                  = "F12";
405
const char RUN_TO_LINE_KEY[]              = "Ctrl+F10";
hjk's avatar
hjk committed
406 407 408 409 410 411 412
const char RUN_TO_SELECTED_FUNCTION_KEY[] = "Ctrl+F6";
const char JUMP_TO_LINE_KEY[]             = "";
const char TOGGLE_BREAK_KEY[]             = "F9";
const char BREAK_BY_FUNCTION_KEY[]        = "";
const char BREAK_AT_MAIN_KEY[]            = "";
const char ADD_TO_WATCH_KEY[]             = "Ctrl+Alt+Q";
const char SNAPSHOT_KEY[]                 = "Ctrl+D,Ctrl+S";
con's avatar
con committed
413 414 415 416 417
#endif

} // namespace Constants


418 419
namespace Internal {

420 421 422 423 424 425 426 427 428 429 430 431 432
// To be passed through margin menu action's data
struct BreakpointMenuContextData : public ContextData
{
    enum Mode
    {
        Breakpoint,
        MessageTracePoint
    };

    BreakpointMenuContextData() : mode(Breakpoint) {}
    Mode mode;
};

433 434 435 436 437 438 439 440 441 442 443
struct TestCallBack
{
    TestCallBack() : receiver(0), slot(0) {}
    TestCallBack(QObject *ob, const char *s) : receiver(ob), slot(s) {}

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


444 445 446 447
} // namespace Internal
} // namespace Debugger

Q_DECLARE_METATYPE(Debugger::Internal::BreakpointMenuContextData)
448 449
Q_DECLARE_METATYPE(Debugger::Internal::TestCallBack)

450 451 452 453

namespace Debugger {
namespace Internal {

454 455 456 457 458 459
// FIXME: Outdated?
// The createCdbEngine function takes a list of options pages it can add to.
// This allows for having a "enabled" toggle on the page independently
// of the engine. That's good for not enabling the related ActiveX control
// unnecessarily.

460
void addCdbOptionPages(QList<IOptionsPage*> *opts);
461 462 463
void addGdbOptionPages(QList<IOptionsPage*> *opts);
void addScriptOptionPages(QList<IOptionsPage*> *opts);
void addTcfOptionPages(QList<IOptionsPage*> *opts);
464

465 466 467 468
#ifdef WITH_LLDB
void addLldbOptionPages(QList<IOptionsPage*> *opts);
#endif

hjk's avatar
hjk committed
469
static SessionManager *sessionManager()
470
{
hjk's avatar
hjk committed
471
    return ProjectExplorerPlugin::instance()->session();
472 473
}

474 475 476 477 478 479 480
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

481
static Abi anyAbiOfBinary(const QString &fileName)
482
{
Tobias Hunger's avatar
Tobias Hunger committed
483
    QList<Abi> abis = Abi::abisOfBinary(Utils::FileName::fromString(fileName));
484 485 486 487
    if (abis.isEmpty())
        return Abi();
    return abis.at(0);
}
488 489 490 491 492 493 494 495 496 497 498 499

///////////////////////////////////////////////////////////////////////
//
// DummyEngine
//
///////////////////////////////////////////////////////////////////////

class DummyEngine : public DebuggerEngine
{
    Q_OBJECT

public:
500
    DummyEngine() : DebuggerEngine(DebuggerStartParameters(), AnyLanguage) {}
501 502 503 504 505 506 507
    ~DummyEngine() {}

    void setupEngine() {}
    void setupInferior() {}
    void runEngine() {}
    void shutdownEngine() {}
    void shutdownInferior() {}
508
    bool hasCapability(unsigned cap) const;
509
    bool acceptsBreakpoint(BreakpointModelId) const { return false; }
510
    bool acceptsDebuggerCommands() const { return false; }
511 512
};

513
bool DummyEngine::hasCapability(unsigned cap) const
514 515
{
    // This can only be a first approximation of what to expect when running.
516
    Project *project = ProjectExplorerPlugin::currentProject();
517 518 519 520 521 522 523 524 525
    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:
    if (activeRc->useCppDebugger())
526
        return cap & (WatchpointByAddressCapability
527 528
               | BreakConditionCapability
               | TracePointCapability
529
               | OperateByInstructionCapability);
530 531

    // This is a Qml or unknown engine.
532
    return cap & AddWatcherCapability;
533 534
}

535 536 537 538 539 540
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

541
class DebugMode : public IMode
hjk's avatar
hjk committed
542 543
{
public:
544 545 546 547
    DebugMode()
    {
        setObjectName(QLatin1String("DebugMode"));
        setContext(Context(CC::C_EDITORMANAGER, C_DEBUGMODE, CC::C_NAVIGATION_PANE));
548 549
        setDisplayName(DebuggerPlugin::tr("Debug"));
        setIcon(QIcon(QLatin1String(":/fancyactionbar/images/mode_Debug.png")));
550
        setPriority(85);
551 552
        setId(QLatin1String(MODE_DEBUG));
        setType(QLatin1String(CC::MODE_EDIT_TYPE));
553
    }
hjk's avatar
hjk committed
554

hjk's avatar
hjk committed
555 556 557 558 559 560
    ~DebugMode()
    {
        // Make sure the editor manager does not get deleted.
        //EditorManager::instance()->setParent(0);
        delete m_widget;
    }
561
};
hjk's avatar
hjk committed
562

563 564 565 566 567 568
///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

569
static TextEditor::ITextEditor *currentTextEditor()
570
{
571 572 573 574 575
    if (const Core::EditorManager *editorManager = Core::EditorManager::instance())
            if (Core::IEditor *editor = editorManager->currentEditor())
                return qobject_cast<TextEditor::ITextEditor*>(editor);
    return 0;
}
con's avatar
con committed
576

577 578
static bool currentTextEditorPosition(ContextData *data)
{
579 580 581 582 583 584 585 586 587 588 589 590 591
    TextEditor::ITextEditor *textEditor = currentTextEditor();
    if (!textEditor)
        return false;
    const Core::IFile *file = textEditor->file();
    QTC_ASSERT(file, return false);
    data->fileName = file->fileName();
    if (textEditor->property("DisassemblerView").toBool()) {
        int lineNumber = textEditor->currentLine();
        QString line = textEditor->contents()
            .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1);
        data->address = DisassemblerLine::addressFromDisassemblyLine(line);
    } else {
        data->lineNumber = textEditor->currentLine();
592
    }
593
    return true;
594
}
595

596 597
///////////////////////////////////////////////////////////////////////
//
598
// DebuggerPluginPrivate
599 600
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
601

602
static DebuggerPluginPrivate *theDebuggerCore = 0;
con's avatar
con committed
603

604 605 606 607 608 609 610 611 612 613 614 615 616 617
/*!
    \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.
*/

618
class DebuggerPluginPrivate : public DebuggerCore
619 620
{
    Q_OBJECT
621

622 623
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
624
    ~DebuggerPluginPrivate();
625

626
    bool initialize(const QStringList &arguments, QString *errorMessage);
627 628 629
    void extensionsInitialized();
    void aboutToShutdown();

630
    void connectEngine(DebuggerEngine *engine);
hjk's avatar
hjk committed
631
    void disconnectEngine() { connectEngine(0); }
632
    DebuggerEngine *currentEngine() const { return m_currentEngine; }
633
    DebuggerEngine *dummyEngine();
634

635 636 637 638 639 640 641 642 643 644
    void setThreads(const QStringList &list, int index)
    {
        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);
    }

645
public slots:
646 647 648 649 650 651
    void writeSettings()
    {
        m_debuggerSettings->writeSettings();
        m_mainWindow->writeSettings();
    }

652 653 654 655
    void selectThread(int index)
    {
        currentEngine()->selectThread(index);
    }
656

hjk's avatar
hjk committed
657
    void breakpointSetMarginActionTriggered()
658
    {
659 660
        const QAction *action = qobject_cast<const QAction *>(sender());
        QTC_ASSERT(action, return);
hjk's avatar
hjk committed
661 662
        const BreakpointMenuContextData data =
            action->data().value<BreakpointMenuContextData>();
663 664 665 666 667 668 669 670 671 672 673 674 675
        QString message;
        if (data.mode == BreakpointMenuContextData::MessageTracePoint) {
            if (data.address) {
                //: Message tracepoint: Address hit.
                message = tr("0x%1 hit").arg(data.address, 0, 16);
            } else {
                //: Message tracepoint: %1 file, %2 line %3 function hit.
                message = tr("%1:%2 %3() hit").arg(QFileInfo(data.fileName).fileName()).
                        arg(data.lineNumber).
                        arg(cppFunctionAt(data.fileName, data.lineNumber));
            }
            QInputDialog dialog; // Create wide input dialog.
            dialog.setWindowFlags(dialog.windowFlags()
hjk's avatar
hjk committed
676
              & ~(Qt::WindowContextHelpButtonHint|Qt::MSWindowsFixedSizeDialogHint));
677 678 679 680 681 682 683 684
            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();
        }
685
        if (data.address)
686
            toggleBreakpointByAddress(data.address, message);
687
        else
688
            toggleBreakpointByFileAndLine(data.fileName, data.lineNumber, message);
689
    }
690

hjk's avatar
hjk committed
691
    void breakpointRemoveMarginActionTriggered()
692
    {
hjk's avatar
hjk committed
693 694
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
695
        BreakpointModelId id = act->data().value<BreakpointModelId>();
hjk's avatar
hjk committed
696
        m_breakHandler->removeBreakpoint(id);
hjk's avatar
hjk committed
697 698 699 700 701 702
     }

    void breakpointEnableMarginActionTriggered()
    {
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
703
        BreakpointModelId id = act->data().value<BreakpointModelId>();
hjk's avatar
hjk committed
704
        breakHandler()->setEnabled(id, true);
hjk's avatar
hjk committed
705 706 707 708 709 710
    }

    void breakpointDisableMarginActionTriggered()
    {
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
711
        BreakpointModelId id = act->data().value<BreakpointModelId>();;
hjk's avatar
hjk committed
712
        breakHandler()->setEnabled(id, false);
713 714
    }

715
    void updateWatchersHeader(int section, int, int newSize)
716 717
    {
        m_watchersWindow->header()->resizeSection(section, newSize);
718
        m_returnWindow->header()->resizeSection(section, newSize);
719
    }
720

721

722
    void sourceFilesDockToggled(bool on)
723
    {
724
        if (on && m_currentEngine->state() == InferiorStopOk)
725 726 727
            m_currentEngine->reloadSourceFiles();
    }

728
    void modulesDockToggled(bool on)
729
    {
730
        if (on && m_currentEngine->state() == InferiorStopOk)
731 732
            m_currentEngine->reloadModules();
    }
733

hjk's avatar
hjk committed
734
    void registerDockToggled(bool on)
735
    {
736
        if (on && m_currentEngine->state() == InferiorStopOk)
737 738
            m_currentEngine->reloadRegisters();
    }
739

740 741
    void synchronizeBreakpoints()
    {
742
        showMessage(QLatin1String("ATTEMPT SYNC"), LogDebug);
743
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
744
            if (DebuggerEngine *engine = m_snapshotHandler->at(i))
745 746 747 748
                engine->attemptBreakpointSynchronization();
        }
    }

hjk's avatar
hjk committed
749 750 751
    void synchronizeWatchers()
    {
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
752
            if (DebuggerEngine *engine = m_snapshotHandler->at(i))
753
                engine->watchHandler()->updateWatchers();
hjk's avatar
hjk committed
754 755 756
        }
    }

757
    void editorOpened(Core::IEditor *editor);
758
    void updateBreakMenuItem(Core::IEditor *editor);
759
    void setBusyCursor(bool busy);
760 761 762
    void requestMark(TextEditor::ITextEditor *editor,
                     int lineNumber,
                     TextEditor::ITextEditor::MarkRequestKind kind);
763 764
    void requestContextMenu(TextEditor::ITextEditor *editor,
        int lineNumber, QMenu *menu);
765

766 767 768
    void activatePreviousMode();
    void activateDebugMode();
    void toggleBreakpoint();
769 770 771 772
    void toggleBreakpointByFileAndLine(const QString &fileName, int lineNumber,
                                       const QString &tracePointMessage = QString());
    void toggleBreakpointByAddress(quint64 address,
                                   const QString &tracePointMessage = QString());
773
    void onModeChanged(Core::IMode *mode);
774
    void onCoreAboutToOpen();
775
    void showSettingsDialog();
776
    void updateDebugWithoutDeployMenu();
777

778
    void debugProject();
779
    void debugProjectWithoutDeploy();
780
    void debugProjectBreakMain();
781
    void startExternalApplication();
782
    void startRemoteCdbSession();
783 784
    void startRemoteProcess();
    void startRemoteServer();
785
    bool queryRemoteParameters(DebuggerStartParameters &sp, bool useScript);
786
    void attachToRemoteServer();
787
    void attachToRemoteProcess();
788
    void attachToQmlPort();
789
    void startRemoteEngine();
790
    void attachExternalApplication();
791
    Q_SLOT void attachExternalApplication(ProjectExplorer::RunControl *rc);
792
    void runScheduled();
793
    void attachCore();
794
    void attachToRemoteServer(const QString &spec);
795

796
    void enableReverseDebuggingTriggered(const QVariant &value);
hjk's avatar
hjk committed
797
    void languagesChanged();
798
    void showStatusMessage(const QString &msg, int timeout = -1);
799
    void openMemoryEditor();
800

801 802 803
    const CPlusPlus::Snapshot &cppCodeModelSnapshot() const;

    void showQtDumperLibraryWarning(const QString &details);
hjk's avatar
hjk committed
804
    DebuggerMainWindow *mainWindow() const { return m_mainWindow; }
805
    bool isDockVisible(const QString &objectName) const
hjk's avatar
hjk committed
806
        { return mainWindow()->isDockVisible(objectName); }
807 808

    bool hasSnapshots() const { return m_snapshotHandler->size(); }
hjk's avatar
hjk committed
809
    void createNewDock(QWidget *widget);
810

811 812
    void runControlStarted(DebuggerEngine *engine);
    void runControlFinished(DebuggerEngine *engine);
813
    DebuggerLanguages activeLanguages() const;
814 815
    unsigned enabledEngines() const { return m_cmdLineEnabledEngines; }
    QString debuggerForAbi(const Abi &abi, DebuggerEngineType et = NoEngineType) const;
816 817 818
    void remoteCommand(const QStringList &options, const QStringList &);

    bool isReverseDebugging() const;
819

820 821 822 823 824
    BreakHandler *breakHandler() const { return m_breakHandler; }
    SnapshotHandler *snapshotHandler() const { return m_snapshotHandler; }

    void setConfigValue(const QString &name, const QVariant &value);
    QVariant configValue(const QString &name) const;
825

ck's avatar
ck committed
826
    DebuggerRunControl *createDebugger(const DebuggerStartParameters &sp,
hjk's avatar
hjk committed
827 828
        RunConfiguration *rc = 0);
    void startDebugger(RunControl *runControl);
829
    void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
830 831 832

    void dumpLog();
    void cleanupViews();
833
    void setInitialState();
834 835 836 837

    void fontSettingsChanged(const TextEditor::FontSettings &settings);

    void updateState(DebuggerEngine *engine);
838
    void updateWatchersWindow();
839
    void onCurrentProjectChanged(ProjectExplorer::Project *project);
840 841 842 843

    void sessionLoaded();
    void aboutToUnloadSession();
    void aboutToSaveSession();
844

845
    void executeDebuggerCommand(const QString &command);
846
    void evaluateExpression(const QString &expression);
847
    void coreShutdown();
848

hjk's avatar
hjk committed
849 850
#ifdef WITH_TESTS
public slots:
851
    void testLoadProject(const QString &proFile, const TestCallBack &cb);
hjk's avatar
hjk committed
852
    void testProjectLoaded(ProjectExplorer::Project *project);
853 854 855 856
    void testUnloadProject();
    void testFinished();

    void testRunProject(const DebuggerStartParameters &sp, const TestCallBack &cb);
hjk's avatar
hjk committed
857
    void testRunControlFinished();
858 859 860 861 862 863 864 865 866 867 868 869 870

    void testPythonDumpers1();
    void testPythonDumpers2();
    void testPythonDumpers3();

    void testStateMachine1();
    void testStateMachine2();
    void testStateMachine3();

public:
    bool m_testSuccess;
    QList<TestCallBack> m_testCallbacks;

hjk's avatar
hjk committed
871 872 873
#endif


hjk's avatar
hjk committed
874
public slots:
875
    void updateDebugActions();
876 877 878

    void handleExecDetach()
    {
879
        currentEngine()->resetLocation();
880 881 882 883 884
        currentEngine()->detachDebugger();
    }

    void handleExecContinue()
    {
885
        currentEngine()->resetLocation();
886 887 888 889 890
        currentEngine()->continueInferior();
    }

    void handleExecInterrupt()
    {
891
        currentEngine()->resetLocation();
892 893 894
        currentEngine()->requestInterruptInferior();
    }

895
    void handleAbort()
896
    {
897
        currentEngine()->resetLocation();
898
        currentEngine()->abortDebugger();
899
    }
hjk's avatar
hjk committed
900 901 902

    void handleExecStep()
    {
903 904 905 906 907 908 909 910 911
        if (currentEngine()->state() == DebuggerNotReady) {
            debugProjectBreakMain();
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeStepI();
            else
                currentEngine()->executeStep();
        }
hjk's avatar
hjk committed
912 913 914 915
    }

    void handleExecNext()
    {
916 917 918 919 920 921 922 923 924
        if (currentEngine()->state() == DebuggerNotReady) {
            debugProjectBreakMain();
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeNextI();
            else
                currentEngine()->executeNext();
        }
hjk's avatar
hjk committed
925 926
    }

927 928
    void handleExecStepOut()
    {
929
        currentEngine()->resetLocation();
930 931 932 933 934
        currentEngine()->executeStepOut();
    }

    void handleExecReturn()
    {
935
        currentEngine()->resetLocation();
936 937
        currentEngine()->executeReturn();
    }
hjk's avatar
hjk committed
938 939 940 941

    void handleExecJumpToLine()
    {
        //removeTooltip();
942
        currentEngine()->resetLocation();
943 944 945
        ContextData data;
        if (currentTextEditorPosition(&data))
            currentEngine()->executeJumpToLine(data);
hjk's avatar
hjk committed
946 947 948 949 950
    }

    void handleExecRunToLine()
    {
        //removeTooltip();
951
        currentEngine()->resetLocation();
952 953 954
        ContextData data;
        if (currentTextEditorPosition(&data))
            currentEngine()->executeRunToLine(data);
hjk's avatar
hjk committed
955 956
    }

957
    void handleExecRunToSelectedFunction()
hjk's avatar
hjk committed
958
    {
959 960 961 962 963 964 965 966 967 968
        ITextEditor *textEditor = currentTextEditor();
        QTC_ASSERT(textEditor, return);
        QPlainTextEdit *ed = qobject_cast<QPlainTextEdit*>(textEditor->widget());
        if (!ed)
            return;
        QTextCursor cursor = ed->textCursor();
        QString functionName = cursor.selectedText();
        if (functionName.isEmpty()) {
            const QTextBlock block = cursor.block();
            const QString line = block.text();
969
            foreach (const QString &str, line.trimmed().split(QLatin1Char('('))) {
970 971 972 973 974 975 976 977 978 979 980 981 982
                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;
                }
            }
        }

983 984 985 986 987 988
        if (functionName.isEmpty()) {
            showStatusMessage(tr("No function selected."));
        } else {
            showStatusMessage(tr("Running to function \"%1\".")
                .arg(functionName));
            currentEngine()->resetLocation();
989
            currentEngine()->executeRunToFunction(functionName);
990
        }
hjk's avatar
hjk committed
991 992
    }

993 994 995 996
    void slotEditBreakpoint()
    {
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
997
        const BreakpointModelId id = act->data().value<BreakpointModelId>();
hjk's avatar
hjk committed
998 999
        QTC_ASSERT(id > 0, return);
        BreakWindow::editBreakpoint(id, mainWindow());
1000 1001 1002 1003
    }

    void slotRunToLine()
    {
1004 1005
        const QAction *action = qobject_cast<const QAction *>(sender());
        QTC_ASSERT(action, return);
1006
        const BreakpointMenuContextData data = action->data().value<BreakpointMenuContextData>();
1007
        currentEngine()->executeRunToLine(data);
1008 1009 1010 1011
    }

    void slotJumpToLine()
    {
1012 1013
        const QAction *action = qobject_cast<const QAction *>(sender());
        QTC_ASSERT(action, return);
1014
        const BreakpointMenuContextData data = action->data().value<BreakpointMenuContextData>();