cdbdebugengine.cpp 58.1 KB
Newer Older
1
/**************************************************************************
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).
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
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.
27
**
28
**************************************************************************/
29

hjk's avatar
hjk committed
30
#include "cdbdebugengine.h"
31
#include "cdbdebugengine_p.h"
32
33
#include "cdbdebugoutput.h"
#include "cdbdebugeventcallback.h"
34
#include "cdbstacktracecontext.h"
35
#include "cdbsymbolgroupcontext.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
36
#include "cdbbreakpoint.h"
37
38
#include "cdbmodules.h"
#include "cdbassembler.h"
39
40
#include "cdboptionspage.h"
#include "cdboptions.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
41
#include "cdbexceptionutils.h"
42
#include "debuggeragents.h"
Robert Loehning's avatar
Robert Loehning committed
43
44
#include "debuggeruiswitcher.h"
#include "debuggermainwindow.h"
Banana Joe's avatar
Banana Joe committed
45

46
#include "debuggeractions.h"
Banana Joe's avatar
Banana Joe committed
47
48
49
#include "debuggermanager.h"
#include "breakhandler.h"
#include "stackhandler.h"
50
#include "watchhandler.h"
51
52
#include "registerhandler.h"
#include "moduleshandler.h"
53
#include "watchutils.h"
Banana Joe's avatar
Banana Joe committed
54

55
#include <coreplugin/icore.h>
hjk's avatar
hjk committed
56
#include <utils/qtcassert.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
57
#include <utils/winutils.h>
58
#include <utils/consoleprocess.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
59
#include <utils/fancymainwindow.h>
60
#include <texteditor/itexteditor.h>
61
#include <utils/savedaction.h>
hjk's avatar
hjk committed
62

Friedemann Kleint's avatar
Friedemann Kleint committed
63
#include <QtCore/QDebug>
64
#include <QtCore/QTimer>
Friedemann Kleint's avatar
Friedemann Kleint committed
65
66
67
#include <QtCore/QTimerEvent>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
Friedemann Kleint's avatar
Friedemann Kleint committed
68
#include <QtCore/QLibrary>
69
#include <QtCore/QCoreApplication>
70
71
#include <QtGui/QMessageBox>
#include <QtGui/QMainWindow>
72
#include <QtGui/QApplication>
73
#include <QtGui/QToolTip>
Banana Joe's avatar
Banana Joe committed
74
75

#define DBGHELP_TRANSLATE_TCHAR
76
#include <inc/Dbghelp.h>
Banana Joe's avatar
Banana Joe committed
77

78
79
80
81
82
static const char *localSymbolRootC = "local";

