debuggerplugin.cpp 129 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
** 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
Eike Ziller's avatar
Eike Ziller committed
13 14
** conditions see http://www.qt.io/licensing.  For further information
** 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 25 26
**
** 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
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/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/cppmodelmanager.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

101
#include <texteditor/texteditor.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 Debugger::Internal;
378
using namespace ExtensionSystem;
con's avatar
con committed
379
using namespace ProjectExplorer;
hjk's avatar
hjk committed
380
using namespace TextEditor;
381
using namespace Utils;
con's avatar
con committed
382

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

con's avatar
con committed
386 387

namespace Debugger {
388 389
namespace Internal {

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

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

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

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


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

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

420 421 422 423

namespace Debugger {
namespace Internal {

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

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

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

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

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

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

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

class DummyEngine : public DebuggerEngine
{
    Q_OBJECT

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

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

481
bool DummyEngine::hasCapability(unsigned cap) const
482 483
{
    // This can only be a first approximation of what to expect when running.
484
    Project *project = ProjectExplorerPlugin::currentProject();
485 486 487 488 489 490 491 492
    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:
493
    if (activeRc->extraAspect<Debugger::DebuggerRunConfigurationAspect>()->useCppDebugger())
494
        return cap & (WatchpointByAddressCapability
495 496
               | BreakConditionCapability
               | TracePointCapability
497
               | OperateByInstructionCapability);
498 499

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

503 504 505 506 507 508
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

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

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

528 529 530 531 532 533
///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

534
static QWidget *addSearch(BaseTreeView *treeView, const QString &title,
535
    const char *objectName)
536
{
hjk's avatar
hjk committed
537
    QAction *act = action(UseAlternatingRowColors);
538
    treeView->setAlternatingRowColors(act->isChecked());
539 540
    QObject::connect(act, &QAction::toggled,
                     treeView, &BaseTreeView::setAlternatingRowColorsHelper);
541

Daniel Teske's avatar
Daniel Teske committed
542
    QWidget *widget = ItemViewFind::createSearchableWrapper(treeView);
543 544 545 546 547
    widget->setObjectName(QLatin1String(objectName));
    widget->setWindowTitle(title);
    return widget;
}

548
static std::function<bool(const Kit *)> cdbMatcher(char wordWidth = 0)
549
{
550
    return [wordWidth](const Kit *k) -> bool {
551 552
        if (DebuggerKitInformation::engineType(k) != CdbEngineType
            || !DebuggerKitInformation::isValidDebugger(k)) {
553
            return false;
554
        }
555
        if (wordWidth) {
556
            const ToolChain *tc = ToolChainKitInformation::toolChain(k);
557
            return tc && wordWidth == tc->targetAbi().wordWidth();
558
        }
559
        return true;
560 561
    };
}
562

563 564 565 566 567 568 569
// 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;
570
    }
571 572
    return KitManager::find(cdbMatcher());
}
573

574 575
static bool currentTextEditorPosition(ContextData *data)
{
576
    BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
577 578
    if (!textEditor)
        return false;
579
    const TextDocument *document = textEditor->textDocument();
580
    QTC_ASSERT(document, return false);
581
    data->fileName = document->filePath();
582
    if (document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) {
583
        int lineNumber = textEditor->currentLine();
584
        QString line = textEditor->textDocument()->plainText()
585 586 587 588
            .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1);
        data->address = DisassemblerLine::addressFromDisassemblyLine(line);
    } else {
        data->lineNumber = textEditor->currentLine();
589
    }
590
    return true;
591
}
592

593 594
///////////////////////////////////////////////////////////////////////
//
595
// DebuggerPluginPrivate
596 597
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
598

599
static DebuggerPluginPrivate *dd = 0;
con's avatar
con committed
600

601 602 603 604 605 606 607 608 609 610 611 612 613 614
/*!
    \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.
*/

615
class DebuggerPluginPrivate : public QObject
616 617
{
    Q_OBJECT
618

619 620
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
621
    ~DebuggerPluginPrivate();
622

623
    bool initialize(const QStringList &arguments, QString *errorMessage);
624 625 626
    void extensionsInitialized();
    void aboutToShutdown();

627
    void connectEngine(DebuggerEngine *engine);
hjk's avatar
hjk committed
628
    void disconnectEngine() { connectEngine(0); }
629
    DebuggerEngine *dummyEngine();
630

631 632 633 634 635 636 637 638 639
    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);
    }
640
    DebuggerRunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process);
641

642
public slots:
643 644 645 646 647 648
    void writeSettings()
    {
        m_debuggerSettings->writeSettings();
        m_mainWindow->writeSettings();
    }

649 650
    void selectThread(int index)
    {
hjk's avatar
hjk committed
651 652
        ThreadId id = m_currentEngine->threadsHandler()->threadAt(index);
        m_currentEngine->selectThread(id);
653
    }
654

hjk's avatar
hjk committed
655
    void breakpointSetMarginActionTriggered()
656
    {
657 658
        const QAction *action = qobject_cast<const QAction *>(sender());
        QTC_ASSERT(action, return);
hjk's avatar
hjk committed
659 660
        const BreakpointMenuContextData data =
            action->data().value<BreakpointMenuContextData>();
661 662 663 664 665 666 667 668 669 670 671 672 673
        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
674
              & ~(Qt::WindowContextHelpButtonHint|Qt::MSWindowsFixedSizeDialogHint));
675 676 677 678 679 680 681 682
            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();
        }
