OSDN Git Service

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