debuggerplugin.cpp 94.8 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
** Commercial Usage
10
**
11 12 13 14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18 19 20 21 22 23
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

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

32
#include "debuggeractions.h"
33
#include "debuggeragents.h"
con's avatar
con committed
34
#include "debuggerconstants.h"
35 36 37 38 39
#include "debuggerdialogs.h"
#include "debuggerengine.h"
#include "debuggermainwindow.h"
#include "debuggeroutputwindow.h"
#include "debuggerplugin.h"
con's avatar
con committed
40
#include "debuggerrunner.h"
41
#include "debuggerstringutils.h"
42
#include "debuggertooltip.h"
43
#include "debuggeruiswitcher.h"
44 45 46 47 48 49 50 51 52 53 54

#include "breakwindow.h"
#include "moduleswindow.h"
#include "registerwindow.h"
#include "snapshotwindow.h"
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
#include "watchwindow.h"

#include "watchutils.h"
55
#include "breakhandler.h"
56 57
#include "stackhandler.h"
#include "watchhandler.h"
58 59 60 61 62

#ifdef Q_OS_WIN
#  include "shared/peutils.h"
#endif

con's avatar
con committed
63

64
#include "ui_commonoptionspage.h"
hjk's avatar
hjk committed
65
#include "ui_dumperoptionpage.h"
66

67
#include <coreplugin/actionmanager/actionmanager.h>
68 69
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
hjk's avatar
hjk committed
70
#include <coreplugin/basemode.h>
con's avatar
con committed
71
#include <coreplugin/coreconstants.h>
72
#include <coreplugin/dialogs/ioptionspage.h>
con's avatar
con committed
73
#include <coreplugin/editormanager/editormanager.h>
hjk's avatar
hjk committed
74
#include <coreplugin/findplaceholder.h>
75
#include <coreplugin/icontext.h>
con's avatar
con committed
76
#include <coreplugin/icore.h>
77
#include <coreplugin/icorelistener.h>
78
#include <coreplugin/manhattanstyle.h>
con's avatar
con committed
79
#include <coreplugin/messagemanager.h>
hjk's avatar
hjk committed
80
#include <coreplugin/minisplitter.h>
con's avatar
con committed
81
#include <coreplugin/modemanager.h>
hjk's avatar
hjk committed
82 83 84
#include <coreplugin/navigationwidget.h>
#include <coreplugin/outputpane.h>
#include <coreplugin/rightpane.h>
hjk's avatar
hjk committed
85

con's avatar
con committed
86
#include <cplusplus/ExpressionUnderCursor.h>
87
#include <cplusplus/CppDocument.h>
hjk's avatar
hjk committed
88

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

92 93
#include <extensionsystem/pluginmanager.h>

94
#include <projectexplorer/project.h>
95
#include <projectexplorer/projectexplorer.h>
con's avatar
con committed
96 97
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
98
#include <projectexplorer/toolchain.h>
hjk's avatar
hjk committed
99 100

#include <texteditor/basetexteditor.h>
con's avatar
con committed
101
#include <texteditor/basetextmark.h>
102
#include <texteditor/fontsettings.h>
con's avatar
con committed
103 104
#include <texteditor/itexteditor.h>
#include <texteditor/texteditorconstants.h>
105
#include <texteditor/texteditorsettings.h>
hjk's avatar
hjk committed
106

107 108
//#include <qt4projectmanager/qt4projectmanagerconstants.h>

hjk's avatar
hjk committed
109
#include <utils/qtcassert.h>
110
#include <utils/savedaction.h>
111
#include <utils/styledbar.h>
con's avatar
con committed
112

113
#include <QtCore/QCoreApplication>
con's avatar
con committed
114
#include <QtCore/QDebug>
115 116
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
con's avatar
con committed
117 118 119
#include <QtCore/QObject>
#include <QtCore/QPoint>
#include <QtCore/QSettings>
120 121
#include <QtCore/QTextStream>
#include <QtCore/QTime>
122
#include <QtCore/QTimer>
123
#include <QtCore/QVariant>
124
#include <QtCore/QtPlugin>
hjk's avatar
hjk committed
125

