debuggerplugin.cpp 135 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

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

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

70
71
#include "snapshothandler.h"
#include "threadshandler.h"
72
#include "commonoptionspage.h"
73
#include "gdb/startgdbserverdialog.h"
con's avatar
con committed
74

75
#include <coreplugin/actionmanager/actionmanager.h>
76
#include <coreplugin/actionmanager/actioncontainer.h>
77
#include <coreplugin/find/treeviewfind.h>
78
#include <coreplugin/imode.h>
con's avatar
con committed
79
80
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
81
#include <coreplugin/messagemanager.h>
con's avatar
con committed
82
#include <coreplugin/modemanager.h>
hjk's avatar
hjk committed
83

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

87
#include <extensionsystem/invoker.h>
88

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

hjk's avatar
hjk committed
101
#include <texteditor/basetexteditor.h>
102
#include <texteditor/fontsettings.h>
103
#include <texteditor/texteditorsettings.h>
hjk's avatar
hjk committed
104

105
#include <utils/basetreeview.h>
106
#include <utils/hostosinfo.h>
107
#include <utils/proxyaction.h>
108
109
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
110
#include <utils/statuslabel.h>
111
#include <utils/styledbar.h>
hjk's avatar
hjk committed
112
#include <utils/winutils.h>
con's avatar
con committed
113

Campbell Barton's avatar
Campbell Barton committed
114
#include <QApplication>
hjk's avatar
hjk committed
115
#include <QCheckBox>
116
#include <QComboBox>
117
118
#include <QDockWidget>
#include <QFileDialog>
hjk's avatar
hjk committed
119
120
#include <QHBoxLayout>
#include <QHeaderView>
hjk's avatar
hjk committed
121
#include <QInputDialog>
122
123
124
#include <QMessageBox>
#include <QTextBlock>
#include <QToolButton>
hjk's avatar
hjk committed
125
#include <QtPlugin>
126
#include <QTreeWidget>
127
128
#include <QVBoxLayout>

hjk's avatar
hjk committed
129
#ifdef WITH_TESTS
130
131
132
#include <QTest>
#include <QSignalSpy>
#include <QTestEventLoop>
133
134
135
136

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

139
140
#endif // WITH_TESTS

141
142
#include <climits>

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

153
154
155
156
157
158
159
160
/*!
    \namespace Debugger
    Debugger plugin namespace
*/

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

