cdbdebugengine.cpp 61.9 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"
40
#include "debuggeragents.h"
Banana Joe's avatar
Banana Joe committed
41

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

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

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

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

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

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

namespace Debugger {
namespace Internal {

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

84
85
// ----- Message helpers

86
QString msgDebugEngineComResult(HRESULT hr)
Friedemann Kleint's avatar
Friedemann Kleint committed
87
88
{
    switch (hr) {
89
90
91
92
        case S_OK:
        return QLatin1String("S_OK");
        case S_FALSE:
        return QLatin1String("S_FALSE");
Friedemann Kleint's avatar
Friedemann Kleint committed
93
94
95
96
97
98
99
100
101
102
103
        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:
104
        return QLatin1String("E_NOTIMPL");
Friedemann Kleint's avatar
Friedemann Kleint committed
105
106
107
108
109
    }
    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");
110
    return QLatin1String("E_FAIL ") + Core::Utils::winErrorMessage(HRESULT_CODE(hr));
Friedemann Kleint's avatar
Friedemann Kleint committed
111
112
}

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

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

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

125
126
127
128
129
130
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);
}

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// 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);
}

147
148
// ----- Engine helpers

149
static inline ULONG getInterruptTimeOutSecs(CIDebugControl *ctl)
150
151
152
153
154
155
{
    ULONG rc = 0;
    ctl->GetInterruptTimeout(&rc);
    return rc;
}

156
157
158
bool getExecutionStatus(CIDebugControl *ctl,
                        ULONG *executionStatus,
                        QString *errorMessage /* = 0 */)
159
160
161
{
    const HRESULT hr = ctl->GetExecutionStatus(executionStatus);
    if (FAILED(hr)) {
162
163
        if (errorMessage)
            *errorMessage = msgComFailed("GetExecutionStatus", hr);
164
165
166
167
168
        return false;
    }
    return true;
}

169
170
171
172
173
174
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
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>";
}

217
// --------- DebuggerEngineLibrary
Friedemann Kleint's avatar
Friedemann Kleint committed
218
219
220
221
222
DebuggerEngineLibrary::DebuggerEngineLibrary() :
    m_debugCreate(0)
{
}

223
224
// 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
225
{
226
227
228
229
230
231
232
    QString rc = path;
    if (!rc.isEmpty())
        rc += QDir::separator();
    rc += libName;
    rc += QLatin1String(".dll");
    return rc;
}
Friedemann Kleint's avatar
Friedemann Kleint committed
233

234
235
236
237
238
239
240
241
242
243
244
245
bool DebuggerEngineLibrary::init(const QString &path, QString *errorMessage)
{
    // 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
246
    if (!lib.isLoaded() && !lib.load()) {
247
        *errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString());
Friedemann Kleint's avatar
Friedemann Kleint committed
248
249
250
251
252
253
254
255
256
257
258
259
260
        return false;
    }
    // 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;
}

261
// ----- SyntaxSetter
262
SyntaxSetter::SyntaxSetter(CIDebugControl *ctl, ULONG desiredSyntax) :
Friedemann Kleint's avatar
Friedemann Kleint committed
263
264
265
266
267
268
269
270
271
272
273
274
275
276
    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);
}

277
278
279
280
281
282
283
284
285
286
287
// CdbComInterfaces
CdbComInterfaces::CdbComInterfaces() :
    debugClient(0),
    debugControl(0),
    debugSystemObjects(0),
    debugSymbols(0),
    debugRegisters(0),
    debugDataSpaces(0)
{
}

Friedemann Kleint's avatar
Friedemann Kleint committed
288
289
// --- CdbDebugEnginePrivate

hjk's avatar
hjk committed
290
CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
291
292
293
                                             const QSharedPointer<CdbOptions> &options,
                                             CdbDebugEngine* engine) :
    m_options(options),
Banana Joe's avatar
Banana Joe committed
294
295
    m_hDebuggeeProcess(0),
    m_hDebuggeeThread(0),
