debuggerplugin.cpp 122 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 "debuggericons.h"
41
#include "debuggeritemmanager.h"
42
#include "debuggermainwindow.h"
43
#include "debuggerrunconfigurationaspect.h"
44
#include "debuggerruncontrol.h"
45
#include "debuggerstringutils.h"
46
#include "debuggeroptionspage.h"
Tobias Hunger's avatar
Tobias Hunger committed
47
#include "debuggerkitinformation.h"
48
#include "memoryagent.h"
49
#include "breakhandler.h"
50
#include "breakwindow.h"
51
#include "disassemblerlines.h"
52
#include "logwindow.h"
53
#include "moduleswindow.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
54
#include "moduleshandler.h"
55 56
#include "registerwindow.h"
#include "snapshotwindow.h"
hjk's avatar
hjk committed
57
#include "stackhandler.h"
58 59 60
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
hjk's avatar
hjk committed
61
#include "watchhandler.h"
62
#include "watchwindow.h"
hjk's avatar
hjk committed
63
#include "watchutils.h"
64
#include "unstartedappwatcherdialog.h"
65
#include "debuggertooltipmanager.h"
66
#include "localsandexpressionswindow.h"
67
#include "loadcoredialog.h"
68
#include "sourceutils.h"
hjk's avatar
hjk committed
69 70
#include "shared/hostutils.h"
#include "console/console.h"
71

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

77
#include <coreplugin/actionmanager/actionmanager.h>
78
#include <coreplugin/actionmanager/actioncontainer.h>
79
#include <coreplugin/actionmanager/command.h>
Daniel Teske's avatar
Daniel Teske committed
80
#include <coreplugin/find/itemviewfind.h>
81
#include <coreplugin/imode.h>
82
#include <coreplugin/coreicons.h>
con's avatar
con committed
83
#include <coreplugin/icore.h>
84
#include <coreplugin/messagebox.h>
85
#include <coreplugin/messagemanager.h>
con's avatar
con committed
86
#include <coreplugin/modemanager.h>
87 88
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/documentmodel.h>
hjk's avatar
hjk committed
89

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

93
#include <extensionsystem/invoker.h>
94

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

109
#include <texteditor/texteditor.h>
110
#include <texteditor/textdocument.h>
111
#include <texteditor/fontsettings.h>
112
#include <texteditor/texteditorsettings.h>
hjk's avatar
hjk committed
113

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

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

hjk's avatar
hjk committed
140
#ifdef WITH_TESTS
141 142 143
#include <QTest>
#include <QSignalSpy>
#include <QTestEventLoop>
144 145 146 147

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

150 151
#endif // WITH_TESTS

152 153
#include <climits>

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

164 165 166 167 168 169 170 171
/*!
    \namespace Debugger
    Debugger plugin namespace
*/

/*!
    \namespace Debugger::Internal
    Internal namespace of the Debugger plugin
172
    \internal
173 174 175 176 177
*/

/*!
    \class Debugger::DebuggerEngine

178
    \brief The DebuggerEngine class is the base class of a debugger engine.
179

Leena Miettinen's avatar
Leena Miettinen committed
180
    \note The Debugger process itself and any helper processes like
181 182
    gdbserver are referred to as 'Engine', whereas the debugged process
    is referred to as 'Inferior'.
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

    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}            +        +                                       +
           +             +        +                                       +
281
            +            +        +                                       +
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
             +           +        +                                       +
            InferiorShutdownOk InferiorShutdownFailed                     +
                      *          *                                        +
                  EngineShutdownRequested                                 +
                            +                                             +
           (calls *Engine->shutdownEngine())  <+-+-+-+-+-+-+-+-+-+-+-+-+-+'
                         |        |
                         |        |
                    {notify-   {notify-
                     Engine-    Engine-
                  ShutdownOk}  ShutdownFailed}
                         +       +
            EngineShutdownOk  EngineShutdownFailed
                         *       *
                     DebuggerFinished

\endcode */
hjk's avatar
hjk committed
299

