cdbdebugengine.cpp 61.4 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 "cdbsymbolpathlisteditor.h"
43
#include "debuggeragents.h"
Robert Loehning's avatar
Robert Loehning committed
44
45
#include "debuggeruiswitcher.h"
#include "debuggermainwindow.h"
Banana Joe's avatar
Banana Joe committed
46

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

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

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

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

81
82
83
84
85
static const char *localSymbolRootC = "local";

namespace Debugger {
namespace Internal {

86
CdbOptionsPage *theOptionsPage = 0;
Friedemann Kleint's avatar
Friedemann Kleint committed
87
88
typedef QList<WatchData> WatchList;

89
90
// ----- Message helpers

91
92
93
94
95
static QString msgStackIndexOutOfRange(int idx, int size)
{
    return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
}

96
97
QString msgDebuggerCommandFailed(const QString &command, HRESULT hr)
{
98
    return QString::fromLatin1("Unable to execute '%1': %2").arg(command, CdbCore::msgDebugEngineComResult(hr));
99
100
}

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

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// 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);
}

119
120
// ----- Engine helpers

Friedemann Kleint's avatar
Friedemann Kleint committed
121
122
// --- CdbDebugEnginePrivate

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

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

149
    if (!CdbCore::CoreEngine::init(m_options->path, errorMessage))
150
        return false;
151
152
153
154
    CdbDebugOutput *output = new CdbDebugOutput;
    connect(output, SIGNAL(showMessage(QString,int,int)),
            m_engine, SLOT(showMessage(QString,int,int)),
            Qt::QueuedConnection); // Multithread invocation when loading dumpers.
155
156
157
    setDebugOutput(DebugOutputBasePtr(output));
    setDebugEventCallback(DebugEventCallbackBasePtr(new CdbDebugEventCallback(m_engine)));
    updateCodeLevel();
158

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

162
163
DebuggerEngine *CdbDebugEngine::create(const DebuggerStartParameters &sp,
                                       QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
164
{
165
    CdbDebugEngine *rc = new CdbDebugEngine(sp);
166
167
    if (rc->m_d->init(errorMessage)) {
        rc->syncDebuggerPaths();
168
        return rc;
169
    }
170
171
    delete rc;
    return 0;
Banana Joe's avatar
Banana Joe committed
172
173
}

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

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

186
void CdbDebugEnginePrivate::clearForRun()
187
188
189
190
{
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

191
    m_breakEventMode = BreakEventHandle;
Friedemann Kleint's avatar
Friedemann Kleint committed
192
    m_eventThreadId = m_interruptArticifialThreadId = -1;
193
    m_interrupted = false;
194
    cleanStackTrace();
195
196
    m_stoppedReason = StoppedOther;
    m_stoppedMessage.clear();
197
    m_engine->threadsHandler()->notifyRunning();
198
199
200
}

void CdbDebugEnginePrivate::cleanStackTrace()
201
{
202
203
204
205
    if (m_currentStackTrace) {
        delete m_currentStackTrace;
        m_currentStackTrace = 0;
    }
206
207
    m_firstActivatedFrame = false;
    m_editorToolTipCache.clear();
208
209
}

210
CdbDebugEngine::CdbDebugEngine(const DebuggerStartParameters &startParameters) :
Friedemann Kleint's avatar
Friedemann Kleint committed
211
    DebuggerEngine(startParameters),
212
    m_d(new CdbDebugEnginePrivate(this))
213
{
214
    m_d->m_consoleStubProc.setMode(Utils::ConsoleProcess::Suspend);
215
216
    connect(&m_d->m_consoleStubProc, SIGNAL(processMessage(QString,bool)),
            this, SLOT(slotConsoleStubMessage(QString, bool)));
hjk's avatar
hjk committed
217
218
219
220
    connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()),
            this, SLOT(slotConsoleStubStarted()));
    connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()),
            this, SLOT(slotConsoleStubTerminated()));
221
222
223
224
225
226
227
}

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

228
229
230
231
void CdbDebugEngine::setState(DebuggerState state, const char *func, int line)
{
    if (debugCDB)
        qDebug() << "setState(" << state << ") at " << func << ':' << line;
232
    DebuggerEngine::setState(state);
233
234
}

