debuggerplugin.cpp 111 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 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
** Commercial Usage
10
**
11 12 13 14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18 19 20 21 22 23
** Alternatively, 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.
24
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30 31
#include "debuggerplugin.h"

32
#include "debuggeractions.h"
33
#include "debuggeragents.h"
con's avatar
con committed
34
#include "debuggerconstants.h"
35 36 37
#include "debuggerdialogs.h"
#include "debuggerengine.h"
#include "debuggermainwindow.h"
con's avatar
con committed
38
#include "debuggerrunner.h"
39
#include "debuggerstringutils.h"
40
#include "debuggertooltip.h"
41
#include "debuggeruiswitcher.h"
42

43 44
#include "breakpoint.h"
#include "breakhandler.h"
45
#include "breakwindow.h"
46
#include "consolewindow.h"
47
#include "logwindow.h"
48 49 50
#include "moduleswindow.h"
#include "registerwindow.h"
#include "snapshotwindow.h"
hjk's avatar
hjk committed
51
#include "stackhandler.h"
52 53 54
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
hjk's avatar
hjk committed
55
#include "watchhandler.h"
56
#include "watchwindow.h"
hjk's avatar
hjk committed
57
#include "watchutils.h"
58

59 60
#include "snapshothandler.h"
#include "threadshandler.h"
con's avatar
con committed
61

62
#include "ui_commonoptionspage.h"
hjk's avatar
hjk committed
63
#include "ui_dumperoptionpage.h"
64

65
#include <coreplugin/actionmanager/actionmanager.h>
66 67
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
68
#include <coreplugin/uniqueidmanager.h>
hjk's avatar
hjk committed
69
#include <coreplugin/basemode.h>
con's avatar
con committed
70
#include <coreplugin/coreconstants.h>
71
#include <coreplugin/dialogs/ioptionspage.h>
con's avatar
con committed
72
#include <coreplugin/editormanager/editormanager.h>
hjk's avatar
hjk committed
73
#include <coreplugin/findplaceholder.h>
74
#include <coreplugin/icontext.h>
con's avatar
con committed
75
#include <coreplugin/icore.h>
76
#include <coreplugin/imode.h>
77
#include <coreplugin/icorelistener.h>
78
#include <coreplugin/manhattanstyle.h>
hjk's avatar
hjk committed
79
#include <coreplugin/minisplitter.h>
con's avatar
con committed
80
#include <coreplugin/modemanager.h>
hjk's avatar
hjk committed
81

con's avatar
con committed
82
#include <cppeditor/cppeditorconstants.h>
83
#include <cpptools/cppmodelmanagerinterface.h>
hjk's avatar
hjk committed
84

85 86
#include <extensionsystem/pluginmanager.h>

87
#include <projectexplorer/project.h>
88
#include <projectexplorer/projectexplorer.h>
con's avatar
con committed
89 90
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
91
#include <projectexplorer/target.h>
92
#include <projectexplorer/toolchaintype.h>
hjk's avatar
hjk committed
93 94

#include <texteditor/basetexteditor.h>
con's avatar
con committed
95
#include <texteditor/basetextmark.h>
96
#include <texteditor/fontsettings.h>
97
#include <texteditor/texteditorsettings.h>
hjk's avatar
hjk committed
98 99

#include <utils/qtcassert.h>
100
#include <utils/savedaction.h>
101
#include <utils/styledbar.h>
con's avatar
con committed
102

103 104
#include <qml/scriptconsole.h>

105
#include <QtCore/QTimer>
106 107
#include <QtCore/QtPlugin>
#include <QtGui/QComboBox>
108
#include <QtGui/QDockWidget>
109
#include <QtGui/QFileDialog>
hjk's avatar
hjk committed
110
#include <QtGui/QMenu>
111
#include <QtGui/QMessageBox>
112
#include <QtGui/QToolButton>
con's avatar
con committed
113

114 115
#include <climits>

116 117 118 119 120 121 122 123 124 125 126
#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