300 301 302
/* 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
303

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


344 345
/*!
    \class Debugger::Internal::GdbEngine
346 347
    \brief The GdbEngine class implements Debugger::Engine driving a GDB
    executable.
348 349 350

    GdbEngine specific startup. All happens in EngineSetupRequested state:

Leena Miettinen's avatar
Leena Miettinen committed
351 352
    \list
        \li Transitions marked by '---' are done in the individual adapters.
353

Leena Miettinen's avatar
Leena Miettinen committed
354 355
        \li Transitions marked by '+-+' are done in the GdbEngine.
    \endlist
356 357 358 359 360 361 362 363 364 365 366 367 368

    \code
                  GdbEngine::setupEngine()
                          +
            (calls *Adapter->startAdapter())
                          |      |
                          |      `---> handleAdapterStartFailed()
                          |                   +
                          |             {notifyEngineSetupFailed}
                          |
                 handleAdapterStarted()
                          +
                 {notifyEngineSetupOk}
369 370 371



372 373 374 375 376 377 378 379 380 381 382
                GdbEngine::setupInferior()
                          +
            (calls *Adapter->prepareInferior())
                          |      |
                          |      `---> handlePrepareInferiorFailed()
                          |                   +
                          |             {notifyInferiorSetupFailed}
                          |
                handleInferiorPrepared()
                          +
                {notifyInferiorSetupOk}
383

384
\endcode */
385

con's avatar
con committed
386
using namespace Core;
hjk's avatar
hjk committed
387
using namespace Debugger::Constants;
388
using namespace Debugger::Internal;
389
using namespace ExtensionSystem;
con's avatar
con committed
390
using namespace ProjectExplorer;
hjk's avatar
hjk committed
391
using namespace TextEditor;
392
using namespace Utils;
con's avatar
con committed
393

hjk's avatar
hjk committed
394 395 396
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
397 398

namespace Debugger {
399 400
namespace Internal {

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

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


412 413 414
} // namespace Internal
} // namespace Debugger

415 416
Q_DECLARE_METATYPE(Debugger::Internal::TestCallBack)

417 418 419
namespace Debugger {
namespace Internal {

420
void addCdbOptionPages(QList<IOptionsPage*> *opts);
421
void addGdbOptionPages(QList<IOptionsPage*> *opts);
422
QObject *createDebuggerRunControlFactory(QObject *parent);
423

424 425 426 427 428 429 430
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

431
static void setProxyAction(ProxyAction *proxy, Id id)
432
{
hjk's avatar
hjk committed
433
    proxy->setAction(ActionManager::command(id)->action());
434 435
}

436
static QToolButton *toolButton(Id id)
437
{
hjk's avatar
hjk committed
438
    return toolButton(ActionManager::command(id)->action());
439 440
}

441 442 443 444 445 446 447 448 449
///////////////////////////////////////////////////////////////////////
//
// DummyEngine
//
///////////////////////////////////////////////////////////////////////

class DummyEngine : public DebuggerEngine
{
public:
450
    DummyEngine() : DebuggerEngine(DebuggerRunParameters()) {}
451 452 453 454 455 456 457
    ~DummyEngine() {}

    void setupEngine() {}
    void setupInferior() {}
    void runEngine() {}
    void shutdownEngine() {}
    void shutdownInferior() {}
458
    bool hasCapability(unsigned cap) const;
459
    bool acceptsBreakpoint(Breakpoint) const { return false; }
460
    bool acceptsDebuggerCommands() const { return false; }
hjk's avatar
hjk committed
461
    void selectThread(ThreadId) {}
462 463
};

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

    // This is a Qml or unknown engine.
483
    return cap & AddWatcherCapability;
484 485
}

486 487 488 489 490 491
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

492
class DebugMode : public IMode
hjk's avatar
hjk committed
493 494
{
public:
495 496 497
    DebugMode()
    {
        setObjectName(QLatin1String("DebugMode"));
498
        setContext(Context(C_DEBUGMODE, CC::C_NAVIGATION_PANE));
499
        setDisplayName(DebuggerPlugin::tr("Debug"));
500 501
        setIcon(Utils::Icon::modeIcon(Icons::MODE_DEBUGGER_CLASSIC,
                                      Icons::MODE_DEBUGGER_FLAT, Icons::MODE_DEBUGGER_FLAT_ACTIVE));
502
        setPriority(85);
503
        setId(MODE_DEBUG);
504
    }
hjk's avatar
hjk committed
505

hjk's avatar
hjk committed
506 507 508 509
    ~DebugMode()
    {
        delete m_widget;
    }
510
};
hjk's avatar
hjk committed
511

512 513 514 515 516 517
///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

518
static QWidget *addSearch(BaseTreeView *treeView, const QString &title,
519
    const char *objectName)
520
{
hjk's avatar
hjk committed
521
    QAction *act = action(UseAlternatingRowColors);
522
    treeView->setAlternatingRowColors(act->isChecked());
523 524
    QObject::connect(act, &QAction::toggled,
                     treeView, &BaseTreeView::setAlternatingRowColorsHelper);
525

Daniel Teske's avatar
Daniel Teske committed
526
    QWidget *widget = ItemViewFind::createSearchableWrapper(treeView);
527 528 529 530 531
    widget->setObjectName(QLatin1String(objectName));
    widget->setWindowTitle(title);
    return widget;
}

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

547 548 549 550 551 552 553
// 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;
554
    }