namespace Debugger {
namespace Internal {

Friedemann Kleint's avatar
Friedemann Kleint committed
83
84
typedef QList<WatchData> WatchList;

85
86
// ----- Message helpers

87
88
89
90
91
static QString msgStackIndexOutOfRange(int idx, int size)
{
    return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
}

92
93
QString msgDebuggerCommandFailed(const QString &command, HRESULT hr)
{
94
    return QString::fromLatin1("Unable to execute '%1': %2").arg(command, CdbCore::msgDebugEngineComResult(hr));
95
96
}

97
static const char *msgNoStackTraceC = "Internal error: no stack trace present.";
Friedemann Kleint's avatar
Friedemann Kleint committed
98

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Format function failure message. Pass in Q_FUNC_INFO
static QString msgFunctionFailed(const char *func, const QString &why)
{
    // Strip a "cdecl_ int namespace1::class::foo(int bar)" as
    // returned by Q_FUNC_INFO down to "foo"
    QString function = QLatin1String(func);
    const int firstParentPos = function.indexOf(QLatin1Char('('));
    if (firstParentPos != -1)
        function.truncate(firstParentPos);
    const int classSepPos = function.lastIndexOf(QLatin1String("::"));
    if (classSepPos != -1)
        function.remove(0, classSepPos + 2);
   //: Function call failed
   return CdbDebugEngine::tr("The function \"%1()\" failed: %2").arg(function, why);
}

115
116
// ----- Engine helpers

Friedemann Kleint's avatar
Friedemann Kleint committed
117
118
// --- CdbDebugEnginePrivate

hjk's avatar
hjk committed
119
CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
120
121
122
                                             const QSharedPointer<CdbOptions> &options,
                                             CdbDebugEngine* engine) :
    m_options(options),
Banana Joe's avatar
Banana Joe committed
123
124
    m_hDebuggeeProcess(0),
    m_hDebuggeeThread(0),
125
    m_breakEventMode(BreakEventHandle),
126
    m_dumper(new CdbDumperHelper(manager, this)),
127
128
    m_currentThreadId(-1),
    m_eventThreadId(-1),
Friedemann Kleint's avatar
Friedemann Kleint committed
129
    m_interruptArticifialThreadId(-1),
130
    m_ignoreInitialBreakPoint(false),
131
    m_interrupted(false),
Friedemann Kleint's avatar
Friedemann Kleint committed
132
    m_engine(engine),
133
    m_currentStackTrace(0),
Friedemann Kleint's avatar
Friedemann Kleint committed
134
    m_firstActivatedFrame(true),
Friedemann Kleint's avatar
Friedemann Kleint committed
135
    m_inferiorStartupComplete(false),
136
137
    m_mode(AttachCore),
    m_stoppedReason(StoppedOther)
138
{
139
    connect(this, SIGNAL(watchTimerDebugEvent()), this, SLOT(handleDebugEvent()));
140
    connect(this, SIGNAL(modulesLoaded()), this, SLOT(slotModulesLoaded()));
141
142
143
}

bool CdbDebugEnginePrivate::init(QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
144
{
145
    enum {  bufLen = 10240 };
146

147
    if (!CdbCore::CoreEngine::init(m_options->path, errorMessage))
148
        return false;
149
150
151
152
153
154
    CdbDebugOutput *output = new CdbDebugOutput;
    setDebugOutput(DebugOutputBasePtr(output));
    connect(output, SIGNAL(debuggerOutput(int,QString)),
            manager(), SLOT(showDebuggerOutput(int,QString)));
    connect(output, SIGNAL(debuggerInputPrompt(int,QString)),
            manager(), SLOT(showDebuggerInput(int,QString)));
155
156
157
158
    connect(output, SIGNAL(debuggeeOutput(QString,bool)),
            manager(), SLOT(showApplicationOutput(QString,bool)));
    connect(output, SIGNAL(debuggeeInputPrompt(QString,bool)),
            manager(), SLOT(showApplicationOutput(QString,bool)));
159
160
161

    setDebugEventCallback(DebugEventCallbackBasePtr(new CdbDebugEventCallback(m_engine)));
    updateCodeLevel();
162

163
    return true;
Friedemann Kleint's avatar
Friedemann Kleint committed
164
}
Banana Joe's avatar
Banana Joe committed
165

166
IDebuggerEngine *CdbDebugEngine::create(Debugger::DebuggerManager *manager,
167
168
                                        const QSharedPointer<CdbOptions> &options,
                                        QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
169
{
hjk's avatar
hjk committed
170
    CdbDebugEngine *rc = new CdbDebugEngine(manager, options);
171
172
    if (rc->m_d->init(errorMessage)) {
        rc->syncDebuggerPaths();
173
        return rc;
174
    }
175
176
    delete rc;
    return 0;
Banana Joe's avatar
Banana Joe committed
177
178
}

179
void  CdbDebugEnginePrivate::updateCodeLevel()
180
{
181
182
183
    const CdbCore::CoreEngine::CodeLevel cl = theDebuggerBoolSetting(OperateByInstruction) ?
                                              CdbCore::CoreEngine::CodeLevelAssembly : CdbCore::CoreEngine::CodeLevelSource;
    setCodeLevel(cl);
184
185
}

186
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
Banana Joe's avatar
Banana Joe committed
187
{
188
    cleanStackTrace();
Banana Joe's avatar
Banana Joe committed
189
190
}

Friedemann Kleint's avatar
Friedemann Kleint committed
191
192
193
194
195
DebuggerManager *CdbDebugEnginePrivate::manager() const
{
    return m_engine->manager();
}

196
void CdbDebugEnginePrivate::clearForRun()
197
198
199
200
{
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

201
    m_breakEventMode = BreakEventHandle;
Friedemann Kleint's avatar
Friedemann Kleint committed
202
    m_eventThreadId = m_interruptArticifialThreadId = -1;
203
    m_interrupted = false;
204
    cleanStackTrace();
205
206
    m_stoppedReason = StoppedOther;
    m_stoppedMessage.clear();
207
208
209
}

void CdbDebugEnginePrivate::cleanStackTrace()
210
{
211
212
213
214
    if (m_currentStackTrace) {
        delete m_currentStackTrace;
        m_currentStackTrace = 0;
    }
215
216
    m_firstActivatedFrame = false;
    m_editorToolTipCache.clear();
217
218
}

hjk's avatar
hjk committed
219
CdbDebugEngine::CdbDebugEngine(DebuggerManager *manager, const QSharedPointer<CdbOptions> &options) :
Friedemann Kleint's avatar
Friedemann Kleint committed
220
221
    IDebuggerEngine(manager),
    m_d(new CdbDebugEnginePrivate(manager, options, this))
222
{
223
    m_d->m_consoleStubProc.setMode(Utils::ConsoleProcess::Suspend);
224
225
    connect(&m_d->m_consoleStubProc, SIGNAL(processMessage(QString,bool)),
            this, SLOT(slotConsoleStubMessage(QString, bool)));
hjk's avatar
hjk committed
226
227
228
229
    connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()),
            this, SLOT(slotConsoleStubStarted()));
    connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()),
            this, SLOT(slotConsoleStubTerminated()));
