cdbdebugengine.cpp 55.4 KB
Newer Older
1
/**************************************************************************
2
3
4
**
** This file is part of Qt Creator
**
5
** Copyright (c) 2009 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>
hjk's avatar
hjk committed
61

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

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

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

namespace Debugger {
namespace Internal {

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

84
85
// ----- Message helpers

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

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

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

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// 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);
}

114
115
// ----- Engine helpers

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

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

bool CdbDebugEnginePrivate::init(QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
141
{
142
    enum {  bufLen = 10240 };
143

144
    if (!CdbCore::CoreEngine::init(m_options->path, errorMessage))
145
        return false;
146
147
148
149
150
151
152
153
154
155
156
157
158
    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)));
    connect(output, SIGNAL(debuggeeOutput(QString)),
            manager(), SLOT(showApplicationOutput(QString)));
    connect(output, SIGNAL(debuggeeInputPrompt(QString)),
            manager(), SLOT(showApplicationOutput(QString)));

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

160
    return true;
Friedemann Kleint's avatar
Friedemann Kleint committed
161
}
Banana Joe's avatar
Banana Joe committed
162

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

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

183
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
Banana Joe's avatar
Banana Joe committed
184
{
185
    cleanStackTrace();
Banana Joe's avatar
Banana Joe committed
186
187
}

Friedemann Kleint's avatar
Friedemann Kleint committed
188
189
190
191
192
DebuggerManager *CdbDebugEnginePrivate::manager() const
{
    return m_engine->manager();
}

193
void CdbDebugEnginePrivate::clearForRun()
194
195
196
197
{
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

198
    m_breakEventMode = BreakEventHandle;
Friedemann Kleint's avatar
Friedemann Kleint committed
199
    m_eventThreadId = m_interruptArticifialThreadId = -1;
200
    m_interrupted = false;
201
202
203
204
    cleanStackTrace();
}

void CdbDebugEnginePrivate::cleanStackTrace()
205
{
206
207
208
209
    if (m_currentStackTrace) {
        delete m_currentStackTrace;
        m_currentStackTrace = 0;
    }
210
211
    m_firstActivatedFrame = false;
    m_editorToolTipCache.clear();
212
213
}

hjk's avatar
hjk committed
214
CdbDebugEngine::CdbDebugEngine(DebuggerManager *manager, const QSharedPointer<CdbOptions> &options) :
Friedemann Kleint's avatar
Friedemann Kleint committed
215
216
    IDebuggerEngine(manager),
    m_d(new CdbDebugEnginePrivate(manager, options, this))
217
{
218
    m_d->m_consoleStubProc.setMode(Utils::ConsoleProcess::Suspend);
hjk's avatar
hjk committed
219
220
221
222
223
224
    connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)),
            this, SLOT(slotConsoleStubError(QString)));
    connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()),
            this, SLOT(slotConsoleStubStarted()));
    connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()),
            this, SLOT(slotConsoleStubTerminated()));
225
226
227
228
229
230
231
}

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

232
233
234
235
236
237
238
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
239
void CdbDebugEngine::shutdown()
Banana Joe's avatar
Banana Joe committed
240
241
242
243
{
    exitDebugger();
}

244
QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &function)
Banana Joe's avatar
Banana Joe committed
245
{
246
247
248
249
250
251
    // 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
252
    CdbSymbolGroupContext *frame = 0;
253
254
    if (m_d->m_currentStackTrace &&  !function.isEmpty()) {
        const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
255
256
        if (debugToolTips)
            qDebug() << "CdbDebugEngine::editorToolTip" << exp << function << frameIndex;
257
        if (frameIndex != -1)
258
            frame = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
259
    }
260
261
    if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
        return rc;
262
263
264
    // 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;
265
266
    if (debugToolTips)
        qDebug() << "Defaulting to expression";
267
    if (!m_d->evaluateExpression(exp, &rc, &type, &errorMessage))
268
269
270
271
272
273
274
        return QString();
    return rc;
}

void CdbDebugEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
{
    typedef CdbDebugEnginePrivate::EditorToolTipCache EditorToolTipCache;
275
    if (debugCDB)
276
277
278
279
280
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
        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
308
309
}

310
311
void CdbDebugEnginePrivate::clearDisplay()
{
Friedemann Kleint's avatar
Friedemann Kleint committed
312
313
314
    manager()->threadsHandler()->removeAll();
    manager()->modulesHandler()->removeAll();
    manager()->registerHandler()->removeAll();
315
316
}

317
318
319
320
321
322
323
324
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;
325
        const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, dbengDLL(), &errorMessage);
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
        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
345
void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
346
{
Friedemann Kleint's avatar
Friedemann Kleint committed
347
348
    if (debugCDBExecution)
        qDebug() << "startDebugger" << *sp;
349
    CdbCore::BreakPoint::clearNormalizeFileNameCache();
350
    setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
351
    m_d->checkVersion();
352
353
    if (m_d->m_hDebuggeeProcess) {
        warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
354
        setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
355
        emit startFailed();
356
        return;
357
    }
358
    m_d->clearDisplay();
Friedemann Kleint's avatar
Friedemann Kleint committed
359
    m_d->m_inferiorStartupComplete = false;
360
    setState(AdapterStarted, Q_FUNC_INFO, __LINE__);
361

362
    m_d->setVerboseSymbolLoading(m_d->m_options->verboseSymbolLoading);
Friedemann Kleint's avatar
Friedemann Kleint committed
363
    const DebuggerStartMode mode = sp->startMode;
364
    // Figure out dumper. @TODO: same in gdb...
Friedemann Kleint's avatar
Friedemann Kleint committed
365
    const QString dumperLibName = QDir::toNativeSeparators(manager()->qtDumperLibraryName());
366
367
    bool dumperEnabled = mode != AttachCore
                         && mode != AttachCrashedExternal
Friedemann Kleint's avatar
Friedemann Kleint committed
368
                         && manager()->qtDumperLibraryEnabled();
369
370
371
    if (dumperEnabled) {
        const QFileInfo fi(dumperLibName);
        if (!fi.isFile()) {
Friedemann Kleint's avatar
Friedemann Kleint committed
372
            const QStringList &locations = manager()->qtDumperLibraryLocations();
373
374
            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
375
            manager()->showQtDumperLibraryWarning(msg);
376
377
378
            dumperEnabled = false;
        }
    }
379
    m_d->m_dumper->reset(dumperLibName, dumperEnabled);
380
381

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

Friedemann Kleint's avatar
Friedemann Kleint committed
384
385
    QString errorMessage;
    bool rc = false;
386
    bool needWatchTimer = false;
387
    m_d->clearForRun();
388
    m_d->updateCodeLevel();
389
    m_d->m_ignoreInitialBreakPoint = false;
390
    switch (mode) {
Friedemann Kleint's avatar
Friedemann Kleint committed
391
    case AttachExternal:
392
    case AttachCrashedExternal:
393
        rc = m_d->startAttachDebugger(sp->attachPID, mode, &errorMessage);
394
        needWatchTimer = true; // Fetch away module load, etc. even if crashed
Friedemann Kleint's avatar
Friedemann Kleint committed
395
396
397
        break;
    case StartInternal:
    case StartExternal:
398
        if (sp->useTerminal) {
399
400
            // Attaching to console processes triggers an initial breakpoint, which we do not want
            m_d->m_ignoreInitialBreakPoint = true;
401
402
            // Launch console stub and wait for its startup
            m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
403
404
405
            m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDir);
            m_d->m_consoleStubProc.setEnvironment(sp->environment);
            rc = m_d->m_consoleStubProc.start(sp->executable, sp->processArgs);
406
            if (!rc)
407
                errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp->executable);
408
            // continues in slotConsoleStubStarted()...
409
        } else {
410
            needWatchTimer = true;
411
412
            rc = startDebuggerWithExecutable(mode, &errorMessage);
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
413
414
        break;
    case AttachCore:
Friedemann Kleint's avatar
Friedemann Kleint committed
415
        errorMessage = tr("Attaching to core files is not supported!");
Friedemann Kleint's avatar
Friedemann Kleint committed
416
417
418
        break;
    }
    if (rc) {
419
        if (needWatchTimer)
420
            m_d->startWatchTimer();
421
            emit startSuccessful();
Friedemann Kleint's avatar
Friedemann Kleint committed
422
    } else {
423
        warning(errorMessage);
424
        setState(InferiorStartFailed, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
425
        emit startFailed();
426
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
427
}
Banana Joe's avatar
Banana Joe committed
428

429
bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
430
{
431
    // Need to attach invasively, otherwise, no notification signals
432
    // for for CreateProcess/ExitProcess occur.
433
434
435
436
437
438
439
440
    // 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).
441
442
443
    const bool suppressInitialBreakPoint = sm != AttachCrashedExternal;
    const bool rc = m_d->startAttachDebugger(pid, suppressInitialBreakPoint, errorMessage);
    if (rc)
444
        m_d->m_mode = sm;
445
    return rc;
Friedemann Kleint's avatar
Friedemann Kleint committed
446
447
}

448
bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
449
{
hjk's avatar
hjk committed
450
    const QSharedPointer<DebuggerStartParameters> sp = manager()->startParameters();
451
452
453
454
455
456
    const bool rc = m_d->startDebuggerWithExecutable(sp->workingDir,
                                                     sp->executable,
                                                     sp->processArgs,
                                                     sp->environment,
                                                     errorMessage);
    if (rc)
457
        m_d->m_mode = sm;
458
    return rc;
Banana Joe's avatar
Banana Joe committed
459
460
}

461
void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
462
{
463
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
464
465
    setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle));
    ULONG currentThreadId;
466
    if (SUCCEEDED(interfaces().debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, &currentThreadId))) {
467
468
469
470
        m_currentThreadId = currentThreadId;
    } else {
        m_currentThreadId = 0;
    }
471
472
    // Clear any saved breakpoints and set initial breakpoints
    m_engine->executeDebuggerCommand(QLatin1String("bc"));
Friedemann Kleint's avatar
Friedemann Kleint committed
473
474
475
    if (manager()->breakHandler()->hasPendingBreakpoints()) {
        if (debugCDBExecution)
            qDebug() << "processCreatedAttached: Syncing breakpoints";
476
        m_engine->attemptBreakpointSynchronization();
Friedemann Kleint's avatar
Friedemann Kleint committed
477
    }
478
479
480
    // Attaching to crashed: This handshake (signalling an event) is required for
    // the exception to be delivered to the debugger
    if (m_mode == AttachCrashedExternal) {
hjk's avatar
hjk committed
481
        const QString crashParameter = manager()->startParameters()->crashParameter;
482
483
        if (!crashParameter.isEmpty()) {
            ULONG64 evtNr = crashParameter.toULongLong();
484
            const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr);
485
486
487
488
489
490
            // Unless QtCreator is spawned by the debugger and inherits the handles,
            // the event handling does not work reliably
            // (that is, the crash event is not delivered).
            if (SUCCEEDED(hr)) {
                QTimer::singleShot(0, m_engine, SLOT(slotBreakAttachToCrashed()));
            } else {
491
                m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(CdbCore::msgComFailed("SetNotifyEventHandle", hr)));
492
            }
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
    if (m_d->evaluateExpression(wd->exp, &value, &type, &errorMessage)) {
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
        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
644
    WatchHandler *watchHandler = manager()->watchHandler();
645
    if (incomplete.iname.startsWith("watch.")) {
646
647
648
649
650
651
        WatchData watchData = incomplete;
        evaluateWatcher(&watchData);
        watchHandler->insertData(watchData);
        return;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
652
    const int frameIndex = manager()->stackHandler()->currentIndex();
653
654
655
656

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

670
671
672
673
674
675
676
// 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();
677
    updateCodeLevel(); // Step by instruction
678
679
680
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
    manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Continuing with '%1'...").arg(command));
    QString errorMessage;
681
    const bool success = executeDebuggerCommand(command, &errorMessage);
682
683
    if (success) {
        m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
684
        startWatchTimer();
685
686
687
688
689
690
691
    } else {
        m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
        m_engine->warning(CdbDebugEngine::tr("Unable to continue: %1").arg(errorMessage));
    }
    return success;
}

692
693
694
695
696
697
698
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
699
700
701
702
703
704
// 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),
705
// DEBUG_STATUS_STEP_INTO ('t'-trace-command) or
Friedemann Kleint's avatar
Friedemann Kleint committed
706
// CdbExtendedExecutionStatusStepOut ("gu"-command)
707
// its reverse equivalents in the case of single threads.
Friedemann Kleint's avatar
Friedemann Kleint committed
708

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

714
715
716
717
718
719
720
721
    // 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
722
723
724
725
726
727
    // 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;
    }

728
729
730
731
732
733
734
735
736
    // 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
737
    m_d->updateCodeLevel(); // Step by instruction or source line
738
    setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
739
    bool success = false;
Friedemann Kleint's avatar
Friedemann Kleint committed
740
    if (sameThread && executionStatus != CdbExtendedExecutionStatusStepOut) { // Step event-triggering thread, use fast API
741
        const HRESULT hr = m_d->interfaces().debugControl->SetExecutionStatus(executionStatus);
742
743
        success = SUCCEEDED(hr);
        if (!success)
744
            warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, CdbCore::msgComFailed("SetExecutionStatus", hr)));
745
746
747
748
    } else {
        // Need to use a command to explicitly specify the current thread
        QString command;
        QTextStream str(&command);
Friedemann Kleint's avatar
Friedemann Kleint committed
749
750
751
752
753
754
        str << '~' << m_d->m_currentThreadId << ' ';
        switch (executionStatus) {
        case DEBUG_STATUS_STEP_OVER:
            str << 'p';
            break;
        case DEBUG_STATUS_STEP_INTO:
755
            str << 't';
Friedemann Kleint's avatar
Friedemann Kleint committed
756
757
758
759
760
            break;
        case CdbExtendedExecutionStatusStepOut:
            str << "gu";
            break;
        }
761
        manager()->showDebuggerOutput(tr("Stepping %1").arg(command));
762
        const HRESULT hr = m_d->interfaces().debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO);
763
764
765
766
767
        success = SUCCEEDED(hr);
        if (!success)
            warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgDebuggerCommandFailed(command, hr)));
    }
    if (success) {
768
769
770
        // 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;
771
        m_d->startWatchTimer();
772
773
774
775
        setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
    } else {
        setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
776
777
    if (debugCDBExecution)
        qDebug() << "<step samethread" << sameThread << "succeeded" << success;
778
779
780
781
782
783
784
785
786
787
788
789
790
791
    return success;
}

void CdbDebugEngine::stepExec()
{
    step(manager()->isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_INTO : DEBUG_STATUS_STEP_INTO);
}

void CdbDebugEngine::nextExec()
{
    step(manager()->isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_OVER : DEBUG_STATUS_STEP_OVER);
}

void CdbDebugEngine::stepIExec()
792
{
793
794
795
796
797
798
    stepExec(); // Step into by instruction (figured out by step)
}

void CdbDebugEngine::nextIExec()
{
    nextExec(); // Step over by instruction (figured out by step)
Banana Joe's avatar
Banana Joe committed
799
800
}

hjk's avatar
hjk committed
801
void CdbDebugEngine::stepOutExec()
Banana Joe's avatar
Banana Joe committed
802
{
Friedemann Kleint's avatar
Friedemann Kleint committed
803
804
    if (!manager()->isReverseDebugging())
        step(CdbExtendedExecutionStatusStepOut);
Banana Joe's avatar
Banana Joe committed
805
806
}

hjk's avatar
hjk committed
807
void CdbDebugEngine::continueInferior()
808
{
809
    QString errorMessage;
810
    if  (!m_d->continueInferior(&errorMessage))
811
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
812
813
814
}

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

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

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

854
855
        if (!continueInferiorProcess(errorMessage))
            break;
856

857
        startWatchTimer();
858
859
860
861
862
863
864
        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?
    }
865
    return true;
Banana Joe's avatar
Banana Joe committed
866
867
}

868
bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
869
{
Friedemann Kleint's avatar
Friedemann Kleint committed
870

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

882
883
884
885
886
887
888
889
890
891
892
void CdbDebugEngine::slotBreakAttachToCrashed()
{
    // Force a break when attaching to crashed process (if Creator was not spawned
    // from handler).
    if (state() != InferiorStopped) {
        manager()->showDebuggerOutput(LogMisc, QLatin1String("Forcing break..."));
        m_d->m_dumper->disable();
        interruptInferior();
    }
}

893
894
895
void CdbDebugEngine::interruptInferior()
{
    if (!m_d->m_hDebuggeeProcess || !m_d->isDebuggeeRunning())
Banana Joe's avatar
Banana Joe committed
896
        return;
897
898

    QString errorMessage;
899
900
901
    setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
    if (!m_d->interruptInterferiorProcess(&errorMessage)) {
        setState(InferiorStopFailed, Q_FUNC_INFO, __LINE__);
902
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
Banana Joe's avatar
Banana Joe committed
903
904
905
    }
}

hjk's avatar
hjk committed
906
void CdbDebugEngine::runToLineExec(const QString &fileName, int lineNumber)
Banana Joe's avatar
Banana Joe committed
907
{
908
909
    manager()->showDebuggerOutput(LogMisc, tr("Running up to %1:%2...").arg(fileName).arg(lineNumber));
    QString errorMessage;
910
    CdbCore::BreakPoint tempBreakPoint;
911
912
913
    tempBreakPoint.fileName = fileName;
    tempBreakPoint.lineNumber = lineNumber;
    tempBreakPoint.oneShot = true;
914
    const bool ok = tempBreakPoint.add(m_d->interfaces().debugControl, &errorMessage)
915
916
917
                    && m_d->continueInferior(&errorMessage);
    if (!ok)
        warning(errorMessage);
Banana Joe's avatar
Banana Joe committed
918
919
}

hjk's avatar
hjk committed
920
void CdbDebugEngine::runToFunctionExec(const QString &functionName)
Banana Joe's avatar
Banana Joe committed