296
    m_breakEventMode(BreakEventHandle),
hjk's avatar
hjk committed
297
    m_dumper(new CdbDumperHelper(manager, &m_cif)),
Banana Joe's avatar
Banana Joe committed
298
    m_watchTimer(-1),
299
    m_debugEventCallBack(engine),
Friedemann Kleint's avatar
Friedemann Kleint committed
300
    m_engine(engine),
301
    m_currentStackTrace(0),
Friedemann Kleint's avatar
Friedemann Kleint committed
302
    m_firstActivatedFrame(true),
303
    m_mode(AttachCore)
304
{
305
306
307
}

bool CdbDebugEnginePrivate::init(QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
308
{
309
    enum {  bufLen = 10240 };
310
311
    // Load the DLL
    DebuggerEngineLibrary lib;
312
    if (!lib.init(m_options->path, errorMessage))
313
314
315
        return false;

    // Initialize the COM interfaces
Banana Joe's avatar
Banana Joe committed
316
    HRESULT hr;
317
    hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient));
Friedemann Kleint's avatar
Friedemann Kleint committed
318
    if (FAILED(hr)) {
319
320
        *errorMessage = QString::fromLatin1("Creation of IDebugClient5 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
Friedemann Kleint's avatar
Friedemann Kleint committed
321
322
    }

323
324
    m_cif.debugClient->SetOutputCallbacksWide(&m_debugOutputCallBack);
    m_cif.debugClient->SetEventCallbacksWide(&m_debugEventCallBack);
325

326
    hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_cif.debugControl));
Friedemann Kleint's avatar
Friedemann Kleint committed
327
    if (FAILED(hr)) {
328
329
        *errorMessage = QString::fromLatin1("Creation of IDebugControl4 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
Friedemann Kleint's avatar
Friedemann Kleint committed
330
331
    }

332
    setCodeLevel();
333

334
    hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_cif.debugSystemObjects));
335
336
337
338
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugSystemObjects4 failed: %1").arg(msgDebugEngineComResult(hr));
        return false;
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
339

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

346
347
348
349
350
351
352
353
    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);

354
    hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_cif.debugRegisters));
355
356
    if (FAILED(hr)) {
        *errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
357
        return false;
358
    }
359
360
361
362
363
364
365

    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;
    }

366
    if (debugCDB)
367
        qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_cif.debugControl));
368
    return true;
Friedemann Kleint's avatar
Friedemann Kleint committed
369
}
Banana Joe's avatar
Banana Joe committed
370

371
IDebuggerEngine *CdbDebugEngine::create(Debugger::DebuggerManager *manager,
372
373
                                        const QSharedPointer<CdbOptions> &options,
                                        QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
374
{
hjk's avatar
hjk committed
375
    CdbDebugEngine *rc = new CdbDebugEngine(manager, options);
376
377
    if (rc->m_d->init(errorMessage)) {
        rc->syncDebuggerPaths();
378
        return rc;
379
    }
380
381
    delete rc;
    return 0;
Banana Joe's avatar
Banana Joe committed
382
383
}

384
385
386
387
388
389
390
391
// 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
392
    const ULONG codeLevel = theDebuggerBoolSetting(OperateByInstruction) ?
393
394
395
396
397
398
399
400
401
                            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) << ')';
402
    if (currentCodeLevel == codeLevel)
403
404
405
406
407
408
409
410
411
        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;
}

412
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
Banana Joe's avatar
Banana Joe committed
413
{
414
    cleanStackTrace();
415
416
417
418
419
420
421
422
423
424
425
426
    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
427
428
}

Friedemann Kleint's avatar
Friedemann Kleint committed
429
430
431
432
433
DebuggerManager *CdbDebugEnginePrivate::manager() const
{
    return m_engine->manager();
}