230
231
232
233
234
235
236
}

CdbDebugEngine::~CdbDebugEngine()
{
    delete m_d;
}

237
238
239
240
241
242
243
void CdbDebugEngine::setState(DebuggerState state, const char *func, int line)
{
    if (debugCDB)
        qDebug() << "setState(" << state << ") at " << func << ':' << line;
    IDebuggerEngine::setState(state);
}

hjk's avatar
hjk committed
244
void CdbDebugEngine::shutdown()
Banana Joe's avatar
Banana Joe committed
245
246
247
248
{
    exitDebugger();
}

249
QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &function)
Banana Joe's avatar
Banana Joe committed
250
{
251
252
253
254
255
256
    // Figure the editor tooltip. Ask the frame context of the
    // function if it is a local variable it knows. If that is not
    // the case, try to evaluate via debugger
    QString errorMessage;
    QString rc;
    // Find the frame of the function if there is any
257
    CdbSymbolGroupContext *frame = 0;
258
259
    if (m_d->m_currentStackTrace &&  !function.isEmpty()) {
        const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
260
261
        if (debugToolTips)
            qDebug() << "CdbDebugEngine::editorToolTip" << exp << function << frameIndex;
262
        if (frameIndex != -1)
263
            frame = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
264
    }
265
266
    if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
        return rc;
267
268
269
    // No function/symbol context found, try to evaluate in current context.
    // Do not append type as this will mostly be 'long long' for integers, etc.
    QString type;
270
271
    if (debugToolTips)
        qDebug() << "Defaulting to expression";
272
    if (!m_d->evaluateExpression(exp, &rc, &type, &errorMessage))
273
274
275
276
277
278
279
        return QString();
    return rc;
}

void CdbDebugEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
{
    typedef CdbDebugEnginePrivate::EditorToolTipCache EditorToolTipCache;
280
    if (debugCDB)
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
        qDebug() << Q_FUNC_INFO << '\n' << cursorPos;
    // Need a stopped debuggee and a cpp file
    if (!m_d->m_hDebuggeeProcess || m_d->isDebuggeeRunning())
        return;
    if (!isCppEditor(editor))
        return;
    // Determine expression and function
    QString toolTip;
    do {
        int line;
        int column;
        QString function;
        const QString exp = cppExpressionAt(editor, cursorPos, &line, &column, &function);
        if (function.isEmpty() || exp.isEmpty())
            break;
        // Check cache (key containing function) or try to figure out expression
        QString cacheKey = function;
        cacheKey += QLatin1Char('@');
        cacheKey += exp;
        const EditorToolTipCache::const_iterator cit = m_d->m_editorToolTipCache.constFind(cacheKey);
        if (cit != m_d->m_editorToolTipCache.constEnd()) {
            toolTip = cit.value();
        } else {
            toolTip = editorToolTip(exp, function);
            if (!toolTip.isEmpty())
                m_d->m_editorToolTipCache.insert(cacheKey, toolTip);
        }
    } while (false);
    // Display
    QToolTip::hideText();
    if (!toolTip.isEmpty())
        QToolTip::showText(mousePos, toolTip);
Banana Joe's avatar
Banana Joe committed
313
314
}

315
316
void CdbDebugEnginePrivate::clearDisplay()
{
Friedemann Kleint's avatar
Friedemann Kleint committed
317
318
319
    manager()->threadsHandler()->removeAll();
    manager()->modulesHandler()->removeAll();
    manager()->registerHandler()->removeAll();
320
321
}

322
323
324
325
326
327
328
329
void CdbDebugEnginePrivate::checkVersion()
{
    static bool versionNotChecked = true;
    // Check for version 6.11 (extended expression syntax)
    if (versionNotChecked) {
        versionNotChecked = false;
        // Get engine DLL version
        QString errorMessage;
330
        const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, dbengDLL(), &errorMessage);
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
        if (version.isEmpty()) {
            qWarning("%s\n", qPrintable(errorMessage));
            return;
        }
        // Compare
        const double minVersion = 6.11;
        manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Version: %1").arg(version));
        if (version.toDouble() <  minVersion) {
            const QString msg = CdbDebugEngine::tr(
                    "<html>The installed version of the <i>Debugging Tools for Windows</i> (%1) "
                    "is rather old. Upgrading to version %2 is recommended "
                    "for the proper display of Qt's data types.</html>").arg(version).arg(minVersion);
            Core::ICore::instance()->showWarningWithOptions(CdbDebugEngine::tr("Debugger"), msg, QString(),
                                                            QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY),
                                                            CdbOptionsPage::settingsId());
        }
    }
}