555 556
    return KitManager::find(cdbMatcher());
}
557

558 559
///////////////////////////////////////////////////////////////////////
//
560
// DebuggerPluginPrivate
561 562
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
563

564
static DebuggerPluginPrivate *dd = 0;
con's avatar
con committed
565

566 567 568 569 570 571 572 573 574 575 576 577 578 579
/*!
    \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.
*/

580
class DebuggerPluginPrivate : public QObject
581 582
{
    Q_OBJECT
583

584 585
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
586
    ~DebuggerPluginPrivate();
587

588
    bool initialize(const QStringList &arguments, QString *errorMessage);
589 590 591
    void extensionsInitialized();
    void aboutToShutdown();

592
    void connectEngine(DebuggerEngine *engine);
hjk's avatar
hjk committed
593
    void disconnectEngine() { connectEngine(0); }
594
    DebuggerEngine *dummyEngine();
595

hjk's avatar
hjk committed
596
    void setThreadBoxContents(const QStringList &list, int index)
597 598 599 600 601 602 603 604
    {
        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);
    }
605 606

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

608 609 610 611 612 613
    void writeSettings()
    {
        m_debuggerSettings->writeSettings();
        m_mainWindow->writeSettings();
    }

614 615
    void selectThread(int index)
    {
hjk's avatar
hjk committed
616 617
        ThreadId id = m_currentEngine->threadsHandler()->threadAt(index);
        m_currentEngine->selectThread(id);
618
    }
619

620
    void breakpointSetMarginActionTriggered(bool isMessageOnly, const ContextData &data)
621
    {
622
        QString message;
623
        if (isMessageOnly) {
624
            if (data.type == LocationByAddress) {
625 626 627 628
                //: Message tracepoint: Address hit.
                message = tr("0x%1 hit").arg(data.address, 0, 16);
            } else {
                //: Message tracepoint: %1 file, %2 line %3 function hit.
629
                message = tr("%1:%2 %3() hit").arg(FileName::fromString(data.fileName).fileName()).
630 631 632 633 634
                        arg(data.lineNumber).
                        arg(cppFunctionAt(data.fileName, data.lineNumber));
            }
            QInputDialog dialog; // Create wide input dialog.
            dialog.setWindowFlags(dialog.windowFlags()
hjk's avatar
hjk committed
635
              & ~(Qt::WindowContextHelpButtonHint|Qt::MSWindowsFixedSizeDialogHint));
636 637 638 639 640 641 642 643
            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();
        }
644
        toggleBreakpoint(data, message);
645
    }
646

647
    void updateWatchersHeader(int section, int, int newSize)
648
    {
649 650
        m_watchersView->header()->resizeSection(section, newSize);
        m_returnView->header()->resizeSection(section, newSize);
651
    }
652

653
    void sourceFilesDockToggled(bool on)
654
    {
655
        if (on && m_currentEngine->state() == InferiorStopOk)
656 657 658
            m_currentEngine->reloadSourceFiles();
    }

659
    void modulesDockToggled(bool on)
660
    {
661
        if (on && m_currentEngine->state() == InferiorStopOk)
662 663
            m_currentEngine->reloadModules();
    }
664

hjk's avatar
hjk committed
665
    void registerDockToggled(bool on)
666
    {
667
        if (on && m_currentEngine->state() == InferiorStopOk)
668 669
            m_currentEngine->reloadRegisters();
    }
670