126 127 128 129
#include <QtGui/QAbstractItemView>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QComboBox>
130
#include <QtGui/QDockWidget>
131 132 133 134 135 136 137
#include <QtGui/QErrorMessage>
#include <QtGui/QFileDialog>
#include <QtGui/QHeaderView>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <QtGui/QMenu>
#include <QtGui/QMessageBox>
con's avatar
con committed
138
#include <QtGui/QPlainTextEdit>
139 140
#include <QtGui/QPushButton>
#include <QtGui/QStatusBar>
con's avatar
con committed
141 142
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
143
#include <QtGui/QToolButton>
144 145
#include <QtGui/QToolTip>
#include <QtGui/QTreeWidget>
con's avatar
con committed
146

147 148
#include <climits>

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

// Note: the Debugger process itself and any helper processes like
160
// gdbserver, the trk client etc are referred to as 'Engine',
161 162
// whereas the debugged process is referred to as 'Inferior'.
//
163 164
// Transitions marked by '---' are done in the individual engines.
// Transitions marked by '+-+' are done in the base DebuggerEngine.
hjk's avatar
hjk committed
165
// The GdbEngine->setupEngine() function is described in more detail below.
166 167 168 169
//
//                   DebuggerNotReady
//                          +
//                          +
170
//                    EngineSettingUp
171 172
//                          +
//                          +
hjk's avatar
hjk committed
173 174 175 176 177
//            (calls *Engine->setupEngine())
//                          |      |
//                     {notify-  {notify-
//                      Engine-   Engine-
//                      StartOk}  StartFailed}
178
//                          |      |
179
//                          |      `---> EngineSetupFailed
180 181 182 183 184
//                          |                   +
//                          |    [calls RunControl->startFailed]
//                          |                   +
//                          |             DebuggerNotReady
//                          v
185
//                    EngineSetupOk
186 187 188
//                          +
//           [calls RunControl->StartSuccessful]
//                          +
hjk's avatar
hjk committed
189 190 191 192 193
//            (calls *Engine->setupInferior())
//                          |       |
//                     {notify-   {notify-
//                      Inferior- Inferior-
//                      SetupOk}  SetupFailed}
194
//                          |       |
hjk's avatar
hjk committed
195
//                          |       ` ----> InferiorSetupFailed +-+-+-+->.
196 197
//                          |                                            +
//                          v                                            +
hjk's avatar
hjk committed
198 199 200
//                   InferiorSetupOk                                     +
//                          +                                            +
//            (calls *Engine->runEngine())                               +
201 202 203 204 205 206 207 208 209 210 211 212 213 214
//                          |                                            +
//         (core)           |     (attach) (term) (remote) (script)      +
//      .-----------------<-|->------------------.                       +
//      |                   v                    |                       +
//  InferiorUnrunnable      | (plain)            |                       +
//      |                   | (trk)              |                       +
//      |                   |                    |                       +
//      |    .--> InferiorRunningRequested       |                       +
//      |    |              |                    |                       +
//      |    |       InferiorRunning             |                       +
//      |    |              |                    |                       +
//      |    |       InferiorStopping            |                       +
//      |    |              |                    |                       +
//      |    '------ InferiorStopped <-----------'                       +
215
//      |                   |                                            v
216 217 218 219 220
//      |          InferiorShuttingDown  ->  InferiorShutdownFailed ---->+
//      |                   |                                            +
//      |            InferiorShutDown                                    +
//      |                   |                                            +
//      '-------->  EngineShuttingDown  <-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
221
//                          |
222 223 224
//                   DebuggerNotReady
//

225
// GdbEngine specific startup. All happens in EngineSettingUp state
226
//
227 228 229
// Transitions marked by '---' are done in the individual adapters.
// Transitions marked by '+-+' are done in the GdbEngine.

hjk's avatar
hjk committed
230
//                  GdbEngine::setupEngine()
231 232 233 234 235 236
//                          +
//                          +
//            (calls *Adapter->startAdapter())
//                          |      |
//                          |      `---> handleAdapterStartFailed()
//                          |                   +
237
//                          |             EngineSetupFailed
238 239 240 241 242 243 244
//                          |
//                 handleAdapterStarted()
//                          +
//            (calls *Adapter->prepareInferior())
//                          |      |
//                          |      `---> handleAdapterStartFailed()
//                          |                   +
245
//                          |             EngineSetupFailed
246 247 248
//                          |
//                 handleInferiorPrepared()
//                          +
249
//                     EngineSetupOk
250 251 252 253