hjk's avatar
hjk committed
350
void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
351
{
Friedemann Kleint's avatar
Friedemann Kleint committed
352
353
    if (debugCDBExecution)
        qDebug() << "startDebugger" << *sp;
354
    CdbCore::BreakPoint::clearNormalizeFileNameCache();
355
    setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
356
    m_d->checkVersion();
357
358
    if (m_d->m_hDebuggeeProcess) {
        warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
359
        setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
360
        emit startFailed();
361
        return;
362
    }
363
364
    switch (sp->startMode) {
    case AttachCore:
ck's avatar
ck committed
365
    case AttachToRemote:
366
367
368
369
370
371
372
373
        warning(QLatin1String("Internal error: Mode not supported."));
        setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
        emit startFailed();
        break;
    default:
        break;
    }
    m_d->m_mode = sp->startMode;
374
    m_d->clearDisplay();
Friedemann Kleint's avatar
Friedemann Kleint committed
375
    m_d->m_inferiorStartupComplete = false;
376
    setState(AdapterStarted, Q_FUNC_INFO, __LINE__);
377
378
379
380
    // Options
    QString errorMessage;
    if (!m_d->setBreakOnThrow(theDebuggerBoolSetting(BreakOnThrow), &errorMessage))
      manager()->showDebuggerOutput(LogWarning, errorMessage);
381
    m_d->setVerboseSymbolLoading(m_d->m_options->verboseSymbolLoading);
382
    // Figure out dumper. @TODO: same in gdb...
Friedemann Kleint's avatar
Friedemann Kleint committed
383
    const QString dumperLibName = QDir::toNativeSeparators(manager()->qtDumperLibraryName());
384
385
    bool dumperEnabled = m_d->m_mode != AttachCore
                         && m_d->m_mode != AttachCrashedExternal
Friedemann Kleint's avatar
Friedemann Kleint committed
386
                         && manager()->qtDumperLibraryEnabled();
387
388
389
    if (dumperEnabled) {
        const QFileInfo fi(dumperLibName);
        if (!fi.isFile()) {
Friedemann Kleint's avatar
Friedemann Kleint committed
390
            const QStringList &locations = manager()->qtDumperLibraryLocations();
391
392
            const QString loc = locations.join(QLatin1String(", "));
            const QString msg = tr("The dumper library was not found at %1.").arg(loc);
Friedemann Kleint's avatar
Friedemann Kleint committed
393
            manager()->showQtDumperLibraryWarning(msg);
394
395
396
            dumperEnabled = false;
        }
    }
397
    m_d->m_dumper->reset(dumperLibName, dumperEnabled);
398
399

    setState(InferiorStarting, Q_FUNC_INFO, __LINE__);
400
    manager()->showStatusMessage("Starting Debugger", messageTimeOut);
401

Friedemann Kleint's avatar
Friedemann Kleint committed
402
    bool rc = false;
403
    bool needWatchTimer = false;
404
    m_d->clearForRun();
405
    m_d->updateCodeLevel();
406
    m_d->m_ignoreInitialBreakPoint = false;
407
    switch (m_d->m_mode) {
Friedemann Kleint's avatar
Friedemann Kleint committed
408
    case AttachExternal:
409
    case AttachCrashedExternal:
410
        rc = startAttachDebugger(sp->attachPID, m_d->m_mode, &errorMessage);
411
        needWatchTimer = true; // Fetch away module load, etc. even if crashed
Friedemann Kleint's avatar
Friedemann Kleint committed
412
413
414
        break;
    case StartInternal:
    case StartExternal:
415
        if (sp->useTerminal) {
416
417
            // Attaching to console processes triggers an initial breakpoint, which we do not want
            m_d->m_ignoreInitialBreakPoint = true;
418
419
            // Launch console stub and wait for its startup
            m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
Friedemann Kleint's avatar
Friedemann Kleint committed
420
            m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDirectory);
421
422
            m_d->m_consoleStubProc.setEnvironment(sp->environment);
            rc = m_d->m_consoleStubProc.start(sp->executable, sp->processArgs);
423
            if (!rc)
424
                errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp->executable);
425
            // continues in slotConsoleStubStarted()...
426
        } else {
427
            needWatchTimer = true;
Friedemann Kleint's avatar
Friedemann Kleint committed
428
            rc = m_d->startDebuggerWithExecutable(sp->workingDirectory,
429
430
431
432
                                                  sp->executable,
                                                  sp->processArgs,
                                                  sp->environment,
                                                  &errorMessage);
433
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
434
435
        break;
    case AttachCore:
Friedemann Kleint's avatar
Friedemann Kleint committed
436
        errorMessage = tr("Attaching to core files is not supported!");
Friedemann Kleint's avatar
Friedemann Kleint committed
437
438
439
        break;
    }
    if (rc) {
440
        if (needWatchTimer)
441
            m_d->startWatchTimer();
442
            emit startSuccessful();
Friedemann Kleint's avatar
Friedemann Kleint committed
443
    } else {
444
        warning(errorMessage);
445
        setState(InferiorStartFailed, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
446
        emit startFailed();
447
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
448
}
Banana Joe's avatar
Banana Joe committed
449

450
bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
451
{
452
    // Need to attach invasively, otherwise, no notification signals
453
    // for for CreateProcess/ExitProcess occur.
454
455
456
457
458
459
460
461
    // Initial breakpoint occur:
    // 1) Desired: When attaching to a crashed process
    // 2) Undesired: When starting up a console process, in conjunction
    //    with the 32bit Wow-engine
    //  As of version 6.11, the flag only affects 1). 2) Still needs to be suppressed
    // by lookup at the state of the application (startup trap). However,
    // there is no startup trap when attaching to a process that has been
    // running for a while. (see notifyException).
462
    const bool suppressInitialBreakPoint = sm != AttachCrashedExternal;
463
    return m_d->startAttachDebugger(pid, suppressInitialBreakPoint, errorMessage);
Banana Joe's avatar
Banana Joe committed
464
465
}

466
void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
467
{
468
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
469
470
    setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle));
    ULONG currentThreadId;