683
        if (data.address)
684
            toggleBreakpointByAddress(data.address, message);
685
        else
686
            toggleBreakpointByFileAndLine(data.fileName, data.lineNumber, message);
687
    }
688

hjk's avatar
hjk committed
689
    void breakpointRemoveMarginActionTriggered()
690
    {
hjk's avatar
hjk committed
691 692
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
693
        BreakpointModelId id = act->data().value<BreakpointModelId>();
hjk's avatar
hjk committed
694
        m_breakHandler->removeBreakpoint(id);
hjk's avatar
hjk committed
695 696 697 698 699 700
     }

    void breakpointEnableMarginActionTriggered()
    {
        const QAction *act = qobject_cast<QAction *>(sender());
        QTC_ASSERT(act, return);
701
        BreakpointModelId id = act->data().value<BreakpointModelId>();
hjk's avatar
hjk committed
702
        breakHandler()->setEnabled(id, true);
hjk's avatar
hjk committed
703 704 705 706 707 708
    }

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

713
    void updateWatchersHeader(int section, int, int newSize)
714
    {
715 716
        m_watchersView->header()->resizeSection(section, newSize);
        m_returnView->header()->resizeSection(section, newSize);
717
    }
718

719
    void sourceFilesDockToggled(bool on)
720
    {
721
        if (on && m_currentEngine->state() == InferiorStopOk)
722 723 724
            m_currentEngine->reloadSourceFiles();
    }

725
    void modulesDockToggled(bool on)
726
    {
727
        if (on && m_currentEngine->state() == InferiorStopOk)
728 729
            m_currentEngine->reloadModules();
    }
730

hjk's avatar
hjk committed
731
    void registerDockToggled(bool on)
732
    {
733
        if (on && m_currentEngine->state() == InferiorStopOk)
734 735
            m_currentEngine->reloadRegisters();
    }
736

737 738
    void synchronizeBreakpoints()
    {
739
        showMessage(QLatin1String("ATTEMPT SYNC"), LogDebug);
740
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
741
            if (DebuggerEngine *engine = m_snapshotHandler->at(i))
742 743 744 745
                engine->attemptBreakpointSynchronization();
        }
    }

746
    void editorOpened(Core::IEditor *editor);
747
    void updateBreakMenuItem(Core::IEditor *editor);
748
    void setBusyCursor(bool busy);
749
    void requestMark(TextEditor::TextEditorWidget *widget, int lineNumber,
750
                     TextEditor::TextMarkRequestKind kind);
751 752
    void requestContextMenu(TextEditor::TextEditorWidget *widget,
                            int lineNumber, QMenu *menu);
753

754 755 756
    void activatePreviousMode();
    void activateDebugMode();
    void toggleBreakpoint();
757 758 759 760
    void toggleBreakpointByFileAndLine(const QString &fileName, int lineNumber,
                                       const QString &tracePointMessage = QString());
    void toggleBreakpointByAddress(quint64 address,
                                   const QString &tracePointMessage = QString());
761
    void onModeChanged(Core::IMode *mode);
762
    void onCoreAboutToOpen();
763
    void showSettingsDialog();
764
    void updateDebugWithoutDeployMenu();
765

766
    void debugProject();
767
    void debugProjectWithoutDeploy();
768
    void debugProjectBreakMain();
769
    void startAndDebugApplication();
770
    void startRemoteCdbSession();
771
    void startRemoteServer();
772
    void attachToRemoteServer();
773
    void attachToProcess(bool startServerOnly);
hjk's avatar
hjk committed
774
    void attachToRunningApplication();
775 776 777
    void attachToUnstartedApplicationDialog();
    void attachToFoundProcess();
    void continueOnAttach(Debugger::DebuggerState state);
778
    void attachToQmlPort();
779
    void runScheduled();
780
    void attachCore();
781

782
    void enableReverseDebuggingTriggered(const QVariant &value);
783
    void showStatusMessage(const QString &msg, int timeout = -1);
784

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

787
    bool isDockVisible(const QString &objectName) const