/*!
    \class Debugger::DebuggerEngine

167
    \brief The DebuggerEngine class is the base class of a debugger engine.
168

Leena Miettinen's avatar
Leena Miettinen committed
169
    \note The Debugger process itself and any helper processes like
170
171
    gdbserver are referred to as 'Engine', whereas the debugged process
    is referred to as 'Inferior'.
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

    Transitions marked by '---' are done in the individual engines.
    Transitions marked by '+-+' are done in the base DebuggerEngine.
    Transitions marked by '*' are done asynchronously.

    The GdbEngine->setupEngine() function is described in more detail below.

    The engines are responsible for local roll-back to the last
    acknowledged state before calling notify*Failed. I.e. before calling
    notifyEngineSetupFailed() any process started during setupEngine()
    so far must be terminated.
    \code

                        DebuggerNotReady
                         progressmanager/progressmanager.cpp      +
                      EngineSetupRequested
                               +
                  (calls *Engine->setupEngine())
                            |      |
                            |      |
                       {notify-  {notify-
                        Engine-   Engine-
                        SetupOk}  SetupFailed}
                            +      +
                            +      `+-+-+> EngineSetupFailed
                            +                   +
                            +    [calls RunControl->startFailed]
                            +                   +
                            +             DebuggerFinished
                            v
                      EngineSetupOk
                            +
             [calls RunControl->StartSuccessful]
                            +
                  InferiorSetupRequested
                            +
             (calls *Engine->setupInferior())
                         |       |
                         |       |
                    {notify-   {notify-
                     Inferior- Inferior-
                     SetupOk}  SetupFailed}
                         +       +
                         +       ` +-+-> InferiorSetupFailed +-+-+-+-+-+->.
                         +                                                +
                  InferiorSetupOk                                         +
                         +                                                +
                  EngineRunRequested                                      +
                         +                                                +
                 (calls *Engine->runEngine())                             +
               /       |            |        \                            +
             /         |            |          \                          +
            | (core)   | (attach)   |           |                         +
            |          |            |           |                         +
      {notify-    {notifyER&- {notifyER&-  {notify-                       +
      Inferior-     Inferior-   Inferior-  EngineRun-                     +
     Unrunnable}     StopOk}     RunOk}     Failed}                       +
           +           +            +           +                         +
   InferiorUnrunnable  +     InferiorRunOk      +                         +
                       +                        +                         +
                InferiorStopOk            EngineRunFailed                 +
                                                +                         v
                                                 `-+-+-+-+-+-+-+-+-+-+-+>-+
                                                                          +
                                                                          +
                       #Interrupt@InferiorRunOk#                          +
                                  +                                       +
                          InferiorStopRequested                           +
  #SpontaneousStop                +                                       +
   @InferiorRunOk#         (calls *Engine->                               +
          +               interruptInferior())                            +
      {notify-               |          |                                 +
     Spontaneous-       {notify-    {notify-                              +
      Inferior-          Inferior-   Inferior-                            +
       StopOk}           StopOk}    StopFailed}                           +
           +              +             +                                 +
            +            +              +                                 +
            InferiorStopOk              +                                 +
                  +                     +                                 +
                  +                    +                                  +
                  +                   +                                   +
        #Stop@InferiorUnrunnable#    +                                    +
          #Creator Close Event#     +                                     +
                       +           +                                      +
                InferiorShutdownRequested                                 +
                            +                                             +
           (calls *Engine->shutdownInferior())                            +
                         |        |                                       +
                    {notify-   {notify-                                   +
                     Inferior- Inferior-                                  +
                  ShutdownOk}  ShutdownFailed}                            +
                         +        +                                       +
                         +        +                                       +
  #Inferior exited#      +        +                                       +
         |               +        +                                       +
   {notifyInferior-      +        +                                       +
      Exited}            +        +                                       +
           +             +        +                                       +
     InferiorExitOk      +        +                                       +
             +           +        +                                       +
            InferiorShutdownOk InferiorShutdownFailed                     +
                      *          *                                        +
                  EngineShutdownRequested                                 +
                            +                                             +
           (calls *Engine->shutdownEngine())  <+-+-+-+-+-+-+-+-+-+-+-+-+-+'
                         |        |
                         |        |
                    {notify-   {notify-
                     Engine-    Engine-
                  ShutdownOk}  ShutdownFailed}
                         +       +
            EngineShutdownOk  EngineShutdownFailed
                         *       *
                     DebuggerFinished

\endcode */
hjk's avatar
hjk committed
288

289
290
291
/* 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
292

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


333
334
/*!
    \class Debugger::Internal::GdbEngine
335
336
    \brief The GdbEngine class implements Debugger::Engine driving a GDB
    executable.
337
338
339

    GdbEngine specific startup. All happens in EngineSetupRequested state:

Leena Miettinen's avatar
Leena Miettinen committed
340
341
    \list
        \li Transitions marked by '---' are done in the individual adapters.
342

Leena Miettinen's avatar
Leena Miettinen committed
343
344
        \li Transitions marked by '+-+' are done in the GdbEngine.
    \endlist
345
346
347
348
349
350
351
352
353
354
355
356
357

    \code
                  GdbEngine::setupEngine()
                          +
            (calls *Adapter->startAdapter())
                          |      |
                          |      `---> handleAdapterStartFailed()
                          |                   +
                          |             {notifyEngineSetupFailed}
                          |
                 handleAdapterStarted()
                          +
                 {notifyEngineSetupOk}
358
359
360



361
362
363
364
365
366
367
368
369
370
371
                GdbEngine::setupInferior()
                          +
            (calls *Adapter->prepareInferior())
                          |      |
                          |      `---> handlePrepareInferiorFailed()
                          |                   +
                          |             {notifyInferiorSetupFailed}
                          |
                handleInferiorPrepared()
                          +
                {notifyInferiorSetupOk}
372

373
\endcode */
374

con's avatar
con committed
375
using namespace Core;
hjk's avatar
hjk committed
376
using namespace Debugger::Constants;
377
using namespace ExtensionSystem;
con's avatar
con committed
378
using namespace ProjectExplorer;
hjk's avatar
hjk committed
379
using namespace TextEditor;
380
using namespace Utils;
con's avatar
con committed
381

hjk's avatar
hjk committed
382
383
384
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
385
386

