debuggerplugin.cpp 107 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

#include "breakwindow.h"
44
#include "consolewindow.h"
45
#include "logwindow.h"
46
47
48
49
50
51
52
53
#include "moduleswindow.h"
#include "registerwindow.h"
#include "snapshotwindow.h"
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
#include "watchwindow.h"

54
#include "sessionengine.h"
55
56
#include "snapshothandler.h"
#include "threadshandler.h"
con's avatar
con committed
57

58
#include "ui_commonoptionspage.h"
hjk's avatar
hjk committed
59
#include "ui_dumperoptionpage.h"
60

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

con's avatar
con committed
78
#include <cppeditor/cppeditorconstants.h>
79
#include <cpptools/cppmodelmanagerinterface.h>
hjk's avatar
hjk committed
80

81
82
#include <extensionsystem/pluginmanager.h>

83
#include <projectexplorer/project.h>
84
#include <projectexplorer/projectexplorer.h>
con's avatar
con committed
85
86
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
87
#include <projectexplorer/target.h>
88
#include <projectexplorer/toolchaintype.h>
hjk's avatar
hjk committed
89
90

#include <texteditor/basetexteditor.h>
con's avatar
con committed
91
#include <texteditor/basetextmark.h>
92
#include <texteditor/fontsettings.h>
93
#include <texteditor/texteditorsettings.h>
hjk's avatar
hjk committed
94
95

#include <utils/qtcassert.h>
96
#include <utils/savedaction.h>
97
#include <utils/styledbar.h>
con's avatar
con committed
98

99
100
#include <qml/scriptconsole.h>

101
#include <QtCore/QTimer>
102
103
#include <QtCore/QtPlugin>
#include <QtGui/QComboBox>
104
#include <QtGui/QDockWidget>
105
106
#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
107
#include <QtGui/QToolButton>
con's avatar
con committed
108

109
110
#include <climits>

