OSDN Git Service

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