debuggerplugin.cpp 47.6 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 "breakhandler.h"
33
#include "debuggeractions.h"
34
#include "debuggerdialogs.h"
con's avatar
con committed
35
36
37
#include "debuggerconstants.h"
#include "debuggermanager.h"
#include "debuggerrunner.h"
38
#include "debuggerstringutils.h"
39
40
#include "debuggeruiswitcher.h"
#include "debuggermainwindow.h"
con's avatar
con committed
41

42
#include "ui_commonoptionspage.h"
hjk's avatar
hjk committed
43
#include "ui_dumperoptionpage.h"
44

45
#include <coreplugin/actionmanager/actionmanager.h>
46
47
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
hjk's avatar
hjk committed
48
#include <coreplugin/basemode.h>
con's avatar
con committed
49
#include <coreplugin/coreconstants.h>
50
#include <coreplugin/dialogs/ioptionspage.h>
con's avatar
con committed
51
#include <coreplugin/editormanager/editormanager.h>
hjk's avatar
hjk committed
52
#include <coreplugin/findplaceholder.h>
con's avatar
con committed
53
#include <coreplugin/icore.h>
54
#include <coreplugin/icorelistener.h>
con's avatar
con committed
55
#include <coreplugin/messagemanager.h>
hjk's avatar
hjk committed
56
#include <coreplugin/minisplitter.h>
con's avatar
con committed
57
#include <coreplugin/modemanager.h>
hjk's avatar
hjk committed
58
59
60
#include <coreplugin/navigationwidget.h>
#include <coreplugin/outputpane.h>
#include <coreplugin/rightpane.h>
con's avatar
con committed
61
#include <coreplugin/uniqueidmanager.h>
hjk's avatar
hjk committed
62

con's avatar
con committed
63
#include <cplusplus/ExpressionUnderCursor.h>
hjk's avatar
hjk committed
64

con's avatar
con committed
65
#include <cppeditor/cppeditorconstants.h>
hjk's avatar
hjk committed
66

67
68
#include <extensionsystem/pluginmanager.h>

69
#include <coreplugin/manhattanstyle.h>
70
#include <projectexplorer/projectexplorer.h>
con's avatar
con committed
71
72
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
73
#include <projectexplorer/project.h>
hjk's avatar
hjk committed
74
75

#include <texteditor/basetexteditor.h>
con's avatar
con committed
76
77
78
#include <texteditor/basetextmark.h>
#include <texteditor/itexteditor.h>
#include <texteditor/texteditorconstants.h>
79
#include <texteditor/texteditorplugin.h>
hjk's avatar
hjk committed
80
81

#include <utils/qtcassert.h>
82
#include <utils/styledbar.h>
83
#include <utils/savedaction.h>
con's avatar
con committed
84
85
86
87
88

#include <QtCore/QDebug>
#include <QtCore/QObject>
#include <QtCore/QPoint>
#include <QtCore/QSettings>
89
#include <QtCore/QtPlugin>
90
#include <QtCore/QCoreApplication>
91
#include <QtCore/QTimer>
92
#include <QtCore/QVariant>
hjk's avatar
hjk committed
93

94
#include <QtGui/QLineEdit>
95
#include <QtGui/QDockWidget>
con's avatar
con committed
96
97
98
#include <QtGui/QPlainTextEdit>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
99
#include <QtGui/QToolButton>
100
#include <QtGui/QMessageBox>
101
102
#include <QtGui/QAction>
#include <QtGui/QMenu>
con's avatar
con committed
103

104
105
#include <climits>

con's avatar
con committed
106
using namespace Core;
107
using namespace Debugger;
hjk's avatar
hjk committed
108
109
using namespace Debugger::Constants;
using namespace Debugger::Internal;
con's avatar
con committed
110
using namespace ProjectExplorer;
hjk's avatar
hjk committed
111
using namespace TextEditor;
con's avatar
con committed
112

hjk's avatar
hjk committed
113
114
115
namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

con's avatar
con committed
116
117
118
119

