debuggerplugin.cpp 125 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
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
** 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
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
hjk's avatar
hjk committed
30

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

Friedemann Kleint's avatar
Friedemann Kleint committed
33
#include "debuggerstartparameters.h"
34
#include "debuggeractions.h"
35
#include "debuggerinternalconstants.h"
36
#include "debuggercore.h"
37
#include "debuggerkitconfigwidget.h"
38
39
#include "debuggerdialogs.h"
#include "debuggerengine.h"
40
#include "debuggeritemmanager.h"
41
#include "debuggermainwindow.h"
42
#include "debuggerrunconfigurationaspect.h"
43
#include "debuggerruncontrol.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>
Daniel Teske's avatar
Daniel Teske committed
77
#include <coreplugin/find/itemviewfind.h>
78
#include <coreplugin/imode.h>
con's avatar
con committed
79
80
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
81
#include <coreplugin/messagebox.h>
82
#include <coreplugin/messagemanager.h>
con's avatar
con committed
83
#include <coreplugin/modemanager.h>
84
85
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/documentmodel.h>
hjk's avatar
hjk committed
86

con's avatar
con committed
87
#include <cppeditor/cppeditorconstants.h>
88
#include <cpptools/cppmodelmanager.h>
hjk's avatar
hjk committed
89

90
#include <extensionsystem/invoker.h>
91

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

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

110
#include <utils/basetreeview.h>
111
#include <utils/hostosinfo.h>
Eike Ziller's avatar
Eike Ziller committed
112
#include <utils/mimetypes/mimedatabase.h>
113
#include <utils/proxyaction.h>
114
115
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
116
#include <utils/statuslabel.h>
117
#include <utils/styledbar.h>
hjk's avatar
hjk committed
118
#include <utils/winutils.h>
con's avatar
con committed
119

Campbell Barton's avatar
Campbell Barton committed
120
#include <QApplication>
hjk's avatar
hjk committed
121
#include <QCheckBox>
122
#include <QComboBox>
123
124
#include <QDockWidget>
#include <QFileDialog>
hjk's avatar
hjk committed
125
126
#include <QHBoxLayout>
#include <QHeaderView>
hjk's avatar
hjk committed
127
#include <QInputDialog>
128
129
130
#include <QMessageBox>
#include <QTextBlock>
#include <QToolButton>
hjk's avatar
hjk committed
131
#include <QtPlugin>
132
#include <QTreeWidget>
133
#include <QVBoxLayout>
134
#include <QMenu>
135

hjk's avatar
hjk committed
136
#ifdef WITH_TESTS
137
138
139
#include <QTest>
#include <QSignalSpy>
#include <QTestEventLoop>
140
141
142
143

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

146
147
#endif // WITH_TESTS

148
149
#include <climits>

150
151
152
153
154
#define DEBUG_STATE 1
#ifdef DEBUG_STATE
//#   define STATE_DEBUG(s)
//    do { QString msg; QTextStream ts(&msg); ts << s;
//      showMessage(msg, LogDebug); } while (0)
155
#   define STATE_DEBUG(s) do { qDebug() << s; } while (0)
156
157
158
159
#else
#   define STATE_DEBUG(s)
#endif

160
161
162
163
164
165
166
167
/*!
    \namespace Debugger
    Debugger plugin namespace
*/

/*!
    \namespace Debugger::Internal
    Internal namespace of the Debugger plugin
168
    \internal
169
170
171
172
173
*/

