OSDN Git Service

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