cdbdebugengine.cpp 72.3 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
#include "cdbstacktracecontext.h"
33
#include "cdbstackframecontext.h"
34
#include "cdbsymbolgroupcontext.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
35
#include "cdbbreakpoint.h"
36
37
#include "cdbmodules.h"
#include "cdbassembler.h"
38
39
#include "cdboptionspage.h"
#include "cdboptions.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
40
#include "cdbexceptionutils.h"
41
#include "debuggeragents.h"
Banana Joe's avatar
Banana Joe committed
42

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

52
#include <coreplugin/icore.h>
hjk's avatar
hjk committed
53
#include <utils/qtcassert.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
54
#include <utils/winutils.h>
55
#include <utils/consoleprocess.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
56
#include <utils/fancymainwindow.h>
57
#include <texteditor/itexteditor.h>
hjk's avatar
hjk committed
58

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

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

74
static const char *dbgHelpDllC = "dbghelp";
Friedemann Kleint's avatar
Friedemann Kleint committed
75
76
static const char *dbgEngineDllC = "dbgeng";
static const char *debugCreateFuncC = "DebugCreate";
Banana Joe's avatar
Banana Joe committed
77

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

namespace Debugger {
namespace Internal {

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

85
86
// ----- Message helpers

87
QString msgDebugEngineComResult(HRESULT hr)
Friedemann Kleint's avatar
Friedemann Kleint committed
88
89
{
    switch (hr) {
90
91
92
93
        case S_OK:
        return QLatin1String("S_OK");
        case S_FALSE:
        return QLatin1String("S_FALSE");
Friedemann Kleint's avatar
Friedemann Kleint committed
94
95
96
97
98
99
100
101
102
103
104
        case E_FAIL:
        break;
        case E_INVALIDARG:
        return QLatin1String("E_INVALIDARG");
        case E_NOINTERFACE:
        return QLatin1String("E_NOINTERFACE");
        case E_OUTOFMEMORY:
        return QLatin1String("E_OUTOFMEMORY");
        case E_UNEXPECTED:
        return QLatin1String("E_UNEXPECTED");
        case E_NOTIMPL:
105
        return QLatin1String("E_NOTIMPL");
Friedemann Kleint's avatar
Friedemann Kleint committed
106
107
108
109
110
    }
    if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
        return QLatin1String("ERROR_ACCESS_DENIED");;
    if (hr == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
        return QLatin1String("STATUS_CONTROL_C_EXIT");
111
    return QLatin1String("E_FAIL ") + Utils::winErrorMessage(HRESULT_CODE(hr));
Friedemann Kleint's avatar
Friedemann Kleint committed
112
113
}

114
115
116
117
118
static QString msgStackIndexOutOfRange(int idx, int size)
{
    return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
}

119
QString msgComFailed(const char *func, HRESULT hr)
120
121
122
123
{
    return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr));
}

124
125
126
127
128
QString msgDebuggerCommandFailed(const QString &command, HRESULT hr)
{
    return QString::fromLatin1("Unable to execute '%1': %2").arg(command, msgDebugEngineComResult(hr));
}

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

131
132
133
134
135
136
static inline QString msgLibLoadFailed(const QString &lib, const QString &why)
{
    return CdbDebugEngine::tr("Unable to load the debugger engine library '%1': %2").
            arg(lib, why);
}

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// 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);
}

153
154
// ----- Engine helpers

155
static inline ULONG getInterruptTimeOutSecs(CIDebugControl *ctl)
156
157
158
159
160
161
{
    ULONG rc = 0;
    ctl->GetInterruptTimeout(&rc);
    return rc;
}

162
163
164
bool getExecutionStatus(CIDebugControl *ctl,
                        ULONG *executionStatus,
                        QString *errorMessage /* = 0 */)