namespace Debugger {
namespace Constants {

120
121
const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebugging";

con's avatar
con committed
122
123
const char * const STARTEXTERNAL        = "Debugger.StartExternal";
const char * const ATTACHEXTERNAL       = "Debugger.AttachExternal";
124
const char * const ATTACHCORE           = "Debugger.AttachCore";
125
const char * const ATTACHREMOTE         = "Debugger.AttachRemote";
126
const char * const DETACH               = "Debugger.Detach";
con's avatar
con committed
127

128
129
const char * const RUN_TO_LINE1         = "Debugger.RunToLine1";
const char * const RUN_TO_LINE2         = "Debugger.RunToLine2";
con's avatar
con committed
130
const char * const RUN_TO_FUNCTION      = "Debugger.RunToFunction";
131
132
const char * const JUMP_TO_LINE1        = "Debugger.JumpToLine1";
const char * const JUMP_TO_LINE2        = "Debugger.JumpToLine2";
133
const char * const RETURN_FROM_FUNCTION = "Debugger.ReturnFromFunction";
134
const char * const SNAPSHOT             = "Debugger.Snapshot";
con's avatar
con committed
135
136
137
const char * const TOGGLE_BREAK         = "Debugger.ToggleBreak";
const char * const BREAK_BY_FUNCTION    = "Debugger.BreakByFunction";
const char * const BREAK_AT_MAIN        = "Debugger.BreakAtMain";
138
139
const char * const ADD_TO_WATCH1        = "Debugger.AddToWatch1";
const char * const ADD_TO_WATCH2        = "Debugger.AddToWatch2";
140
const char * const OPERATE_BY_INSTRUCTION  = "Debugger.OperateByInstruction";
con's avatar
con committed
141

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
142
#ifdef Q_WS_MAC
con's avatar
con committed
143
144
145
146
147
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";
148
const char * const REVERSE_KEY              = "";
con's avatar
con committed
149
150
151
152
153
154
155
const char * const RUN_TO_LINE_KEY          = "Shift+F8";
const char * const RUN_TO_FUNCTION_KEY      = "Ctrl+F6";
const char * const JUMP_TO_LINE_KEY         = "Alt+D,Alt+L";
const char * const TOGGLE_BREAK_KEY         = "F8";
const char * const BREAK_BY_FUNCTION_KEY    = "Alt+D,Alt+F";
const char * const BREAK_AT_MAIN_KEY        = "Alt+D,Alt+M";
const char * const ADD_TO_WATCH_KEY         = "Alt+D,Alt+W";
156
const char * const SNAPSHOT_KEY             = "Alt+D,Alt+S";
con's avatar
con committed
157
158
159
160
161
162
#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";
163
const char * const REVERSE_KEY              = "F12";
con's avatar
con committed
164
165
166
167
168
169
170
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";
171
const char * const SNAPSHOT_KEY             = "Alt+D,Alt+S";
con's avatar
con committed
172
173
174
175
176
177
#endif

} // namespace Constants
} // namespace Debugger


178
179
180
181
182
static ProjectExplorer::SessionManager *sessionManager()
{
    return ProjectExplorer::ProjectExplorerPlugin::instance()->session();
}

183
184
185
186
187
static QSettings *settings()
{
    return ICore::instance()->settings();
}

188
189
190
191
192
193
194
static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

195
196
197
198
199
200
///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
201
202
203
204
205
206
207
208
209
210
211
212
213
namespace Debugger {
namespace Internal {

class DebugMode : public Core::BaseMode
{
    Q_OBJECT

public:
    DebugMode(QObject *parent = 0);
    ~DebugMode();
};

DebugMode::DebugMode(QObject *parent)
hjk's avatar
hjk committed
214
  : BaseMode(parent)
hjk's avatar
hjk committed
215
{
216
    setDisplayName(tr("Debug"));
hjk's avatar
hjk committed
217
    setId(MODE_DEBUG);
hjk's avatar
hjk committed
218
    setIcon(QIcon(":/fancyactionbar/images/mode_Debug.png"));
hjk's avatar
hjk committed
219
    setPriority(P_MODE_DEBUG);
hjk's avatar
hjk committed
220
221
222
223
224
225
226
227
}

DebugMode::~DebugMode()
{
    // Make sure the editor manager does not get deleted
    EditorManager::instance()->setParent(0);
}

228
229
230
231
232
233
///////////////////////////////////////////////////////////////////////
//
// DebuggerListener: Close the debugging session if running.
//
///////////////////////////////////////////////////////////////////////

234
235
class DebuggerListener : public Core::ICoreListener
{
236
237
    Q_OBJECT
public:
hjk's avatar
hjk committed
238
    DebuggerListener() {}
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    virtual bool coreAboutToClose();
};

bool DebuggerListener::coreAboutToClose()
{
    DebuggerManager *mgr = DebuggerManager::instance();
    if (!mgr)
        return true;
    // Ask to terminate the session.
    bool cleanTermination = false;
    switch (mgr->state()) {
    case DebuggerNotReady:
        return true;
    case AdapterStarted:     // Most importantly, terminating a running
    case AdapterStartFailed: // debuggee can cause problems.
    case InferiorUnrunnable:
    case InferiorStartFailed:
    case InferiorStopped:
    case InferiorShutDown:
        cleanTermination = true;
        break;
    default:
        break;
    }
hjk's avatar
hjk committed
263

264
    const QString question = cleanTermination ?
hjk's avatar
hjk committed
265
266
267
268
        tr("A debugging session is still in progress.\n"
           "Would you like to terminate it?") :
        tr("A debugging session is still in progress. "
           "Terminating the session in the current"
269
           " state (%1) can leave the target in an inconsistent state."
270
           " Would you still like to terminate it?")
hjk's avatar
hjk committed
271
272
273
274
275
276
277
        .arg(_(DebuggerManager::stateName(mgr->state())));

    QMessageBox::StandardButton answer =
        QMessageBox::question(DebuggerUISwitcher::instance()->mainWindow(),
            tr("Close Debugging Session"), question,
            QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);

278
    if (answer != QMessageBox::Yes)
279
        return false;
hjk's avatar
hjk committed
280

281
    mgr->exitDebugger();
282
    QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
283
284
285
    return true;
}

286
287
288
} // namespace Internal
} // namespace Debugger