/*!
    \class Debugger::DebuggerEngine

174
    \brief The DebuggerEngine class is the base class of a debugger engine.
175

Leena Miettinen's avatar
Leena Miettinen committed
176
    \note The Debugger process itself and any helper processes like
177
178
    gdbserver are referred to as 'Engine', whereas the debugged process
    is referred to as 'Inferior'.
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
288
289
290
291
292
293
294

    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
295

296
297
298
/* 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
299

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


340
341
/*!
    \class Debugger::Internal::GdbEngine
342
343
    \brief The GdbEngine class implements Debugger::Engine driving a GDB
    executable.
344
345
346

    GdbEngine specific startup. All happens in EngineSetupRequested state:

Leena Miettinen's avatar
Leena Miettinen committed
347
348
    \list
        \li Transitions marked by '---' are done in the individual adapters.
349

Leena Miettinen's avatar
Leena Miettinen committed
350
351
        \li Transitions marked by '+-+' are done in the GdbEngine.
    \endlist
352
353
354
355
356
357
358
359
360
361
362
363
364

    \code
                  GdbEngine::setupEngine()
                          +
            (calls *Adapter->startAdapter())
                          |      |
                          |      `---> handleAdapterStartFailed()
                          |                   +
                          |             {notifyEngineSetupFailed}
                          |
                 handleAdapterStarted()
                          +
                 {notifyEngineSetupOk}
365
366
367



368
369
370
371
372
373
374
375
376
377
378
                GdbEngine::setupInferior()
                          +
            (calls *Adapter->prepareInferior())
                          |      |
                          |      `---> handlePrepareInferiorFailed()
                          |                   +
                          |             {notifyInferiorSetupFailed}
                          |
                handleInferiorPrepared()
                          +
                {notifyInferiorSetupOk}
379

380
\endcode */
381

con's avatar
con committed
382
using namespace Core;
hjk's avatar
hjk committed
383
using namespace Debugger::Constants;
384
using namespace Debugger::Internal;
385
using namespace ExtensionSystem;
con's avatar
con committed
386
using namespace ProjectExplorer;
hjk's avatar
hjk committed
387
using namespace TextEditor;
388
using namespace Utils;
con's avatar
con committed
389

hjk's avatar
hjk committed
390
391
392
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
393
394

namespace Debugger {
395
396
namespace Internal {

397
398
399
400
401
402
403
404
405
406
407
struct TestCallBack
{
    TestCallBack() : receiver(0), slot(0) {}
    TestCallBack(QObject *ob, const char *s) : receiver(ob), slot(s) {}

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


408
409
410
} // namespace Internal
} // namespace Debugger

411
412
Q_DECLARE_METATYPE(Debugger::Internal::TestCallBack)

413
414
415
namespace Debugger {
namespace Internal {

416
void addCdbOptionPages(QList<IOptionsPage*> *opts);
417
void addGdbOptionPages(QList<IOptionsPage*> *opts);
418

419
420
421
422
423
424
425
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

426
static void setProxyAction(ProxyAction *proxy, Id id)
427
{
hjk's avatar
hjk committed
428
    proxy->setAction(ActionManager::command(id)->action());
429
430
}

431
static QToolButton *toolButton(Id id)
432
{
hjk's avatar
hjk committed
433
    return toolButton(ActionManager::command(id)->action());
434
435
}

436
437
438
439
440
441
442
443
444
///////////////////////////////////////////////////////////////////////
//
// DummyEngine
//
///////////////////////////////////////////////////////////////////////

class DummyEngine : public DebuggerEngine
{
public:
445
    DummyEngine() : DebuggerEngine(DebuggerStartParameters()) {}
446
447
448
449
450
451
452
    ~DummyEngine() {}

