cdbdebugengine.cpp 60.2 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
50
#include "debuggermanager.h"
#include "breakhandler.h"
#include "stackhandler.h"
51
#include "watchhandler.h"
52
#include "threadshandler.h"
53
54
#include "registerhandler.h"
#include "moduleshandler.h"
55
#include "watchutils.h"
Banana Joe's avatar
Banana Joe committed
56

57
#include <coreplugin/icore.h>
hjk's avatar
hjk committed
58
#include <utils/qtcassert.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
59
#include <utils/winutils.h>
60
#include <utils/consoleprocess.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
61
#include <utils/fancymainwindow.h>
62
#include <texteditor/itexteditor.h>
63
#include <utils/savedaction.h>
64
#include <utils/checkablemessagebox.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 {

Friedemann Kleint's avatar
Friedemann Kleint committed
86
87
typedef QList<WatchData> WatchList;

88
89
// ----- Message helpers

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

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

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

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

118
119
// ----- Engine helpers

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

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

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

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

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

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

197
    m_breakEventMode = BreakEventHandle;
Friedemann Kleint's avatar
Friedemann Kleint committed
198
    m_eventThreadId = m_interruptArticifialThreadId = -1;
199
    m_interrupted = false;
200
    cleanStackTrace();
201
202
    m_stoppedReason = StoppedOther;
    m_stoppedMessage.clear();
203
204
205
}

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

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

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

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

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

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

311
312
void CdbDebugEnginePrivate::clearDisplay()
{
313
314
315
    m_engine->threadsHandler()->removeAll();
    m_engine->modulesHandler()->removeAll();
    m_engine->registerHandler()->removeAll();
316
317
}

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

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
377
378
379
380
381
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();
}

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

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

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

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

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

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

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

585
586
587
588
589
590
591
// 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;
592

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

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

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

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

void CdbDebugEngine::evaluateWatcher(WatchData *wd)
{
    if (debugCDBWatchHandling)
        qDebug() << Q_FUNC_INFO << wd->exp;
    QString errorMessage;
    QString value;
    QString type;
660
661
662
663
664
    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)) {
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
        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
683
    WatchHandler *watchHandler = manager()->watchHandler();
684
    if (incomplete.iname.startsWith("watch.")) {
685
686
687
688
689
690
        WatchData watchData = incomplete;
        evaluateWatcher(&watchData);
        watchHandler->insertData(watchData);
        return;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
691
    const int frameIndex = manager()->stackHandler()->currentIndex();
692
693
694
695

    bool success = false;
    QString errorMessage;
    do {
696
        CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
697
698
699
700
701
702
703
704
        if (!sg)
            break;
        if (!sg->completeData(incomplete, watchHandler, &errorMessage))
            break;
        success = true;
    } while (false);
    if (!success)
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
705
    if (debugCDBWatchHandling > 1)
Friedemann Kleint's avatar
Friedemann Kleint committed
706
        qDebug() << *manager()->watchHandler()->model(LocalsWatch);
707
708
}

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

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

748
bool CdbDebugEngine::step(unsigned long executionStatus)
Banana Joe's avatar
Banana Joe committed
749
{
Friedemann Kleint's avatar
Friedemann Kleint committed
750
751
    if (debugCDBExecution)
        qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId;
Friedemann Kleint's avatar
Friedemann Kleint committed
752

753
754
755
756
757
758
759
760
    // 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
761
762
763
764
765
766
    // 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;
    }

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

hjk's avatar
hjk committed
820
void CdbDebugEngine::executeStep()
821
822
823
824
{
    step(manager()->isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_INTO : DEBUG_STATUS_STEP_INTO);
}

hjk's avatar
hjk committed
825
void CdbDebugEngine::executeNext()
826
827
828
829
{
    step(manager()->isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_OVER : DEBUG_STATUS_STEP_OVER);
}

hjk's avatar
hjk committed
830
void CdbDebugEngine::executeStepI()
831
{
hjk's avatar
hjk committed
832
    executeStep(); // Step into by instruction (figured out by step)
833
834
}

hjk's avatar
hjk committed
835
void CdbDebugEngine::executeNextI()
836
{
hjk's avatar
hjk committed
837
    executeNext(); // Step over by instruction (figured out by step)
Banana Joe's avatar
Banana Joe committed
838
839
}

hjk's avatar
hjk committed
840
void CdbDebugEngine::executeStepOut()
Banana Joe's avatar
Banana Joe committed
841
{
Friedemann Kleint's avatar
Friedemann Kleint committed
842
843
    if (!manager()->isReverseDebugging())
        step(CdbExtendedExecutionStatusStepOut);
Banana Joe's avatar
Banana Joe committed
844
845
}

hjk's avatar
hjk committed
846
void CdbDebugEngine::continueInferior()
847
{
848
    QString errorMessage;
849
    if  (!m_d->continueInferior(&errorMessage))
850
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
851
852
853
}

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

871
872
// Continue process with notifications
bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
873
{
874
    // Check state: Are we running?
875
    const ULONG ex = executionStatus();
876
    if (debugCDB)
877
        qDebug() << Q_FUNC_INFO << "\n    ex=" << ex;
878

879
    if (ex == DEBUG_STATUS_GO) {
880
        m_engine->warning(QLatin1String("continueInferior() called while debuggee is running."));
881
        return true;
882
    }
883
884
885
886
887
    // Request continue
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
    bool success = false;
    do {
        clearForRun();
888
889
        updateCodeLevel();
        killWatchTimer();
890
        manager()->resetLocation();
891
        manager()->showStatusMessage(CdbDebugEngine::tr("Running requested..."), messageTimeOut);
892

893
894
        if (!continueInferiorProcess(errorMessage))
            break;
895

896
        startWatchTimer();
897
898
899
900
901
902
903