165
166
167
{
    const HRESULT hr = ctl->GetExecutionStatus(executionStatus);
    if (FAILED(hr)) {
168
169
        if (errorMessage)
            *errorMessage = msgComFailed("GetExecutionStatus", hr);
170
171
172
173
174
        return false;
    }
    return true;
}

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
const char *executionStatusString(ULONG executionStatus)
{
    switch (executionStatus) {
    case DEBUG_STATUS_NO_CHANGE:
        return "DEBUG_STATUS_NO_CHANGE";
    case DEBUG_STATUS_GO:
        return "DEBUG_STATUS_GO";
    case DEBUG_STATUS_GO_HANDLED:
        return "DEBUG_STATUS_GO_HANDLED";
    case DEBUG_STATUS_GO_NOT_HANDLED:
        return "DEBUG_STATUS_GO_NOT_HANDLED";
    case DEBUG_STATUS_STEP_OVER:
        return "DEBUG_STATUS_STEP_OVER";
    case DEBUG_STATUS_STEP_INTO:
        return "DEBUG_STATUS_STEP_INTO";
    case DEBUG_STATUS_BREAK:
        return "DEBUG_STATUS_BREAK";
    case DEBUG_STATUS_NO_DEBUGGEE:
        return "DEBUG_STATUS_NO_DEBUGGEE";
    case DEBUG_STATUS_STEP_BRANCH:
        return "DEBUG_STATUS_STEP_BRANCH";
    case DEBUG_STATUS_IGNORE_EVENT:
        return "DEBUG_STATUS_IGNORE_EVENT";
    case DEBUG_STATUS_RESTART_REQUESTED:
        return "DEBUG_STATUS_RESTART_REQUESTED";
    case DEBUG_STATUS_REVERSE_GO:
        return "DEBUG_STATUS_REVERSE_GO";
          case DEBUG_STATUS_REVERSE_STEP_BRANCH:
        return "DEBUG_STATUS_REVERSE_STEP_BRANCH";
    case DEBUG_STATUS_REVERSE_STEP_OVER:
        return "DEBUG_STATUS_REVERSE_STEP_OVER";
    case DEBUG_STATUS_REVERSE_STEP_INTO:
        return "DEBUG_STATUS_REVERSE_STEP_INTO";
        default:
        break;
    }
    return "<Unknown execution status>";
}

// Debug convenience
const char *executionStatusString(CIDebugControl *ctl)
{
    ULONG executionStatus;
    if (getExecutionStatus(ctl, &executionStatus))
        return executionStatusString(executionStatus);
    return "<failed>";
}

223
// --------- DebuggerEngineLibrary
Friedemann Kleint's avatar
Friedemann Kleint committed
224
225
226
227
228
DebuggerEngineLibrary::DebuggerEngineLibrary() :
    m_debugCreate(0)
{
}

229
230
// Build a lib name as "Path\x.dll"
static inline QString libPath(const QString &libName, const QString &path = QString())
Friedemann Kleint's avatar
Friedemann Kleint committed
231
{
232
233
234
235
236
237
238
    QString rc = path;
    if (!rc.isEmpty())
        rc += QDir::separator();
    rc += libName;
    rc += QLatin1String(".dll");
    return rc;
}
Friedemann Kleint's avatar
Friedemann Kleint committed
239

240
241
242
bool DebuggerEngineLibrary::init(const QString &path,
                                 QString *dbgEngDLL,
                                 QString *errorMessage)
243
244
245
246
247
248
249
250
251
252
253
{
    // Load the dependent help lib first
    const QString helpLibPath = libPath(QLatin1String(dbgHelpDllC), path);
    QLibrary helpLib(helpLibPath, 0);
    if (!helpLib.isLoaded() && !helpLib.load()) {
        *errorMessage = msgLibLoadFailed(helpLibPath, helpLib.errorString());
        return false;
    }
    // Load dbgeng lib
    const QString engineLibPath = libPath(QLatin1String(dbgEngineDllC), path);
    QLibrary lib(engineLibPath, 0);
Friedemann Kleint's avatar
Friedemann Kleint committed
254
    if (!lib.isLoaded() && !lib.load()) {
255
        *errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString());
Friedemann Kleint's avatar
Friedemann Kleint committed
256
257
        return false;
    }
258
    *dbgEngDLL = engineLibPath;
Friedemann Kleint's avatar
Friedemann Kleint committed
259
260
261
262
263
264
265
266
267
268
269
    // Locate symbols
    void *createFunc = lib.resolve(debugCreateFuncC);
    if (!createFunc) {
        *errorMessage = CdbDebugEngine::tr("Unable to resolve '%1' in the debugger engine library '%2'").
                        arg(QLatin1String(debugCreateFuncC), QLatin1String(dbgEngineDllC));
        return false;
    }
    m_debugCreate = static_cast<DebugCreateFunction>(createFunc);
    return true;
}

270
// ----- SyntaxSetter
271
SyntaxSetter::SyntaxSetter(CIDebugControl *ctl, ULONG desiredSyntax) :
Friedemann Kleint's avatar
Friedemann Kleint committed
272
273
274
275
276
277
278
279
280
281
282
283
284
285
    m_desiredSyntax(desiredSyntax),
    m_ctl(ctl)
{
    m_ctl->GetExpressionSyntax(&m_oldSyntax);
    if (m_oldSyntax != m_desiredSyntax)
        m_ctl->SetExpressionSyntax(m_desiredSyntax);
}

SyntaxSetter::~SyntaxSetter()
{
    if (m_oldSyntax != m_desiredSyntax)
        m_ctl->SetExpressionSyntax(m_oldSyntax);
}