    void setupEngine() {}
    void setupInferior() {}
    void runEngine() {}
    void shutdownEngine() {}
    void shutdownInferior() {}
453
    bool hasCapability(unsigned cap) const;
454
    bool acceptsBreakpoint(Breakpoint) const { return false; }
455
    bool acceptsDebuggerCommands() const { return false; }
hjk's avatar
hjk committed
456
    void selectThread(ThreadId) {}
457
458
};

459
bool DummyEngine::hasCapability(unsigned cap) const
460
461
{
    // This can only be a first approximation of what to expect when running.
462
    Project *project = ProjectTree::currentProject();
463
464
465
466
467
468
469
470
    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:
471
    if (activeRc->extraAspect<Debugger::DebuggerRunConfigurationAspect>()->useCppDebugger())
472
        return cap & (WatchpointByAddressCapability
473
474
               | BreakConditionCapability
               | TracePointCapability
475
               | OperateNativeMixed
476
               | OperateByInstructionCapability);
477
478

    // This is a Qml or unknown engine.
479
    return cap & AddWatcherCapability;
480
481
}

482
483
484
485
486
487
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

488
class DebugMode : public IMode
hjk's avatar
hjk committed
489
490
{
public:
491
492
493
    DebugMode()
    {
        setObjectName(QLatin1String("DebugMode"));
494
        setContext(Context(C_DEBUGMODE, CC::C_NAVIGATION_PANE));
495
        setDisplayName(DebuggerPlugin::tr("Debug"));
496
        setIcon(QIcon(QLatin1String(":/debugger/images/mode_debug.png")));
497
        setPriority(85);
498
        setId(MODE_DEBUG);
499
    }
hjk's avatar
hjk committed
500

hjk's avatar
hjk committed
501
502
503
504
    ~DebugMode()
    {
        delete m_widget;
    }
505
};
hjk's avatar
hjk committed
506

507
508
509
510
511
512
///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

513
static QWidget *addSearch(BaseTreeView *treeView, const QString &title,
514
    const char *objectName)
515
{
hjk's avatar
hjk committed
516
    QAction *act = action(UseAlternatingRowColors);
517
    treeView->setAlternatingRowColors(act->isChecked());
518
519
    QObject::connect(act, &QAction::toggled,
                     treeView, &BaseTreeView::setAlternatingRowColorsHelper);
520

Daniel Teske's avatar
Daniel Teske committed
521
    QWidget *widget = ItemViewFind::createSearchableWrapper(treeView);
522
523
524
525
526
    widget->setObjectName(QLatin1String(objectName));
    widget->setWindowTitle(title);
    return widget;
}

527
static std::function<bool(const Kit *)> cdbMatcher(char wordWidth = 0)
528
{
529
    return [wordWidth](const Kit *k) -> bool {
530
531
        if (DebuggerKitInformation::engineType(k) != CdbEngineType
            || !DebuggerKitInformation::isValidDebugger(k)) {
532
            return false;
533
        }
534
        if (wordWidth) {
535
            const ToolChain *tc = ToolChainKitInformation::toolChain(k);
536
            return tc && wordWidth == tc->targetAbi().wordWidth();
537
        }
538
        return true;
539
540
    };
}
541

542
543
544
545
546
547
548
// Find a CDB kit for debugging unknown processes.
// On a 64bit OS, prefer a 64bit debugger.
static Kit *findUniversalCdbKit()
{
    if (Utils::is64BitWindowsSystem()) {
        if (Kit *cdb64Kit = KitManager::find(cdbMatcher(64)))
            return cdb64Kit;
549
    }
550
551
    return KitManager::find(cdbMatcher());
}
552

553
554
static bool currentTextEditorPosition(ContextData *data)
{
555
    BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
556
557
    if (!textEditor)
        return false;
558
    const TextDocument *document = textEditor->textDocument();
559
    QTC_ASSERT(document, return false);
560
    data->fileName = document->filePath().toString();
561
    if (document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) {
562
        int lineNumber = textEditor->currentLine();
563
        QString line = textEditor->textDocument()->plainText()
564
565
566
567
            .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1);
        data->address = DisassemblerLine::addressFromDisassemblyLine(line);
    } else {
        data->lineNumber = textEditor->currentLine();
568
    }
569
    return true;
570
}
571

572
573
///////////////////////////////////////////////////////////////////////
//
574
// DebuggerPluginPrivate
575
576
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
577

578
static DebuggerPluginPrivate *dd = 0;
con's avatar
con committed
579

580
581
582
583
584
585
586
587
588
589
590
591
592
593
/*!
    \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.
*/

594
class DebuggerPluginPrivate : public QObject
595
596
{
    Q_OBJECT
597

598
599
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
600
    ~DebuggerPluginPrivate();
601

602
    bool initialize(const QStringList &arguments, QString *errorMessage);
603
604
605
    void extensionsInitialized();
    void aboutToShutdown();

606
    void connectEngine(DebuggerEngine *engine);
hjk's avatar
hjk committed
607
    void disconnectEngine() { connectEngine(0); }
608
    DebuggerEngine *dummyEngine();
609

610
611
612
613
614
615
616
617
618
    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);
    }
619
620

    DebuggerRunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process, bool contAfterAttach);
621

622
623
624
625
626
627
    void writeSettings()
    {
        m_debuggerSettings->writeSettings();
        m_mainWindow->writeSettings();
    }

628
629
    void selectThread(int index)
    {
hjk's avatar
hjk committed
630
631
        ThreadId id = m_currentEngine->threadsHandler()->threadAt(index);
        m_currentEngine->selectThread(id);
632
    }
633

634
    void breakpointSetMarginActionTriggered(bool isMessageOnly, const ContextData &data)
635
    {
636
        QString message;
637
        if (isMessageOnly) {
638
639
640
641
642
            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.
643
                message = tr("%1:%2 %3() hit").arg(FileName::fromString(data.fileName).fileName()).
644
645
646
647
648
                        arg(data.lineNumber).
                        arg(cppFunctionAt(data.fileName, data.lineNumber));
            }
            QInputDialog dialog; // Create wide input dialog.
            dialog.setWindowFlags(dialog.windowFlags()
hjk's avatar
hjk committed
649
              & ~(Qt::WindowContextHelpButtonHint|Qt::MSWindowsFixedSizeDialogHint));
650
651
652
653
654
655
656
657
            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();
        }
658
        if (data.address)
659
            toggleBreakpointByAddress(data.address, message);
660
        else
661
            toggleBreakpointByFileAndLine(data.fileName, data.lineNumber, message);
662
    }
663

664
    void updateWatchersHeader(int section, int, int newSize)
665
    {
666
667
        m_watchersView->header()->resizeSection(section, newSize);
        m_returnView->header()->resizeSection(section, newSize);
668
    }
669

670
    void sourceFilesDockToggled(bool on)
671
    {
672
        if (on && m_currentEngine->state() == InferiorStopOk)
673
674
675
            m_currentEngine->reloadSourceFiles();
    }

676
    void modulesDockToggled(bool on)
677
    {
678
        if (on && m_currentEngine->state() == InferiorStopOk)
679
680
            m_currentEngine->reloadModules();
    }
681

hjk's avatar
hjk committed
682
    void registerDockToggled(bool on)
683
    {
684
        if (on && m_currentEngine->state() == InferiorStopOk)
685
686
            m_currentEngine->reloadRegisters();
    }
687

688
689
    void synchronizeBreakpoints()
    {
690
        showMessage(QLatin1String("ATTEMPT SYNC"), LogDebug);
691
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
692
            if (DebuggerEngine *engine = m_snapshotHandler->at(i))
693
694
695
696
                engine->attemptBreakpointSynchronization();
        }
    }

697
698
    void editorOpened(IEditor *editor);
    void updateBreakMenuItem(IEditor *editor);
699
    void setBusyCursor(bool busy);
700
701
702
    void requestMark(TextEditorWidget *widget, int lineNumber,
                     TextMarkRequestKind kind);
    void requestContextMenu(TextEditorWidget *widget,
703
                            int lineNumber, QMenu *menu);
704

705
706
707
    void activatePreviousMode();
    void activateDebugMode();
    void toggleBreakpoint();
708
709
710
711
    void toggleBreakpointByFileAndLine(const QString &fileName, int lineNumber,
                                       const QString &tracePointMessage = QString());
    void toggleBreakpointByAddress(quint64 address,
                                   const QString &tracePointMessage = QString());
712
    void onModeChanged(IMode *mode);
713
    void onCoreAboutToOpen();
714
    void updateDebugWithoutDeployMenu();
715

716
    void startAndDebugApplication();
717
    void startRemoteCdbSession();
718
    void startRemoteServerAndAttachToProcess();
719
    void attachToRemoteServer();
hjk's avatar
hjk committed
720
    void attachToRunningApplication();
721
    void attachToUnstartedApplicationDialog();
722
    void attachToQmlPort();
hjk's avatar
hjk committed
723
    Q_SLOT void runScheduled();
724
    void attachCore();
725

726
    void enableReverseDebuggingTriggered(const QVariant &value);