hjk's avatar
hjk committed
235
void CdbDebugEngine::shutdown()
Banana Joe's avatar
Banana Joe committed
236
237
238
239
{
    exitDebugger();
}

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

void CdbDebugEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
{
    typedef CdbDebugEnginePrivate::EditorToolTipCache EditorToolTipCache;
271
    if (debugCDB)
272
273
274
275
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
        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
304
305
}

306
307
void CdbDebugEnginePrivate::clearDisplay()
{
308
309
310
    m_engine->threadsHandler()->removeAll();
    m_engine->modulesHandler()->removeAll();
    m_engine->registerHandler()->removeAll();
311
312
}

313
314
315
316
317
318
319
320
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;
321
        const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, dbengDLL(), &errorMessage);
322
323
324
325
326
327
        if (version.isEmpty()) {
            qWarning("%s\n", qPrintable(errorMessage));
            return;
        }
        // Compare
        const double minVersion = 6.11;
Robert Loehning's avatar
Robert Loehning committed
328
        m_engine->showMessage(CdbDebugEngine::tr("Version: %1").arg(version));
329
330
331
332
333
334
335
336
337
338
339
340
        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());
        }
    }
}

341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
void CdbDebugEngine::startupChecks()
{
    // Check symbol server unless the user has an external/internal setup
    if (!qgetenv("_NT_SYMBOL_PATH").isEmpty()
        || CdbOptions::indexOfSymbolServerPath(m_d->m_options->symbolPaths) != -1)
        return;
    // Prompt to use Symbol server unless the user checked "No nagging".
    Core::ICore *core = Core::ICore::instance();
    const QString nagSymbolServerKey = CdbOptions::settingsGroup() + QLatin1String("/NoPromptSymbolServer");
    bool noFurtherNagging = core->settings()->value(nagSymbolServerKey, false).toBool();
    if (noFurtherNagging)
        return;

    const QString symServUrl = QLatin1String("http://support.microsoft.com/kb/311503");
    const QString msg = tr("<html><head/><body><p>The debugger is not configured to use the public "
                           "<a href=\"%1\">Microsoft Symbol Server</a>. This is recommended "
                           "for retrieval of the symbols of the operating system libraries.</p>"
                           "<p><i>Note:</i> A fast internet connection is required for this to work smoothly. Also, a delay "
                           "might occur when connecting for the first time.</p>"
                           "<p>Would you like to set it up?</p></br>"
                           "</body></html>").arg(symServUrl);
    const QDialogButtonBox::StandardButton answer =
            Utils::CheckableMessageBox::question(core->mainWindow(), tr("Symbol Server"), msg,
                                                 tr("Do not ask again"), &noFurtherNagging);
    core->settings()->setValue(nagSymbolServerKey, noFurtherNagging);
    if (answer == QDialogButtonBox::No)
        return;
    // Prompt for path and add it. Synchronize QSetting and debugger.
    const QString cacheDir = CdbSymbolPathListEditor::promptCacheDirectory(core->mainWindow());
    if (cacheDir.isEmpty())
        return;
    m_d->m_options->symbolPaths.push_back(CdbOptions::symbolServerPath(cacheDir));
    m_d->m_options->toSettings(core->settings());
    syncDebuggerPaths();
}