286
287
288
289
290
291
292
293
294
295
296
// CdbComInterfaces
CdbComInterfaces::CdbComInterfaces() :
    debugClient(0),
    debugControl(0),
    debugSystemObjects(0),
    debugSymbols(0),
    debugRegisters(0),
    debugDataSpaces(0)
{
}

Friedemann Kleint's avatar
Friedemann Kleint committed
297
298
// --- CdbDebugEnginePrivate

hjk's avatar
hjk committed
299
CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
300
301
302
                                             const QSharedPointer<CdbOptions> &options,
                                             CdbDebugEngine* engine) :
    m_options(options),
Banana Joe's avatar
Banana Joe committed
303
304
    m_hDebuggeeProcess(0),
    m_hDebuggeeThread(0),
305
    m_breakEventMode(BreakEventHandle),
hjk's avatar
hjk committed
306
    m_dumper(new CdbDumperHelper(manager, &m_cif)),
307
308
    m_currentThreadId(-1),
    m_eventThreadId(-1),
Friedemann Kleint's avatar
Friedemann Kleint committed
309
    m_interruptArticifialThreadId(-1),
310
    m_ignoreInitialBreakPoint(false),
Friedemann Kleint's avatar
Friedemann Kleint committed
311
    m_interrupted(false),    
Banana Joe's avatar
Banana Joe committed
312
    m_watchTimer(-1),
313
    m_debugEventCallBack(engine),
Friedemann Kleint's avatar
Friedemann Kleint committed
314
    m_engine(engine),
315
    m_currentStackTrace(0),
Friedemann Kleint's avatar
Friedemann Kleint committed
316
    m_firstActivatedFrame(true),
Friedemann Kleint's avatar
Friedemann Kleint committed
317
    m_inferiorStartupComplete(false),
318
    m_mode(AttachCore)
319
{
320
321
322
}

bool CdbDebugEnginePrivate::init(QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
323
{
324
    enum {  bufLen = 10240 };
325
326
    // Load the DLL
    DebuggerEngineLibrary lib;
327
    if (!lib.init(m_options->path, &m_dbengDLL, errorMessage))
328
329
        return false;
    // Initialize the COM interfaces
Banana Joe's avatar
Banana Joe committed
330
    HRESULT hr;
331
    hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient));
Friedemann Kleint's avatar
Friedemann Kleint committed
332
    if (FAILED(hr)) {
333
334
        *errorMessage = QString::fromLatin1("Creation of IDebugClient5 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
Friedemann Kleint's avatar
Friedemann Kleint committed
335
336
    }

337
338
    m_cif.debugClient->SetOutputCallbacksWide(&m_debugOutputCallBack);
    m_cif.debugClient->SetEventCallbacksWide(&m_debugEventCallBack);
339

340
    hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_cif.debugControl));
Friedemann Kleint's avatar
Friedemann Kleint committed
341
    if (FAILED(hr)) {
342
343
        *errorMessage = QString::fromLatin1("Creation of IDebugControl4 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
Friedemann Kleint's avatar
Friedemann Kleint committed
344
345
    }

346
    setCodeLevel();
347

348
    hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_cif.debugSystemObjects));
349
350
351
352
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugSystemObjects4 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
353

354
    hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_cif.debugSymbols));
355
356
357
358
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugSymbols3 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
359

360
361
362
363
364
365
366
367
    WCHAR buf[bufLen];
    hr = m_cif.debugSymbols->GetImagePathWide(buf, bufLen, 0);
    if (FAILED(hr)) {
        *errorMessage = msgComFailed("GetImagePathWide", hr);
        return false;
    }
    m_baseImagePath = QString::fromUtf16(buf);

368
    hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_cif.debugRegisters));
369
370
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
371
        return false;
372
    }
373
374
375
376
377
378
379

    hr = lib.debugCreate( __uuidof(IDebugDataSpaces4), reinterpret_cast<void**>(&m_cif.debugDataSpaces));
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugDataSpaces4 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }

380
    if (debugCDB)
381
        qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_cif.debugControl));
382
    return true;
Friedemann Kleint's avatar
Friedemann Kleint committed
383
}
Banana Joe's avatar
Banana Joe committed
384