434
void CdbDebugEnginePrivate::clearForRun()
435
436
437
438
{
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

439
440
441
    m_breakEventMode = BreakEventHandle;
    m_firstActivatedFrame = false;
    cleanStackTrace();
442
    m_editorToolTipCache.clear();
443
444
445
}

void CdbDebugEnginePrivate::cleanStackTrace()
446
{
447
448
449
450
451
452
    if (m_currentStackTrace) {
        delete m_currentStackTrace;
        m_currentStackTrace = 0;
    }
}

hjk's avatar
hjk committed
453
CdbDebugEngine::CdbDebugEngine(DebuggerManager *manager, const QSharedPointer<CdbOptions> &options) :
Friedemann Kleint's avatar
Friedemann Kleint committed
454
455
    IDebuggerEngine(manager),
    m_d(new CdbDebugEnginePrivate(manager, options, this))
456
{
457
    m_d->m_consoleStubProc.setMode(Core::Utils::ConsoleProcess::Suspend);
hjk's avatar
hjk committed
458
459
460
461
462
463
    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()));
464
    connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerOutput(int,QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
465
            manager, SLOT(showDebuggerOutput(int,QString)));
466
    connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerInputPrompt(int,QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
467
            manager, SLOT(showDebuggerInput(int,QString)));
468
    connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeOutput(QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
469
            manager, SLOT(showApplicationOutput(QString)));
470
    connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeInputPrompt(QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
471
            manager, SLOT(showApplicationOutput(QString)));
472
473
474
475
476
477
478
}

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

479
480
481
482
483
484
485
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
486
void CdbDebugEngine::startWatchTimer()
Banana Joe's avatar
Banana Joe committed
487
{
488
489
490
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

491
492
    if (m_d->m_watchTimer == -1)
        m_d->m_watchTimer = startTimer(0);
Banana Joe's avatar
Banana Joe committed
493
494
}

hjk's avatar
hjk committed
495
void CdbDebugEngine::killWatchTimer()
Banana Joe's avatar
Banana Joe committed
496
{
497
498
499
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

500
501
502
    if (m_d->m_watchTimer != -1) {
        killTimer(m_d->m_watchTimer);
        m_d->m_watchTimer = -1;
Banana Joe's avatar
Banana Joe committed
503
504
505
    }
}

hjk's avatar
hjk committed
506
void CdbDebugEngine::shutdown()
Banana Joe's avatar
Banana Joe committed
507
508
509
510
{
    exitDebugger();
}

511
QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &function)
Banana Joe's avatar
Banana Joe committed
512
{
513
514
515
516
517
518
    // 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
519
    CdbStackFrameContext *frame = 0;
520
521
    if (m_d->m_currentStackTrace &&  !function.isEmpty()) {
        const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
522
523
        if (frameIndex != -1)
            frame = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
524
    }
525
526
    if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
        return rc;
527
528
529
530
531
532
533
534
535
536
537
    // 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;
538
    if (debugCDB)
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
        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
571
572
}

573
574
void CdbDebugEnginePrivate::clearDisplay()
{
Friedemann Kleint's avatar
Friedemann Kleint committed
575
576
577
    manager()->threadsHandler()->removeAll();
    manager()->modulesHandler()->removeAll();
    manager()->registerHandler()->removeAll();
578
579
}