hjk's avatar
hjk committed
289

con's avatar
con committed
290
291
292
293
294
295
///////////////////////////////////////////////////////////////////////
//
// LocationMark
//
///////////////////////////////////////////////////////////////////////

296
297
298
namespace Debugger {
namespace Internal {

299
// Used in "real" editors
300
class LocationMark : public TextEditor::BaseTextMark
con's avatar
con committed
301
302
303
304
305
306
{
    Q_OBJECT

public:
    LocationMark(const QString &fileName, int linenumber)
        : BaseTextMark(fileName, linenumber)
307
    {}
con's avatar
con committed
308

309
    QIcon icon() const { return DebuggerManager::instance()->locationMarkIcon(); }
con's avatar
con committed
310
311
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
312
    void removedFromEditor() {}
con's avatar
con committed
313
314
};

315
316
317
318
319
320
} // namespace Internal
} // namespace Debugger


///////////////////////////////////////////////////////////////////////
//
321
// CommonOptionsPage
322
323
324
325
326
327
//
///////////////////////////////////////////////////////////////////////

namespace Debugger {
namespace Internal {

328
class CommonOptionsPage : public Core::IOptionsPage
329
330
331
332
{
    Q_OBJECT

public:
333
    CommonOptionsPage() {}
334
335

    // IOptionsPage
336
    QString id() const
hjk's avatar
hjk committed
337
        { return _(DEBUGGER_COMMON_SETTINGS_ID); }
338
    QString displayName() const
hjk's avatar
hjk committed
339
        { return QCoreApplication::translate("Debugger", DEBUGGER_COMMON_SETTINGS_NAME); }
340
    QString category() const
hjk's avatar
hjk committed
341
        { return _(DEBUGGER_SETTINGS_CATEGORY);  }
342
    QString displayCategory() const
hjk's avatar
hjk committed
343
        { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
344
345

    QWidget *createPage(QWidget *parent);
346
    void apply() { m_group.apply(settings()); }
347
    void finish() { m_group.finish(); }
348
    virtual bool matches(const QString &s) const;
349
350

private:
351
    Ui::CommonOptionsPage m_ui;
352
    Utils::SavedActionSet m_group;
353
    QString m_searchKeywords;
354
355
};

356
QWidget *CommonOptionsPage::createPage(QWidget *parent)
357
358
359
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);
360
    m_group.clear();
361

362
    m_group.insert(theDebuggerAction(ListSourceFiles),
363
        m_ui.checkBoxListSourceFiles);
364
    m_group.insert(theDebuggerAction(UseAlternatingRowColors),
365
        m_ui.checkBoxUseAlternatingRowColors);
366
367
    m_group.insert(theDebuggerAction(UseMessageBoxForSignals),
        m_ui.checkBoxUseMessageBoxForSignals);
368
    m_group.insert(theDebuggerAction(SkipKnownFrames),
369
        m_ui.checkBoxSkipKnownFrames);
370
    m_group.insert(theDebuggerAction(UseToolTipsInMainEditor),
371
        m_ui.checkBoxUseToolTipsInMainEditor);
372
    m_group.insert(theDebuggerAction(AutoDerefPointers), 0);
373
374
375
376
    m_group.insert(theDebuggerAction(UseToolTipsInLocalsView), 0);
    m_group.insert(theDebuggerAction(UseToolTipsInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInStackView), 0);
377
    m_group.insert(theDebuggerAction(EnableReverseDebugging),
378
        m_ui.checkBoxEnableReverseDebugging);
379
    m_group.insert(theDebuggerAction(MaximalStackDepth),
380
        m_ui.spinBoxMaximalStackDepth);
381
    m_group.insert(theDebuggerAction(GdbWatchdogTimeout), 0);
382
383
    m_group.insert(theDebuggerAction(ShowStdNamespace), 0);
    m_group.insert(theDebuggerAction(ShowQtNamespace), 0);
384
    m_group.insert(theDebuggerAction(LogTimeStamps), 0);
385
    m_group.insert(theDebuggerAction(VerboseLog), 0);
386
    m_group.insert(theDebuggerAction(UsePreciseBreakpoints), 0);
387
388
    m_group.insert(theDebuggerAction(BreakOnThrow), 0);
    m_group.insert(theDebuggerAction(BreakOnCatch), 0);
389

390
391
392
393
394
395
396
397
398
399
400
    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords) << ' ' << m_ui.checkBoxListSourceFiles->text()
                << ' ' << m_ui.checkBoxUseMessageBoxForSignals->text()
                << ' ' << m_ui.checkBoxUseAlternatingRowColors->text()
                << ' ' << m_ui.checkBoxUseToolTipsInMainEditor->text()
                << ' ' << m_ui.checkBoxSkipKnownFrames->text()
                << ' ' << m_ui.checkBoxEnableReverseDebugging->text()
                << ' ' << m_ui.labelMaximalStackDepth->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }

401
402
403
    return w;
}

404
405
406
407
408
bool CommonOptionsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

409
410
411
} // namespace Internal
} // namespace Debugger

hjk's avatar
hjk committed
412

hjk's avatar
hjk committed
413
414
///////////////////////////////////////////////////////////////////////
//
415
// DebuggingHelperOptionPage
hjk's avatar
hjk committed
416
417
418
//
///////////////////////////////////////////////////////////////////////

419
420
421
static inline bool oxygenStyle()
{
    if (const ManhattanStyle *ms = qobject_cast<const ManhattanStyle *>(qApp->style()))
422
        return !qstrcmp("OxygenStyle", ms->baseStyle()->metaObject()->className());
423
424
425
    return false;
}

hjk's avatar
hjk committed
426
427
428
namespace Debugger {
namespace Internal {

429
class DebuggingHelperOptionPage : public Core::IOptionsPage
hjk's avatar
hjk committed
430
431
432
433
{
    Q_OBJECT

public:
434
    DebuggingHelperOptionPage() {}
hjk's avatar
hjk committed
435
436

    // IOptionsPage
hjk's avatar
hjk committed
437
    QString id() const { return _("B.DebuggingHelper"); }
438
    QString displayName() const { return tr("Debugging Helper"); }
hjk's avatar
hjk committed
439
440
    QString category() const { return _(DEBUGGER_SETTINGS_CATEGORY); }
    QString displayCategory() const { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
hjk's avatar
hjk committed
441
442

    QWidget *createPage(QWidget *parent);
443
    void apply() { m_group.apply(settings()); }
444
    void finish() { m_group.finish(); }
445
    virtual bool matches(const QString &s) const;
hjk's avatar
hjk committed
446
447

private:
448
    Ui::DebuggingHelperOptionPage m_ui;
449
    Utils::SavedActionSet m_group;
450
    QString m_searchKeywords;
hjk's avatar
hjk committed
451
452
};

453
QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent)
hjk's avatar
hjk committed
454
455
456
457
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);

458
    m_ui.dumperLocationChooser->setExpectedKind(Utils::PathChooser::Command);
459
    m_ui.dumperLocationChooser->setPromptDialogTitle(tr("Choose DebuggingHelper Location"));
hjk's avatar
hjk committed
460
461
    m_ui.dumperLocationChooser->setInitialBrowsePathBackup(
        Core::ICore::instance()->resourcePath() + "../../lib");
hjk's avatar
hjk committed
462

463
    m_group.clear();
464
    m_group.insert(theDebuggerAction(UseDebuggingHelpers),
465
        m_ui.debuggingHelperGroupBox);
466
    m_group.insert(theDebuggerAction(UseCustomDebuggingHelperLocation),
467
        m_ui.customLocationGroupBox);
hjk's avatar
hjk committed
468
    // Suppress Oxygen style's giving flat group boxes bold titles.
469
    if (oxygenStyle())
hjk's avatar
hjk committed
470
        m_ui.customLocationGroupBox->setStyleSheet(_("QGroupBox::title { font: ; }"));
471

472
    m_group.insert(theDebuggerAction(CustomDebuggingHelperLocation),
473
        m_ui.dumperLocationChooser);
hjk's avatar
hjk committed
474

475
476
477
    m_group.insert(theDebuggerAction(UseCodeModel),
        m_ui.checkBoxUseCodeModel);

478
#ifdef QT_DEBUG
479
480
    m_group.insert(theDebuggerAction(DebugDebuggingHelpers),
        m_ui.checkBoxDebugDebuggingHelpers);
481
482
483
#else
    m_ui.checkBoxDebugDebuggingHelpers->hide();
#endif
hjk's avatar
hjk committed
484
485
486
487

#ifndef QT_DEBUG
#if 0
    cmd = am->registerAction(m_manager->m_dumpLogAction,
hjk's avatar
hjk committed
488
        DUMP_LOG, globalcontext);
hjk's avatar
hjk committed
489
490
491
492
493
494
    //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+L")));
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F11")));
    mdebug->addAction(cmd);
#endif
#endif

495
496
497
498
499
500
501
502
503
    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
504
505
506
    return w;
}