385
IDebuggerEngine *CdbDebugEngine::create(Debugger::DebuggerManager *manager,
386
387
                                        const QSharedPointer<CdbOptions> &options,
                                        QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
388
{
hjk's avatar
hjk committed
389
    CdbDebugEngine *rc = new CdbDebugEngine(manager, options);
390
391
    if (rc->m_d->init(errorMessage)) {
        rc->syncDebuggerPaths();
392
        return rc;
393
    }
394
395
    delete rc;
    return 0;
Banana Joe's avatar
Banana Joe committed
396
397
}

398
399
400
401
402
403
404
405
// Adapt code level setting to the setting of the action.
static inline const char *codeLevelName(ULONG level)
{
    return level == DEBUG_LEVEL_ASSEMBLY ? "assembly" : "source";
}

bool CdbDebugEnginePrivate::setCodeLevel()
{
Friedemann Kleint's avatar
Friedemann Kleint committed
406
    const ULONG codeLevel = theDebuggerBoolSetting(OperateByInstruction) ?
407
408
409
410
411
412
413
414
415
                            DEBUG_LEVEL_ASSEMBLY : DEBUG_LEVEL_SOURCE;
    ULONG currentCodeLevel = DEBUG_LEVEL_ASSEMBLY;
    HRESULT hr = m_cif.debugControl->GetCodeLevel(&currentCodeLevel);
    if (FAILED(hr)) {
        m_engine->warning(QString::fromLatin1("Cannot determine code level: %1").arg(msgComFailed("GetCodeLevel", hr)));
        return true;
    }
    if (debugCDB)
        qDebug() << Q_FUNC_INFO << "\nSetting code level to " << codeLevelName(codeLevel) << " (was" << codeLevelName(currentCodeLevel) << ')';
416
    if (currentCodeLevel == codeLevel)
417
418
419
420
421
422
423
424
425
        return false;
    hr = m_cif.debugControl->SetCodeLevel(codeLevel);
    if (FAILED(hr)) {
        m_engine->warning(QString::fromLatin1("Cannot set code level: %1").arg(msgComFailed("SetCodeLevel", hr)));
        return false;
    }
    return true;
}

426
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
Banana Joe's avatar
Banana Joe committed
427
{
428
    cleanStackTrace();
429
430
431
432
433
434
435
436
437
438
439
440
    if (m_cif.debugClient)
        m_cif.debugClient->Release();
    if (m_cif.debugControl)
        m_cif.debugControl->Release();
    if (m_cif.debugSystemObjects)
        m_cif.debugSystemObjects->Release();
    if (m_cif.debugSymbols)
        m_cif.debugSymbols->Release();
    if (m_cif.debugRegisters)
        m_cif.debugRegisters->Release();
    if (m_cif.debugDataSpaces)
        m_cif.debugDataSpaces->Release();
Banana Joe's avatar
Banana Joe committed
441
442
}

Friedemann Kleint's avatar
Friedemann Kleint committed
443
444
445
446
447
DebuggerManager *CdbDebugEnginePrivate::manager() const
{
    return m_engine->manager();
}

448
void CdbDebugEnginePrivate::clearForRun()
449
450
451
452
{
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

453
    m_breakEventMode = BreakEventHandle;
Friedemann Kleint's avatar
Friedemann Kleint committed
454
    m_eventThreadId = m_interruptArticifialThreadId = -1;
455
    m_interrupted = false;
456
457
458
459
    cleanStackTrace();
}

void CdbDebugEnginePrivate::cleanStackTrace()
460
{
461
462
463
464
    if (m_currentStackTrace) {
        delete m_currentStackTrace;
        m_currentStackTrace = 0;
    }
465
466
    m_firstActivatedFrame = false;
    m_editorToolTipCache.clear();
467
468
}

hjk's avatar
hjk committed
469
CdbDebugEngine::CdbDebugEngine(DebuggerManager *manager, const QSharedPointer<CdbOptions> &options) :
Friedemann Kleint's avatar
Friedemann Kleint committed
470
471
    IDebuggerEngine(manager),
    m_d(new CdbDebugEnginePrivate(manager, options, this))
472
{
473
    m_d->m_consoleStubProc.setMode(Utils::ConsoleProcess::Suspend);
hjk's avatar
hjk committed
474
475
476
477
478
479
    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()));
480
    connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerOutput(int,QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
481
            manager, SLOT(showDebuggerOutput(int,QString)));
482
    connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerInputPrompt(int,QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
483
            manager, SLOT(showDebuggerInput(int,QString)));
484
    connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeOutput(QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
485
            manager, SLOT(showApplicationOutput(QString)));
486
    connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeInputPrompt(QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
487
            manager, SLOT(showApplicationOutput(QString)));
488
489
490
491
492
493
494
}

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

495
496
497
498
499
500
501
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
502
void CdbDebugEngine::startWatchTimer()
Banana Joe's avatar
Banana Joe committed
503
{
504
505
506
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

507
508
    if (m_d->m_watchTimer == -1)
        m_d->m_watchTimer = startTimer(0);
Banana Joe's avatar
Banana Joe committed
509
510
}

hjk's avatar
hjk committed
511
void CdbDebugEngine::killWatchTimer()
Banana Joe's avatar
Banana Joe committed
512
{
513
514
515
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

516
517
518
    if (m_d->m_watchTimer != -1) {
        killTimer(m_d->m_watchTimer);
        m_d->m_watchTimer = -1;
Banana Joe's avatar
Banana Joe committed
519
520
521
    }
}

