OSDN Git Service

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