471
    if (SUCCEEDED(interfaces().debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, &currentThreadId))) {
472
473
474
475
        m_currentThreadId = currentThreadId;
    } else {
        m_currentThreadId = 0;
    }
476
477
    // Clear any saved breakpoints and set initial breakpoints
    m_engine->executeDebuggerCommand(QLatin1String("bc"));
Friedemann Kleint's avatar
Friedemann Kleint committed
478
479
480
    if (manager()->breakHandler()->hasPendingBreakpoints()) {
        if (debugCDBExecution)
            qDebug() << "processCreatedAttached: Syncing breakpoints";
481
        m_engine->attemptBreakpointSynchronization();
Friedemann Kleint's avatar
Friedemann Kleint committed
482
    }
483
484
    // Attaching to crashed: This handshake (signalling an event) is required for
    // the exception to be delivered to the debugger
485
    // Also, see special handling in slotModulesLoaded().
486
    if (m_mode == AttachCrashedExternal) {
hjk's avatar
hjk committed
487
        const QString crashParameter = manager()->startParameters()->crashParameter;
488
489
        if (!crashParameter.isEmpty()) {
            ULONG64 evtNr = crashParameter.toULongLong();
490
            const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr);
491
            if (FAILED(hr))
492
                m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(CdbCore::msgComFailed("SetNotifyEventHandle", hr)));
493
494
        }
    }
495
    m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
Friedemann Kleint's avatar
Friedemann Kleint committed
496
    if (debugCDBExecution)
497
        qDebug() << "<processCreatedAttached";
498
499
}

500
501
void CdbDebugEngine::processTerminated(unsigned long exitCode)
{
502
    manager()->showDebuggerOutput(LogMisc, tr("The process exited with exit code %1.").arg(exitCode));
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
503
    if (state() != InferiorStopping)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
504
505
        setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
    setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
506
    setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__);
507
    m_d->setDebuggeeHandles(0, 0);
508
509
510
511
    m_d->clearForRun();
    setState(InferiorShutDown, Q_FUNC_INFO, __LINE__);
    // Avoid calls from event handler.
    QTimer::singleShot(0, manager(), SLOT(exitDebugger()));
512
513
}

514
bool CdbDebugEnginePrivate::endInferior(EndInferiorAction action, QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
515
{
516
517
    // Process must be stopped in order to terminate
    m_engine->setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__); // pretend it is shutdown
Friedemann Kleint's avatar
Friedemann Kleint committed
518
    const bool wasRunning = isDebuggeeRunning();
519
520
    if (wasRunning) {
        interruptInterferiorProcess(errorMessage);
Friedemann Kleint's avatar
Friedemann Kleint committed
521
        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
522
    }
523
    bool success = false;
Friedemann Kleint's avatar
Friedemann Kleint committed
524
    switch (action) {
525
526
    case DetachInferior:
            if (detachCurrentProcess(errorMessage))
527
528
                success = true;
            break;
529
    case TerminateInferior:
530
531
            do {
                // The exit process event handler will not be called.
532
                terminateCurrentProcess(errorMessage);
533
534
535
536
                if (wasRunning) {
                    success = true;
                    break;
                }
537
                if (terminateProcesses(errorMessage))
538
539
540
541
                    success = true;
            } while (false);
            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
            break;
Friedemann Kleint's avatar
Friedemann Kleint committed
542
    }
543
    // Perform cleanup even when failed..no point clinging to the process
Friedemann Kleint's avatar
Friedemann Kleint committed
544
    setDebuggeeHandles(0, 0);
545
    killWatchTimer();
546
547
548
    m_engine->setState(success ? InferiorShutDown : InferiorShutdownFailed, Q_FUNC_INFO, __LINE__);
    return success;
}
549

