OSDN Git Service

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