727
    void showStatusMessage(const QString &msg, int timeout = -1);
728

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

731
    bool isDockVisible(const QString &objectName) const
hjk's avatar
hjk committed
732
733
734
735
    {
        QDockWidget *dock = mainWindow()->findChild<QDockWidget *>(objectName);
        return dock && dock->toggleViewAction()->isChecked();
    }
736

737
738
    void runControlStarted(DebuggerEngine *engine);
    void runControlFinished(DebuggerEngine *engine);
739
740
    void remoteCommand(const QStringList &options, const QStringList &);

741
    void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
742
743
744

    void dumpLog();
    void cleanupViews();
745
    void setInitialState();
746

747
    void fontSettingsChanged(const FontSettings &settings);
748
749

    void updateState(DebuggerEngine *engine);
hjk's avatar
hjk committed
750
    void updateWatchersWindow(bool showWatch, bool showReturn);
751
    void onCurrentProjectChanged(Project *project);
752
753
754
755

    void sessionLoaded();
    void aboutToUnloadSession();
    void aboutToSaveSession();
756

757
    void coreShutdown();
758

hjk's avatar
hjk committed
759
760
#ifdef WITH_TESTS
public slots:
761
    void testLoadProject(const QString &proFile, const TestCallBack &cb);
762
    void testProjectLoaded(Project *project);
763
764
    void testProjectEvaluated();
    void testProjectBuilt(bool success);
765
766
767
768
    void testUnloadProject();
    void testFinished();

    void testRunProject(const DebuggerStartParameters &sp, const TestCallBack &cb);
hjk's avatar
hjk committed
769
    void testRunControlFinished();
770

hjk's avatar
hjk committed
771
772
773
//    void testStateMachine1();
//    void testStateMachine2();
//    void testStateMachine3();
774

775
776
    void testBenchmark1();

777
public:
hjk's avatar
hjk committed
778
    Project *m_testProject;
779
780
781
    bool m_testSuccess;
    QList<TestCallBack> m_testCallbacks;

hjk's avatar
hjk committed
782
783
#endif

hjk's avatar
hjk committed
784
public slots:
785
    void updateDebugActions();
786
787
788

    void handleExecDetach()
    {
789
        currentEngine()->resetLocation();
790
791
792
793
794
        currentEngine()->detachDebugger();
    }

    void handleExecContinue()
    {
795
        currentEngine()->resetLocation();
796
797
798
799
800
        currentEngine()->continueInferior();
    }

    void handleExecInterrupt()
    {
801
        currentEngine()->resetLocation();
802
803
804
        currentEngine()->requestInterruptInferior();
    }

805
    void handleAbort()
806
    {
807
        currentEngine()->resetLocation();
808
        currentEngine()->abortDebugger();
809
    }
hjk's avatar
hjk committed
810

811
812
813
814
815
816
    void handleReset()
    {
        currentEngine()->resetLocation();
        currentEngine()->resetInferior();
    }

hjk's avatar
hjk committed
817
818
    void handleExecStep()
    {
819
        if (currentEngine()->state() == DebuggerNotReady) {
820
            ProjectExplorerPlugin::runStartupProject(DebugRunModeWithBreakOnMain);
821
822
823
824
825
826
827
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeStepI();
            else
                currentEngine()->executeStep();
        }
hjk's avatar
hjk committed
828
829
830
831
    }

    void handleExecNext()
    {
832
        if (currentEngine()->state() == DebuggerNotReady) {
833
            ProjectExplorerPlugin::runStartupProject(DebugRunModeWithBreakOnMain);
834
835
836
837
838
839
840
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeNextI();
            else
                currentEngine()->executeNext();
        }
hjk's avatar
hjk committed
841
842
    }

843
844
    void handleExecStepOut()
    {
845
        currentEngine()->resetLocation();
846
847
848
849
850
        currentEngine()->executeStepOut();
    }

    void handleExecReturn()
    {
851
        currentEngine()->resetLocation();
852
853
        currentEngine()->executeReturn();
    }
