debuggerplugin.cpp 117 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
**
con's avatar
con committed
9
** No Commercial Usage
10
**
con's avatar
con committed
11
12
13
14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
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
**
con's avatar
con committed
25
26
27
28
29
30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
con's avatar
con committed
31
**
32
**************************************************************************/
hjk's avatar
hjk committed
33

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

Friedemann Kleint's avatar
Friedemann Kleint committed
36
#include "debuggerstartparameters.h"
37
#include "debuggeractions.h"
con's avatar
con committed
38
#include "debuggerconstants.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
47
#include "debuggertooltip.h"

48
49
#include "breakpoint.h"
#include "breakhandler.h"
50
#include "breakwindow.h"
51
#include "consolewindow.h"
52
#include "disassembleragent.h"
53
#include "logwindow.h"
54
#include "moduleswindow.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
55
#include "moduleshandler.h"
56
57
#include "registerwindow.h"
#include "snapshotwindow.h"
hjk's avatar
hjk committed
58
#include "stackhandler.h"
59
60
61
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
hjk's avatar
hjk committed
62
#include "watchhandler.h"
63
#include "watchwindow.h"
hjk's avatar
hjk committed
64
#include "watchutils.h"
65

66
67
#include "snapshothandler.h"
#include "threadshandler.h"
hjk's avatar
hjk committed
68
#include "gdb/gdboptionspage.h"
con's avatar
con committed
69

70
#include "ui_commonoptionspage.h"
hjk's avatar
hjk committed
71
#include "ui_dumperoptionpage.h"
72

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

con's avatar
con committed
90
#include <cppeditor/cppeditorconstants.h>
91
#include <cplusplus/ModelManagerInterface.h>
hjk's avatar
hjk committed
92

93
94
#include <extensionsystem/pluginmanager.h>

95
#include <projectexplorer/project.h>
96
#include <projectexplorer/projectexplorer.h>
con's avatar
con committed
97
98
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
99
#include <projectexplorer/target.h>
hjk's avatar
hjk committed
100
#include <projectexplorer/toolchain.h>
101
#include <projectexplorer/toolchaintype.h>
hjk's avatar
hjk committed
102

103
104
#include <qt4projectmanager/qt4projectmanagerconstants.h>

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

#include <utils/qtcassert.h>
110
#include <utils/savedaction.h>
111
#include <utils/styledbar.h>
112
#include <utils/proxyaction.h>
con's avatar
con committed
113

114
115
#include <qml/scriptconsole.h>

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

129
130
#include <climits>

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


