OSDN Git Service

Merge remote branch 'origin/2.0'
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / cdb / cdbdebugengine.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** 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
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #include "cdbdebugengine.h"
31 #include "cdbdebugengine_p.h"
32 #include "cdbdebugoutput.h"
33 #include "cdbdebugeventcallback.h"
34 #include "cdbstacktracecontext.h"
35 #include "cdbsymbolgroupcontext.h"
36 #include "cdbbreakpoint.h"
37 #include "cdbmodules.h"
38 #include "cdbassembler.h"
39 #include "cdboptionspage.h"
40 #include "cdboptions.h"
41 #include "cdbexceptionutils.h"
42 #include "debuggeragents.h"
43 #include "debuggeruiswitcher.h"
44 #include "debuggermainwindow.h"
45
46 #include "debuggeractions.h"
47 #include "debuggermanager.h"
48 #include "breakhandler.h"
49 #include "stackhandler.h"
50 #include "watchhandler.h"
51 #include "registerhandler.h"
52 #include "moduleshandler.h"
53 #include "watchutils.h"
54
55 #include <coreplugin/icore.h>
56 #include <utils/qtcassert.h>
57 #include <utils/winutils.h>
58 #include <utils/consoleprocess.h>
59 #include <utils/fancymainwindow.h>
60 #include <texteditor/itexteditor.h>
61 #include <utils/savedaction.h>
62
63 #include <QtCore/QDebug>
64 #include <QtCore/QTimer>
65 #include <QtCore/QTimerEvent>
66 #include <QtCore/QFileInfo>
67 #include <QtCore/QDir>
68 #include <QtCore/QLibrary>
69 #include <QtCore/QCoreApplication>
70 #include <QtGui/QMessageBox>
71 #include <QtGui/QMainWindow>
72 #include <QtGui/QApplication>
73 #include <QtGui/QToolTip>
74
75 #define DBGHELP_TRANSLATE_TCHAR
76 #include <inc/Dbghelp.h>
77
78 static const char *localSymbolRootC = "local";
79
80 namespace Debugger {
81 namespace Internal {
82
83 typedef QList<WatchData> WatchList;
84
85 // ----- Message helpers
86
87 static QString msgStackIndexOutOfRange(int idx, int size)
88 {
89     return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
90 }
91
92 QString msgDebuggerCommandFailed(const QString &command, HRESULT hr)
93 {
94     return QString::fromLatin1("Unable to execute '%1': %2").arg(command, CdbCore::msgDebugEngineComResult(hr));
95 }
96
97 static const char *msgNoStackTraceC = "Internal error: no stack trace present.";
98
99 // Format function failure message. Pass in Q_FUNC_INFO
100 static QString msgFunctionFailed(const char *func, const QString &why)
101 {
102     // Strip a "cdecl_ int namespace1::class::foo(int bar)" as
103     // returned by Q_FUNC_INFO down to "foo"
104     QString function = QLatin1String(func);
105     const int firstParentPos = function.indexOf(QLatin1Char('('));
106     if (firstParentPos != -1)
107         function.truncate(firstParentPos);
108     const int classSepPos = function.lastIndexOf(QLatin1String("::"));
109     if (classSepPos != -1)
110         function.remove(0, classSepPos + 2);
111    //: Function call failed
112    return CdbDebugEngine::tr("The function \"%1()\" failed: %2").arg(function, why);
113 }
114
115 // ----- Engine helpers
116
117 // --- CdbDebugEnginePrivate
118
119 CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
120                                              const QSharedPointer<CdbOptions> &options,
121                                              CdbDebugEngine* engine) :
122     m_options(options),
123     m_hDebuggeeProcess(0),
124     m_hDebuggeeThread(0),
125     m_breakEventMode(BreakEventHandle),
126     m_dumper(new CdbDumperHelper(manager, this)),
127     m_currentThreadId(-1),
128     m_eventThreadId(-1),
129     m_interruptArticifialThreadId(-1),
130     m_ignoreInitialBreakPoint(false),
131     m_interrupted(false),
132     m_engine(engine),
133     m_currentStackTrace(0),
134     m_firstActivatedFrame(true),
135     m_inferiorStartupComplete(false),
136     m_mode(AttachCore),
137     m_stoppedReason(StoppedOther)
138 {
139     connect(this, SIGNAL(watchTimerDebugEvent()), this, SLOT(handleDebugEvent()));
140     connect(this, SIGNAL(modulesLoaded()), this, SLOT(slotModulesLoaded()));
141 }
142
143 bool CdbDebugEnginePrivate::init(QString *errorMessage)
144 {
145     enum {  bufLen = 10240 };
146
147     if (!CdbCore::CoreEngine::init(m_options->path, errorMessage))
148         return false;
149     CdbDebugOutput *output = new CdbDebugOutput;
150     setDebugOutput(DebugOutputBasePtr(output));
151     connect(output, SIGNAL(debuggerOutput(int,QString)),
152             manager(), SLOT(showDebuggerOutput(int,QString)));
153     connect(output, SIGNAL(debuggerInputPrompt(int,QString)),
154             manager(), SLOT(showDebuggerInput(int,QString)));
155     connect(output, SIGNAL(debuggeeOutput(QString,bool)),
156             manager(), SLOT(showApplicationOutput(QString,bool)));
157     connect(output, SIGNAL(debuggeeInputPrompt(QString,bool)),
158             manager(), SLOT(showApplicationOutput(QString,bool)));
159
160     setDebugEventCallback(DebugEventCallbackBasePtr(new CdbDebugEventCallback(m_engine)));
161     updateCodeLevel();
162
163     return true;
164 }
165
166 IDebuggerEngine *CdbDebugEngine::create(Debugger::DebuggerManager *manager,
167                                         const QSharedPointer<CdbOptions> &options,
168                                         QString *errorMessage)
169 {
170     CdbDebugEngine *rc = new CdbDebugEngine(manager, options);
171     if (rc->m_d->init(errorMessage)) {
172         rc->syncDebuggerPaths();
173         return rc;
174     }
175     delete rc;
176     return 0;
177 }
178
179 void  CdbDebugEnginePrivate::updateCodeLevel()
180 {
181     const CdbCore::CoreEngine::CodeLevel cl = theDebuggerBoolSetting(OperateByInstruction) ?
182                                               CdbCore::CoreEngine::CodeLevelAssembly : CdbCore::CoreEngine::CodeLevelSource;
183     setCodeLevel(cl);
184 }
185
186 CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
187 {
188     cleanStackTrace();
189 }
190
191 DebuggerManager *CdbDebugEnginePrivate::manager() const
192 {
193     return m_engine->manager();
194 }
195
196 void CdbDebugEnginePrivate::clearForRun()
197 {
198     if (debugCDB)
199         qDebug() << Q_FUNC_INFO;
200
201     m_breakEventMode = BreakEventHandle;
202     m_eventThreadId = m_interruptArticifialThreadId = -1;
203     m_interrupted = false;
204     cleanStackTrace();
205     m_stoppedReason = StoppedOther;
206     m_stoppedMessage.clear();
207 }
208
209 void CdbDebugEnginePrivate::cleanStackTrace()
210 {
211     if (m_currentStackTrace) {
212         delete m_currentStackTrace;
213         m_currentStackTrace = 0;
214     }
215     m_firstActivatedFrame = false;
216     m_editorToolTipCache.clear();
217 }
218
219 CdbDebugEngine::CdbDebugEngine(DebuggerManager *manager, const QSharedPointer<CdbOptions> &options) :
220     IDebuggerEngine(manager),
221     m_d(new CdbDebugEnginePrivate(manager, options, this))
222 {
223     m_d->m_consoleStubProc.setMode(Utils::ConsoleProcess::Suspend);
224     connect(&m_d->m_consoleStubProc, SIGNAL(processMessage(QString,bool)),
225             this, SLOT(slotConsoleStubMessage(QString, bool)));
226     connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()),
227             this, SLOT(slotConsoleStubStarted()));
228     connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()),
229             this, SLOT(slotConsoleStubTerminated()));
230 }
231
232 CdbDebugEngine::~CdbDebugEngine()
233 {
234     delete m_d;
235 }
236
237 void CdbDebugEngine::setState(DebuggerState state, const char *func, int line)
238 {
239     if (debugCDB)
240         qDebug() << "setState(" << state << ") at " << func << ':' << line;
241     IDebuggerEngine::setState(state);
242 }
243
244 void CdbDebugEngine::shutdown()
245 {
246     exitDebugger();
247 }
248
249 QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &function)
250 {
251     // Figure the editor tooltip. Ask the frame context of the
252     // function if it is a local variable it knows. If that is not
253     // the case, try to evaluate via debugger
254     QString errorMessage;
255     QString rc;
256     // Find the frame of the function if there is any
257     CdbSymbolGroupContext *frame = 0;
258     if (m_d->m_currentStackTrace &&  !function.isEmpty()) {
259         const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
260         if (debugToolTips)
261             qDebug() << "CdbDebugEngine::editorToolTip" << exp << function << frameIndex;
262         if (frameIndex != -1)
263             frame = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
264     }
265     if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
266         return rc;
267     // No function/symbol context found, try to evaluate in current context.
268     // Do not append type as this will mostly be 'long long' for integers, etc.
269     QString type;
270     if (debugToolTips)
271         qDebug() << "Defaulting to expression";
272     if (!m_d->evaluateExpression(exp, &rc, &type, &errorMessage))
273         return QString();
274     return rc;
275 }
276
277 void CdbDebugEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
278 {
279     typedef CdbDebugEnginePrivate::EditorToolTipCache EditorToolTipCache;
280     if (debugCDB)
281         qDebug() << Q_FUNC_INFO << '\n' << cursorPos;
282     // Need a stopped debuggee and a cpp file
283     if (!m_d->m_hDebuggeeProcess || m_d->isDebuggeeRunning())
284         return;
285     if (!isCppEditor(editor))
286         return;
287     // Determine expression and function
288     QString toolTip;
289     do {
290         int line;
291         int column;
292         QString function;
293         const QString exp = cppExpressionAt(editor, cursorPos, &line, &column, &function);
294         if (function.isEmpty() || exp.isEmpty())
295             break;
296         // Check cache (key containing function) or try to figure out expression
297         QString cacheKey = function;
298         cacheKey += QLatin1Char('@');
299         cacheKey += exp;
300         const EditorToolTipCache::const_iterator cit = m_d->m_editorToolTipCache.constFind(cacheKey);
301         if (cit != m_d->m_editorToolTipCache.constEnd()) {
302             toolTip = cit.value();
303         } else {
304             toolTip = editorToolTip(exp, function);
305             if (!toolTip.isEmpty())
306                 m_d->m_editorToolTipCache.insert(cacheKey, toolTip);
307         }
308     } while (false);
309     // Display
310     QToolTip::hideText();
311     if (!toolTip.isEmpty())
312         QToolTip::showText(mousePos, toolTip);
313 }
314
315 void CdbDebugEnginePrivate::clearDisplay()
316 {
317     manager()->threadsHandler()->removeAll();
318     manager()->modulesHandler()->removeAll();
319     manager()->registerHandler()->removeAll();
320 }
321
322 void CdbDebugEnginePrivate::checkVersion()
323 {
324     static bool versionNotChecked = true;
325     // Check for version 6.11 (extended expression syntax)
326     if (versionNotChecked) {
327         versionNotChecked = false;
328         // Get engine DLL version
329         QString errorMessage;
330         const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, dbengDLL(), &errorMessage);
331         if (version.isEmpty()) {
332             qWarning("%s\n", qPrintable(errorMessage));
333             return;
334         }
335         // Compare
336         const double minVersion = 6.11;
337         manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Version: %1").arg(version));
338         if (version.toDouble() <  minVersion) {
339             const QString msg = CdbDebugEngine::tr(
340                     "<html>The installed version of the <i>Debugging Tools for Windows</i> (%1) "
341                     "is rather old. Upgrading to version %2 is recommended "
342                     "for the proper display of Qt's data types.</html>").arg(version).arg(minVersion);
343             Core::ICore::instance()->showWarningWithOptions(CdbDebugEngine::tr("Debugger"), msg, QString(),
344                                                             QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY),
345                                                             CdbOptionsPage::settingsId());
346         }
347     }
348 }
349
350 void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
351 {
352     if (debugCDBExecution)
353         qDebug() << "startDebugger" << *sp;
354     CdbCore::BreakPoint::clearNormalizeFileNameCache();
355     setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
356     m_d->checkVersion();
357     if (m_d->m_hDebuggeeProcess) {
358         warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
359         setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
360         emit startFailed();
361         return;
362     }
363     switch (sp->startMode) {
364     case AttachCore:
365     case AttachToRemote:
366         warning(QLatin1String("Internal error: Mode not supported."));
367         setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
368         emit startFailed();
369         break;
370     default:
371         break;
372     }
373     m_d->m_mode = sp->startMode;
374     m_d->clearDisplay();
375     m_d->m_inferiorStartupComplete = false;
376     setState(AdapterStarted, Q_FUNC_INFO, __LINE__);
377     // Options
378     QString errorMessage;
379     if (!m_d->setBreakOnThrow(theDebuggerBoolSetting(BreakOnThrow), &errorMessage))
380       manager()->showDebuggerOutput(LogWarning, errorMessage);
381     m_d->setVerboseSymbolLoading(m_d->m_options->verboseSymbolLoading);
382     // Figure out dumper. @TODO: same in gdb...
383     const QString dumperLibName = QDir::toNativeSeparators(manager()->qtDumperLibraryName());
384     bool dumperEnabled = m_d->m_mode != AttachCore
385                          && m_d->m_mode != AttachCrashedExternal
386                          && manager()->qtDumperLibraryEnabled();
387     if (dumperEnabled) {
388         const QFileInfo fi(dumperLibName);
389         if (!fi.isFile()) {
390             const QStringList &locations = manager()->qtDumperLibraryLocations();
391             const QString loc = locations.join(QLatin1String(", "));
392             const QString msg = tr("The dumper library was not found at %1.").arg(loc);
393             manager()->showQtDumperLibraryWarning(msg);
394             dumperEnabled = false;
395         }
396     }
397     m_d->m_dumper->reset(dumperLibName, dumperEnabled);
398
399     setState(InferiorStarting, Q_FUNC_INFO, __LINE__);
400     manager()->showStatusMessage("Starting Debugger", messageTimeOut);
401
402     bool rc = false;
403     bool needWatchTimer = false;
404     m_d->clearForRun();
405     m_d->updateCodeLevel();
406     m_d->m_ignoreInitialBreakPoint = false;
407     switch (m_d->m_mode) {
408     case AttachExternal:
409     case AttachCrashedExternal:
410         rc = startAttachDebugger(sp->attachPID, m_d->m_mode, &errorMessage);
411         needWatchTimer = true; // Fetch away module load, etc. even if crashed
412         break;
413     case StartInternal:
414     case StartExternal:
415         if (sp->useTerminal) {
416             // Attaching to console processes triggers an initial breakpoint, which we do not want
417             m_d->m_ignoreInitialBreakPoint = true;
418             // Launch console stub and wait for its startup
419             m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
420             m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDirectory);
421             m_d->m_consoleStubProc.setEnvironment(sp->environment);
422             rc = m_d->m_consoleStubProc.start(sp->executable, sp->processArgs);
423             if (!rc)
424                 errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp->executable);
425             // continues in slotConsoleStubStarted()...
426         } else {
427             needWatchTimer = true;
428             rc = m_d->startDebuggerWithExecutable(sp->workingDirectory,
429                                                   sp->executable,
430                                                   sp->processArgs,
431                                                   sp->environment,
432                                                   &errorMessage);
433         }
434         break;
435     case AttachCore:
436         errorMessage = tr("Attaching to core files is not supported!");
437         break;
438     }
439     if (rc) {
440         if (needWatchTimer)
441             m_d->startWatchTimer();
442             emit startSuccessful();
443     } else {
444         warning(errorMessage);
445         setState(InferiorStartFailed, Q_FUNC_INFO, __LINE__);
446         emit startFailed();
447     }
448 }
449
450 bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage)
451 {
452     // Need to attach invasively, otherwise, no notification signals
453     // for for CreateProcess/ExitProcess occur.
454     // Initial breakpoint occur:
455     // 1) Desired: When attaching to a crashed process
456     // 2) Undesired: When starting up a console process, in conjunction
457     //    with the 32bit Wow-engine
458     //  As of version 6.11, the flag only affects 1). 2) Still needs to be suppressed
459     // by lookup at the state of the application (startup trap). However,
460     // there is no startup trap when attaching to a process that has been
461     // running for a while. (see notifyException).
462     const bool suppressInitialBreakPoint = sm != AttachCrashedExternal;
463     return m_d->startAttachDebugger(pid, suppressInitialBreakPoint, errorMessage);
464 }
465
466 void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
467 {
468     m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
469     setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle));
470     ULONG currentThreadId;
471     if (SUCCEEDED(interfaces().debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, &currentThreadId))) {
472         m_currentThreadId = currentThreadId;
473     } else {
474         m_currentThreadId = 0;
475     }
476     // Clear any saved breakpoints and set initial breakpoints
477     m_engine->executeDebuggerCommand(QLatin1String("bc"));
478     if (manager()->breakHandler()->hasPendingBreakpoints()) {
479         if (debugCDBExecution)
480             qDebug() << "processCreatedAttached: Syncing breakpoints";
481         m_engine->attemptBreakpointSynchronization();
482     }
483     // Attaching to crashed: This handshake (signalling an event) is required for
484     // the exception to be delivered to the debugger
485     // Also, see special handling in slotModulesLoaded().
486     if (m_mode == AttachCrashedExternal) {
487         const QString crashParameter = manager()->startParameters()->crashParameter;
488         if (!crashParameter.isEmpty()) {
489             ULONG64 evtNr = crashParameter.toULongLong();
490             const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr);
491             if (FAILED(hr))
492                 m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(CdbCore::msgComFailed("SetNotifyEventHandle", hr)));
493         }
494     }
495     m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
496     if (debugCDBExecution)
497         qDebug() << "<processCreatedAttached";
498 }
499
500 void CdbDebugEngine::processTerminated(unsigned long exitCode)
501 {
502     manager()->showDebuggerOutput(LogMisc, tr("The process exited with exit code %1.").arg(exitCode));
503     if (state() != InferiorStopping)
504         setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
505     setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
506     setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__);
507     m_d->setDebuggeeHandles(0, 0);
508     m_d->clearForRun();
509     setState(InferiorShutDown, Q_FUNC_INFO, __LINE__);
510     // Avoid calls from event handler.
511     QTimer::singleShot(0, manager(), SLOT(exitDebugger()));
512 }
513
514 bool CdbDebugEnginePrivate::endInferior(EndInferiorAction action, QString *errorMessage)
515 {
516     // Process must be stopped in order to terminate
517     m_engine->setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__); // pretend it is shutdown
518     const bool wasRunning = isDebuggeeRunning();
519     if (wasRunning) {
520         interruptInterferiorProcess(errorMessage);
521         QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
522     }
523     bool success = false;
524     switch (action) {
525     case DetachInferior:
526             if (detachCurrentProcess(errorMessage))
527                 success = true;
528             break;
529     case TerminateInferior:
530             do {
531                 // The exit process event handler will not be called.
532                 terminateCurrentProcess(errorMessage);
533                 if (wasRunning) {
534                     success = true;
535                     break;
536                 }
537                 if (terminateProcesses(errorMessage))
538                     success = true;
539             } while (false);
540             QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
541             break;
542     }
543     // Perform cleanup even when failed..no point clinging to the process
544     setDebuggeeHandles(0, 0);
545     killWatchTimer();
546     m_engine->setState(success ? InferiorShutDown : InferiorShutdownFailed, Q_FUNC_INFO, __LINE__);
547     return success;
548 }
549
550 // End debugging. Note that this can invoked via user action
551 // or the processTerminated() event handler, in which case it
552 // must not kill the process again.
553 void CdbDebugEnginePrivate::endDebugging(EndDebuggingMode em)
554 {
555     if (debugCDB)
556         qDebug() << Q_FUNC_INFO << em;
557
558     const DebuggerState oldState = m_engine->state();
559     if (oldState == DebuggerNotReady || m_mode == AttachCore)
560         return;
561     // Do we need to stop the process?
562     QString errorMessage;
563     if (oldState != InferiorShutDown && m_hDebuggeeProcess) {
564         EndInferiorAction action;
565         switch (em) {
566         case EndDebuggingAuto:
567             action = (m_mode == AttachExternal || m_mode == AttachCrashedExternal) ?
568                      DetachInferior : TerminateInferior;
569             break;
570         case EndDebuggingDetach:
571             action = DetachInferior;
572             break;
573         case EndDebuggingTerminate:
574             action = TerminateInferior;
575             break;
576         }
577         if (debugCDB)
578             qDebug() << Q_FUNC_INFO << action;
579         // Need a stopped debuggee to act
580         if (!endInferior(action, &errorMessage)) {
581             errorMessage = QString::fromLatin1("Unable to detach from/end the debuggee: %1").arg(errorMessage);
582             manager()->showDebuggerOutput(LogError, errorMessage);
583         }
584         errorMessage.clear();
585     }
586     // Clean up resources (open files, etc.)
587     m_engine->setState(EngineShuttingDown, Q_FUNC_INFO, __LINE__);
588     clearForRun();
589     const bool endedCleanly = endSession(&errorMessage);
590     m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
591     if (!endedCleanly) {
592         errorMessage = QString::fromLatin1("There were errors trying to end debugging:\n%1").arg(errorMessage);
593         manager()->showDebuggerOutput(LogError, errorMessage);
594     }
595 }
596
597 void CdbDebugEngine::exitDebugger()
598 {
599     m_d->endDebugging();
600 }
601
602 void CdbDebugEngine::detachDebugger()
603 {
604     m_d->endDebugging(CdbDebugEnginePrivate::EndDebuggingDetach);
605 }
606
607 CdbSymbolGroupContext *CdbDebugEnginePrivate::getSymbolGroupContext(int frameIndex, QString *errorMessage) const
608 {
609     if (!m_currentStackTrace) {
610         *errorMessage = QLatin1String(msgNoStackTraceC);
611         return 0;
612     }
613     if (CdbSymbolGroupContext *sg = m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, errorMessage))
614         return sg;
615     return 0;
616 }
617
618 void CdbDebugEngine::evaluateWatcher(WatchData *wd)
619 {
620     if (debugCDBWatchHandling)
621         qDebug() << Q_FUNC_INFO << wd->exp;
622     QString errorMessage;
623     QString value;
624     QString type;
625     QString exp = wd->exp;
626     // Remove locals watch prefix.
627     if (exp.startsWith(QLatin1String("local.")))
628         exp.remove(0, 6);
629     if (m_d->evaluateExpression(exp, &value, &type, &errorMessage)) {
630         wd->setValue(value);
631         wd->setType(type);
632     } else {
633         wd->setValue(errorMessage);
634         wd->setTypeUnneeded();
635     }
636     wd->setHasChildren(false);
637 }
638
639 void CdbDebugEngine::updateWatchData(const WatchData &incomplete)
640 {
641     // Watch item was edited while running
642     if (m_d->isDebuggeeRunning())
643         return;
644
645     if (debugCDBWatchHandling)
646         qDebug() << Q_FUNC_INFO << "\n    " << incomplete.toString();
647
648     WatchHandler *watchHandler = manager()->watchHandler();
649     if (incomplete.iname.startsWith("watch.")) {
650         WatchData watchData = incomplete;
651         evaluateWatcher(&watchData);
652         watchHandler->insertData(watchData);
653         return;
654     }
655
656     const int frameIndex = manager()->stackHandler()->currentIndex();
657
658     bool success = false;
659     QString errorMessage;
660     do {
661         CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
662         if (!sg)
663             break;
664         if (!sg->completeData(incomplete, watchHandler, &errorMessage))
665             break;
666         success = true;
667     } while (false);
668     if (!success)
669         warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
670     if (debugCDBWatchHandling > 1)
671         qDebug() << *manager()->watchHandler()->model(LocalsWatch);
672 }
673
674 // Continue inferior with a debugger command, such as "p", "pt"
675 // or its thread variations
676 bool CdbDebugEnginePrivate::executeContinueCommand(const QString &command)
677 {
678     if (debugCDB)
679         qDebug() << Q_FUNC_INFO << command;
680     clearForRun();
681     updateCodeLevel(); // Step by instruction
682     m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
683     manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Continuing with '%1'...").arg(command));
684     QString errorMessage;
685     const bool success = executeDebuggerCommand(command, &errorMessage);
686     if (success) {
687         m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
688         startWatchTimer();
689     } else {
690         m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
691         m_engine->warning(CdbDebugEngine::tr("Unable to continue: %1").arg(errorMessage));
692     }
693     return success;
694 }
695
696 static inline QString msgStepFailed(unsigned long executionStatus, int threadId, const QString &why)
697 {
698     if (executionStatus ==  DEBUG_STATUS_STEP_OVER)
699         return QString::fromLatin1("Thread %1: Unable to step over: %2").arg(threadId).arg(why);
700     return QString::fromLatin1("Thread %1: Unable to step into: %2").arg(threadId).arg(why);
701 }
702
703 // Step out has to be done via executing 'gu'. TODO: Remove once it is
704 // accessible via normal API for SetExecutionStatus().
705
706 enum { CdbExtendedExecutionStatusStepOut = 7452347 };
707
708 // Step with  DEBUG_STATUS_STEP_OVER ('p'-command),
709 // DEBUG_STATUS_STEP_INTO ('t'-trace-command) or
710 // CdbExtendedExecutionStatusStepOut ("gu"-command)
711 // its reverse equivalents in the case of single threads.
712
713 bool CdbDebugEngine::step(unsigned long executionStatus)
714 {
715     if (debugCDBExecution)
716         qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId;
717
718     // State of reverse stepping as of 10/2009 (Debugging tools 6.11@404):
719     // The constants exist, but invoking the calls leads to E_NOINTERFACE.
720     // Also there is no CDB command for it.
721     if (executionStatus == DEBUG_STATUS_REVERSE_STEP_OVER || executionStatus == DEBUG_STATUS_REVERSE_STEP_INTO) {
722         warning(tr("Reverse stepping is not implemented."));
723         return false;
724     }
725
726     // Do not step the artifical thread created to interrupt the debuggee.
727     if (m_d->m_interrupted && m_d->m_currentThreadId == m_d->m_interruptArticifialThreadId) {
728         warning(tr("Thread %1 cannot be stepped.").arg(m_d->m_currentThreadId));
729         return false;
730     }
731
732     // SetExecutionStatus() continues the thread that triggered the
733     // stop event (~# p). This can be confusing if the user is looking
734     // at the stack trace of another thread and wants to step that one. If that
735     // is the case, explicitly tell it to step the current thread using a command.
736     const int triggeringEventThread = m_d->m_eventThreadId;
737     const bool sameThread = triggeringEventThread == -1
738                             || m_d->m_currentThreadId == triggeringEventThread
739                             || manager()->threadsHandler()->threads().size() == 1;
740     m_d->clearForRun(); // clears thread ids
741     m_d->updateCodeLevel(); // Step by instruction or source line
742     setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
743     bool success = false;
744     if (sameThread && executionStatus != CdbExtendedExecutionStatusStepOut) { // Step event-triggering thread, use fast API
745         const HRESULT hr = m_d->interfaces().debugControl->SetExecutionStatus(executionStatus);
746         success = SUCCEEDED(hr);
747         if (!success)
748             warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, CdbCore::msgComFailed("SetExecutionStatus", hr)));
749     } else {
750         // Need to use a command to explicitly specify the current thread
751         QString command;
752         QTextStream str(&command);
753         str << '~' << m_d->m_currentThreadId << ' ';
754         switch (executionStatus) {
755         case DEBUG_STATUS_STEP_OVER:
756             str << 'p';
757             break;
758         case DEBUG_STATUS_STEP_INTO:
759             str << 't';
760             break;
761         case CdbExtendedExecutionStatusStepOut:
762             str << "gu";
763             break;
764         }
765         manager()->showDebuggerOutput(tr("Stepping %1").arg(command));
766         const HRESULT hr = m_d->interfaces().debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO);
767         success = SUCCEEDED(hr);
768         if (!success)
769             warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgDebuggerCommandFailed(command, hr)));
770     }
771     if (success) {
772         // Oddity: Step into will first break at the calling function. Ignore
773         if (executionStatus == DEBUG_STATUS_STEP_INTO || executionStatus == DEBUG_STATUS_REVERSE_STEP_INTO)
774             m_d->m_breakEventMode = CdbDebugEnginePrivate::BreakEventIgnoreOnce;
775         m_d->startWatchTimer();
776         setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
777     } else {
778         setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
779     }
780     if (debugCDBExecution)
781         qDebug() << "<step samethread" << sameThread << "succeeded" << success;
782     return success;
783 }
784
785 void CdbDebugEngine::executeStep()
786 {
787     step(manager()->isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_INTO : DEBUG_STATUS_STEP_INTO);
788 }
789
790 void CdbDebugEngine::executeNext()
791 {
792     step(manager()->isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_OVER : DEBUG_STATUS_STEP_OVER);
793 }
794
795 void CdbDebugEngine::executeStepI()
796 {
797     executeStep(); // Step into by instruction (figured out by step)
798 }
799
800 void CdbDebugEngine::executeNextI()
801 {
802     executeNext(); // Step over by instruction (figured out by step)
803 }
804
805 void CdbDebugEngine::executeStepOut()
806 {
807     if (!manager()->isReverseDebugging())
808         step(CdbExtendedExecutionStatusStepOut);
809 }
810
811 void CdbDebugEngine::continueInferior()
812 {
813     QString errorMessage;
814     if  (!m_d->continueInferior(&errorMessage))
815         warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
816 }
817
818 // Continue process without notifications
819 bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /* = 0 */)
820 {
821     if (debugCDBExecution)
822         qDebug() << "continueInferiorProcess";
823     const HRESULT hr = interfaces().debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
824     if (FAILED(hr)) {
825         const QString errorMessage = CdbCore::msgComFailed("SetExecutionStatus", hr);
826         if (errorMessagePtr) {
827             *errorMessagePtr = errorMessage;
828         } else {
829             m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
830         }
831         return false;
832     }
833     return  true;
834 }
835
836 // Continue process with notifications
837 bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
838 {
839     // Check state: Are we running?
840     const ULONG ex = executionStatus();
841     if (debugCDB)
842         qDebug() << Q_FUNC_INFO << "\n    ex=" << ex;
843
844     if (ex == DEBUG_STATUS_GO) {
845         m_engine->warning(QLatin1String("continueInferior() called while debuggee is running."));
846         return true;
847     }
848     // Request continue
849     m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
850     bool success = false;
851     do {
852         clearForRun();
853         updateCodeLevel();
854         killWatchTimer();
855         manager()->resetLocation();
856         manager()->showStatusMessage(CdbDebugEngine::tr("Running requested..."), messageTimeOut);
857
858         if (!continueInferiorProcess(errorMessage))
859             break;
860
861         startWatchTimer();
862         success = true;
863     } while (false);
864     if (success) {
865         m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
866     } else {
867         m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__); // No RunningRequestFailed?
868     }
869     return true;
870 }
871
872 bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
873 {
874
875     // Interrupt the interferior process without notifications
876     // Could use setInterrupt, but that does not work.
877     if (debugCDBExecution) {
878         qDebug() << "interruptInterferiorProcess  ex=" << executionStatus();
879     }
880     const bool rc = debugBreakProcess(m_hDebuggeeProcess, errorMessage);
881     if (rc)
882         m_interrupted = true;
883     return rc;
884 }
885
886 void CdbDebugEnginePrivate::slotModulesLoaded()
887 {
888     // Attaching to crashed windows processes: Unless QtCreator is
889     // spawned by the debug handler and inherits the handles,
890     // the event handling does not work reliably (that is, the crash
891     // event is not delivered). In that case, force a break
892     if (m_mode == AttachCrashedExternal && m_engine->state() != InferiorStopped)
893         QTimer::singleShot(10, m_engine, SLOT(slotBreakAttachToCrashed()));
894 }
895
896 void CdbDebugEngine::slotBreakAttachToCrashed()
897 {
898     // Force a break when attaching to crashed process (if Creator was not spawned
899     // from handler).
900     if (state() != InferiorStopped) {
901         manager()->showDebuggerOutput(LogMisc, QLatin1String("Forcing break..."));
902         m_d->m_dumper->disable();
903         interruptInferior();
904     }
905 }
906
907 void CdbDebugEngine::interruptInferior()
908 {
909     if (!m_d->m_hDebuggeeProcess || !m_d->isDebuggeeRunning())
910         return;
911
912     QString errorMessage;
913     setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
914     if (!m_d->interruptInterferiorProcess(&errorMessage)) {
915         setState(InferiorStopFailed, Q_FUNC_INFO, __LINE__);
916         warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
917     }
918 }
919
920 void CdbDebugEngine::executeRunToLine(const QString &fileName, int lineNumber)
921 {
922     manager()->showDebuggerOutput(LogMisc, tr("Running up to %1:%2...").arg(fileName).arg(lineNumber));
923     QString errorMessage;
924     CdbCore::BreakPoint tempBreakPoint;
925     tempBreakPoint.fileName = fileName;
926     tempBreakPoint.lineNumber = lineNumber;
927     tempBreakPoint.oneShot = true;
928     const bool ok = tempBreakPoint.add(m_d->interfaces().debugControl, &errorMessage)
929                     && m_d->continueInferior(&errorMessage);
930     if (!ok)
931         warning(errorMessage);
932 }
933
934 void CdbDebugEngine::executeRunToFunction(const QString &functionName)
935 {
936     manager()->showDebuggerOutput(LogMisc, tr("Running up to function '%1()'...").arg(functionName));
937     QString errorMessage;
938     CdbCore::BreakPoint tempBreakPoint;
939     tempBreakPoint.funcName = functionName;
940     tempBreakPoint.oneShot = true;
941     const bool ok = tempBreakPoint.add(m_d->interfaces().debugControl, &errorMessage)
942                     && m_d->continueInferior(&errorMessage);
943     if (!ok)
944         warning(errorMessage);
945 }
946
947 void CdbDebugEngine::executeJumpToLine(const QString & /* fileName */, int /*lineNumber*/)
948 {
949     warning(tr("Jump to line is not implemented"));
950 }
951
952 void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &value)
953 {
954     if (debugCDB)
955         qDebug() << Q_FUNC_INFO << expr << value;
956     const int frameIndex = manager()->stackHandler()->currentIndex();
957     QString errorMessage;
958     bool success = false;
959     do {
960         QString newValue;
961         CdbSymbolGroupContext *sg = m_d->getSymbolGroupContext(frameIndex, &errorMessage);
962         if (!sg)
963             break;
964         if (!sg->assignValue(expr, value, &newValue, &errorMessage))
965             break;
966         // Update view
967         WatchHandler *watchHandler = manager()->watchHandler();
968         if (WatchData *fwd = watchHandler->findItem(expr.toLatin1())) {
969             fwd->setValue(newValue);
970             watchHandler->insertData(*fwd);
971             watchHandler->updateWatchers();
972         }
973         success = true;
974     } while (false);
975     if (!success) {
976         const QString msg = tr("Unable to assign the value '%1' to '%2': %3").arg(value, expr, errorMessage);
977         warning(msg);
978     }
979 }
980
981 void CdbDebugEngine::executeDebuggerCommand(const QString &command)
982 {
983     QString errorMessage;
984     if (!m_d->executeDebuggerCommand(command, &errorMessage))
985         warning(errorMessage);
986 }
987
988 void CdbDebugEngine::activateFrame(int frameIndex)
989 {
990     if (debugCDB)
991         qDebug() << Q_FUNC_INFO << frameIndex;
992
993     if (state() != InferiorStopped) {
994         qWarning("WARNING %s: invoked while debuggee is running\n", Q_FUNC_INFO);
995         return;
996     }
997
998     QString errorMessage;
999     bool success = false;
1000     StackHandler *stackHandler = manager()->stackHandler();
1001     do {
1002         WatchHandler *watchHandler = manager()->watchHandler();
1003         const int oldIndex = stackHandler->currentIndex();
1004         if (frameIndex >= stackHandler->stackSize()) {
1005             errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler->stackSize());
1006             break;
1007         }
1008
1009         if (oldIndex != frameIndex)
1010             stackHandler->setCurrentIndex(frameIndex);
1011
1012         const StackFrame &frame = stackHandler->currentFrame();
1013
1014         const bool showAssembler = !frame.isUsable();
1015         if (showAssembler) { // Assembly code: Clean out model and force instruction mode.
1016             watchHandler->beginCycle();
1017             watchHandler->endCycle();
1018             QAction *assemblerAction = theDebuggerAction(OperateByInstruction);
1019             if (!assemblerAction->isChecked())
1020                 assemblerAction->trigger();
1021             success = true;
1022             break;
1023         }
1024
1025         manager()->gotoLocation(frame, true);
1026
1027         if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) {
1028             watchHandler->beginCycle();
1029             if (CdbSymbolGroupContext *sgc = m_d->getSymbolGroupContext(frameIndex, &errorMessage))
1030                 success = sgc->populateModelInitially(watchHandler, &errorMessage);
1031             watchHandler->endCycle();
1032         } else {
1033             success = true;
1034         }
1035     } while (false);
1036     if (!success) {
1037         const QString msg = QString::fromLatin1("Internal error: activateFrame() failed for frame #%1 of %2, thread %3: %4").
1038                             arg(frameIndex).arg(stackHandler->stackSize()).arg(m_d->m_currentThreadId).arg(errorMessage);
1039         warning(msg);
1040     }
1041     m_d->m_firstActivatedFrame = false;
1042 }
1043
1044 void CdbDebugEngine::selectThread(int index)
1045 {
1046     if (debugCDB)
1047         qDebug() << Q_FUNC_INFO << index;
1048
1049     //reset location arrow
1050     manager()->resetLocation();
1051
1052     ThreadsHandler *threadsHandler = manager()->threadsHandler();
1053     threadsHandler->setCurrentThread(index);
1054     const int newThreadId = threadsHandler->threads().at(index).id;
1055     if (newThreadId != m_d->m_currentThreadId) {
1056         m_d->m_currentThreadId = threadsHandler->threads().at(index).id;
1057         m_d->updateStackTrace();
1058     }
1059 }
1060
1061 void CdbDebugEngine::attemptBreakpointSynchronization()
1062 {
1063     if (!m_d->m_hDebuggeeProcess) // Sometimes called from the breakpoint Window
1064         return;
1065     QString errorMessage;
1066     if (!m_d->attemptBreakpointSynchronization(&errorMessage))
1067         warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
1068 }
1069
1070 bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessage)
1071 {
1072     if (!m_hDebuggeeProcess) {
1073         *errorMessage = QLatin1String("attemptBreakpointSynchronization() called while debugger is not running");
1074         return false;
1075     }
1076     // This is called from
1077     // 1) CreateProcessEvent with the halted engine
1078     // 2) from the break handler, potentially while the debuggee is running
1079     // If the debuggee is running (for which the execution status is
1080     // no reliable indicator), we temporarily halt and have ourselves
1081     // called again from the debug event handler.
1082
1083     ULONG dummy;
1084     const bool wasRunning = !CdbCore::BreakPoint::getBreakPointCount(interfaces().debugControl, &dummy);
1085     if (debugCDB)
1086         qDebug() << Q_FUNC_INFO << "\n  Running=" << wasRunning;
1087
1088     if (wasRunning) {
1089         const HandleBreakEventMode oldMode = m_breakEventMode;
1090         m_breakEventMode = BreakEventSyncBreakPoints;
1091         if (!interruptInterferiorProcess(errorMessage)) {
1092             m_breakEventMode = oldMode;
1093             return false;
1094         }
1095         return true;
1096     }
1097
1098     QStringList warnings;
1099     const bool ok = synchronizeBreakPoints(interfaces().debugControl,
1100                                            interfaces().debugSymbols,
1101                                            manager()->breakHandler(),
1102                                            errorMessage, &warnings);
1103     if (const int warningsCount = warnings.size())
1104         for (int w = 0; w < warningsCount; w++)
1105             m_engine->warning(warnings.at(w));
1106     return ok;
1107 }
1108
1109 void CdbDebugEngine::fetchDisassembler(DisassemblerViewAgent *agent)
1110 {
1111     StackFrame frame = agent->frame();
1112     enum { ContextLines = 40 };
1113     bool ok = false;
1114     QString errorMessage;
1115     do {
1116         // get address
1117         QString address;
1118         if (!frame.file.isEmpty())
1119             address = frame.address;
1120         if (address.isEmpty())
1121             address = agent->address();
1122         if (debugCDB)
1123             qDebug() << "fetchDisassembler" << address << " Agent: " << agent->address()
1124             << " Frame" << frame.file << frame.line << frame.address;
1125         if (address.isEmpty()) { // Clear window
1126             agent->setContents(QString());
1127             ok = true;
1128             break;
1129         }
1130         if (address.startsWith(QLatin1String("0x")))
1131             address.remove(0, 2);
1132         const int addressFieldWith = address.size(); // For the Marker
1133
1134         const ULONG64 offset = address.toULongLong(&ok, 16);
1135         if (!ok) {
1136             errorMessage = QString::fromLatin1("Internal error: Invalid address for disassembly: '%1'.").arg(agent->address());
1137             break;
1138         }
1139         QString disassembly;
1140         QApplication::setOverrideCursor(Qt::WaitCursor);
1141         ok = dissassemble(m_d, offset, ContextLines, ContextLines, addressFieldWith, QTextStream(&disassembly), &errorMessage);
1142         QApplication::restoreOverrideCursor();
1143         if (!ok)
1144             break;
1145         agent->setContents(disassembly);
1146
1147     } while (false);
1148
1149     if (!ok) {
1150         agent->setContents(QString());
1151         warning(errorMessage);
1152     }
1153 }
1154
1155 void CdbDebugEngine::fetchMemory(MemoryViewAgent *agent, QObject *token, quint64 addr, quint64 length)
1156 {
1157     if (!m_d->m_hDebuggeeProcess && !length)
1158         return;
1159     ULONG received;
1160     QByteArray data(length, '\0');
1161     const HRESULT hr = m_d->interfaces().debugDataSpaces->ReadVirtual(addr, data.data(), length, &received);
1162     if (FAILED(hr)) {
1163         warning(tr("Unable to retrieve %1 bytes of memory at 0x%2: %3").
1164                 arg(length).arg(addr, 0, 16).arg(CdbCore::msgComFailed("ReadVirtual", hr)));
1165         return;
1166     }
1167     if (received < length)
1168         data.truncate(received);
1169     agent->addLazyData(token, addr, data);
1170 }
1171
1172 void CdbDebugEngine::reloadModules()
1173 {
1174 }
1175
1176 void CdbDebugEngine::loadSymbols(const QString &moduleName)
1177 {
1178     if (debugCDB)
1179         qDebug() << Q_FUNC_INFO << moduleName;
1180 }
1181
1182 void CdbDebugEngine::loadAllSymbols()
1183 {
1184     if (debugCDB)
1185         qDebug() << Q_FUNC_INFO;
1186 }
1187
1188 void CdbDebugEngine::requestModuleSymbols(const QString &moduleName)
1189 {
1190     QList<Symbol> rc;
1191     QString errorMessage;
1192     bool success = false;
1193     do {
1194         if (m_d->isDebuggeeRunning()) {
1195             errorMessage = tr("Cannot retrieve symbols while the debuggee is running.");
1196             break;
1197         }
1198         if (!getModuleSymbols(m_d->interfaces().debugSymbols, moduleName, &rc, &errorMessage))
1199             break;
1200         success = true;
1201     } while (false);
1202     if (!success)
1203         warning(errorMessage);
1204     manager()->showModuleSymbols(moduleName, rc);
1205 }
1206
1207 void CdbDebugEngine::reloadRegisters()
1208 {
1209     if (state() != InferiorStopped)
1210         return;
1211     const int intBase = 10;
1212     if (debugCDB)
1213         qDebug() << Q_FUNC_INFO << intBase;
1214
1215     QString errorMessage;
1216     const Registers registers = getRegisters(m_d->interfaces().debugControl, m_d->interfaces().debugRegisters, &errorMessage, intBase);
1217     if (registers.isEmpty() && !errorMessage.isEmpty())
1218         warning(msgFunctionFailed("reloadRegisters" , errorMessage));
1219     manager()->registerHandler()->setRegisters(registers);
1220 }
1221
1222 void CdbDebugEngine::slotConsoleStubStarted()
1223 {
1224     const qint64 appPid = m_d->m_consoleStubProc.applicationPID();
1225     if (debugCDB)
1226         qDebug() << Q_FUNC_INFO << appPid;
1227     // Attach to console process
1228     QString errorMessage;
1229     if (startAttachDebugger(appPid, AttachExternal, &errorMessage)) {
1230         m_d->startWatchTimer();
1231         manager()->notifyInferiorPidChanged(appPid);
1232     } else {
1233         QMessageBox::critical(DebuggerUISwitcher::instance()->mainWindow(), tr("Debugger Error"), errorMessage);
1234     }
1235 }
1236
1237 void CdbDebugEngine::slotConsoleStubMessage(const QString &msg, bool)
1238 {
1239     QMessageBox::critical(DebuggerUISwitcher::instance()->mainWindow(), tr("Debugger Error"), msg);
1240 }
1241
1242 void CdbDebugEngine::slotConsoleStubTerminated()
1243 {
1244     exitDebugger();
1245 }
1246
1247 void CdbDebugEngine::warning(const QString &w)
1248 {
1249     manager()->showDebuggerOutput(LogWarning, w);
1250     qWarning("%s\n", qPrintable(w));
1251 }
1252
1253 void CdbDebugEnginePrivate::notifyException(long code, bool fatal, const QString &message)
1254 {
1255     if (debugCDBExecution)
1256         qDebug() << "notifyException code" << code << " fatal=" << fatal;
1257     // Suppress the initial breakpoint that occurs when
1258     // attaching to a console (If a breakpoint is encountered before startup
1259     // is complete, see startAttachDebugger()).
1260     switch (code) {
1261     case winExceptionStartupCompleteTrap:
1262         m_inferiorStartupComplete = true;
1263         break;
1264     case EXCEPTION_BREAKPOINT:
1265         if (m_ignoreInitialBreakPoint && !m_inferiorStartupComplete && m_breakEventMode == BreakEventHandle) {
1266             manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Ignoring initial breakpoint..."));
1267             m_breakEventMode = BreakEventIgnoreOnce;
1268         }
1269         break;
1270     }
1271     // Cannot go over crash point to execute calls.
1272     if (fatal) {
1273         m_dumper->disable();
1274         m_stoppedReason = StoppedCrash;
1275         m_stoppedMessage = message;
1276     }
1277 }
1278
1279 static int threadIndexById(const ThreadsHandler *threadsHandler, int id)
1280 {
1281     const QList<ThreadData> threads = threadsHandler->threads();
1282     const int count = threads.count();
1283     for (int i = 0; i < count; i++)
1284         if (threads.at(i).id == id)
1285             return i;
1286     return -1;
1287 }
1288
1289 void CdbDebugEnginePrivate::handleDebugEvent()
1290 {
1291     if (debugCDBExecution)
1292         qDebug() << "handleDebugEvent mode " << m_breakEventMode
1293                 << CdbCore::msgExecutionStatusString(executionStatus()) << " interrupt" << m_interrupted
1294                 << " startupcomplete" << m_inferiorStartupComplete;
1295     // restore mode and do special handling
1296     const HandleBreakEventMode mode = m_breakEventMode;
1297     m_breakEventMode = BreakEventHandle;
1298
1299     switch (mode) {
1300     case BreakEventHandle: {
1301         // If this is triggered by breakpoint/crash: Set state to stopping
1302         // to avoid warnings as opposed to interrupt inferior
1303         if (m_engine->state() != InferiorStopping)
1304             m_engine->setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
1305         m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
1306         m_eventThreadId = updateThreadList();
1307         m_interruptArticifialThreadId = m_interrupted ? m_eventThreadId : -1;
1308         // Get thread to stop and its index. If avoidable, do not use
1309         // the artifical thread that is created when interrupting,
1310         // use the oldest thread 0 instead.
1311         ThreadsHandler *threadsHandler = manager()->threadsHandler();
1312         m_currentThreadId = m_interrupted ? 0 : m_eventThreadId;
1313         int currentThreadIndex = -1;
1314         m_currentThreadId = -1;
1315         if (m_interrupted) {
1316             m_currentThreadId = 0;
1317             currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId);
1318         }
1319         if (!m_interrupted || currentThreadIndex == -1) {
1320             m_currentThreadId = m_eventThreadId;
1321             currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId);
1322         }
1323         const QString msg = m_interrupted ?
1324                             CdbDebugEngine::tr("Interrupted in thread %1, current thread: %2").arg(m_interruptArticifialThreadId).arg(m_currentThreadId) :
1325                             CdbDebugEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId);
1326         manager()->showDebuggerOutput(LogMisc, msg);
1327         const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId);
1328         if (threadIndex != -1)
1329             threadsHandler->setCurrentThread(threadIndex);
1330         updateStackTrace();
1331     }
1332         break;
1333     case BreakEventIgnoreOnce:
1334         startWatchTimer();
1335         m_interrupted = false;
1336         break;
1337     case BreakEventSyncBreakPoints: {
1338             m_interrupted = false;
1339             // Temp stop to sync breakpoints
1340             QString errorMessage;
1341             attemptBreakpointSynchronization(&errorMessage);
1342             startWatchTimer();
1343             continueInferiorProcess(&errorMessage);
1344             if (!errorMessage.isEmpty())
1345                 m_engine->warning(QString::fromLatin1("In handleDebugEvent: %1").arg(errorMessage));
1346     }
1347         break;
1348     }
1349 }
1350
1351 void CdbDebugEnginePrivate::setDebuggeeHandles(HANDLE hDebuggeeProcess,  HANDLE hDebuggeeThread)
1352 {
1353     if (debugCDB)
1354         qDebug() << Q_FUNC_INFO << hDebuggeeProcess << hDebuggeeThread;
1355     m_hDebuggeeProcess = hDebuggeeProcess;
1356     m_hDebuggeeThread = hDebuggeeThread;
1357 }
1358
1359 // Set thread in CDB engine
1360 bool CdbDebugEnginePrivate::setCDBThreadId(unsigned long threadId, QString *errorMessage)
1361 {
1362     ULONG currentThreadId;
1363     HRESULT hr = interfaces().debugSystemObjects->GetCurrentThreadId(&currentThreadId);
1364     if (FAILED(hr)) {
1365         *errorMessage = CdbCore::msgComFailed("GetCurrentThreadId", hr);
1366         return false;
1367     }
1368     if (currentThreadId == threadId)
1369         return true;
1370     hr = interfaces().debugSystemObjects->SetCurrentThreadId(threadId);
1371     if (FAILED(hr)) {
1372         *errorMessage = QString::fromLatin1("Failed to change to from thread %1 to %2: SetCurrentThreadId() failed: %3").
1373                         arg(currentThreadId).arg(threadId).arg(CdbCore::msgDebugEngineComResult(hr));
1374         return false;
1375     }
1376     const QString msg = CdbDebugEngine::tr("Changing threads: %1 -> %2").arg(currentThreadId).arg(threadId);
1377     m_engine->showStatusMessage(msg, 500);
1378     return true;
1379 }
1380
1381 ULONG CdbDebugEnginePrivate::updateThreadList()
1382 {
1383     if (debugCDB)
1384         qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
1385
1386     QList<ThreadData> threads;
1387     ULONG currentThreadId;
1388     QString errorMessage;
1389     // When interrupting, an artifical thread with a breakpoint is created.
1390     if (!CdbStackTraceContext::getThreads(interfaces(), &threads, &currentThreadId, &errorMessage))
1391         m_engine->warning(errorMessage);
1392     manager()->threadsHandler()->setThreads(threads);
1393     return currentThreadId;
1394 }
1395
1396 // Figure out the thread to run the dumpers in (see notes on.
1397 // CdbDumperHelper). Avoid the artifical threads created by interrupt
1398 // and threads that are in waitFor().
1399 // A stricter version could only use the thread if it is the event
1400 // thread of a step or breakpoint hit (see CdbDebugEnginePrivate::m_interrupted).
1401
1402 static inline unsigned long dumperThreadId(const QList<StackFrame> &frames,
1403                                            unsigned long currentThread)
1404 {
1405     if (frames.empty())
1406         return CdbDumperHelper::InvalidDumperCallThread;
1407     switch (CdbCore::StackTraceContext::specialFunction(frames.at(0).from, frames.at(0).function)) {
1408     case CdbCore::StackTraceContext::BreakPointFunction:
1409     case CdbCore::StackTraceContext::WaitFunction:
1410         return CdbDumperHelper::InvalidDumperCallThread;
1411     default:
1412         break;
1413     }
1414     // Check remaining frames for wait
1415     const int waitCheckDepth = qMin(frames.size(), 5);
1416     for (int f = 1; f < waitCheckDepth; f++) {
1417         if (CdbCore::StackTraceContext::specialFunction(frames.at(f).from, frames.at(f).function)
1418             == CdbCore::StackTraceContext::WaitFunction)
1419             return CdbDumperHelper::InvalidDumperCallThread;
1420     }
1421     return currentThread;
1422 }
1423
1424 // Format stop message with all available information.
1425 QString CdbDebugEnginePrivate::stoppedMessage(const StackFrame *topFrame /*  = 0 */) const
1426 {
1427     QString msg;
1428     if (topFrame) {
1429         if (topFrame->isUsable()) {
1430             // Stopped at basename:line
1431             const int lastSlashPos = topFrame->file.lastIndexOf(QLatin1Char('/'));
1432             const QString file = lastSlashPos == -1 ? topFrame->file : topFrame->file.mid(lastSlashPos + 1);
1433             msg = CdbDebugEngine::tr("Stopped at %1:%2 in thread %3.").
1434                   arg(file).arg(topFrame->line).arg(m_currentThreadId);
1435         } else {
1436             // Somewhere in assembly code.
1437             if (topFrame->function.isEmpty()) {
1438                 msg = CdbDebugEngine::tr("Stopped at %1 in thread %2 (missing debug information).").
1439                       arg(topFrame->address).arg(m_currentThreadId);
1440             } else {
1441                 msg = CdbDebugEngine::tr("Stopped at %1 (%2) in thread %3 (missing debug information).").
1442                       arg(topFrame->address).arg(topFrame->function).arg(m_currentThreadId);
1443             }
1444         } // isUsable
1445     } else {
1446         msg = CdbDebugEngine::tr("Stopped in thread %1 (missing debug information).").arg(m_currentThreadId);
1447
1448     }
1449     if (!m_stoppedMessage.isEmpty()) {
1450         msg += QLatin1Char(' ');
1451         msg += m_stoppedMessage;
1452     }
1453     return msg;
1454 }
1455
1456 void CdbDebugEnginePrivate::updateStackTrace()
1457 {
1458     if (debugCDB)
1459         qDebug() << Q_FUNC_INFO;
1460     // Create a new context
1461     cleanStackTrace();
1462     QString errorMessage;
1463     m_engine->reloadRegisters();
1464     if (!setCDBThreadId(m_currentThreadId, &errorMessage)) {
1465         m_engine->warning(errorMessage);
1466         return;
1467     }
1468     m_currentStackTrace =
1469             CdbStackTraceContext::create(m_dumper, &errorMessage);
1470     if (!m_currentStackTrace) {
1471         m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
1472         return;
1473     }
1474     // Disassembling slows things down a bit. Assembler is still available via menu.
1475 #if 0
1476     m_engine->reloadDisassembler(); // requires stack trace
1477 #endif
1478     const QList<StackFrame> stackFrames = m_currentStackTrace->stackFrames();
1479     // find the first usable frame and select it
1480     int current = -1;
1481     const int count = stackFrames.count();
1482     for (int i=0; i < count; ++i)
1483         if (stackFrames.at(i).isUsable()) {
1484             current = i;
1485             break;
1486         }
1487     // Format stop message.
1488     const QString stopMessage = stoppedMessage(stackFrames.isEmpty() ? static_cast<const StackFrame *>(0) : &stackFrames.front());
1489     // Set up dumper with a thread (or invalid)
1490     const unsigned long dumperThread = dumperThreadId(stackFrames, m_currentThreadId);
1491     if (debugCDBExecution)
1492         qDebug() << "updateStackTrace() current: " << m_currentThreadId << " dumper=" << dumperThread;
1493     m_dumper->setDumperCallThread(dumperThread);
1494     // Display frames
1495     manager()->stackHandler()->setFrames(stackFrames);
1496     m_firstActivatedFrame = true;
1497     if (current >= 0) {
1498         manager()->stackHandler()->setCurrentIndex(current);
1499         m_engine->activateFrame(current);
1500     } else {
1501         // Clean out variables
1502         manager()->watchHandler()->beginCycle();
1503         manager()->watchHandler()->endCycle();
1504     }
1505     manager()->watchHandler()->updateWatchers();
1506     // Show message after a lengthy dumper initialization
1507     manager()->showStatusMessage(stopMessage, 15000);
1508 }
1509
1510 void CdbDebugEnginePrivate::updateModules()
1511 {
1512     QList<Module> modules;
1513     QString errorMessage;
1514     if (!getModuleList(interfaces().debugSymbols, &modules, &errorMessage))
1515         m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
1516     manager()->modulesHandler()->setModules(modules);
1517 }
1518
1519 static const char *dumperPrefixC = "dumper";
1520
1521 void CdbDebugEnginePrivate::handleModuleLoad(const QString &name)
1522 {
1523     if (debugCDB>2)
1524         qDebug() << Q_FUNC_INFO << "\n    " << name;
1525     m_dumper->moduleLoadHook(name, m_hDebuggeeProcess);
1526     updateModules();
1527 }
1528
1529 void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP)
1530 {
1531     Q_UNUSED(pBP)
1532     if (debugCDB)
1533         qDebug() << Q_FUNC_INFO;
1534     m_stoppedReason = StoppedBreakpoint;
1535     CdbCore::BreakPoint breakpoint;
1536     // Format message unless it is a temporary step-out breakpoint with empty expression.
1537     QString expression;
1538     if (breakpoint.retrieve(pBP, &expression)) {
1539         expression = breakpoint.expression();
1540     } else {
1541         expression.clear();
1542     }
1543     if (!expression.isEmpty())
1544         m_stoppedMessage = breakpoint.type == CdbCore::BreakPoint::Code ?
1545                            CdbDebugEngine::tr("Breakpoint: %1").arg(expression) :
1546                            CdbDebugEngine::tr("Watchpoint: %1").arg(expression);
1547 }
1548
1549 void CdbDebugEngine::reloadSourceFiles()
1550 {
1551 }
1552
1553 void CdbDebugEngine::syncDebuggerPaths()
1554 {
1555      if (debugCDB)
1556         qDebug() << Q_FUNC_INFO << m_d->m_options->symbolPaths << m_d->m_options->sourcePaths;
1557     QString errorMessage;
1558     if (!m_d->setSourcePaths(m_d->m_options->sourcePaths, &errorMessage)
1559         || !m_d->setSymbolPaths(m_d->m_options->symbolPaths, &errorMessage)) {
1560         errorMessage = QString::fromLatin1("Unable to set the debugger paths: %1").arg(errorMessage);
1561         warning(errorMessage);
1562     }
1563 }
1564
1565 unsigned CdbDebugEngine::debuggerCapabilities() const
1566 {
1567     return DisassemblerCapability | RegisterCapability | ShowMemoryCapability
1568            |WatchpointCapability
1569            |BreakOnThrowAndCatchCapability; // Sort-of: Can break on throw().
1570 }
1571
1572 // Accessed by DebuggerManager
1573 IDebuggerEngine *createCdbEngine(DebuggerManager *parent,
1574                                  bool cmdLineEnabled,
1575                                  QList<Core::IOptionsPage*> *opts)
1576 {
1577     // Create options page
1578     QSharedPointer<CdbOptions> options(new CdbOptions);
1579     options->fromSettings(Core::ICore::instance()->settings());
1580     CdbOptionsPage *optionsPage = new CdbOptionsPage(options);
1581     opts->push_back(optionsPage);
1582     if (!cmdLineEnabled || !options->enabled)
1583         return 0;
1584     // Create engine
1585     QString errorMessage;
1586     IDebuggerEngine *engine = CdbDebugEngine::create(parent, options, &errorMessage);
1587     if (engine) {
1588         QObject::connect(optionsPage, SIGNAL(debuggerPathsChanged()), engine, SLOT(syncDebuggerPaths()));
1589     } else {
1590         optionsPage->setFailureMessage(errorMessage);
1591         qWarning("%s\n" ,qPrintable(errorMessage));
1592     }
1593     return engine;
1594 }
1595
1596 } // namespace Internal
1597 } // namespace Debugger
1598