hjk's avatar
hjk committed
522
void CdbDebugEngine::shutdown()
Banana Joe's avatar
Banana Joe committed
523
524
525
526
{
    exitDebugger();
}

527
QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &function)
Banana Joe's avatar
Banana Joe committed
528
{
529
530
531
532
533
534
    // 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
535
    CdbStackFrameContext *frame = 0;
536
537
    if (m_d->m_currentStackTrace &&  !function.isEmpty()) {
        const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
538
539
        if (frameIndex != -1)
            frame = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
540
    }
541
542
    if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
        return rc;
543
544
545
546
547
548
549
550
551
552
553
    // 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;
    if (!evaluateExpression(exp, &rc, &type, &errorMessage))
        return QString();
    return rc;
}

void CdbDebugEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
{
    typedef CdbDebugEnginePrivate::EditorToolTipCache EditorToolTipCache;
554
    if (debugCDB)
555
556
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
        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
587
588
}

589
590
void CdbDebugEnginePrivate::clearDisplay()
{
Friedemann Kleint's avatar
Friedemann Kleint committed
591
592
593
    manager()->threadsHandler()->removeAll();
    manager()->modulesHandler()->removeAll();
    manager()->registerHandler()->removeAll();
594
595
}

596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
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;
        const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, m_dbengDLL, &errorMessage);
        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
624
void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
625
{
Friedemann Kleint's avatar
Friedemann Kleint committed
626
627
    if (debugCDBExecution)
        qDebug() << "startDebugger" << *sp;
628
    setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
629
    m_d->checkVersion();
630
631
    if (m_d->m_hDebuggeeProcess) {
        warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
632
        setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
633
        emit startFailed();
634
    }
635
    m_d->clearDisplay();
Friedemann Kleint's avatar
Friedemann Kleint committed
636
    m_d->m_inferiorStartupComplete = false;
637
    setState(AdapterStarted, Q_FUNC_INFO, __LINE__);
638

Friedemann Kleint's avatar
Friedemann Kleint committed
639
    const DebuggerStartMode mode = sp->startMode;
640
    // Figure out dumper. @TODO: same in gdb...
Friedemann Kleint's avatar
Friedemann Kleint committed
641
    const QString dumperLibName = QDir::toNativeSeparators(manager()->qtDumperLibraryName());
642
643
    bool dumperEnabled = mode != AttachCore
                         && mode != AttachCrashedExternal
Friedemann Kleint's avatar
Friedemann Kleint committed
644
                         && manager()->qtDumperLibraryEnabled();
645
646
647
    if (dumperEnabled) {
        const QFileInfo fi(dumperLibName);
        if (!fi.isFile()) {
Friedemann Kleint's avatar
Friedemann Kleint committed
648
            const QStringList &locations = manager()->qtDumperLibraryLocations();
649
650
            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
651
            manager()->showQtDumperLibraryWarning(msg);
652
653
654
            dumperEnabled = false;
        }
    }
655
    m_d->m_dumper->reset(dumperLibName, dumperEnabled);
656
657

    setState(InferiorStarting, Q_FUNC_INFO, __LINE__);
Friedemann Kleint's avatar
Friedemann Kleint committed
658
    manager()->showStatusMessage("Starting Debugger", -1);
659

Friedemann Kleint's avatar
Friedemann Kleint committed
660
661
    QString errorMessage;
    bool rc = false;
662
    bool needWatchTimer = false;
663
    m_d->clearForRun();
664
    m_d->setCodeLevel();
665
    m_d->m_ignoreInitialBreakPoint = false;
666
    switch (mode) {
Friedemann Kleint's avatar
Friedemann Kleint committed
667
    case AttachExternal:
668
669
670
    case AttachCrashedExternal:
        rc = startAttachDebugger(sp->attachPID, mode, &errorMessage);
        needWatchTimer = true; // Fetch away module load, etc. even if crashed
Friedemann Kleint's avatar
Friedemann Kleint committed
671
672
673
        break;
    case StartInternal:
    case StartExternal:
674
        if (sp->useTerminal) {
675
676
            // Attaching to console processes triggers an initial breakpoint, which we do not want
            m_d->m_ignoreInitialBreakPoint = true;
677
678
            // Launch console stub and wait for its startup
            m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
679
680
681
            m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDir);
            m_d->m_consoleStubProc.setEnvironment(sp->environment);
            rc = m_d->m_consoleStubProc.start(sp->executable, sp->processArgs);
682
            if (!rc)
683
                errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp->executable);
684
            // continues in slotConsoleStubStarted()...
685
        } else {
686
            needWatchTimer = true;
687
688
            rc = startDebuggerWithExecutable(mode, &errorMessage);
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
689
690
        break;
    case AttachCore:
Friedemann Kleint's avatar
Friedemann Kleint committed
691
        errorMessage = tr("Attaching to core files is not supported!");
Friedemann Kleint's avatar
Friedemann Kleint committed
692
693
694
        break;
    }
    if (rc) {
Friedemann Kleint's avatar
Friedemann Kleint committed
695
        manager()->showStatusMessage(tr("Debugger running"), -1);
696
697
        if (needWatchTimer)
            startWatchTimer();
698
            emit startSuccessful();
Friedemann Kleint's avatar
Friedemann Kleint committed
699
    } else {
700
        warning(errorMessage);
701
        setState(InferiorStartFailed, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
702
        emit startFailed();
703
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
704
}
Banana Joe's avatar
Banana Joe committed
705

706
bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
707
{
708
    // Need to attrach invasively, otherwise, no notification signals
709
    // for for CreateProcess/ExitProcess occur.
Friedemann Kleint's avatar
Friedemann Kleint committed
710
    // As of version 6.11, the initial breakpoint suppression has no effect (see notifyException).
711
712
    // when attaching to a console process starting up. However, there is no initial breakpoint
    // (and no startup trap), when attaching to a running GUI process.
Friedemann Kleint's avatar
Friedemann Kleint committed
713
    const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS|DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
714
    const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags);
Friedemann Kleint's avatar
Friedemann Kleint committed
715
    if (debugCDB)
Friedemann Kleint's avatar
Friedemann Kleint committed
716
        qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr << executionStatusString(m_d->m_cif.debugControl);
Friedemann Kleint's avatar
Friedemann Kleint committed
717
    if (FAILED(hr)) {
Friedemann Kleint's avatar
Friedemann Kleint committed
718
        *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
Friedemann Kleint's avatar
Friedemann Kleint committed
719
        return false;
720
    } else {
721
        m_d->m_mode = sm;
Friedemann Kleint's avatar
Friedemann Kleint committed
722
723
724
725
    }
    return true;
}