377
void CdbDebugEngine::startEngine()
378
{
379
    QTC_ASSERT(state() == EngineStarting, qDebug() << state());
Friedemann Kleint's avatar
Friedemann Kleint committed
380
    const DebuggerStartParameters &sp = startParameters();
Friedemann Kleint's avatar
Friedemann Kleint committed
381
    if (debugCDBExecution)
382
        qDebug() << "startDebugger";
383
    CdbCore::BreakPoint::clearNormalizeFileNameCache();
384
    startupChecks();
385
    m_d->checkVersion();
386
387
    if (m_d->m_hDebuggeeProcess) {
        warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
388
        setState(EngineStartFailed, Q_FUNC_INFO, __LINE__);
389
        setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
390
        emit startFailed();
391
        return;
392
    }
393
    switch (sp.startMode) {
394
    case AttachCore:
ck's avatar
ck committed
395
    case AttachToRemote:
396
        warning(QLatin1String("Internal error: Mode not supported."));
397
        setState(EngineStartFailed, Q_FUNC_INFO, __LINE__);
398
        setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
399
400
401
402
403
        emit startFailed();
        break;
    default:
        break;
    }
404
    m_d->m_mode = sp.startMode;
405
    m_d->clearDisplay();
Friedemann Kleint's avatar
Friedemann Kleint committed
406
    m_d->m_inferiorStartupComplete = false;
407
    setState(EngineStarted, Q_FUNC_INFO, __LINE__);
408
409
410
    // Options
    QString errorMessage;
    if (!m_d->setBreakOnThrow(theDebuggerBoolSetting(BreakOnThrow), &errorMessage))
hjk's avatar
hjk committed
411
        showMessage(errorMessage, LogWarning);
412
    m_d->setVerboseSymbolLoading(m_d->m_options->verboseSymbolLoading);
413
    // Figure out dumper. @TODO: same in gdb...
414
    const QString dumperLibName = QDir::toNativeSeparators(qtDumperLibraryName());
415
416
    bool dumperEnabled = m_d->m_mode != AttachCore
                         && m_d->m_mode != AttachCrashedExternal
417
                         && qtDumperLibraryEnabled();
418
419
420
    if (dumperEnabled) {
        const QFileInfo fi(dumperLibName);
        if (!fi.isFile()) {
421
            const QStringList &locations = qtDumperLibraryLocations();
422
423
            const QString loc = locations.join(QLatin1String(", "));
            const QString msg = tr("The dumper library was not found at %1.").arg(loc);
424
            showQtDumperLibraryWarning(msg);
425
426
427
            dumperEnabled = false;
        }
    }
428
    m_d->m_dumper->reset(dumperLibName, dumperEnabled);
429
430

    setState(InferiorStarting, Q_FUNC_INFO, __LINE__);
431
    showStatusMessage("Starting Debugger", messageTimeOut);
432

Friedemann Kleint's avatar
Friedemann Kleint committed
433
    bool rc = false;
434
    bool needWatchTimer = false;
435
    m_d->clearForRun();
436
    m_d->updateCodeLevel();
437
    m_d->m_ignoreInitialBreakPoint = false;
438
    switch (m_d->m_mode) {
Friedemann Kleint's avatar
Friedemann Kleint committed
439
    case AttachExternal:
440
    case AttachCrashedExternal:
441
        rc = startAttachDebugger(sp.attachPID, m_d->m_mode, &errorMessage);
442
        needWatchTimer = true; // Fetch away module load, etc. even if crashed
Friedemann Kleint's avatar
Friedemann Kleint committed
443
444
445
        break;
    case StartInternal:
    case StartExternal:
446
        if (sp.useTerminal) {
447
448
            // Attaching to console processes triggers an initial breakpoint, which we do not want
            m_d->m_ignoreInitialBreakPoint = true;
449
450
            // Launch console stub and wait for its startup
            m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
451
452
453
            m_d->m_consoleStubProc.setWorkingDirectory(sp.workingDirectory);
            m_d->m_consoleStubProc.setEnvironment(sp.environment);
            rc = m_d->m_consoleStubProc.start(sp.executable, sp.processArgs);
454
            if (!rc)
455
                errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp.executable);
456
            // continues in slotConsoleStubStarted()...
457
        } else {
458
            needWatchTimer = true;
459
460
461
462
            rc = m_d->startDebuggerWithExecutable(sp.workingDirectory,
                                                  sp.executable,
                                                  sp.processArgs,
                                                  sp.environment,
463
                                                  &errorMessage);
464
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
465
466
        break;
    case AttachCore:
Friedemann Kleint's avatar
Friedemann Kleint committed
467
        errorMessage = tr("Attaching to core files is not supported!");
Friedemann Kleint's avatar
Friedemann Kleint committed
468
469
470
        break;
    }
    if (rc) {
471
        if (needWatchTimer)
472
            m_d->startWatchTimer();
473
        startSuccessful();
Friedemann Kleint's avatar
Friedemann Kleint committed
474
    } else {
475
        warning(errorMessage);
476
        setState(InferiorStartFailed, Q_FUNC_INFO, __LINE__);
477
        startFailed();
478
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
479
}
Banana Joe's avatar
Banana Joe committed
480

481
bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
482
{
483
    // Need to attach invasively, otherwise, no notification signals
484
    // for for CreateProcess/ExitProcess occur.
485
486
487
488
489
490
491
492
    // 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).
493
    const bool suppressInitialBreakPoint = sm != AttachCrashedExternal;
494
    return m_d->startAttachDebugger(pid, suppressInitialBreakPoint, errorMessage);
Banana Joe's avatar
Banana Joe committed
495
496
}

497
void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
498
{
499
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
500
501
    setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle));
    ULONG currentThreadId;