hjk's avatar
hjk committed
580
void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
581
582
{    
    setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
583
584
    if (m_d->m_hDebuggeeProcess) {
        warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
585
        setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
586
        emit startFailed();
587
    }
588
    m_d->clearDisplay();
589
    setState(AdapterStarted, Q_FUNC_INFO, __LINE__);
590

591
    setState(InferiorPreparing, Q_FUNC_INFO, __LINE__);
Friedemann Kleint's avatar
Friedemann Kleint committed
592
    const DebuggerStartMode mode = sp->startMode;
593
    // Figure out dumper. @TODO: same in gdb...
Friedemann Kleint's avatar
Friedemann Kleint committed
594
    const QString dumperLibName = QDir::toNativeSeparators(manager()->qtDumperLibraryName());
595
596
    bool dumperEnabled = mode != AttachCore
                         && mode != AttachCrashedExternal
Friedemann Kleint's avatar
Friedemann Kleint committed
597
                         && manager()->qtDumperLibraryEnabled();
598
599
600
    if (dumperEnabled) {
        const QFileInfo fi(dumperLibName);
        if (!fi.isFile()) {
Friedemann Kleint's avatar
Friedemann Kleint committed
601
            const QStringList &locations = manager()->qtDumperLibraryLocations();
602
603
            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
604
            manager()->showQtDumperLibraryWarning(msg);
605
606
607
            dumperEnabled = false;
        }
    }
608
    m_d->m_dumper->reset(dumperLibName, dumperEnabled);
609
610
611

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

Friedemann Kleint's avatar
Friedemann Kleint committed
614
615
    QString errorMessage;
    bool rc = false;
616
    bool needWatchTimer = false;
617
    m_d->clearForRun();
618
    m_d->setCodeLevel();
619
    switch (mode) {
Friedemann Kleint's avatar
Friedemann Kleint committed
620
    case AttachExternal:
621
622
623
    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
624
625
626
        break;
    case StartInternal:
    case StartExternal:
627
        if (sp->useTerminal) {
628
629
            // Launch console stub and wait for its startup
            m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
630
631
632
            m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDir);
            m_d->m_consoleStubProc.setEnvironment(sp->environment);
            rc = m_d->m_consoleStubProc.start(sp->executable, sp->processArgs);
633
            if (!rc)
634
                errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp->executable);
635
            // continues in slotConsoleStubStarted()...
636
        } else {
637
            needWatchTimer = true;
638
639
            rc = startDebuggerWithExecutable(mode, &errorMessage);
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
640
641
        break;
    case AttachCore:
Friedemann Kleint's avatar
Friedemann Kleint committed
642
        errorMessage = tr("Attaching to core files is not supported!");
Friedemann Kleint's avatar
Friedemann Kleint committed
643
644
645
        break;
    }
    if (rc) {
Friedemann Kleint's avatar
Friedemann Kleint committed
646
        manager()->showStatusMessage(tr("Debugger running"), -1);
647
648
        if (needWatchTimer)
            startWatchTimer();
649
            emit startSuccessful();
Friedemann Kleint's avatar
Friedemann Kleint committed
650
    } else {
651
        warning(errorMessage);
652
        setState(InferiorStartFailed, Q_FUNC_INFO, __LINE__);
hjk's avatar
hjk committed
653
        emit startFailed();
654
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
655
}
Banana Joe's avatar
Banana Joe committed
656

657
bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
658
{
659
    // Need to attrach invasively, otherwise, no notification signals
660
    // for for CreateProcess/ExitProcess occur.
661
662
    const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
    const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags);
Friedemann Kleint's avatar
Friedemann Kleint committed
663
    if (debugCDB)
664
        qDebug() << "Attaching to " << pid << " returns " << hr << executionStatusString(m_d->m_cif.debugControl);
Friedemann Kleint's avatar
Friedemann Kleint committed
665
    if (FAILED(hr)) {
Friedemann Kleint's avatar
Friedemann Kleint committed
666
        *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
Friedemann Kleint's avatar
Friedemann Kleint committed
667
        return false;
668
    } else {
669
        m_d->m_mode = sm;
Friedemann Kleint's avatar
Friedemann Kleint committed
670
671
672
673
    }
    return true;
}

674
bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage)
Friedemann Kleint's avatar
Friedemann Kleint committed
675
{
hjk's avatar
hjk committed
676
    showStatusMessage("Starting Debugger", -1);
Banana Joe's avatar
Banana Joe committed
677
678
679
680
681

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

hjk's avatar
hjk committed
682
    const QSharedPointer<DebuggerStartParameters> sp = manager()->startParameters();
683
    const QString filename(sp->executable);
684
685
686
687
688
689
690
    // 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;
    }
