OSDN Git Service

Merge branch 'master' of scm.dev.nokia.troll.no:creator/mainline
[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) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "cdbengine.h"
35 #include "debuggerstartparameters.h"
36 #include "disassemblerlines.h"
37 #include "cdboptions.h"
38 #include "cdboptionspage.h"
39 #include "bytearrayinputstream.h"
40 #include "breakpoint.h"
41 #include "breakhandler.h"
42 #include "stackframe.h"
43 #include "stackhandler.h"
44 #include "watchhandler.h"
45 #include "threadshandler.h"
46 #include "moduleshandler.h"
47 #include "debuggeractions.h"
48 #include "debuggercore.h"
49 #include "registerhandler.h"
50 #include "disassembleragent.h"
51 #include "memoryagent.h"
52 #include "debuggerrunner.h"
53 #include "debuggertooltipmanager.h"
54 #include "cdbparsehelpers.h"
55 #include "watchutils.h"
56 #include "gdb/gdbmi.h"
57 #include "shared/cdbsymbolpathlisteditor.h"
58
59 #include <coreplugin/icore.h>
60 #include <texteditor/itexteditor.h>
61 #include <projectexplorer/abi.h>
62 #include <projectexplorer/projectexplorerconstants.h>
63
64 #include <utils/synchronousprocess.h>
65 #include <utils/winutils.h>
66 #include <utils/qtcassert.h>
67 #include <utils/savedaction.h>
68 #include <utils/consoleprocess.h>
69
70 #include <QtCore/QCoreApplication>
71 #include <QtCore/QFileInfo>
72 #include <QtCore/QDir>
73 #include <QtCore/QDebug>
74 #include <QtCore/QTextStream>
75 #include <QtCore/QDateTime>
76 #include <QtGui/QToolTip>
77 #include <QtGui/QMainWindow>
78 #include <QtGui/QMessageBox>
79
80 #ifdef Q_OS_WIN
81 #    include <utils/winutils.h>
82 #    include "dbgwinutils.h"
83 #endif
84
85 #include <cctype>
86
87 Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgent*)
88 Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
89
90 enum { debug = 0 };
91 enum { debugLocals = 0 };
92 enum { debugSourceMapping = 0 };
93 enum { debugWatches = 0 };
94 enum { debugBreakpoints = 0 };
95
96 #if 0
97 #  define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
98 #else
99 #  define STATE_DEBUG(state, func, line, notifyFunc)
100 #endif
101
102 /*!
103     \class Debugger::Internal::CdbEngine
104
105     Cdb engine version 2: Run the CDB process on pipes and parse its output.
106     The engine relies on a CDB extension Qt Creator provides as an extension
107     library (32/64bit), which is loaded into cdb.exe. It serves to:
108
109     \list
110     \o Notify the engine about the state of the debugging session:
111         \list
112         \o idle: (hooked up with .idle_cmd) debuggee stopped
113         \o accessible: Debuggee stopped, cdb.exe accepts commands
114         \o inaccessible: Debuggee runs, no way to post commands
115         \o session active/inactive: Lost debuggee, terminating.
116         \endlist
117     \o Hook up with output/event callbacks and produce formatted output to be able
118        to catch application output and exceptions.
119     \o Provide some extension commands that produce output in a standardized (GDBMI)
120       format that ends up in handleExtensionMessage(), for example:
121       \list
122       \o pid     Return debuggee pid for interrupting.
123       \o locals  Print locals from SymbolGroup
124       \o expandLocals Expand locals in symbol group
125       \o registers, modules, threads
126       \endlist
127    \endlist
128
129    Debugger commands can be posted by calling:
130
131    \list
132
133     \o postCommand(): Does not expect a reply
134     \o postBuiltinCommand(): Run a builtin-command producing free-format, multiline output
135        that is captured by enclosing it in special tokens using the 'echo' command and
136        then invokes a callback with a CdbBuiltinCommand structure.
137     \o postExtensionCommand(): Run a command provided by the extension producing
138        one-line output and invoke a callback with a CdbExtensionCommand structure
139        (output is potentially split up in chunks).
140     \endlist
141
142
143     Startup sequence:
144     [Console: The console stub launches the process. On process startup,
145               launchCDB() is called with AttachExternal].
146     setupEngine() calls launchCDB() with the startparameters. The debuggee
147     runs into the initial breakpoint (session idle). EngineSetupOk is
148     notified (inferior still stopped). setupInferior() is then called
149     which does breakpoint synchronization and issues the extension 'pid'
150     command to obtain the inferior pid (which also hooks up the output callbacks).
151      handlePid() notifies notifyInferiorSetupOk.
152     runEngine() is then called which issues 'g' to continue the inferior.
153     Shutdown mostly uses notifyEngineSpontaneousShutdown() as cdb just quits
154     when the inferior exits (except attach modes).
155 */
156
157 using namespace ProjectExplorer;
158
159 namespace Debugger {
160 namespace Internal {
161
162 static const char localsPrefixC[] = "local.";
163
164 struct MemoryViewCookie
165 {
166     explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0,
167                               quint64 addr = 0, quint64 l = 0) :
168         agent(a), editorToken(e), address(addr), length(l)
169     {}
170
171     MemoryAgent *agent;
172     QObject *editorToken;
173     quint64 address;
174     quint64 length;
175 };
176
177 struct MemoryChangeCookie
178 {
179     explicit MemoryChangeCookie(quint64 addr = 0, const QByteArray &d = QByteArray()) :
180                                address(addr), data(d) {}
181
182     quint64 address;
183     QByteArray data;
184 };
185
186 struct ConditionalBreakPointCookie
187 {
188     ConditionalBreakPointCookie(BreakpointId i = 0) : id(i) {}
189     BreakpointId id;
190     GdbMi stopReason;
191 };
192
193 } // namespace Internal
194 } // namespace Debugger
195
196 Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
197 Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
198 Q_DECLARE_METATYPE(Debugger::Internal::ConditionalBreakPointCookie)
199
200 namespace Debugger {
201 namespace Internal {
202
203 static inline bool isConsole(const DebuggerStartParameters &sp)
204 {
205     return (sp.startMode == StartInternal || sp.startMode == StartExternal)
206         && sp.useTerminal;
207 }
208
209 static QMessageBox *
210 nonModalMessageBox(QMessageBox::Icon icon, const QString &title, const QString &text)
211 {
212     QMessageBox *mb = new QMessageBox(icon, title, text, QMessageBox::Ok,
213                                       debuggerCore()->mainWindow());
214     mb->setAttribute(Qt::WA_DeleteOnClose);
215     mb->show();
216     return mb;
217 }
218
219 // Base data structure for command queue entries with callback
220 struct CdbCommandBase
221 {
222     typedef CdbEngine::BuiltinCommandHandler CommandHandler;
223
224     CdbCommandBase();
225     CdbCommandBase(const QByteArray  &cmd, int token, unsigned flags,
226                    unsigned nc, const QVariant &cookie);
227
228     int token;
229     unsigned flags;
230     QByteArray command;
231     QVariant cookie;
232     // Continue with another commands as specified in CommandSequenceFlags
233     unsigned commandSequence;
234 };
235
236 CdbCommandBase::CdbCommandBase() :
237     token(0), flags(0), commandSequence(0)
238 {
239 }
240
241 CdbCommandBase::CdbCommandBase(const QByteArray  &cmd, int t, unsigned f,
242                                unsigned nc, const QVariant &c) :
243     token(t), flags(f), command(cmd), cookie(c), commandSequence(nc)
244 {
245 }
246
247 // Queue entry for builtin commands producing free-format
248 // line-by-line output.
249 struct CdbBuiltinCommand : public CdbCommandBase
250 {
251     typedef CdbEngine::BuiltinCommandHandler CommandHandler;
252
253     CdbBuiltinCommand() {}
254     CdbBuiltinCommand(const QByteArray  &cmd, int token, unsigned flags,
255                       CommandHandler h,
256                       unsigned nc, const QVariant &cookie) :
257         CdbCommandBase(cmd, token, flags, nc, cookie), handler(h)
258     {}
259
260
261     QByteArray joinedReply() const;
262
263     CommandHandler handler;
264     QList<QByteArray> reply;
265 };
266
267 QByteArray CdbBuiltinCommand::joinedReply() const
268 {
269     if (reply.isEmpty())
270         return QByteArray();
271     QByteArray answer;
272     answer.reserve(120  * reply.size());
273     foreach (const QByteArray &l, reply) {
274         answer += l;
275         answer += '\n';
276     }
277     return answer;
278 }
279
280 // Queue entry for Qt Creator extension commands producing one-line
281 // output with success flag and error message.
282 struct CdbExtensionCommand : public CdbCommandBase
283 {
284     typedef CdbEngine::ExtensionCommandHandler CommandHandler;
285
286     CdbExtensionCommand() : success(false) {}
287     CdbExtensionCommand(const QByteArray  &cmd, int token, unsigned flags,
288                       CommandHandler h,
289                       unsigned nc, const QVariant &cookie) :
290         CdbCommandBase(cmd, token, flags, nc, cookie), handler(h),success(false) {}
291
292     CommandHandler handler;
293     QByteArray reply;
294     QByteArray errorMessage;
295     bool success;
296 };
297
298 template <class CommandPtrType>
299 int indexOfCommand(const QList<CommandPtrType> &l, int token)
300 {
301     const int count = l.size();
302     for (int i = 0; i < count; i++)
303         if (l.at(i)->token == token)
304             return i;
305     return -1;
306 }
307
308 static inline bool validMode(DebuggerStartMode sm)
309 {
310     switch (sm) {
311     case NoStartMode:
312     case AttachTcf:
313     case AttachCore:
314     case StartRemoteGdb:
315         return false;
316     default:
317         break;
318     }
319     return true;
320 }
321
322 // Accessed by RunControlFactory
323 DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
324     DebuggerEngine *masterEngine, QString *errorMessage)
325 {
326 #ifdef Q_OS_WIN
327     CdbOptionsPage *op = CdbOptionsPage::instance();
328     if (!op || !op->options()->isValid() || !validMode(sp.startMode)) {
329         *errorMessage = QLatin1String("Internal error: Invalid start parameters passed for thre CDB engine.");
330         return 0;
331     }
332     return new CdbEngine(sp, masterEngine, op->options());
333 #else
334     Q_UNUSED(masterEngine)
335     Q_UNUSED(sp)
336 #endif
337     *errorMessage = QString::fromLatin1("Unsupported debug mode");
338     return 0;
339 }
340
341 bool isCdbEngineEnabled()
342 {
343 #ifdef Q_OS_WIN
344     return CdbOptionsPage::instance() && CdbOptionsPage::instance()->options()->isValid();
345 #else
346     return false;
347 #endif
348 }
349
350 static inline QString msgNoCdbBinaryForToolChain(const ProjectExplorer::Abi &tc)
351 {
352     return CdbEngine::tr("There is no CDB binary available for binaries in format '%1'").arg(tc.toString());
353 }
354
355 static QString cdbBinary(const DebuggerStartParameters &sp)
356 {
357     if (!sp.debuggerCommand.isEmpty()) {
358         // Do not use a GDB binary if we got started for a project with MinGW runtime.
359         const bool abiMatch = sp.toolChainAbi.os() == ProjectExplorer::Abi::WindowsOS
360                     && (sp.toolChainAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2005Flavor
361                         || sp.toolChainAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2008Flavor
362                         || sp.toolChainAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2010Flavor);
363         if (abiMatch)
364             return sp.debuggerCommand;
365     }
366     return debuggerCore()->debuggerForAbi(sp.toolChainAbi, CdbEngineType);
367 }
368
369 bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check)
370 {
371 #ifdef Q_OS_WIN
372     if (!isCdbEngineEnabled()) {
373         check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine required for %1 is currently disabled.").
374                            arg(sp.toolChainAbi.toString()));
375         check->settingsCategory = QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY);
376         check->settingsPage = CdbOptionsPage::settingsId();
377         return false;
378     }
379
380     if (!validMode(sp.startMode)) {
381         check->errorDetails.push_back(CdbEngine::tr("The CDB engine does not support start mode %1.").arg(sp.startMode));
382         return false;
383     }
384
385     if (sp.toolChainAbi.binaryFormat() != Abi::PEFormat || sp.toolChainAbi.os() != Abi::WindowsOS) {
386         check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine does not support the %1 ABI.").
387                                       arg(sp.toolChainAbi.toString()));
388         return false;
389     }
390
391     if (cdbBinary(sp).isEmpty()) {
392         check->errorDetails.push_back(msgNoCdbBinaryForToolChain(sp.toolChainAbi));
393         check->settingsCategory = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
394         check->settingsPage = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
395         return false;
396     }
397
398     return true;
399 #else
400     Q_UNUSED(sp);
401     check->errorDetails.push_back(QString::fromLatin1("Unsupported debug mode"));
402     return false;
403 #endif
404 }
405
406 void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
407 {
408 #ifdef Q_OS_WIN
409     opts->push_back(new CdbOptionsPage);
410 #else
411     Q_UNUSED(opts);
412 #endif
413 }
414
415 #define QT_CREATOR_CDB_EXT "qtcreatorcdbext"
416
417 static inline Utils::SavedAction *theAssemblerAction()
418 {
419     return debuggerCore()->action(OperateByInstruction);
420 }
421
422 CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
423         DebuggerEngine *masterEngine, const OptionsPtr &options) :
424     DebuggerEngine(sp, masterEngine),
425     m_creatorExtPrefix("<qtcreatorcdbext>|"),
426     m_tokenPrefix("<token>"),
427     m_options(options),
428     m_effectiveStartMode(NoStartMode),
429     m_inferiorPid(0),
430     m_accessible(false),
431     m_specialStopMode(NoSpecialStop),
432     m_nextCommandToken(0),
433     m_currentBuiltinCommandIndex(-1),
434     m_extensionCommandPrefixBA("!"QT_CREATOR_CDB_EXT"."),
435     m_operateByInstructionPending(true),
436     m_operateByInstruction(true), // Default CDB setting
437     m_notifyEngineShutdownOnTermination(false),
438     m_hasDebuggee(false),
439     m_elapsedLogTime(0),
440     m_sourceStepInto(false),
441     m_watchPointX(0),
442     m_watchPointY(0),
443     m_ignoreCdbOutput(false)
444 {
445     connect(theAssemblerAction(), SIGNAL(triggered(bool)), this, SLOT(operateByInstructionTriggered(bool)));
446
447     setObjectName(QLatin1String("CdbEngine"));
448     connect(&m_process, SIGNAL(finished(int)), this, SLOT(processFinished()));
449     connect(&m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
450     connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOut()));
451     connect(&m_process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardOut()));
452 }
453
454 void CdbEngine::init()
455 {
456     m_effectiveStartMode = NoStartMode;
457     m_inferiorPid = 0;
458     m_accessible = false;
459     m_specialStopMode = NoSpecialStop;
460     m_nextCommandToken  = 0;
461     m_currentBuiltinCommandIndex = -1;
462     m_operateByInstructionPending = theAssemblerAction()->isChecked();
463     m_operateByInstruction = true; // Default CDB setting
464     m_notifyEngineShutdownOnTermination = false;
465     m_hasDebuggee = false;
466     m_sourceStepInto = false;
467     m_watchPointX = m_watchPointY = 0;
468     m_ignoreCdbOutput = false;
469
470     m_outputBuffer.clear();
471     m_builtinCommandQueue.clear();
472     m_extensionCommandQueue.clear();
473     m_extensionMessageBuffer.clear();
474     m_pendingBreakpointMap.clear();
475     m_customSpecialStopData.clear();
476
477     // Create local list of mappings in native separators
478     m_sourcePathMappings.clear();
479     const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions();
480     if (!globalOptions->sourcePathMap.isEmpty()) {
481         typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator;
482         m_sourcePathMappings.reserve(globalOptions->sourcePathMap.size());
483         const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd();
484         for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) {
485             m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
486                                                              QDir::toNativeSeparators(it.value())));
487         }
488     }
489     QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process); )
490 }
491
492 CdbEngine::~CdbEngine()
493 {
494 }
495
496 void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
497 {
498     if (state() == InferiorStopOk) {
499         syncOperateByInstruction(operateByInstruction);
500     } else {
501         // To be set next time session becomes accessible
502         m_operateByInstructionPending = operateByInstruction;
503     }
504 }
505
506 void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
507 {
508     if (debug)
509         qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
510     if (m_operateByInstruction == operateByInstruction)
511         return;
512     QTC_ASSERT(m_accessible, return; )
513     m_operateByInstruction = operateByInstruction;
514     postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"), 0);
515     postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"), 0);
516 }
517
518 bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
519                                      TextEditor::ITextEditor *editor,
520                                      const DebuggerToolTipContext &contextIn)
521 {
522     if (debug)
523         qDebug() << Q_FUNC_INFO;
524     // Need a stopped debuggee and a cpp file in a valid frame
525     if (state() != InferiorStopOk || !isCppEditor(editor) || stackHandler()->currentIndex() < 0)
526         return false;
527     // Determine expression and function
528     int line;
529     int column;
530     DebuggerToolTipContext context = contextIn;
531     QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
532     // Are we in the current stack frame
533     if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
534         return false;
535     // No numerical or any other expressions [yet]
536     if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_')))
537         return false;
538     // Can this be found as a local variable?
539     const QByteArray localsPrefix(localsPrefixC);
540     QByteArray iname = localsPrefix + exp.toAscii();
541     QModelIndex index = watchHandler()->itemIndex(iname);
542     if (!index.isValid()) {
543         // Nope, try a 'local.this.m_foo'.
544         exp.prepend(QLatin1String("this."));
545         iname.insert(localsPrefix.size(), "this.");
546         index = watchHandler()->itemIndex(iname);
547         if (!index.isValid())
548             return false;
549     }
550     DebuggerTreeViewToolTipWidget *tw = new DebuggerTreeViewToolTipWidget;
551     tw->setContext(context);
552     tw->setDebuggerModel(LocalsWatch);
553     tw->setExpression(exp);
554     tw->acquireEngine(this);
555     DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
556     return true;
557 }
558
559 // Determine full path to the CDB extension library.
560 QString CdbEngine::extensionLibraryName(bool is64Bit)
561 {
562     // Determine extension lib name and path to use
563     QString rc;
564     QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
565                      << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT"64" : QT_CREATOR_CDB_EXT"32")
566                      << '/' << QT_CREATOR_CDB_EXT << ".dll";
567     return rc;
568 }
569
570 // Determine environment for CDB.exe, start out with run config and
571 // add CDB extension path merged with system value should there be one.
572 static QStringList mergeEnvironment(QStringList runConfigEnvironment,
573                                     QString cdbExtensionPath)
574 {
575     // Determine CDB extension path from Qt Creator
576     static const char cdbExtensionPathVariableC[] = "_NT_DEBUGGER_EXTENSION_PATH";
577     const QByteArray oldCdbExtensionPath = qgetenv(cdbExtensionPathVariableC);
578     if (!oldCdbExtensionPath.isEmpty()) {
579         cdbExtensionPath.append(QLatin1Char(';'));
580         cdbExtensionPath.append(QString::fromLocal8Bit(oldCdbExtensionPath));
581     }
582     // We do not assume someone sets _NT_DEBUGGER_EXTENSION_PATH in the run
583     // config, just to make sure, delete any existing entries
584     const QString cdbExtensionPathVariableAssign =
585             QLatin1String(cdbExtensionPathVariableC) + QLatin1Char('=');
586     for (QStringList::iterator it = runConfigEnvironment.begin(); it != runConfigEnvironment.end() ; ) {
587         if (it->startsWith(cdbExtensionPathVariableAssign)) {
588             it = runConfigEnvironment.erase(it);
589             break;
590         } else {
591             ++it;
592         }
593     }
594     runConfigEnvironment.append(cdbExtensionPathVariableAssign +
595                                 QDir::toNativeSeparators(cdbExtensionPath));
596     return runConfigEnvironment;
597 }
598
599 int CdbEngine::elapsedLogTime() const
600 {
601     const int elapsed = m_logTime.elapsed();
602     const int delta = elapsed - m_elapsedLogTime;
603     m_elapsedLogTime = elapsed;
604     return delta;
605 }
606
607 // Start the console stub with the sub process. Continue in consoleStubProcessStarted.
608 bool CdbEngine::startConsole(const DebuggerStartParameters &sp, QString *errorMessage)
609 {
610     if (debug)
611         qDebug("startConsole %s", qPrintable(sp.executable));
612     m_consoleStub.reset(new Utils::ConsoleProcess);
613     m_consoleStub->setMode(Utils::ConsoleProcess::Suspend);
614     connect(m_consoleStub.data(), SIGNAL(processMessage(QString, bool)),
615             SLOT(consoleStubMessage(QString, bool)));
616     connect(m_consoleStub.data(), SIGNAL(processStarted()),
617             SLOT(consoleStubProcessStarted()));
618     connect(m_consoleStub.data(), SIGNAL(wrapperStopped()),
619             SLOT(consoleStubExited()));
620     m_consoleStub->setWorkingDirectory(sp.workingDirectory);
621     if (sp.environment.size())
622         m_consoleStub->setEnvironment(sp.environment);
623     if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
624         *errorMessage = tr("The console process '%1' could not be started.").arg(sp.executable);
625         return false;
626     }
627     return true;
628 }
629
630 void CdbEngine::consoleStubMessage(const QString &msg, bool isError)
631 {
632     if (debug)
633         qDebug("consoleStubProcessMessage() in %s error=%d %s", stateName(state()), isError, qPrintable(msg));
634     if (isError) {
635         if (state() == EngineSetupRequested) {
636             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
637             notifyEngineSetupFailed();
638         } else {
639             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
640             notifyEngineIll();
641         }
642         nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
643     } else {
644         showMessage(msg, AppOutput);
645     }
646 }
647
648 void CdbEngine::consoleStubProcessStarted()
649 {
650     if (debug)
651         qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
652     // Attach to console process.
653     DebuggerStartParameters attachParameters = startParameters();
654     attachParameters.executable.clear();
655     attachParameters.processArgs.clear();
656     attachParameters.attachPID = m_consoleStub->applicationPID();
657     attachParameters.startMode = AttachExternal;
658     showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
659     QString errorMessage;
660     if (!launchCDB(attachParameters, &errorMessage)) {
661         showMessage(errorMessage, LogError);
662         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
663         notifyEngineSetupFailed();
664     }
665 }
666
667 void CdbEngine::consoleStubExited()
668 {
669 }
670
671 void CdbEngine::setupEngine()
672 {
673     if (debug)
674         qDebug(">setupEngine");
675     // Nag to add symbol server
676     if (CdbSymbolPathListEditor::promptToAddSymbolServer(CdbOptions::settingsGroup(),
677                                                          &(m_options->symbolPaths)))
678         m_options->toSettings(Core::ICore::instance()->settings());
679
680     init();
681     if (!m_logTime.elapsed())
682         m_logTime.start();
683     QString errorMessage;
684     // Console: Launch the stub with the suspended application and attach to it
685     // CDB in theory has a command line option '-2' that launches a
686     // console, too, but that immediately closes when the debuggee quits.
687     // Use the Creator stub instead.
688     const DebuggerStartParameters &sp = startParameters();
689     const bool launchConsole = isConsole(sp);
690     m_effectiveStartMode = launchConsole ? AttachExternal : sp.startMode;
691     const bool ok = launchConsole ?
692                 startConsole(startParameters(), &errorMessage) :
693                 launchCDB(startParameters(), &errorMessage);
694     if (debug)
695         qDebug("<setupEngine ok=%d", ok);
696     if (!ok) {
697         showMessage(errorMessage, LogError);
698         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
699         notifyEngineSetupFailed();
700     }
701 }
702
703 bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessage)
704 {
705     if (debug)
706         qDebug("launchCDB startMode=%d", sp.startMode);
707     const QChar blank(QLatin1Char(' '));
708     // Start engine which will run until initial breakpoint:
709     // Determine binary (force MSVC), extension lib name and path to use
710     // The extension is passed as relative name with the path variable set
711     //(does not work with absolute path names)
712     const QString executable = cdbBinary(sp);
713     if (executable.isEmpty()) {
714         *errorMessage = tr("There is no CDB executable specified.");
715         return false;
716     }
717
718     const bool is64bit =
719 #ifdef Q_OS_WIN
720             Utils::winIs64BitBinary(executable);
721 #else
722             false;
723 #endif
724     const QFileInfo extensionFi(CdbEngine::extensionLibraryName(is64bit));
725     if (!extensionFi.isFile()) {
726         *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
727                 arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
728         return false;
729     }
730     const QString extensionFileName = extensionFi.fileName();
731     // Prepare arguments
732     QStringList arguments;
733     const bool isRemote = sp.startMode == AttachToRemote;
734     if (isRemote) { // Must be first
735         arguments << QLatin1String("-remote") << sp.remoteChannel;
736     } else {
737         arguments << (QLatin1String("-a") + extensionFileName);
738     }
739     // Source line info/No terminal breakpoint / Pull extension
740     arguments << QLatin1String("-lines") << QLatin1String("-G")
741     // register idle (debuggee stop) notification
742               << QLatin1String("-c")
743               << QLatin1String(".idle_cmd ") + QString::fromAscii(m_extensionCommandPrefixBA) + QLatin1String("idle");
744     if (sp.useTerminal) // Separate console
745         arguments << QLatin1String("-2");
746     if (!m_options->symbolPaths.isEmpty())
747         arguments << QLatin1String("-y") << m_options->symbolPaths.join(QString(QLatin1Char(';')));
748     if (!m_options->sourcePaths.isEmpty())
749         arguments << QLatin1String("-srcpath") << m_options->sourcePaths.join(QString(QLatin1Char(';')));
750     // Compile argument string preserving quotes
751     QString nativeArguments = m_options->additionalArguments;
752     switch (sp.startMode) {
753     case StartInternal:
754     case StartExternal:
755         if (!nativeArguments.isEmpty())
756             nativeArguments.push_back(blank);
757         nativeArguments += QDir::toNativeSeparators(sp.executable);
758         break;
759     case AttachToRemote:
760         break;
761     case AttachExternal:
762     case AttachCrashedExternal:
763         arguments << QLatin1String("-p") << QString::number(sp.attachPID);
764         if (sp.startMode == AttachCrashedExternal)
765             arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
766         break;
767     default:
768         *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
769         return false;
770     }
771     if (!sp.processArgs.isEmpty()) { // Complete native argument string.
772         if (!nativeArguments.isEmpty())
773             nativeArguments.push_back(blank);
774         nativeArguments += sp.processArgs;
775     }
776
777     const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
778             arg(QDir::toNativeSeparators(executable),
779                 arguments.join(QString(blank)) + blank + nativeArguments,
780                 QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
781                 extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
782     showMessage(msg, LogMisc);
783
784     m_outputBuffer.clear();
785     const QStringList environment = sp.environment.size() == 0 ?
786                                     QProcessEnvironment::systemEnvironment().toStringList() :
787                                     sp.environment.toStringList();
788     m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
789     if (!sp.workingDirectory.isEmpty())
790         m_process.setWorkingDirectory(sp.workingDirectory);
791
792 #ifdef Q_OS_WIN
793     if (!nativeArguments.isEmpty()) // Appends
794         m_process.setNativeArguments(nativeArguments);
795 #endif
796     m_process.start(executable, arguments);
797     if (!m_process.waitForStarted()) {
798         *errorMessage = QString::fromLatin1("Internal error: Cannot start process %1: %2").
799                 arg(QDir::toNativeSeparators(executable), m_process.errorString());
800         return false;
801     }
802 #ifdef Q_OS_WIN
803     const unsigned long pid = Utils::winQPidToPid(m_process.pid());
804 #else
805     const unsigned long pid = 0;
806 #endif
807     showMessage(QString::fromLatin1("%1 running as %2").
808                 arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc);
809     m_hasDebuggee = true;
810     if (isRemote) { // We do not get an 'idle' in a remote session, but are accessible
811         m_accessible = true;
812         const QByteArray loadCommand = QByteArray(".load ")
813                 + extensionFileName.toLocal8Bit();
814         postCommand(loadCommand, 0);
815         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
816         notifyEngineSetupOk();
817     }
818     return true;
819 }
820
821 void CdbEngine::setupInferior()
822 {
823     if (debug)
824         qDebug("setupInferior");
825     attemptBreakpointSynchronization();
826     postCommand("sxn 0x4000001f", 0); // Do not break on WowX86 exceptions.
827     postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
828 }
829
830 void CdbEngine::runEngine()
831 {
832     if (debug)
833         qDebug("runEngine");
834     // Resume the threads frozen by the console stub.
835     if (isConsole(startParameters()))
836         postCommand("~* m", 0);
837     foreach (const QString &breakEvent, m_options->breakEvents)
838             postCommand(QByteArray("sxe ") + breakEvent.toAscii(), 0);
839     postCommand("g", 0);
840 }
841
842 bool CdbEngine::commandsPending() const
843 {
844     return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
845 }
846
847 void CdbEngine::shutdownInferior()
848 {
849     if (debug)
850         qDebug("CdbEngine::shutdownInferior in state '%s', process running %d", stateName(state()),
851                isCdbProcessRunning());
852
853     if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
854         if (debug)
855             qDebug("notifyInferiorShutdownOk");
856         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
857         notifyInferiorShutdownOk();
858         return;
859     }
860
861     if (m_accessible) {
862         if (m_effectiveStartMode == AttachExternal || m_effectiveStartMode == AttachCrashedExternal)
863             detachDebugger();
864         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
865         notifyInferiorShutdownOk();
866     } else {
867         // A command got stuck.
868         if (commandsPending()) {
869             showMessage(QLatin1String("Cannot shut down inferior due to pending commands."), LogWarning);
870             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
871             notifyInferiorShutdownFailed();
872             return;
873         }
874         if (!canInterruptInferior()) {
875             showMessage(QLatin1String("Cannot interrupt the inferior."), LogWarning);
876             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
877             notifyInferiorShutdownFailed();
878             return;
879         }
880         interruptInferior(); // Calls us again
881     }
882 }
883
884 /* shutdownEngine/processFinished:
885  * Note that in the case of launching a process by the debugger, the debugger
886  * automatically quits a short time after reporting the session becoming
887  * inaccessible without debuggee (notifyInferiorExited). In that case,
888  * processFinished() must not report any arbitrarily notifyEngineShutdownOk()
889  * as not to confuse the state engine.
890  */
891
892 void CdbEngine::shutdownEngine()
893 {
894     if (debug)
895         qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
896                "accessible=%d,commands pending=%d",
897                stateName(state()), isCdbProcessRunning(), m_accessible,
898                commandsPending());
899
900     if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
901         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
902         notifyEngineShutdownOk();
903         return;
904     }
905
906     // No longer trigger anything from messages
907     m_ignoreCdbOutput = true;
908     // Go for kill if there are commands pending.
909     if (m_accessible && !commandsPending()) {
910         // detach: Wait for debugger to finish.
911         if (m_effectiveStartMode == AttachExternal)
912             detachDebugger();
913         // Remote requires a bit more force to quit.
914         if (m_effectiveStartMode == AttachToRemote) {
915             postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
916             postCommand("qq", 0);
917         } else {
918             postCommand("q", 0);
919         }
920         m_notifyEngineShutdownOnTermination = true;
921         return;
922     } else {
923         // Remote process. No can do, currently
924         m_notifyEngineShutdownOnTermination = true;
925         Utils::SynchronousProcess::stopProcess(m_process);
926         return;
927     }
928     // Lost debuggee, debugger should quit anytime now
929     if (!m_hasDebuggee) {
930         m_notifyEngineShutdownOnTermination = true;
931         return;
932     }
933     interruptInferior();
934 }
935
936 void CdbEngine::processFinished()
937 {
938     if (debug)
939         qDebug("CdbEngine::processFinished %dms '%s' notify=%d (exit state=%d, ex=%d)",
940                elapsedLogTime(), stateName(state()), m_notifyEngineShutdownOnTermination,
941                m_process.exitStatus(), m_process.exitCode());
942
943     const bool crashed = m_process.exitStatus() == QProcess::CrashExit;
944     if (crashed) {
945         showMessage(tr("CDB crashed"), LogError); // not in your life.
946     } else {
947         showMessage(tr("CDB exited (%1)").arg(m_process.exitCode()), LogMisc);
948     }
949
950     if (m_notifyEngineShutdownOnTermination) {
951         if (crashed) {
952             if (debug)
953                 qDebug("notifyEngineIll");
954             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
955             notifyEngineIll();
956         } else {
957             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
958             notifyEngineShutdownOk();
959         }
960     } else {
961         // The QML/CPP engine relies on the standard sequence of InferiorShutDown,etc.
962         // Otherwise, we take a shortcut.
963         if (isSlaveEngine()) {
964             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorExited")
965             notifyInferiorExited();
966         } else {
967             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
968             notifyEngineSpontaneousShutdown();
969         }
970     }
971 }
972
973 void CdbEngine::detachDebugger()
974 {
975     postCommand(".detach", 0);
976 }
977
978 static inline bool isWatchIName(const QByteArray &iname)
979 {
980     return iname.startsWith("watch");
981 }
982
983 void CdbEngine::updateWatchData(const WatchData &dataIn,
984                                 const WatchUpdateFlags & flags)
985 {
986     if (debug || debugLocals || debugWatches)
987         qDebug("CdbEngine::updateWatchData() %dms accessible=%d %s incr=%d: %s",
988                elapsedLogTime(), m_accessible, stateName(state()),
989                flags.tryIncremental,
990                qPrintable(dataIn.toString()));
991
992     if (!m_accessible) // Add watch data while running?
993         return;
994
995     // New watch item?
996     if (isWatchIName(dataIn.iname) && dataIn.isValueNeeded()) {
997         QByteArray args;
998         ByteArrayInputStream str(args);
999         str << dataIn.iname << " \"" << dataIn.exp << '"';
1000         postExtensionCommand("addwatch", args, 0,
1001                              &CdbEngine::handleAddWatch, 0,
1002                              qVariantFromValue(dataIn));
1003         return;
1004     }
1005
1006     if (!dataIn.hasChildren && !dataIn.isValueNeeded()) {
1007         WatchData data = dataIn;
1008         data.setAllUnneeded();
1009         watchHandler()->insertData(data);
1010         return;
1011     }
1012     updateLocalVariable(dataIn.iname);
1013 }
1014
1015 void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
1016 {
1017     WatchData item = qvariant_cast<WatchData>(reply->cookie);
1018     if (debugWatches)
1019         qDebug() << "handleAddWatch ok="  << reply->success << item.iname;
1020     if (reply->success) {
1021         updateLocalVariable(item.iname);
1022     } else {
1023         item.setError(tr("Unable to add expression"));
1024         watchHandler()->insertData(item);
1025         showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
1026                     arg(QString::fromAscii(item.iname), QString::fromAscii(item.exp),
1027                         reply->errorMessage), LogError);
1028     }
1029 }
1030
1031 void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
1032 {
1033     if (debuggerCore()->boolSetting(VerboseLog))
1034         str << blankSeparator << "-v";
1035     if (debuggerCore()->boolSetting(UseDebuggingHelpers))
1036         str << blankSeparator << "-c";
1037     const QByteArray typeFormats = watchHandler()->typeFormatRequests();
1038     if (!typeFormats.isEmpty())
1039         str << blankSeparator << "-T " << typeFormats;
1040     const QByteArray individualFormats = watchHandler()->individualFormatRequests();
1041     if (!individualFormats.isEmpty())
1042         str << blankSeparator << "-I " << individualFormats;
1043 }
1044
1045 void CdbEngine::updateLocalVariable(const QByteArray &iname)
1046 {
1047     const bool isWatch = isWatchIName(iname);
1048     if (debugWatches)
1049         qDebug() << "updateLocalVariable watch=" << isWatch << iname;
1050     QByteArray localsArguments;
1051     ByteArrayInputStream str(localsArguments);
1052     addLocalsOptions(str);
1053     if (!isWatch) {
1054         const int stackFrame = stackHandler()->currentIndex();
1055         if (stackFrame < 0) {
1056             qWarning("Internal error; no stack frame in updateLocalVariable");
1057             return;
1058         }
1059         str << blankSeparator << stackFrame;
1060     }
1061     str << blankSeparator << iname;
1062     postExtensionCommand(isWatch ? "watches" : "locals", localsArguments, 0, &CdbEngine::handleLocals);
1063 }
1064
1065 unsigned CdbEngine::debuggerCapabilities() const
1066 {
1067     return DisassemblerCapability | RegisterCapability | ShowMemoryCapability
1068            |WatchpointCapability|JumpToLineCapability|AddWatcherCapability
1069            |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
1070            |BreakConditionCapability|TracePointCapability
1071            |BreakModuleCapability;
1072 }
1073
1074 void CdbEngine::executeStep()
1075 {
1076     if (!m_operateByInstruction)
1077         m_sourceStepInto = true; // See explanation at handleStackTrace().
1078     postCommand(QByteArray("t"), 0); // Step into-> t (trace)
1079     STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1080     notifyInferiorRunRequested();
1081 }
1082
1083 void CdbEngine::executeStepOut()
1084 {
1085     postCommand(QByteArray("gu"), 0); // Step out-> gu (go up)
1086     STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1087     notifyInferiorRunRequested();
1088 }
1089
1090 void CdbEngine::executeNext()
1091 {
1092     postCommand(QByteArray("p"), 0); // Step over -> p
1093     STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1094     notifyInferiorRunRequested();
1095 }
1096
1097 void CdbEngine::executeStepI()
1098 {
1099     executeStep();
1100 }
1101
1102 void CdbEngine::executeNextI()
1103 {
1104     executeNext();
1105 }
1106
1107 void CdbEngine::continueInferior()
1108 {
1109     STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1110     notifyInferiorRunRequested();
1111     doContinueInferior();
1112 }
1113
1114 void CdbEngine::doContinueInferior()
1115 {
1116     postCommand(QByteArray("g"), 0);
1117 }
1118
1119 bool CdbEngine::canInterruptInferior() const
1120 {
1121     return m_effectiveStartMode != AttachToRemote && m_inferiorPid;
1122 }
1123
1124 void CdbEngine::interruptInferior()
1125 {
1126     if (debug)
1127         qDebug() << "CdbEngine::interruptInferior()" << stateName(state());
1128     if (canInterruptInferior()) {
1129         doInterruptInferior(NoSpecialStop);
1130     } else {
1131         showMessage(tr("Interrupting is not possible in remote sessions."), LogError);
1132         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorStopOk")
1133         notifyInferiorStopOk();
1134         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1135         notifyInferiorRunRequested();
1136         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk")
1137         notifyInferiorRunOk();
1138     }
1139 }
1140
1141 void CdbEngine::doInterruptInferiorCustomSpecialStop(const QVariant &v)
1142 {
1143     if (m_specialStopMode == NoSpecialStop)
1144         doInterruptInferior(CustomSpecialStop);
1145     m_customSpecialStopData.push_back(v);
1146 }
1147
1148 void CdbEngine::doInterruptInferior(SpecialStopMode sm)
1149 {
1150 #ifdef Q_OS_WIN
1151     const SpecialStopMode oldSpecialMode = m_specialStopMode;
1152     m_specialStopMode = sm;
1153     QString errorMessage;
1154     showMessage(QString::fromLatin1("Interrupting process %1...").arg(m_inferiorPid), LogMisc);
1155     if (!winDebugBreakProcess(m_inferiorPid, &errorMessage)) {
1156         m_specialStopMode = oldSpecialMode;
1157         showMessage(QString::fromLatin1("Cannot interrupt process %1: %2").arg(m_inferiorPid).arg(errorMessage), LogError);
1158     }
1159 #else
1160     Q_UNUSED(sm)
1161 #endif
1162 }
1163
1164 void CdbEngine::executeRunToLine(const ContextData &data)
1165 {
1166     // Add one-shot breakpoint
1167     BreakpointParameters bp;
1168     if (data.address) {
1169         bp.type =BreakpointByAddress;
1170         bp.address = data.address;
1171     } else {
1172         bp.type =BreakpointByFileAndLine;
1173         bp.fileName = data.fileName;
1174         bp.lineNumber = data.lineNumber;
1175     }
1176     postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointId(-1), true), 0);
1177     continueInferior();
1178 }
1179
1180 void CdbEngine::executeRunToFunction(const QString &functionName)
1181 {
1182     // Add one-shot breakpoint
1183     BreakpointParameters bp(BreakpointByFunction);
1184     bp.functionName = functionName;
1185
1186     postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointId(-1), true), 0);
1187     continueInferior();
1188 }
1189
1190 void CdbEngine::setRegisterValue(int regnr, const QString &value)
1191 {
1192     const Registers registers = registerHandler()->registers();
1193     QTC_ASSERT(regnr < registers.size(), return)
1194     // Value is decimal or 0x-hex-prefixed
1195     QByteArray cmd;
1196     ByteArrayInputStream str(cmd);
1197     str << "r " << registers.at(regnr).name << '=' << value;
1198     postCommand(cmd, 0);
1199     reloadRegisters();
1200 }
1201
1202 void CdbEngine::executeJumpToLine(const ContextData &data)
1203 {
1204     if (data.address) {
1205         // Goto address directly.
1206         jumpToAddress(data.address);
1207         gotoLocation(Location(data.address));
1208     } else {
1209         // Jump to source line: Resolve source line address and go to that location
1210         QByteArray cmd;
1211         ByteArrayInputStream str(cmd);
1212         str << "? `" << QDir::toNativeSeparators(data.fileName) << ':' << data.lineNumber << '`';
1213         const QVariant cookie = qVariantFromValue(data);
1214         postBuiltinCommand(cmd, 0, &CdbEngine::handleJumpToLineAddressResolution, 0, cookie);
1215     }
1216 }
1217
1218 void CdbEngine::jumpToAddress(quint64 address)
1219 {
1220     // Fake a jump to address by setting the PC register.
1221     QByteArray registerCmd;
1222     ByteArrayInputStream str(registerCmd);
1223     // PC-register depending on 64/32bit.
1224     str << "r " << (startParameters().toolChainAbi.wordWidth() == 64 ? "rip" : "eip") << '=';
1225     str.setHexPrefix(true);
1226     str.setIntegerBase(16);
1227     str << address;
1228     postCommand(registerCmd, 0);
1229 }
1230
1231 void CdbEngine::handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &cmd)
1232 {
1233     if (cmd->reply.isEmpty())
1234         return;
1235     // Evaluate expression: 5365511549 = 00000001`3fcf357d
1236     // Set register 'rip' to hex address and goto lcoation
1237     QString answer = QString::fromAscii(cmd->reply.front()).trimmed();
1238     const int equalPos = answer.indexOf(" = ");
1239     if (equalPos == -1)
1240         return;
1241     answer.remove(0, equalPos + 3);
1242     answer.remove(QLatin1Char('`'));
1243     bool ok;
1244     const quint64 address = answer.toLongLong(&ok, 16);
1245     if (ok && address) {
1246         QTC_ASSERT(qVariantCanConvert<ContextData>(cmd->cookie), return);
1247         const ContextData cookie = qvariant_cast<ContextData>(cmd->cookie);
1248         jumpToAddress(address);
1249         gotoLocation(Location(cookie.fileName, cookie.lineNumber));
1250     }
1251 }
1252
1253 void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value)
1254 {
1255     if (debug)
1256         qDebug() << "CdbEngine::assignValueInDebugger" << w->iname << expr << value;
1257
1258     if (state() != InferiorStopOk || stackHandler()->currentIndex() < 0) {
1259         qWarning("Internal error: assignValueInDebugger: Invalid state or no stack frame.");
1260         return;
1261     }
1262
1263     QByteArray cmd;
1264     ByteArrayInputStream str(cmd);
1265     str << m_extensionCommandPrefixBA << "assign " << w->iname << '=' << value.toString();
1266     postCommand(cmd, 0);
1267     // Update all locals in case we change a union or something pointed to
1268     // that affects other variables, too.
1269     updateLocals();
1270 }
1271
1272 void CdbEngine::parseThreads(const GdbMi &data, int forceCurrentThreadId /* = -1 */)
1273 {
1274     int currentThreadId;
1275     Threads threads = ThreadsHandler::parseGdbmiThreads(data, &currentThreadId);
1276     threadsHandler()->setThreads(threads);
1277     threadsHandler()->setCurrentThreadId(forceCurrentThreadId >= 0 ?
1278                                          forceCurrentThreadId : currentThreadId);
1279 }
1280
1281 void CdbEngine::handleThreads(const CdbExtensionCommandPtr &reply)
1282 {
1283     if (debug)
1284         qDebug("CdbEngine::handleThreads success=%d", reply->success);
1285     if (reply->success) {
1286         GdbMi data;
1287         data.fromString(reply->reply);
1288         parseThreads(data);
1289         // Continue sequence
1290         postCommandSequence(reply->commandSequence);
1291     } else {
1292         showMessage(QString::fromLatin1(reply->errorMessage), LogError);
1293     }
1294 }
1295
1296 void CdbEngine::executeDebuggerCommand(const QString &command)
1297 {
1298     postCommand(command.toLocal8Bit(), QuietCommand);
1299 }
1300
1301 // Post command without callback
1302 void CdbEngine::postCommand(const QByteArray &cmd, unsigned flags)
1303 {
1304     if (debug)
1305         qDebug("CdbEngine::postCommand %dms '%s' %u %s\n",
1306                elapsedLogTime(), cmd.constData(), flags, stateName(state()));
1307     if (!(flags & QuietCommand))
1308         showMessage(QString::fromLocal8Bit(cmd), LogInput);
1309     m_process.write(cmd + '\n');
1310 }
1311
1312 // Post a built-in-command producing free-format output with a callback.
1313 // In order to catch the output, it is enclosed in 'echo' commands
1314 // printing a specially formatted token to be identifiable in the output.
1315 void CdbEngine::postBuiltinCommand(const QByteArray &cmd, unsigned flags,
1316                                    BuiltinCommandHandler handler,
1317                                    unsigned nextCommandFlag,
1318                                    const QVariant &cookie)
1319 {
1320     if (!m_accessible) {
1321         const QString msg = QString::fromLatin1("Attempt to issue builtin command '%1' to non-accessible session (%2)")
1322                 .arg(QString::fromLocal8Bit(cmd), QString::fromAscii(stateName(state())));
1323         showMessage(msg, LogError);
1324         return;
1325     }
1326     if (!flags & QuietCommand)
1327         showMessage(QString::fromLocal8Bit(cmd), LogInput);
1328
1329     const int token = m_nextCommandToken++;
1330     CdbBuiltinCommandPtr pendingCommand(new CdbBuiltinCommand(cmd, token, flags, handler, nextCommandFlag, cookie));
1331
1332     m_builtinCommandQueue.push_back(pendingCommand);
1333     // Enclose command in echo-commands for token
1334     QByteArray fullCmd;
1335     ByteArrayInputStream str(fullCmd);
1336     str << ".echo \"" << m_tokenPrefix << token << "<\"\n"
1337             << cmd << "\n.echo \"" << m_tokenPrefix << token << ">\"\n";
1338     if (debug)
1339         qDebug("CdbEngine::postBuiltinCommand %dms '%s' flags=%u token=%d %s next=%u, cookie='%s', pending=%d, sequence=0x%x",
1340                elapsedLogTime(), cmd.constData(), flags, token, stateName(state()), nextCommandFlag, qPrintable(cookie.toString()),
1341                m_builtinCommandQueue.size(), nextCommandFlag);
1342     if (debug > 1)
1343         qDebug("CdbEngine::postBuiltinCommand: resulting command '%s'\n",
1344                fullCmd.constData());
1345     m_process.write(fullCmd);
1346 }
1347
1348 // Post an extension command producing one-line output with a callback,
1349 // pass along token for identification in queue.
1350 void CdbEngine::postExtensionCommand(const QByteArray &cmd,
1351                                      const QByteArray &arguments,
1352                                      unsigned flags,
1353                                      ExtensionCommandHandler handler,
1354                                      unsigned nextCommandFlag,
1355                                      const QVariant &cookie)
1356 {
1357     if (!m_accessible) {
1358         const QString msg = QString::fromLatin1("Attempt to issue extension command '%1' to non-accessible session (%2)")
1359                 .arg(QString::fromLocal8Bit(cmd), QString::fromAscii(stateName(state())));
1360         showMessage(msg, LogError);
1361         return;
1362     }
1363
1364     const int token = m_nextCommandToken++;
1365
1366     // Format full command with token to be recognizeable in the output
1367     QByteArray fullCmd;
1368     ByteArrayInputStream str(fullCmd);
1369     str << m_extensionCommandPrefixBA << cmd << " -t " << token;
1370     if (!arguments.isEmpty())
1371         str <<  ' ' << arguments;
1372
1373     if (!flags & QuietCommand)
1374         showMessage(QString::fromLocal8Bit(fullCmd), LogInput);
1375
1376     CdbExtensionCommandPtr pendingCommand(new CdbExtensionCommand(fullCmd, token, flags, handler, nextCommandFlag, cookie));
1377
1378     m_extensionCommandQueue.push_back(pendingCommand);
1379     // Enclose command in echo-commands for token
1380     if (debug)
1381         qDebug("CdbEngine::postExtensionCommand %dms '%s' flags=%u token=%d %s next=%u, cookie='%s', pending=%d, sequence=0x%x",
1382                elapsedLogTime(), fullCmd.constData(), flags, token, stateName(state()), nextCommandFlag, qPrintable(cookie.toString()),
1383                m_extensionCommandQueue.size(), nextCommandFlag);
1384     m_process.write(fullCmd + '\n');
1385 }
1386
1387 void CdbEngine::activateFrame(int index)
1388 {
1389     // TODO: assembler,etc
1390     if (index < 0)
1391         return;
1392     const StackFrames &frames = stackHandler()->frames();
1393     QTC_ASSERT(index < frames.size(), return; )
1394
1395     const StackFrame frame = frames.at(index);
1396     if (debug || debugLocals)
1397         qDebug("activateFrame idx=%d '%s' %d", index,
1398                qPrintable(frame.file), frame.line);
1399     stackHandler()->setCurrentIndex(index);
1400     const bool showAssembler = !frames.at(index).isUsable();
1401     if (showAssembler) { // Assembly code: Clean out model and force instruction mode.
1402         watchHandler()->beginCycle();
1403         watchHandler()->endCycle();
1404         QAction *assemblerAction = theAssemblerAction();
1405         if (assemblerAction->isChecked()) {
1406             gotoLocation(frame);
1407         } else {
1408             assemblerAction->trigger(); // Seems to trigger update
1409         }
1410     } else {
1411         gotoLocation(frame);
1412         updateLocals(true);
1413     }
1414 }
1415
1416 void CdbEngine::updateLocals(bool forNewStackFrame)
1417 {
1418     typedef QHash<QByteArray, int> WatcherHash;
1419
1420     const int frameIndex = stackHandler()->currentIndex();
1421     if (frameIndex < 0) {
1422         watchHandler()->beginCycle();
1423         watchHandler()->endCycle();
1424         return;
1425     }
1426     const StackFrame frame = stackHandler()->currentFrame();
1427     if (!frame.isUsable()) {
1428         watchHandler()->beginCycle();
1429         watchHandler()->endCycle();
1430         return;
1431     }
1432     /* Watchers: Forcibly discard old symbol group as switching from
1433      * thread 0/frame 0 -> thread 1/assembly -> thread 0/frame 0 will otherwise re-use it
1434      * and cause errors as it seems to go 'stale' when switching threads.
1435      * Initial expand, get uninitialized and query */
1436     QByteArray arguments;
1437     ByteArrayInputStream str(arguments);
1438     str << "-D";
1439     // Pre-expand
1440     const QSet<QByteArray> expanded = watchHandler()->expandedINames();
1441     if (!expanded.isEmpty()) {
1442         str << blankSeparator << "-e ";
1443         int i = 0;
1444         foreach(const QByteArray &e, expanded) {
1445             if (i++)
1446                 str << ',';
1447             str << e;
1448         }
1449     }
1450     addLocalsOptions(str);
1451     // Uninitialized variables if desired
1452     if (debuggerCore()->boolSetting(UseCodeModel)) {
1453         QStringList uninitializedVariables;
1454         getUninitializedVariables(debuggerCore()->cppCodeModelSnapshot(),
1455                                   frame.function, frame.file, frame.line, &uninitializedVariables);
1456         if (!uninitializedVariables.isEmpty()) {
1457             str << blankSeparator << "-u ";
1458             int i = 0;
1459             foreach(const QString &u, uninitializedVariables) {
1460                 if (i++)
1461                     str << ',';
1462                 str << localsPrefixC << u;
1463             }
1464         }
1465     }
1466     // Perform watches synchronization
1467     str << blankSeparator << "-W";
1468     const WatcherHash watcherHash = WatchHandler::watcherNames();
1469     if (!watcherHash.isEmpty()) {
1470         const WatcherHash::const_iterator cend = watcherHash.constEnd();
1471         for (WatcherHash::const_iterator it = watcherHash.constBegin(); it != cend; ++it) {
1472             str << blankSeparator << "-w " << it.value() << " \"" << it.key() << '"';
1473         }
1474     }
1475
1476     // Required arguments: frame
1477     str << blankSeparator << frameIndex;
1478     watchHandler()->beginCycle();
1479     postExtensionCommand("locals", arguments, 0, &CdbEngine::handleLocals, 0, QVariant(forNewStackFrame));
1480 }
1481
1482 void CdbEngine::selectThread(int index)
1483 {
1484     if (index < 0 || index == threadsHandler()->currentThread())
1485         return;
1486
1487     resetLocation();
1488     const int newThreadId = threadsHandler()->threads().at(index).id;
1489     threadsHandler()->setCurrentThread(index);
1490
1491     const QByteArray cmd = "~" + QByteArray::number(newThreadId) + " s";
1492     postBuiltinCommand(cmd, 0, &CdbEngine::dummyHandler, CommandListStack);
1493 }
1494
1495 void CdbEngine::fetchDisassembler(DisassemblerAgent *agent)
1496 {
1497     QTC_ASSERT(m_accessible, return;)
1498     QByteArray cmd;
1499     ByteArrayInputStream str(cmd);
1500     str <<  "u " << hex << hexPrefixOn << agent->address() << " L40";
1501     const QVariant cookie = qVariantFromValue<DisassemblerAgent*>(agent);
1502     postBuiltinCommand(cmd, 0, &CdbEngine::handleDisassembler, 0, cookie);
1503 }
1504
1505 // Parse: "00000000`77606060 cc              int     3"
1506 void CdbEngine::handleDisassembler(const CdbBuiltinCommandPtr &command)
1507 {
1508     QTC_ASSERT(qVariantCanConvert<DisassemblerAgent*>(command->cookie), return;)
1509     DisassemblerAgent *agent = qvariant_cast<DisassemblerAgent*>(command->cookie);
1510     DisassemblerLines disassemblerLines;
1511     foreach(const QByteArray &line, command->reply)
1512         disassemblerLines.appendLine(DisassemblerLine(QString::fromLatin1(line)));
1513     agent->setContents(disassemblerLines);
1514 }
1515
1516 void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length)
1517 {
1518     if (!m_accessible) {
1519         qWarning("Internal error: Attempt to read memory from inaccessible session: %s", Q_FUNC_INFO);
1520         return;
1521     }
1522     if (debug)
1523         qDebug("CdbEngine::fetchMemory %llu bytes from 0x%llx", length, addr);
1524
1525     QByteArray args;
1526     ByteArrayInputStream str(args);
1527     str << addr << ' ' << length;
1528     const QVariant cookie = qVariantFromValue<MemoryViewCookie>(MemoryViewCookie(agent, editor, addr, length));
1529     postExtensionCommand("memory", args, 0, &CdbEngine::handleMemory, 0, cookie);
1530 }
1531
1532 void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data)
1533 {
1534     QTC_ASSERT(!data.isEmpty(), return; )
1535     if (!m_accessible) {
1536         const MemoryChangeCookie cookie(addr, data);
1537         doInterruptInferiorCustomSpecialStop(qVariantFromValue(cookie));
1538     } else {
1539         postCommand(cdbWriteMemoryCommand(addr, data), 0);
1540     }
1541 }
1542
1543 void CdbEngine::handleMemory(const CdbExtensionCommandPtr &command)
1544 {
1545     QTC_ASSERT(qVariantCanConvert<MemoryViewCookie>(command->cookie), return;)
1546     const MemoryViewCookie memViewCookie = qvariant_cast<MemoryViewCookie>(command->cookie);
1547     if (command->success) {
1548         const QByteArray data = QByteArray::fromBase64(command->reply);
1549         if (unsigned(data.size()) == memViewCookie.length)
1550             memViewCookie.agent->addLazyData(memViewCookie.editorToken,
1551                                              memViewCookie.address, data);
1552     } else {
1553         showMessage(QString::fromLocal8Bit(command->errorMessage), LogError);
1554     }
1555 }
1556
1557 void CdbEngine::reloadModules()
1558 {
1559     postCommandSequence(CommandListModules);
1560 }
1561
1562 void CdbEngine::loadSymbols(const QString & /* moduleName */)
1563 {
1564 }
1565
1566 void CdbEngine::loadAllSymbols()
1567 {
1568 }
1569
1570 void CdbEngine::requestModuleSymbols(const QString &moduleName)
1571 {
1572     Q_UNUSED(moduleName)
1573 }
1574
1575 void CdbEngine::reloadRegisters()
1576 {
1577     postCommandSequence(CommandListRegisters);
1578 }
1579
1580 void CdbEngine::reloadSourceFiles()
1581 {
1582 }
1583
1584 void CdbEngine::reloadFullStack()
1585 {
1586     if (debug)
1587         qDebug("%s", Q_FUNC_INFO);
1588     postCommandSequence(CommandListStack);
1589 }
1590
1591 void CdbEngine::handlePid(const CdbExtensionCommandPtr &reply)
1592 {
1593     if (reply->success) {
1594         m_inferiorPid = reply->reply.toUInt();
1595         showMessage(QString::fromLatin1("Inferior pid: %1.").arg(m_inferiorPid), LogMisc);
1596         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupOk")
1597         notifyInferiorSetupOk();
1598     }  else {
1599         showMessage(QString::fromLatin1("Failed to determine inferior pid: %1").
1600                     arg(QLatin1String(reply->errorMessage)), LogError);
1601         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupFailed")
1602         notifyInferiorSetupFailed();
1603     }
1604 }
1605
1606 // Parse CDB gdbmi register syntax
1607 static inline Register parseRegister(const GdbMi &gdbmiReg)
1608 {
1609     Register reg;
1610     reg.name = gdbmiReg.findChild("name").data();
1611     const GdbMi description = gdbmiReg.findChild("description");
1612     if (description.type() != GdbMi::Invalid) {
1613         reg.name += " (";
1614         reg.name += description.data();
1615         reg.name += ')';
1616     }
1617     reg.value = QString::fromAscii(gdbmiReg.findChild("value").data());
1618     return reg;
1619 }
1620
1621 void CdbEngine::handleModules(const CdbExtensionCommandPtr &reply)
1622 {
1623     if (reply->success) {
1624         GdbMi value;
1625         value.fromString(reply->reply);
1626         if (value.type() == GdbMi::List) {
1627             Modules modules;
1628             modules.reserve(value.childCount());
1629             foreach (const GdbMi &gdbmiModule, value.children()) {
1630                 Module module;
1631                 module.moduleName = QString::fromAscii(gdbmiModule.findChild("name").data());
1632                 module.modulePath = QString::fromAscii(gdbmiModule.findChild("image").data());
1633                 module.startAddress = gdbmiModule.findChild("start").data().toULongLong(0, 0);
1634                 module.endAddress = gdbmiModule.findChild("end").data().toULongLong(0, 0);
1635                 if (gdbmiModule.findChild("deferred").type() == GdbMi::Invalid)
1636                     module.symbolsRead = Module::ReadOk;
1637                 modules.push_back(module);
1638             }
1639             modulesHandler()->setModules(modules);
1640         } else {
1641             showMessage(QString::fromLatin1("Parse error in modules response."), LogError);
1642             qWarning("Parse error in modules response:\n%s", reply->reply.constData());
1643         }
1644     }  else {
1645         showMessage(QString::fromLatin1("Failed to determine modules: %1").
1646                     arg(QLatin1String(reply->errorMessage)), LogError);
1647     }
1648     postCommandSequence(reply->commandSequence);
1649
1650 }
1651
1652 void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply)
1653 {
1654     if (reply->success) {
1655         GdbMi value;
1656         value.fromString(reply->reply);
1657         if (value.type() == GdbMi::List) {
1658             Registers registers;
1659             registers.reserve(value.childCount());
1660             foreach (const GdbMi &gdbmiReg, value.children())
1661                 registers.push_back(parseRegister(gdbmiReg));
1662             registerHandler()->setRegisters(registers);
1663         } else {
1664             showMessage(QString::fromLatin1("Parse error in registers response."), LogError);
1665             qWarning("Parse error in registers response:\n%s", reply->reply.constData());
1666         }
1667     }  else {
1668         showMessage(QString::fromLatin1("Failed to determine registers: %1").
1669                     arg(QLatin1String(reply->errorMessage)), LogError);
1670     }
1671     postCommandSequence(reply->commandSequence);
1672 }
1673
1674 void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
1675 {
1676     if (reply->success) {
1677         QList<WatchData> watchData;
1678         GdbMi root;
1679         root.fromString(reply->reply);
1680         QTC_ASSERT(root.isList(), return ; )
1681         if (debugLocals) {
1682             qDebug() << root.toString(true, 4);
1683         }
1684         // Courtesy of GDB engine
1685         foreach (const GdbMi &child, root.children()) {
1686             WatchData dummy;
1687             dummy.iname = child.findChild("iname").data();
1688             dummy.name = QLatin1String(child.findChild("name").data());
1689             parseWatchData(watchHandler()->expandedINames(), dummy, child, &watchData);
1690         }
1691         watchHandler()->insertBulkData(watchData);
1692         watchHandler()->endCycle();
1693         if (debugLocals) {
1694             QDebug nsp = qDebug().nospace();
1695             nsp << "Obtained " << watchData.size() << " items:\n";
1696             foreach (const WatchData &wd, watchData)
1697                 nsp << wd.toString() <<'\n';
1698         }
1699         const bool forNewStackFrame = reply->cookie.toBool();
1700         if (forNewStackFrame)
1701             emit stackFrameCompleted();
1702     } else {
1703         showMessage(QString::fromLatin1(reply->errorMessage), LogError);
1704     }
1705 }
1706
1707 void CdbEngine::handleExpandLocals(const CdbExtensionCommandPtr &reply)
1708 {
1709     if (!reply->success)
1710         showMessage(QString::fromLatin1(reply->errorMessage), LogError);
1711 }
1712
1713 enum CdbExecutionStatus {
1714 CDB_STATUS_NO_CHANGE=0, CDB_STATUS_GO = 1, CDB_STATUS_GO_HANDLED = 2,
1715 CDB_STATUS_GO_NOT_HANDLED = 3, CDB_STATUS_STEP_OVER = 4,
1716 CDB_STATUS_STEP_INTO = 5, CDB_STATUS_BREAK = 6, CDB_STATUS_NO_DEBUGGEE = 7,
1717 CDB_STATUS_STEP_BRANCH = 8, CDB_STATUS_IGNORE_EVENT = 9,
1718 CDB_STATUS_RESTART_REQUESTED = 10, CDB_STATUS_REVERSE_GO = 11,
1719 CDB_STATUS_REVERSE_STEP_BRANCH = 12, CDB_STATUS_REVERSE_STEP_OVER = 13,
1720 CDB_STATUS_REVERSE_STEP_INTO = 14 };
1721
1722 static const char *cdbStatusName(unsigned long s)
1723 {
1724     switch (s) {
1725     case CDB_STATUS_NO_CHANGE:
1726         return "No change";
1727     case CDB_STATUS_GO:
1728         return "go";
1729     case CDB_STATUS_GO_HANDLED:
1730         return "go_handled";
1731     case CDB_STATUS_GO_NOT_HANDLED:
1732         return "go_not_handled";
1733     case CDB_STATUS_STEP_OVER:
1734         return "step_over";
1735     case CDB_STATUS_STEP_INTO:
1736         return "step_into";
1737     case CDB_STATUS_BREAK:
1738         return "break";
1739     case CDB_STATUS_NO_DEBUGGEE:
1740         return "no_debuggee";
1741     case CDB_STATUS_STEP_BRANCH:
1742         return "step_branch";
1743     case CDB_STATUS_IGNORE_EVENT:
1744         return "ignore_event";
1745     case CDB_STATUS_RESTART_REQUESTED:
1746         return "restart_requested";
1747     case CDB_STATUS_REVERSE_GO:
1748         return "reverse_go";
1749     case CDB_STATUS_REVERSE_STEP_BRANCH:
1750         return "reverse_step_branch";
1751     case CDB_STATUS_REVERSE_STEP_OVER:
1752         return "reverse_step_over";
1753     case CDB_STATUS_REVERSE_STEP_INTO:
1754         return "reverse_step_into";
1755     }
1756     return "unknown";
1757 }
1758
1759 /* Examine how to react to a stop. */
1760 enum StopActionFlags
1761 {
1762     // Report options
1763     StopReportLog = 0x1,
1764     StopReportStatusMessage = 0x2,
1765     StopReportParseError = 0x4,
1766     StopShowExceptionMessageBox = 0x8,
1767     // Notify stop or just continue
1768     StopNotifyStop = 0x10,
1769     StopIgnoreContinue = 0x20,
1770     // Hit on break in artificial stop thread (created by DebugBreak()).
1771     StopInArtificialThread = 0x40,
1772     StopShutdownInProgress = 0x80 // Shutdown in progress
1773 };
1774
1775 static inline QString msgTracePointTriggered(BreakpointId id, const int number,
1776                                              const QString &threadId)
1777 {
1778     return CdbEngine::tr("Trace point %1 (%2) in thread %3 triggered.")
1779             .arg(id).arg(number).arg(threadId);
1780 }
1781
1782 static inline QString msgCheckingConditionalBreakPoint(BreakpointId id, const int number,
1783                                                        const QByteArray &condition,
1784                                                        const QString &threadId)
1785 {
1786     return CdbEngine::tr("Conditional breakpoint %1 (%2) in thread %3 triggered, examining expression '%4'.")
1787             .arg(id).arg(number).arg(threadId, QString::fromAscii(condition));
1788 }
1789
1790 unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
1791                                       QString *message,
1792                                       QString *exceptionBoxMessage,
1793                                       bool conditionalBreakPointTriggered)
1794 {
1795     // Report stop reason (GDBMI)
1796     unsigned rc  = 0;
1797     if (targetState() == DebuggerFinished)
1798         rc |= StopShutdownInProgress;
1799     if (debug)
1800         qDebug("%s", stopReason.toString(true, 4).constData());
1801     const QByteArray reason = stopReason.findChild("reason").data();
1802     if (reason.isEmpty()) {
1803         *message = tr("Malformed stop response received.");
1804         rc |= StopReportParseError|StopNotifyStop;
1805         return rc;
1806     }
1807     // Additional stop messages occurring for debuggee function calls (widgetAt, etc). Just log.
1808     if (state() == InferiorStopOk) {
1809         *message = QString::fromLatin1("Ignored stop notification from function call (%1).").
1810                     arg(QString::fromAscii(reason));
1811         rc |= StopReportLog;
1812         return rc;
1813     }
1814     const int threadId = stopReason.findChild("threadId").data().toInt();
1815     if (reason == "breakpoint") {
1816         // Note: Internal breakpoints (run to line) are reported with id=0.
1817         // Step out creates temporary breakpoints with id 10000.
1818         BreakpointId id = 0;
1819         int number = 0;
1820         const GdbMi breakpointIdG = stopReason.findChild("breakpointId");
1821         if (breakpointIdG.isValid()) {
1822             id = breakpointIdG.data().toULongLong();
1823             if (id && breakHandler()->engineBreakpointIds(this).contains(id)) {
1824                 const BreakpointResponse parameters =  breakHandler()->response(id);
1825                 // Trace point? Just report.
1826                 number = parameters.number;
1827                 if (parameters.tracepoint) {
1828                     *message = msgTracePointTriggered(id, number, QString::number(threadId));
1829                     return StopReportLog|StopIgnoreContinue;
1830                 }
1831                 // Trigger evaluation of BP expression unless we are already in the response.
1832                 if (!conditionalBreakPointTriggered && !parameters.condition.isEmpty()) {
1833                     *message = msgCheckingConditionalBreakPoint(id, number, parameters.condition,
1834                                                                 QString::number(threadId));
1835                     ConditionalBreakPointCookie cookie(id);
1836                     cookie.stopReason = stopReason;
1837                     evaluateExpression(parameters.condition, qVariantFromValue(cookie));
1838                     return StopReportLog;
1839                 }
1840             } else {
1841                 id = 0;
1842             }
1843         }
1844         if (id && breakHandler()->type(id) == Watchpoint) {
1845             *message = msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId));
1846         } else {
1847             *message = msgBreakpointTriggered(id, number, QString::number(threadId));
1848         }
1849         rc |= StopReportStatusMessage|StopNotifyStop;
1850         return rc;
1851     }
1852     if (reason == "exception") {
1853         WinException exception;
1854         exception.fromGdbMI(stopReason);
1855         QString description = exception.toString();
1856 #ifdef Q_OS_WIN
1857         // It is possible to hit on a startup trap or WOW86 exception while stepping (if something
1858         // pulls DLLs. Avoid showing a 'stopped' Message box.
1859         if (exception.exceptionCode == winExceptionStartupCompleteTrap
1860             || exception.exceptionCode == winExceptionWX86Breakpoint)
1861             return StopNotifyStop;
1862         if (exception.exceptionCode == winExceptionCtrlPressed) {
1863             // Detect interruption by pressing Ctrl in a console and force a switch to thread 0.
1864             *message = msgInterrupted();
1865             rc |= StopReportStatusMessage|StopNotifyStop|StopInArtificialThread;
1866             return rc;
1867         }
1868         if (isDebuggerWinException(exception.exceptionCode)) {
1869             rc |= StopReportStatusMessage|StopNotifyStop;
1870             // Detect interruption by DebugBreak() and force a switch to thread 0.
1871             if (exception.function == "ntdll!DbgBreakPoint")
1872                 rc |= StopInArtificialThread;
1873             *message = msgInterrupted();
1874             return rc;
1875         }
1876 #endif
1877         *exceptionBoxMessage = msgStoppedByException(description, QString::number(threadId));
1878         *message = description;
1879         rc |= StopShowExceptionMessageBox|StopReportStatusMessage|StopNotifyStop;
1880         return rc;
1881     }
1882     *message = msgStopped(QLatin1String(reason));
1883     rc |= StopReportStatusMessage|StopNotifyStop;
1884     return rc;
1885 }
1886
1887 void CdbEngine::handleSessionIdle(const QByteArray &messageBA)
1888 {
1889     if (!m_hasDebuggee)
1890         return;
1891
1892     if (debug)
1893         qDebug("CdbEngine::handleSessionIdle %dms '%s' in state '%s', special mode %d",
1894                elapsedLogTime(), messageBA.constData(),
1895                stateName(state()), m_specialStopMode);
1896
1897     // Switch source level debugging
1898     syncOperateByInstruction(m_operateByInstructionPending);
1899
1900     // Engine-special stop reasons: Breakpoints and setup
1901     const SpecialStopMode specialStopMode =  m_specialStopMode;
1902
1903     m_specialStopMode = NoSpecialStop;
1904
1905     switch(specialStopMode) {
1906     case SpecialStopSynchronizeBreakpoints:
1907         if (debug)
1908             qDebug("attemptBreakpointSynchronization in special stop");
1909         attemptBreakpointSynchronization();
1910         doContinueInferior();
1911         return;
1912     case SpecialStopGetWidgetAt:
1913         postWidgetAtCommand();
1914         return;
1915     case CustomSpecialStop:
1916         foreach (const QVariant &data, m_customSpecialStopData)
1917             handleCustomSpecialStop(data);
1918         m_customSpecialStopData.clear();
1919         doContinueInferior();
1920         return;
1921     case NoSpecialStop:
1922         break;
1923     }
1924
1925     if (state() == EngineSetupRequested) { // Temporary stop at beginning
1926         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
1927         notifyEngineSetupOk();
1928         return;
1929     }
1930     GdbMi stopReason;
1931     stopReason.fromString(messageBA);
1932     processStop(stopReason, false);
1933 }
1934
1935 void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointTriggered)
1936 {
1937     // Further examine stop and report to user
1938     QString message;
1939     QString exceptionBoxMessage;
1940     int forcedThreadId = -1;
1941     const unsigned stopFlags = examineStopReason(stopReason, &message, &exceptionBoxMessage,
1942                                                  conditionalBreakPointTriggered);
1943     // Do the non-blocking log reporting
1944     if (stopFlags & StopReportLog)
1945         showMessage(message, LogMisc);
1946     if (stopFlags & StopReportStatusMessage)
1947         showStatusMessage(message);
1948     if (stopFlags & StopReportParseError)
1949         showMessage(message, LogError);
1950     // Ignore things like WOW64, report tracepoints.
1951     if (stopFlags & StopIgnoreContinue) {
1952         postCommand("g", 0);
1953         return;
1954     }
1955     // Notify about state and send off command sequence to get stack, etc.
1956     if (stopFlags & StopNotifyStop) {
1957         if (state() == InferiorStopRequested) {
1958             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorStopOk")
1959             notifyInferiorStopOk();
1960         } else {
1961             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSpontaneousStop")
1962             notifyInferiorSpontaneousStop();
1963         }
1964         // Prevent further commands from being sent if shutdown is in progress
1965         if (stopFlags & StopShutdownInProgress) {
1966             showMessage(QString::fromLatin1("Shutdown request detected..."));
1967             return;
1968         }
1969         const bool sourceStepInto = m_sourceStepInto;
1970         m_sourceStepInto = false;
1971         // Start sequence to get all relevant data.
1972         if (stopFlags & StopInArtificialThread) {
1973             showMessage(tr("Switching to main thread..."), LogMisc);
1974             postCommand("~0 s", 0);
1975             forcedThreadId = 0;
1976             // Re-fetch stack again.
1977             postCommandSequence(CommandListStack);
1978         } else {
1979             const GdbMi stack = stopReason.findChild("stack");
1980             if (stack.isValid()) {
1981                 if (parseStackTrace(stack, sourceStepInto) & ParseStackStepInto) {
1982                     executeStep(); // Hit on a frame while step into, see parseStackTrace().
1983                     return;
1984                 }
1985             } else {
1986                 showMessage(QString::fromAscii(stopReason.findChild("stackerror").data()), LogError);
1987             }
1988         }
1989         const GdbMi threads = stopReason.findChild("threads");
1990         if (threads.isValid()) {
1991             parseThreads(threads, forcedThreadId);
1992         } else {
1993             showMessage(QString::fromAscii(stopReason.findChild("threaderror").data()), LogError);
1994         }
1995         // Fire off remaining commands asynchronously
1996         if (!m_pendingBreakpointMap.isEmpty())
1997             postCommandSequence(CommandListBreakPoints);
1998         if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_REGISTER)))
1999             postCommandSequence(CommandListRegisters);
2000         if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_MODULES)))
2001             postCommandSequence(CommandListModules);
2002     }
2003     // After the sequence has been sent off and CDB is pondering the commands,
2004     // pop up a message box for exceptions.
2005     if (stopFlags & StopShowExceptionMessageBox)
2006         showStoppedByExceptionMessageBox(exceptionBoxMessage);
2007 }
2008
2009 void CdbEngine::handleSessionAccessible(unsigned long cdbExState)
2010 {
2011     const DebuggerState s = state();
2012     if (!m_hasDebuggee || s == InferiorRunOk) // suppress reports
2013         return;
2014
2015     if (debug)
2016         qDebug("CdbEngine::handleSessionAccessible %dms in state '%s'/'%s', special mode %d",
2017                elapsedLogTime(), cdbStatusName(cdbExState), stateName(state()), m_specialStopMode);
2018
2019     switch(s) {
2020     case EngineShutdownRequested:
2021         shutdownEngine();
2022         break;
2023     case InferiorShutdownRequested:
2024         shutdownInferior();
2025         break;
2026     default:
2027         break;
2028     }
2029 }
2030
2031 void CdbEngine::handleSessionInaccessible(unsigned long cdbExState)
2032 {
2033     const DebuggerState s = state();
2034
2035     // suppress reports
2036     if (!m_hasDebuggee || (s == InferiorRunOk && cdbExState != CDB_STATUS_NO_DEBUGGEE))
2037         return;
2038
2039     if (debug)
2040         qDebug("CdbEngine::handleSessionInaccessible %dms in state '%s', '%s', special mode %d",
2041                elapsedLogTime(), cdbStatusName(cdbExState), stateName(state()), m_specialStopMode);
2042
2043     switch (state()) {
2044     case EngineSetupRequested:
2045         break;
2046     case EngineRunRequested:
2047         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineRunAndInferiorRunOk")
2048         notifyEngineRunAndInferiorRunOk();
2049         break;
2050     case InferiorRunOk:
2051     case InferiorStopOk:
2052         // Inaccessible without debuggee (exit breakpoint)
2053         // We go for spontaneous engine shutdown instead.
2054         if (cdbExState == CDB_STATUS_NO_DEBUGGEE) {
2055             if (debug)
2056                 qDebug("Lost debuggeee");
2057             m_hasDebuggee = false;
2058         }
2059         break;
2060     case InferiorRunRequested:
2061         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk")
2062         notifyInferiorRunOk();
2063         resetLocation();
2064         break;
2065     case EngineShutdownRequested:
2066         break;
2067     default:
2068         break;
2069     }
2070 }
2071
2072 void CdbEngine::handleExtensionMessage(char t, int token, const QByteArray &what, const QByteArray &message)
2073 {
2074     if (debug > 1) {
2075         QDebug nospace = qDebug().nospace();
2076         nospace << "handleExtensionMessage " << t << ' ' << token << ' ' << what
2077                 << ' ' << stateName(state());
2078         if (t == 'N' || debug > 1) {
2079             nospace << ' ' << message;
2080         } else {
2081             nospace << ' ' << message.size() << " bytes";
2082         }
2083     }
2084
2085     // Is there a reply expected, some command queued?
2086     if (t == 'R' || t == 'N') {
2087         if (token == -1) { // Default token, user typed in extension command
2088             showMessage(QString::fromLatin1(message), LogMisc);
2089             return;
2090         }
2091         const int index = indexOfCommand(m_extensionCommandQueue, token);
2092         if (index != -1) {
2093             // Did the command finish? Take off queue and complete, invoke CB
2094             const CdbExtensionCommandPtr command = m_extensionCommandQueue.takeAt(index);
2095             if (t == 'R') {
2096                 command->success = true;
2097                 command->reply = message;
2098             } else {
2099                 command->success = false;
2100                 command->errorMessage = message;
2101             }
2102             if (debug)
2103                 qDebug("### Completed extension command '%s', token=%d, pending=%d",
2104                        command->command.constData(), command->token, m_extensionCommandQueue.size());
2105             if (command->handler)
2106                 (this->*(command->handler))(command);
2107             return;
2108         }
2109     }
2110
2111     if (what == "debuggee_output") {
2112         showMessage(StringFromBase64EncodedUtf16(message), AppOutput);
2113         return;
2114     }
2115
2116     if (what == "event") {
2117         showStatusMessage(QString::fromAscii(message),  5000);
2118         return;
2119     }
2120
2121     if (what == "session_accessible") {
2122         if (!m_accessible) {
2123             m_accessible = true;
2124             handleSessionAccessible(message.toULong());
2125         }
2126         return;
2127     }
2128
2129     if (what == "session_inaccessible") {
2130         if (m_accessible) {
2131             m_accessible = false;
2132             handleSessionInaccessible(message.toULong());
2133         }
2134         return;
2135     }
2136
2137     if (what == "session_idle") {
2138         handleSessionIdle(message);
2139         return;
2140     }
2141
2142     if (what == "exception") {
2143         WinException exception;
2144         GdbMi gdbmi;
2145         gdbmi.fromString(message);
2146         exception.fromGdbMI(gdbmi);
2147         const QString message = exception.toString(true);
2148         showStatusMessage(message);
2149 #ifdef Q_OS_WIN // Report C++ exception in application output as well.
2150         if (exception.exceptionCode == winExceptionCppException)
2151             showMessage(message + QLatin1Char('\n'), AppOutput);
2152 #endif
2153         return;
2154     }
2155
2156     return;
2157 }
2158
2159 // Check for a CDB prompt '0:000> ' ('process:thread> ')..no regexps for QByteArray...
2160 enum { CdbPromptLength = 7 };
2161
2162 static inline bool isCdbPrompt(const QByteArray &c)
2163 {
2164     return c.size() >= CdbPromptLength && c.at(6) == ' ' && c.at(5) == '>' && c.at(1) == ':'
2165             && std::isdigit(c.at(0)) &&  std::isdigit(c.at(2)) && std::isdigit(c.at(3))
2166             && std::isdigit(c.at(4));
2167 }
2168
2169 // Check for '<token>32>' or '<token>32<'
2170 static inline bool checkCommandToken(const QByteArray &tokenPrefix, const QByteArray &c,
2171                                   int *token, bool *isStart)
2172 {
2173     *token = 0;
2174     *isStart = false;
2175     const int tokenPrefixSize = tokenPrefix.size();
2176     const int size = c.size();
2177     if (size < tokenPrefixSize + 2 || !std::isdigit(c.at(tokenPrefixSize)))
2178         return false;
2179     switch (c.at(size - 1)) {
2180     case '>':
2181         *isStart = false;
2182         break;
2183     case '<':
2184         *isStart = true;
2185         break;
2186     default:
2187         return false;
2188     }
2189     if (!c.startsWith(tokenPrefix))
2190         return false;
2191     bool ok;
2192     *token = c.mid(tokenPrefixSize, size - tokenPrefixSize - 1).toInt(&ok);
2193     return ok;
2194 }
2195
2196 void CdbEngine::parseOutputLine(QByteArray line)
2197 {
2198     // The hooked output callback in the extension suppresses prompts,
2199     // it should happen only in initial and exit stages. Note however that
2200     // if the output is not hooked, sequences of prompts are possible which
2201     // can mix things up.
2202     while (isCdbPrompt(line))
2203         line.remove(0, CdbPromptLength);
2204     // An extension notification (potentially consisting of several chunks)
2205     if (line.startsWith(m_creatorExtPrefix)) {
2206         // "<qtcreatorcdbext>|type_char|token|remainingChunks|serviceName|message"
2207         const char type = line.at(m_creatorExtPrefix.size());
2208         // integer token
2209         const int tokenPos = m_creatorExtPrefix.size() + 2;
2210         const int tokenEndPos = line.indexOf('|', tokenPos);
2211         QTC_ASSERT(tokenEndPos != -1, return)
2212         const int token = line.mid(tokenPos, tokenEndPos - tokenPos).toInt();
2213         // remainingChunks
2214         const int remainingChunksPos = tokenEndPos + 1;
2215         const int remainingChunksEndPos = line.indexOf('|', remainingChunksPos);
2216         QTC_ASSERT(remainingChunksEndPos != -1, return)
2217         const int remainingChunks = line.mid(remainingChunksPos, remainingChunksEndPos - remainingChunksPos).toInt();
2218         // const char 'serviceName'
2219         const int whatPos = remainingChunksEndPos + 1;
2220         const int whatEndPos = line.indexOf('|', whatPos);
2221         QTC_ASSERT(whatEndPos != -1, return)
2222         const QByteArray what = line.mid(whatPos, whatEndPos - whatPos);
2223         // Build up buffer, call handler once last chunk was encountered
2224         m_extensionMessageBuffer += line.mid(whatEndPos + 1);
2225         if (remainingChunks == 0) {
2226             handleExtensionMessage(type, token, what, m_extensionMessageBuffer);
2227             m_extensionMessageBuffer.clear();
2228         }
2229         return;
2230     }
2231     // Check for command start/end tokens within which the builtin command
2232     // output is enclosed
2233     int token = 0;
2234     bool isStartToken = false;
2235     const bool isCommandToken = checkCommandToken(m_tokenPrefix, line, &token, &isStartToken);
2236     if (debug > 1)
2237         qDebug("Reading CDB stdout '%s',\n  isCommand=%d, token=%d, isStart=%d, current=%d",
2238                line.constData(), isCommandToken, token, isStartToken, m_currentBuiltinCommandIndex);
2239
2240     // If there is a current command, wait for end of output indicated by token,
2241     // command, trigger handler and finish, else append to its output.
2242     if (m_currentBuiltinCommandIndex != -1) {
2243         QTC_ASSERT(!isStartToken && m_currentBuiltinCommandIndex < m_builtinCommandQueue.size(), return; );
2244         const CdbBuiltinCommandPtr &currentCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex);
2245         if (isCommandToken) {
2246             // Did the command finish? Invoke callback and remove from queue.
2247             if (debug)
2248                 qDebug("### Completed builtin command '%s', token=%d, %d lines, pending=%d",
2249                        currentCommand->command.constData(), currentCommand->token,
2250                        currentCommand->reply.size(), m_builtinCommandQueue.size() - 1);
2251             QTC_ASSERT(token == currentCommand->token, return; );
2252             if (currentCommand->handler)
2253                 (this->*(currentCommand->handler))(currentCommand);
2254             m_builtinCommandQueue.removeAt(m_currentBuiltinCommandIndex);
2255             m_currentBuiltinCommandIndex = -1;
2256         } else {
2257             // Record output of current command
2258             currentCommand->reply.push_back(line);
2259         }
2260         return;
2261     } // m_currentCommandIndex
2262     if (isCommandToken) {
2263         // Beginning command token encountered, start to record output.
2264         const int index = indexOfCommand(m_builtinCommandQueue, token);
2265         QTC_ASSERT(isStartToken && index != -1, return; );
2266         m_currentBuiltinCommandIndex = index;
2267         const CdbBuiltinCommandPtr &currentCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex);
2268         if (debug)
2269             qDebug("### Gathering output for '%s' token %d", currentCommand->command.constData(), currentCommand->token);
2270         return;
2271     }
2272
2273     showMessage(QString::fromLocal8Bit(line), LogMisc);
2274 }
2275
2276 void CdbEngine::readyReadStandardOut()
2277 {
2278     if (m_ignoreCdbOutput)
2279         return;
2280     m_outputBuffer += m_process.readAllStandardOutput();
2281     // Split into lines and parse line by line.
2282     while (true) {
2283         const int endOfLinePos = m_outputBuffer.indexOf('\n');
2284         if (endOfLinePos == -1) {
2285             break;
2286         } else {
2287             // Check for '\r\n'
2288             QByteArray line = m_outputBuffer.left(endOfLinePos);
2289             if (!line.isEmpty() && line.at(line.size() - 1) == '\r')
2290                 line.truncate(line.size() - 1);
2291             parseOutputLine(line);
2292             m_outputBuffer.remove(0, endOfLinePos + 1);
2293         }
2294     }
2295 }
2296
2297 void CdbEngine::readyReadStandardError()
2298 {
2299     showMessage(QString::fromLocal8Bit(m_process.readAllStandardError()), LogError);
2300 }
2301
2302 void CdbEngine::processError()
2303 {
2304     showMessage(m_process.errorString(), LogError);
2305 }
2306
2307 #if 0
2308 // Join breakpoint ids for a multi-breakpoint id commands like 'bc', 'be', 'bd'
2309 static QByteArray multiBreakpointCommand(const char *cmdC, const Breakpoints &bps)
2310 {
2311     QByteArray cmd(cmdC);
2312     ByteArrayInputStream str(cmd);
2313     foreach(const BreakpointData *bp, bps)
2314         str << ' ' << bp->bpNumber;
2315     return cmd;
2316 }
2317 #endif
2318
2319 bool CdbEngine::stateAcceptsBreakpointChanges() const
2320 {
2321     switch (state()) {
2322     case InferiorRunOk:
2323     case InferiorStopOk:
2324     return true;
2325     default:
2326         break;
2327     }
2328     return false;
2329 }
2330
2331 bool CdbEngine::acceptsBreakpoint(BreakpointId id) const
2332 {
2333     const BreakpointParameters &data = breakHandler()->breakpointData(id);
2334     if (!DebuggerEngine::isCppBreakpoint(data))
2335         return false;
2336     switch (data.type) {
2337     case UnknownType:
2338     case BreakpointAtFork:
2339     //case BreakpointAtVFork:
2340     case BreakpointAtSysCall:
2341         return false;
2342     case Watchpoint:
2343     case BreakpointByFileAndLine:
2344     case BreakpointByFunction:
2345     case BreakpointByAddress:
2346     case BreakpointAtThrow:
2347     case BreakpointAtCatch:
2348     case BreakpointAtMain:
2349     case BreakpointAtExec:
2350         break;
2351     }
2352     return true;
2353 }
2354
2355 void CdbEngine::attemptBreakpointSynchronization()
2356 {
2357     if (debug)
2358         qDebug("attemptBreakpointSynchronization in %s", stateName(state()));
2359     // Check if there is anything to be done at all.
2360     BreakHandler *handler = breakHandler();
2361     // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
2362     foreach (BreakpointId id, handler->unclaimedBreakpointIds())
2363         if (acceptsBreakpoint(id))
2364             handler->setEngine(id, this);
2365
2366     // Quick check: is there a need to change something? - Populate module cache
2367     bool changed = false;
2368     const BreakpointIds ids = handler->engineBreakpointIds(this);
2369     foreach (BreakpointId id, ids) {
2370         switch (handler->state(id)) {
2371         case BreakpointInsertRequested:
2372         case BreakpointRemoveRequested:
2373         case BreakpointChangeRequested:
2374             changed = true;
2375             break;
2376         case BreakpointInserted: {
2377             // Collect the new modules matching the files.
2378             // In the future, that information should be obtained from the build system.
2379             const BreakpointParameters &data = handler->breakpointData(id);
2380             if (data.type == BreakpointByFileAndLine && !data.module.isEmpty())
2381                 m_fileNameModuleHash.insert(data.fileName, data.module);
2382         }
2383         break;
2384         default:
2385             break;
2386         }
2387     }
2388
2389     if (debugBreakpoints)
2390         qDebug("attemptBreakpointSynchronizationI %dms accessible=%d, %s %d breakpoints, changed=%d",
2391                elapsedLogTime(), m_accessible, stateName(state()), ids.size(), changed);
2392     if (!changed)
2393         return;
2394
2395     if (!m_accessible) {
2396         // No nested calls.
2397         if (m_specialStopMode != SpecialStopSynchronizeBreakpoints)
2398             doInterruptInferior(SpecialStopSynchronizeBreakpoints);
2399         return;
2400     }
2401     // Add/Change breakpoints and store pending ones in map, since
2402     // Breakhandler::setResponse() on pending breakpoints clears the pending flag.
2403     // handleBreakPoints will the complete that information and set it on the break handler.
2404     bool addedChanged = false;
2405     foreach (BreakpointId id, ids) {
2406         BreakpointParameters parameters = handler->breakpointData(id);
2407         BreakpointResponse response;
2408         response.fromParameters(parameters);
2409         // If we encountered that file and have a module for it: Add it.
2410         if (parameters.type == BreakpointByFileAndLine && parameters.module.isEmpty()) {
2411             const QHash<QString, QString>::const_iterator it = m_fileNameModuleHash.constFind(parameters.fileName);
2412             if (it != m_fileNameModuleHash.constEnd())
2413                 parameters.module = it.value();
2414         }
2415         switch (handler->state(id)) {
2416         case BreakpointInsertRequested:
2417             postCommand(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), 0);
2418             if (!parameters.enabled)
2419                 postCommand("bd " + QByteArray::number(id), 0);
2420             handler->notifyBreakpointInsertProceeding(id);
2421             handler->notifyBreakpointInsertOk(id);
2422             m_pendingBreakpointMap.insert(id, response);
2423             addedChanged = true;
2424             // Ensure enabled/disabled is correct in handler and line number is there.
2425             handler->setResponse(id, response);
2426             if (debugBreakpoints)
2427                 qDebug("Adding %llu %s\n", id, qPrintable(response.toString()));
2428             break;
2429         case BreakpointChangeRequested:
2430             handler->notifyBreakpointChangeProceeding(id);
2431             if (debugBreakpoints)
2432                 qDebug("Changing %llu:\n    %s\nTo %s\n", id, qPrintable(handler->response(id).toString()),
2433                        qPrintable(parameters.toString()));
2434             if (parameters.enabled != handler->response(id).enabled) {
2435                 // Change enabled/disabled breakpoints without triggering update.
2436                 postCommand((parameters.enabled ? "be " : "bd ") + QByteArray::number(id), 0);
2437                 response.pending = false;
2438                 response.enabled = parameters.enabled;
2439                 handler->setResponse(id, response);
2440             } else {
2441                 // Delete and re-add, triggering update
2442                 addedChanged = true;
2443                 postCommand("bc " + QByteArray::number(id), 0);
2444                 postCommand(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), 0);
2445                 m_pendingBreakpointMap.insert(id, response);
2446             }
2447             handler->notifyBreakpointChangeOk(id);
2448             break;
2449         case BreakpointRemoveRequested:
2450             postCommand("bc " + QByteArray::number(id), 0);
2451             handler->notifyBreakpointRemoveProceeding(id);
2452             handler->notifyBreakpointRemoveOk(id);
2453             m_pendingBreakpointMap.remove(id);
2454             break;
2455         default:
2456             break;
2457         }
2458     }
2459     // List breakpoints and send responses
2460     if (addedChanged)
2461         postCommandSequence(CommandListBreakPoints);
2462 }
2463
2464 // Pass a file name through source mapping and normalize upper/lower case (for the editor
2465 // manager to correctly process it) and convert to clean path.
2466 CdbEngine::NormalizedSourceFileName CdbEngine::sourceMapNormalizeFileNameFromDebugger(const QString &f)
2467 {
2468     // 1) Check cache.
2469     QMap<QString, NormalizedSourceFileName>::const_iterator it = m_normalizedFileCache.constFind(f);
2470     if (it != m_normalizedFileCache.constEnd())
2471         return it.value();
2472     if (debugSourceMapping)
2473         qDebug(">sourceMapNormalizeFileNameFromDebugger %s", qPrintable(f));
2474     // Do we have source path mappings? ->Apply.
2475     const QString fileName = cdbSourcePathMapping(QDir::toNativeSeparators(f), m_sourcePathMappings,
2476                                                   DebuggerToSource);
2477     // Up/lower case normalization according to Windows.
2478 #ifdef Q_OS_WIN
2479     QString normalized = winNormalizeFileName(fileName);
2480 #else
2481     QString normalized = fileName;
2482 #endif
2483     if (debugSourceMapping)
2484         qDebug(" sourceMapNormalizeFileNameFromDebugger %s->%s", qPrintable(fileName), qPrintable(normalized));
2485     // Check if it really exists, that is normalize worked and QFileInfo confirms it.
2486     const bool exists = !normalized.isEmpty() && QFileInfo(normalized).isFile();
2487     NormalizedSourceFileName result(QDir::cleanPath(normalized.isEmpty() ? fileName : normalized), exists);
2488     if (!exists) {
2489         // At least upper case drive letter if failed.
2490         if (result.fileName.size() > 2 && result.fileName.at(1) == QLatin1Char(':'))
2491             result.fileName[0] = result.fileName.at(0).toUpper();
2492     }
2493     m_normalizedFileCache.insert(f, result);
2494     if (debugSourceMapping)
2495         qDebug("<sourceMapNormalizeFileNameFromDebugger %s %d", qPrintable(result.fileName), result.exists);
2496     return result;
2497 }
2498
2499 // Parse frame from GDBMI. Duplicate of the gdb code, but that
2500 // has more processing.
2501 static StackFrames parseFrames(const GdbMi &gdbmi)
2502 {
2503     StackFrames rc;
2504     const int count = gdbmi.childCount();
2505     rc.reserve(count);
2506     for (int i = 0; i  < count; i++) {
2507         const GdbMi &frameMi = gdbmi.childAt(i);
2508         StackFrame frame;
2509         frame.level = i;
2510         const GdbMi fullName = frameMi.findChild("fullname");
2511         if (fullName.isValid()) {
2512             frame.file = QFile::decodeName(fullName.data());
2513             frame.line = frameMi.findChild("line").data().toInt();
2514             frame.usable = false; // To be decided after source path mapping.
2515         }
2516         frame.function = QLatin1String(frameMi.findChild("func").data());
2517         frame.from = QLatin1String(frameMi.findChild("from").data());
2518         frame.address = frameMi.findChild("addr").data().toULongLong(0, 16);
2519         rc.push_back(frame);
2520     }
2521     return rc;
2522 }
2523
2524 unsigned CdbEngine::parseStackTrace(const GdbMi &data, bool sourceStepInto)
2525 {
2526     // Parse frames, find current. Special handling for step into:
2527     // When stepping into on an actual function (source mode) by executing 't', an assembler
2528     // frame pointing at the jmp instruction is hit (noticeable by top function being
2529     // 'ILT+'). If that is the case, execute another 't' to step into the actual function.    .
2530     // Note that executing 't 2' does not work since it steps 2 instructions on a non-call code line.
2531     int current = -1;
2532     StackFrames frames = parseFrames(data);
2533     const int count = frames.size();
2534     for (int i = 0; i < count; i++) {
2535         const bool hasFile = !frames.at(i).file.isEmpty();
2536         // jmp-frame hit by step into, do another 't' and abort sequence.
2537         if (!hasFile && i == 0 && sourceStepInto && frames.at(i).function.contains(QLatin1String("ILT+"))) {
2538             showMessage(QString::fromAscii("Step into: Call instruction hit, performing additional step..."), LogMisc);
2539             return ParseStackStepInto;
2540         }
2541         if (hasFile) {
2542             const NormalizedSourceFileName fileName = sourceMapNormalizeFileNameFromDebugger(frames.at(i).file);
2543             frames[i].file = fileName.fileName;
2544             frames[i].usable = fileName.exists;
2545             if (current == -1 && frames[i].usable)
2546                 current = i;
2547         }
2548     }
2549     if (count && current == -1) // No usable frame, use assembly.
2550         current = 0;
2551     // Set
2552     stackHandler()->setFrames(frames);
2553     activateFrame(current);
2554     return 0;
2555 }
2556
2557 void CdbEngine::handleStackTrace(const CdbExtensionCommandPtr &command)
2558 {
2559     if (command->success) {
2560         GdbMi data;
2561         data.fromString(command->reply);
2562         parseStackTrace(data, false);
2563         postCommandSequence(command->commandSequence);
2564     } else {
2565         showMessage(command->errorMessage, LogError);
2566     }
2567 }
2568
2569 void CdbEngine::handleExpression(const CdbExtensionCommandPtr &command)
2570 {
2571     int value = 0;
2572     if (command->success) {
2573         value = command->reply.toInt();
2574     } else {
2575         showMessage(command->errorMessage, LogError);
2576     }
2577     // Is this a conditional breakpoint?
2578     if (command->cookie.isValid() && qVariantCanConvert<ConditionalBreakPointCookie>(command->cookie)) {
2579         const ConditionalBreakPointCookie cookie = qvariant_cast<ConditionalBreakPointCookie>(command->cookie);
2580         const QString message = value ?
2581             tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping.").
2582             arg(value).arg(cookie.id) :
2583             tr("Value 0 obtained from evaluating the condition of breakpoint %1, continuing.").
2584             arg(cookie.id);
2585         showMessage(message, LogMisc);
2586         // Stop if evaluation is true, else continue
2587         if (value) {
2588             processStop(cookie.stopReason, true);
2589         } else {
2590             postCommand("g", 0);
2591         }
2592     }
2593 }
2594
2595 void CdbEngine::evaluateExpression(QByteArray exp, const QVariant &cookie)
2596 {
2597     if (exp.contains(' ') && !exp.startsWith('"')) {
2598         exp.prepend('"');
2599         exp.append('"');
2600     }
2601     postExtensionCommand("expression", exp, 0, &CdbEngine::handleExpression, 0, cookie);
2602 }
2603
2604 void CdbEngine::dummyHandler(const CdbBuiltinCommandPtr &command)
2605 {
2606     postCommandSequence(command->commandSequence);
2607 }
2608
2609 // Post a sequence of standard commands: Trigger next once one completes successfully
2610 void CdbEngine::postCommandSequence(unsigned mask)
2611 {
2612     if (debug)
2613         qDebug("postCommandSequence 0x%x\n", mask);
2614
2615     if (!mask)
2616         return;
2617     if (mask & CommandListThreads) {
2618         postExtensionCommand("threads", QByteArray(), 0, &CdbEngine::handleThreads, mask & ~CommandListThreads);
2619         return;
2620     }
2621     if (mask & CommandListStack) {
2622         postExtensionCommand("stack", QByteArray(), 0, &CdbEngine::handleStackTrace, mask & ~CommandListStack);
2623         return;
2624     }
2625     if (mask & CommandListRegisters) {
2626         QTC_ASSERT(threadsHandler()->currentThread() >= 0,  return; )
2627         postExtensionCommand("registers", QByteArray(), 0, &CdbEngine::handleRegisters, mask & ~CommandListRegisters);
2628         return;
2629     }
2630     if (mask & CommandListModules) {
2631         postExtensionCommand("modules", QByteArray(), 0, &CdbEngine::handleModules, mask & ~CommandListModules);
2632         return;
2633     }
2634     if (mask & CommandListBreakPoints) {
2635         postExtensionCommand("breakpoints", QByteArray("-v"), 0,
2636                              &CdbEngine::handleBreakPoints, mask & ~CommandListBreakPoints);
2637         return;
2638     }
2639 }
2640
2641 void CdbEngine::handleWidgetAt(const CdbExtensionCommandPtr &reply)
2642 {
2643     bool success = false;
2644     QString message;
2645     do {
2646         if (!reply->success) {
2647             message = QString::fromAscii(reply->errorMessage);
2648             break;
2649         }
2650         // Should be "namespace::QWidget:0x555"
2651         QString watchExp = QString::fromAscii(reply->reply);
2652         const int sepPos = watchExp.lastIndexOf(QLatin1Char(':'));
2653         if (sepPos == -1) {
2654             message = QString::fromAscii("Invalid output: %1").arg(watchExp);
2655             break;
2656         }
2657         // 0x000 -> nothing found
2658         if (!watchExp.mid(sepPos + 1).toULongLong(0, 0)) {
2659             message = QString::fromAscii("No widget could be found at %1, %2.").arg(m_watchPointX).arg(m_watchPointY);
2660             break;
2661         }
2662         // Turn into watch expression: "*(namespace::QWidget*)0x555"
2663         watchExp.replace(sepPos, 1, QLatin1String("*)"));
2664         watchExp.insert(0, QLatin1String("*("));
2665         watchHandler()->watchExpression(watchExp);
2666         success = true;
2667     } while (false);
2668     if (!success)
2669         showMessage(message, LogWarning);
2670     m_watchPointX = m_watchPointY = 0;
2671 }
2672
2673 static inline void formatCdbBreakPointResponse(BreakpointId id, const BreakpointResponse &r,
2674                                                   QTextStream &str)
2675 {
2676     str << "Obtained breakpoint " << id << " (#" << r.number << ')';
2677     if (r.pending) {
2678         str << ", pending";
2679     } else {
2680         str.setIntegerBase(16);
2681         str << ", at 0x" << r.address;
2682         str.setIntegerBase(10);
2683     }
2684     if (!r.enabled)
2685         str << ", disabled";
2686     if (!r.module.isEmpty())
2687         str << ", module: '" << r.module << '\'';
2688     str << '\n';
2689 }
2690
2691 void CdbEngine::handleBreakPoints(const CdbExtensionCommandPtr &reply)
2692 {
2693     if (debugBreakpoints)
2694         qDebug("CdbEngine::handleBreakPoints: success=%d: %s", reply->success, reply->reply.constData());
2695     if (!reply->success) {
2696         showMessage(QString::fromAscii(reply->errorMessage), LogError);
2697         return;
2698     }
2699     GdbMi value;
2700     value.fromString(reply->reply);
2701     if (value.type() != GdbMi::List) {
2702         showMessage(QString::fromAscii("Unabled to parse breakpoints reply"), LogError);
2703         return;
2704     }
2705     handleBreakPoints(value);
2706 }
2707
2708 void CdbEngine::handleBreakPoints(const GdbMi &value)
2709 {
2710     // Report all obtained parameters back. Note that not all parameters are reported
2711     // back, so, match by id and complete
2712     if (debugBreakpoints)
2713         qDebug("\nCdbEngine::handleBreakPoints with %d", value.childCount());
2714     QString message;
2715     QTextStream str(&message);
2716     BreakHandler *handler = breakHandler();
2717     foreach (const GdbMi &breakPointG, value.children()) {
2718         BreakpointResponse reportedResponse;
2719         const BreakpointId id = parseBreakPoint(breakPointG, &reportedResponse);
2720         if (debugBreakpoints)
2721             qDebug("  Parsed %llu: pending=%d %s\n", id, reportedResponse.pending,
2722                    qPrintable(reportedResponse.toString()));
2723
2724         if (!reportedResponse.pending) {
2725             const PendingBreakPointMap::iterator it = m_pendingBreakpointMap.find(id);
2726             if (it != m_pendingBreakpointMap.end()) {
2727                 // Complete the response and set on handler.
2728                 BreakpointResponse &currentResponse = it.value();
2729                 currentResponse.number = reportedResponse.number;
2730                 currentResponse.address = reportedResponse.address;
2731                 currentResponse.module = reportedResponse.module;
2732                 currentResponse.pending = reportedResponse.pending;
2733                 currentResponse.enabled = reportedResponse.enabled;
2734                 formatCdbBreakPointResponse(id, currentResponse, str);
2735                 if (debugBreakpoints)
2736                     qDebug("  Setting for %llu: %s\n", id, qPrintable(currentResponse.toString()));
2737                 handler->setResponse(id, currentResponse);
2738                 m_pendingBreakpointMap.erase(it);
2739             }
2740         } // not pending reported
2741     } // foreach
2742     if (m_pendingBreakpointMap.empty()) {
2743         str << QLatin1String("All breakpoints have been resolved.\n");
2744     } else {
2745         str << QString::fromLatin1("%1 breakpoint(s) pending...\n").arg(m_pendingBreakpointMap.size());
2746     }
2747     showMessage(message, LogMisc);
2748 }
2749
2750 void CdbEngine::watchPoint(const QPoint &p)
2751 {
2752     m_watchPointX = p.x();
2753     m_watchPointY = p.y();
2754     switch (state()) {
2755     case InferiorStopOk:
2756         postWidgetAtCommand();
2757         break;
2758     case InferiorRunOk:
2759         // "Select Widget to Watch" from a running application is currently not
2760         // supported. It could be implemented via SpecialStopGetWidgetAt-mode,
2761         // but requires some work as not to confuse the engine by state-change notifications
2762         // emitted by the debuggee function call.
2763         showMessage(tr("\"Select Widget to Watch\": Please stop the application first."), LogWarning);
2764         break;
2765     default:
2766         showMessage(tr("\"Select Widget to Watch\": Not supported in state '%1'.").
2767                     arg(QString::fromAscii(stateName(state()))), LogWarning);
2768         break;
2769     }
2770 }
2771
2772 void CdbEngine::postWidgetAtCommand()
2773 {
2774     QByteArray arguments = QByteArray::number(m_watchPointX);
2775     arguments.append(' ');
2776     arguments.append(QByteArray::number(m_watchPointY));
2777     postExtensionCommand("widgetat", arguments, 0, &CdbEngine::handleWidgetAt, 0);
2778 }
2779
2780 void CdbEngine::handleCustomSpecialStop(const QVariant &v)
2781 {
2782     if (qVariantCanConvert<MemoryChangeCookie>(v)) {
2783         const MemoryChangeCookie changeData = qVariantValue<MemoryChangeCookie>(v);
2784         postCommand(cdbWriteMemoryCommand(changeData.address, changeData.data), 0);
2785         return;
2786     }
2787 }
2788
2789 } // namespace Internal
2790 } // namespace Debugger