502
    if (SUCCEEDED(interfaces().debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, &currentThreadId))) {
503
504
505
506
        m_currentThreadId = currentThreadId;
    } else {
        m_currentThreadId = 0;
    }
507
508
    // Clear any saved breakpoints and set initial breakpoints
    m_engine->executeDebuggerCommand(QLatin1String("bc"));
509
    if (m_engine->breakHandler()->hasPendingBreakpoints()) {
Friedemann Kleint's avatar
Friedemann Kleint committed
510
511
        if (debugCDBExecution)
            qDebug() << "processCreatedAttached: Syncing breakpoints";
512
        m_engine->attemptBreakpointSynchronization();
Friedemann Kleint's avatar
Friedemann Kleint committed
513
    }
514
515
    // Attaching to crashed: This handshake (signalling an event) is required for
    // the exception to be delivered to the debugger
516
    // Also, see special handling in slotModulesLoaded().
517
    if (m_mode == AttachCrashedExternal) {
Friedemann Kleint's avatar
Friedemann Kleint committed
518
        const QString crashParameter = m_engine->startParameters().crashParameter;
519
520
        if (!crashParameter.isEmpty()) {
            ULONG64 evtNr = crashParameter.toULongLong();
521
            const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr);
522
            if (FAILED(hr))
523
                m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(CdbCore::msgComFailed("SetNotifyEventHandle", hr)));
524
525
        }
    }
526
    m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
Friedemann Kleint's avatar
Friedemann Kleint committed
527
    if (debugCDBExecution)
528
        qDebug() << "<processCreatedAttached";
529
530
}

531
532
void CdbDebugEngine::processTerminated(unsigned long exitCode)
{
hjk's avatar
hjk committed
533
    showMessage(tr("The process exited with exit code %1.").arg(exitCode));
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
534
    if (state() != InferiorStopping)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
535
536
        setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
    setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
537
    setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__);
538
    m_d->setDebuggeeHandles(0, 0);
539
540
541
    m_d->clearForRun();
    setState(InferiorShutDown, Q_FUNC_INFO, __LINE__);
    // Avoid calls from event handler.
542
    QTimer::singleShot(0, this, SLOT(quitDebugger()));
543
544
}

545
bool CdbDebugEnginePrivate::endInferior(EndInferiorAction action, QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
546
{
547
548
    // 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
549
    const bool wasRunning = isDebuggeeRunning();
550
551
    if (wasRunning) {
        interruptInterferiorProcess(errorMessage);
Friedemann Kleint's avatar
Friedemann Kleint committed
552
        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
553
    }
554
    bool success = false;
Friedemann Kleint's avatar
Friedemann Kleint committed
555
    switch (action) {
556
557
    case DetachInferior:
            if (detachCurrentProcess(errorMessage))
558
559
                success = true;
            break;
560
    case TerminateInferior:
561
562
            do {
                // The exit process event handler will not be called.
563
                terminateCurrentProcess(errorMessage);
564
565
566
567
                if (wasRunning) {
                    success = true;
                    break;
                }
568
                if (terminateProcesses(errorMessage))
569
570
571
572
                    success = true;
            } while (false);
            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
            break;
Friedemann Kleint's avatar
Friedemann Kleint committed
573
    }
574
    // Perform cleanup even when failed..no point clinging to the process
Friedemann Kleint's avatar
Friedemann Kleint committed
575
    setDebuggeeHandles(0, 0);
576
    killWatchTimer();
577
578
579
    m_engine->setState(success ? InferiorShutDown : InferiorShutdownFailed, Q_FUNC_INFO, __LINE__);
    return success;
}
580

581
582
583
584
585
586
587
// 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;
588

589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
    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);