254

con's avatar
con committed
255
using namespace Core;
256
using namespace Debugger;
hjk's avatar
hjk committed
257 258
using namespace Debugger::Constants;
using namespace Debugger::Internal;
con's avatar
con committed
259
using namespace ProjectExplorer;
hjk's avatar
hjk committed
260
using namespace TextEditor;
con's avatar
con committed
261

hjk's avatar
hjk committed
262 263 264
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
265 266 267 268

namespace Debugger {
namespace Constants {

269 270
const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebugging";

con's avatar
con committed
271 272
const char * const STARTEXTERNAL        = "Debugger.StartExternal";
const char * const ATTACHEXTERNAL       = "Debugger.AttachExternal";
273
const char * const ATTACHCORE           = "Debugger.AttachCore";
hjk's avatar
hjk committed
274
const char * const ATTACHTCF            = "Debugger.AttachTcf";
275
const char * const ATTACHREMOTE         = "Debugger.AttachRemote";
276
const char * const DETACH               = "Debugger.Detach";
con's avatar
con committed
277

278 279
const char * const RUN_TO_LINE1         = "Debugger.RunToLine1";
const char * const RUN_TO_LINE2         = "Debugger.RunToLine2";
con's avatar
con committed
280
const char * const RUN_TO_FUNCTION      = "Debugger.RunToFunction";
281 282
const char * const JUMP_TO_LINE1        = "Debugger.JumpToLine1";
const char * const JUMP_TO_LINE2        = "Debugger.JumpToLine2";
283
const char * const RETURN_FROM_FUNCTION = "Debugger.ReturnFromFunction";
284
const char * const SNAPSHOT             = "Debugger.Snapshot";
con's avatar
con committed
285 286 287
const char * const TOGGLE_BREAK         = "Debugger.ToggleBreak";
const char * const BREAK_BY_FUNCTION    = "Debugger.BreakByFunction";
const char * const BREAK_AT_MAIN        = "Debugger.BreakAtMain";
288 289
const char * const ADD_TO_WATCH1        = "Debugger.AddToWatch1";
const char * const ADD_TO_WATCH2        = "Debugger.AddToWatch2";
290
const char * const OPERATE_BY_INSTRUCTION  = "Debugger.OperateByInstruction";
291 292
const char * const FRAME_UP             = "Debugger.FrameUp";
const char * const FRAME_DOWN           = "Debugger.FrameDown";
con's avatar
con committed
293

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
294
#ifdef Q_WS_MAC
con's avatar
con committed
295 296 297 298 299
const char * const INTERRUPT_KEY            = "Shift+F5";
const char * const RESET_KEY                = "Ctrl+Shift+F5";
const char * const STEP_KEY                 = "F7";
const char * const STEPOUT_KEY              = "Shift+F7";
const char * const NEXT_KEY                 = "F6";
300
const char * const REVERSE_KEY              = "";
con's avatar
con committed
301 302
const char * const RUN_TO_LINE_KEY          = "Shift+F8";
const char * const RUN_TO_FUNCTION_KEY      = "Ctrl+F6";
303
const char * const JUMP_TO_LINE_KEY         = "Ctrl+D,Ctrl+L";
con's avatar
con committed
304
const char * const TOGGLE_BREAK_KEY         = "F8";
305 306 307 308
const char * const BREAK_BY_FUNCTION_KEY    = "Ctrl+D,Ctrl+F";
const char * const BREAK_AT_MAIN_KEY        = "Ctrl+D,Ctrl+M";
const char * const ADD_TO_WATCH_KEY         = "Ctrl+D,Ctrl+W";
const char * const SNAPSHOT_KEY             = "Ctrl+D,Ctrl+S";
con's avatar
con committed
309 310 311 312 313 314
#else
const char * const INTERRUPT_KEY            = "Shift+F5";
const char * const RESET_KEY                = "Ctrl+Shift+F5";
const char * const STEP_KEY                 = "F11";
const char * const STEPOUT_KEY              = "Shift+F11";
const char * const NEXT_KEY                 = "F10";
315
const char * const REVERSE_KEY              = "F12";
con's avatar
con committed
316 317 318 319 320 321 322
const char * const RUN_TO_LINE_KEY          = "";
const char * const RUN_TO_FUNCTION_KEY      = "";
const char * const JUMP_TO_LINE_KEY         = "";
const char * const TOGGLE_BREAK_KEY         = "F9";
const char * const BREAK_BY_FUNCTION_KEY    = "";
const char * const BREAK_AT_MAIN_KEY        = "";
const char * const ADD_TO_WATCH_KEY         = "Ctrl+Alt+Q";
323
const char * const SNAPSHOT_KEY             = "Ctrl+D,Ctrl+S";
con's avatar
con committed
324 325 326 327 328 329
#endif

} // namespace Constants
} // namespace Debugger