550
551
552
553
554
555
556
// End debugging. Note that this can invoked via user action
// or the processTerminated() event handler, in which case it
// must not kill the process again.
void CdbDebugEnginePrivate::endDebugging(EndDebuggingMode em)
{
    if (debugCDB)
        qDebug() << Q_FUNC_INFO << em;
557

558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
    const DebuggerState oldState = m_engine->state();
    if (oldState == DebuggerNotReady || m_mode == AttachCore)
        return;
    // Do we need to stop the process?
    QString errorMessage;
    if (oldState != InferiorShutDown && m_hDebuggeeProcess) {
        EndInferiorAction action;
        switch (em) {
        case EndDebuggingAuto:
            action = (m_mode == AttachExternal || m_mode == AttachCrashedExternal) ?
                     DetachInferior : TerminateInferior;
            break;
        case EndDebuggingDetach:
            action = DetachInferior;
            break;
        case EndDebuggingTerminate:
            action = TerminateInferior;
            break;
        }
        if (debugCDB)
            qDebug() << Q_FUNC_INFO << action;
        // Need a stopped debuggee to act
        if (!endInferior(action, &errorMessage)) {
            errorMessage = QString::fromLatin1("Unable to detach from/end the debuggee: %1").arg(errorMessage);
            manager()->showDebuggerOutput(LogError, errorMessage);
        }
        errorMessage.clear();
    }
    // Clean up resources (open files, etc.)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
587
    m_engine->setState(EngineShuttingDown, Q_FUNC_INFO, __LINE__);
588
    clearForRun();
589
    const bool endedCleanly = endSession(&errorMessage);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
590
    m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
591
592
    if (!endedCleanly) {
        errorMessage = QString::fromLatin1("There were errors trying to end debugging:\n%1").arg(errorMessage);
Friedemann Kleint's avatar
Friedemann Kleint committed
593
        manager()->showDebuggerOutput(LogError, errorMessage);
594
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
595
596
597
598
599
600
601
602
603
604
}

void CdbDebugEngine::exitDebugger()
{
    m_d->endDebugging();
}

void CdbDebugEngine::detachDebugger()
{
    m_d->endDebugging(CdbDebugEnginePrivate::EndDebuggingDetach);
Banana Joe's avatar
Banana Joe committed
605
606
}

607
CdbSymbolGroupContext *CdbDebugEnginePrivate::getSymbolGroupContext(int frameIndex, QString *errorMessage) const
608
609
610
611
612
{
    if (!m_currentStackTrace) {
        *errorMessage = QLatin1String(msgNoStackTraceC);
        return 0;
    }
613
    if (CdbSymbolGroupContext *sg = m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, errorMessage))
614
615
616
617
618
619
620
621
622
623
624
        return sg;
    return 0;
}

void CdbDebugEngine::evaluateWatcher(WatchData *wd)
{
    if (debugCDBWatchHandling)
        qDebug() << Q_FUNC_INFO << wd->exp;
    QString errorMessage;
    QString value;
    QString type;
625
626
627
628
629
    QString exp = wd->exp;
    // Remove locals watch prefix.
    if (exp.startsWith(QLatin1String("local.")))
        exp.remove(0, 6);
    if (m_d->evaluateExpression(exp, &value, &type, &errorMessage)) {
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
        wd->setValue(value);
        wd->setType(type);
    } else {
        wd->setValue(errorMessage);
        wd->setTypeUnneeded();
    }
    wd->setHasChildren(false);
}