507
bool DebuggingHelperOptionPage::matches(const QString &s) const
hjk's avatar
hjk committed
508
{
509
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
hjk's avatar
hjk committed
510
511
}

hjk's avatar
hjk committed
512
513
514
} // namespace Internal
} // namespace Debugger

515

con's avatar
con committed
516
517
518
519
520
521
///////////////////////////////////////////////////////////////////////
//
// DebuggerPlugin
//
///////////////////////////////////////////////////////////////////////

522
523
524
525
526
527
528

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

529
530
DebuggerPlugin::DebuggerPlugin()
  : m_manager(0),
531
532
533
    m_debugMode(0),
    m_locationMark(0),
    m_gdbRunningContext(0),
534
    m_cmdLineEnabledEngines(AllEngineTypes)
535
{}
con's avatar
con committed
536
537
538
539
540
541

DebuggerPlugin::~DebuggerPlugin()
{}

void DebuggerPlugin::shutdown()
{
hjk's avatar
hjk committed
542
    QTC_ASSERT(m_manager, /**/);
con's avatar
con committed
543
544
545
    if (m_manager)
        m_manager->shutdown();

hjk's avatar
hjk committed
546
    writeSettings();
547
548
549
550

    if (m_uiSwitcher)
        m_uiSwitcher->shutdown();

dt's avatar
dt committed
551
    delete DebuggerSettings::instance();
hjk's avatar
hjk committed
552

con's avatar
con committed
553
554
555
556
557
558
559
560
561
562
    removeObject(m_debugMode);

    // FIXME: when using the line below, BreakWindow etc gets deleted twice.
    // so better leak for now...
    delete m_debugMode;
    m_debugMode = 0;

    delete m_locationMark;
    m_locationMark = 0;

ck's avatar
ck committed
563
    removeObject(m_manager);
con's avatar
con committed
564
565
    delete m_manager;
    m_manager = 0;
566
567
568
569

    removeObject(m_uiSwitcher);
    delete m_uiSwitcher;
    m_uiSwitcher = 0;
con's avatar
con committed
570
571
}

572
static QString msgParameterMissing(const QString &a)
573
574
575
576
{
    return DebuggerPlugin::tr("Option '%1' is missing the parameter.").arg(a);
}

577
static QString msgInvalidNumericParameter(const QString &a, const QString &number)
578
579
580
581
582
{
    return DebuggerPlugin::tr("The parameter '%1' of option '%2' is not a number.").arg(number, a);
}

// Parse arguments
583
584
585
586
static bool parseArgument(QStringList::const_iterator &it,
                          const QStringList::const_iterator &cend,
                          DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters,
                          unsigned *enabledEngines, QString *errorMessage)
587
588
589
{
    const QString &option = *it;
    // '-debug <pid>'
hjk's avatar
hjk committed
590
    if (*it == _("-debug")) {
591
592
593
594
595
596
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
597
        attachRemoteParameters->attachPid = it->toULongLong(&ok);
598
        if (!ok) {
599
600
            attachRemoteParameters->attachPid = 0;
            attachRemoteParameters->attachCore = *it;
601
602
603
        }
        return true;
    }
604
605
    // -wincrashevent <event-handle>. A handle used for
    // a handshake when attaching to a crashed Windows process.
hjk's avatar
hjk committed
606
    if (*it == _("-wincrashevent")) {
607
608
609
610
611
612
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
613
        attachRemoteParameters->winCrashEvent = it->toULongLong(&ok);
614
615
616
617
618
619
620
        if (!ok) {
            *errorMessage = msgInvalidNumericParameter(option, *it);
            return false;
        }
        return true;
    }
    // engine disabling
hjk's avatar
hjk committed
621
    if (option == _("-disable-cdb")) {
622
        *enabledEngines &= ~Debugger::CdbEngineType;
623
624
        return true;
    }
hjk's avatar
hjk committed
625
    if (option == _("-disable-gdb")) {
626
        *enabledEngines &= ~Debugger::GdbEngineType;
627
628
        return true;
    }
hjk's avatar
hjk committed
629
    if (option == _("-disable-sdb")) {
630
        *enabledEngines &= ~Debugger::ScriptEngineType;
631
632
633
        return true;
    }

634
    *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
635
636
637
    return false;
}