// Note: the Debugger process itself and any helper processes like
127
// gdbserver, the trk client etc are referred to as 'Engine',
128 129
// whereas the debugged process is referred to as 'Inferior'.
//
130 131
// Transitions marked by '---' are done in the individual engines.
// Transitions marked by '+-+' are done in the base DebuggerEngine.
hjk's avatar
hjk committed
132
// Transitions marked by '*' are done asynchronously.
hjk's avatar
hjk committed
133
// The GdbEngine->setupEngine() function is described in more detail below.
134
//
hjk's avatar
hjk committed
135 136 137 138 139 140 141
// 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.
//
//
//
hjk's avatar
hjk committed
142 143 144 145 146 147
//                        DebuggerNotReady
//                               +
//                      EngineSetupRequested
//                               +
//                  (calls *Engine->setupEngine())
//                            |      |
148
//                            |      |
hjk's avatar
hjk committed
149 150 151
//                       {notify-  {notify-
//                        Engine-   Engine-
//                        SetupOk}  SetupFailed}
152 153 154 155 156 157
//                            +      +
//                            +      `+-+-+> EngineSetupFailed
//                            +                   +
//                            +    [calls RunControl->startFailed]
//                            +                   +
//                            +             DebuggerFinished
hjk's avatar
hjk committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
//                            v
//                      EngineSetupOk
//                            +
//             [calls RunControl->StartSuccessful]
//                            +
//                  InferiorSetupRequested
//                            +
//             (calls *Engine->setupInferior())
//                         |       |
//                         |       |
//                    {notify-   {notify-
//                     Inferior- Inferior-
//                     SetupOk}  SetupFailed}
//                         +       +
//                         +       ` +-+-> InferiorSetupFailed +-+-+-+-+-+->.
//                         +                                                +
//                         +                                                +
//                  EngineRunRequested                                      +
//                         +                                                +
//                 (calls *Engine->runEngine())                             +
//               /       |            |        \                            +
//             /         |            |          \                          +
//            | (core)   | (attach)   |           |                         +
//            |          |            |           |                         +
//      {notify-    {notifyER&- {notifyER&-  {notify-                       +
//      Inferior-     Inferior-   Inferior-  RunEngine-                     +
//     Unrunnable}     StopOk}     RunOk}     Failed}                       +
//           +           +            +           +                         +
//   InferiorUnrunnable  +     InferiorRunOk      +                         +
//                       +                        +                         +
//                InferiorStopOk            EngineRunFailed                 +
//                                                +                         v
//                                                 `-+-+-+-+-+-+-+-+-+-+-+>-+
//                                                                          +
hjk's avatar
hjk committed
192
//                                                                          +
Tobias Hunger's avatar
Tobias Hunger committed
193
//                       #Interrupt@InferiorRunOk#                           +
hjk's avatar
hjk committed
194
//                                  +                                       +
hjk's avatar
hjk committed
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
//                          InferiorStopRequested                           +
//  #SpontaneousStop                +                                       +
//   @InferiorRunOk#         (calls *Engine->                               +
//          +               interruptInferior())                            +
//      {notify-               |          |                                 +
//     Spontaneous-       {notify-    {notify-                              +
//      Inferior-          Inferior-   Inferior-                            +
//       StopOk}           StopOk}    StopFailed}                           +
//           +              +             +                                 +
//            +            +              +                                 +
//            InferiorStopOk              +                                 +
//                  +                     +                                 +
//                  +                    +                                  +
//                  +                   +                                   +
//        #Stop@InferiorUnrunnable#    +                                    +
//          #Creator Close Event#     +                                     +
//                       +           +                                      +
hjk's avatar
hjk committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
//                InferiorShutdownRequested                                 +
//                            +                                             +
//           (calls *Engine->shutdownInferior())                            +
//                         |        |                                       +
//                    {notify-   {notify-                                   +
//                     Inferior- Inferior-                                  +
//                  ShutdownOk}  ShutdownFailed}                            +
//                         +        +                                       +
//                         +        +                                       +
//  #Inferior exited#      +        +                                       +
//         |               +        +                                       +
//   {notifyInferior-      +        +                                       +
//      Exited}            +        +                                       +
//           +             +        +                                       +
//            +            +        +                                       +
//             +           +        +                                       +
//            InferiorShutdownOk InferiorShutdownFailed                     +
//                      *          *                                        +
//                  EngineShutdownRequested                                 +
//                            +                                             +
232
//           (calls *Engine->shutdownEngine())  <+-+-+-+-+-+-+-+-+-+-+-+-+-+'
hjk's avatar
hjk committed
233 234 235
//                         |        |
//                         |        |
//                    {notify-   {notify-
hjk's avatar
hjk committed
236
//                     Engine-    Engine-
hjk's avatar
hjk committed
237 238 239
//                  ShutdownOk}  ShutdownFailed}
//                         +       +
//            EngineShutdownOk  EngineShutdownFailed
hjk's avatar
hjk committed
240 241
//                         *       *
//                     DebuggerFinished
hjk's avatar
hjk committed
242 243 244
//