Robert Loehning's avatar
Robert Loehning committed
613
            m_engine->showMessage(errorMessage, LogError);
614
615
616
617
        }
        errorMessage.clear();
    }
    // Clean up resources (open files, etc.)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
618
    m_engine->setState(EngineShuttingDown, Q_FUNC_INFO, __LINE__);
619
    clearForRun();
620
    const bool endedCleanly = endSession(&errorMessage);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
621
    m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
622
623
    if (!endedCleanly) {
        errorMessage = QString::fromLatin1("There were errors trying to end debugging:\n%1").arg(errorMessage);
Robert Loehning's avatar
Robert Loehning committed
624
        m_engine->showMessage(errorMessage, LogError);
625
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
626
627
628
629
630
631
632
633
634
635
}

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

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

638
CdbSymbolGroupContext *CdbDebugEnginePrivate::getSymbolGroupContext(int frameIndex, QString *errorMessage) const
639
640
641
642
643
{
    if (!m_currentStackTrace) {
        *errorMessage = QLatin1String(msgNoStackTraceC);
        return 0;
    }
644
    if (CdbSymbolGroupContext *sg = m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, errorMessage))
645
646
647
648
649
650
651
652
653
654
655
        return sg;
    return 0;
}

void CdbDebugEngine::evaluateWatcher(WatchData *wd)
{
    if (debugCDBWatchHandling)
        qDebug() << Q_FUNC_INFO << wd->exp;
    QString errorMessage;
    QString value;
    QString type;
656
657
658
659
660
    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)) {
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
        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();

679
    if (incomplete.iname.startsWith("watch.")) {
680
681
        WatchData watchData = incomplete;
        evaluateWatcher(&watchData);
682
        watchHandler()->insertData(watchData);
683
684
685
        return;
    }

686
    const int frameIndex = stackHandler()->currentIndex();
687
688
689
690

    bool success = false;
    QString errorMessage;
    do {
691
        CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
692
693
        if (!sg)
            break;
694
        if (!sg->completeData(incomplete, watchHandler(), &errorMessage))
695
696
697
698
699
            break;
        success = true;
    } while (false);
    if (!success)
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
700
    if (debugCDBWatchHandling > 1)
701
        qDebug() << *watchHandler()->model(LocalsWatch);
702
703
}

704
705
706
707
708
709
710
// 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();
711
    updateCodeLevel(); // Step by instruction
712
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
Robert Loehning's avatar
Robert Loehning committed
713
    m_engine->showMessage(CdbDebugEngine::tr("Continuing with '%1'...").arg(command));
714
    QString errorMessage;
715
    const bool success = executeDebuggerCommand(command, &errorMessage);
716
717
    if (success) {
        m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
718
        startWatchTimer();
719
720
721
722
723
724
725
    } else {
        m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
        m_engine->warning(CdbDebugEngine::tr("Unable to continue: %1").arg(errorMessage));
    }
    return success;
}

726
727
728
729
730
731
732
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
733
734
735
736
737
738
// 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),
739
// DEBUG_STATUS_STEP_INTO ('t'-trace-command) or
Friedemann Kleint's avatar
Friedemann Kleint committed
740
// CdbExtendedExecutionStatusStepOut ("gu"-command)
741
// its reverse equivalents in the case of single threads.
Friedemann Kleint's avatar
Friedemann Kleint committed
742

743
bool CdbDebugEngine::step(unsigned long executionStatus)
Banana Joe's avatar
Banana Joe committed
744
{
Friedemann Kleint's avatar
Friedemann Kleint committed
745
746
    if (debugCDBExecution)
        qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId;
Friedemann Kleint's avatar
Friedemann Kleint committed
747

748
749
750
751
752
753
754
755
    // 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
756
757
758
759
760
761
    // 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;
    }

762
763
764
765
766
767
768
    // 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
769
                            || threadsHandler()->threads().size() == 1;
770
    m_d->clearForRun(); // clears thread ids
771
    m_d->updateCodeLevel(); // Step by instruction or source line
772
    setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
773
    bool success = false;