638
639
640
static bool parseArguments(const QStringList &args,
                           DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters,
                           unsigned *enabledEngines, QString *errorMessage)
641
642
643
{
    const QStringList::const_iterator cend = args.constEnd();
    for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
644
        if (!parseArgument(it, cend, attachRemoteParameters, enabledEngines, errorMessage))
645
646
            return false;
    if (Debugger::Constants::Internal::debug)
647
        qDebug().nospace() << args << "engines=0x"
648
649
650
            << QString::number(*enabledEngines, 16)
            << " pid" << attachRemoteParameters->attachPid
            << " core" << attachRemoteParameters->attachCore << '\n';
651
652
653
    return true;
}

654
655
656
657
658
659
660
661
662
663
664
665
666
void DebuggerPlugin::remoteCommand(const QStringList &options, const QStringList &)
{
    QString errorMessage;
    AttachRemoteParameters parameters;
    unsigned dummy = 0;
    // Did we receive a request for debugging (unless it is ourselves)?
    if (parseArguments(options, &parameters, &dummy, &errorMessage)
        && parameters.attachPid != quint64(QCoreApplication::applicationPid())) {
        m_attachRemoteParameters = parameters;
        attachCmdLine();
    }
}

hjk's avatar
hjk committed
667
bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMessage)
con's avatar
con committed
668
{
hjk's avatar
hjk committed
669
    // Do not fail the whole plugin if something goes wrong here.
670
    if (!parseArguments(arguments, &m_attachRemoteParameters, &m_cmdLineEnabledEngines, errorMessage)) {
671
672
        *errorMessage = tr("Error evaluating command line arguments: %1")
            .arg(*errorMessage);
673
674
675
        qWarning("%s\n", qPrintable(*errorMessage));
        errorMessage->clear();
    }
con's avatar
con committed
676

hjk's avatar
hjk committed
677
    // Debug mode setup.
678
679
680
681
682
    m_debugMode = new DebugMode(this);
    m_uiSwitcher = new DebuggerUISwitcher(m_debugMode, this);
    ExtensionSystem::PluginManager::instance()->addObject(m_uiSwitcher);
    m_uiSwitcher->addLanguage(LANG_CPP);

683
    ICore *core = ICore::instance();
hjk's avatar
hjk committed
684
    QTC_ASSERT(core, return false);
con's avatar
con committed
685

686
687
    Core::ActionManager *am = core->actionManager();
    QTC_ASSERT(am, return false);
con's avatar
con committed
688
689

    Core::UniqueIDManager *uidm = core->uniqueIDManager();
hjk's avatar
hjk committed
690
    QTC_ASSERT(uidm, return false);
con's avatar
con committed
691
692

    QList<int> globalcontext;
hjk's avatar
hjk committed
693
    globalcontext << CC::C_GLOBAL_ID;
con's avatar
con committed
694
695

    QList<int> cppcontext;
hjk's avatar
hjk committed
696
    cppcontext << uidm->uniqueIdentifier(PE::LANG_CXX);
con's avatar
con committed
697
698
699
700
701

    QList<int> debuggercontext;
    debuggercontext << uidm->uniqueIdentifier(C_GDBDEBUGGER);

    QList<int> cppeditorcontext;
702
    cppeditorcontext << uidm->uniqueIdentifier(CppEditor::Constants::C_CPPEDITOR);
con's avatar
con committed
703
704
705
706
707
708

    QList<int> texteditorcontext;
    texteditorcontext << uidm->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);

    m_gdbRunningContext = uidm->uniqueIdentifier(Constants::GDBRUNNING);

709
710
711
712
713
    DebuggerManager *manager = new DebuggerManager(this);
    ExtensionSystem::PluginManager::instance()->addObject(manager);
    const QList<Core::IOptionsPage *> engineOptionPages =
        manager->initializeEngines(m_cmdLineEnabledEngines);

714
    // Register factory of DebuggerRunControl.
715
    m_debuggerRunControlFactory = new DebuggerRunControlFactory(manager);
716
717
718
    addAutoReleasedObject(m_debuggerRunControlFactory);

    QList<int> context;
