OSDN Git Service

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