726
bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
727
{
hjk's avatar
hjk committed
728
    showStatusMessage("Starting Debugger", -1);
Banana Joe's avatar
Banana Joe committed
729
730
731
732
733

    DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
    memset(&dbgopts, 0, sizeof(dbgopts));
    dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;

hjk's avatar
hjk committed
734
    const QSharedPointer<DebuggerStartParameters> sp = manager()->startParameters();
735
    const QString filename(sp->executable);
736
737
738
739
740
741
742
    // Set image path
    const QFileInfo fi(filename);
    QString imagePath = QDir::toNativeSeparators(fi.absolutePath());
    if (!m_d->m_baseImagePath.isEmpty()) {
        imagePath += QLatin1Char(';');
        imagePath += m_d->m_baseImagePath;
    }
743
744
745
746
747
748
    HRESULT hr = m_d->m_cif.debugSymbols->SetImagePathWide(reinterpret_cast<PCWSTR>(imagePath.utf16()));
    if (FAILED(hr)) {
        *errorMessage = tr("Unable to set the image path to %1: %2").arg(imagePath, msgComFailed("SetImagePathWide", hr));
        return false;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
749
    if (debugCDB)
750
        qDebug() << Q_FUNC_INFO <<'\n' << filename << imagePath;
Banana Joe's avatar
Banana Joe committed
751

752
753
754
755
    ULONG symbolOptions = SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS;
    if (m_d->m_options->verboseSymbolLoading)
        symbolOptions |= SYMOPT_DEBUG;
    m_d->m_cif.debugSymbols->SetSymbolOptions(symbolOptions);
Banana Joe's avatar
Banana Joe committed
756

757
    const QString cmd = Utils::AbstractProcess::createWinCommandline(filename, sp->processArgs);
Friedemann Kleint's avatar
Friedemann Kleint committed
758
759
760
761
    if (debugCDB)
        qDebug() << "Starting " << cmd;
    PCWSTR env = 0;
    QByteArray envData;
762
    if (!sp->environment.empty()) {
763
        envData = Utils::AbstractProcess::createWinEnvironment(Utils::AbstractProcess::fixWinEnvironment(sp->environment));
Friedemann Kleint's avatar
Friedemann Kleint committed
764
765
        env = reinterpret_cast<PCWSTR>(envData.data());
    }
766
767
768
769
770
771
772
773
774
    // The working directory cannot be empty.
    PCWSTR workingDirC = 0;
    const QString workingDir = sp->workingDir.isEmpty() ? QString() : QDir::toNativeSeparators(sp->workingDir);
    if (!workingDir.isEmpty())
        workingDirC = workingDir.utf16();
    hr = m_d->m_cif.debugClient->CreateProcess2Wide(NULL,
                                                    reinterpret_cast<PWSTR>(const_cast<ushort *>(cmd.utf16())),
                                                    &dbgopts, sizeof(dbgopts),
                                                    workingDirC, env);
Friedemann Kleint's avatar
Friedemann Kleint committed
775
    if (FAILED(hr)) {
Friedemann Kleint's avatar
Friedemann Kleint committed
776
        *errorMessage = tr("Unable to create a process '%1': %2").arg(cmd, msgDebugEngineComResult(hr));
Friedemann Kleint's avatar
Friedemann Kleint committed
777
        return false;
778
779
    } else {
        m_d->m_mode = sm;
Banana Joe's avatar
Banana Joe committed
780
781
782
783
    }
    return true;
}

784
void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
Friedemann Kleint's avatar
Friedemann Kleint committed
785
{   
786
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
787
788
789
790
791
792
793
    setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle));
    ULONG currentThreadId;
    if (SUCCEEDED(m_cif.debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, &currentThreadId))) {
        m_currentThreadId = currentThreadId;
    } else {
        m_currentThreadId = 0;
    }
