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
        }