namespace Debugger {
387
388
namespace Internal {

389
390
391
392
393
394
395
396
397
398
399
400
401
// To be passed through margin menu action's data
struct BreakpointMenuContextData : public ContextData
{
    enum Mode
    {
        Breakpoint,
        MessageTracePoint
    };

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

402
403
404
405
406
407
408
409
410
411
412
struct TestCallBack
{
    TestCallBack() : receiver(0), slot(0) {}
    TestCallBack(QObject *ob, const char *s) : receiver(ob), slot(s) {}

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


413
414
415
416
} // namespace Internal
} // namespace Debugger

Q_DECLARE_METATYPE(Debugger::Internal::BreakpointMenuContextData)
417
418
Q_DECLARE_METATYPE(Debugger::Internal::TestCallBack)

419
420
421
422

namespace Debugger {
namespace Internal {

423
424
425
426
427
428
// 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.

429
void addCdbOptionPages(QList<IOptionsPage*> *opts);
430
431
432
void addGdbOptionPages(QList<IOptionsPage*> *opts);
void addScriptOptionPages(QList<IOptionsPage*> *opts);
void addTcfOptionPages(QList<IOptionsPage*> *opts);
433

434
435
436
437
#ifdef WITH_LLDB
void addLldbOptionPages(QList<IOptionsPage*> *opts);
#endif

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

Orgad Shaneh's avatar
Orgad Shaneh committed
445
static void setProxyAction(ProxyAction *proxy, Core::Id id)
446
{
hjk's avatar
hjk committed
447
    proxy->setAction(ActionManager::command(id)->action());
448
449
}

Orgad Shaneh's avatar
Orgad Shaneh committed
450
static QToolButton *toolButton(Core::Id id)
451
{
hjk's avatar
hjk committed
452
    return toolButton(ActionManager::command(id)->action());
453
454
}

455
456
457
458
459
460
461
462
463
464
465
///////////////////////////////////////////////////////////////////////
//
// DummyEngine
//
///////////////////////////////////////////////////////////////////////

class DummyEngine : public DebuggerEngine
{
    Q_OBJECT

public:
466
    DummyEngine() : DebuggerEngine(DebuggerStartParameters()) {}
467
468
469
470
471
472
473
    ~DummyEngine() {}