void CdbDebugEngine::updateWatchData(const WatchData &incomplete)
{
    // Watch item was edited while running
    if (m_d->isDebuggeeRunning())
        return;

    if (debugCDBWatchHandling)
        qDebug() << Q_FUNC_INFO << "\n    " << incomplete.toString();

Friedemann Kleint's avatar
Friedemann Kleint committed
648
    WatchHandler *watchHandler = manager()->watchHandler();
649
    if (incomplete.iname.startsWith("watch.")) {
650
651
652
653
654
655
        WatchData watchData = incomplete;
        evaluateWatcher(&watchData);
        watchHandler->insertData(watchData);
        return;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
656
    const int frameIndex = manager()->stackHandler()->currentIndex();
657
658
659
660

    bool success = false;
    QString errorMessage;
    do {
661
        CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
662
663
664
665
666
667
668
669
        if (!sg)
            break;
        if (!sg->completeData(incomplete, watchHandler, &errorMessage))
            break;
        success = true;
    } while (false);
    if (!success)
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
670
    if (debugCDBWatchHandling > 1)
Friedemann Kleint's avatar
Friedemann Kleint committed
671
        qDebug() << *manager()->watchHandler()->model(LocalsWatch);
672
673
}

674
675
676
677
678
679
680
// Continue inferior with a debugger command, such as "p", "pt"
// or its thread variations
bool CdbDebugEnginePrivate::executeContinueCommand(const QString &command)
{
    if (debugCDB)
        qDebug() << Q_FUNC_INFO << command;
    clearForRun();
681
    updateCodeLevel(); // Step by instruction
682
683
684
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
    manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Continuing with '%1'...").arg(command));
    QString errorMessage;
685
    const bool success = executeDebuggerCommand(command, &errorMessage);
686
687
    if (success) {
        m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
688
        startWatchTimer();
689
690
691
692
693
694
695
    } else {
        m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
        m_engine->warning(CdbDebugEngine::tr("Unable to continue: %1").arg(errorMessage));
    }
    return success;
}

696
697
698
699
700
701
702
static inline QString msgStepFailed(unsigned long executionStatus, int threadId, const QString &why)
{
    if (executionStatus ==  DEBUG_STATUS_STEP_OVER)
        return QString::fromLatin1("Thread %1: Unable to step over: %2").arg(threadId).arg(why);
    return QString::fromLatin1("Thread %1: Unable to step into: %2").arg(threadId).arg(why);
}

Friedemann Kleint's avatar
Friedemann Kleint committed
703
704
705
706
707
708
// Step out has to be done via executing 'gu'. TODO: Remove once it is
// accessible via normal API for SetExecutionStatus().

enum { CdbExtendedExecutionStatusStepOut = 7452347 };

// Step with  DEBUG_STATUS_STEP_OVER ('p'-command),
709
// DEBUG_STATUS_STEP_INTO ('t'-trace-command) or
Friedemann Kleint's avatar
Friedemann Kleint committed
710
// CdbExtendedExecutionStatusStepOut ("gu"-command)
711
// its reverse equivalents in the case of single threads.
Friedemann Kleint's avatar
Friedemann Kleint committed
712

713
bool CdbDebugEngine::step(unsigned long executionStatus)
Banana Joe's avatar
Banana Joe committed
714
{
Friedemann Kleint's avatar
Friedemann Kleint committed
715
716
    if (debugCDBExecution)
        qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId;
Friedemann Kleint's avatar
Friedemann Kleint committed
717

718
719
720
721
722
723
724
725
    // State of reverse stepping as of 10/2009 (Debugging tools 6.11@404):
    // The constants exist, but invoking the calls leads to E_NOINTERFACE.
    // Also there is no CDB command for it.
    if (executionStatus == DEBUG_STATUS_REVERSE_STEP_OVER || executionStatus == DEBUG_STATUS_REVERSE_STEP_INTO) {
        warning(tr("Reverse stepping is not implemented."));
        return false;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
726
727
728
729
730
731
    // Do not step the artifical thread created to interrupt the debuggee.
    if (m_d->m_interrupted && m_d->m_currentThreadId == m_d->m_interruptArticifialThreadId) {
        warning(tr("Thread %1 cannot be stepped.").arg(m_d->m_currentThreadId));
        return false;
    }

732
733
734
735
736
737
738
739
740
    // SetExecutionStatus() continues the thread that triggered the
    // stop event (~# p). This can be confusing if the user is looking
    // at the stack trace of another thread and wants to step that one. If that
    // is the case, explicitly tell it to step the current thread using a command.
    const int triggeringEventThread = m_d->m_eventThreadId;
    const bool sameThread = triggeringEventThread == -1
                            || m_d->m_currentThreadId == triggeringEventThread
                            || manager()->threadsHandler()->threads().size() == 1;
    m_d->clearForRun(); // clears thread ids
741
    m_d->updateCodeLevel(); // Step by instruction or source line
742
    setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
743
    bool success = false;
Friedemann Kleint's avatar
Friedemann Kleint committed
744
    if (sameThread && executionStatus != CdbExtendedExecutionStatusStepOut) { // Step event-triggering thread, use fast API
745
        const HRESULT hr = m_d->interfaces().debugControl->SetExecutionStatus(executionStatus);
746
747
        success = SUCCEEDED(hr);
        if (!success)
748
            warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, CdbCore::msgComFailed("SetExecutionStatus", hr)));
749
750
751
752
    } else {
        // Need to use a command to explicitly specify the current thread
        QString command;
        QTextStream str(&command);
Friedemann Kleint's avatar
Friedemann Kleint committed
753
754
755
756
757
758
        str << '~' << m_d->m_currentThreadId << ' ';
        switch (executionStatus) {
        case DEBUG_STATUS_STEP_OVER:
            str << 'p';
            break;
        case DEBUG_STATUS_STEP_INTO:
759
            str << 't';
Friedemann Kleint's avatar
Friedemann Kleint committed
760
761
762
763
764
            break;
        case CdbExtendedExecutionStatusStepOut:
            str << "gu";
            break;
        }
765
        manager()->showDebuggerOutput(tr("Stepping %1").arg(command));
766
        const HRESULT hr = m_d->interfaces().debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO);
767
768
769
770
771
        success = SUCCEEDED(hr);
        if (!success)
            warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgDebuggerCommandFailed(command, hr)));
    }
    if (success) {
772
773
774
        // Oddity: Step into will first break at the calling function. Ignore
        if (executionStatus == DEBUG_STATUS_STEP_INTO || executionStatus == DEBUG_STATUS_REVERSE_STEP_INTO)
            m_d->m_breakEventMode = CdbDebugEnginePrivate::BreakEventIgnoreOnce;
775
        m_d->startWatchTimer();
776
777
778
779
        setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
    } else {
        setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
780
781
    if (debugCDBExecution)
        qDebug() << "<step samethread" << sameThread << "succeeded" << success;
782
783
784
    return success;
}

