OSDN Git Service

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