691
692
693
694
695
696
    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
697
    if (debugCDB)
698
        qDebug() << Q_FUNC_INFO <<'\n' << filename << imagePath;
Banana Joe's avatar
Banana Joe committed
699

700
701
702
703
    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
704

705
    const QString cmd = Core::Utils::AbstractProcess::createWinCommandline(filename, sp->processArgs);
Friedemann Kleint's avatar
Friedemann Kleint committed
706
707
708
709
    if (debugCDB)
        qDebug() << "Starting " << cmd;
    PCWSTR env = 0;
    QByteArray envData;
710
711
    if (!sp->environment.empty()) {
        envData = Core::Utils::AbstractProcess::createWinEnvironment(Core::Utils::AbstractProcess::fixWinEnvironment(sp->environment));
Friedemann Kleint's avatar
Friedemann Kleint committed
712
713
        env = reinterpret_cast<PCWSTR>(envData.data());
    }
714
715
716
717
718
719
720
721
722
    // 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
723
    if (FAILED(hr)) {
Friedemann Kleint's avatar
Friedemann Kleint committed
724
        *errorMessage = tr("Unable to create a process '%1': %2").arg(cmd, msgDebugEngineComResult(hr));
Friedemann Kleint's avatar
Friedemann Kleint committed
725
        return false;
726
727
    } else {
        m_d->m_mode = sm;
Banana Joe's avatar
Banana Joe committed
728
729
730
731
    }
    return true;
}

732
733
void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
{
734
    m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
735
736
737
738
739
740
741
    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;
    }
742
743
    // Clear any saved breakpoints and set initial breakpoints
    m_engine->executeDebuggerCommand(QLatin1String("bc"));
Friedemann Kleint's avatar
Friedemann Kleint committed
744
    if (manager()->breakHandler()->hasPendingBreakpoints())
745
        m_engine->attemptBreakpointSynchronization();
746
747
748
    // 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
749
        const QString crashParameter = manager()->startParameters()->crashParameter;
750
751
752
753
754
755
756
        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)));
        }
    }
757
    m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
758
759
    if (debugCDB)
        qDebug() << Q_FUNC_INFO << '\n' << executionStatusString(m_cif.debugControl);
760
761
}

762
763
void CdbDebugEngine::processTerminated(unsigned long exitCode)
{
764
765
    manager()->showDebuggerOutput(LogMisc, tr("The process exited with exit code %1.").arg(exitCode));
    setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__);
766
    m_d->setDebuggeeHandles(0, 0);
767
768
769
770
    m_d->clearForRun();
    setState(InferiorShutDown, Q_FUNC_INFO, __LINE__);
    // Avoid calls from event handler.
    QTimer::singleShot(0, manager(), SLOT(exitDebugger()));
771
772
}

773
bool CdbDebugEnginePrivate::endInferior(EndInferiorAction action, QString *errorMessage)
Banana Joe's avatar
Banana Joe committed
774
{
775
776
    // 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
777
    const bool wasRunning = isDebuggeeRunning();
778
779
    if (wasRunning) {
        interruptInterferiorProcess(errorMessage);
Friedemann Kleint's avatar
Friedemann Kleint committed
780
        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
781
    }
782
    bool success = false;
Friedemann Kleint's avatar
Friedemann Kleint committed
783
    switch (action) {
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
    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;
814
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
815
    }
816
    // Perform cleanup even when failed..no point clinging to the process
Friedemann Kleint's avatar
Friedemann Kleint committed
817
818
    setDebuggeeHandles(0, 0);
    m_engine->killWatchTimer();
819
820
821
    m_engine->setState(success ? InferiorShutDown : InferiorShutdownFailed, Q_FUNC_INFO, __LINE__);
    return success;
}
822