    void setupEngine() {}
    void setupInferior() {}
    void runEngine() {}
    void shutdownEngine() {}
    void shutdownInferior() {}
474
    bool hasCapability(unsigned cap) const;
475
    bool acceptsBreakpoint(BreakpointModelId) const { return false; }
476
    bool acceptsDebuggerCommands() const { return false; }
hjk's avatar
hjk committed
477
    void selectThread(ThreadId) {}
478
479
};

480
bool DummyEngine::hasCapability(unsigned cap) const
481
482
{
    // This can only be a first approximation of what to expect when running.
483
    Project *project = ProjectExplorerPlugin::currentProject();
484
485
486
487
488
489
490
491
    if (!project)
        return 0;
    Target *target = project->activeTarget();
    QTC_ASSERT(target, return 0);
    RunConfiguration *activeRc = target->activeRunConfiguration();
    QTC_ASSERT(activeRc, return 0);

    // This is a non-started Cdb or Gdb engine:
492
    if (activeRc->extraAspect<Debugger::DebuggerRunConfigurationAspect>()->useCppDebugger())
493
        return cap & (WatchpointByAddressCapability
494
495
               | BreakConditionCapability
               | TracePointCapability
496
               | OperateByInstructionCapability);
497
498

    // This is a Qml or unknown engine.
499
    return cap & AddWatcherCapability;
500
501
}

502
503
504
505
506
507
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

508
class DebugMode : public IMode
hjk's avatar
hjk committed
509
510
{
public:
511
512
513
    DebugMode()
    {
        setObjectName(QLatin1String("DebugMode"));
514
        setContext(Context(C_DEBUGMODE, CC::C_NAVIGATION_PANE));
515
        setDisplayName(DebuggerPlugin::tr("Debug"));
516
        setIcon(QIcon(QLatin1String(":/debugger/images/mode_debug.png")));
517
        setPriority(85);
518
        setId(MODE_DEBUG);
519
    }
hjk's avatar
hjk committed
520

hjk's avatar
hjk committed
521
522
523
524
    ~DebugMode()
    {
        delete m_widget;
    }
525
};
hjk's avatar
hjk committed
526

527
528
529
530
531
532
///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

533
static QWidget *addSearch(BaseTreeView *treeView, const QString &title,
534
    const char *objectName)
535
536
537
538
539
540
{
    QAction *act = debuggerCore()->action(UseAlternatingRowColors);
    treeView->setAlternatingRowColors(act->isChecked());
    QObject::connect(act, SIGNAL(toggled(bool)),
            treeView, SLOT(setAlternatingRowColorsHelper(bool)));

541
    QWidget *widget = TreeViewFind::createSearchableWrapper(treeView);
542
543
544
545
546
    widget->setObjectName(QLatin1String(objectName));
    widget->setWindowTitle(title);
    return widget;
}

hjk's avatar
hjk committed
547
static QString executableForPid(qint64 pid)
548
{
549
    foreach (const DeviceProcessItem &p, DeviceProcessList::localProcesses())
550
551
552
553
554
        if (p.pid == pid)
            return p.exe;
    return QString();
}

Tobias Hunger's avatar
Tobias Hunger committed
555
class AbiKitMatcher : public KitMatcher
556
557
{
public:
Tobias Hunger's avatar
Tobias Hunger committed
558
    explicit AbiKitMatcher(const QList<Abi> &abis) : m_abis(abis) {}
559
    bool matches(const Kit *k) const
560
    {
561
        if (const ToolChain *tc = ToolChainKitInformation::toolChain(k)) {
562
            return m_abis.contains(tc->targetAbi())
563
                   && DebuggerKitInformation::isValidDebugger(k);
564
        }
565
566
567
568
569
570
571
        return false;
    }

private:
    const QList<Abi> m_abis;
};

Tobias Hunger's avatar
Tobias Hunger committed
572
class CompatibleAbiKitMatcher : public KitMatcher
573
574
{
public:
Tobias Hunger's avatar
Tobias Hunger committed
575
    explicit CompatibleAbiKitMatcher(const QList<Abi> &abis) : m_abis(abis) {}
576
    bool matches(const Kit *k) const
577
    {
578
        if (const ToolChain *tc = ToolChainKitInformation::toolChain(k))
579
            foreach (const Abi &a, m_abis)
580
                if (a.isCompatibleWith(tc->targetAbi()) && DebuggerKitInformation::isValidDebugger(k))
581
582
583
584
585
586
587
588
                    return true;
        return false;
    }

private:
    const QList<Abi> m_abis;
};

Tobias Hunger's avatar
Tobias Hunger committed
589
class CdbMatcher : KitMatcher
hjk's avatar
hjk committed
590
{
591
592
593
public:
    CdbMatcher(char wordWidth = 0) : m_wordWidth(wordWidth) {}

Tobias Hunger's avatar
Tobias Hunger committed
594
    bool matches(const Kit *k) const
595
    {
596
597
        if (DebuggerKitInformation::engineType(k) != CdbEngineType
            || !DebuggerKitInformation::isValidDebugger(k)) {
598
            return false;
599
600
601
602
603
        }
        if (m_wordWidth) {
            const ToolChain *tc = ToolChainKitInformation::toolChain(k);
            return tc && m_wordWidth == tc->targetAbi().wordWidth();
        }
604
605
606
        return true;
    }

Tobias Hunger's avatar
Tobias Hunger committed
607
    // Find a CDB kit for debugging unknown processes.
608
    // On a 64bit OS, prefer a 64bit debugger.
Tobias Hunger's avatar
Tobias Hunger committed
609
    static Kit *findUniversalCdbKit()
610
    {
hjk's avatar
hjk committed
611
        if (Utils::is64BitWindowsSystem()) {
612
            CdbMatcher matcher64(64);
613
            if (Kit *cdb64Kit = KitManager::find(matcher64))
Tobias Hunger's avatar
Tobias Hunger committed
614
                return cdb64Kit;
615
616
        }
        CdbMatcher matcher;
617
        return KitManager::find(matcher);
618
619
620
621
622
623
    }

private:
    const char m_wordWidth;
};

624
bool fillParameters(DebuggerStartParameters *sp, const Kit *kit, QString *errorMessage /* = 0 */)
625
{
Tobias Hunger's avatar
Tobias Hunger committed
626
    if (!kit) {
627
628
        // This code can only be reached when starting via the command line
        // (-debug pid or executable) or attaching from runconfiguration
Tobias Hunger's avatar
Tobias Hunger committed
629
        // without specifying a kit. Try to find a kit via ABI.
630
631
632
633
634
635
636
637
638
639
640
        QList<Abi> abis;
        if (sp->toolChainAbi.isValid()) {
            abis.push_back(sp->toolChainAbi);
        } else {
            // Try via executable.
            if (sp->executable.isEmpty()
                && (sp->startMode == AttachExternal || sp->startMode == AttachCrashedExternal)) {
                sp->executable = executableForPid(sp->attachPID);
            }
            if (!sp->executable.isEmpty())
                abis = Abi::abisOfBinary(Utils::FileName::fromString(sp->executable));
641
        }
642
        if (!abis.isEmpty()) {
643
644
645
            kit = KitManager::find(AbiKitMatcher(abis));
            if (!kit)
                kit = KitManager::find(CompatibleAbiKitMatcher(abis));
646
        }
Tobias Hunger's avatar
Tobias Hunger committed
647
        if (!kit)
648
            kit = KitManager::defaultKit();
649
650
    }

651
652
653
654
655
656
657
    // Verify that debugger and profile are valid
    if (!kit) {
        sp->startMode = NoStartMode;
        if (errorMessage)
            *errorMessage = DebuggerKitInformation::tr("No kit found.");
        return false;
    }
658
659
    // validate debugger if C++ debugging is enabled
    if (sp->languages & CppLanguage) {
hjk's avatar
hjk committed
660
        const QList<Task> tasks = DebuggerKitInformation::validateDebugger(kit);
661
662
663
        if (!tasks.isEmpty()) {
            sp->startMode = NoStartMode;
            if (errorMessage) {
hjk's avatar
hjk committed
664
                foreach (const Task &t, tasks) {
665
666
667
668
                    if (errorMessage->isEmpty())
                        errorMessage->append(QLatin1Char('\n'));
                    errorMessage->append(t.description);
                }
669
            }
670
            return false;
671
672
673
        }
    }
    sp->cppEngineType = DebuggerKitInformation::engineType(kit);
Tobias Hunger's avatar
Tobias Hunger committed
674
675
    sp->sysRoot = SysRootKitInformation::sysRoot(kit).toString();
    sp->debuggerCommand = DebuggerKitInformation::debuggerCommand(kit).toString();
676

Tobias Hunger's avatar
Tobias Hunger committed
677
    ToolChain *tc = ToolChainKitInformation::toolChain(kit);
hjk's avatar
hjk committed
678
679
    if (tc)
        sp->toolChainAbi = tc->targetAbi();
680

681
682
683
    sp->device = DeviceKitInformation::device(kit);
    if (sp->device) {
        sp->connParams = sp->device->sshParameters();
684
685
686
        // Could have been set from command line.
        if (sp->remoteChannel.isEmpty())
            sp->remoteChannel = sp->connParams.host + QLatin1Char(':') + QString::number(sp->connParams.port);
687
    }
688
    return true;
hjk's avatar
hjk committed
689
690
}

691
692
static bool currentTextEditorPosition(ContextData *data)
{
693
    BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
694
695
    if (!textEditor)
        return false;
hjk's avatar
hjk committed
696
    const IDocument *document = textEditor->document();
697
    QTC_ASSERT(document, return false);
698
    data->fileName = document->filePath();
699
    if (document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) {
700
        int lineNumber = textEditor->currentLine();
701
        QString line = textEditor->textDocument()->plainText()
702
703
704
705
            .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1);
        data->address = DisassemblerLine::addressFromDisassemblyLine(line);
    } else {
        data->lineNumber = textEditor->currentLine();
706
    }
707
    return true;
708
}
709

710
711
///////////////////////////////////////////////////////////////////////
//
712
// DebuggerPluginPrivate
713
714
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
715

716
static DebuggerPluginPrivate *theDebuggerCore = 0;
con's avatar
con committed
717

718
719
720
721
722
723
724
725
726
727
728
729
730
731
/*!
    \class Debugger::Internal::DebuggerCore

    This is the "internal" interface of the debugger plugin that's
    used by debugger views and debugger engines. The interface is
    implemented in DebuggerPluginPrivate.
*/

/*!
    \class Debugger::Internal::DebuggerPluginPrivate

    Implementation of DebuggerCore.
*/

732
class DebuggerPluginPrivate : public DebuggerCore
733
734
{
    Q_OBJECT
735

736
737
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
738
    ~DebuggerPluginPrivate();
739

740
    bool initialize(const QStringList &arguments, QString *errorMessage);
741
742
743
    void extensionsInitialized();
    void aboutToShutdown();

744
    void connectEngine(DebuggerEngine *engine);
hjk's avatar
hjk committed
745
    void disconnectEngine() { connectEngine(0); }
746
    DebuggerEngine *currentEngine() const { return m_currentEngine; }
747
    DebuggerEngine *dummyEngine();
748

749
750
751
752
753
754
755
756
757
    void setThreads(const QStringList &list, int index)
    {
        const bool state = m_threadBox->blockSignals(true);
        m_threadBox->clear();
        foreach (const QString &item, list)
            m_threadBox->addItem(item);
        m_threadBox->setCurrentIndex(index);
        m_threadBox->blockSignals(state);
    }
758
    DebuggerRunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process);
759

760
public slots:
761
762
763
764
765
766
    void writeSettings()
    {
        m_debuggerSettings->writeSettings();
        m_mainWindow->writeSettings();
    }

767
768
    void selectThread(int index)
    {
hjk's avatar
hjk committed
769
770
        ThreadId id = m_currentEngine->threadsHandler()->threadAt(index);
        m_currentEngine->selectThread(id);
771
    }
772

hjk's avatar
hjk committed
773
    void breakpointSetMarginActionTriggered()
774
    {
775
776
        const QAction *action = qobject_cast<const QAction *>(sender());
        QTC_ASSERT(action, return);
hjk's avatar
hjk committed
777
778
        const BreakpointMenuContextData data =
            action->data().value<BreakpointMenuContextData>();
779
780
781
782
783
784
785
786
787
788
789
790
791
        QString message;
        if (data.mode == BreakpointMenuContextData::MessageTracePoint) {
            if (data.address) {
                //: Message tracepoint: Address hit.
                message = tr("0x%1 hit").arg(data.address, 0, 16);
            } else {
                //: Message tracepoint: %1 file, %2 line %3 function hit.
                message = tr("%1:%2 %3() hit").arg(QFileInfo(data.fileName).fileName()).
                        arg(data.lineNumber).
                        arg(cppFunctionAt(data.fileName, data.lineNumber));
            }
            QInputDialog dialog; // Create wide input dialog.
            dialog.setWindowFlags(dialog.windowFlags()
hjk's avatar
hjk committed
792
              & ~(Qt::WindowContextHelpButtonHint|Qt::MSWindowsFixedSizeDialogHint));
793
794
795
796
797
798
799
800
            dialog.resize(600, dialog.height());
            dialog.setWindowTitle(tr("Add Message Tracepoint"));
            dialog.setLabelText (tr("Message:"));
            dialog.setTextValue(message);
            if (dialog.exec() != QDialog::Accepted || dialog.textValue().isEmpty())
                return;
            message = dialog.textValue();
        }
801
        if (data.address)
802
            toggleBreakpointByAddress(data.address, message);
803
        else
804
            toggleBreakpointByFileAndLine(data.fileName, data.lineNumber, message);
805
    }
806

hjk's avatar
hjk committed
807
    void breakpointRemoveMarginActionTriggered()
808
    {
hjk's avatar
hjk committed
809
810
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
811
        BreakpointModelId id = act->data().value<BreakpointModelId>();
hjk's avatar
hjk committed
812
        m_breakHandler->removeBreakpoint(id);
hjk's avatar
hjk committed
813
814
815
816
817
818
     }