794
795
    // Clear any saved breakpoints and set initial breakpoints
    m_engine->executeDebuggerCommand(QLatin1String("bc"));
Friedemann Kleint's avatar
Friedemann Kleint committed
796
797
798
    if (manager()->breakHandler()->hasPendingBreakpoints()) {
        if (debugCDBExecution)
            qDebug() << "processCreatedAttached: Syncing breakpoints";
799
        m_engine->attemptBreakpointSynchronization();
Friedemann Kleint's avatar
Friedemann Kleint committed
800
    }
801
802
803
    // 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
804
        const QString crashParameter = manager()->startParameters()->crashParameter;
805
806
807
808
809
810
811
        if (!crashParameter.isEmpty()) {
            ULONG64 evtNr = crashParameter.toULongLong();
            const HRESULT hr = m_cif.debugControl->SetNotifyEventHandle(evtNr);
            if (FAILED(hr))
                m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(msgComFailed("SetNotifyEventHandle", hr)));
        }
    }
812
    m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
Friedemann Kleint's avatar
Friedemann Kleint committed
813
814
    if (debugCDBExecution)
        qDebug() << "<processCreatedAttached" << executionStatusString(m_cif.debugControl);
815
816
}

817
818
void CdbDebugEngine::processTerminated(unsigned long exitCode)
{
819
820
    manager()->showDebuggerOutput(LogMisc, tr("The process exited with exit code %1.").arg(exitCode));
    setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__);
821
    m_d->setDebuggeeHandles(0, 0);
822
823
824
825
    m_d->clearForRun();
    setState(InferiorShutDown, Q_FUNC_INFO, __LINE__);
    // Avoid calls from event handler.
    QTimer::singleShot(0, manager(), SLOT(exitDebugger()));
826
827
}

828
bool CdbDebugEnginePrivate::endInferior(EndInferiorAction action, QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
829
{
830
831
    // 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
832
    const bool wasRunning = isDebuggeeRunning();
833
834
    if (wasRunning) {
        interruptInterferiorProcess(errorMessage);
Friedemann Kleint's avatar
Friedemann Kleint committed
835
        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
836
    }
837
    bool success = false;
Friedemann Kleint's avatar
Friedemann Kleint committed
838
    switch (action) {
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
    case DetachInferior: {            
            const HRESULT hr = m_cif.debugClient->DetachCurrentProcess();
            if (SUCCEEDED(hr)) {
                success = true;
            } else {
                *errorMessage += msgComFailed("DetachCurrentProcess", hr);
            }
        }
            break;
    case TerminateInferior: {
            do {
                // The exit process event handler will not be called.
                HRESULT hr = m_cif.debugClient->TerminateCurrentProcess();
                if (FAILED(hr)) {
                    *errorMessage += msgComFailed("TerminateCurrentProcess", hr);
                    break;
                }
                if (wasRunning) {
                    success = true;
                    break;
                }
                hr = m_cif.debugClient->TerminateProcesses();
                if (SUCCEEDED(hr)) {
                    success = true;
                } else {
                    *errorMessage += msgComFailed("TerminateProcesses", hr);
                }
            } while (false);
            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
            break;
869
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
870
    }
871
    // Perform cleanup even when failed..no point clinging to the process
Friedemann Kleint's avatar
Friedemann Kleint committed
872
873
    setDebuggeeHandles(0, 0);
    m_engine->killWatchTimer();
874
875
876
    m_engine->setState(success ? InferiorShutDown : InferiorShutdownFailed, Q_FUNC_INFO, __LINE__);
    return success;
}
877

878
879
880
881
882
883
884
// 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;
885

886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
    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.)
    m_engine->setState(AdapterShuttingDown, Q_FUNC_INFO, __LINE__);
    clearForRun();
    const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE);
    if (SUCCEEDED(hr)) {
        m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
    } else {
        m_engine->setState(AdapterShutdownFailed, Q_FUNC_INFO, __LINE__);
        m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
        errorMessage = QString::fromLatin1("There were errors trying to end debugging: %1").arg(msgComFailed("EndSession", hr));
Friedemann Kleint's avatar
Friedemann Kleint committed
924
        manager()->showDebuggerOutput(LogError, errorMessage);
925
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
926
927
928
929
930
931
932
933
934
935
}

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

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