823
824
825
826
827
828
829
// 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;
830

831
832
833
834
835
836
837
838
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
    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
869
        manager()->showDebuggerOutput(LogError, errorMessage);
870
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
871
872
873
874
875
876
877
878
879
880
}

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

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

883
884
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
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
920
    WatchHandler *watchHandler = manager()->watchHandler();
921
922
923
924
925
926
927
    if (incomplete.iname.startsWith(QLatin1String("watch."))) {
        WatchData watchData = incomplete;
        evaluateWatcher(&watchData);
        watchHandler->insertData(watchData);
        return;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
928
    const int frameIndex = manager()->stackHandler()->currentIndex();
929
930
931
932
933
934
935
936
937
938
939
940
941

    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));
942
    if (debugCDBWatchHandling > 1)
Friedemann Kleint's avatar
Friedemann Kleint committed
943
        qDebug() << *manager()->watchHandler()->model(LocalsWatch);
944
945
}

hjk's avatar
hjk committed
946
void CdbDebugEngine::stepExec()
Banana Joe's avatar
Banana Joe committed
947
{
Friedemann Kleint's avatar
Friedemann Kleint committed
948
949
950
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

951
    m_d->clearForRun();
952
    m_d->setCodeLevel();
953
    setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
954
    const HRESULT hr = m_d->m_cif.debugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
955
956
957
958
    if (SUCCEEDED(hr)) {
        setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
    } else {
        setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
959
        warning(msgFunctionFailed(Q_FUNC_INFO, msgComFailed("SetExecutionStatus", hr)));
960
    }
961
    m_d->m_breakEventMode = CdbDebugEnginePrivate::BreakEventIgnoreOnce;
Banana Joe's avatar
Banana Joe committed
962
963
964
    startWatchTimer();
}

hjk's avatar
hjk committed
965
void CdbDebugEngine::stepOutExec()
Banana Joe's avatar
Banana Joe committed
966
{
Friedemann Kleint's avatar
Friedemann Kleint committed
967
968
969
    if (debugCDB)
        qDebug() << Q_FUNC_INFO;

Friedemann Kleint's avatar
Friedemann Kleint committed
970
    StackHandler* sh = manager()->stackHandler();
Banana Joe's avatar
Banana Joe committed
971
972
973
    const int idx = sh->currentIndex() + 1;
    QList<StackFrame> stackframes = sh->frames();
    if (idx < 0 || idx >= stackframes.size()) {
974
        warning(QString::fromLatin1("Cannot step out of stack frame %1").arg(idx));
Banana Joe's avatar
Banana Joe committed
975
976
977
        return;
    }

978
    // Set a temporary breakpoint and continue
Banana Joe's avatar
Banana Joe committed
979
    const StackFrame& frame = stackframes.at(idx);
980
981
982
983
984
985
986
987
    bool success = false;
    QString errorMessage;
    do {
        const ULONG64 address = frame.address.toULongLong(&success, 16);
        if (!success) {
            errorMessage = QLatin1String("Cannot obtain address from stack frame");
            break;
        }
Banana Joe's avatar
Banana Joe committed
988

989
        IDebugBreakpoint2* pBP;
990
        HRESULT hr = m_d->m_cif.debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &pBP);
991
992
993
994
        if (FAILED(hr) || !pBP) {
            errorMessage = QString::fromLatin1("Cannot create temporary breakpoint: %1").arg(msgDebugEngineComResult(hr));
            break;
        }
Banana Joe's avatar
Banana Joe committed
995

996
997
998
999
1000
1001
1002
1003
        pBP->SetOffset(address);
        pBP->AddFlags(DEBUG_BREAKPOINT_ENABLED);
        pBP->AddFlags(DEBUG_BREAKPOINT_ONE_SHOT);
        if (!m_d->continueInferior(&errorMessage))
            break;
        success = true;
    } while (false);
    if (!success)
Friedemann Kleint's avatar