671 672
    void synchronizeBreakpoints()
    {
673
        showMessage(QLatin1String("ATTEMPT SYNC"), LogDebug);
674
        for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
675
            if (DebuggerEngine *engine = m_snapshotHandler->at(i))
676 677 678 679
                engine->attemptBreakpointSynchronization();
        }
    }

680 681
    void editorOpened(IEditor *editor);
    void updateBreakMenuItem(IEditor *editor);
682
    void setBusyCursor(bool busy);
683 684 685
    void requestMark(TextEditorWidget *widget, int lineNumber,
                     TextMarkRequestKind kind);
    void requestContextMenu(TextEditorWidget *widget,
686
                            int lineNumber, QMenu *menu);
687

688 689
    void activatePreviousMode();
    void activateDebugMode();
690 691
    void toggleBreakpointHelper();
    void toggleBreakpoint(const ContextData &location, const QString &tracePointMessage = QString());
692
    void onModeChanged(IMode *mode);
693
    void onCoreAboutToOpen();
694
    void updateDebugWithoutDeployMenu();
695

696
    void startAndDebugApplication();
697
    void startRemoteCdbSession();
698
    void startRemoteServerAndAttachToProcess();
699
    void attachToRemoteServer();
hjk's avatar
hjk committed
700
    void attachToRunningApplication();
701
    void attachToUnstartedApplicationDialog();
702
    void attachToQmlPort();
hjk's avatar
hjk committed
703
    Q_SLOT void runScheduled();
704
    void attachCore();
705

706
    void enableReverseDebuggingTriggered(const QVariant &value);
707
    void showStatusMessage(const QString &msg, int timeout = -1);
708

709 710
    void runControlStarted(DebuggerEngine *engine);
    void runControlFinished(DebuggerEngine *engine);
711
    void remoteCommand(const QStringList &options);
712

713
    void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
714 715 716

    void dumpLog();
    void cleanupViews();
717
    void setInitialState();
718

719
    void fontSettingsChanged(const FontSettings &settings);
720 721

    void updateState(DebuggerEngine *engine);
722
    void onCurrentProjectChanged(Project *project);
723 724 725 726

    void sessionLoaded();
    void aboutToUnloadSession();
    void aboutToSaveSession();
727

728
    void coreShutdown();
729

hjk's avatar
hjk committed
730 731
#ifdef WITH_TESTS
public slots:
732
    void testLoadProject(const QString &proFile, const TestCallBack &cb);
733
    void testProjectLoaded(Project *project);
734 735
    void testProjectEvaluated();
    void testProjectBuilt(bool success);
736 737 738
    void testUnloadProject();
    void testFinished();

739
    void testRunProject(const DebuggerRunParameters &sp, const TestCallBack &cb);
hjk's avatar
hjk committed
740
    void testRunControlFinished();
741

hjk's avatar
hjk committed
742 743 744
//    void testStateMachine1();
//    void testStateMachine2();
//    void testStateMachine3();
745

746 747
    void testBenchmark1();

748
public:
hjk's avatar
hjk committed
749
    Project *m_testProject;
750 751 752
    bool m_testSuccess;
    QList<TestCallBack> m_testCallbacks;

hjk's avatar
hjk committed
753 754
#endif

hjk's avatar
hjk committed
755
public slots:
756
    void updateDebugActions();
757 758 759

    void handleExecDetach()
    {
760
        currentEngine()->resetLocation();
761 762 763 764 765
        currentEngine()->detachDebugger();
    }

    void handleExecContinue()
    {
766
        currentEngine()->resetLocation();
767 768 769 770 771
        currentEngine()->continueInferior();
    }

    void handleExecInterrupt()
    {
772
        currentEngine()->resetLocation();
773 774 775
        currentEngine()->requestInterruptInferior();
    }

776
    void handleAbort()
777
    {
778
        currentEngine()->resetLocation();
779
        currentEngine()->abortDebugger();
780
    }
hjk's avatar
hjk committed
781

782 783 784 785 786 787
    void handleReset()
    {
        currentEngine()->resetLocation();
        currentEngine()->resetInferior();
    }

hjk's avatar
hjk committed
788 789
    void handleExecStep()
    {
790
        if (currentEngine()->state() == DebuggerNotReady) {
791
            ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN);
792 793 794 795 796 797 798
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeStepI();
            else
                currentEngine()->executeStep();
        }