hjk's avatar
hjk committed
785
void CdbDebugEngine::executeStep()
786
787
788
789
{
    step(manager()->isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_INTO : DEBUG_STATUS_STEP_INTO);
}

hjk's avatar
hjk committed
790
void CdbDebugEngine::executeNext()
791
792
793
794
{
    step(manager()->isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_OVER : DEBUG_STATUS_STEP_OVER);
}

hjk's avatar
hjk committed
795
void CdbDebugEngine::executeStepI()
796
{
hjk's avatar
hjk committed
797
    executeStep(); // Step into by instruction (figured out by step)
798
799
}

hjk's avatar
hjk committed
800
void CdbDebugEngine::executeNextI()
801
{
hjk's avatar
hjk committed
802
    executeNext(); // Step over by instruction (figured out by step)
Banana Joe's avatar
Banana Joe committed
803
804
}

hjk's avatar
hjk committed
805
void CdbDebugEngine::executeStepOut()
Banana Joe's avatar
Banana Joe committed
806
{
Friedemann Kleint's avatar
Friedemann Kleint committed
807
808
    if (!manager()->isReverseDebugging())
        step(CdbExtendedExecutionStatusStepOut);
Banana Joe's avatar
Banana Joe committed
809
810
}

hjk's avatar
hjk committed
811
void CdbDebugEngine::continueInferior()
812
{
813
    QString errorMessage;
814
    if  (!m_d->continueInferior(&errorMessage))
815
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
816
817
818
}

// Continue process without notifications
819
bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /* = 0 */)
Banana Joe's avatar
Banana Joe committed
820
{
Friedemann Kleint's avatar
Friedemann Kleint committed
821
822
    if (debugCDBExecution)
        qDebug() << "continueInferiorProcess";
823
    const HRESULT hr = interfaces().debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
824
    if (FAILED(hr)) {
825
        const QString errorMessage = CdbCore::msgComFailed("SetExecutionStatus", hr);
826
827
828
        if (errorMessagePtr) {
            *errorMessagePtr = errorMessage;
        } else {
829
            m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
830
        }
831
832
833
834
        return false;
    }
    return  true;
}
Friedemann Kleint's avatar
Friedemann Kleint committed
835

836
837
// Continue process with notifications
bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
838
{
839
    // Check state: Are we running?
840
    const ULONG ex = executionStatus();
841
    if (debugCDB)
842
        qDebug() << Q_FUNC_INFO << "\n    ex=" << ex;
843

844
    if (ex == DEBUG_STATUS_GO) {
845
        m_engine->warning(QLatin1String("continueInferior() called while debuggee is running."));
846
        return true;
847
    }
848
849
850
851
852
    // Request continue
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
    bool success = false;
    do {
        clearForRun();
853
854
        updateCodeLevel();
        killWatchTimer();
855
        manager()->resetLocation();
856
        manager()->showStatusMessage(CdbDebugEngine::tr("Running requested..."), messageTimeOut);
857

858
859
        if (!continueInferiorProcess(errorMessage))
            break;
860

861
        startWatchTimer();
862
863
864
865
866
867
868
        success = true;
    } while (false);
    if (success) {
        m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
    } else {
        m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__); // No RunningRequestFailed?
    }
869
    return true;
Banana Joe's avatar
Banana Joe committed
870
871
}

872
bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
873
{
Friedemann Kleint's avatar
Friedemann Kleint committed
874

875
    // Interrupt the interferior process without notifications
876
    // Could use setInterrupt, but that does not work.
Friedemann Kleint's avatar
Friedemann Kleint committed
877
    if (debugCDBExecution) {
878
        qDebug() << "interruptInterferiorProcess  ex=" << executionStatus();
879
    }
880
881
    const bool rc = debugBreakProcess(m_hDebuggeeProcess, errorMessage);
    if (rc)
882
        m_interrupted = true;
883
    return rc;
884
}
Friedemann Kleint's avatar
Friedemann Kleint committed
885

886
887
888
889
890
891
892
893
894
895
void CdbDebugEnginePrivate::slotModulesLoaded()
{
    // Attaching to crashed windows processes: Unless QtCreator is
    // spawned by the debug handler and inherits the handles,
    // the event handling does not work reliably (that is, the crash
    // event is not delivered). In that case, force a break
    if (m_mode == AttachCrashedExternal && m_engine->state() != InferiorStopped)
        QTimer::singleShot(10, m_engine, SLOT(slotBreakAttachToCrashed()));
}

896