330

331 332 333 334 335
static ProjectExplorer::SessionManager *sessionManager()
{
    return ProjectExplorer::ProjectExplorerPlugin::instance()->session();
}

336 337 338 339 340
static QSettings *settings()
{
    return ICore::instance()->settings();
}

341 342 343 344 345 346 347
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

348 349 350
namespace Debugger {
namespace Internal {

hjk's avatar
hjk committed
351 352
static const char *Role = "ROLE";

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
// 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.

void addGdbOptionPages(QList<Core::IOptionsPage*> *opts);
void addScriptOptionPages(QList<Core::IOptionsPage*> *opts);
void addTcfOptionPages(QList<Core::IOptionsPage*> *opts);
#ifdef CDB_ENABLED
void addCdbOptionPages(QList<Core::IOptionsPage*> *opts);
#endif


struct AttachRemoteParameters
{
    AttachRemoteParameters() : attachPid(0), winCrashEvent(0) {}

    quint64 attachPid;
    QString attachCore;
    // Event handle for attaching to crashed Windows processes.
    quint64 winCrashEvent;
};


378 379 380 381 382 383
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
384 385 386
class DebugMode : public Core::BaseMode
{
public:
387 388
    DebugMode(QObject *parent = 0) : BaseMode(parent)
    {
389
        setDisplayName(QCoreApplication::translate("Debugger::Internal::DebugMode", "Debug"));
390 391 392 393
        setId(MODE_DEBUG);
        setIcon(QIcon(":/fancyactionbar/images/mode_Debug.png"));
        setPriority(P_MODE_DEBUG);
    }
hjk's avatar
hjk committed
394

395 396 397 398 399 400
    ~DebugMode()
    {
        // Make sure the editor manager does not get deleted.
        EditorManager::instance()->setParent(0);
    }
};
hjk's avatar
hjk committed
401 402


403 404 405 406 407 408
///////////////////////////////////////////////////////////////////////
//
// DebuggerListener: Close the debugging session if running.
//
///////////////////////////////////////////////////////////////////////

409 410
class DebuggerListener : public Core::ICoreListener
{
411
public:
hjk's avatar
hjk committed
412
    DebuggerListener() {}
413 414 415
    virtual bool coreAboutToClose();
};

hjk's avatar
hjk committed
416

con's avatar
con committed
417 418 419 420 421 422
///////////////////////////////////////////////////////////////////////
//
// LocationMark
//
///////////////////////////////////////////////////////////////////////

423
// Used in "real" editors
424
class LocationMark : public TextEditor::BaseTextMark
con's avatar
con committed
425 426 427 428
{
public:
    LocationMark(const QString &fileName, int linenumber)
        : BaseTextMark(fileName, linenumber)
429
    {}
con's avatar
con committed
430

431
    QIcon icon() const { return DebuggerPlugin::instance()->locationMarkIcon(); }
con's avatar
con committed
432 433
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
434
    void removedFromEditor() {}
con's avatar
con committed
435 436
};

437 438 439

///////////////////////////////////////////////////////////////////////
//
440
// CommonOptionsPage
441 442 443
//
///////////////////////////////////////////////////////////////////////

444
class CommonOptionsPage : public Core::IOptionsPage
445 446
{
public:
447
    CommonOptionsPage() {}
448 449

    // IOptionsPage
450
    QString id() const
hjk's avatar
hjk committed
451
        { return _(DEBUGGER_COMMON_SETTINGS_ID); }
452
    QString displayName() const
hjk's avatar
hjk committed
453
        { return QCoreApplication::translate("Debugger", DEBUGGER_COMMON_SETTINGS_NAME); }
454
    QString category() const
hjk's avatar
hjk committed
455
        { return _(DEBUGGER_SETTINGS_CATEGORY);  }
456
    QString displayCategory() const
hjk's avatar
hjk committed
457
        { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
458 459
    QIcon categoryIcon() const
        { return QIcon(QLatin1String(DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); }
460 461

    QWidget *createPage(QWidget *parent);
462
    void apply() { m_group.apply(settings()); }
463
    void finish() { m_group.finish(); }
464
    virtual bool matches(const QString &s) const;
465 466

private:
467
    Ui::CommonOptionsPage m_ui;
468
    Utils::SavedActionSet m_group;
469
    QString m_searchKeywords;
470 471
};

472
QWidget *CommonOptionsPage::createPage(QWidget *parent)
473 474 475
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);
476
    m_group.clear();
477

478 479 480
    m_group.insert(theDebuggerAction(SwitchLanguageAutomatically),
        m_ui.checkBoxChangeLanguageAutomatically);

481
    m_group.insert(theDebuggerAction(ListSourceFiles),
482
        m_ui.checkBoxListSourceFiles);
483
    m_group.insert(theDebuggerAction(UseAlternatingRowColors),
484
        m_ui.checkBoxUseAlternatingRowColors);
485
    m_group.insert(theDebuggerAction(UseToolTipsInMainEditor),
486
        m_ui.checkBoxUseToolTipsInMainEditor);
487
    m_group.insert(theDebuggerAction(AutoDerefPointers), 0);
488 489 490 491
    m_group.insert(theDebuggerAction(UseToolTipsInLocalsView), 0);
    m_group.insert(theDebuggerAction(UseToolTipsInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInStackView), 0);
492
    m_group.insert(theDebuggerAction(MaximalStackDepth),
493
        m_ui.spinBoxMaximalStackDepth);
494 495
    m_group.insert(theDebuggerAction(ShowStdNamespace), 0);
    m_group.insert(theDebuggerAction(ShowQtNamespace), 0);
496
    m_group.insert(theDebuggerAction(LogTimeStamps), 0);
497
    m_group.insert(theDebuggerAction(VerboseLog), 0);
498
    m_group.insert(theDebuggerAction(UsePreciseBreakpoints), 0);
499 500
    m_group.insert(theDebuggerAction(BreakOnThrow), 0);
    m_group.insert(theDebuggerAction(BreakOnCatch), 0);
501 502 503 504 505 506 507
#ifdef Q_OS_WIN
    Utils::SavedAction *registerAction = theDebuggerAction(RegisterForPostMortem);
    m_group.insert(registerAction,
        m_ui.checkBoxRegisterForPostMortem);
    connect(registerAction, SIGNAL(toggled(bool)),
            m_ui.checkBoxRegisterForPostMortem, SLOT(setChecked(bool)));
#endif
508

509
    if (m_searchKeywords.isEmpty()) {
510 511 512
        QTextStream(&m_searchKeywords) << ' '
                << m_ui.checkBoxChangeLanguageAutomatically->text()
                << m_ui.checkBoxListSourceFiles->text()
513 514
                << ' ' << m_ui.checkBoxUseAlternatingRowColors->text()
                << ' ' << m_ui.checkBoxUseToolTipsInMainEditor->text()
515 516 517
#ifdef Q_OS_WIN
                << ' ' << m_ui.checkBoxRegisterForPostMortem->text()
#endif
518 519 520
                << ' ' << m_ui.labelMaximalStackDepth->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
521 522 523
#ifndef Q_OS_WIN
    m_ui.checkBoxRegisterForPostMortem->setVisible(false);
#endif
524 525 526
    return w;
}

527 528 529 530 531
bool CommonOptionsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

hjk's avatar
hjk committed
532 533
///////////////////////////////////////////////////////////////////////
//
534
// DebuggingHelperOptionPage
hjk's avatar
hjk committed
535 536 537
//
///////////////////////////////////////////////////////////////////////

538 539 540
static inline bool oxygenStyle()
{
    if (const ManhattanStyle *ms = qobject_cast<const ManhattanStyle *>(qApp->style()))
541
        return !qstrcmp("OxygenStyle", ms->baseStyle()->metaObject()->className());
542 543 544
    return false;
}

545
class DebuggingHelperOptionPage : public Core::IOptionsPage
546 547
{   // Needs tr - context
    Q_OBJECT
hjk's avatar
hjk committed
548
public:
549
    DebuggingHelperOptionPage() {}
hjk's avatar
hjk committed
550 551

    // IOptionsPage
hjk's avatar
hjk committed
552
    QString id() const { return _("Z.DebuggingHelper"); }
553
    QString displayName() const { return tr("Debugging Helper"); }
hjk's avatar
hjk committed
554 555
    QString category() const { return _(DEBUGGER_SETTINGS_CATEGORY); }
    QString displayCategory() const { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
556
    QIcon categoryIcon() const { return QIcon(QLatin1String(DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); }
hjk's avatar
hjk committed
557 558

    QWidget *createPage(QWidget *parent);
559
    void apply() { m_group.apply(settings()); }
560
    void finish() { m_group.finish(); }
561
    virtual bool matches(const QString &s) const;
hjk's avatar
hjk committed
562 563

private:
564
    Ui::DebuggingHelperOptionPage m_ui;
565
    Utils::SavedActionSet m_group;
566
    QString m_searchKeywords;
hjk's avatar
hjk committed
567 568
};

569
QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent)
hjk's avatar
hjk committed
570 571 572 573
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);

574
    m_ui.dumperLocationChooser->setExpectedKind(Utils::PathChooser::Command);
575
    m_ui.dumperLocationChooser->setPromptDialogTitle(tr("Choose DebuggingHelper Location"));
hjk's avatar
hjk committed
576 577
    m_ui.dumperLocationChooser->setInitialBrowsePathBackup(
        Core::ICore::instance()->resourcePath() + "../../lib");
hjk's avatar
hjk committed
578

579
    m_group.clear();
580
    m_group.insert(theDebuggerAction(UseDebuggingHelpers),
581
        m_ui.debuggingHelperGroupBox);
582
    m_group.insert(theDebuggerAction(UseCustomDebuggingHelperLocation),
583
        m_ui.customLocationGroupBox);
hjk's avatar
hjk committed
584
    // Suppress Oxygen style's giving flat group boxes bold titles.
585
    if (oxygenStyle())
hjk's avatar
hjk committed
586
        m_ui.customLocationGroupBox->setStyleSheet(_("QGroupBox::title { font: ; }"));
587

588
    m_group.insert(theDebuggerAction(CustomDebuggingHelperLocation),
589
        m_ui.dumperLocationChooser);
hjk's avatar
hjk committed
590

591 592 593
    m_group.insert(theDebuggerAction(UseCodeModel),
        m_ui.checkBoxUseCodeModel);

594
#ifdef QT_DEBUG
595 596
    m_group.insert(theDebuggerAction(DebugDebuggingHelpers),
        m_ui.checkBoxDebugDebuggingHelpers);
597 598 599
#else
    m_ui.checkBoxDebugDebuggingHelpers->hide();
#endif
hjk's avatar
hjk committed
600 601 602 603

#ifndef QT_DEBUG
#if 0
    cmd = am->registerAction(m_manager->m_dumpLogAction,
hjk's avatar
hjk committed
604
        DUMP_LOG, globalcontext);
hjk's avatar
hjk committed
605 606 607 608 609 610
    //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+L")));
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F11")));
    mdebug->addAction(cmd);
#endif
#endif

611 612 613 614 615 616 617 618 619
    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords)
                << ' ' << m_ui.debuggingHelperGroupBox->title()
                << ' ' << m_ui.customLocationGroupBox->title()
                << ' ' << m_ui.dumperLocationLabel->text()
                << ' ' << m_ui.checkBoxUseCodeModel->text()
                << ' ' << m_ui.checkBoxDebugDebuggingHelpers->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
hjk's avatar
hjk committed
620 621 622
    return w;
}

623
bool DebuggingHelperOptionPage::matches(const QString &s) const
hjk's avatar
hjk committed
624
{
625
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
hjk's avatar
hjk committed
626 627
}

628

con's avatar
con committed
629 630
///////////////////////////////////////////////////////////////////////
//
631
// Argument parsing
con's avatar
con committed
632 633 634
//
///////////////////////////////////////////////////////////////////////

635
static QString msgParameterMissing(const QString &a)
636 637 638 639
{
    return DebuggerPlugin::tr("Option '%1' is missing the parameter.").arg(a);
}

640
static QString msgInvalidNumericParameter(const QString &a, const QString &number)
641 642 643 644
{
    return DebuggerPlugin::tr("The parameter '%1' of option '%2' is not a number.").arg(number, a);
}

645
static bool parseArgument(QStringList::const_iterator &it,
646 647 648
    const QStringList::const_iterator &cend,
    AttachRemoteParameters *attachRemoteParameters,
    unsigned *enabledEngines, QString *errorMessage)
649 650 651
{
    const QString &option = *it;
    // '-debug <pid>'
hjk's avatar
hjk committed
652
    if (*it == _("-debug")) {
653 654 655 656 657 658
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
659
        attachRemoteParameters->attachPid = it->toULongLong(&ok);
660
        if (!ok) {
661 662
            attachRemoteParameters->attachPid = 0;
            attachRemoteParameters->attachCore = *it;
663 664 665
        }
        return true;
    }
666 667
    // -wincrashevent <event-handle>. A handle used for
    // a handshake when attaching to a crashed Windows process.
hjk's avatar
hjk committed
668
    if (*it == _("-wincrashevent")) {
669 670 671 672 673 674
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
675
        attachRemoteParameters->winCrashEvent = it->toULongLong(&ok);
676 677 678 679 680 681
        if (!ok) {
            *errorMessage = msgInvalidNumericParameter(option, *it);
            return false;
        }
        return true;
    }
hjk's avatar
hjk committed
682
    // Engine disabling.
hjk's avatar
hjk committed
683
    if (option == _("-disable-cdb")) {
684
        *enabledEngines &= ~Debugger::CdbEngineType;
685 686
        return true;
    }
hjk's avatar
hjk committed
687
    if (option == _("-disable-gdb")) {
688
        *enabledEngines &= ~Debugger::GdbEngineType;
689 690
        return true;
    }
691 692 693 694
    if (option == _("-disable-qmldb")) {
        *enabledEngines &= ~Debugger::QmlEngineType;
        return true;
    }
hjk's avatar
hjk committed
695
    if (option == _("-disable-sdb")) {
696
        *enabledEngines &= ~Debugger::ScriptEngineType;
697 698
        return true;
    }
699
    if (option == _("-disable-tcf")) {
hjk's avatar
hjk committed
700 701 702
        *enabledEngines &= ~TcfEngineType;
        return true;
    }
703

704
    *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
705 706 707
    return false;
}

708
static bool parseArguments(const QStringList &args,
709
   AttachRemoteParameters *attachRemoteParameters,
hjk's avatar
hjk committed
710
   unsigned *enabledEngines, QString *errorMessage)
711 712 713
{
    const QStringList::const_iterator cend = args.constEnd();
    for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
714
        if (!parseArgument(it, cend, attachRemoteParameters, enabledEngines, errorMessage))
715 716
            return false;
    if (Debugger::Constants::Internal::debug)
717
        qDebug().nospace() << args << "engines=0x"
718 719 720
            << QString::number(*enabledEngines, 16)
            << " pid" << attachRemoteParameters->attachPid
            << " core" << attachRemoteParameters->attachCore << '\n';
721 722 723
    return true;
}

724 725 726 727 728 729 730 731

///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

static bool isDebuggable(Core::IEditor *editor)
732
{
733 734 735 736 737 738 739 740
    // Only blacklist Qml. Whitelisting would fail on C++ code in files
    // with strange names, more harm would be done this way.
    //Core::IFile *file = editor->file();
    //return !(file && file->mimeType() == "application/x-qml");

    // Nowadays, even Qml is debuggable.
    Q_UNUSED(editor);
    return true;
741 742
}

743
static TextEditor::ITextEditor *currentTextEditor()
con's avatar
con committed
744
{
745 746 747 748 749 750
    EditorManager *editorManager = EditorManager::instance();
    if (!editorManager)
        return 0;
    Core::IEditor *editor = editorManager->currentEditor();
    return qobject_cast<ITextEditor*>(editor);
}
con's avatar
con committed
751

752 753 754 755 756 757 758 759 760 761
static bool isCurrentProjectCppBased()
{
    Project *startupProject = ProjectExplorerPlugin::instance()->startupProject();
    if (!startupProject)
        return false;
    const QString id = startupProject->id();
    return id == _("GenericProjectManager.GenericProject")
        || id == _("CMakeProjectManager.CMakeProject")
        || id == _("Qt4ProjectManager.Qt4Project");
}
762

con's avatar
con committed
763

764 765
///////////////////////////////////////////////////////////////////////
//
766
// SessionEngine
767 768
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
769

770 771 772 773
// This class contains data serving as a template for debugger engines
// started during a session.

class SessionEngine : public DebuggerEngine
774 775
{
public:
776 777
    SessionEngine() : DebuggerEngine(DebuggerStartParameters()) {}

778 779
    bool isSessionEngine() const { return true; }

780 781 782 783 784 785 786 787 788 789 790 791
    void loadSessionData()
    {
        breakHandler()->loadSessionData();
        watchHandler()->loadSessionData();
    }

    void saveSessionData()
    {
        watchHandler()->saveSessionData();
        breakHandler()->saveSessionData();
    }

792
};
con's avatar
con committed
793 794


795 796 797 798 799
///////////////////////////////////////////////////////////////////////
//
// DebuggerPluginPrivate
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
800

801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
struct DebuggerActions
{
    QAction *continueAction;
    QAction *stopAction;
    QAction *resetAction; // FIXME: Should not be needed in a stable release
    QAction *stepAction;
    QAction *stepOutAction;
    QAction *runToLineAction1; // in the Debug menu
    QAction *runToLineAction2; // in the text editor context menu
    QAction *runToFunctionAction;
    QAction *jumpToLineAction1; // in the Debug menu
    QAction *jumpToLineAction2; // in the text editor context menu
    QAction *returnFromFunctionAction;
    QAction *nextAction;
    QAction *snapshotAction;
    QAction *watchAction1; // in the Debug menu
    QAction *watchAction2; // in the text editor context menu
    QAction *breakAction;
    QAction *sepAction;
    QAction *reverseDirectionAction;
    QAction *frameUpAction;
    QAction *frameDownAction;
};
con's avatar
con committed
824

825
} // namespace Internal
con's avatar
con committed
826