hjk's avatar
hjk committed
799 800 801 802
    }

    void handleExecNext()
    {
803
        if (currentEngine()->state() == DebuggerNotReady) {
804
            ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN);
805 806 807 808 809 810 811
        } else {
            currentEngine()->resetLocation();
            if (boolSetting(OperateByInstruction))
                currentEngine()->executeNextI();
            else
                currentEngine()->executeNext();
        }
hjk's avatar
hjk committed
812 813
    }

814 815
    void handleExecStepOut()
    {
816
        currentEngine()->resetLocation();
817 818 819 820 821
        currentEngine()->executeStepOut();
    }

    void handleExecReturn()
    {
822
        currentEngine()->resetLocation();
823 824
        currentEngine()->executeReturn();
    }
hjk's avatar
hjk committed
825 826 827

    void handleExecJumpToLine()
    {
828
        currentEngine()->resetLocation();
829 830 831 832 833 834
        if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
            ContextData location = getLocationContext(textEditor->textDocument(),
                                                      textEditor->currentLine());
            if (location.isValid())
                currentEngine()->executeJumpToLine(location);
        }
hjk's avatar
hjk committed
835 836 837 838
    }

    void handleExecRunToLine()
    {
839
        currentEngine()->resetLocation();
840 841 842 843 844 845
        if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
            ContextData location = getLocationContext(textEditor->textDocument(),
                                                      textEditor->currentLine());
            if (location.isValid())
                currentEngine()->executeRunToLine(location);
        }
hjk's avatar
hjk committed
846 847
    }

848
    void handleExecRunToSelectedFunction()
hjk's avatar
hjk committed
849
    {
850
        BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
851
        QTC_ASSERT(textEditor, return);
852
        QTextCursor cursor = textEditor->textCursor();
853 854 855 856
        QString functionName = cursor.selectedText();
        if (functionName.isEmpty()) {
            const QTextBlock block = cursor.block();
            const QString line = block.text();
857
            foreach (const QString &str, line.trimmed().split(QLatin1Char('('))) {
858 859 860 861 862 863 864 865 866 867 868 869 870
                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;
                }
            }
        }

871 872 873 874 875 876
        if (functionName.isEmpty()) {
            showStatusMessage(tr("No function selected."));
        } else {
            showStatusMessage(tr("Running to function \"%1\".")
                .arg(functionName));
            currentEngine()->resetLocation();
877
            currentEngine()->executeRunToFunction(functionName);
878
        }
hjk's avatar
hjk committed
879 880 881 882 883
    }

    void handleAddToWatchWindow()
    {
        // Requires a selection, but that's the only case we want anyway.
884
        BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
hjk's avatar
hjk committed
885 886
        if (!textEditor)
            return;
887
        QTextCursor tc = textEditor->textCursor();
hjk's avatar
hjk committed
888 889 890 891 892
        QString exp;
        if (tc.hasSelection()) {
            exp = tc.selectedText();
        } else {
            int line, column;
893
            exp = cppExpressionAt(textEditor->editorWidget(), tc.position(), &line, &column);
hjk's avatar
hjk committed
894
        }
895 896 897 898
        if (currentEngine()->hasCapability(WatchComplexExpressionsCapability))
            exp = removeObviousSideEffects(exp);
        else
            exp = fixCppExpression(exp);
899
        exp = exp.trimmed();
hjk's avatar
hjk committed
900 901
        if (exp.isEmpty())
            return;
902
        currentEngine()->watchHandler()->watchVariable(exp);
hjk's avatar
hjk committed
903 904 905 906
    }

    void handleExecExit()
    {
907
        currentEngine()->exitDebugger();
hjk's avatar
hjk committed
908 909 910 911 912 913 914 915 916 917 918 919
    }

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

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

920
    void handleOperateByInstructionTriggered(bool operateByInstructionTriggered)
hjk's avatar
hjk committed
921
    {
922
        // Go to source only if we have the file.
923 924 925 926 927 928
        if (DebuggerEngine *cppEngine = currentEngine()->cppEngine()) {
            if (cppEngine->stackHandler()->currentIndex() >= 0) {
                const StackFrame frame = cppEngine->stackHandler()->currentFrame();
                if (operateByInstructionTriggered || frame.isUsable())
                    cppEngine->gotoLocation(Location(frame, true));
            }
Friedemann Kleint's avatar