hjk's avatar
hjk committed
788 789 790 791
    {
        QDockWidget *dock = mainWindow()->findChild<QDockWidget *>(objectName);
        return dock && dock->toggleViewAction()->isChecked();
    }
792

793 794
    void runControlStarted(DebuggerEngine *engine);
    void runControlFinished(DebuggerEngine *engine);
795 796
    void remoteCommand(const QStringList &options, const QStringList &);

797
    void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
798 799 800

    void dumpLog();
    void cleanupViews();
801
    void setInitialState();
802 803 804 805

    void fontSettingsChanged(const TextEditor::FontSettings &settings);

    void updateState(DebuggerEngine *engine);
hjk's avatar
hjk committed
806
    void updateWatchersWindow(bool showWatch, bool showReturn);
807
    void onCurrentProjectChanged(ProjectExplorer::Project *project);
808 809 810 811

    void sessionLoaded();
    void aboutToUnloadSession();
    void aboutToSaveSession();
812

813
    void coreShutdown();
814

hjk's avatar
hjk committed
815 816
#ifdef WITH_TESTS
public slots:
817
    void testLoadProject(const QString &proFile, const TestCallBack &cb);
hjk's avatar
hjk committed
818
    void testProjectLoaded(ProjectExplorer::Project *project);
819 820
    void testProjectEvaluated();
    void testProjectBuilt(bool success);
821 822 823 824
    void testUnloadProject();
    void testFinished();

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

hjk's avatar
hjk committed
827 828 829
//    void testStateMachine1();
//    void testStateMachine2();
//    void testStateMachine3();
830

831 832
    void testBenchmark1();

833
public:
hjk's avatar
hjk committed
834
    Project *m_testProject;
835 836 837
    bool m_testSuccess;
    QList<TestCallBack> m_testCallbacks;

hjk's avatar
hjk committed
838 839
#endif

hjk's avatar
hjk committed
840
public slots:
841
    void updateDebugActions();
842 843 844

    void handleExecDetach()
    {
845
        currentEngine()->resetLocation();
846 847 848 849 850
        currentEngine()->detachDebugger();
    }

    void handleExecContinue()
    {
851
        currentEngine()->resetLocation();
852 853 854 855 856
        currentEngine()->continueInferior();
    }

    void handleExecInterrupt()
    {
857
        currentEngine()->resetLocation();
858 859 860
        currentEngine()->requestInterruptInferior();
    }

861
    void handleAbort()
862
    {
863
        currentEngine()->resetLocation();
864
        currentEngine()->abortDebugger();
865
    }
hjk's avatar
hjk committed
866

867 868 869 870 871 872
    void handleReset()
    {
        currentEngine()->resetLocation();
        currentEngine()->resetInferior();
    }

hjk's avatar
hjk committed
873 874
    void handleExecStep()
    {
875 876 877 878 879 880 881 882 883
        if (currentEngine()->state() == DebuggerNotReady) {
            debugProjectBreakMain();
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeStepI();
            else
                currentEngine()->executeStep();
        }
hjk's avatar
hjk committed
884 885 886 887
    }

    void handleExecNext()
    {
888 889 890 891 892 893 894 895 896
        if (currentEngine()->state() == DebuggerNotReady) {
            debugProjectBreakMain();
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeNextI();
            else
                currentEngine()->executeNext();
        }
hjk's avatar
hjk committed
897 898
    }

899 900
    void handleExecStepOut()
    {
901
        currentEngine()->resetLocation();
902 903 904 905 906
        currentEngine()->executeStepOut();
    }

    void handleExecReturn()
    {
907
        currentEngine()->resetLocation();
908 909
        currentEngine()->executeReturn();
    }
hjk's avatar
hjk committed
910 911 912

    void handleExecJumpToLine()
    {
913
        currentEngine()->resetLocation();
914 915 916
        ContextData data;
        if (currentTextEditorPosition(&data))
            currentEngine()->executeJumpToLine(data);
hjk's avatar
hjk committed
917 918 919 920
    }

    void handleExecRunToLine()
    {
921
        currentEngine()->resetLocation();
922 923 924
        ContextData data;
        if (currentTextEditorPosition(&data))
            currentEngine()->executeRunToLine(data);
hjk's avatar
hjk committed
925 926
    }

927
    void handleExecRunToSelectedFunction()
hjk's avatar
hjk committed
928
    {
929
        BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
930
        QTC_ASSERT(textEditor, return);
931
        QTextCursor cursor = textEditor->textCursor();
932 933 934 935
        QString functionName = cursor.selectedText();
        if (functionName.isEmpty()) {
            const QTextBlock block = cursor.block();
            const QString line = block.text();
936
            foreach (const QString &str, line.trimmed().split(QLatin1Char('('))) {
937 938 939 940 941