827
using namespace Debugger::Internal;
con's avatar
con committed
828

829 830 831 832 833
///////////////////////////////////////////////////////////////////////
//
// DebuggerPluginPrivate
//
///////////////////////////////////////////////////////////////////////
con's avatar
con committed
834

835 836 837
class DebuggerPluginPrivate : public QObject
{
    Q_OBJECT
838

839 840
public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);
841

842 843 844
    bool initialize(const QStringList &arguments, QString *errorMessage);
    void notifyCurrentEngine(int role, const QVariant &value = QVariant());
    void connectEngine(DebuggerEngine *engine);
845
    void disconnectEngine() { connectEngine(m_sessionEngine); }
846

847 848 849
public slots:
    void updateWatchersHeader(int section, int, int newSize)
        { m_watchersWindow->header()->resizeSection(section, newSize); }
850

851
    void sourceFilesDockToggled(bool on)
hjk's avatar
hjk committed
852
        { if (on) notifyCurrentEngine(RequestReloadSourceFilesRole); }
853
    void modulesDockToggled(bool on)
hjk's avatar
hjk committed
854 855 856
        { if (on) notifyCurrentEngine(RequestReloadModulesRole); }
    void registerDockToggled(bool on)
        { if (on) notifyCurrentEngine(RequestReloadRegistersRole); }
857

858 859
    void onAction();
    void setSimpleDockWidgetArrangement(const QString &activeLanguage);
860

861 862 863 864 865 866 867
    void editorOpened(Core::IEditor *editor);
    void editorAboutToClose(Core::IEditor *editor);
    void setBusyCursor(bool busy);
    void requestMark(TextEditor::ITextEditor *editor, int lineNumber);
    void showToolTip(TextEditor::ITextEditor *editor, const QPoint &pnt, int pos);
    void requestContextMenu(TextEditor::ITextEditor *editor,
        int lineNumber, QMenu *menu);
868

869 870 871 872 873 874
    void activatePreviousMode();
    void activateDebugMode();
    void toggleBreakpoint();
    void toggleBreakpoint(const QString &fileName, int lineNumber);
    void onModeChanged(Core::IMode