OSDN Git Service

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