261
262
263
/* 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
264

265
266
267
268
269
270
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" ];
271
sg1:   InferiorSetupRequested -> InferiorSetupOk [ label="notifyInferiorSetupOk", style="dashed" ];
272
sg1:   InferiorSetupRequested -> InferiorSetupFailed [ label="notifyInferiorFailed", style="dashed" ];
273
sg1:   InferiorSetupOk -> EngineRunRequested
274
275
276
277
278
279
280
281
282
283
284
285
286
287
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
288
289
sg1:   InferiorStopOk -> InferiorShutdownRequested [ label="Close event" ];
sg1:   InferiorUnrunnable -> InferiorShutdownRequested [ label="Close event" ];
290
291
sg1:   InferiorShutdownRequested -> InferiorShutdownOk [ label= "Engine::shutdownInferior\nnotifyInferiorShutdownOk", style="dashed" ];
sg1:   InferiorShutdownRequested -> InferiorShutdownFailed [ label="Engine::shutdownInferior\nnotifyInferiorShutdownFailed", style="dashed" ];
292
293
sg1:   InferiorExited -> InferiorExitOk [ label="notifyInferiorExited", style="dashed"];
sg1:   InferiorExitOk -> InferiorShutdownOk
294
295
296
297
298
299
300
301
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
302
// Additional signalling:    {notifyInferiorIll}   {notifyEngineIll}
hjk's avatar
hjk committed
303
304
305


// GdbEngine specific startup. All happens in EngineSetupRequested state
306
//
307
308
// Transitions marked by '---' are done in the individual adapters.
// Transitions marked by '+-+' are done in the GdbEngine.
hjk's avatar
hjk committed
309
//
hjk's avatar
hjk committed
310
//                  GdbEngine::setupEngine()
311
312
313
314
315
//                          +
//            (calls *Adapter->startAdapter())
//                          |      |
//                          |      `---> handleAdapterStartFailed()
//                          |                   +
hjk's avatar
hjk committed
316
//                          |             {notifyEngineSetupFailed}
317
318
319
//                          |
//                 handleAdapterStarted()
//                          +
hjk's avatar
hjk committed
320
321
322
323
324
//                 {notifyEngineSetupOk}
//
//
//
//                GdbEngine::setupInferior()
325
//                          +
326
327
//            (calls *Adapter->prepareInferior())
//                          |      |
hjk's avatar
hjk committed
328
//                          |      `---> handlePrepareInferiorFailed()
329
//                          |                   +
hjk's avatar
hjk committed
330
//                          |             {notifyInferiorSetupFailed}
331
//                          |
hjk's avatar
hjk committed
332
//                handleInferiorPrepared()
333
//                          +
334
//                {notifyInferiorSetupOk}
335
336
337
338




339

con's avatar
con committed
340
using namespace Core;
hjk's avatar
hjk committed
341
using namespace Debugger::Constants;
con's avatar
con committed
342
using namespace ProjectExplorer;
hjk's avatar
hjk committed
343
using namespace TextEditor;
con's avatar
con committed
344

hjk's avatar
hjk committed
345
346
347
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
348
349
350
351

namespace Debugger {
namespace Constants {

352
353
const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebugging";

con's avatar
con committed
354
355
const char * const STARTEXTERNAL        = "Debugger.StartExternal";
const char * const ATTACHEXTERNAL       = "Debugger.AttachExternal";
356
const char * const ATTACHCORE           = "Debugger.AttachCore";
hjk's avatar
hjk committed
357
const char * const ATTACHTCF            = "Debugger.AttachTcf";
358
const char * const ATTACHREMOTE         = "Debugger.AttachRemote";
359
const char * const ATTACHREMOTECDB      = "Debugger.AttachRemoteCDB";
360
const char * const STARTREMOTELLDB      = "Debugger.StartRemoteLLDB";
361
const char * const DETACH               = "Debugger.Detach";
con's avatar
con committed
362

363
364
const char * const RUN_TO_LINE1         = "Debugger.RunToLine1";
const char * const RUN_TO_LINE2         = "Debugger.RunToLine2";
con's avatar
con committed
365
const char * const RUN_TO_FUNCTION      = "Debugger.RunToFunction";
366
367
const char * const JUMP_TO_LINE1        = "Debugger.JumpToLine1";
const char * const JUMP_TO_LINE2        = "Debugger.JumpToLine2";
368
const char * const RETURN_FROM_FUNCTION = "Debugger.ReturnFromFunction";
369
const char * const SNAPSHOT             = "Debugger.Snapshot";
con's avatar
con committed
370
371
372
const char * const TOGGLE_BREAK         = "Debugger.ToggleBreak";
const char * const BREAK_BY_FUNCTION    = "Debugger.BreakByFunction";
const char * const BREAK_AT_MAIN        = "Debugger.BreakAtMain";
373
374
const char * const ADD_TO_WATCH1        = "Debugger.AddToWatch1";
const char * const ADD_TO_WATCH2        = "Debugger.AddToWatch2";
375
const char * const OPERATE_BY_INSTRUCTION  = "Debugger.OperateByInstruction";
376
377
const char * const FRAME_UP             = "Debugger.FrameUp";
const char * const FRAME_DOWN           = "Debugger.FrameDown";
con's avatar
con committed
378

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
379
#ifdef Q_WS_MAC
con's avatar
con committed
380
const char * const STOP_KEY                 = "Shift+Ctrl+Y";
con's avatar
con committed
381
const char * const RESET_KEY                = "Ctrl+Shift+F5";
con's avatar
con committed
382
383
384
const char * const STEP_KEY                 = "Ctrl+Shift+I";
const char * const STEPOUT_KEY              = "Ctrl+Shift+T";
const char * const NEXT_KEY                 = "Ctrl+Shift+O";
385
const char * const REVERSE_KEY              = "";
con's avatar
con committed
386
387
const char * const RUN_TO_LINE_KEY          = "Shift+F8";
const char * const RUN_TO_FUNCTION_KEY      = "Ctrl+F6";
388
const char * const JUMP_TO_LINE_KEY         = "Ctrl+D,Ctrl+L";
con's avatar
con committed
389
const char * const TOGGLE_BREAK_KEY         = "F8";
390
391
392
393
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
394
#else
395
const char * const STOP_KEY                 = "Shift+F5";
con's avatar
con committed
396
397
398
399
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";
400
const char * const REVERSE_KEY              = "F12";
con's avatar
con committed
401
402
403
404
405
406
407
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";
408
const char * const SNAPSHOT_KEY             = "Ctrl+D,Ctrl+S";
con's avatar
con committed
409
410
411
412
413
#endif

} // namespace Constants


414
415
416
417
418
419
420
421
namespace Internal {

// 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.

422
void addCdbOptionPages(QList<IOptionsPage*> *opts);
423
424
425
void addGdbOptionPages(QList<IOptionsPage*> *opts);
void addScriptOptionPages(QList<IOptionsPage*> *opts);
void addTcfOptionPages(QList<IOptionsPage*> *opts);
426

427
428
429
430
#ifdef WITH_LLDB
void addLldbOptionPages(QList<IOptionsPage*> *opts);
#endif

hjk's avatar
hjk committed
431
static SessionManager *sessionManager()
432
{
hjk's avatar
hjk committed
433
    return ProjectExplorerPlugin::instance()->session();
434
435
}

436
437
438
439
440
441
442
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

443
444
445
struct AttachRemoteParameters
{
    AttachRemoteParameters() : attachPid(0), winCrashEvent(0) {}
446
    void clear();
447
448

    quint64 attachPid;
449
    QString attachTarget;  // core file name or  server:port
450
    // Event handle for attaching to crashed Windows processes.
451
452
453
    quint64 winCrashEvent;
};

454
455
456
457
458
void AttachRemoteParameters::clear()
{
    attachPid = winCrashEvent = 0;
    attachTarget.clear();
}
459

460
461
462
463
464
465
466
467
468
469
470
471
472

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

class DummyEngine : public DebuggerEngine
{
    Q_OBJECT

public:
    DummyEngine() : DebuggerEngine(DebuggerStartParameters()) {}
473
474
475
476
477
478
479
480
481
482
    ~DummyEngine() {}

    void setupEngine() {}
    void setupInferior() {}
    void runEngine() {}
    void shutdownEngine() {}
    void shutdownInferior() {}
    void executeDebuggerCommand(const QString &) {}
    unsigned debuggerCapabilities() const { return 0; }
    bool acceptsBreakpoint(BreakpointId) const { return false; }
483
484
485
486
487
488
489
490
491
};

static DebuggerEngine *dummyEngine()
{
    static DummyEngine dummy;
    return &dummy;
}


492
493
494
495
496
497
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

498
class DebugMode : public IMode
hjk's avatar
hjk committed
499
500
{
public:
hjk's avatar
hjk committed
501
    DebugMode() : m_widget(0) { setObjectName(QLatin1String("DebugMode")); }
hjk's avatar
hjk committed
502

hjk's avatar
hjk committed
503
504
505
506
507
508
    ~DebugMode()
    {
        // Make sure the editor manager does not get deleted.
        //EditorManager::instance()->setParent(0);
        delete m_widget;
    }
509
510

    // IMode
hjk's avatar
hjk committed
511
512
513
514
515
516
517
518
519
    QString displayName() const { return DebuggerPlugin::tr("Debug"); }
    QIcon icon() const { return QIcon(__(":/fancyactionbar/images/mode_Debug.png")); }
    int priority() const { return P_MODE_DEBUG; }
    QWidget *widget();
    QString id() const { return MODE_DEBUG; }
    QString type() const { return CC::MODE_EDIT_TYPE; }
    Context context() const
        { return Context(CC::C_EDITORMANAGER, C_DEBUGMODE, CC::C_NAVIGATION_PANE); }
    QString contextHelpId() const { return QString(); }
520
521
private:
    QWidget *m_widget;
522
};
hjk's avatar
hjk committed
523

524

525
526
///////////////////////////////////////////////////////////////////////
//
527
// CommonOptionsPage
528
529
530
//
///////////////////////////////////////////////////////////////////////

531
class CommonOptionsPage : public Core::IOptionsPage
532
533
{
public:
534
    CommonOptionsPage() {}
535
536

    // IOptionsPage
537
    QString id() const
hjk's avatar
hjk committed
538
        { return _(DEBUGGER_COMMON_SETTINGS_ID); }
539
    QString displayName() const
hjk's avatar
hjk committed
540
        { return QCoreApplication::translate("Debugger", DEBUGGER_COMMON_SETTINGS_NAME); }
541
    QString category() const
hjk's avatar
hjk committed
542
        { return _(DEBUGGER_SETTINGS_CATEGORY);  }
543
    QString displayCategory() const
hjk's avatar
hjk committed
544
        { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
545
546
    QIcon categoryIcon() const
        { return QIcon(QLatin1String(DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); }
547
548

    QWidget *createPage(QWidget *parent);
hjk's avatar
hjk committed
549
    void apply() { m_group.apply(ICore::instance()->settings()); }
550
    void finish() { m_group.finish(); }
551
    virtual bool matches(const QString &s) const;
552
553

private:
554
    Ui::CommonOptionsPage m_ui;
555
    Utils::SavedActionSet m_group;
556
    QString m_searchKeywords;
557
558
};

559
QWidget *CommonOptionsPage::createPage(QWidget *parent)
560
561
562
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);
563
    m_group.clear();
564

hjk's avatar
hjk committed
565
    m_group.insert(debuggerCore()->action(ListSourceFiles),
566
        m_ui.checkBoxListSourceFiles);
hjk's avatar
hjk committed
567
    m_group.insert(debuggerCore()->action(UseAlternatingRowColors),
568
        m_ui.checkBoxUseAlternatingRowColors);
hjk's avatar
hjk committed
569
    m_group.insert(debuggerCore()->action(UseToolTipsInMainEditor),
570
        m_ui.checkBoxUseToolTipsInMainEditor);
hjk's avatar
hjk committed
571
    m_group.insert(debuggerCore()->action(CloseBuffersOnExit),
572
        m_ui.checkBoxCloseBuffersOnExit);
hjk's avatar
hjk committed
573
    m_group.insert(debuggerCore()->action(SwitchModeOnExit),
574
        m_ui.checkBoxSwitchModeOnExit);
hjk's avatar
hjk committed
575
576
577
578
579
580
    m_group.insert(debuggerCore()->action(AutoDerefPointers), 0);
    m_group.insert(debuggerCore()->action(UseToolTipsInLocalsView), 0);
    m_group.insert(debuggerCore()->action(UseToolTipsInBreakpointsView), 0);
    m_group.insert(debuggerCore()->action(UseAddressInBreakpointsView), 0);
    m_group.insert(debuggerCore()->action(UseAddressInStackView), 0);
    m_group.insert(debuggerCore()->action(MaximalStackDepth),
581
        m_ui.spinBoxMaximalStackDepth);
hjk's avatar
hjk committed
582
583
584
585
586
587
588
    m_group.insert(debuggerCore()->action(ShowStdNamespace), 0);
    m_group.insert(debuggerCore()->action(ShowQtNamespace), 0);
    m_group.insert(debuggerCore()->action(SortStructMembers), 0);
    m_group.insert(debuggerCore()->action(LogTimeStamps), 0);
    m_group.insert(debuggerCore()->action(VerboseLog), 0);
    m_group.insert(debuggerCore()->action(BreakOnThrow), 0);
    m_group.insert(debuggerCore()->action(BreakOnCatch), 0);
589
#ifdef Q_OS_WIN
hjk's avatar
hjk committed
590
    Utils::SavedAction *registerAction = debuggerCore()->action(RegisterForPostMortem);
591
592
593
594
595
    m_group.insert(registerAction,
        m_ui.checkBoxRegisterForPostMortem);
    connect(registerAction, SIGNAL(toggled(bool)),
            m_ui.checkBoxRegisterForPostMortem, SLOT(setChecked(bool)));
#endif
596

597
    if (m_searchKeywords.isEmpty()) {
598
599
600
601
602
        QLatin1Char sep(' ');
        QTextStream(&m_searchKeywords)
                << sep << m_ui.checkBoxUseAlternatingRowColors->text()
                << sep << m_ui.checkBoxUseToolTipsInMainEditor->text()
                << sep << m_ui.checkBoxListSourceFiles->text()
603
#ifdef Q_OS_WIN
604
                << sep << m_ui.checkBoxRegisterForPostMortem->text()
605
#endif
606
607
608
609
                << sep << m_ui.checkBoxCloseBuffersOnExit->text()
                << sep << m_ui.checkBoxSwitchModeOnExit->text()
                << sep << m_ui.labelMaximalStackDepth->text()
                   ;
610
611
        m_searchKeywords.remove(QLatin1Char('&'));
    }
612
613
614
#ifndef Q_OS_WIN
    m_ui.checkBoxRegisterForPostMortem->setVisible(false);
#endif
615
616
617
    return w;
}

618
619
620
621
622
bool CommonOptionsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

hjk's avatar
hjk committed
623
624
///////////////////////////////////////////////////////////////////////
//
625
// DebuggingHelperOptionPage
hjk's avatar
hjk committed
626
627
628
//
///////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
629
static bool oxygenStyle()
630
{
hjk's avatar
hjk committed
631
632
    const ManhattanStyle *ms = qobject_cast<const ManhattanStyle *>(qApp->style());
    return ms && !qstrcmp("OxygenStyle", ms->baseStyle()->metaObject()->className());
633
634
}

635
class DebuggingHelperOptionPage : public Core::IOptionsPage
hjk's avatar
hjk committed
636
637
{
    Q_OBJECT // Needs tr-context.
hjk's avatar
hjk committed
638
public:
639
    DebuggingHelperOptionPage() {}
hjk's avatar
hjk committed
640
641

    // IOptionsPage
hjk's avatar
hjk committed
642
    QString id() const { return _("Z.DebuggingHelper"); }
643
    QString displayName() const { return tr("Debugging Helper"); }
hjk's avatar
hjk committed
644
    QString category() const { return _(DEBUGGER_SETTINGS_CATEGORY); }
645
646
647
648
    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
649
650

    QWidget *createPage(QWidget *parent);
hjk's avatar
hjk committed
651
    void apply() { m_group.apply(ICore::instance()->settings()); }
652
    void finish() { m_group.finish(); }
653
    virtual bool matches(const QString &s) const;
hjk's avatar
hjk committed
654
655

private:
656
    Ui::DebuggingHelperOptionPage m_ui;
657
    Utils::SavedActionSet m_group;
658
    QString m_searchKeywords;
hjk's avatar
hjk committed
659
660
};

661
QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent)
hjk's avatar
hjk committed
662
663
664
665
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);

666
    m_ui.dumperLocationChooser->setExpectedKind(Utils::PathChooser::Command);
667
    m_ui.dumperLocationChooser->setPromptDialogTitle(tr("Choose DebuggingHelper Location"));
hjk's avatar
hjk committed
668
    m_ui.dumperLocationChooser->setInitialBrowsePathBackup(
hjk's avatar
hjk committed
669
        ICore::instance()->resourcePath() + "../../lib");
hjk's avatar
hjk committed
670

671
    m_group.clear();
hjk's avatar
hjk committed
672
    m_group.insert(debuggerCore()->action(UseDebuggingHelpers),
673
        m_ui.debuggingHelperGroupBox);
hjk's avatar
hjk committed
674
    m_group.insert(debuggerCore()->action(UseCustomDebuggingHelperLocation),
675
        m_ui.customLocationGroupBox);
hjk's avatar
hjk committed
676
    // Suppress Oxygen style's giving flat group boxes bold titles.
677
    if (oxygenStyle())
hjk's avatar
hjk committed
678
        m_ui.customLocationGroupBox->setStyleSheet(_("QGroupBox::title { font: ; }"));
679

hjk's avatar
hjk committed
680
    m_group.insert(debuggerCore()->action(CustomDebuggingHelperLocation),
681
        m_ui.dumperLocationChooser);
hjk's avatar
hjk committed
682

hjk's avatar
hjk committed
683
    m_group.insert(debuggerCore()->action(UseCodeModel),
684
        m_ui.checkBoxUseCodeModel);
685
686
687
    m_group.insert(debuggerCore()->action(ShowThreadNames),
        m_ui.checkBoxShowThreadNames);

688

hjk's avatar
hjk committed
689
690
#ifndef QT_DEBUG
#if 0
hjk's avatar
hjk committed
691
    cmd = am->registerAction(m_dumpLogAction,
hjk's avatar
hjk committed
692
        DUMP_LOG, globalcontext);
hjk's avatar
hjk committed
693
694
695
696
697
698
    //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+L")));
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F11")));
    mdebug->addAction(cmd);
#endif
#endif

699
700
701
702
703
    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords)
                << ' ' << m_ui.debuggingHelperGroupBox->title()
                << ' ' << m_ui.customLocationGroupBox->title()
                << ' ' << m_ui.dumperLocationLabel->text()
704
705
                << ' ' << m_ui.checkBoxUseCodeModel->text()
                << ' ' << m_ui.checkBoxShowThreadNames->text();
706
707
        m_searchKeywords.remove(QLatin1Char('&'));
    }
hjk's avatar
hjk committed
708
709
710
    return w;
}

711
bool DebuggingHelperOptionPage::matches(const QString &s) const
hjk's avatar
hjk committed
712
{
713
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
hjk's avatar
hjk committed
714
715
}

716

con's avatar
con committed
717
718
///////////////////////////////////////////////////////////////////////
//
719
// Argument parsing
con's avatar
con committed
720
721
722
//
///////////////////////////////////////////////////////////////////////

723
static QString msgParameterMissing(const QString &a)
724
725
726
727
{
    return DebuggerPlugin::tr("Option '%1' is missing the parameter.").arg(a);
}

728
static QString msgInvalidNumericParameter(const QString &a, const QString &number)
729
730
731
732
{
    return DebuggerPlugin::tr("The parameter '%1' of option '%2' is not a number.").arg(number, a);
}

733
static bool parseArgument(QStringList::const_iterator &it,
734
735
736
    const QStringList::const_iterator &cend,
    AttachRemoteParameters *attachRemoteParameters,
    unsigned *enabledEngines, QString *errorMessage)
737
738
739
{
    const QString &option = *it;
    // '-debug <pid>'
740
741
    // '-debug <corefile>'
    // '-debug <server:port>'
hjk's avatar
hjk committed
742
    if (*it == _("-debug")) {
743
744
745
746
747
748
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
749
        attachRemoteParameters->attachPid = it->toULongLong(&ok);
750
751
        if (!ok)
            attachRemoteParameters->attachTarget = *it;
752
753
        return true;
    }
754
755
    // -wincrashevent <event-handle>. A handle used for
    // a handshake when attaching to a crashed Windows process.
hjk's avatar
hjk committed
756
    if (*it == _("-wincrashevent")) {
757
758
759
760
761
762
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
763
        attachRemoteParameters->winCrashEvent = it->toULongLong(&ok);
764
765
766
767
768
769
        if (!ok) {
            *errorMessage = msgInvalidNumericParameter(option, *it);
            return false;
        }
        return true;
    }
hjk's avatar
hjk committed
770
    // Engine disabling.
hjk's avatar
hjk committed
771
    if (option == _("-disable-cdb")) {
772
        *enabledEngines &= ~CdbEngineType;
773
774
        return true;
    }
hjk's avatar
hjk committed
775
    if (option == _("-disable-gdb")) {
776
        *enabledEngines &= ~GdbEngineType;
777
778
        return true;
    }
779
    if (option == _("-disable-qmldb")) {
780
        *enabledEngines &= ~QmlEngineType;
781
782
        return true;
    }
hjk's avatar
hjk committed
783
    if (option == _("-disable-sdb")) {
784
        *enabledEngines &= ~ScriptEngineType;
785
786
        return true;
    }
787
    if (option == _("-disable-tcf")) {
hjk's avatar
hjk committed
788
789
790
        *enabledEngines &= ~TcfEngineType;
        return true;
    }
791
792
793
794
    if (option == _("-disable-lldb")) {
        *enabledEngines &= ~LldbEngineType;
        return true;
    }
795

796
    *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
797
798
799
    return false;
}

800
static bool parseArguments(const QStringList &args,
801
   AttachRemoteParameters *attachRemoteParameters,
hjk's avatar
hjk committed
802
   unsigned *enabledEngines, QString *errorMessage)
803
{
804
    attachRemoteParameters->clear();
805
806
    const QStringList::const_iterator cend = args.constEnd();
    for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
807
        if (!parseArgument(it, cend, attachRemoteParameters, enabledEngines, errorMessage))
808
            return false;
809
    if (Constants::Internal::debug)
810
        qDebug().nospace() << args << "engines=0x"
811
812
            << QString::number(*enabledEngines, 16)
            << " pid" << attachRemoteParameters->attachPid
813
            << " target" << attachRemoteParameters->attachTarget << '\n';
814
815
816
    return true;
}

817
818
819
820
821
822
823

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

hjk's avatar
hjk committed
824
static bool isDebuggable(IEditor *editor)
825
{
826
827
    // Only blacklist Qml. Whitelisting would fail on C++ code in files
    // with strange names, more harm would be done this way.
hjk's avatar
hjk committed
828
829
    //   IFile *file = editor->file();
    //   return !(file && file->mimeType() == "application/x-qml");
830
    // Nowadays, even Qml is debuggable.
hjk's avatar
hjk committed
831
    return editor;
832
833
}

834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
class ContextData
{
public:
    ContextData() : lineNumber(0), address(0) {}

public:
    QString fileName;
    int lineNumber;
    quint64 address;
};

} // namespace Internal
} // namespace Debugger

Q_DECLARE_METATYPE(Debugger::Internal::ContextData)
con's avatar
con committed
849

850
851
///////////////////////////////////////////////////////////////////////
//
hjk's avatar
hjk committed
852
// Debugger Actions
853
854
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
855

856
857
858
namespace Debugger {
namespace Internal {

859
860
861
struct DebuggerActions
{
    QAction *continueAction;
862
    QAction *exitAction; // on the application output button if "Stop" is possible
863
864
    QAction *interruptAction; // on the fat debug button if "Pause" is possible
    QAction *undisturbableAction; // on the fat debug button if nothing can be done
865
866
867
    QAction *resetAction; // FIXME: Should not be needed in a stable release
    QAction *stepAction;
    QAction *stepOutAction;
868
    QAction *runToLineAction; // Debug menu
869
    QAction *runToFunctionAction;
870
    QAction *jumpToLineAction; // in the Debug menu
871
872
    QAction *returnFromFunctionAction;
    QAction *nextAction;
873
    //QAction *snapshotAction;
874
875
876
877
878
879
880
881
    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
882

883
static DebuggerPluginPrivate *theDebuggerCore = 0;
con's avatar
con committed
884
885


886
887
888
889
890
///////////////////////////////////////////////////////////////////////
//
// DebuggerPluginPrivate
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
891

892
class DebuggerPluginPrivate : public DebuggerCore
893
894
{
    Q_OBJECT
895

896
897
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
898
    ~DebuggerPluginPrivate();
899

900
    bool initialize(const QStringList &arguments, QString *errorMessage);
901
902
903
    void extensionsInitialized();
    void aboutToShutdown();

904
    void connectEngine(DebuggerEngine *engine);
hjk's avatar
hjk committed
905
    void disconnectEngine() { connectEngine(0); }
906
    DebuggerEngine *currentEngine() const { return m_currentEngine; }
907

908
public slots:
909
910
911
912
    void selectThread(int index)
    {
        currentEngine()->selectThread(index);
    }
913

hjk's avatar
hjk committed
914
    void breakpointSetMarginActionTriggered()
915
    {
916
917
918
919
920
921
922
        const QAction *action = qobject_cast<const QAction *>(sender());
        QTC_ASSERT(action, return);
        const ContextData data = action->data().value<ContextData>();
        if (data.address)
            toggleBreakpointByAddress(data.address);
        else
            toggleBreakpointByFileAndLine(data.fileName, data.lineNumber);
923
    }
924

hjk's avatar
hjk committed