245 246 247
/* 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
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
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" ];
sg1:   InferiorSetupRequested -> InferiorSetupFailed [ label="notifyInferiorFailed", style="dashed" ];
sg1:   InferiorSetupRequested -> EngineRunRequested [ label="notifyInferiorSetupOk", style="dashed" ];
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
sg1:   InferiorShutdownRequested -> InferiorShutdownOk [ label= "Engine::shutdownInferior\nnotifyInferiorShutdownOk", style="dashed" ];
sg1:   InferiorShutdownRequested -> InferiorShutdownFailed [ label="Engine::shutdownInferior\nnotifyInferiorShutdownFailed", style="dashed" ];
sg1:   InferiorExited -> InferiorShutdownOk [ label="notifyInferiorExited", style="dashed"];
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
282
// Additional signalling:    {notifyInferiorIll}   {notifyEngineIll}
hjk's avatar
hjk committed
283 284 285


// GdbEngine specific startup. All happens in EngineSetupRequested state
286
//
287 288
// Transitions marked by '---' are done in the individual adapters.
// Transitions marked by '+-+' are done in the GdbEngine.
hjk's avatar
hjk committed
289
//
hjk's avatar
hjk committed
290
//                  GdbEngine::setupEngine()
291 292 293 294 295
//                          +
//            (calls *Adapter->startAdapter())
//                          |      |
//                          |      `---> handleAdapterStartFailed()
//                          |                   +
hjk's avatar
hjk committed
296
//                          |             {notifyEngineSetupFailed}
297 298 299
//                          |
//                 handleAdapterStarted()
//                          +
hjk's avatar
hjk committed
300 301 302 303 304
//                 {notifyEngineSetupOk}
//
//
//
//                GdbEngine::setupInferior()
305
//                          +
306 307
//            (calls *Adapter->prepareInferior())
//                          |      |
hjk's avatar
hjk committed
308
//                          |      `---> handlePrepareInferiorFailed()
309
//                          |                   +
hjk's avatar
hjk committed
310
//                          |             {notifyInferiorSetupFailed}
311
//                          |
hjk's avatar
hjk committed
312
//                handleInferiorPrepared()
313
//                          +
314
//                {notifyInferiorSetupOk}
315 316 317 318




319

con's avatar
con committed
320
using namespace Core;
hjk's avatar
hjk committed
321 322
using namespace Debugger::Constants;
using namespace Debugger::Internal;
con's avatar
con committed
323
using namespace ProjectExplorer;
hjk's avatar
hjk committed
324
using namespace TextEditor;
con's avatar
con committed
325

hjk's avatar
hjk committed
326 327 328
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
329 330 331 332

namespace Debugger {
namespace Constants {

333 334
const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebugging";

con's avatar
con committed
335 336
const char * const STARTEXTERNAL        = "Debugger.StartExternal";
const char * const ATTACHEXTERNAL       = "Debugger.AttachExternal";
337
const char * const ATTACHCORE           = "Debugger.AttachCore";
hjk's avatar
hjk committed
338
const char * const ATTACHTCF            = "Debugger.AttachTcf";
339
const char * const ATTACHREMOTE         = "Debugger.AttachRemote";
340
const char * const DETACH               = "Debugger.Detach";
con's avatar
con committed
341

342 343
const char * const RUN_TO_LINE1         = "Debugger.RunToLine1";
const char * const RUN_TO_LINE2         = "Debugger.RunToLine2";
con's avatar
con committed
344
const char * const RUN_TO_FUNCTION      = "Debugger.RunToFunction";
345 346
const char * const JUMP_TO_LINE1        = "Debugger.JumpToLine1";
const char * const JUMP_TO_LINE2        = "Debugger.JumpToLine2";
347
const char * const RETURN_FROM_FUNCTION = "Debugger.ReturnFromFunction";
348
const char * const SNAPSHOT             = "Debugger.Snapshot";
con's avatar
con committed
349 350 351
const char * const TOGGLE_BREAK         = "Debugger.ToggleBreak";
const char * const BREAK_BY_FUNCTION    = "Debugger.BreakByFunction";
const char * const BREAK_AT_MAIN        = "Debugger.BreakAtMain";
352 353
const char * const ADD_TO_WATCH1        = "Debugger.AddToWatch1";
const char * const ADD_TO_WATCH2        = "Debugger.AddToWatch2";
354
const char * const OPERATE_BY_INSTRUCTION  = "Debugger.OperateByInstruction";
355 356
const char * const FRAME_UP             = "Debugger.FrameUp";
const char * const FRAME_DOWN           = "Debugger.FrameDown";
con's avatar
con committed
357

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
358
#ifdef Q_WS_MAC
con's avatar
con committed
359
const char * const STOP_KEY                 = "Shift+Ctrl+Y";
con's avatar
con committed
360
const char * const RESET_KEY                = "Ctrl+Shift+F5";
con's avatar
con committed
361 362 363
const char * const STEP_KEY                 = "Ctrl+Shift+I";
const char * const STEPOUT_KEY              = "Ctrl+Shift+T";
const char * const NEXT_KEY                 = "Ctrl+Shift+O";
364
const char * const REVERSE_KEY              = "";
con's avatar
con committed
365 366
const char * const RUN_TO_LINE_KEY          = "Shift+F8";
const char * const RUN_TO_FUNCTION_KEY      = "Ctrl+F6";
367
const char * const JUMP_TO_LINE_KEY         = "Ctrl+D,Ctrl+L";
con's avatar
con committed
368
const char * const TOGGLE_BREAK_KEY         = "F8";
369 370 371 372
const char * const BREAK_BY_FUNCTION_KEY    = "Ctrl+D,Ctrl+F";
const char * const BREAK_AT_MAIN_KEY        = "Ctrl+D,Ctrl+M";
const char * const ADD_TO_WATCH_KEY         = "Ctrl+D,Ctrl+W";
const char * const SNAPSHOT_KEY             = "Ctrl+D,Ctrl+S";
con's avatar
con committed
373
#else
374
const char * const STOP_KEY                 = "Shift+F5";
con's avatar
con committed
375 376 377 378
const char * const RESET_KEY                = "Ctrl+Shift+F5";
const char * const STEP_KEY                 = "F11";
const char * const STEPOUT_KEY              = "Shift+F11";
const char * const NEXT_KEY                 = "F10";
379
const char * const REVERSE_KEY              = "F12";
con's avatar
con committed
380 381 382 383 384 385 386
const char * const RUN_TO_LINE_KEY          = "";
const char * const RUN_TO_FUNCTION_KEY      = "";
const char * const JUMP_TO_LINE_KEY         = "";
const char * const TOGGLE_BREAK_KEY         = "F9";
const char * const BREAK_BY_FUNCTION_KEY    = "";
const char * const BREAK_AT_MAIN_KEY        = "";
const char * const ADD_TO_WATCH_KEY         = "Ctrl+Alt+Q";
387
const char * const SNAPSHOT_KEY             = "Ctrl+D,Ctrl+S";
con's avatar
con committed
388 389 390 391 392 393
#endif

} // namespace Constants
} // namespace Debugger


394

hjk's avatar
hjk committed
395
static SessionManager *sessionManager()
396
{
hjk's avatar
hjk committed
397
    return ProjectExplorerPlugin::instance()->session();
398 399
}

400 401 402 403 404
static QSettings *settings()
{
    return ICore::instance()->settings();
}

405 406 407 408 409 410 411
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

412 413 414
namespace Debugger {
namespace Internal {

hjk's avatar
hjk committed
415 416
static const char *Role = "ROLE";

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
// 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.

void addGdbOptionPages(QList<Core::IOptionsPage*> *opts);
void addScriptOptionPages(QList<Core::IOptionsPage*> *opts);
void addTcfOptionPages(QList<Core::IOptionsPage*> *opts);
#ifdef CDB_ENABLED
void addCdbOptionPages(QList<Core::IOptionsPage*> *opts);
#endif


struct AttachRemoteParameters
{
    AttachRemoteParameters() : attachPid(0), winCrashEvent(0) {}
434
    void clear();
435 436

    quint64 attachPid;
437
    QString attachTarget;  // core file name or  server:port
438
    // Event handle for attaching to crashed Windows processes.
439 440 441
    quint64 winCrashEvent;
};

442 443 444 445 446
void AttachRemoteParameters::clear()
{
    attachPid = winCrashEvent = 0;
    attachTarget.clear();
}
447

448 449 450 451 452 453
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
454 455 456
class DebugMode : public Core::BaseMode
{
public:
457 458
    DebugMode(QObject *parent = 0) : BaseMode(parent)
    {
459
        setDisplayName(QCoreApplication::translate("Debugger::Internal::DebugMode", "Debug"));
460
        setType(Core::Constants::MODE_EDIT_TYPE);
461
        setId(MODE_DEBUG);
462
        setIcon(QIcon(__(":/fancyactionbar/images/mode_Debug.png")));
463 464
        setPriority(P_MODE_DEBUG);
    }
hjk's avatar
hjk committed
465

466 467 468 469 470 471
    ~DebugMode()
    {
        // Make sure the editor manager does not get deleted.
        EditorManager::instance()->setParent(0);
    }
};
hjk's avatar
hjk committed
472

473

con's avatar
con committed
474 475 476 477 478 479
///////////////////////////////////////////////////////////////////////
//
// LocationMark
//
///////////////////////////////////////////////////////////////////////

480
// Used in "real" editors
481
class LocationMark : public TextEditor::BaseTextMark
con's avatar
con committed
482 483 484 485
{
public:
    LocationMark(const QString &fileName, int linenumber)
        : BaseTextMark(fileName, linenumber)
486
    {}
con's avatar
con committed
487

488
    QIcon icon() const { return DebuggerPlugin::instance()->locationMarkIcon(); }
con's avatar
con committed
489 490
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
491
    void removedFromEditor() {}
con's avatar
con committed
492 493
};

494 495 496

///////////////////////////////////////////////////////////////////////
//
497
// CommonOptionsPage
498 499 500
//
///////////////////////////////////////////////////////////////////////

501
class CommonOptionsPage : public Core::IOptionsPage
502 503
{
public:
504
    CommonOptionsPage() {}
505 506

    // IOptionsPage
507
    QString id() const
hjk's avatar
hjk committed
508
        { return _(DEBUGGER_COMMON_SETTINGS_ID); }
509
    QString displayName() const
hjk's avatar
hjk committed
510
        { return QCoreApplication::translate("Debugger", DEBUGGER_COMMON_SETTINGS_NAME); }
511
    QString category() const
hjk's avatar
hjk committed
512
        { return _(DEBUGGER_SETTINGS_CATEGORY);  }
513
    QString displayCategory() const
hjk's avatar
hjk committed
514
        { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
515 516
    QIcon categoryIcon() const
        { return QIcon(QLatin1String(DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); }
517 518

    QWidget *createPage(QWidget *parent);
519
    void apply() { m_group.apply(settings()); }
520
    void finish() { m_group.finish(); }
521
    virtual bool matches(const QString &s) const;
522 523

private:
524
    Ui::CommonOptionsPage m_ui;
525
    Utils::SavedActionSet m_group;
526
    QString m_searchKeywords;
527 528
};

529
QWidget *CommonOptionsPage::createPage(QWidget *parent)
530 531 532
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);
533
    m_group.clear();
534

535
    m_group.insert(theDebuggerAction(ListSourceFiles),
536
        m_ui.checkBoxListSourceFiles);
537
    m_group.insert(theDebuggerAction(UseAlternatingRowColors),
538
        m_ui.checkBoxUseAlternatingRowColors);
539
    m_group.insert(theDebuggerAction(UseToolTipsInMainEditor),
540
        m_ui.checkBoxUseToolTipsInMainEditor);
541 542 543 544
    m_group.insert(theDebuggerAction(CloseBuffersOnExit),
        m_ui.checkBoxCloseBuffersOnExit);
    m_group.insert(theDebuggerAction(SwitchModeOnExit),
        m_ui.checkBoxSwitchModeOnExit);
545
    m_group.insert(theDebuggerAction(AutoDerefPointers), 0);
546 547 548 549
    m_group.insert(theDebuggerAction(UseToolTipsInLocalsView), 0);
    m_group.insert(theDebuggerAction(UseToolTipsInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInStackView), 0);
550
    m_group.insert(theDebuggerAction(MaximalStackDepth),
551
        m_ui.spinBoxMaximalStackDepth);
552 553
    m_group.insert(theDebuggerAction(ShowStdNamespace), 0);
    m_group.insert(theDebuggerAction(ShowQtNamespace), 0);
554
    m_group.insert(theDebuggerAction(SortStructMembers), 0);
555
    m_group.insert(theDebuggerAction(LogTimeStamps), 0);
556
    m_group.insert(theDebuggerAction(VerboseLog), 0);
557 558
    m_group.insert(theDebuggerAction(BreakOnThrow), 0);
    m_group.insert(theDebuggerAction(BreakOnCatch), 0);
559 560 561 562 563 564 565
#ifdef Q_OS_WIN
    Utils::SavedAction *registerAction = theDebuggerAction(RegisterForPostMortem);
    m_group.insert(registerAction,
        m_ui.checkBoxRegisterForPostMortem);
    connect(registerAction, SIGNAL(toggled(bool)),
            m_ui.checkBoxRegisterForPostMortem, SLOT(setChecked(bool)));
#endif
566

567
    if (m_searchKeywords.isEmpty()) {
568 569
        QTextStream(&m_searchKeywords) << ' '
                << m_ui.checkBoxListSourceFiles->text()
570 571
                << ' ' << m_ui.checkBoxUseAlternatingRowColors->text()
                << ' ' << m_ui.checkBoxUseToolTipsInMainEditor->text()
572 573 574
#ifdef Q_OS_WIN
                << ' ' << m_ui.checkBoxRegisterForPostMortem->text()
#endif
575 576 577
                << ' ' << m_ui.labelMaximalStackDepth->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
578 579 580
#ifndef Q_OS_WIN
    m_ui.checkBoxRegisterForPostMortem->setVisible(false);
#endif
581 582 583
    return w;
}

584 585 586 587 588
bool CommonOptionsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

hjk's avatar
hjk committed
589 590
///////////////////////////////////////////////////////////////////////
//
591
// DebuggingHelperOptionPage
hjk's avatar
hjk committed
592 593 594
//
///////////////////////////////////////////////////////////////////////

595 596 597
static inline bool oxygenStyle()
{
    if (const ManhattanStyle *ms = qobject_cast<const ManhattanStyle *>(qApp->style()))
598
        return !qstrcmp("OxygenStyle", ms->baseStyle()->metaObject()->className());
599 600 601
    return false;
}

602
class DebuggingHelperOptionPage : public Core::IOptionsPage
603 604
{   // Needs tr - context
    Q_OBJECT
hjk's avatar
hjk committed
605
public:
606
    DebuggingHelperOptionPage() {}
hjk's avatar
hjk committed
607 608

    // IOptionsPage
hjk's avatar
hjk committed
609
    QString id() const { return _("Z.DebuggingHelper"); }
610
    QString displayName() const { return tr("Debugging Helper"); }
hjk's avatar
hjk committed
611
    QString category() const { return _(DEBUGGER_SETTINGS_CATEGORY); }
612 613 614 615
    QString displayCategory() const
    { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
    QIcon categoryIcon() const
    { return QIcon(QLatin1String(DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); }
hjk's avatar
hjk committed
616 617

    QWidget *createPage(QWidget *parent);
618
    void apply() { m_group.apply(settings()); }
619
    void finish() { m_group.finish(); }
620
    virtual bool matches(const QString &s) const;
hjk's avatar
hjk committed
621 622

private:
623
    Ui::DebuggingHelperOptionPage m_ui;
624
    Utils::SavedActionSet m_group;
625
    QString m_searchKeywords;
hjk's avatar
hjk committed
626 627
};

628
QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent)
hjk's avatar
hjk committed
629 630 631 632
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);

633
    m_ui.dumperLocationChooser->setExpectedKind(Utils::PathChooser::Command);
634
    m_ui.dumperLocationChooser->setPromptDialogTitle(tr("Choose DebuggingHelper Location"));
hjk's avatar
hjk committed
635 636
    m_ui.dumperLocationChooser->setInitialBrowsePathBackup(
        Core::ICore::instance()->resourcePath() + "../../lib");
hjk's avatar
hjk committed
637

638
    m_group.clear();
639
    m_group.insert(theDebuggerAction(UseDebuggingHelpers),
640
        m_ui.debuggingHelperGroupBox);
641
    m_group.insert(theDebuggerAction(UseCustomDebuggingHelperLocation),
642
        m_ui.customLocationGroupBox);
hjk's avatar
hjk committed
643
    // Suppress Oxygen style's giving flat group boxes bold titles.
644
    if (oxygenStyle())
hjk's avatar
hjk committed
645
        m_ui.customLocationGroupBox->setStyleSheet(_("QGroupBox::title { font: ; }"));
646

647
    m_group.insert(theDebuggerAction(CustomDebuggingHelperLocation),
648
        m_ui.dumperLocationChooser);
hjk's avatar
hjk committed
649

650 651 652
    m_group.insert(theDebuggerAction(UseCodeModel),
        m_ui.checkBoxUseCodeModel);

653
#ifdef QT_DEBUG
654 655
    m_group.insert(theDebuggerAction(DebugDebuggingHelpers),
        m_ui.checkBoxDebugDebuggingHelpers);
656 657 658
#else
    m_ui.checkBoxDebugDebuggingHelpers->hide();
#endif
hjk's avatar
hjk committed
659 660 661 662

#ifndef QT_DEBUG
#if 0
    cmd = am->registerAction(m_manager->m_dumpLogAction,
hjk's avatar
hjk committed
663
        DUMP_LOG, globalcontext);
hjk's avatar
hjk committed
664 665 666 667 668 669
    //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+L")));
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F11")));
    mdebug->addAction(cmd);
#endif
#endif

670 671 672 673 674 675
    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords)
                << ' ' << m_ui.debuggingHelperGroupBox->title()
                << ' ' << m_ui.customLocationGroupBox->title()
                << ' ' << m_ui.dumperLocationLabel->text()
                << ' ' << m_ui.checkBoxUseCodeModel->text()
676
                << ' ' << m_ui.checkBoxDebugDebuggingHelpers->text();
677 678
        m_searchKeywords.remove(QLatin1Char('&'));
    }
hjk's avatar
hjk committed
679 680 681
    return w;
}

682
bool DebuggingHelperOptionPage::matches(const QString &s) const
hjk's avatar
hjk committed
683
{
684
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
hjk's avatar
hjk committed
685 686
}

687

con's avatar
con committed
688 689
///////////////////////////////////////////////////////////////////////
//
690
// Argument parsing
con's avatar
con committed
691 692 693
//
///////////////////////////////////////////////////////////////////////

694
static QString msgParameterMissing(const QString &a)
695 696 697 698
{
    return DebuggerPlugin::tr("Option '%1' is missing the parameter.").arg(a);
}

699
static QString msgInvalidNumericParameter(const QString &a, const QString &number)
700 701 702 703
{
    return DebuggerPlugin::tr("The parameter '%1' of option '%2' is not a number.").arg(number, a);
}

704
static bool parseArgument(QStringList::const_iterator &it,
705 706 707
    const QStringList::const_iterator &cend,
    AttachRemoteParameters *attachRemoteParameters,
    unsigned *enabledEngines, QString *errorMessage)
708 709 710
{
    const QString &option = *it;
    // '-debug <pid>'
711 712
    // '-debug <corefile>'
    // '-debug <server:port>'
hjk's avatar
hjk committed
713
    if (*it == _("-debug")) {
714 715 716 717 718 719
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
720
        attachRemoteParameters->attachPid = it->toULongLong(&ok);
721 722
        if (!ok)
            attachRemoteParameters->attachTarget = *it;
723 724
        return true;
    }
725 726
    // -wincrashevent <event-handle>. A handle used for
    // a handshake when attaching to a crashed Windows process.
hjk's avatar
hjk committed
727
    if (*it == _("-wincrashevent")) {
728 729 730 731 732 733
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
734
        attachRemoteParameters->winCrashEvent = it->toULongLong(&ok);
735 736 737 738 739 740
        if (!ok) {
            *errorMessage = msgInvalidNumericParameter(option, *it);
            return false;
        }
        return true;
    }
hjk's avatar
hjk committed
741
    // Engine disabling.
hjk's avatar
hjk committed
742
    if (option == _("-disable-cdb")) {
743
        *enabledEngines &= ~Debugger::CdbEngineType;
744 745
        return true;
    }
hjk's avatar
hjk committed
746
    if (option == _("-disable-gdb")) {
747
        *enabledEngines &= ~Debugger::GdbEngineType;
748 749
        return true;
    }
750 751 752 753
    if (option == _("-disable-qmldb")) {
        *enabledEngines &= ~Debugger::QmlEngineType;
        return true;
    }
hjk's avatar
hjk committed
754
    if (option == _("-disable-sdb")) {
755
        *enabledEngines &= ~Debugger::ScriptEngineType;
756 757
        return true;
    }
758
    if (option == _("-disable-tcf")) {
hjk's avatar
hjk committed
759 760 761
        *enabledEngines &= ~TcfEngineType;
        return true;
    }
762

763
    *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
764 765 766
    return false;
}

767
static bool parseArguments(const QStringList &args,
768
   AttachRemoteParameters *attachRemoteParameters,
hjk's avatar
hjk committed
769
   unsigned *enabledEngines, QString *errorMessage)
770
{
771
    attachRemoteParameters->clear();
772 773
    const QStringList::const_iterator cend = args.constEnd();
    for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
774
        if (!parseArgument(it, cend, attachRemoteParameters, enabledEngines, errorMessage))
775 776
            return false;
    if (Debugger::Constants::Internal::debug)
777
        qDebug().nospace() << args << "engines=0x"
778 779
            << QString::number(*enabledEngines, 16)
            << " pid" << attachRemoteParameters->attachPid
780
            << " target" << attachRemoteParameters->attachTarget << '\n';
781 782 783
    return true;
}

784 785 786 787 788 789 790 791

///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

static bool isDebuggable(Core::IEditor *editor)
792
{
793 794 795 796 797 798 799 800
    // Only blacklist Qml. Whitelisting would fail on C++ code in files
    // with strange names, more harm would be done this way.
    //Core::IFile *file = editor->file();
    //return !(file && file->mimeType() == "application/x-qml");

    // Nowadays, even Qml is debuggable.
    Q_UNUSED(editor);
    return true;
801 802
}

con's avatar
con committed
803

804 805 806 807 808
///////////////////////////////////////////////////////////////////////
//
// DebuggerPluginPrivate
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
809

810 811 812
struct DebuggerActions
{
    QAction *continueAction;
813 814 815
    QAction *stopAction; // on the application output button if "Stop" is possible
    QAction *interruptAction; // on the fat debug button if "Pause" is possible
    QAction *undisturbableAction; // on the fat debug button if nothing can be done
816 817 818
    QAction *resetAction; // FIXME: Should not be needed in a stable release
    QAction *stepAction;
    QAction *stepOutAction;
819
    QAction *runToLineAction; // Debug menu
820
    QAction *runToFunctionAction;
821
    QAction *jumpToLineAction; // in the Debug menu
822 823
    QAction *returnFromFunctionAction;
    QAction *nextAction;
824
    //QAction *snapshotAction;
825 826 827 828 829 830 831 832
    QAction *watchAction1; // in the Debug menu
    QAction *watchAction2; // in the text editor context menu
    QAction *breakAction;
    QAction *sepAction;
    QAction *reverseDirectionAction;
    QAction *frameUpAction;
    QAction *frameDownAction;
};
con's avatar
con committed
833

834
} // namespace Internal
con's avatar
con committed
835

836
using namespace Debugger::Internal;
con's avatar
con committed
837

838 839 840 841 842
///////////////////////////////////////////////////////////////////////
//
// DebuggerPluginPrivate
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
843

844 845 846
class DebuggerPluginPrivate : public QObject
{
    Q_OBJECT
847

848 849
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
850

851
    bool initialize(const QStringList &arguments, QString *errorMessage);
852
    void connectEngine(DebuggerEngine *engine, bool notify = true);
hjk's avatar
hjk committed
853
    void disconnectEngine() { connectEngine(0); }
854
    DebuggerEngine *currentEngine() const { return m_currentEngine; }
855

856 857
public slots:
    void updateWatchersHeader(int section, int, int newSize)
858 859 860
    {
        m_watchersWindow->header()->resizeSection(section, newSize);
    }
861

862
    void sourceFilesDockToggled(bool on)
863 864 865 866 867
    {
        if (on)
            m_currentEngine->reloadSourceFiles();
    }

868
    void modulesDockToggled(bool on)
869 870 871 872
    {
        if (on)
            m_currentEngine->reloadModules();
    }
873

hjk's avatar
hjk committed
874
    void registerDockToggled(bool on)
875
    {
876
        if (on)
877 878
            m_currentEngine->reloadRegisters();
    }
879

880 881 882 883 884 885 886 887 888 889
    void synchronizeBreakpoints()
    {
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
            if (DebuggerRunControl *runControl = m_snapshotHandler->at(i)) {
                DebuggerEngine *engine = runControl->engine();
                engine->attemptBreakpointSynchronization();
            }
        }
    }

hjk's avatar
hjk committed
890 891 892 893 894 895 896 897 898 899
    void synchronizeWatchers()
    {
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
            if (DebuggerRunControl *runControl = m_snapshotHandler->at(i)) {
                DebuggerEngine *engine = runControl->engine();
                engine->watchHandler()->synchronizeWatchers();
            }
        }
    }

900
    void setSimpleDockWidgetArrangement(Debugger::DebuggerLanguages activeLanguages);
901

902 903 904 905 906 907 908
    void editorOpened(Core::IEditor *editor);
    void editorAboutToClose(Core::IEditor *editor);
    void setBusyCursor(bool busy);
    void requestMark(TextEditor::ITextEditor *editor, int lineNumber);
    void showToolTip(TextEditor::ITextEditor *editor, const QPoint &pnt, int pos);
    void requestContextMenu(TextEditor::ITextEditor *editor,
        int lineNumber, QMenu *menu);
909

910 911 912 913 914 915
    void activatePreviousMode();
    void activateDebugMode();
    void toggleBreakpoint();
    void toggleBreakpoint(const QString &fileName, int lineNumber);
    void onModeChanged(Core::IMode *mode);
    void showSettingsDialog();
916

917 918 919 920 921
    void startExternalApplication();
    void startRemoteApplication();
    void attachExternalApplication();
    void attachExternalApplication
        (qint64 pid, const QString &binary, const QString &crashParameter);
922
    bool attachCmdLine();
923 924
    void attachCore();
    void attachCore(const QString &core, const QString &exeFileName);
925
    void attachRemote(const QString &spec