OSDN Git Service

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