hjk's avatar
hjk committed
854
855
856

    void handleExecJumpToLine()
    {
857
        currentEngine()->resetLocation();
858
859
860
        ContextData data;
        if (currentTextEditorPosition(&data))
            currentEngine()->executeJumpToLine(data);
hjk's avatar
hjk committed
861
862
863
864
    }

    void handleExecRunToLine()
    {
865
        currentEngine()->resetLocation();
866
867
868
        ContextData data;
        if (currentTextEditorPosition(&data))
            currentEngine()->executeRunToLine(data);
hjk's avatar
hjk committed
869
870
    }

871
    void handleExecRunToSelectedFunction()
hjk's avatar
hjk committed
872
    {
873
        BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
874
        QTC_ASSERT(textEditor, return);
875
        QTextCursor cursor = textEditor->textCursor();
876
877
878
879
        QString functionName = cursor.selectedText();
        if (functionName.isEmpty()) {
            const QTextBlock block = cursor.block();
            const QString line = block.text();
880
            foreach (const QString &str, line.trimmed().split(QLatin1Char('('))) {
881
882
883
884
885
886
887
888
889
890
891
892
893
                QString a;
                for (int i = str.size(); --i >= 0; ) {
                    if (!str.at(i).isLetterOrNumber())
                        break;
                    a = str.at(i) + a;
                }
                if (!a.isEmpty()) {
                    functionName = a;
                    break;
                }
            }
        }

894
895
896
897
898
899
        if (functionName.isEmpty()) {
            showStatusMessage(tr("No function selected."));
        } else {
            showStatusMessage(tr("Running to function \"%1\".")
                .arg(functionName));
            currentEngine()->resetLocation();
900
            currentEngine()->executeRunToFunction(functionName);
901
        }
hjk's avatar
hjk committed
902
903
904
905
906
    }

    void handleAddToWatchWindow()
    {
        // Requires a selection, but that's the only case we want anyway.
907
        BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
hjk's avatar
hjk committed
908
909
        if (!textEditor)
            return;
910
        QTextCursor tc = textEditor->textCursor();
hjk's avatar
hjk committed
911
912
913
914
915
        QString exp;
        if (tc.hasSelection()) {
            exp = tc.selectedText();
        } else {
            int line, column;
916
            exp = cppExpressionAt(textEditor->editorWidget(), tc.position(), &line, &column);
hjk's avatar
hjk committed
917
        }
918
919
920
921
        if (currentEngine()->hasCapability(WatchComplexExpressionsCapability))
            exp = removeObviousSideEffects(exp);
        else
            exp = fixCppExpression(exp);
hjk's avatar
hjk committed
922
923
        if (exp.isEmpty())
            return;
924
        currentEngine()->watchHandler()->watchVariable(exp);
hjk's avatar
hjk committed
925
926
927
928
    }

    void handleExecExit()
    {
929
        currentEngine()->exitDebugger();
hjk's avatar
hjk committed
930
931
932
933
934
935
936
937
938
939
940
941
    }

    void handleFrameDown()
    {
        currentEngine()->frameDown();
    }

    void handleFrameUp()
    {
        currentEngine()->frameUp();
    }

942
    void handleOperateByInstructionTriggered(bool operateByInstructionTriggered)
hjk's avatar
hjk committed
943
    {
944
945
946
        // Go to source only if we have the file.
        if (currentEngine()->stackHandler()->currentIndex() >= 0) {
            const StackFrame frame = currentEngine()->stackHandler()->currentFrame();
947
            if (operateByInstructionTriggered || frame.isUsable())
948
                currentEngine()->gotoLocation(Location(frame, true));
949
        }
hjk's avatar
hjk committed
950
951
    }

952
953
    void showMessage(const QString &msg, int channel, int timeout = -1);

954
    bool parseArgument(QStringList::const_iterator &it,
955
956
        const QStringList::const_iterator &cend, QString *errorMessage);
    bool parseArguments(const QStringList &args, QString *errorMessage);
957
    void parseCommandLineArguments();
958

959
960
961
962
    void updateQmlActions() {
        action(QmlUpdateOnSave)->setEnabled(boolSetting(ShowQmlObjectTree));
    }