OSDN Git Service

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