938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
CdbStackFrameContext *CdbDebugEnginePrivate::getStackFrameContext(int frameIndex, QString *errorMessage) const
{
    if (!m_currentStackTrace) {
        *errorMessage = QLatin1String(msgNoStackTraceC);
        return 0;
    }
    if (CdbStackFrameContext *sg = m_currentStackTrace->frameContextAt(frameIndex, errorMessage))
        return sg;
    return 0;
}

void CdbDebugEngine::evaluateWatcher(WatchData *wd)
{
    if (debugCDBWatchHandling)
        qDebug() << Q_FUNC_INFO << wd->exp;
    QString errorMessage;
    QString value;
    QString type;
    if (evaluateExpression(wd->exp, &value, &type, &errorMessage)) {
        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
975
    WatchHandler *watchHandler = manager()->watchHandler();
976
977
978
979
980
981
982
    if (incomplete.iname.startsWith(QLatin1String("watch."))) {
        WatchData watchData = incomplete;
        evaluateWatcher(&watchData);
        watchHandler->insertData(watchData);
        return;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
983
    const int frameIndex = manager()->stackHandler()->currentIndex();
984
985
986
987
988
989
990
991
992
993
994
995
996

    bool success = false;
    QString errorMessage;
    do {
        CdbStackFrameContext *sg = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
        if (!sg)
            break;
        if (!sg->completeData(incomplete, watchHandler, &errorMessage))
            break;
        success = true;
    } while (false);
    if (!success)
        warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
997
    if (debugCDBWatchHandling > 1)
Friedemann Kleint's avatar
Friedemann Kleint committed
998
        qDebug() << *manager()->watchHandler()->model(LocalsWatch);
999
1000
}

1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
// 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();
    setCodeLevel(); // Step by instruction
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
    manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Continuing with '%1'...").arg(command));
    QString errorMessage;
    const bool success = CdbDebugEnginePrivate::executeDebuggerCommand(m_cif.debugControl, command, &errorMessage);
    if (success) {
        m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
        m_engine->startWatchTimer();
    } else {
        m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
        m_engine->warning(CdbDebugEngine::tr("Unable to continue: %1").arg(errorMessage));
    }
    return success;
}

1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
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);
}

// Step with  DEBUG_STATUS_STEP_OVER ('p'-command) or
// DEBUG_STATUS_STEP_INTO ('t'-trace-command) or
// its reverse equivalents in the case of single threads.
bool CdbDebugEngine::step(unsigned long executionStatus)
Banana Joe's avatar
Banana Joe committed
1034
{
Friedemann Kleint's avatar
Friedemann Kleint committed
1035
1036
    if (debugCDBExecution)
        qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId;
Friedemann Kleint's avatar
Friedemann Kleint committed
1037

1038
1039
1040
1041
1042
1043
1044
1045
    // 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
1046
1047
1048
1049
1050
1051
    // 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;
    }

1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
    // 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
    m_d->setCodeLevel(); // Step by instruction or source line
1062
    setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
    bool success = false;
    if (sameThread) { // Step event-triggering thread, use fast API
        const HRESULT hr = m_d->m_cif.debugControl->SetExecutionStatus(executionStatus);
        success = SUCCEEDED(hr);
        if (!success)
            warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgComFailed("SetExecutionStatus", hr)));
    } else {
        // Need to use a command to explicitly specify the current thread
        QString command;
        QTextStream str(&command);
        str << '~' << m_d->m_currentThreadId << ' '
                << (executionStatus == DEBUG_STATUS_STEP_OVER ? 'p' : 't');
        manager()->showDebuggerOutput(tr("Stepping %1").arg(command));
        const HRESULT hr = m_d->m_cif.debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO);
        success = SUCCEEDED(hr);
        if (!success)
            warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgDebuggerCommandFailed(command, hr)));
    }
    if (success) {
1082
1083
1084
        // 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;
1085
        startWatchTimer();
1086
1087
1088
1089
        setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
    } else {
        setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
1090
1091
    if (debugCDBExecution)
        qDebug() << "<step samethread" << sameThread << "succeeded" << success;
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
    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()
{      
    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
1113
1114
}

hjk's avatar
hjk committed
1115
void CdbDebugEngine::stepOutExec()