Friedemann Kleint's avatar
Friedemann Kleint committed
774
    if (sameThread && executionStatus != CdbExtendedExecutionStatusStepOut) { // Step event-triggering thread, use fast API
775
        const HRESULT hr = m_d->interfaces().debugControl->SetExecutionStatus(executionStatus);
776
777
        success = SUCCEEDED(hr);
        if (!success)
778
            warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, CdbCore::msgComFailed("SetExecutionStatus", hr)));
779
780
781
782
    } else {
        // Need to use a command to explicitly specify the current thread
        QString command;
        QTextStream str(&command);
Friedemann Kleint's avatar
Friedemann Kleint committed
783
784
785
786
787
788
        str << '~' << m_d->m_currentThreadId << ' ';
        switch (executionStatus) {
        case DEBUG_STATUS_STEP_OVER:
            str << 'p';
            break;
        case DEBUG_STATUS_STEP_INTO:
789
            str << 't';
Friedemann Kleint's avatar
Friedemann Kleint committed
790
791
792
793
794
            break;
        case CdbExtendedExecutionStatusStepOut:
            str << "gu";
            break;
        }
hjk's avatar
hjk committed
795
        showMessage(tr("Stepping %1").arg(command));
796
        const HRESULT hr = m_d->interfaces().debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO);
797
798
799
800
801
        success = SUCCEEDED(hr);
        if (!success)
            warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgDebuggerCommandFailed(command, hr)));
    }
    if (success) {
802
803
804
        // 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;
805
        m_d->startWatchTimer();
806
807
808
809
        setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
    } else {
        setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
810
811
    if (debugCDBExecution)
        qDebug() << "<step samethread" << sameThread << "succeeded" << success;
812
813
814
    return success;
}

hjk's avatar
hjk committed
815
void CdbDebugEngine::executeStep()
816
{
817
    step(isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_INTO : DEBUG_STATUS_STEP_INTO);
818
819
}

hjk's avatar
hjk committed
820
void CdbDebugEngine::executeNext()
821
{
822
    step(isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_OVER : DEBUG_STATUS_STEP_OVER);
823
824
}

hjk's avatar
hjk committed
825
void CdbDebugEngine::executeStepI()
826
{
hjk's avatar
hjk committed
827
    executeStep(); // Step into by instruction (figured out by step)
828
829
}

hjk's avatar
hjk committed
830
void CdbDebugEngine::executeNextI()
831
{
hjk's avatar
hjk committed
832
    executeNext(); // Step over by instruction (figured out by step)
Banana Joe's avatar
Banana Joe committed
833
834
}

hjk's avatar
hjk committed
835
void CdbDebugEngine::executeStepOut()
Banana Joe's avatar
Banana Joe committed
836
{
837
    if (!isReverseDebugging())
Friedemann Kleint's avatar
Friedemann Kleint committed
838
        step(CdbExtendedExecutionStatusStepOut);
Banana Joe's avatar
Banana Joe committed
839
840
}

hjk's avatar
hjk committed
841
void CdbDebugEngine::continueInferior()
842
{
843
    QString errorMessage;
844
    if  (!m_d->continueInferior(&errorMessage))
845
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
846
847
848
}

// Continue process without notifications
849
bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /* = 0 */)
Banana Joe's avatar
Banana Joe committed
850
{
Friedemann Kleint's avatar
Friedemann Kleint committed
851
852
    if (debugCDBExecution)
        qDebug() << "continueInferiorProcess";
853
    const HRESULT hr = interfaces().debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
854
    if (FAILED(hr)) {
855
        const QString errorMessage = CdbCore::msgComFailed("SetExecutionStatus", hr);
856
857
858
        if (errorMessagePtr) {
            *errorMessagePtr = errorMessage;
        } else {
859
            m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
860
        }
861
862
863
864
        return false;
    }
    return  true;
}
Friedemann Kleint's avatar
Friedemann Kleint committed
865

866
867
// Continue process with notifications
bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
868
{
869
    // Check state: Are we running?
870
    const ULONG ex = executionStatus();
871
    if (debugCDB)
872
        qDebug() << Q_FUNC_INFO << "\n    ex=" << ex;
873

874
    if (ex == DEBUG_STATUS_GO) {
875
        m_engine->warning(QLatin1String("continueInferior() called while debuggee is running."));
8