111
112
113
114
115
116
117
118
119
120
121
#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
122
// gdbserver, the trk client etc are referred to as 'Engine',
123
124
// whereas the debugged process is referred to as 'Inferior'.
//
125
126
// Transitions marked by '---' are done in the individual engines.
// Transitions marked by '+-+' are done in the base DebuggerEngine.
hjk's avatar
hjk committed
127
// Transitions marked by '*' are done asynchronously.
hjk's avatar
hjk committed
128
// The GdbEngine->setupEngine() function is described in more detail below.
129
//
hjk's avatar
hjk committed
130
131
132
133
134
135
136
// 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
137
138
139
140
141
142
//                        DebuggerNotReady
//                               +
//                      EngineSetupRequested
//                               +
//                  (calls *Engine->setupEngine())
//                            |      |
143
//                            |      |
hjk's avatar
hjk committed
144
145
146
//                       {notify-  {notify-
//                        Engine-   Engine-
//                        SetupOk}  SetupFailed}
147
148
149
150
151
152
//                            +      +
//                            +      `+-+-+> EngineSetupFailed
//                            +                   +
//                            +    [calls RunControl->startFailed]
//                            +                   +
//                            +             DebuggerFinished
hjk's avatar
hjk committed
153
154
155
156
157
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
//                            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
187
//                                                                          +
Tobias Hunger's avatar
Tobias Hunger committed
188
//                       #Interrupt@InferiorRunOk#                           +
hjk's avatar
hjk committed
189
//                                  +                                       +
hjk's avatar
hjk committed
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//                          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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
//                InferiorShutdownRequested                                 +
//                            +                                             +
//           (calls *Engine->shutdownInferior())                            +
//                         |        |                                       +
//                    {notify-   {notify-                                   +
//                     Inferior- Inferior-                                  +
//                  ShutdownOk}  ShutdownFailed}                            +
//                         +        +                                       +
//                         +        +                                       +
//  #Inferior exited#      +        +                                       +
//         |               +        +                                       +
//   {notifyInferior-      +        +                                       +
//      Exited}            +        +                                       +
//           +             +        +                                       +
//            +            +        +                                       +
//             +           +        +                                       +
//            InferiorShutdownOk InferiorShutdownFailed                     +
//                      *          *                                        +
//                  EngineShutdownRequested                                 +
//                            +                                             +
//           (calls *Engine->shutdownEngine())  <+-+-+-+-+-+-+-+-+-+-+-+-+-+' 
//                         |        |                                        
229
//                         |        |                                        
hjk's avatar
hjk committed
230
//                    {notify-   {notify-                                    
hjk's avatar
hjk committed
231
//                     Engine-    Engine-
hjk's avatar
hjk committed
232
233
234
235
236
//                  ShutdownOk}  ShutdownFailed}                             
//                         +       +                                         
//            EngineShutdownOk  EngineShutdownFailed                         
//                         *       *
//                     DebuggerFinished
237
238
239
/* 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
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
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
274
// Additional signalling:    {notifyInferiorIll}   {notifyEngineIll}
hjk's avatar
hjk committed
275
276
277


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




311

con's avatar
con committed
312
using namespace Core;
hjk's avatar
hjk committed
313
314
using namespace Debugger::Constants;
using namespace Debugger::Internal;
con's avatar
con committed
315
using namespace ProjectExplorer;
hjk's avatar
hjk committed
316
using namespace TextEditor;
con's avatar
con committed
317

hjk's avatar
hjk committed
318
319
320
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
321
322
323
324

namespace Debugger {
namespace Constants {

325
326
const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebugging";

con's avatar
con committed
327
328
const char * const STARTEXTERNAL        = "Debugger.StartExternal";
const char * const ATTACHEXTERNAL       = "Debugger.AttachExternal";
329
const char * const ATTACHCORE           = "Debugger.AttachCore";
hjk's avatar
hjk committed
330
const char * const ATTACHTCF            = "Debugger.AttachTcf";
331
const char * const ATTACHREMOTE         = "Debugger.AttachRemote";
332
const char * const DETACH               = "Debugger.Detach";
con's avatar
con committed
333

334
335
const char * const RUN_TO_LINE1         = "Debugger.RunToLine1";
const char * const RUN_TO_LINE2         = "Debugger.RunToLine2";
con's avatar
con committed
336
const char * const RUN_TO_FUNCTION      = "Debugger.RunToFunction";
337
338
const char * const JUMP_TO_LINE1        = "Debugger.JumpToLine1";
const char * const JUMP_TO_LINE2        = "Debugger.JumpToLine2";
339
const char * const RETURN_FROM_FUNCTION = "Debugger.ReturnFromFunction";
340
const char * const SNAPSHOT             = "Debugger.Snapshot";
con's avatar
con committed
341
342
343
const char * const TOGGLE_BREAK         = "Debugger.ToggleBreak";
const char * const BREAK_BY_FUNCTION    = "Debugger.BreakByFunction";
const char * const BREAK_AT_MAIN        = "Debugger.BreakAtMain";
344
345
const char * const ADD_TO_WATCH1        = "Debugger.AddToWatch1";
const char * const ADD_TO_WATCH2        = "Debugger.AddToWatch2";
346
const char * const OPERATE_BY_INSTRUCTION  = "Debugger.OperateByInstruction";
347
348
const char * const FRAME_UP             = "Debugger.FrameUp";
const char * const FRAME_DOWN           = "Debugger.FrameDown";
con's avatar
con committed
349

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
350
#ifdef Q_WS_MAC
con's avatar
con committed
351
const char * const STOP_KEY                 = "Shift+Ctrl+Y";
con's avatar
con committed
352
const char * const RESET_KEY                = "Ctrl+Shift+F5";
con's avatar
con committed
353
354
355
const char * const STEP_KEY                 = "Ctrl+Shift+I";
const char * const STEPOUT_KEY              = "Ctrl+Shift+T";
const char * const NEXT_KEY                 = "Ctrl+Shift+O";
356
const char * const REVERSE_KEY              = "";
con's avatar
con committed
357
358
const char * const RUN_TO_LINE_KEY          = "Shift+F8";
const char * const RUN_TO_FUNCTION_KEY      = "Ctrl+F6";
359
const char * const JUMP_TO_LINE_KEY         = "Ctrl+D,Ctrl+L";
con's avatar
con committed
360
const char * const TOGGLE_BREAK_KEY         = "F8";
361
362
363
364
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
365
#else
366
const char * const STOP_KEY                 = "Shift+F5";
con's avatar
con committed
367
368
369
370
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";
371
const char * const REVERSE_KEY              = "F12";
con's avatar
con committed
372
373
374
375
376
377
378
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";
379
const char * const SNAPSHOT_KEY             = "Ctrl+D,Ctrl+S";
con's avatar
con committed
380
381
382
383
384
385
#endif

} // namespace Constants
} // namespace Debugger


386

hjk's avatar
hjk committed
387
static SessionManager *sessionManager()
388
{
hjk's avatar
hjk committed
389
    return ProjectExplorerPlugin::instance()->session();
390
391
}

392
393
394
395
396
static QSettings *settings()
{
    return ICore::instance()->settings();
}

397
398
399
400
401
402
403
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

404
405
406
namespace Debugger {
namespace Internal {

hjk's avatar
hjk committed
407
408
static const char *Role = "ROLE";

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
// 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) {}
426
    void clear();
427
428

    quint64 attachPid;
429
430
    QString attachTarget;  // core file name or  server:port
    // Event handle for attaching to crashed Windows processes. 
431
432
433
    quint64 winCrashEvent;
};

434
435
436
437
438
void AttachRemoteParameters::clear()
{
    attachPid = winCrashEvent = 0;
    attachTarget.clear();
}
439

440
441
442
443
444
445
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
446
447
448
class DebugMode : public Core::BaseMode
{
public:
449
450
    DebugMode(QObject *parent = 0) : BaseMode(parent)
    {
451
        setDisplayName(QCoreApplication::translate("Debugger::Internal::DebugMode", "Debug"));
452
        setType(Core::Constants::MODE_EDIT_TYPE);
453
        setId(MODE_DEBUG);
454
        setIcon(QIcon(__(":/fancyactionbar/images/mode_Debug.png")));
455
456
        setPriority(P_MODE_DEBUG);
    }
hjk's avatar
hjk committed
457

458
459
460
461
462
463
    ~DebugMode()
    {
        // Make sure the editor manager does not get deleted.
        EditorManager::instance()->setParent(0);
    }
};
hjk's avatar
hjk committed
464

con's avatar
con committed
465
466
467
468
469
470
///////////////////////////////////////////////////////////////////////
//
// LocationMark
//
///////////////////////////////////////////////////////////////////////

471
// Used in "real" editors
472
class LocationMark : public TextEditor::BaseTextMark
con's avatar
con committed
473
474
475
476
{
public:
    LocationMark(const QString &fileName, int linenumber)
        : BaseTextMark(fileName, linenumber)
477
    {}
con's avatar
con committed
478

479
    QIcon icon() const { return DebuggerPlugin::instance()->locationMarkIcon(); }
con's avatar
con committed
480
481
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
482
    void removedFromEditor() {}
con's avatar
con committed
483
484
};

485
486
487

///////////////////////////////////////////////////////////////////////
//
488
// CommonOptionsPage
489
490
491
//
///////////////////////////////////////////////////////////////////////

492
class CommonOptionsPage : public Core::IOptionsPage
493
494
{
public:
495
    CommonOptionsPage() {}
496
497

    // IOptionsPage
498
    QString id() const
hjk's avatar
hjk committed
499
        { return _(DEBUGGER_COMMON_SETTINGS_ID); }
500
    QString displayName() const
hjk's avatar
hjk committed
501
        { return QCoreApplication::translate("Debugger", DEBUGGER_COMMON_SETTINGS_NAME); }
502
    QString category() const
hjk's avatar
hjk committed
503
        { return _(DEBUGGER_SETTINGS_CATEGORY);  }
504
    QString displayCategory() const
hjk's avatar
hjk committed
505
        { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
506
507
    QIcon categoryIcon() const
        { return QIcon(QLatin1String(DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); }
508
509

    QWidget *createPage(QWidget *parent);
510
    void apply() { m_group.apply(settings()); }
511
    void finish() { m_group.finish(); }
512
    virtual bool matches(const QString &s) const;
513
514

private:
515
    Ui::CommonOptionsPage m_ui;
516
    Utils::SavedActionSet m_group;
517
    QString m_searchKeywords;
518
519
};

520
QWidget *CommonOptionsPage::createPage(QWidget *parent)
521
522
523
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);
524
    m_group.clear();
525

526
    m_group.insert(theDebuggerAction(ListSourceFiles),
527
        m_ui.checkBoxListSourceFiles);
528
    m_group.insert(theDebuggerAction(UseAlternatingRowColors),
529
        m_ui.checkBoxUseAlternatingRowColors);
530
    m_group.insert(theDebuggerAction(UseToolTipsInMainEditor),
531
        m_ui.checkBoxUseToolTipsInMainEditor);
532
533
534
535
    m_group.insert(theDebuggerAction(CloseBuffersOnExit),
        m_ui.checkBoxCloseBuffersOnExit);
    m_group.insert(theDebuggerAction(SwitchModeOnExit),
        m_ui.checkBoxSwitchModeOnExit);
536
    m_group.insert(theDebuggerAction(AutoDerefPointers), 0);
537
538
539
540
    m_group.insert(theDebuggerAction(UseToolTipsInLocalsView), 0);
    m_group.insert(theDebuggerAction(UseToolTipsInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInStackView), 0);
541
    m_group.insert(theDebuggerAction(MaximalStackDepth),
542
        m_ui.spinBoxMaximalStackDepth);
543
544
    m_group.insert(theDebuggerAction(ShowStdNamespace), 0);
    m_group.insert(theDebuggerAction(ShowQtNamespace), 0);
545
    m_group.insert(theDebuggerAction(SortStructMembers), 0);
546
    m_group.insert(theDebuggerAction(LogTimeStamps), 0);
547
    m_group.insert(theDebuggerAction(VerboseLog), 0);
548
549
    m_group.insert(theDebuggerAction(BreakOnThrow), 0);
    m_group.insert(theDebuggerAction(BreakOnCatch), 0);
550
551
552
553
554
555
556
#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
557

558
    if (m_searchKeywords.isEmpty()) {
559
560
        QTextStream(&m_searchKeywords) << ' '
                << m_ui.checkBoxListSourceFiles->text()
561
562
                << ' ' << m_ui.checkBoxUseAlternatingRowColors->text()
                << ' ' << m_ui.checkBoxUseToolTipsInMainEditor->text()
563
564
565
#ifdef Q_OS_WIN
                << ' ' << m_ui.checkBoxRegisterForPostMortem->text()
#endif
566
567
568
                << ' ' << m_ui.labelMaximalStackDepth->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
569
570
571
#ifndef Q_OS_WIN
    m_ui.checkBoxRegisterForPostMortem->setVisible(false);
#endif
572
573
574
    return w;
}

575
576
577
578
579
bool CommonOptionsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

hjk's avatar
hjk committed
580
581
///////////////////////////////////////////////////////////////////////
//
582
// DebuggingHelperOptionPage
hjk's avatar
hjk committed
583
584
585
//
///////////////////////////////////////////////////////////////////////

586
587
588
static inline bool oxygenStyle()
{
    if (const ManhattanStyle *ms = qobject_cast<const ManhattanStyle *>(qApp->style()))
589
        return !qstrcmp("OxygenStyle", ms->baseStyle()->metaObject()->className());
590
591
592
    return false;
}

593
class DebuggingHelperOptionPage : public Core::IOptionsPage
594
595
{   // Needs tr - context
    Q_OBJECT
hjk's avatar
hjk committed
596
public:
597
    DebuggingHelperOptionPage() {}
hjk's avatar
hjk committed
598
599

    // IOptionsPage
hjk's avatar
hjk committed
600
    QString id() const { return _("Z.DebuggingHelper"); }
601
    QString displayName() const { return tr("Debugging Helper"); }
hjk's avatar
hjk committed
602
    QString category() const { return _(DEBUGGER_SETTINGS_CATEGORY); }
603
604
605
606
    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
607
608

    QWidget *createPage(QWidget *parent);
609
    void apply() { m_group.apply(settings()); }
610
    void finish() { m_group.finish(); }
611
    virtual bool matches(const QString &s) const;
hjk's avatar
hjk committed
612
613

private:
614
    Ui::DebuggingHelperOptionPage m_ui;
615
    Utils::SavedActionSet m_group;
616
    QString m_searchKeywords;
hjk's avatar
hjk committed
617
618
};

619
QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent)
hjk's avatar
hjk committed
620
621
622
623
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);

624
    m_ui.dumperLocationChooser->setExpectedKind(Utils::PathChooser::Command);
625
    m_ui.dumperLocationChooser->setPromptDialogTitle(tr("Choose DebuggingHelper Location"));
hjk's avatar
hjk committed
626
627
    m_ui.dumperLocationChooser->setInitialBrowsePathBackup(
        Core::ICore::instance()->resourcePath() + "../../lib");
hjk's avatar
hjk committed
628

629
    m_group.clear();
630
    m_group.insert(theDebuggerAction(UseDebuggingHelpers),
631
        m_ui.debuggingHelperGroupBox);
632
    m_group.insert(theDebuggerAction(UseCustomDebuggingHelperLocation),
633
        m_ui.customLocationGroupBox);
hjk's avatar
hjk committed
634
    // Suppress Oxygen style's giving flat group boxes bold titles.
635
    if (oxygenStyle())
hjk's avatar
hjk committed
636
        m_ui.customLocationGroupBox->setStyleSheet(_("QGroupBox::title { font: ; }"));
637

638
    m_group.insert(theDebuggerAction(CustomDebuggingHelperLocation),
639
        m_ui.dumperLocationChooser);
hjk's avatar
hjk committed
640

641
642
643
    m_group.insert(theDebuggerAction(UseCodeModel),
        m_ui.checkBoxUseCodeModel);

644
#ifdef QT_DEBUG
645
646
    m_group.insert(theDebuggerAction(DebugDebuggingHelpers),
        m_ui.checkBoxDebugDebuggingHelpers);
647
648
649
#else
    m_ui.checkBoxDebugDebuggingHelpers->hide();
#endif
hjk's avatar
hjk committed
650
651
652
653

#ifndef QT_DEBUG
#if 0
    cmd = am->registerAction(m_manager->m_dumpLogAction,
hjk's avatar
hjk committed
654
        DUMP_LOG, globalcontext);
hjk's avatar
hjk committed
655
656
657
658
659
660
    //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+L")));
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F11")));
    mdebug->addAction(cmd);
#endif
#endif

661
662
663
664
665
666
    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords)
                << ' ' << m_ui.debuggingHelperGroupBox->title()
                << ' ' << m_ui.customLocationGroupBox->title()
                << ' ' << m_ui.dumperLocationLabel->text()
                << ' ' << m_ui.checkBoxUseCodeModel->text()
667
                << ' ' << m_ui.checkBoxDebugDebuggingHelpers->text();
668
669
        m_searchKeywords.remove(QLatin1Char('&'));
    }
hjk's avatar
hjk committed
670
671
672
    return w;
}

673
bool DebuggingHelperOptionPage::matches(const QString &s) const
hjk's avatar
hjk committed
674
{
675
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
hjk's avatar
hjk committed
676
677
}

678

con's avatar
con committed
679
680
///////////////////////////////////////////////////////////////////////
//
681
// Argument parsing
con's avatar
con committed
682
683
684
//
///////////////////////////////////////////////////////////////////////

685
static QString msgParameterMissing(const QString &a)
686
687
688
689
{
    return DebuggerPlugin::tr("Option '%1' is missing the parameter.").arg(a);
}

690
static QString msgInvalidNumericParameter(const QString &a, const QString &number)
691
692
693
694
{
    return DebuggerPlugin::tr("The parameter '%1' of option '%2' is not a number.").arg(number, a);
}

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

754
    *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
755
756
757
    return false;
}

758
static bool parseArguments(const QStringList &args,
759
   AttachRemoteParameters *attachRemoteParameters,
hjk's avatar
hjk committed
760
   unsigned *enabledEngines, QString *errorMessage)
761
{
762
    attachRemoteParameters->clear();
763
764
    const QStringList::const_iterator cend = args.constEnd();
    for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
765
        if (!parseArgument(it, cend, attachRemoteParameters, enabledEngines, errorMessage))
766
767
            return false;
    if (Debugger::Constants::Internal::debug)
768
        qDebug().nospace() << args << "engines=0x"
769
770
            << QString::number(*enabledEngines, 16)
            << " pid" << attachRemoteParameters->attachPid
771
            << " target" << attachRemoteParameters->attachTarget << '\n';
772
773
774
    return true;
}

775
776
777
778
779
780
781
782

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

static bool isDebuggable(Core::IEditor *editor)
783
{
784
785
786
787
788
789
790
791
    // 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;
792
793
}

794
static TextEditor::ITextEditor *currentTextEditor()
con's avatar
con committed
795
{
796
797
798
799
800
801
    EditorManager *editorManager = EditorManager::instance();
    if (!editorManager)
        return 0;
    Core::IEditor *editor = editorManager->currentEditor();
    return qobject_cast<ITextEditor*>(editor);
}
con's avatar
con committed
802

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

809
810
811
struct DebuggerActions
{
    QAction *continueAction;
812
813
814
    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
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
    QAction *resetAction; // FIXME: Should not be needed in a stable release
    QAction *stepAction;
    QAction *stepOutAction;
    QAction *runToLineAction1; // in the Debug menu
    QAction *runToLineAction2; // in the text editor context menu
    QAction *runToFunctionAction;
    QAction *jumpToLineAction1; // in the Debug menu
    QAction *jumpToLineAction2; // in the text editor context menu
    QAction *returnFromFunctionAction;
    QAction *nextAction;
    QAction *snapshotAction;
    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
834

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

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

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

845
846
847
class DebuggerPluginPrivate : public QObject
{
    Q_OBJECT
848

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

852
853
    bool initialize(const QStringList &arguments, QString *errorMessage);
    void notifyCurrentEngine(int role, const QVariant &value = QVariant());
854
    void connectEngine(DebuggerEngine *engine, bool notify = true);
855
    void disconnectEngine() { connectEngine(m_sessionEngine); }
856

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

861
    void sourceFilesDockToggled(bool on)
hjk's avatar
hjk committed
862
        { if (on) notifyCurrentEngine(RequestReloadSourceFilesRole); }
863
    void modulesDockToggled(bool on)
hjk's avatar
hjk committed
864
865
866
        { if (on) notifyCurrentEngine(RequestReloadModulesRole); }
    void registerDockToggled(bool on)
        { if (on) notifyCurrentEngine(RequestReloadRegistersRole); }
867

868
    void onAction();
869
    void setSimpleDockWidgetArrangement(const Debugger::DebuggerLanguages &activeLanguages);
870

871
872
873
874
875
876
877
    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);
878

879
880
881
882
883
884
    void activatePreviousMode();
    void activateDebugMode();
    void toggleBreakpoint();
    void toggleBreakpoint(const QString &fileName, int lineNumber);
    void onModeChanged(Core::IMode *mode);
    void showSettingsDialog();
885

886
887
888
889
890
    void startExternalApplication();
    void startRemoteApplication();
    void attachExternalApplication();
    void attachExternalApplication
        (qint64 pid, const QString &binary, const QString &crashParameter);
891
    bool attachCmdLine();
892
893
    void attachCore();
    void attachCore(const QString &core, const QString &exeFileName);
894
    void attachRemote(const QString &spec);
895
    void attachRemoteTcf();
896

897
    void enableReverseDebuggingTriggered(const QVariant &value);
898
    void languagesChanged(const Debugger::DebuggerLanguages &languages);
899
    void showStatusMessage(const QString &msg, int timeout = -1);
900
    void openMemoryEditor();
901
902
903
904
905

    DebuggerMainWindow *mainWindow()
        { return qobject_cast<DebuggerMainWindow*>
            (DebuggerUISwitcher::instance()->mainWindow()); }

906
907
    inline void setConfigValue(const QString &name, const QVariant &value);
    inline QVariant configValue(const QString &name) const;
908

ck's avatar
ck committed
909
    DebuggerRunControl *createDebugger(const DebuggerStartParameters &sp,
hjk's avatar
hjk committed
910
911
        RunConfiguration *rc = 0);
    void startDebugger(RunControl *runControl);
912
    void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
913
914
915

    void dumpLog();
    void cleanupViews();
916
    void setInitialState();
917
918
919
920
921

    void fontSettingsChanged(const TextEditor::FontSettings &settings);
    DebuggerState state() const { return m_state; }

    void updateState(DebuggerEngine *engine);
922
    void onCurrentProjectChanged(ProjectExplorer::Project *project);
923
924
925
926
927
928
929
930

    void gotoLocation(const QString &file, int line, bool setMarker);

    void clearStatusMessage();

    void sessionLoaded();
    void aboutToUnloadSession();
    void aboutToSaveSession();
931
932

    void executeDebuggerCommand();
hjk's avatar
hjk committed
933
    void scriptExpressionEntered(const QString &expression);
934
    void coreShutdown();
935

936
937
938
939
940
941
942
943
public:
    DebuggerState m_state;
    DebuggerUISwitcher *m_uiSwitcher;
    DebuggerPlugin *m_manager;
    DebugMode *m_debugMode;
    DebuggerRunControlFactory *m_debuggerRunControlFactory;

    QString m_previousMode;
944
    QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
945
946
    Core::Context m_continuableContext;
    Core::Context m_interruptibleContext;
947
948
949
    Core::Context m_undisturbableContext;
    Core::Context m_finishedContext;
    Core::Context m_anyContext;
950
951
952
953
954
955
956
957
958
959
960
    AttachRemoteParameters m_attachRemoteParameters;

    QAction *m_startExternalAction;
    QAction *m_startRemoteAction;
    QAction *m_attachExternalAction;
    QAction *m_attachCoreAction;
    QAction *m_attachTcfAction;
    QAction *m_detachAction;
    QComboBox *m_langBox;
    QToolButton *m_reverseToolButton;

961
    QIcon m_startIcon;
962
    QIcon m_stopIcon;
963
    QIcon m_continueIcon;
964
965
966
967
968
969
970
    QIcon m_interruptIcon;
    QIcon m_locationMarkIcon;

    QLabel *m_statusLabel;
    QComboBox *m_threadBox;

    QDockWidget *m_breakDock;
971
    //QDockWidget *m_consoleDock;
972
973
974
975
976
977
978
979
    QDockWidget *m_modulesDock;
    QDockWidget *m_outputDock;
    QDockWidget *m_registerDock;
    QDockWidget *m_snapshotDock;
    QDockWidget *m_sourceFilesDock;
    QDockWidget *m_stackDock;
    QDockWidget *m_threadsDock;
    QDockWidget *m_watchDock;