hjk's avatar
hjk committed
719
720
721
    context.append(uidm->uniqueIdentifier(CC::C_EDITORMANAGER));
    context.append(uidm->uniqueIdentifier(C_GDBDEBUGGER));
    context.append(uidm->uniqueIdentifier(CC::C_NAVIGATION_PANE));
722
723
    m_debugMode->setContext(context);

724
    m_reverseToolButton = 0;
con's avatar
con committed
725

726
    // Handling of external applications.
727
728
729
730
731
732
733
734
735
736
737
738
739
740
    m_startExternalAction = new QAction(this);
    m_startExternalAction->setText(tr("Start and Debug External Application..."));
    connect(m_startExternalAction, SIGNAL(triggered()),
        this, SLOT(startExternalApplication()));

    m_attachExternalAction = new QAction(this);
    m_attachExternalAction->setText(tr("Attach to Running External Application..."));
    connect(m_attachExternalAction, SIGNAL(triggered()),
        this, SLOT(attachExternalApplication()));

    m_attachCoreAction = new QAction(this);
    m_attachCoreAction->setText(tr("Attach to Core..."));
    connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore()));

741
742
743
744
    m_startRemoteAction = new QAction(this);
    m_startRemoteAction->setText(tr("Start and Attach to Remote Application..."));
    connect(m_startRemoteAction, SIGNAL(triggered()),
        this, SLOT(startRemoteApplication()));
745

746
    m_detachAction = new QAction(this);
747
    m_detachAction->setText(tr("Detach Debugger"));
748
    connect(m_detachAction, SIGNAL(triggered()),
749
        manager, SLOT(detachDebugger()));
750

751
    Core::Command *cmd = 0;
752
    const DebuggerManagerActions actions = manager->debuggerManagerActions();
753

754
    Core::ActionContainer *mstart =
hjk's avatar
hjk committed
755
        am->actionContainer(PE::M_DEBUG_STARTDEBUGGING);
756

757
    cmd = am->registerAction(actions.continueAction,
hjk's avatar
hjk committed
758
759
        PE::DEBUG, QList<int>() << m_gdbRunningContext);
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);
760

761
    cmd = am->registerAction(m_startExternalAction,
con's avatar
con committed
762
        Constants::STARTEXTERNAL, globalcontext);
hjk's avatar
hjk committed
763
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);
con's avatar
con committed
764

765
    cmd = am->registerAction(m_attachExternalAction,
con's avatar
con committed
766
        Constants::ATTACHEXTERNAL, globalcontext);
hjk's avatar
hjk committed
767
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);
768

769
770
    cmd = am->registerAction(m_attachCoreAction,
        Constants::ATTACHCORE, globalcontext);
hjk's avatar
hjk committed
771
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);
772

773
    cmd = am->registerAction(m_startRemoteAction,
774
        Constants::ATTACHREMOTE, globalcontext);
hjk's avatar
hjk committed
775
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);
776

777
778
    cmd = am->registerAction(m_detachAction,
        Constants::DETACH, globalcontext);
hjk's avatar
hjk committed
779
    m_uiSwitcher->addMenuAction(cmd, CC::G_DEFAULT_ONE);
con's avatar
con committed
780

781
    cmd = am->registerAction(actions.stopAction,
con's avatar
con committed
782
        Constants::INTERRUPT, globalcontext);
hjk's avatar
hjk committed
783
784
    cmd->setAttribute(Command::CA_UpdateText);
    cmd->setAttribute(Command::CA_UpdateIcon);
con's avatar
con committed
785
786
    cmd->setDefaultKeySequence(QKeySequence(Constants::INTERRUPT_KEY));
    cmd->setDefaultText(tr("Stop Debugger/Interrupt Debugger"));
hjk's avatar
hjk committed
787
    m_uiSwitcher->addMenuAction(cmd, CC::G_DEFAULT_ONE);
con's avatar
con committed
788

789
    cmd = am->registerAction(actions.resetAction,
con's avatar
con committed
790
        Constants::RESET, globalcontext);
con's avatar
con committed
791
    cmd->setAttribute(Core::Command::CA_UpdateText);
792
    //cmd->setDefaultKeySequence(QKeySequence(Constants::RESET_KEY));
con's avatar
con committed
793
    cmd->setDefaultText(tr("Reset Debugger"));
hjk's avatar
hjk committed
794
    m_uiSwitcher->addMenuAction(cmd, CC::G_DEFAULT_ONE);
con's avatar
con committed
795
796
797

    QAction *sep = new QAction(this);
    sep->setSeparator(true);
hjk's avatar
hjk committed
798
    cmd = am->registerAction(sep, _("Debugger.Sep.Step"), globalcontext);