    void breakpointEnableMarginActionTriggered()
    {
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
819
        BreakpointModelId id = act->data().value<BreakpointModelId>();
hjk's avatar
hjk committed
820
        breakHandler()->setEnabled(id, true);
hjk's avatar
hjk committed
821
822
823
824
825
826
    }

    void breakpointDisableMarginActionTriggered()
    {
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
Nikolai Kosjar's avatar
Nikolai Kosjar committed
827
        BreakpointModelId id = act->data().value<BreakpointModelId>();
hjk's avatar
hjk committed
828
        breakHandler()->setEnabled(id, false);
829
830
    }

831
    void updateWatchersHeader(int section, int, int newSize)
832
    {
833
834
        m_watchersView->header()->resizeSection(section, newSize);
        m_returnView->header()->resizeSection(section, newSize);
835
    }
836

837
    void sourceFilesDockToggled(bool on)
838
    {
839
        if (on && m_currentEngine->state() == InferiorStopOk)
840
841
842
            m_currentEngine->reloadSourceFiles();
    }

843
    void modulesDockToggled(bool on)
844
    {
845
        if (on && m_currentEngine->state() == InferiorStopOk)
846
847
            m_currentEngine->reloadModules();
    }
848

hjk's avatar
hjk committed
849
    void registerDockToggled(bool on)
850
    {
851
        if (on && m_currentEngine->state() == InferiorStopOk)
852
853
            m_currentEngine->reloadRegisters();
    }
854

855
856
    void synchronizeBreakpoints()
    {
857
        showMessage(QLatin1String("ATTEMPT SYNC"), LogDebug);
858
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
859
            if (DebuggerEngine *engine = m_snapshotHandler->at(i))
860
861
862
863
                engine->attemptBreakpointSynchronization();
        }
    }

864
    void editorOpened(Core::IEditor *editor);
865
    void updateBreakMenuItem(Core::IEditor *editor);
866
    void setBusyCursor(bool busy);
867
    void requestMark(TextEditor::BaseTextEditor *editor,
868
                     int lineNumber,
869
870
                     TextEditor::BaseTextEditor::MarkRequestKind kind);
    void requestContextMenu(TextEditor::BaseTextEditor *editor,
871
        int lineNumber, QMenu *menu);
872

873
874
875
    void activatePreviousMode();
    void activateDebugMode();
    void toggleBreakpoint();
876
877
878
879
    void toggleBreakpointByFileAndLine(const QString &fileName, int lineNumber,
                                       const QString &tracePointMessage = QString());
    void toggleBreakpointByAddress(quint64 address,
                                   const QString &tracePointMessage = QString());
880
    void onModeChanged(Core::IMode *mode);
881
    void onCoreAboutToOpen();
882
    void showSettingsDialog();
883
    void updateDebugWithoutDeployMenu();
884

885
    void debugProject();
886
    void debugProjectWithoutDeploy();
887
    void debugProjectBreakMain();
888
    void startAndDebugApplication();
889
    void startRemoteCdbSession();
890
    void startRemoteServer();
891
    void attachToRemoteServer();
892
    void attachToProcess(bool startServerOnly);
hjk's avatar
hjk committed
893
    void attachToRunningApplication();
894
895
896
    void attachToUnstartedApplicationDialog();
    void attachToFoundProcess();
    void continueOnAttach(Debugger::DebuggerState state);
897
    void attachExternalApplication(ProjectExplorer::RunControl *rc);
898
    void attachToQmlPort();
899
    void startRemoteEngine();
900
    void runScheduled();
901
    void attachCore();
902

903
    void enableReverseDebuggingTriggered(const QVariant &value);
hjk's avatar
hjk committed
904
    void languagesChanged();
905
    void showStatusMessage(const QString &msg, int timeout = -1);
906
    void openMemoryEditor();
907

908
909
    const CPlusPlus::Snapshot &cppCodeModelSnapshot() const;

hjk's avatar
hjk committed
910
    DebuggerMainWindow *mainWindow() const { return m_mainWindow; }
hjk's avatar
hjk committed
911

912
    bool isDockVisible(const QString &objectName) const
hjk's avatar
hjk committed
913
914
915
916
    {
        QDockWidget *dock = mainWindow()->findChild<QDockWidget *>(objectName);
        return dock && dock->toggleViewAction()->isChecked();
    }
917
918

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

921
922
    void runControlStarted(DebuggerEngine *engine);
    void runControlFinished(DebuggerEngine *engine);
923
924
925
926
    DebuggerLanguages activeLanguages() const;
    void remoteCommand(const QStringList &options, const QStringList &);

    bool isReverseDebugging() const;
927

928
929
930
    BreakHandler *breakHandler() const { return m_breakHandler; }
    SnapshotHandler *snapshotHandler() const { return m_snapshotHandler; }

931
    void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
932
933
934

    void dumpLog();
    void cleanupViews();
935
    void setInitialState();
936
937
938
939

    void fontSettingsChanged(const