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 (!m_accessible) {
1516         qWarning("Internal error: Attempt to read memory from inaccessible session: %s", Q_FUNC_INFO);
1517         return;
1518     }
1519     if (debug)
1520         qDebug("CdbEngine::fetchMemory %llu bytes from 0x%llx", length, addr);
1521
1522     QByteArray args;
1523     ByteArrayInputStream str(args);
1524     str << addr << ' ' << length;
1525     const QVariant cookie = qVariantFromValue<MemoryViewCookie>(MemoryViewCookie(agent, editor, addr, length));
1526     postExtensionCommand("memory", args, 0, &CdbEngine::handleMemory, 0, cookie);
1527 }
1528
1529 void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data)
1530 {
1531     QTC_ASSERT(!data.isEmpty(), return; )
1532     if (!m_accessible) {
1533         const MemoryChangeCookie cookie(addr, data);
1534         doInterruptInferiorCustomSpecialStop(qVariantFromValue(cookie));
1535     } else {
1536         postCommand(cdbWriteMemoryCommand(addr, data), 0);
1537     }
1538 }
1539
1540 void CdbEngine::handleMemory(const CdbExtensionCommandPtr &command)
1541 {
1542     QTC_ASSERT(qVariantCanConvert<MemoryViewCookie>(command->cookie), return;)
1543     const MemoryViewCookie memViewCookie = qvariant_cast<MemoryViewCookie>(command->cookie);
1544     if (command->success) {
1545         const QByteArray data = QByteArray::fromBase64(command->reply);
1546         if (unsigned(data.size()) == memViewCookie.length)
1547             memViewCookie.agent->addLazyData(memViewCookie.editorToken,
1548                                              memViewCookie.address, data);
1549     } else {
1550         showMessage(QString::fromLocal8Bit(command->errorMessage), LogError);
1551     }
1552 }
1553
1554 void CdbEngine::reloadModules()
1555 {
1556     postCommandSequence(CommandListModules);
1557 }
1558
1559 void CdbEngine::loadSymbols(const QString & /* moduleName */)
1560 {
1561 }
1562
1563 void CdbEngine::loadAllSymbols()
1564 {
1565 }
1566
1567 void CdbEngine::requestModuleSymbols(const QString &moduleName)
1568 {
1569     Q_UNUSED(moduleName)
1570 }
1571
1572 void CdbEngine::reloadRegisters()
1573 {
1574     postCommandSequence(CommandListRegisters);
1575 }
1576
1577 void CdbEngine::reloadSourceFiles()
1578 {
1579 }
1580
1581 void CdbEngine::reloadFullStack()
1582 {
1583     if (debug)
1584         qDebug("%s", Q_FUNC_INFO);
1585     postCommandSequence(CommandListStack);
1586 }
1587
1588 void CdbEngine::handlePid(const CdbExtensionCommandPtr &reply)
1589 {
1590     if (reply->success) {
1591         m_inferiorPid = reply->reply.toUInt();
1592         showMessage(QString::fromLatin1("Inferior pid: %1.").arg(m_inferiorPid), LogMisc);
1593         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupOk")
1594         notifyInferiorSetupOk();
1595     }  else {
1596         showMessage(QString::fromLatin1("Failed to determine inferior pid: %1").
1597                     arg(QLatin1String(reply->errorMessage)), LogError);
1598         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupFailed")
1599         notifyInferiorSetupFailed();
1600     }
1601 }
1602
1603 // Parse CDB gdbmi register syntax
1604 static inline Register parseRegister(const GdbMi &gdbmiReg)
1605 {
1606     Register reg;
1607     reg.name = gdbmiReg.findChild("name").data();
1608     const GdbMi description = gdbmiReg.findChild("description");
1609     if (description.type() != GdbMi::Invalid) {
1610         reg.name += " (";
1611         reg.name += description.data();
1612         reg.name += ')';
1613     }
1614     reg.value = QString::fromAscii(gdbmiReg.findChild("value").data());
1615     return reg;
1616 }
1617
1618 void CdbEngine::handleModules(const CdbExtensionCommandPtr &reply)
1619 {
1620     if (reply->success) {
1621         GdbMi value;
1622         value.fromString(reply->reply);
1623         if (value.type() == GdbMi::List) {
1624             Modules modules;
1625             modules.reserve(value.childCount());
1626             foreach (const GdbMi &gdbmiModule, value.children()) {
1627                 Module module;
1628                 module.moduleName = QString::fromAscii(gdbmiModule.findChild("name").data());
1629                 module.modulePath = QString::fromAscii(gdbmiModule.findChild("image").data());
1630                 module.startAddress = gdbmiModule.findChild("start").data().toULongLong(0, 0);
1631                 module.endAddress = gdbmiModule.findChild("end").data().toULongLong(0, 0);
1632                 if (gdbmiModule.findChild("deferred").type() == GdbMi::Invalid)
1633                     module.symbolsRead = Module::ReadOk;
1634                 modules.push_back(module);
1635             }
1636             modulesHandler()->setModules(modules);
1637         } else {
1638             showMessage(QString::fromLatin1("Parse error in modules response."), LogError);
1639             qWarning("Parse error in modules response:\n%s", reply->reply.constData());
1640         }
1641     }  else {
1642         showMessage(QString::fromLatin1("Failed to determine modules: %1").
1643                     arg(QLatin1String(reply->errorMessage)), LogError);
1644     }
1645     postCommandSequence(reply->commandSequence);
1646
1647 }
1648
1649 void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply)
1650 {
1651     if (reply->success) {
1652         GdbMi value;
1653         value.fromString(reply->reply);
1654         if (value.type() == GdbMi::List) {
1655             Registers registers;
1656             registers.reserve(value.childCount());
1657             foreach (const GdbMi &gdbmiReg, value.children())
1658                 registers.push_back(parseRegister(gdbmiReg));
1659             registerHandler()->setAndMarkRegisters(registers);
1660         } else {
1661             showMessage(QString::fromLatin1("Parse error in registers response."), LogError);
1662             qWarning("Parse error in registers response:\n%s", reply->reply.constData());
1663         }
1664     }  else {
1665         showMessage(QString::fromLatin1("Failed to determine registers: %1").
1666                     arg(QLatin1String(reply->errorMessage)), LogError);
1667     }
1668     postCommandSequence(reply->commandSequence);
1669 }
1670
1671 void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
1672 {
1673     if (reply->success) {
1674         QList<WatchData> watchData;
1675         GdbMi root;
1676         root.fromString(reply->reply);
1677         QTC_ASSERT(root.isList(), return ; )
1678         if (debugLocals) {
1679             qDebug() << root.toString(true, 4);
1680         }
1681         // Courtesy of GDB engine
1682         foreach (const GdbMi &child, root.children()) {
1683             WatchData dummy;
1684             dummy.iname = child.findChild("iname").data();
1685             dummy.name = QLatin1String(child.findChild("name").data());
1686             parseWatchData(watchHandler()->expandedINames(), dummy, child, &watchData);
1687         }
1688         watchHandler()->insertBulkData(watchData);
1689         watchHandler()->endCycle();
1690         if (debugLocals) {
1691             QDebug nsp = qDebug().nospace();
1692             nsp << "Obtained " << watchData.size() << " items:\n";
1693             foreach (const WatchData &wd, watchData)
1694                 nsp << wd.toString() <<'\n';
1695         }
1696         const bool forNewStackFrame = reply->cookie.toBool();
1697         if (forNewStackFrame)
1698             emit stackFrameCompleted();
1699     } else {
1700         showMessage(QString::fromLatin1(reply->errorMessage), LogWarning);
1701     }
1702 }
1703
1704 void CdbEngine::handleExpandLocals(const CdbExtensionCommandPtr &reply)
1705 {
1706     if (!reply->success)
1707         showMessage(QString::fromLatin1(reply->errorMessage), LogError);
1708 }
1709
1710 enum CdbExecutionStatus {
1711 CDB_STATUS_NO_CHANGE=0, CDB_STATUS_GO = 1, CDB_STATUS_GO_HANDLED = 2,
1712 CDB_STATUS_GO_NOT_HANDLED = 3, CDB_STATUS_STEP_OVER = 4,
1713 CDB_STATUS_STEP_INTO = 5, CDB_STATUS_BREAK = 6, CDB_STATUS_NO_DEBUGGEE = 7,
1714 CDB_STATUS_STEP_BRANCH = 8, CDB_STATUS_IGNORE_EVENT = 9,
1715 CDB_STATUS_RESTART_REQUESTED = 10, CDB_STATUS_REVERSE_GO = 11,
1716 CDB_STATUS_REVERSE_STEP_BRANCH = 12, CDB_STATUS_REVERSE_STEP_OVER = 13,
1717 CDB_STATUS_REVERSE_STEP_INTO = 14 };
1718
1719 static const char *cdbStatusName(unsigned long s)
1720 {
1721     switch (s) {
1722     case CDB_STATUS_NO_CHANGE:
1723         return "No change";
1724     case CDB_STATUS_GO:
1725         return "go";
1726     case CDB_STATUS_GO_HANDLED:
1727         return "go_handled";
1728     case CDB_STATUS_GO_NOT_HANDLED:
1729         return "go_not_handled";
1730     case CDB_STATUS_STEP_OVER:
1731         return "step_over";
1732     case CDB_STATUS_STEP_INTO:
1733         return "step_into";
1734     case CDB_STATUS_BREAK:
1735         return "break";
1736     case CDB_STATUS_NO_DEBUGGEE:
1737         return "no_debuggee";
1738     case CDB_STATUS_STEP_BRANCH:
1739         return "step_branch";
1740     case CDB_STATUS_IGNORE_EVENT:
1741         return "ignore_event";
1742     case CDB_STATUS_RESTART_REQUESTED:
1743         return "restart_requested";
1744     case CDB_STATUS_REVERSE_GO:
1745         return "reverse_go";
1746     case CDB_STATUS_REVERSE_STEP_BRANCH:
1747         return "reverse_step_branch";
1748     case CDB_STATUS_REVERSE_STEP_OVER:
1749         return "reverse_step_over";
1750     case CDB_STATUS_REVERSE_STEP_INTO:
1751         return "reverse_step_into";
1752     }
1753     return "unknown";
1754 }
1755
1756 /* Examine how to react to a stop. */
1757 enum StopActionFlags
1758 {
1759     // Report options
1760     StopReportLog = 0x1,
1761     StopReportStatusMessage = 0x2,
1762     StopReportParseError = 0x4,
1763     StopShowExceptionMessageBox = 0x8,
1764     // Notify stop or just continue
1765     StopNotifyStop = 0x10,
1766     StopIgnoreContinue = 0x20,
1767     // Hit on break in artificial stop thread (created by DebugBreak()).
1768     StopInArtificialThread = 0x40,
1769     StopShutdownInProgress = 0x80 // Shutdown in progress
1770 };
1771
1772 static inline QString msgTracePointTriggered(BreakpointId id, const int number,
1773                                              const QString &threadId)
1774 {
1775     return CdbEngine::tr("Trace point %1 (%2) in thread %3 triggered.")
1776             .arg(id).arg(number).arg(threadId);
1777 }
1778
1779 static inline QString msgCheckingConditionalBreakPoint(BreakpointId id, const int number,
1780                                                        const QByteArray &condition,
1781                                                        const QString &threadId)
1782 {
1783     return CdbEngine::tr("Conditional breakpoint %1 (%2) in thread %3 triggered, examining expression '%4'.")
1784             .arg(id).arg(number).arg(threadId, QString::fromAscii(condition));
1785 }
1786
1787 unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
1788                                       QString *message,
1789                                       QString *exceptionBoxMessage,
1790                                       bool conditionalBreakPointTriggered)
1791 {
1792     // Report stop reason (GDBMI)
1793     unsigned rc  = 0;
1794     if (targetState() == DebuggerFinished)
1795         rc |= StopShutdownInProgress;
1796     if (debug)
1797         qDebug("%s", stopReason.toString(true, 4).constData());
1798     const QByteArray reason = stopReason.findChild("reason").data();
1799     if (reason.isEmpty()) {
1800         *message = tr("Malformed stop response received.");
1801         rc |= StopReportParseError|StopNotifyStop;
1802         return rc;
1803     }
1804     // Additional stop messages occurring for debuggee function calls (widgetAt, etc). Just log.
1805     if (state() == InferiorStopOk) {
1806         *message = QString::fromLatin1("Ignored stop notification from function call (%1).").
1807                     arg(QString::fromAscii(reason));
1808         rc |= StopReportLog;
1809         return rc;
1810     }
1811     const int threadId = stopReason.findChild("threadId").data().toInt();
1812     if (reason == "breakpoint") {
1813         // Note: Internal breakpoints (run to line) are reported with id=0.
1814         // Step out creates temporary breakpoints with id 10000.
1815         BreakpointId id = 0;
1816         int number = 0;
1817         const GdbMi breakpointIdG = stopReason.findChild("breakpointId");
1818         if (breakpointIdG.isValid()) {
1819             id = breakpointIdG.data().toULongLong();
1820             if (id && breakHandler()->engineBreakpointIds(this).contains(id)) {
1821                 const BreakpointResponse parameters =  breakHandler()->response(id);
1822                 // Trace point? Just report.
1823                 number = parameters.number;
1824                 if (parameters.tracepoint) {
1825                     *message = msgTracePointTriggered(id, number, QString::number(threadId));
1826                     return StopReportLog|StopIgnoreContinue;
1827                 }
1828                 // Trigger evaluation of BP expression unless we are already in the response.
1829                 if (!conditionalBreakPointTriggered && !parameters.condition.isEmpty()) {
1830                     *message = msgCheckingConditionalBreakPoint(id, number, parameters.condition,
1831                                                                 QString::number(threadId));
1832                     ConditionalBreakPointCookie cookie(id);
1833                     cookie.stopReason = stopReason;
1834                     evaluateExpression(parameters.condition, qVariantFromValue(cookie));
1835                     return StopReportLog;
1836                 }
1837             } else {
1838                 id = 0;
1839             }
1840         }
1841         if (id && breakHandler()->type(id) == Watchpoint) {
1842             *message = msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId));
1843         } else {
1844             *message = msgBreakpointTriggered(id, number, QString::number(threadId));
1845         }
1846         rc |= StopReportStatusMessage|StopNotifyStop;
1847         return rc;
1848     }
1849     if (reason == "exception") {
1850         WinException exception;
1851         exception.fromGdbMI(stopReason);
1852         QString description = exception.toString();
1853 #ifdef Q_OS_WIN
1854         // It is possible to hit on a startup trap or WOW86 exception while stepping (if something
1855         // pulls DLLs. Avoid showing a 'stopped' Message box.
1856         if (exception.exceptionCode == winExceptionStartupCompleteTrap
1857             || exception.exceptionCode == winExceptionWX86Breakpoint)
1858             return StopNotifyStop;
1859         if (exception.exceptionCode == winExceptionCtrlPressed) {
1860             // Detect interruption by pressing Ctrl in a console and force a switch to thread 0.
1861             *message = msgInterrupted();
1862             rc |= StopReportStatusMessage|StopNotifyStop|StopInArtificialThread;
1863             return rc;
1864         }
1865         if (isDebuggerWinException(exception.exceptionCode)) {
1866             rc |= StopReportStatusMessage|StopNotifyStop;
1867             // Detect interruption by DebugBreak() and force a switch to thread 0.
1868             if (exception.function == "ntdll!DbgBreakPoint")
1869                 rc |= StopInArtificialThread;
1870             *message = msgInterrupted();
1871             return rc;
1872         }
1873 #endif
1874         *exceptionBoxMessage = msgStoppedByException(description, QString::number(threadId));
1875         *message = description;
1876         rc |= StopShowExceptionMessageBox|StopReportStatusMessage|StopNotifyStop;
1877         return rc;
1878     }
1879     *message = msgStopped(QLatin1String(reason));
1880     rc |= StopReportStatusMessage|StopNotifyStop;
1881     return rc;
1882 }
1883
1884 void CdbEngine::handleSessionIdle(const QByteArray &messageBA)
1885 {
1886     if (!m_hasDebuggee)
1887         return;
1888
1889     if (debug)
1890         qDebug("CdbEngine::handleSessionIdle %dms '%s' in state '%s', special mode %d",
1891                elapsedLogTime(), messageBA.constData(),
1892                stateName(state()), m_specialStopMode);
1893
1894     // Switch source level debugging
1895     syncOperateByInstruction(m_operateByInstructionPending);
1896
1897     // Engine-special stop reasons: Breakpoints and setup
1898     const SpecialStopMode specialStopMode =  m_specialStopMode;
1899
1900     m_specialStopMode = NoSpecialStop;
1901
1902     switch(specialStopMode) {
1903     case SpecialStopSynchronizeBreakpoints:
1904         if (debug)
1905             qDebug("attemptBreakpointSynchronization in special stop");
1906         attemptBreakpointSynchronization();
1907         doContinueInferior();
1908         return;
1909     case SpecialStopGetWidgetAt:
1910         postWidgetAtCommand();
1911         return;
1912     case CustomSpecialStop:
1913         foreach (const QVariant &data, m_customSpecialStopData)
1914             handleCustomSpecialStop(data);
1915         m_customSpecialStopData.clear();
1916         doContinueInferior();
1917         return;
1918     case NoSpecialStop:
1919         break;
1920     }
1921
1922     if (state() == EngineSetupRequested) { // Temporary stop at beginning
1923         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
1924         notifyEngineSetupOk();
1925         return;
1926     }
1927     GdbMi stopReason;
1928     stopReason.fromString(messageBA);
1929     processStop(stopReason, false);
1930 }
1931
1932 void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointTriggered)
1933 {
1934     // Further examine stop and report to user
1935     QString message;
1936     QString exceptionBoxMessage;
1937     int forcedThreadId = -1;
1938     const unsigned stopFlags = examineStopReason(stopReason, &message, &exceptionBoxMessage,
1939                                                  conditionalBreakPointTriggered);
1940     // Do the non-blocking log reporting
1941     if (stopFlags & StopReportLog)
1942         showMessage(message, LogMisc);
1943     if (stopFlags & StopReportStatusMessage)
1944         showStatusMessage(message);
1945     if (stopFlags & StopReportParseError)
1946         showMessage(message, LogError);
1947     // Ignore things like WOW64, report tracepoints.
1948     if (stopFlags & StopIgnoreContinue) {
1949         postCommand("g", 0);
1950         return;
1951     }
1952     // Notify about state and send off command sequence to get stack, etc.
1953     if (stopFlags & StopNotifyStop) {
1954         if (state() == InferiorStopRequested) {
1955             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorStopOk")
1956             notifyInferiorStopOk();
1957         } else {
1958             STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSpontaneousStop")
1959             notifyInferiorSpontaneousStop();
1960         }
1961         // Prevent further commands from being sent if shutdown is in progress
1962         if (stopFlags & StopShutdownInProgress) {
1963             showMessage(QString::fromLatin1("Shutdown request detected..."));
1964             return;
1965         }
1966         const bool sourceStepInto = m_sourceStepInto;
1967         m_sourceStepInto = false;
1968         // Start sequence to get all relevant data.
1969         if (stopFlags & StopInArtificialThread) {
1970             showMessage(tr("Switching to main thread..."), LogMisc);
1971             postCommand("~0 s", 0);
1972             forcedThreadId = 0;
1973             // Re-fetch stack again.
1974             postCommandSequence(CommandListStack);
1975         } else {
1976             const GdbMi stack = stopReason.findChild("stack");
1977             if (stack.isValid()) {
1978                 if (parseStackTrace(stack, sourceStepInto) & ParseStackStepInto) {
1979                     executeStep(); // Hit on a frame while step into, see parseStackTrace().
1980                     return;
1981                 }
1982             } else {
1983                 showMessage(QString::fromAscii(stopReason.findChild("stackerror").data()), LogError);
1984             }
1985         }
1986         const GdbMi threads = stopReason.findChild("threads");
1987         if (threads.isValid()) {
1988             parseThreads(threads, forcedThreadId);
1989         } else {
1990             showMessage(QString::fromAscii(stopReason.findChild("threaderror").data()), LogError);
1991         }
1992         // Fire off remaining commands asynchronously
1993         if (!m_pendingBreakpointMap.isEmpty())
1994             postCommandSequence(CommandListBreakPoints);
1995         if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_REGISTER)))
1996             postCommandSequence(CommandListRegisters);
1997         if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_MODULES)))
1998             postCommandSequence(CommandListModules);
1999     }
2000     // After the sequence has been sent off and CDB is pondering the commands,
2001     // pop up a message box for exceptions.
2002     if (stopFlags & StopShowExceptionMessageBox)
2003         showStoppedByExceptionMessageBox(exceptionBoxMessage);
2004 }
2005
2006 void CdbEngine::handleSessionAccessible(unsigned long cdbExState)
2007 {
2008     const DebuggerState s = state();
2009     if (!m_hasDebuggee || s == InferiorRunOk) // suppress reports
2010         return;
2011
2012     if (debug)
2013         qDebug("CdbEngine::handleSessionAccessible %dms in state '%s'/'%s', special mode %d",
2014                elapsedLogTime(), cdbStatusName(cdbExState), stateName(state()), m_specialStopMode);
2015
2016     switch(s) {
2017     case EngineShutdownRequested:
2018         shutdownEngine();
2019         break;
2020     case InferiorShutdownRequested:
2021         shutdownInferior();
2022         break;
2023     default:
2024         break;
2025     }
2026 }
2027
2028 void CdbEngine::handleSessionInaccessible(unsigned long cdbExState)
2029 {
2030     const DebuggerState s = state();
2031
2032     // suppress reports
2033     if (!m_hasDebuggee || (s == InferiorRunOk && cdbExState != CDB_STATUS_NO_DEBUGGEE))
2034         return;
2035
2036     if (debug)
2037         qDebug("CdbEngine::handleSessionInaccessible %dms in state '%s', '%s', special mode %d",
2038                elapsedLogTime(), cdbStatusName(cdbExState), stateName(state()), m_specialStopMode);
2039
2040     switch (state()) {
2041     case EngineSetupRequested:
2042         break;
2043     case EngineRunRequested:
2044         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineRunAndInferiorRunOk")
2045         notifyEngineRunAndInferiorRunOk();
2046         break;
2047     case InferiorRunOk:
2048     case InferiorStopOk:
2049         // Inaccessible without debuggee (exit breakpoint)
2050         // We go for spontaneous engine shutdown instead.
2051         if (cdbExState == CDB_STATUS_NO_DEBUGGEE) {
2052             if (debug)
2053                 qDebug("Lost debuggeee");
2054             m_hasDebuggee = false;
2055         }
2056         break;
2057     case InferiorRunRequested:
2058         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk")
2059         notifyInferiorRunOk();
2060         resetLocation();
2061         break;
2062     case EngineShutdownRequested:
2063         break;
2064     default:
2065         break;
2066     }
2067 }
2068
2069 void CdbEngine::handleExtensionMessage(char t, int token, const QByteArray &what, const QByteArray &message)
2070 {
2071     if (debug > 1) {
2072         QDebug nospace = qDebug().nospace();
2073         nospace << "handleExtensionMessage " << t << ' ' << token << ' ' << what
2074                 << ' ' << stateName(state());
2075         if (t == 'N' || debug > 1) {
2076             nospace << ' ' << message;
2077         } else {
2078             nospace << ' ' << message.size() << " bytes";
2079         }
2080     }
2081
2082     // Is there a reply expected, some command queued?
2083     if (t == 'R' || t == 'N') {
2084         if (token == -1) { // Default token, user typed in extension command
2085             showMessage(QString::fromLatin1(message), LogMisc);
2086             return;
2087         }
2088         const int index = indexOfCommand(m_extensionCommandQueue, token);
2089         if (index != -1) {
2090             // Did the command finish? Take off queue and complete, invoke CB
2091             const CdbExtensionCommandPtr command = m_extensionCommandQueue.takeAt(index);
2092             if (t == 'R') {
2093                 command->success = true;
2094                 command->reply = message;
2095             } else {
2096                 command->success = false;
2097                 command->errorMessage = message;
2098             }
2099             if (debug)
2100                 qDebug("### Completed extension command '%s', token=%d, pending=%d",
2101                        command->command.constData(), command->token, m_extensionCommandQueue.size());
2102             if (command->handler)
2103                 (this->*(command->handler))(command);
2104             return;
2105         }
2106     }
2107
2108     if (what == "debuggee_output") {
2109         showMessage(StringFromBase64EncodedUtf16(message), AppOutput);
2110         return;
2111     }
2112
2113     if (what == "event") {
2114         showStatusMessage(QString::fromAscii(message),  5000);
2115         return;
2116     }
2117
2118     if (what == "session_accessible") {
2119         if (!m_accessible) {
2120             m_accessible = true;
2121             handleSessionAccessible(message.toULong());
2122         }
2123         return;
2124     }
2125
2126     if (what == "session_inaccessible") {
2127         if (m_accessible) {
2128             m_accessible = false;
2129             handleSessionInaccessible(message.toULong());
2130         }
2131         return;
2132     }
2133
2134     if (what == "session_idle") {
2135         handleSessionIdle(message);
2136         return;
2137     }
2138
2139     if (what == "exception") {
2140         WinException exception;
2141         GdbMi gdbmi;
2142         gdbmi.fromString(message);
2143         exception.fromGdbMI(gdbmi);
2144         const QString message = exception.toString(true);
2145         showStatusMessage(message);
2146 #ifdef Q_OS_WIN // Report C++ exception in application output as well.
2147         if (exception.exceptionCode == winExceptionCppException)
2148             showMessage(message + QLatin1Char('\n'), AppOutput);
2149 #endif
2150         return;
2151     }
2152
2153     return;
2154 }
2155
2156 // Check for a CDB prompt '0:000> ' ('process:thread> ')..no regexps for QByteArray...
2157 enum { CdbPromptLength = 7 };
2158
2159 static inline bool isCdbPrompt(const QByteArray &c)
2160 {
2161     return c.size() >= CdbPromptLength && c.at(6) == ' ' && c.at(5) == '>' && c.at(1) == ':'
2162             && std::isdigit(c.at(0)) &&  std::isdigit(c.at(2)) && std::isdigit(c.at(3))
2163             && std::isdigit(c.at(4));
2164 }
2165
2166 // Check for '<token>32>' or '<token>32<'
2167 static inline bool checkCommandToken(const QByteArray &tokenPrefix, const QByteArray &c,
2168                                   int *token, bool *isStart)
2169 {
2170     *token = 0;
2171     *isStart = false;
2172     const int tokenPrefixSize = tokenPrefix.size();
2173     const int size = c.size();
2174     if (size < tokenPrefixSize + 2 || !std::isdigit(c.at(tokenPrefixSize)))
2175         return false;
2176     switch (c.at(size - 1)) {
2177     case '>':
2178         *isStart = false;
2179         break;
2180     case '<':
2181         *isStart = true;
2182         break;
2183     default:
2184         return false;
2185     }
2186     if (!c.startsWith(tokenPrefix))
2187         return false;
2188     bool ok;
2189     *token = c.mid(tokenPrefixSize, size - tokenPrefixSize - 1).toInt(&ok);
2190     return ok;
2191 }
2192
2193 void CdbEngine::parseOutputLine(QByteArray line)
2194 {
2195     // The hooked output callback in the extension suppresses prompts,
2196     // it should happen only in initial and exit stages. Note however that
2197     // if the output is not hooked, sequences of prompts are possible which
2198     // can mix things up.
2199     while (isCdbPrompt(line))
2200         line.remove(0, CdbPromptLength);
2201     // An extension notification (potentially consisting of several chunks)
2202     if (line.startsWith(m_creatorExtPrefix)) {
2203         // "<qtcreatorcdbext>|type_char|token|remainingChunks|serviceName|message"
2204         const char type = line.at(m_creatorExtPrefix.size());
2205         // integer token
2206         const int tokenPos = m_creatorExtPrefix.size() + 2;
2207         const int tokenEndPos = line.indexOf('|', tokenPos);
2208         QTC_ASSERT(tokenEndPos != -1, return)
2209         const int token = line.mid(tokenPos, tokenEndPos - tokenPos).toInt();
2210         // remainingChunks
2211         const int remainingChunksPos = tokenEndPos + 1;
2212         const int remainingChunksEndPos = line.indexOf('|', remainingChunksPos);
2213         QTC_ASSERT(remainingChunksEndPos != -1, return)
2214         const int remainingChunks = line.mid(remainingChunksPos, remainingChunksEndPos - remainingChunksPos).toInt();
2215         // const char 'serviceName'
2216         const int whatPos = remainingChunksEndPos + 1;
2217         const int whatEndPos = line.indexOf('|', whatPos);
2218         QTC_ASSERT(whatEndPos != -1, return)
2219         const QByteArray what = line.mid(whatPos, whatEndPos - whatPos);
2220         // Build up buffer, call handler once last chunk was encountered
2221         m_extensionMessageBuffer += line.mid(whatEndPos + 1);
2222         if (remainingChunks == 0) {
2223             handleExtensionMessage(type, token, what, m_extensionMessageBuffer);
2224             m_extensionMessageBuffer.clear();
2225         }
2226         return;
2227     }
2228     // Check for command start/end tokens within which the builtin command
2229     // output is enclosed
2230     int token = 0;
2231     bool isStartToken = false;
2232     const bool isCommandToken = checkCommandToken(m_tokenPrefix, line, &token, &isStartToken);
2233     if (debug > 1)
2234         qDebug("Reading CDB stdout '%s',\n  isCommand=%d, token=%d, isStart=%d, current=%d",
2235                line.constData(), isCommandToken, token, isStartToken, m_currentBuiltinCommandIndex);
2236
2237     // If there is a current command, wait for end of output indicated by token,
2238     // command, trigger handler and finish, else append to its output.
2239     if (m_currentBuiltinCommandIndex != -1) {
2240         QTC_ASSERT(!isStartToken && m_currentBuiltinCommandIndex < m_builtinCommandQueue.size(), return; );
2241         const CdbBuiltinCommandPtr &currentCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex);
2242         if (isCommandToken) {
2243             // Did the command finish? Invoke callback and remove from queue.
2244             if (debug)
2245                 qDebug("### Completed builtin command '%s', token=%d, %d lines, pending=%d",
2246                        currentCommand->command.constData(), currentCommand->token,
2247                        currentCommand->reply.size(), m_builtinCommandQueue.size() - 1);
2248             QTC_ASSERT(token == currentCommand->token, return; );
2249             if (currentCommand->handler)
2250                 (this->*(currentCommand->handler))(currentCommand);
2251             m_builtinCommandQueue.removeAt(m_currentBuiltinCommandIndex);
2252             m_currentBuiltinCommandIndex = -1;
2253         } else {
2254             // Record output of current command
2255             currentCommand->reply.push_back(line);
2256         }
2257         return;
2258     } // m_currentCommandIndex
2259     if (isCommandToken) {
2260         // Beginning command token encountered, start to record output.
2261         const int index = indexOfCommand(m_builtinCommandQueue, token);
2262         QTC_ASSERT(isStartToken && index != -1, return; );
2263         m_currentBuiltinCommandIndex = index;
2264         const CdbBuiltinCommandPtr &currentCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex);
2265         if (debug)
2266             qDebug("### Gathering output for '%s' token %d", currentCommand->command.constData(), currentCommand->token);
2267         return;
2268     }
2269
2270     showMessage(QString::fromLocal8Bit(line), LogMisc);
2271 }
2272
2273 void CdbEngine::readyReadStandardOut()
2274 {
2275     if (m_ignoreCdbOutput)
2276         return;
2277     m_outputBuffer += m_process.readAllStandardOutput();
2278     // Split into lines and parse line by line.
2279     while (true) {
2280         const int endOfLinePos = m_outputBuffer.indexOf('\n');
2281         if (endOfLinePos == -1) {
2282             break;
2283         } else {
2284             // Check for '\r\n'
2285             QByteArray line = m_outputBuffer.left(endOfLinePos);
2286             if (!line.isEmpty() && line.at(line.size() - 1) == '\r')
2287                 line.truncate(line.size() - 1);
2288             parseOutputLine(line);
2289             m_outputBuffer.remove(0, endOfLinePos + 1);
2290         }
2291     }
2292 }
2293
2294 void CdbEngine::readyReadStandardError()
2295 {
2296     showMessage(QString::fromLocal8Bit(m_process.readAllStandardError()), LogError);
2297 }
2298
2299 void CdbEngine::processError()
2300 {
2301     showMessage(m_process.errorString(), LogError);
2302 }
2303
2304 #if 0
2305 // Join breakpoint ids for a multi-breakpoint id commands like 'bc', 'be', 'bd'
2306 static QByteArray multiBreakpointCommand(const char *cmdC, const Breakpoints &bps)
2307 {
2308     QByteArray cmd(cmdC);
2309     ByteArrayInputStream str(cmd);
2310     foreach(const BreakpointData *bp, bps)
2311         str << ' ' << bp->bpNumber;
2312     return cmd;
2313 }
2314 #endif
2315
2316 bool CdbEngine::stateAcceptsBreakpointChanges() const
2317 {
2318     switch (state()) {
2319     case InferiorRunOk:
2320     case InferiorStopOk:
2321     return true;
2322     default:
2323         break;
2324     }
2325     return false;
2326 }
2327
2328 bool CdbEngine::acceptsBreakpoint(BreakpointId id) const
2329 {
2330     const BreakpointParameters &data = breakHandler()->breakpointData(id);
2331     if (!DebuggerEngine::isCppBreakpoint(data))
2332         return false;
2333     switch (data.type) {
2334     case UnknownType:
2335     case BreakpointAtFork:
2336     //case BreakpointAtVFork:
2337     case BreakpointAtSysCall:
2338         return false;
2339     case Watchpoint:
2340     case BreakpointByFileAndLine:
2341     case BreakpointByFunction:
2342     case BreakpointByAddress:
2343     case BreakpointAtThrow:
2344     case BreakpointAtCatch:
2345     case BreakpointAtMain:
2346     case BreakpointAtExec:
2347         break;
2348     }
2349     return true;
2350 }
2351
2352 void CdbEngine::attemptBreakpointSynchronization()
2353 {
2354     if (debug)
2355         qDebug("attemptBreakpointSynchronization in %s", stateName(state()));
2356     // Check if there is anything to be done at all.
2357     BreakHandler *handler = breakHandler();
2358     // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
2359     foreach (BreakpointId id, handler->unclaimedBreakpointIds())
2360         if (acceptsBreakpoint(id))
2361             handler->setEngine(id, this);
2362
2363     // Quick check: is there a need to change something? - Populate module cache
2364     bool changed = false;
2365     const BreakpointIds ids = handler->engineBreakpointIds(this);
2366     foreach (BreakpointId id, ids) {
2367         switch (handler->state(id)) {
2368         case BreakpointInsertRequested:
2369         case BreakpointRemoveRequested:
2370         case BreakpointChangeRequested:
2371             changed = true;
2372             break;
2373         case BreakpointInserted: {
2374             // Collect the new modules matching the files.
2375             // In the future, that information should be obtained from the build system.
2376             const BreakpointParameters &data = handler->breakpointData(id);
2377             if (data.type == BreakpointByFileAndLine && !data.module.isEmpty())
2378                 m_fileNameModuleHash.insert(data.fileName, data.module);
2379         }
2380         break;
2381         default:
2382             break;
2383         }
2384     }
2385
2386     if (debugBreakpoints)
2387         qDebug("attemptBreakpointSynchronizationI %dms accessible=%d, %s %d breakpoints, changed=%d",
2388                elapsedLogTime(), m_accessible, stateName(state()), ids.size(), changed);
2389     if (!changed)
2390         return;
2391
2392     if (!m_accessible) {
2393         // No nested calls.
2394         if (m_specialStopMode != SpecialStopSynchronizeBreakpoints)
2395             doInterruptInferior(SpecialStopSynchronizeBreakpoints);
2396         return;
2397     }
2398     // Add/Change breakpoints and store pending ones in map, since
2399     // Breakhandler::setResponse() on pending breakpoints clears the pending flag.
2400     // handleBreakPoints will the complete that information and set it on the break handler.
2401     bool addedChanged = false;
2402     foreach (BreakpointId id, ids) {
2403         BreakpointParameters parameters = handler->breakpointData(id);
2404         BreakpointResponse response;
2405         response.fromParameters(parameters);
2406         // If we encountered that file and have a module for it: Add it.
2407         if (parameters.type == BreakpointByFileAndLine && parameters.module.isEmpty()) {
2408             const QHash<QString, QString>::const_iterator it = m_fileNameModuleHash.constFind(parameters.fileName);
2409             if (it != m_fileNameModuleHash.constEnd())
2410                 parameters.module = it.value();
2411         }
2412         switch (handler->state(id)) {
2413         case BreakpointInsertRequested:
2414             postCommand(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), 0);
2415             if (!parameters.enabled)
2416                 postCommand("bd " + QByteArray::number(id), 0);
2417             handler->notifyBreakpointInsertProceeding(id);
2418             handler->notifyBreakpointInsertOk(id);
2419             m_pendingBreakpointMap.insert(id, response);
2420             addedChanged = true;
2421             // Ensure enabled/disabled is correct in handler and line number is there.
2422             handler->setResponse(id, response);
2423             if (debugBreakpoints)
2424                 qDebug("Adding %llu %s\n", id, qPrintable(response.toString()));
2425             break;
2426         case BreakpointChangeRequested:
2427             handler->notifyBreakpointChangeProceeding(id);
2428             if (debugBreakpoints)
2429                 qDebug("Changing %llu:\n    %s\nTo %s\n", id, qPrintable(handler->response(id).toString()),
2430                        qPrintable(parameters.toString()));
2431             if (parameters.enabled != handler->response(id).enabled) {
2432                 // Change enabled/disabled breakpoints without triggering update.
2433                 postCommand((parameters.enabled ? "be " : "bd ") + QByteArray::number(id), 0);
2434                 response.pending = false;
2435                 response.enabled = parameters.enabled;
2436                 handler->setResponse(id, response);
2437             } else {
2438                 // Delete and re-add, triggering update
2439                 addedChanged = true;
2440                 postCommand("bc " + QByteArray::number(id), 0);
2441                 postCommand(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), 0);
2442                 m_pendingBreakpointMap.insert(id, response);
2443             }
2444             handler->notifyBreakpointChangeOk(id);
2445             break;
2446         case BreakpointRemoveRequested:
2447             postCommand("bc " + QByteArray::number(id), 0);
2448             handler->notifyBreakpointRemoveProceeding(id);
2449             handler->notifyBreakpointRemoveOk(id);
2450             m_pendingBreakpointMap.remove(id);
2451             break;
2452         default:
2453             break;
2454         }
2455     }
2456     // List breakpoints and send responses
2457     if (addedChanged)
2458         postCommandSequence(CommandListBreakPoints);
2459 }
2460
2461 // Pass a file name through source mapping and normalize upper/lower case (for the editor
2462 // manager to correctly process it) and convert to clean path.
2463 CdbEngine::NormalizedSourceFileName CdbEngine::sourceMapNormalizeFileNameFromDebugger(const QString &f)
2464 {
2465     // 1) Check cache.
2466     QMap<QString, NormalizedSourceFileName>::const_iterator it = m_normalizedFileCache.constFind(f);
2467     if (it != m_normalizedFileCache.constEnd())
2468         return it.value();
2469     if (debugSourceMapping)
2470         qDebug(">sourceMapNormalizeFileNameFromDebugger %s", qPrintable(f));
2471     // Do we have source path mappings? ->Apply.
2472     const QString fileName = cdbSourcePathMapping(QDir::toNativeSeparators(f), m_sourcePathMappings,
2473                                                   DebuggerToSource);
2474     // Up/lower case normalization according to Windows.
2475 #ifdef Q_OS_WIN
2476     QString normalized = winNormalizeFileName(fileName);
2477 #else
2478     QString normalized = fileName;
2479 #endif
2480     if (debugSourceMapping)
2481         qDebug(" sourceMapNormalizeFileNameFromDebugger %s->%s", qPrintable(fileName), qPrintable(normalized));
2482     // Check if it really exists, that is normalize worked and QFileInfo confirms it.
2483     const bool exists = !normalized.isEmpty() && QFileInfo(normalized).isFile();
2484     NormalizedSourceFileName result(QDir::cleanPath(normalized.isEmpty() ? fileName : normalized), exists);
2485     if (!exists) {
2486         // At least upper case drive letter if failed.
2487         if (result.fileName.size() > 2 && result.fileName.at(1) == QLatin1Char(':'))
2488             result.fileName[0] = result.fileName.at(0).toUpper();
2489     }
2490     m_normalizedFileCache.insert(f, result);
2491     if (debugSourceMapping)
2492         qDebug("<sourceMapNormalizeFileNameFromDebugger %s %d", qPrintable(result.fileName), result.exists);
2493     return result;
2494 }
2495
2496 // Parse frame from GDBMI. Duplicate of the gdb code, but that
2497 // has more processing.
2498 static StackFrames parseFrames(const GdbMi &gdbmi)
2499 {
2500     StackFrames rc;
2501     const int count = gdbmi.childCount();
2502     rc.reserve(count);
2503     for (int i = 0; i  < count; i++) {
2504         const GdbMi &frameMi = gdbmi.childAt(i);
2505         StackFrame frame;
2506         frame.level = i;
2507         const GdbMi fullName = frameMi.findChild("fullname");
2508         if (fullName.isValid()) {
2509             frame.file = QFile::decodeName(fullName.data());
2510             frame.line = frameMi.findChild("line").data().toInt();
2511             frame.usable = false; // To be decided after source path mapping.
2512         }
2513         frame.function = QLatin1String(frameMi.findChild("func").data());
2514         frame.from = QLatin1String(frameMi.findChild("from").data());
2515         frame.address = frameMi.findChild("addr").data().toULongLong(0, 16);
2516         rc.push_back(frame);
2517     }
2518     return rc;
2519 }
2520
2521 unsigned CdbEngine::parseStackTrace(const GdbMi &data, bool sourceStepInto)
2522 {
2523     // Parse frames, find current. Special handling for step into:
2524     // When stepping into on an actual function (source mode) by executing 't', an assembler
2525     // frame pointing at the jmp instruction is hit (noticeable by top function being
2526     // 'ILT+'). If that is the case, execute another 't' to step into the actual function.    .
2527     // Note that executing 't 2' does not work since it steps 2 instructions on a non-call code line.
2528     int current = -1;
2529     StackFrames frames = parseFrames(data);
2530     const int count = frames.size();
2531     for (int i = 0; i < count; i++) {
2532         const bool hasFile = !frames.at(i).file.isEmpty();
2533         // jmp-frame hit by step into, do another 't' and abort sequence.
2534         if (!hasFile && i == 0 && sourceStepInto && frames.at(i).function.contains(QLatin1String("ILT+"))) {
2535             showMessage(QString::fromAscii("Step into: Call instruction hit, performing additional step..."), LogMisc);
2536             return ParseStackStepInto;
2537         }
2538         if (hasFile) {
2539             const NormalizedSourceFileName fileName = sourceMapNormalizeFileNameFromDebugger(frames.at(i).file);
2540             frames[i].file = fileName.fileName;
2541             frames[i].usable = fileName.exists;
2542             if (current == -1 && frames[i].usable)
2543                 current = i;
2544         }
2545     }
2546     if (count && current == -1) // No usable frame, use assembly.
2547         current = 0;
2548     // Set
2549     stackHandler()->setFrames(frames);
2550     activateFrame(current);
2551     return 0;
2552 }
2553
2554 void CdbEngine::handleStackTrace(const CdbExtensionCommandPtr &command)
2555 {
2556     if (command->success) {
2557         GdbMi data;
2558         data.fromString(command->reply);
2559         parseStackTrace(data, false);
2560         postCommandSequence(command->commandSequence);
2561     } else {
2562         showMessage(command->errorMessage, LogError);
2563     }
2564 }
2565
2566 void CdbEngine::handleExpression(const CdbExtensionCommandPtr &command)
2567 {
2568     int value = 0;
2569     if (command->success) {
2570         value = command->reply.toInt();
2571     } else {
2572         showMessage(command->errorMessage, LogError);
2573     }
2574     // Is this a conditional breakpoint?
2575     if (command->cookie.isValid() && qVariantCanConvert<ConditionalBreakPointCookie>(command->cookie)) {
2576         const ConditionalBreakPointCookie cookie = qvariant_cast<ConditionalBreakPointCookie>(command->cookie);
2577         const QString message = value ?
2578             tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping.").
2579             arg(value).arg(cookie.id) :
2580             tr("Value 0 obtained from evaluating the condition of breakpoint %1, continuing.").
2581             arg(cookie.id);
2582         showMessage(message, LogMisc);
2583         // Stop if evaluation is true, else continue
2584         if (value) {
2585             processStop(cookie.stopReason, true);
2586         } else {
2587             postCommand("g", 0);
2588         }
2589     }
2590 }
2591
2592 void CdbEngine::evaluateExpression(QByteArray exp, const QVariant &cookie)
2593 {
2594     if (exp.contains(' ') && !exp.startsWith('"')) {
2595         exp.prepend('"');
2596         exp.append('"');
2597     }
2598     postExtensionCommand("expression", exp, 0, &CdbEngine::handleExpression, 0, cookie);
2599 }
2600
2601 void CdbEngine::dummyHandler(const CdbBuiltinCommandPtr &command)
2602 {
2603     postCommandSequence(command->commandSequence);
2604 }
2605
2606 // Post a sequence of standard commands: Trigger next once one completes successfully
2607 void CdbEngine::postCommandSequence(unsigned mask)
2608 {
2609     if (debug)
2610         qDebug("postCommandSequence 0x%x\n", mask);
2611
2612     if (!mask)
2613         return;
2614     if (mask & CommandListThreads) {
2615         postExtensionCommand("threads", QByteArray(), 0, &CdbEngine::handleThreads, mask & ~CommandListThreads);
2616         return;
2617     }
2618     if (mask & CommandListStack) {
2619         postExtensionCommand("stack", QByteArray(), 0, &CdbEngine::handleStackTrace, mask & ~CommandListStack);
2620         return;
2621     }
2622     if (mask & CommandListRegisters) {
2623         QTC_ASSERT(threadsHandler()->currentThread() >= 0,  return; )
2624         postExtensionCommand("registers", QByteArray(), 0, &CdbEngine::handleRegisters, mask & ~CommandListRegisters);
2625         return;
2626     }
2627     if (mask & CommandListModules) {
2628         postExtensionCommand("modules", QByteArray(), 0, &CdbEngine::handleModules, mask & ~CommandListModules);
2629         return;
2630     }
2631     if (mask & CommandListBreakPoints) {
2632         postExtensionCommand("breakpoints", QByteArray("-v"), 0,
2633                              &CdbEngine::handleBreakPoints, mask & ~CommandListBreakPoints);
2634         return;
2635     }
2636 }
2637
2638 void CdbEngine::handleWidgetAt(const CdbExtensionCommandPtr &reply)
2639 {
2640     bool success = false;
2641     QString message;
2642     do {
2643         if (!reply->success) {
2644             message = QString::fromAscii(reply->errorMessage);
2645             break;
2646         }
2647         // Should be "namespace::QWidget:0x555"
2648         QString watchExp = QString::fromAscii(reply->reply);
2649         const int sepPos = watchExp.lastIndexOf(QLatin1Char(':'));
2650         if (sepPos == -1) {
2651             message = QString::fromAscii("Invalid output: %1").arg(watchExp);
2652             break;
2653         }
2654         // 0x000 -> nothing found
2655         if (!watchExp.mid(sepPos + 1).toULongLong(0, 0)) {
2656             message = QString::fromAscii("No widget could be found at %1, %2.").arg(m_watchPointX).arg(m_watchPointY);
2657             break;
2658         }
2659         // Turn into watch expression: "*(namespace::QWidget*)0x555"
2660         watchExp.replace(sepPos, 1, QLatin1String("*)"));
2661         watchExp.insert(0, QLatin1String("*("));
2662         watchHandler()->watchExpression(watchExp);
2663         success = true;
2664     } while (false);
2665     if (!success)
2666         showMessage(message, LogWarning);
2667     m_watchPointX = m_watchPointY = 0;
2668 }
2669
2670 static inline void formatCdbBreakPointResponse(BreakpointId id, const BreakpointResponse &r,
2671                                                   QTextStream &str)
2672 {
2673     str << "Obtained breakpoint " << id << " (#" << r.number << ')';
2674     if (r.pending) {
2675         str << ", pending";
2676     } else {
2677         str.setIntegerBase(16);
2678         str << ", at 0x" << r.address;
2679         str.setIntegerBase(10);
2680     }
2681     if (!r.enabled)
2682         str << ", disabled";
2683     if (!r.module.isEmpty())
2684         str << ", module: '" << r.module << '\'';
2685     str << '\n';
2686 }
2687
2688 void CdbEngine::handleBreakPoints(const CdbExtensionCommandPtr &reply)
2689 {
2690     if (debugBreakpoints)
2691         qDebug("CdbEngine::handleBreakPoints: success=%d: %s", reply->success, reply->reply.constData());
2692     if (!reply->success) {
2693         showMessage(QString::fromAscii(reply->errorMessage), LogError);
2694         return;
2695     }
2696     GdbMi value;
2697     value.fromString(reply->reply);
2698     if (value.type() != GdbMi::List) {
2699         showMessage(QString::fromAscii("Unabled to parse breakpoints reply"), LogError);
2700         return;
2701     }
2702     handleBreakPoints(value);
2703 }
2704
2705 void CdbEngine::handleBreakPoints(const GdbMi &value)
2706 {
2707     // Report all obtained parameters back. Note that not all parameters are reported
2708     // back, so, match by id and complete
2709     if (debugBreakpoints)
2710         qDebug("\nCdbEngine::handleBreakPoints with %d", value.childCount());
2711     QString message;
2712     QTextStream str(&message);
2713     BreakHandler *handler = breakHandler();
2714     foreach (const GdbMi &breakPointG, value.children()) {
2715         BreakpointResponse reportedResponse;
2716         const BreakpointId id = parseBreakPoint(breakPointG, &reportedResponse);
2717         if (debugBreakpoints)
2718             qDebug("  Parsed %llu: pending=%d %s\n", id, reportedResponse.pending,
2719                    qPrintable(reportedResponse.toString()));
2720
2721         if (!reportedResponse.pending) {
2722             const PendingBreakPointMap::iterator it = m_pendingBreakpointMap.find(id);
2723             if (it != m_pendingBreakpointMap.end()) {
2724                 // Complete the response and set on handler.
2725                 BreakpointResponse &currentResponse = it.value();
2726                 currentResponse.number = reportedResponse.number;
2727                 currentResponse.address = reportedResponse.address;
2728                 currentResponse.module = reportedResponse.module;
2729                 currentResponse.pending = reportedResponse.pending;
2730                 currentResponse.enabled = reportedResponse.enabled;
2731                 formatCdbBreakPointResponse(id, currentResponse, str);
2732                 if (debugBreakpoints)
2733                     qDebug("  Setting for %llu: %s\n", id, qPrintable(currentResponse.toString()));
2734                 handler->setResponse(id, currentResponse);
2735                 m_pendingBreakpointMap.erase(it);
2736             }
2737         } // not pending reported
2738     } // foreach
2739     if (m_pendingBreakpointMap.empty()) {
2740         str << QLatin1String("All breakpoints have been resolved.\n");
2741     } else {
2742         str << QString::fromLatin1("%1 breakpoint(s) pending...\n").arg(m_pendingBreakpointMap.size());
2743     }
2744     showMessage(message, LogMisc);
2745 }
2746
2747 void CdbEngine::watchPoint(const QPoint &p)
2748 {
2749     m_watchPointX = p.x();
2750     m_watchPointY = p.y();
2751     switch (state()) {
2752     case InferiorStopOk:
2753         postWidgetAtCommand();
2754         break;
2755     case InferiorRunOk:
2756         // "Select Widget to Watch" from a running application is currently not
2757         // supported. It could be implemented via SpecialStopGetWidgetAt-mode,
2758         // but requires some work as not to confuse the engine by state-change notifications
2759         // emitted by the debuggee function call.
2760         showMessage(tr("\"Select Widget to Watch\": Please stop the application first."), LogWarning);
2761         break;
2762     default:
2763         showMessage(tr("\"Select Widget to Watch\": Not supported in state '%1'.").
2764                     arg(QString::fromAscii(stateName(state()))), LogWarning);
2765         break;
2766     }
2767 }
2768
2769 void CdbEngine::postWidgetAtCommand()
2770 {
2771     QByteArray arguments = QByteArray::number(m_watchPointX);
2772     arguments.append(' ');
2773     arguments.append(QByteArray::number(m_watchPointY));
2774     postExtensionCommand("widgetat", arguments, 0, &CdbEngine::handleWidgetAt, 0);
2775 }
2776
2777 void CdbEngine::handleCustomSpecialStop(const QVariant &v)
2778 {
2779     if (qVariantCanConvert<MemoryChangeCookie>(v)) {
2780         const MemoryChangeCookie changeData = qVariantValue<MemoryChangeCookie>(v);
2781         postCommand(cdbWriteMemoryCommand(changeData.address, changeData.data), 0);
2782         return;
2783     }
2784 }
2785
2786 } // namespace Internal
2787 } // namespace Debugger