799
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
800

801
    cmd = am->registerAction(actions.nextAction,
con's avatar
con committed
802
803
        Constants::NEXT, debuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::NEXT_KEY));
804
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
805

806
    cmd = am->registerAction(actions.stepAction,
con's avatar
con committed
807
808
        Constants::STEP, debuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::STEP_KEY));
809
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
810

811
    cmd = am->registerAction(actions.stepOutAction,
con's avatar
con committed
812
813
        Constants::STEPOUT, debuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::STEPOUT_KEY));
814
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
815

816
817
    cmd = am->registerAction(actions.runToLineAction1,
        Constants::RUN_TO_LINE1, debuggercontext);
con's avatar
con committed
818
    cmd->setDefaultKeySequence(QKeySequence(Constants::RUN_TO_LINE_KEY));
819
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
820

821
    cmd = am->registerAction(actions.runToFunctionAction,
con's avatar
con committed
822
823
        Constants::RUN_TO_FUNCTION, debuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::RUN_TO_FUNCTION_KEY));
824
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
825

826
827
    cmd = am->registerAction(actions.jumpToLineAction1,
        Constants::JUMP_TO_LINE1, debuggercontext);
828
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
829

830
831
    cmd = am->registerAction(actions.returnFromFunctionAction,
        Constants::RETURN_FROM_FUNCTION, debuggercontext);
832
    m_uiSwitcher->addMenuAction(cmd);
833

834
    cmd = am->registerAction(actions.reverseDirectionAction,
835
836
        Constants::REVERSE, debuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::REVERSE_KEY));
837
    m_uiSwitcher->addMenuAction(cmd);
838

con's avatar
con committed
839
840
    sep = new QAction(this);
    sep->setSeparator(true);
hjk's avatar
hjk committed
841
    cmd = am->registerAction(sep, _("Debugger.Sep.Break"), globalcontext);
842
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
843

844
845
846
    cmd = am->registerAction(actions.snapshotAction,
        Constants::SNAPSHOT, debuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::SNAPSHOT_KEY));
847
    m_uiSwitcher->addMenuAction(cmd);
848

849
850
    cmd = am->registerAction(theDebuggerAction(OperateByInstruction),
        Constants::OPERATE_BY_INSTRUCTION, debuggercontext);
851
    m_uiSwitcher->addMenuAction(cmd);
852

853
    cmd = am->registerAction(actions.breakAction,
con's avatar
con committed
854
855
        Constants::TOGGLE_BREAK, cppeditorcontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::TOGGLE_BREAK_KEY));
856
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
857
858
859
860
    //mcppcontext->addAction(cmd);

    sep = new QAction(this);
    sep->setSeparator(true);
hjk's avatar
hjk committed
861
    cmd = am->registerAction(sep, _("Debugger.Sep.Watch"), globalcontext);
862
    m_uiSwitcher->addMenuAction(cmd);
con's avatar
con committed
863

864
865
    cmd = am->registerAction(actions.watchAction1,
        Constants::ADD_TO_WATCH1, cppeditorcontext);
866
    cmd->action()->setEnabled(true);
867
    //cmd->setDefaultKeySequence(QKeySequence(tr("ALT+D,ALT+W")));
868
    m_uiSwitcher->addMenuAction(cmd);
869

870
    // Editor context menu
871
872
    ActionContainer *editorContextMenu =
        am->actionContainer(CppEditor::Constants::M_CONTEXT);
hjk's avatar
hjk committed
873
    cmd = am->registerAction(sep, _("Debugger.Sep.Views"),
874
875
876
        debuggercontext);
    editorContextMenu->addAction(cmd);
    cmd->setAttribute(Command::CA_Hide);
877

878
879
880
    cmd = am->registerAction(actions.watchAction2,
        Constants::ADD_TO_WATCH2, debuggercontext);
    cmd->action()->setEnabled(true);
881
882
883
884
885
886
887
888
889
890
891
892
    editorContextMenu->addAction(cmd);
    cmd->setAttribute(Command::CA_Hide);

    cmd = am->registerAction(actions.runToLineAction2,
        Constants::RUN_TO_LINE2, debuggercontext);
    cmd->action()->setEnabled(true);
    editorContextMenu->addAction(cmd);
    cmd->setAttribute(Command::CA_Hide);

    cmd = am->registerAction(actions.jumpToLineAction2,
        Constants::JUMP_TO_LINE2, debuggercontext);
    cmd->action()->setEnabled(true);
893
894
    editorContextMenu->addAction(cmd);
    cmd->setAttribute(Command::CA_Hide);
con's avatar
con committed
895

hjk's avatar