| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | /**************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-01-11 16:28:15 +01:00
										 |  |  | ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | ** | 
					
						
							|  |  |  | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-12-17 17:14:20 +01:00
										 |  |  | ** No Commercial Usage | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-12-17 17:14:20 +01:00
										 |  |  | ** This file contains pre-release code and may not be distributed. | 
					
						
							|  |  |  | ** You may use this file in accordance with the terms and conditions | 
					
						
							|  |  |  | ** contained in the Technology Preview License Agreement accompanying | 
					
						
							|  |  |  | ** this package. | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | ** | 
					
						
							|  |  |  | ** GNU Lesser General Public License Usage | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
					
						
							|  |  |  | ** General Public License version 2.1 as published by the Free Software | 
					
						
							|  |  |  | ** Foundation and appearing in the file LICENSE.LGPL included in the | 
					
						
							|  |  |  | ** packaging of this file.  Please review the following information to | 
					
						
							|  |  |  | ** ensure the GNU Lesser General Public License version 2.1 requirements | 
					
						
							|  |  |  | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-12-17 17:14:20 +01:00
										 |  |  | ** In addition, as a special exception, Nokia gives you certain additional | 
					
						
							|  |  |  | ** rights.  These rights are described in the Nokia Qt LGPL Exception | 
					
						
							|  |  |  | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** If you have questions regarding the use of this file, please contact | 
					
						
							|  |  |  | ** Nokia at qt-info@nokia.com. | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | ** | 
					
						
							|  |  |  | **************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:22:55 +01:00
										 |  |  | #include "cdbengine.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-10 10:14:23 +01:00
										 |  |  | #include "debuggerstartparameters.h"
 | 
					
						
							|  |  |  | #include "disassemblerlines.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:22:55 +01:00
										 |  |  | #include "cdboptions.h"
 | 
					
						
							|  |  |  | #include "cdboptionspage.h"
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | #include "bytearrayinputstream.h"
 | 
					
						
							|  |  |  | #include "breakpoint.h"
 | 
					
						
							|  |  |  | #include "breakhandler.h"
 | 
					
						
							|  |  |  | #include "stackframe.h"
 | 
					
						
							|  |  |  | #include "stackhandler.h"
 | 
					
						
							|  |  |  | #include "watchhandler.h"
 | 
					
						
							|  |  |  | #include "threadshandler.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-10 10:14:23 +01:00
										 |  |  | #include "moduleshandler.h"
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | #include "debuggeractions.h"
 | 
					
						
							|  |  |  | #include "debuggercore.h"
 | 
					
						
							|  |  |  | #include "registerhandler.h"
 | 
					
						
							| 
									
										
										
										
											2010-12-08 12:43:11 +01:00
										 |  |  | #include "disassembleragent.h"
 | 
					
						
							|  |  |  | #include "memoryagent.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  | #include "debuggerrunner.h"
 | 
					
						
							| 
									
										
										
										
											2010-11-22 17:06:08 +01:00
										 |  |  | #include "debuggertooltip.h"
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | #include "cdbparsehelpers.h"
 | 
					
						
							|  |  |  | #include "watchutils.h"
 | 
					
						
							|  |  |  | #include "gdb/gdbmi.h"
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:22:41 +01:00
										 |  |  | #include "shared/cdbsymbolpathlisteditor.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <coreplugin/icore.h>
 | 
					
						
							| 
									
										
										
										
											2010-11-22 17:06:08 +01:00
										 |  |  | #include <texteditor/itexteditor.h>
 | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  | #include <projectexplorer/toolchain.h>
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  | #include <utils/synchronousprocess.h>
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | #include <utils/winutils.h>
 | 
					
						
							|  |  |  | #include <utils/qtcassert.h>
 | 
					
						
							|  |  |  | #include <utils/savedaction.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QtCore/QCoreApplication>
 | 
					
						
							|  |  |  | #include <QtCore/QFileInfo>
 | 
					
						
							|  |  |  | #include <QtCore/QDir>
 | 
					
						
							|  |  |  | #include <QtCore/QDebug>
 | 
					
						
							|  |  |  | #include <QtCore/QTextStream>
 | 
					
						
							|  |  |  | #include <QtCore/QDateTime>
 | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  | #include <QtGui/QToolTip>
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  | #    include <utils/winutils.h>
 | 
					
						
							|  |  |  | #    include "dbgwinutils.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <cctype>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-14 12:29:32 +01:00
										 |  |  | Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgent*) | 
					
						
							|  |  |  | Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | enum { debug = 0 }; | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  | enum { debugLocals = 0 }; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | enum { debugBreakpoints = 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  | #  define STATE_DEBUG(func, line, notifyFunc) qDebug("%s at %s:%d", notifyFunc, func, line);
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #  define STATE_DEBUG(func, line, notifyFunc)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* CdbEngine version 2: Run the CDB process on pipes and parse its output.
 | 
					
						
							|  |  |  |  * The engine relies on a CDB extension Qt Creator provides as an extension | 
					
						
							| 
									
										
										
										
											2011-01-11 14:58:32 +01:00
										 |  |  |  * library (32/64bit), which is loaded into cdb.exe. It serves to: | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |  * - Notify the engine about the state of the debugging session: | 
					
						
							| 
									
										
										
										
											2011-01-11 14:58:32 +01:00
										 |  |  |  *   + idle: (hooked up with .idle_cmd) debuggee stopped | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |  *   + accessible: Debuggee stopped, cdb.exe accepts commands | 
					
						
							|  |  |  |  *   + inaccessible: Debuggee runs, no way to post commands | 
					
						
							|  |  |  |  *   + session active/inactive: Lost debuggee, terminating. | 
					
						
							| 
									
										
										
										
											2011-01-11 14:58:32 +01:00
										 |  |  |  * - Hook up with output/event callbacks and produce formatted output to be able | 
					
						
							|  |  |  |  *   to catch application output and exceptions. | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |  * - Provide some extension commands that produce output in a standardized (GDBMI) | 
					
						
							|  |  |  |  *   format that ends up in handleExtensionMessage(). | 
					
						
							|  |  |  |  *   + pid     Return debuggee pid for interrupting. | 
					
						
							|  |  |  |  *   + locals  Print locals from SymbolGroup | 
					
						
							|  |  |  |  *   + expandLocals Expand locals in symbol group | 
					
						
							|  |  |  |  *   + registers, modules, threads | 
					
						
							| 
									
										
										
										
											2011-01-11 14:58:32 +01:00
										 |  |  |  * Commands can be posted by calling: | 
					
						
							|  |  |  |  * 1) postCommand(): Does not expect a reply | 
					
						
							|  |  |  |  * 2) postBuiltinCommand(): Run a builtin-command producing free-format, multiline output | 
					
						
							|  |  |  |  *    that is captured by enclosing it in special tokens using the 'echo' command and | 
					
						
							|  |  |  |  *    then invokes a callback with a CdbBuiltinCommand structure. | 
					
						
							|  |  |  |  * 3) postExtensionCommand(): Run a command provided by the extension producing | 
					
						
							|  |  |  |  *    one-line output and invoke a callback with a CdbExtensionCommand structure | 
					
						
							|  |  |  |  *    (output is potentially split up in chunks). */ | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  | using namespace ProjectExplorer; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | namespace Debugger { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | namespace Internal { | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  | static const char localsPrefixC[] = "local."; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | struct MemoryViewCookie { | 
					
						
							| 
									
										
										
										
											2010-12-14 12:29:32 +01:00
										 |  |  |     explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0, | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |                               quint64 addr = 0, quint64 l = 0) : | 
					
						
							|  |  |  |         agent(a), editorToken(e), address(addr), length(l) {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-14 12:29:32 +01:00
										 |  |  |     MemoryAgent *agent; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     QObject *editorToken; | 
					
						
							|  |  |  |     quint64 address; | 
					
						
							|  |  |  |     quint64 length; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct SourceLocationCookie { | 
					
						
							|  |  |  |     explicit SourceLocationCookie(const QString &f = QString(), int l = 0) : | 
					
						
							|  |  |  |              fileName(f), lineNumber(l) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString fileName; | 
					
						
							|  |  |  |     int lineNumber; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | } // namespace Internal
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } // namespace Debugger
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie) | 
					
						
							|  |  |  | Q_DECLARE_METATYPE(Debugger::Internal::SourceLocationCookie) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Debugger { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | namespace Internal { | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Base data structure for command queue entries with callback
 | 
					
						
							|  |  |  | struct CdbCommandBase | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     typedef CdbEngine::BuiltinCommandHandler CommandHandler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CdbCommandBase(); | 
					
						
							|  |  |  |     CdbCommandBase(const QByteArray  &cmd, int token, unsigned flags, | 
					
						
							|  |  |  |                    unsigned nc, const QVariant &cookie); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int token; | 
					
						
							|  |  |  |     unsigned flags; | 
					
						
							|  |  |  |     QByteArray command; | 
					
						
							|  |  |  |     QVariant cookie; | 
					
						
							|  |  |  |     // Continue with another commands as specified in CommandSequenceFlags
 | 
					
						
							|  |  |  |     unsigned commandSequence; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CdbCommandBase::CdbCommandBase() : | 
					
						
							|  |  |  |     token(0), flags(0), commandSequence(0) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CdbCommandBase::CdbCommandBase(const QByteArray  &cmd, int t, unsigned f, | 
					
						
							|  |  |  |                                unsigned nc, const QVariant &c) : | 
					
						
							|  |  |  |     token(t), flags(f), command(cmd), cookie(c), commandSequence(nc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Queue entry for builtin commands producing free-format
 | 
					
						
							|  |  |  | // line-by-line output.
 | 
					
						
							|  |  |  | struct CdbBuiltinCommand : public CdbCommandBase | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     typedef CdbEngine::BuiltinCommandHandler CommandHandler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CdbBuiltinCommand() {} | 
					
						
							|  |  |  |     CdbBuiltinCommand(const QByteArray  &cmd, int token, unsigned flags, | 
					
						
							|  |  |  |                       CommandHandler h, | 
					
						
							|  |  |  |                       unsigned nc, const QVariant &cookie) : | 
					
						
							|  |  |  |         CdbCommandBase(cmd, token, flags, nc, cookie), handler(h) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QByteArray joinedReply() const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CommandHandler handler; | 
					
						
							|  |  |  |     QList<QByteArray> reply; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray CdbBuiltinCommand::joinedReply() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (reply.isEmpty()) | 
					
						
							|  |  |  |         return QByteArray(); | 
					
						
							|  |  |  |     QByteArray answer; | 
					
						
							|  |  |  |     answer.reserve(120  * reply.size()); | 
					
						
							|  |  |  |     foreach (const QByteArray &l, reply) { | 
					
						
							|  |  |  |         answer += l; | 
					
						
							|  |  |  |         answer += '\n'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return answer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Queue entry for Qt Creator extension commands producing one-line
 | 
					
						
							|  |  |  | // output with success flag and error message.
 | 
					
						
							|  |  |  | struct CdbExtensionCommand : public CdbCommandBase | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     typedef CdbEngine::ExtensionCommandHandler CommandHandler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CdbExtensionCommand() : success(false) {} | 
					
						
							|  |  |  |     CdbExtensionCommand(const QByteArray  &cmd, int token, unsigned flags, | 
					
						
							|  |  |  |                       CommandHandler h, | 
					
						
							|  |  |  |                       unsigned nc, const QVariant &cookie) : | 
					
						
							|  |  |  |         CdbCommandBase(cmd, token, flags, nc, cookie), handler(h),success(false) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CommandHandler handler; | 
					
						
							|  |  |  |     QByteArray reply; | 
					
						
							|  |  |  |     QByteArray errorMessage; | 
					
						
							|  |  |  |     bool success; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class CommandPtrType> | 
					
						
							|  |  |  | int indexOfCommand(const QList<CommandPtrType> &l, int token) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const int count = l.size(); | 
					
						
							|  |  |  |     for (int i = 0; i < count; i++) | 
					
						
							|  |  |  |         if (l.at(i)->token == token) | 
					
						
							|  |  |  |             return i; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool validMode(DebuggerStartMode sm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (sm) { | 
					
						
							|  |  |  |     case NoStartMode: | 
					
						
							|  |  |  |     case AttachTcf: | 
					
						
							|  |  |  |     case AttachCore: | 
					
						
							|  |  |  |     case StartRemoteGdb: | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  | static inline QString msgCdbDisabled(ToolChainType tc) | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return CdbEngine::tr("The CDB debug engine required for %1 is currently disabled."). | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  |                       arg(ToolChain::toolChainName(tc)); | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | // Accessed by RunControlFactory
 | 
					
						
							|  |  |  | DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp, QString *errorMessage) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  |     CdbOptionsPage *op = CdbOptionsPage::instance(); | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  |     if (!op || !op->options()->isValid()) { | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  |         *errorMessage = msgCdbDisabled(sp.toolChainType); | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!validMode(sp.startMode)) { | 
					
						
							|  |  |  |         *errorMessage = CdbEngine::tr("The CDB debug engine does not support start mode %1.").arg(sp.startMode); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return new CdbEngine(sp, op->options()); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  |     Q_UNUSED(sp) | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     *errorMessage = QString::fromLatin1("Unsuppported debug mode"); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool isCdbEngineEnabled() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  |     return CdbOptionsPage::instance() && CdbOptionsPage::instance()->options()->isValid(); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  | ConfigurationCheck checkCdbConfiguration(ToolChainType toolChain) | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  |     ConfigurationCheck check; | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  |     switch (toolChain) { | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  |     case ToolChain_MinGW: // Do our best
 | 
					
						
							|  |  |  |     case ToolChain_MSVC: | 
					
						
							|  |  |  |     case ToolChain_WINCE: | 
					
						
							|  |  |  |     case ToolChain_OTHER: | 
					
						
							|  |  |  |     case ToolChain_UNKNOWN: | 
					
						
							|  |  |  |     case ToolChain_INVALID: | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  |         if (!isCdbEngineEnabled()) { | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  |             check.errorMessage = msgCdbDisabled(toolChain); | 
					
						
							|  |  |  |             check.settingsPage = CdbOptionsPage::settingsId(); | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         //: %1 is something like "GCCE" or "Intel C++ Compiler (Linux)" (see ToolChain context)
 | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  |         check.errorMessage = CdbEngine::tr("The CDB debug engine does not support the %1 toolchain."). | 
					
						
							|  |  |  |                     arg(ToolChain::toolChainName(toolChain)); | 
					
						
							|  |  |  |         check.settingsPage = CdbOptionsPage::settingsId(); | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-01-07 19:50:41 +01:00
										 |  |  |     return check; | 
					
						
							| 
									
										
										
										
											2011-01-07 15:04:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | void addCdb2OptionPages(QList<Core::IOptionsPage *> *opts) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     opts->push_back(new CdbOptionsPage); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define QT_CREATOR_CDB_EXT "qtcreatorcdbext"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline Utils::SavedAction *theAssemblerAction() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |     return debuggerCore()->action(OperateByInstruction); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CdbEngine::CdbEngine(const DebuggerStartParameters &sp, const OptionsPtr &options) : | 
					
						
							|  |  |  |     DebuggerEngine(sp), | 
					
						
							|  |  |  |     m_creatorExtPrefix("<qtcreatorcdbext>|"), | 
					
						
							|  |  |  |     m_tokenPrefix("<token>"), | 
					
						
							|  |  |  |     m_options(options), | 
					
						
							|  |  |  |     m_inferiorPid(0), | 
					
						
							|  |  |  |     m_accessible(false), | 
					
						
							|  |  |  |     m_specialStopMode(NoSpecialStop), | 
					
						
							|  |  |  |     m_nextCommandToken(0), | 
					
						
							|  |  |  |     m_nextBreakpointNumber(1), | 
					
						
							|  |  |  |     m_currentBuiltinCommandIndex(-1), | 
					
						
							|  |  |  |     m_extensionCommandPrefixBA("!"QT_CREATOR_CDB_EXT"."), | 
					
						
							|  |  |  |     m_operateByInstructionPending(true), | 
					
						
							|  |  |  |     m_operateByInstruction(true), // Default CDB setting
 | 
					
						
							|  |  |  |     m_notifyEngineShutdownOnTermination(false), | 
					
						
							|  |  |  |     m_hasDebuggee(false), | 
					
						
							| 
									
										
										
										
											2011-01-05 11:34:35 +01:00
										 |  |  |     m_elapsedLogTime(0), | 
					
						
							|  |  |  |     m_sourceStepInto(false) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     Utils::SavedAction *assemblerAction = theAssemblerAction(); | 
					
						
							|  |  |  |     m_operateByInstructionPending = assemblerAction->isChecked(); | 
					
						
							|  |  |  |     connect(assemblerAction, SIGNAL(triggered(bool)), this, SLOT(operateByInstructionTriggered(bool))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     setObjectName(QLatin1String("CdbEngine")); | 
					
						
							|  |  |  |     connect(&m_process, SIGNAL(finished(int)), this, SLOT(processFinished())); | 
					
						
							|  |  |  |     connect(&m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError())); | 
					
						
							|  |  |  |     connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOut())); | 
					
						
							|  |  |  |     connect(&m_process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardOut())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CdbEngine::~CdbEngine() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::operateByInstructionTriggered(bool operateByInstruction) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  |     if (state() == InferiorStopOk) { | 
					
						
							|  |  |  |         syncOperateByInstruction(operateByInstruction); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         // To be set next time session becomes accessible
 | 
					
						
							|  |  |  |         m_operateByInstructionPending = operateByInstruction; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::syncOperateByInstruction(bool operateByInstruction) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_operateByInstruction == operateByInstruction) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     QTC_ASSERT(m_accessible, return; ) | 
					
						
							|  |  |  |     m_operateByInstruction = operateByInstruction; | 
					
						
							|  |  |  |     postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"), 0); | 
					
						
							|  |  |  |     postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"), 0); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-22 17:06:08 +01:00
										 |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << Q_FUNC_INFO; | 
					
						
							|  |  |  |     // Need a stopped debuggee and a cpp file in a valid frame
 | 
					
						
							|  |  |  |     if (state() != InferiorStopOk || !isCppEditor(editor) || stackHandler()->currentIndex() < 0) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     // Determine expression and function
 | 
					
						
							|  |  |  |     int line; | 
					
						
							|  |  |  |     int column; | 
					
						
							|  |  |  |     QString function; | 
					
						
							|  |  |  |     const QString exp = cppExpressionAt(editor, cursorPos, &line, &column, &function); | 
					
						
							|  |  |  |     // Are we in the current stack frame
 | 
					
						
							|  |  |  |     if (function.isEmpty() || exp.isEmpty() || function != stackHandler()->currentFrame().function) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     // No numerical or any other expressions [yet]
 | 
					
						
							|  |  |  |     if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_'))) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |     const QByteArray iname = QByteArray(localsPrefixC) + exp.toAscii(); | 
					
						
							|  |  |  |     if (const WatchData *data = watchHandler()->findItem(iname)) { | 
					
						
							|  |  |  |         QToolTip::hideText(); | 
					
						
							|  |  |  |         QToolTip::showText(mousePos, data->toToolTip()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::setupEngine() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:22:41 +01:00
										 |  |  |     // Nag to add symbol server
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     if (CdbSymbolPathListEditor::promptToAddSymbolServer(CdbOptions::settingsGroup(), | 
					
						
							|  |  |  |                                                          &(m_options->symbolPaths))) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:22:41 +01:00
										 |  |  |         m_options->toSettings(Core::ICore::instance()->settings()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     QString errorMessage; | 
					
						
							|  |  |  |     if (!doSetupEngine(&errorMessage)) { // Start engine which will run until initial breakpoint
 | 
					
						
							|  |  |  |         showMessage(errorMessage, LogError); | 
					
						
							|  |  |  |         notifyEngineSetupFailed(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Determine full path to the CDB extension library.
 | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  | QString CdbEngine::extensionLibraryName(bool is64Bit) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     // Determine extension lib name and path to use
 | 
					
						
							|  |  |  |     QString rc; | 
					
						
							|  |  |  |     QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path() | 
					
						
							|  |  |  |                      << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT"64" : QT_CREATOR_CDB_EXT"32") | 
					
						
							|  |  |  |                      << '/' << QT_CREATOR_CDB_EXT << ".dll"; | 
					
						
							|  |  |  |     return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Determine environment for CDB.exe, start out with run config and
 | 
					
						
							|  |  |  | // add CDB extension path merged with system value should there be one.
 | 
					
						
							|  |  |  | static QStringList mergeEnvironment(QStringList runConfigEnvironment, | 
					
						
							|  |  |  |                                     QString cdbExtensionPath) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Determine CDB extension path from Qt Creator
 | 
					
						
							|  |  |  |     static const char cdbExtensionPathVariableC[] = "_NT_DEBUGGER_EXTENSION_PATH"; | 
					
						
							|  |  |  |     const QByteArray oldCdbExtensionPath = qgetenv(cdbExtensionPathVariableC); | 
					
						
							|  |  |  |     if (!oldCdbExtensionPath.isEmpty()) { | 
					
						
							|  |  |  |         cdbExtensionPath.append(QLatin1Char(';')); | 
					
						
							|  |  |  |         cdbExtensionPath.append(QString::fromLocal8Bit(oldCdbExtensionPath)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // We do not assume someone sets _NT_DEBUGGER_EXTENSION_PATH in the run
 | 
					
						
							|  |  |  |     // config, just to make sure, delete any existing entries
 | 
					
						
							|  |  |  |     const QString cdbExtensionPathVariableAssign = | 
					
						
							|  |  |  |             QLatin1String(cdbExtensionPathVariableC) + QLatin1Char('='); | 
					
						
							|  |  |  |     for (QStringList::iterator it = runConfigEnvironment.begin(); it != runConfigEnvironment.end() ; ) { | 
					
						
							|  |  |  |         if (it->startsWith(cdbExtensionPathVariableAssign)) { | 
					
						
							|  |  |  |             it = runConfigEnvironment.erase(it); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             ++it; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     runConfigEnvironment.append(cdbExtensionPathVariableAssign + | 
					
						
							|  |  |  |                                 QDir::toNativeSeparators(cdbExtensionPath)); | 
					
						
							|  |  |  |     return runConfigEnvironment; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CdbEngine::elapsedLogTime() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const int elapsed = m_logTime.elapsed(); | 
					
						
							|  |  |  |     const int delta = elapsed - m_elapsedLogTime; | 
					
						
							|  |  |  |     m_elapsedLogTime = elapsed; | 
					
						
							|  |  |  |     return delta; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool CdbEngine::doSetupEngine(QString *errorMessage) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_logTime.start(); | 
					
						
							|  |  |  |     // Determine extension lib name and path to use
 | 
					
						
							|  |  |  |     // The extension is passed as relative name with the path variable set
 | 
					
						
							|  |  |  |     //(does not work with absolute path names)
 | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     const QFileInfo extensionFi(CdbEngine::extensionLibraryName(m_options->is64bit)); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     if (!extensionFi.isFile()) { | 
					
						
							|  |  |  |         *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found."). | 
					
						
							|  |  |  |                 arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath())); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     const QString extensionFileName = extensionFi.fileName(); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     // Prepare arguments
 | 
					
						
							|  |  |  |     const DebuggerStartParameters &sp = startParameters(); | 
					
						
							|  |  |  |     QStringList arguments; | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     const bool isRemote = sp.startMode == AttachToRemote; | 
					
						
							|  |  |  |     if (isRemote) { // Must be first
 | 
					
						
							|  |  |  |         arguments << QLatin1String("-remote") << sp.remoteChannel; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         arguments << (QLatin1String("-a") + extensionFileName); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     // Source line info/No terminal breakpoint / Pull extension
 | 
					
						
							|  |  |  |     arguments << QLatin1String("-lines") << QLatin1String("-G") | 
					
						
							|  |  |  |     // register idle (debuggee stop) notification
 | 
					
						
							|  |  |  |               << QLatin1String("-c") | 
					
						
							|  |  |  |               << QString::fromAscii(".idle_cmd " + m_extensionCommandPrefixBA + "idle"); | 
					
						
							|  |  |  |     if (sp.useTerminal) // Separate console
 | 
					
						
							|  |  |  |         arguments << QLatin1String("-2"); | 
					
						
							|  |  |  |     if (!m_options->symbolPaths.isEmpty()) | 
					
						
							|  |  |  |         arguments << QLatin1String("-y") << m_options->symbolPaths.join(QString(QLatin1Char(';'))); | 
					
						
							|  |  |  |     if (!m_options->sourcePaths.isEmpty()) | 
					
						
							|  |  |  |         arguments << QLatin1String("-srcpath") << m_options->sourcePaths.join(QString(QLatin1Char(';'))); | 
					
						
							|  |  |  |     switch (sp.startMode) { | 
					
						
							|  |  |  |     case StartInternal: | 
					
						
							|  |  |  |     case StartExternal: | 
					
						
							| 
									
										
										
										
											2010-11-18 16:06:02 +01:00
										 |  |  |         arguments << QDir::toNativeSeparators(sp.executable); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     case AttachToRemote: | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     case AttachExternal: | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     case AttachCrashedExternal: | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         arguments << QLatin1String("-p") << QString::number(sp.attachPID); | 
					
						
							|  |  |  |         if (sp.startMode == AttachCrashedExternal) | 
					
						
							|  |  |  |             arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const QString executable = m_options->executable; | 
					
						
							|  |  |  |     const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4."). | 
					
						
							|  |  |  |             arg(QDir::toNativeSeparators(executable), | 
					
						
							|  |  |  |                 arguments.join(QString(QLatin1Char(' '))), | 
					
						
							|  |  |  |                 QDir::toNativeSeparators(extensionFi.absoluteFilePath()), | 
					
						
							|  |  |  |                 extensionFi.lastModified().toString(Qt::SystemLocaleShortDate)); | 
					
						
							|  |  |  |     showMessage(msg, LogMisc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_outputBuffer.clear(); | 
					
						
							|  |  |  |     m_process.setEnvironment(mergeEnvironment(sp.environment.toStringList(), extensionFi.absolutePath())); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:06:02 +01:00
										 |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  |     if (!sp.processArgs.isEmpty()) // Appends
 | 
					
						
							|  |  |  |         m_process.setNativeArguments(sp.processArgs); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     m_process.start(executable, arguments); | 
					
						
							|  |  |  |     if (!m_process.waitForStarted()) { | 
					
						
							|  |  |  |         *errorMessage = QString::fromLatin1("Internal error: Cannot start process %1: %2"). | 
					
						
							|  |  |  |                 arg(QDir::toNativeSeparators(executable), m_process.errorString()); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  |     const unsigned long pid = Utils::winQPidToPid(m_process.pid()); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     const unsigned long pid = 0; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     showMessage(QString::fromLatin1("%1 running as %2"). | 
					
						
							|  |  |  |                 arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc); | 
					
						
							|  |  |  |     m_hasDebuggee = true; | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     if (isRemote) { // We do not get an 'idle' in a remote session, but are accessible
 | 
					
						
							|  |  |  |         m_accessible = true; | 
					
						
							|  |  |  |         const QByteArray loadCommand = QByteArray(".load ") | 
					
						
							|  |  |  |                 + extensionFileName.toLocal8Bit(); | 
					
						
							|  |  |  |         postCommand(loadCommand, 0); | 
					
						
							|  |  |  |         notifyEngineSetupOk(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::setupInferior() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("setupInferior"); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     attemptBreakpointSynchronization(); | 
					
						
							|  |  |  |     postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::runEngine() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("runEngine"); | 
					
						
							| 
									
										
										
										
											2010-12-17 12:00:44 +01:00
										 |  |  |     foreach (const QString &breakEvent, m_options->breakEvents) | 
					
						
							|  |  |  |             postCommand(QByteArray("sxe ") + breakEvent.toAscii(), 0); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     postCommand("g", 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-16 12:17:54 +01:00
										 |  |  | bool CdbEngine::commandsPending() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | void CdbEngine::shutdownInferior() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::shutdownInferior in state '%s', process running %d", stateName(state()), | 
					
						
							|  |  |  |                isCdbProcessRunning()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
 | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyInferiorShutdownOk"); | 
					
						
							|  |  |  |         notifyInferiorShutdownOk(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-12-16 12:17:54 +01:00
										 |  |  |     if (!canInterruptInferior() || commandsPending()) { | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |         notifyInferiorShutdownFailed(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     if (m_accessible) { | 
					
						
							|  |  |  |         if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal) | 
					
						
							|  |  |  |             detachDebugger(); | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyInferiorShutdownOk"); | 
					
						
							|  |  |  |         notifyInferiorShutdownOk(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         interruptInferior(); // Calls us again
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* shutdownEngine/processFinished:
 | 
					
						
							|  |  |  |  * Note that in the case of launching a process by the debugger, the debugger | 
					
						
							|  |  |  |  * automatically quits a short time after reporting the session becoming | 
					
						
							|  |  |  |  * inaccessible without debuggee (notifyInferiorExited). In that case, | 
					
						
							|  |  |  |  * processFinished() must not report any arbitrarily notifyEngineShutdownOk() | 
					
						
							|  |  |  |  * as not to confuse the state engine. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::shutdownEngine() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							| 
									
										
										
										
											2010-12-16 12:17:54 +01:00
										 |  |  |         qDebug("CdbEngine::shutdownEngine in state '%s', process running %d," | 
					
						
							|  |  |  |                "accessible=%d,commands pending=%d", | 
					
						
							|  |  |  |                stateName(state()), isCdbProcessRunning(), m_accessible, | 
					
						
							|  |  |  |                commandsPending()); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
 | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyEngineShutdownOk"); | 
					
						
							|  |  |  |         notifyEngineShutdownOk(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-16 12:17:54 +01:00
										 |  |  |     // No longer trigger anything from messages
 | 
					
						
							|  |  |  |     disconnect(&m_process, SIGNAL(readyReadStandardOutput()), this, 0); | 
					
						
							|  |  |  |     disconnect(&m_process, SIGNAL(readyReadStandardError()), this, 0); | 
					
						
							|  |  |  |     // Go for kill if there are commands pending.
 | 
					
						
							|  |  |  |     if (m_accessible && !commandsPending()) { | 
					
						
							|  |  |  |         // detach: Wait for debugger to finish.
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         if (startParameters().startMode == AttachExternal) | 
					
						
							|  |  |  |             detachDebugger(); | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |         // Remote requires a bit more force to quit.
 | 
					
						
							|  |  |  |         if (startParameters().startMode == AttachToRemote) { | 
					
						
							|  |  |  |             postCommand(m_extensionCommandPrefixBA + "shutdownex", 0); | 
					
						
							|  |  |  |             postCommand("qq", 0); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             postCommand("q", 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         m_notifyEngineShutdownOnTermination = true; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         // Remote process. No can do, currently
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         m_notifyEngineShutdownOnTermination = true; | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |         Utils::SynchronousProcess::stopProcess(m_process); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Lost debuggee, debugger should quit anytime now
 | 
					
						
							|  |  |  |     if (!m_hasDebuggee) { | 
					
						
							|  |  |  |         m_notifyEngineShutdownOnTermination = true; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     interruptInferior(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::processFinished() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::processFinished %dms '%s' notify=%d (exit state=%d, ex=%d)", | 
					
						
							|  |  |  |                elapsedLogTime(), stateName(state()), m_notifyEngineShutdownOnTermination, | 
					
						
							|  |  |  |                m_process.exitStatus(), m_process.exitCode()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const bool crashed = m_process.exitStatus() == QProcess::CrashExit; | 
					
						
							|  |  |  |     if (crashed) { | 
					
						
							|  |  |  |         showMessage(tr("CDB crashed"), LogError); // not in your life.
 | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         showMessage(tr("CDB exited (%1)").arg(m_process.exitCode()), LogMisc); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_notifyEngineShutdownOnTermination) { | 
					
						
							|  |  |  |         if (crashed) { | 
					
						
							|  |  |  |             if (debug) | 
					
						
							|  |  |  |                 qDebug("notifyEngineIll"); | 
					
						
							|  |  |  |             notifyEngineIll(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             if (debug) | 
					
						
							|  |  |  |                 qDebug("notifyEngineShutdownOk"); | 
					
						
							|  |  |  |             notifyEngineShutdownOk(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyEngineSpontaneousShutdown"); | 
					
						
							|  |  |  |         notifyEngineSpontaneousShutdown(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::detachDebugger() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommand(".detach", 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | void CdbEngine::updateWatchData(const WatchData &dataIn, | 
					
						
							|  |  |  |                                 const WatchUpdateFlags & flags) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::updateWatchData() %dms %s incr=%d: %s", | 
					
						
							|  |  |  |                elapsedLogTime(), stateName(state()), | 
					
						
							|  |  |  |                flags.tryIncremental, | 
					
						
							|  |  |  |                qPrintable(dataIn.toString())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!dataIn.hasChildren) { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         WatchData data = dataIn; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         data.setAllUnneeded(); | 
					
						
							|  |  |  |         watchHandler()->insertData(data); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     updateLocalVariable(dataIn.iname); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-09 17:04:43 +01:00
										 |  |  | void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-01-06 12:53:54 +01:00
										 |  |  |     if (debuggerCore()->boolSetting(VerboseLog)) | 
					
						
							|  |  |  |         str << blankSeparator << "-v"; | 
					
						
							| 
									
										
										
										
											2010-12-09 17:04:43 +01:00
										 |  |  |     if (debuggerCore()->boolSetting(UseDebuggingHelpers)) | 
					
						
							|  |  |  |         str << blankSeparator << "-c"; | 
					
						
							|  |  |  |     const QByteArray typeFormats = watchHandler()->typeFormatRequests(); | 
					
						
							|  |  |  |     if (!typeFormats.isEmpty()) | 
					
						
							|  |  |  |         str << blankSeparator << "-T " << typeFormats; | 
					
						
							|  |  |  |     const QByteArray individualFormats = watchHandler()->individualFormatRequests(); | 
					
						
							|  |  |  |     if (!individualFormats.isEmpty()) | 
					
						
							|  |  |  |         str << blankSeparator << "-I " << individualFormats; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | void CdbEngine::updateLocalVariable(const QByteArray &iname) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const int stackFrame = stackHandler()->currentIndex(); | 
					
						
							|  |  |  |     if (stackFrame >= 0) { | 
					
						
							|  |  |  |         QByteArray localsArguments; | 
					
						
							|  |  |  |         ByteArrayInputStream str(localsArguments); | 
					
						
							| 
									
										
										
										
											2010-12-09 17:04:43 +01:00
										 |  |  |         addLocalsOptions(str); | 
					
						
							|  |  |  |         str << blankSeparator << stackFrame <<  ' ' << iname; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         postExtensionCommand("locals", localsArguments, 0, &CdbEngine::handleLocals); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         qWarning("Internal error; no stack frame in updateLocalVariable"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned CdbEngine::debuggerCapabilities() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return DisassemblerCapability | RegisterCapability | ShowMemoryCapability | 
					
						
							|  |  |  |            |WatchpointCapability|JumpToLineCapability | 
					
						
							|  |  |  |            |BreakOnThrowAndCatchCapability; // Sort-of: Can break on throw().
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeStep() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommand(QByteArray("t"), 0); // Step into-> t (trace)
 | 
					
						
							| 
									
										
										
										
											2011-01-05 11:34:35 +01:00
										 |  |  |     if (!m_operateByInstruction) | 
					
						
							|  |  |  |         m_sourceStepInto = true; // See explanation at handleStackTrace().
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     notifyInferiorRunRequested(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeStepOut() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommand(QByteArray("gu"), 0); // Step out-> gu (go up)
 | 
					
						
							|  |  |  |     notifyInferiorRunRequested(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeNext() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommand(QByteArray("p"), 0); // Step over -> p
 | 
					
						
							|  |  |  |     notifyInferiorRunRequested(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeStepI() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     executeStep(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeNextI() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     executeNext(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::continueInferior() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     notifyInferiorRunRequested(); | 
					
						
							|  |  |  |     doContinueInferior(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::doContinueInferior() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommand(QByteArray("g"), 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  | bool CdbEngine::canInterruptInferior() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return startParameters().startMode != AttachToRemote; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | void CdbEngine::interruptInferior() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-19 16:13:22 +01:00
										 |  |  |     if (canInterruptInferior()) { | 
					
						
							|  |  |  |         doInterruptInferior(NoSpecialStop); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         showMessage(tr("Interrupting is not possible in remote sessions."), LogError); | 
					
						
							|  |  |  |         notifyInferiorStopOk(); | 
					
						
							|  |  |  |         notifyInferiorRunRequested(); | 
					
						
							|  |  |  |         notifyInferiorRunOk(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::doInterruptInferior(SpecialStopMode sm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  |     const SpecialStopMode oldSpecialMode = m_specialStopMode; | 
					
						
							|  |  |  |     m_specialStopMode = sm; | 
					
						
							|  |  |  |     QString errorMessage; | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     if (!winDebugBreakProcess(m_inferiorPid, &errorMessage)) { | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         m_specialStopMode = oldSpecialMode; | 
					
						
							|  |  |  |         showMessage(errorMessage, LogError); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     Q_UNUSED(sm) | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeRunToLine(const QString &fileName, int lineNumber) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Add one-shot breakpoint
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     BreakpointParameters bp(BreakpointByFileAndLine); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     bp.fileName = fileName; | 
					
						
							|  |  |  |     bp.lineNumber = lineNumber; | 
					
						
							|  |  |  |     postCommand(cdbAddBreakpointCommand(bp, true), 0); | 
					
						
							|  |  |  |     continueInferior(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeRunToFunction(const QString &functionName) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Add one-shot breakpoint
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     BreakpointParameters bp(BreakpointByFunction); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     bp.functionName = functionName; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     postCommand(cdbAddBreakpointCommand(bp, true), 0); | 
					
						
							|  |  |  |     continueInferior(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::setRegisterValue(int regnr, const QString &value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     const Registers registers = registerHandler()->registers(); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     QTC_ASSERT(regnr < registers.size(), return) | 
					
						
							|  |  |  |     // Value is decimal or 0x-hex-prefixed
 | 
					
						
							|  |  |  |     QByteArray cmd; | 
					
						
							|  |  |  |     ByteArrayInputStream str(cmd); | 
					
						
							|  |  |  |     str << "r " << registers.at(regnr).name << '=' << value; | 
					
						
							|  |  |  |     postCommand(cmd, 0); | 
					
						
							|  |  |  |     reloadRegisters(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeJumpToLine(const QString & fileName, int lineNumber) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QByteArray cmd; | 
					
						
							|  |  |  |     ByteArrayInputStream str(cmd); | 
					
						
							|  |  |  |     // Resolve source line address and go to that location
 | 
					
						
							|  |  |  |     str << "? `" << QDir::toNativeSeparators(fileName) << ':' << lineNumber << '`'; | 
					
						
							|  |  |  |     const QVariant cookie = qVariantFromValue(SourceLocationCookie(fileName, lineNumber)); | 
					
						
							|  |  |  |     postBuiltinCommand(cmd, 0, &CdbEngine::handleJumpToLineAddressResolution, 0, cookie); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (cmd->reply.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     // Evaluate expression: 5365511549 = 00000001`3fcf357d
 | 
					
						
							|  |  |  |     // Set register 'rip' to hex address and goto lcoation
 | 
					
						
							|  |  |  |     QByteArray answer = cmd->reply.front(); | 
					
						
							|  |  |  |     const int equalPos = answer.indexOf(" = "); | 
					
						
							|  |  |  |     if (equalPos == -1) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     answer.remove(0, equalPos + 3); | 
					
						
							|  |  |  |     QTC_ASSERT(qVariantCanConvert<SourceLocationCookie>(cmd->cookie), return ; ) | 
					
						
							|  |  |  |     const SourceLocationCookie cookie = qvariant_cast<SourceLocationCookie>(cmd->cookie); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QByteArray registerCmd; | 
					
						
							|  |  |  |     ByteArrayInputStream str(registerCmd); | 
					
						
							| 
									
										
										
										
											2010-12-13 17:19:21 +01:00
										 |  |  |     // PC-register depending on 64/32bit.
 | 
					
						
							|  |  |  |     str << "r " << (m_options->is64bit ? "rip" : "eip") << "=0x" << answer; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     postCommand(registerCmd, 0); | 
					
						
							| 
									
										
										
										
											2010-12-16 19:06:33 +01:00
										 |  |  |     gotoLocation(Location(cookie.fileName, cookie.lineNumber)); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << "CdbEngine::assignValueInDebugger" << w->iname << expr << value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (state() != InferiorStopOk || stackHandler()->currentIndex() < 0) { | 
					
						
							|  |  |  |         qWarning("Internal error: assignValueInDebugger: Invalid state or no stack frame."); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QByteArray cmd; | 
					
						
							|  |  |  |     ByteArrayInputStream str(cmd); | 
					
						
							|  |  |  |     str << m_extensionCommandPrefixBA << "assign " << w->iname << '=' << value.toString(); | 
					
						
							|  |  |  |     postCommand(cmd, 0); | 
					
						
							| 
									
										
										
										
											2011-01-11 14:58:32 +01:00
										 |  |  |     // Update all locals in case we change a union or something pointed to
 | 
					
						
							|  |  |  |     // that affects other variables, too.
 | 
					
						
							|  |  |  |     updateLocals(); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleThreads(const CdbExtensionCommandPtr &reply) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::handleThreads success=%d", reply->success); | 
					
						
							|  |  |  |     if (reply->success) { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         GdbMi data; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         data.fromString(reply->reply); | 
					
						
							|  |  |  |         int currentThreadId; | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         Threads threads = ThreadsHandler::parseGdbmiThreads(data, ¤tThreadId); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         threadsHandler()->setThreads(threads); | 
					
						
							|  |  |  |         threadsHandler()->setCurrentThreadId(currentThreadId); | 
					
						
							|  |  |  |         // Continue sequence
 | 
					
						
							|  |  |  |         postCommandSequence(reply->commandSequence); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         showMessage(QString::fromLatin1(reply->errorMessage), LogError); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::executeDebuggerCommand(const QString &command) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommand(command.toLocal8Bit(), QuietCommand); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Post command without callback
 | 
					
						
							|  |  |  | void CdbEngine::postCommand(const QByteArray &cmd, unsigned flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::postCommand %dms '%s' %u %s\n", | 
					
						
							|  |  |  |                elapsedLogTime(), cmd.constData(), flags, stateName(state())); | 
					
						
							|  |  |  |     if (!(flags & QuietCommand)) | 
					
						
							|  |  |  |         showMessage(QString::fromLocal8Bit(cmd), LogInput); | 
					
						
							|  |  |  |     m_process.write(cmd + '\n'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Post a built-in-command producing free-format output with a callback.
 | 
					
						
							|  |  |  | // In order to catch the output, it is enclosed in 'echo' commands
 | 
					
						
							|  |  |  | // printing a specially formatted token to be identifiable in the output.
 | 
					
						
							|  |  |  | void CdbEngine::postBuiltinCommand(const QByteArray &cmd, unsigned flags, | 
					
						
							|  |  |  |                                    BuiltinCommandHandler handler, | 
					
						
							|  |  |  |                                    unsigned nextCommandFlag, | 
					
						
							|  |  |  |                                    const QVariant &cookie) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_accessible) { | 
					
						
							|  |  |  |         const QString msg = QString::fromLatin1("Attempt to issue builtin command '%1' to non-accessible session (%2)") | 
					
						
							|  |  |  |                 .arg(QString::fromLocal8Bit(cmd), QString::fromAscii(stateName(state()))); | 
					
						
							|  |  |  |         showMessage(msg, LogError); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!flags & QuietCommand) | 
					
						
							|  |  |  |         showMessage(QString::fromLocal8Bit(cmd), LogInput); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int token = m_nextCommandToken++; | 
					
						
							|  |  |  |     CdbBuiltinCommandPtr pendingCommand(new CdbBuiltinCommand(cmd, token, flags, handler, nextCommandFlag, cookie)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_builtinCommandQueue.push_back(pendingCommand); | 
					
						
							|  |  |  |     // Enclose command in echo-commands for token
 | 
					
						
							|  |  |  |     QByteArray fullCmd; | 
					
						
							|  |  |  |     ByteArrayInputStream str(fullCmd); | 
					
						
							|  |  |  |     str << ".echo \"" << m_tokenPrefix << token << "<\"\n" | 
					
						
							|  |  |  |             << cmd << "\n.echo \"" << m_tokenPrefix << token << ">\"\n"; | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::postBuiltinCommand %dms '%s' flags=%u token=%d %s next=%u, cookie='%s', pending=%d, sequence=0x%x", | 
					
						
							|  |  |  |                elapsedLogTime(), cmd.constData(), flags, token, stateName(state()), nextCommandFlag, qPrintable(cookie.toString()), | 
					
						
							|  |  |  |                m_builtinCommandQueue.size(), nextCommandFlag); | 
					
						
							|  |  |  |     if (debug > 1) | 
					
						
							|  |  |  |         qDebug("CdbEngine::postBuiltinCommand: resulting command '%s'\n", | 
					
						
							|  |  |  |                fullCmd.constData()); | 
					
						
							|  |  |  |     m_process.write(fullCmd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Post an extension command producing one-line output with a callback,
 | 
					
						
							|  |  |  | // pass along token for identification in queue.
 | 
					
						
							|  |  |  | void CdbEngine::postExtensionCommand(const QByteArray &cmd, | 
					
						
							|  |  |  |                                      const QByteArray &arguments, | 
					
						
							|  |  |  |                                      unsigned flags, | 
					
						
							|  |  |  |                                      ExtensionCommandHandler handler, | 
					
						
							|  |  |  |                                      unsigned nextCommandFlag, | 
					
						
							|  |  |  |                                      const QVariant &cookie) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_accessible) { | 
					
						
							|  |  |  |         const QString msg = QString::fromLatin1("Attempt to issue extension command '%1' to non-accessible session (%2)") | 
					
						
							|  |  |  |                 .arg(QString::fromLocal8Bit(cmd), QString::fromAscii(stateName(state()))); | 
					
						
							|  |  |  |         showMessage(msg, LogError); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int token = m_nextCommandToken++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Format full command with token to be recognizeable in the output
 | 
					
						
							|  |  |  |     QByteArray fullCmd; | 
					
						
							|  |  |  |     ByteArrayInputStream str(fullCmd); | 
					
						
							|  |  |  |     str << m_extensionCommandPrefixBA << cmd << " -t " << token; | 
					
						
							|  |  |  |     if (!arguments.isEmpty()) | 
					
						
							|  |  |  |         str <<  ' ' << arguments; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |     if (!flags & QuietCommand) | 
					
						
							|  |  |  |         showMessage(QString::fromLocal8Bit(fullCmd), LogInput); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     CdbExtensionCommandPtr pendingCommand(new CdbExtensionCommand(fullCmd, token, flags, handler, nextCommandFlag, cookie)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_extensionCommandQueue.push_back(pendingCommand); | 
					
						
							|  |  |  |     // Enclose command in echo-commands for token
 | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::postExtensionCommand %dms '%s' flags=%u token=%d %s next=%u, cookie='%s', pending=%d, sequence=0x%x", | 
					
						
							|  |  |  |                elapsedLogTime(), fullCmd.constData(), flags, token, stateName(state()), nextCommandFlag, qPrintable(cookie.toString()), | 
					
						
							|  |  |  |                m_extensionCommandQueue.size(), nextCommandFlag); | 
					
						
							|  |  |  |     m_process.write(fullCmd + '\n'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::activateFrame(int index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // TODO: assembler,etc
 | 
					
						
							|  |  |  |     if (index < 0) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     const StackFrames &frames = stackHandler()->frames(); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     QTC_ASSERT(index < frames.size(), return; ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |     const StackFrame frame = frames.at(index); | 
					
						
							|  |  |  |     if (debug || debugLocals) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         qDebug("activateFrame idx=%d '%s' %d", index, | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |                qPrintable(frame.file), frame.line); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     stackHandler()->setCurrentIndex(index); | 
					
						
							|  |  |  |     const bool showAssembler = !frames.at(index).isUsable(); | 
					
						
							|  |  |  |     if (showAssembler) { // Assembly code: Clean out model and force instruction mode.
 | 
					
						
							|  |  |  |         watchHandler()->beginCycle(); | 
					
						
							|  |  |  |         watchHandler()->endCycle(); | 
					
						
							|  |  |  |         QAction *assemblerAction = theAssemblerAction(); | 
					
						
							|  |  |  |         if (assemblerAction->isChecked()) { | 
					
						
							| 
									
										
										
										
											2010-12-16 19:06:33 +01:00
										 |  |  |             gotoLocation(frame); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             assemblerAction->trigger(); // Seems to trigger update
 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-01-11 14:58:32 +01:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         gotoLocation(frame); | 
					
						
							|  |  |  |         updateLocals(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::updateLocals() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const int frameIndex = stackHandler()->currentIndex(); | 
					
						
							|  |  |  |     if (frameIndex < 0) { | 
					
						
							|  |  |  |         watchHandler()->beginCycle(); | 
					
						
							|  |  |  |         watchHandler()->endCycle(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const StackFrame frame = stackHandler()->currentFrame(); | 
					
						
							|  |  |  |     if (!frame.isUsable()) { | 
					
						
							|  |  |  |         watchHandler()->beginCycle(); | 
					
						
							|  |  |  |         watchHandler()->endCycle(); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |     // Watchers: Initial expand, get uninitialized and query
 | 
					
						
							|  |  |  |     QByteArray arguments; | 
					
						
							|  |  |  |     ByteArrayInputStream str(arguments); | 
					
						
							|  |  |  |     // Pre-expand
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     const QSet<QByteArray> expanded = watchHandler()->expandedINames(); | 
					
						
							|  |  |  |     if (!expanded.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |         str << blankSeparator << "-e "; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         int i = 0; | 
					
						
							|  |  |  |         foreach(const QByteArray &e, expanded) { | 
					
						
							|  |  |  |             if (i++) | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |                 str << ','; | 
					
						
							|  |  |  |             str << e; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-12-09 17:04:43 +01:00
										 |  |  |     addLocalsOptions(str); | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |     // Uninitialized variables if desired
 | 
					
						
							|  |  |  |     if (debuggerCore()->boolSetting(UseCodeModel)) { | 
					
						
							|  |  |  |         QStringList uninitializedVariables; | 
					
						
							|  |  |  |         getUninitializedVariables(debuggerCore()->cppCodeModelSnapshot(), | 
					
						
							|  |  |  |                                   frame.function, frame.file, frame.line, &uninitializedVariables); | 
					
						
							|  |  |  |         if (!uninitializedVariables.isEmpty()) { | 
					
						
							|  |  |  |             str << blankSeparator << "-u "; | 
					
						
							|  |  |  |             int i = 0; | 
					
						
							|  |  |  |             foreach(const QString &u, uninitializedVariables) { | 
					
						
							|  |  |  |                 if (i++) | 
					
						
							|  |  |  |                     str << ','; | 
					
						
							|  |  |  |                 str << localsPrefixC << u; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Required arguments: frame
 | 
					
						
							| 
									
										
										
										
											2011-01-11 14:58:32 +01:00
										 |  |  |     str << blankSeparator << frameIndex; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     watchHandler()->beginCycle(); | 
					
						
							| 
									
										
										
										
											2010-11-23 13:36:39 +01:00
										 |  |  |     postExtensionCommand("locals", arguments, 0, &CdbEngine::handleLocals); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::selectThread(int index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (index < 0 || index == threadsHandler()->currentThread()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     resetLocation(); | 
					
						
							|  |  |  |     const int newThreadId = threadsHandler()->threads().at(index).id; | 
					
						
							|  |  |  |     threadsHandler()->setCurrentThread(index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const QByteArray cmd = "~" + QByteArray::number(newThreadId) + " s"; | 
					
						
							|  |  |  |     postBuiltinCommand(cmd, 0, &CdbEngine::dummyHandler, CommandListStack); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | void CdbEngine::fetchDisassembler(DisassemblerAgent *agent) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(m_accessible, return;) | 
					
						
							|  |  |  |     QByteArray cmd; | 
					
						
							|  |  |  |     ByteArrayInputStream str(cmd); | 
					
						
							|  |  |  |     str <<  "u " << hex << hexPrefixOn << agent->address() << " L40"; | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     const QVariant cookie = qVariantFromValue<DisassemblerAgent*>(agent); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     postBuiltinCommand(cmd, 0, &CdbEngine::handleDisassembler, 0, cookie); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Parse: "00000000`77606060 cc              int     3"
 | 
					
						
							|  |  |  | void CdbEngine::handleDisassembler(const CdbBuiltinCommandPtr &command) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     QTC_ASSERT(qVariantCanConvert<DisassemblerAgent*>(command->cookie), return;) | 
					
						
							|  |  |  |     DisassemblerAgent *agent = qvariant_cast<DisassemblerAgent*>(command->cookie); | 
					
						
							| 
									
										
										
										
											2010-11-24 16:51:02 +01:00
										 |  |  |     DisassemblerLines disassemblerLines; | 
					
						
							|  |  |  |     foreach(const QByteArray &line, command->reply) | 
					
						
							|  |  |  |         disassemblerLines.appendLine(DisassemblerLine(QString::fromLatin1(line))); | 
					
						
							|  |  |  |     agent->setContents(disassemblerLines); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-12-17 15:34:18 +01:00
										 |  |  |     if (!m_accessible) { | 
					
						
							|  |  |  |         qWarning("Internal error: Attempt to read memory from inaccessible session: %s", Q_FUNC_INFO); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::fetchMemory %llu bytes from 0x%llx", length, addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QByteArray args; | 
					
						
							|  |  |  |     ByteArrayInputStream str(args); | 
					
						
							|  |  |  |     str << addr << ' ' << length; | 
					
						
							|  |  |  |     const QVariant cookie = qVariantFromValue<MemoryViewCookie>(MemoryViewCookie(agent, editor, addr, length)); | 
					
						
							|  |  |  |     postExtensionCommand("memory", args, 0, &CdbEngine::handleMemory, 0, cookie); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleMemory(const CdbExtensionCommandPtr &command) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(qVariantCanConvert<MemoryViewCookie>(command->cookie), return;) | 
					
						
							|  |  |  |     const MemoryViewCookie memViewCookie = qvariant_cast<MemoryViewCookie>(command->cookie); | 
					
						
							|  |  |  |     if (command->success) { | 
					
						
							|  |  |  |         const QByteArray data = QByteArray::fromBase64(command->reply); | 
					
						
							|  |  |  |         if (unsigned(data.size()) == memViewCookie.length) | 
					
						
							|  |  |  |             memViewCookie.agent->addLazyData(memViewCookie.editorToken, | 
					
						
							|  |  |  |                                              memViewCookie.address, data); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         showMessage(QString::fromLocal8Bit(command->errorMessage), LogError); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::reloadModules() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommandSequence(CommandListModules); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::loadSymbols(const QString & /* moduleName */) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::loadAllSymbols() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::requestModuleSymbols(const QString &moduleName) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Q_UNUSED(moduleName) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::reloadRegisters() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommandSequence(CommandListRegisters); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::reloadSourceFiles() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::reloadFullStack() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("%s", Q_FUNC_INFO); | 
					
						
							|  |  |  |     postCommandSequence(CommandListStack); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handlePid(const CdbExtensionCommandPtr &reply) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (reply->success) { | 
					
						
							|  |  |  |         m_inferiorPid = reply->reply.toUInt(); | 
					
						
							|  |  |  |         showMessage(QString::fromLatin1("Inferior pid: %1."), LogMisc); | 
					
						
							|  |  |  |         notifyInferiorSetupOk(); | 
					
						
							|  |  |  |     }  else { | 
					
						
							|  |  |  |         showMessage(QString::fromLatin1("Failed to determine inferior pid: %1"). | 
					
						
							|  |  |  |                     arg(QLatin1String(reply->errorMessage)), LogError); | 
					
						
							|  |  |  |         notifyInferiorSetupFailed(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Parse CDB gdbmi register syntax
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | static inline Register parseRegister(const GdbMi &gdbmiReg) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     Register reg; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     reg.name = gdbmiReg.findChild("name").data(); | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     const GdbMi description = gdbmiReg.findChild("description"); | 
					
						
							|  |  |  |     if (description.type() != GdbMi::Invalid) { | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         reg.name += " ("; | 
					
						
							|  |  |  |         reg.name += description.data(); | 
					
						
							|  |  |  |         reg.name += ')'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     reg.value = QString::fromAscii(gdbmiReg.findChild("value").data()); | 
					
						
							|  |  |  |     return reg; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleModules(const CdbExtensionCommandPtr &reply) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (reply->success) { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         GdbMi value; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         value.fromString(reply->reply); | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         if (value.type() == GdbMi::List) { | 
					
						
							|  |  |  |             Modules modules; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             modules.reserve(value.childCount()); | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |             foreach (const GdbMi &gdbmiModule, value.children()) { | 
					
						
							|  |  |  |                 Module module; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |                 module.moduleName = QString::fromAscii(gdbmiModule.findChild("name").data()); | 
					
						
							|  |  |  |                 module.modulePath = QString::fromAscii(gdbmiModule.findChild("image").data()); | 
					
						
							| 
									
										
										
										
											2010-12-21 13:34:59 +01:00
										 |  |  |                 module.startAddress = gdbmiModule.findChild("start").data().toULongLong(0, 0); | 
					
						
							|  |  |  |                 module.endAddress = gdbmiModule.findChild("end").data().toULongLong(0, 0); | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |                 if (gdbmiModule.findChild("deferred").type() == GdbMi::Invalid) | 
					
						
							|  |  |  |                     module.symbolsRead = Module::ReadOk; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |                 modules.push_back(module); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             modulesHandler()->setModules(modules); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             showMessage(QString::fromLatin1("Parse error in modules response."), LogError); | 
					
						
							|  |  |  |             qWarning("Parse error in modules response:\n%s", reply->reply.constData()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }  else { | 
					
						
							|  |  |  |         showMessage(QString::fromLatin1("Failed to determine modules: %1"). | 
					
						
							|  |  |  |                     arg(QLatin1String(reply->errorMessage)), LogError); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     postCommandSequence(reply->commandSequence); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (reply->success) { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         GdbMi value; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         value.fromString(reply->reply); | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         if (value.type() == GdbMi::List) { | 
					
						
							|  |  |  |             Registers registers; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             registers.reserve(value.childCount()); | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |             foreach (const GdbMi &gdbmiReg, value.children()) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |                 registers.push_back(parseRegister(gdbmiReg)); | 
					
						
							|  |  |  |             registerHandler()->setRegisters(registers); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             showMessage(QString::fromLatin1("Parse error in registers response."), LogError); | 
					
						
							|  |  |  |             qWarning("Parse error in registers response:\n%s", reply->reply.constData()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }  else { | 
					
						
							|  |  |  |         showMessage(QString::fromLatin1("Failed to determine registers: %1"). | 
					
						
							|  |  |  |                     arg(QLatin1String(reply->errorMessage)), LogError); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     postCommandSequence(reply->commandSequence); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (reply->success) { | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         QList<WatchData> watchData; | 
					
						
							| 
									
										
										
										
											2010-12-15 14:07:48 +01:00
										 |  |  |         GdbMi root; | 
					
						
							|  |  |  |         root.fromString(reply->reply); | 
					
						
							|  |  |  |         QTC_ASSERT(root.isList(), return ; ) | 
					
						
							|  |  |  |         if (debugLocals) { | 
					
						
							|  |  |  |             qDebug() << root.toString(true, 4); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Courtesy of GDB engine
 | 
					
						
							|  |  |  |         foreach (const GdbMi &child, root.children()) { | 
					
						
							|  |  |  |             WatchData dummy; | 
					
						
							|  |  |  |             dummy.iname = child.findChild("iname").data(); | 
					
						
							|  |  |  |             dummy.name = QLatin1String(child.findChild("name").data()); | 
					
						
							|  |  |  |             parseWatchData(watchHandler()->expandedINames(), dummy, child, &watchData); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         watchHandler()->insertBulkData(watchData); | 
					
						
							|  |  |  |         watchHandler()->endCycle(); | 
					
						
							|  |  |  |         if (debugLocals) { | 
					
						
							|  |  |  |             QDebug nsp = qDebug().nospace(); | 
					
						
							|  |  |  |             nsp << "Obtained " << watchData.size() << " items:\n"; | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |             foreach (const WatchData &wd, watchData) | 
					
						
							| 
									
										
										
										
											2010-12-15 14:07:48 +01:00
										 |  |  |                 nsp << wd.toString() <<'\n'; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         showMessage(QString::fromLatin1(reply->errorMessage), LogError); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleExpandLocals(const CdbExtensionCommandPtr &reply) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!reply->success) | 
					
						
							|  |  |  |         showMessage(QString::fromLatin1(reply->errorMessage), LogError); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum CdbExecutionStatus { | 
					
						
							|  |  |  | CDB_STATUS_NO_CHANGE=0, CDB_STATUS_GO = 1, CDB_STATUS_GO_HANDLED = 2, | 
					
						
							|  |  |  | CDB_STATUS_GO_NOT_HANDLED = 3, CDB_STATUS_STEP_OVER = 4, | 
					
						
							|  |  |  | CDB_STATUS_STEP_INTO = 5, CDB_STATUS_BREAK = 6, CDB_STATUS_NO_DEBUGGEE = 7, | 
					
						
							|  |  |  | CDB_STATUS_STEP_BRANCH = 8, CDB_STATUS_IGNORE_EVENT = 9, | 
					
						
							|  |  |  | CDB_STATUS_RESTART_REQUESTED = 10, CDB_STATUS_REVERSE_GO = 11, | 
					
						
							|  |  |  | CDB_STATUS_REVERSE_STEP_BRANCH = 12, CDB_STATUS_REVERSE_STEP_OVER = 13, | 
					
						
							|  |  |  | CDB_STATUS_REVERSE_STEP_INTO = 14 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *cdbStatusName(unsigned long s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (s) { | 
					
						
							|  |  |  |     case CDB_STATUS_NO_CHANGE: | 
					
						
							|  |  |  |         return "No change"; | 
					
						
							|  |  |  |     case CDB_STATUS_GO: | 
					
						
							|  |  |  |         return "go"; | 
					
						
							|  |  |  |     case CDB_STATUS_GO_HANDLED: | 
					
						
							|  |  |  |         return "go_handled"; | 
					
						
							|  |  |  |     case CDB_STATUS_GO_NOT_HANDLED: | 
					
						
							|  |  |  |         return "go_not_handled"; | 
					
						
							|  |  |  |     case CDB_STATUS_STEP_OVER: | 
					
						
							|  |  |  |         return "step_over"; | 
					
						
							|  |  |  |     case CDB_STATUS_STEP_INTO: | 
					
						
							|  |  |  |         return "step_into"; | 
					
						
							|  |  |  |     case CDB_STATUS_BREAK: | 
					
						
							|  |  |  |         return "break"; | 
					
						
							|  |  |  |     case CDB_STATUS_NO_DEBUGGEE: | 
					
						
							|  |  |  |         return "no_debuggee"; | 
					
						
							|  |  |  |     case CDB_STATUS_STEP_BRANCH: | 
					
						
							|  |  |  |         return "step_branch"; | 
					
						
							|  |  |  |     case CDB_STATUS_IGNORE_EVENT: | 
					
						
							|  |  |  |         return "ignore_event"; | 
					
						
							|  |  |  |     case CDB_STATUS_RESTART_REQUESTED: | 
					
						
							|  |  |  |         return "restart_requested"; | 
					
						
							|  |  |  |     case CDB_STATUS_REVERSE_GO: | 
					
						
							|  |  |  |         return "reverse_go"; | 
					
						
							|  |  |  |     case CDB_STATUS_REVERSE_STEP_BRANCH: | 
					
						
							|  |  |  |         return "reverse_step_branch"; | 
					
						
							|  |  |  |     case CDB_STATUS_REVERSE_STEP_OVER: | 
					
						
							|  |  |  |         return "reverse_step_over"; | 
					
						
							|  |  |  |     case CDB_STATUS_REVERSE_STEP_INTO: | 
					
						
							|  |  |  |         return "reverse_step_into"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return "unknown"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleSessionIdle(const QByteArray &message) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_hasDebuggee) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::handleSessionIdle %dms '%s' in state '%s', special mode %d", | 
					
						
							|  |  |  |                elapsedLogTime(), message.constData(), | 
					
						
							|  |  |  |                stateName(state()), m_specialStopMode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Switch source level debugging
 | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  |     syncOperateByInstruction(m_operateByInstructionPending); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const SpecialStopMode specialStopMode =  m_specialStopMode; | 
					
						
							|  |  |  |     m_specialStopMode = NoSpecialStop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch(specialStopMode) { | 
					
						
							|  |  |  |     case SpecialStopSynchronizeBreakpoints: | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("attemptBreakpointSynchronization in special stop"); | 
					
						
							|  |  |  |         attemptBreakpointSynchronization(); | 
					
						
							|  |  |  |         doContinueInferior(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     case NoSpecialStop: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     switch(state()) { // Temporary stop at beginning
 | 
					
						
							|  |  |  |     case EngineSetupRequested: | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyEngineSetupOk"); | 
					
						
							|  |  |  |         notifyEngineSetupOk(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     case InferiorSetupRequested: | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     case InferiorStopRequested: | 
					
						
							|  |  |  |     case InferiorRunOk: | 
					
						
							|  |  |  |         break; // Proper stop of inferior handled below.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         qWarning("WARNING: CdbEngine::handleSessionAccessible called in state %s", stateName(state())); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Handle stop.
 | 
					
						
							|  |  |  |     if (state() == InferiorStopRequested) { | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyInferiorStopOk"); | 
					
						
							|  |  |  |         notifyInferiorStopOk(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyInferiorSpontaneousStop"); | 
					
						
							|  |  |  |         notifyInferiorSpontaneousStop(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Start sequence to get all relevant data. Hack: Avoid module reload?
 | 
					
						
							| 
									
										
										
										
											2010-12-14 16:14:05 +01:00
										 |  |  |     unsigned sequence = CommandListStack|CommandListThreads; | 
					
						
							| 
									
										
										
										
											2010-12-09 17:04:43 +01:00
										 |  |  |     if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_REGISTER))) | 
					
						
							|  |  |  |         sequence |= CommandListRegisters; | 
					
						
							|  |  |  |     if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_MODULES))) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         sequence |= CommandListModules; | 
					
						
							|  |  |  |     postCommandSequence(sequence); | 
					
						
							|  |  |  |     // Report stop reason (GDBMI)
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     GdbMi stopReason; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     stopReason.fromString(message); | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("%s", stopReason.toString(true, 4).constData()); | 
					
						
							|  |  |  |     const QByteArray reason = stopReason.findChild("reason").data(); | 
					
						
							|  |  |  |     if (reason.isEmpty()) { | 
					
						
							|  |  |  |         showStatusMessage(tr("Malformed stop response received."), LogError); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const int threadId = stopReason.findChild("threadId").data().toInt(); | 
					
						
							|  |  |  |     if (reason == "breakpoint") { | 
					
						
							|  |  |  |         const int number = stopReason.findChild("breakpointId").data().toInt(); | 
					
						
							|  |  |  |         const BreakpointId id = breakHandler()->findBreakpointByNumber(number); | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         if (id && breakHandler()->type(id) == Watchpoint) { | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             showStatusMessage(msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId))); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             showStatusMessage(msgBreakpointTriggered(id, number, QString::number(threadId))); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (reason == "exception") { | 
					
						
							|  |  |  |         WinException exception; | 
					
						
							|  |  |  |         exception.fromGdbMI(stopReason); | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							| 
									
										
										
										
											2010-12-16 12:17:54 +01:00
										 |  |  |         // It is possible to hit on a startup trap while stepping (if something
 | 
					
						
							|  |  |  |         // pulls DLLs. Avoid showing a 'stopped' Message box.
 | 
					
						
							|  |  |  |         if (exception.exceptionCode == winExceptionStartupCompleteTrap) | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         if (isDebuggerWinException(exception.exceptionCode)) { | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             showStatusMessage(msgInterrupted()); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |         const QString description = exception.toString(); | 
					
						
							|  |  |  |         showStatusMessage(msgStoppedByException(description, QString::number(threadId))); | 
					
						
							|  |  |  |         showStoppedByExceptionMessageBox(description); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     showStatusMessage(msgStopped(QLatin1String(reason))); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleSessionAccessible(unsigned long cdbExState) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const DebuggerState s = state(); | 
					
						
							|  |  |  |     if (!m_hasDebuggee || s == InferiorRunOk) // suppress reports
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::handleSessionAccessible %dms in state '%s'/'%s', special mode %d", | 
					
						
							|  |  |  |                elapsedLogTime(), cdbStatusName(cdbExState), stateName(state()), m_specialStopMode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch(s) { | 
					
						
							|  |  |  |     case EngineShutdownRequested: | 
					
						
							|  |  |  |         shutdownEngine(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case InferiorShutdownRequested: | 
					
						
							|  |  |  |         shutdownInferior(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleSessionInaccessible(unsigned long cdbExState) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const DebuggerState s = state(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // suppress reports
 | 
					
						
							|  |  |  |     if (!m_hasDebuggee || (s == InferiorRunOk && cdbExState != CDB_STATUS_NO_DEBUGGEE)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("CdbEngine::handleSessionInaccessible %dms in state '%s', '%s', special mode %d", | 
					
						
							|  |  |  |                elapsedLogTime(), cdbStatusName(cdbExState), stateName(state()), m_specialStopMode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (state()) { | 
					
						
							|  |  |  |     case EngineSetupRequested: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case EngineRunRequested: | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyEngineRunAndInferiorRunOk"); | 
					
						
							|  |  |  |         notifyEngineRunAndInferiorRunOk(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case InferiorRunOk: | 
					
						
							|  |  |  |     case InferiorStopOk: | 
					
						
							|  |  |  |         // Inaccessible without debuggee (exit breakpoint)
 | 
					
						
							|  |  |  |         // We go for spontaneous engine shutdown instead.
 | 
					
						
							|  |  |  |         if (cdbExState == CDB_STATUS_NO_DEBUGGEE) { | 
					
						
							|  |  |  |             if (debug) | 
					
						
							|  |  |  |                 qDebug("Lost debuggeee"); | 
					
						
							|  |  |  |             m_hasDebuggee = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case InferiorRunRequested: | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("notifyInferiorRunOk"); | 
					
						
							|  |  |  |         notifyInferiorRunOk(); | 
					
						
							|  |  |  |         resetLocation(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case EngineShutdownRequested: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::handleExtensionMessage(char t, int token, const QByteArray &what, const QByteArray &message) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug > 1) { | 
					
						
							|  |  |  |         QDebug nospace = qDebug().nospace(); | 
					
						
							|  |  |  |         nospace << "handleExtensionMessage " << t << ' ' << token << ' ' << what | 
					
						
							|  |  |  |                 << ' ' << stateName(state()); | 
					
						
							|  |  |  |         if (t == 'N' || debug > 1) { | 
					
						
							|  |  |  |             nospace << ' ' << message; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             nospace << ' ' << message.size() << " bytes"; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Is there a reply expected, some command queued?
 | 
					
						
							|  |  |  |     if (t == 'R' || t == 'N') { | 
					
						
							| 
									
										
										
										
											2010-11-25 10:01:40 +01:00
										 |  |  |         if (token == -1) { // Default token, user typed in extension command
 | 
					
						
							|  |  |  |             showMessage(QString::fromLatin1(message), LogMisc); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         const int index = indexOfCommand(m_extensionCommandQueue, token); | 
					
						
							|  |  |  |         if (index != -1) { | 
					
						
							|  |  |  |             // Did the command finish? Take off queue and complete, invoke CB
 | 
					
						
							|  |  |  |             const CdbExtensionCommandPtr command = m_extensionCommandQueue.takeAt(index); | 
					
						
							|  |  |  |             if (t == 'R') { | 
					
						
							|  |  |  |                 command->success = true; | 
					
						
							|  |  |  |                 command->reply = message; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 command->success = false; | 
					
						
							|  |  |  |                 command->errorMessage = message; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (debug) | 
					
						
							|  |  |  |                 qDebug("### Completed extension command '%s', token=%d, pending=%d", | 
					
						
							|  |  |  |                        command->command.constData(), command->token, m_extensionCommandQueue.size()); | 
					
						
							|  |  |  |             if (command->handler) | 
					
						
							|  |  |  |                 (this->*(command->handler))(command); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (what == "debuggee_output") { | 
					
						
							|  |  |  |         showMessage(StringFromBase64EncodedUtf16(message), AppOutput); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (what == "event") { | 
					
						
							|  |  |  |         showStatusMessage(QString::fromAscii(message),  5000); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (what == "session_accessible") { | 
					
						
							|  |  |  |         if (!m_accessible) { | 
					
						
							|  |  |  |             m_accessible = true; | 
					
						
							|  |  |  |             handleSessionAccessible(message.toULong()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (what == "session_inaccessible") { | 
					
						
							|  |  |  |         if (m_accessible) { | 
					
						
							|  |  |  |             m_accessible = false; | 
					
						
							|  |  |  |             handleSessionInaccessible(message.toULong()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (what == "session_idle") { | 
					
						
							|  |  |  |         handleSessionIdle(message); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (what == "exception") { | 
					
						
							|  |  |  |         WinException exception; | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         GdbMi gdbmi; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         gdbmi.fromString(message); | 
					
						
							|  |  |  |         exception.fromGdbMI(gdbmi); | 
					
						
							|  |  |  |         const QString message = exception.toString(true); | 
					
						
							|  |  |  |         showStatusMessage(message); | 
					
						
							|  |  |  | #ifdef Q_OS_WIN // Report C++ exception in application output as well.
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |         if (exception.exceptionCode == winExceptionCppException) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             showMessage(message + QLatin1Char('\n'), AppOutput); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Check for a CDB prompt '0:000> ' ('process:thread> ')..no regexps for QByteArray...
 | 
					
						
							|  |  |  | enum { CdbPromptLength = 7 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool isCdbPrompt(const QByteArray &c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return c.size() >= CdbPromptLength && c.at(6) == ' ' && c.at(5) == '>' && c.at(1) == ':' | 
					
						
							|  |  |  |             && std::isdigit(c.at(0)) &&  std::isdigit(c.at(2)) && std::isdigit(c.at(3)) | 
					
						
							|  |  |  |             && std::isdigit(c.at(4)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Check for '<token>32>' or '<token>32<'
 | 
					
						
							|  |  |  | static inline bool checkCommandToken(const QByteArray &tokenPrefix, const QByteArray &c, | 
					
						
							|  |  |  |                                   int *token, bool *isStart) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     *token = 0; | 
					
						
							|  |  |  |     *isStart = false; | 
					
						
							|  |  |  |     const int tokenPrefixSize = tokenPrefix.size(); | 
					
						
							|  |  |  |     const int size = c.size(); | 
					
						
							|  |  |  |     if (size < tokenPrefixSize + 2 || !std::isdigit(c.at(tokenPrefixSize))) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     switch (c.at(size - 1)) { | 
					
						
							|  |  |  |     case '>': | 
					
						
							|  |  |  |         *isStart = false; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case '<': | 
					
						
							|  |  |  |         *isStart = true; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!c.startsWith(tokenPrefix)) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     bool ok; | 
					
						
							|  |  |  |     *token = c.mid(tokenPrefixSize, size - tokenPrefixSize - 1).toInt(&ok); | 
					
						
							|  |  |  |     return ok; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::parseOutputLine(QByteArray line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // The hooked output callback in the extension suppresses prompts,
 | 
					
						
							|  |  |  |     // it should happen only in initial and exit stages. Note however that
 | 
					
						
							|  |  |  |     // if the output is not hooked, sequences of prompts are possible which
 | 
					
						
							|  |  |  |     // can mix things up.
 | 
					
						
							|  |  |  |     while (isCdbPrompt(line)) | 
					
						
							|  |  |  |         line.remove(0, CdbPromptLength); | 
					
						
							| 
									
										
										
										
											2011-01-04 12:40:52 +01:00
										 |  |  |     // An extension notification (potentially consisting of several chunks)
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     if (line.startsWith(m_creatorExtPrefix)) { | 
					
						
							| 
									
										
										
										
											2011-01-04 12:40:52 +01:00
										 |  |  |         // "<qtcreatorcdbext>|type_char|token|remainingChunks|serviceName|message"
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         const char type = line.at(m_creatorExtPrefix.size()); | 
					
						
							|  |  |  |         // integer token
 | 
					
						
							|  |  |  |         const int tokenPos = m_creatorExtPrefix.size() + 2; | 
					
						
							|  |  |  |         const int tokenEndPos = line.indexOf('|', tokenPos); | 
					
						
							|  |  |  |         QTC_ASSERT(tokenEndPos != -1, return) | 
					
						
							|  |  |  |         const int token = line.mid(tokenPos, tokenEndPos - tokenPos).toInt(); | 
					
						
							| 
									
										
										
										
											2011-01-04 12:40:52 +01:00
										 |  |  |         // remainingChunks
 | 
					
						
							|  |  |  |         const int remainingChunksPos = tokenEndPos + 1; | 
					
						
							|  |  |  |         const int remainingChunksEndPos = line.indexOf('|', remainingChunksPos); | 
					
						
							|  |  |  |         QTC_ASSERT(remainingChunksEndPos != -1, return) | 
					
						
							|  |  |  |         const int remainingChunks = line.mid(remainingChunksPos, remainingChunksEndPos - remainingChunksPos).toInt(); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         // const char 'serviceName'
 | 
					
						
							| 
									
										
										
										
											2011-01-04 12:40:52 +01:00
										 |  |  |         const int whatPos = remainingChunksEndPos + 1; | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         const int whatEndPos = line.indexOf('|', whatPos); | 
					
						
							|  |  |  |         QTC_ASSERT(whatEndPos != -1, return) | 
					
						
							|  |  |  |         const QByteArray what = line.mid(whatPos, whatEndPos - whatPos); | 
					
						
							| 
									
										
										
										
											2011-01-04 12:40:52 +01:00
										 |  |  |         // Build up buffer, call handler once last chunk was encountered
 | 
					
						
							|  |  |  |         m_extensionMessageBuffer += line.mid(whatEndPos + 1); | 
					
						
							|  |  |  |         if (remainingChunks == 0) { | 
					
						
							|  |  |  |             handleExtensionMessage(type, token, what, m_extensionMessageBuffer); | 
					
						
							|  |  |  |             m_extensionMessageBuffer.clear(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Check for command start/end tokens within which the builtin command
 | 
					
						
							|  |  |  |     // output is enclosed
 | 
					
						
							|  |  |  |     int token = 0; | 
					
						
							|  |  |  |     bool isStartToken = false; | 
					
						
							|  |  |  |     const bool isCommandToken = checkCommandToken(m_tokenPrefix, line, &token, &isStartToken); | 
					
						
							|  |  |  |     if (debug > 1) | 
					
						
							|  |  |  |         qDebug("Reading CDB stdout '%s',\n  isCommand=%d, token=%d, isStart=%d, current=%d", | 
					
						
							|  |  |  |                line.constData(), isCommandToken, token, isStartToken, m_currentBuiltinCommandIndex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // If there is a current command, wait for end of output indicated by token,
 | 
					
						
							|  |  |  |     // command, trigger handler and finish, else append to its output.
 | 
					
						
							|  |  |  |     if (m_currentBuiltinCommandIndex != -1) { | 
					
						
							|  |  |  |         QTC_ASSERT(!isStartToken && m_currentBuiltinCommandIndex < m_builtinCommandQueue.size(), return; ); | 
					
						
							|  |  |  |         const CdbBuiltinCommandPtr ¤tCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex); | 
					
						
							|  |  |  |         if (isCommandToken) { | 
					
						
							|  |  |  |             // Did the command finish? Invoke callback and remove from queue.
 | 
					
						
							|  |  |  |             if (debug) | 
					
						
							|  |  |  |                 qDebug("### Completed builtin command '%s', token=%d, %d lines, pending=%d", | 
					
						
							|  |  |  |                        currentCommand->command.constData(), currentCommand->token, | 
					
						
							|  |  |  |                        currentCommand->reply.size(), m_builtinCommandQueue.size() - 1); | 
					
						
							|  |  |  |             QTC_ASSERT(token == currentCommand->token, return; ); | 
					
						
							|  |  |  |             if (currentCommand->handler) | 
					
						
							|  |  |  |                 (this->*(currentCommand->handler))(currentCommand); | 
					
						
							|  |  |  |             m_builtinCommandQueue.removeAt(m_currentBuiltinCommandIndex); | 
					
						
							|  |  |  |             m_currentBuiltinCommandIndex = -1; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // Record output of current command
 | 
					
						
							|  |  |  |             currentCommand->reply.push_back(line); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } // m_currentCommandIndex
 | 
					
						
							|  |  |  |     if (isCommandToken) { | 
					
						
							|  |  |  |         // Beginning command token encountered, start to record output.
 | 
					
						
							|  |  |  |         const int index = indexOfCommand(m_builtinCommandQueue, token); | 
					
						
							|  |  |  |         QTC_ASSERT(isStartToken && index != -1, return; ); | 
					
						
							|  |  |  |         m_currentBuiltinCommandIndex = index; | 
					
						
							|  |  |  |         const CdbBuiltinCommandPtr ¤tCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex); | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug("### Gathering output for '%s' token %d", currentCommand->command.constData(), currentCommand->token); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     showMessage(QString::fromLocal8Bit(line), LogMisc); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::readyReadStandardOut() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_outputBuffer += m_process.readAllStandardOutput(); | 
					
						
							|  |  |  |     // Split into lines and parse line by line.
 | 
					
						
							|  |  |  |     while (true) { | 
					
						
							|  |  |  |         const int endOfLinePos = m_outputBuffer.indexOf('\n'); | 
					
						
							|  |  |  |         if (endOfLinePos == -1) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // Check for '\r\n'
 | 
					
						
							|  |  |  |             QByteArray line = m_outputBuffer.left(endOfLinePos); | 
					
						
							|  |  |  |             if (!line.isEmpty() && line.at(line.size() - 1) == '\r') | 
					
						
							|  |  |  |                 line.truncate(line.size() - 1); | 
					
						
							|  |  |  |             parseOutputLine(line); | 
					
						
							|  |  |  |             m_outputBuffer.remove(0, endOfLinePos + 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::readyReadStandardError() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     showMessage(QString::fromLocal8Bit(m_process.readAllStandardError()), LogError); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::processError() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     showMessage(m_process.errorString(), LogError); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  | // Join breakpoint ids for a multi-breakpoint id commands like 'bc', 'be', 'bd'
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | static QByteArray multiBreakpointCommand(const char *cmdC, const Breakpoints &bps) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     QByteArray cmd(cmdC); | 
					
						
							|  |  |  |     ByteArrayInputStream str(cmd); | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  |     foreach(const BreakpointData *bp, bps) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         str << ' ' << bp->bpNumber; | 
					
						
							|  |  |  |     return cmd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Figure out what kind of changes are required to synchronize
 | 
					
						
							|  |  |  | enum BreakPointSyncType { | 
					
						
							|  |  |  |     BreakpointsUnchanged, BreakpointsAdded, BreakpointsRemovedChanged | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  | static inline BreakPointSyncType breakPointSyncType(const BreakHandler *handler, | 
					
						
							|  |  |  |                                                     const BreakpointIds ids) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     bool added = false; | 
					
						
							|  |  |  |     foreach (BreakpointId id, ids) { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |         const BreakpointState state = handler->state(id); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         if (debugBreakpoints > 1) | 
					
						
							|  |  |  |             qDebug("    Checking on breakpoint %llu, state %d\n", id, state); | 
					
						
							|  |  |  |         switch (state) { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |         case BreakpointInsertRequested: | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             added = true; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |         case BreakpointChangeRequested: | 
					
						
							|  |  |  |         case BreakpointRemoveRequested: | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             return BreakpointsRemovedChanged; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return added ? BreakpointsAdded : BreakpointsUnchanged; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-26 13:06:03 +01:00
										 |  |  | bool CdbEngine::stateAcceptsBreakpointChanges() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (state()) { | 
					
						
							|  |  |  |     case InferiorRunOk: | 
					
						
							|  |  |  |     case InferiorStopOk: | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool CdbEngine::acceptsBreakpoint(BreakpointId id) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return DebuggerEngine::isCppBreakpoint(breakHandler()->breakpointData(id)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | void CdbEngine::attemptBreakpointSynchronization() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Check if there is anything to be done at all.
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |     BreakHandler *handler = breakHandler(); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |     foreach (BreakpointId id, handler->unclaimedBreakpointIds()) | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         if (acceptsBreakpoint(id)) | 
					
						
							|  |  |  |             handler->setEngine(id, this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Find out if there is a need to synchronize again
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |     const BreakpointIds ids = handler->engineBreakpointIds(this); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     const BreakPointSyncType syncType = breakPointSyncType(handler, ids); | 
					
						
							|  |  |  |     if (debugBreakpoints) | 
					
						
							|  |  |  |         qDebug("attemptBreakpointSynchronizationI %dms accessible=%d, %s %d breakpoints, syncType=%d", | 
					
						
							|  |  |  |                elapsedLogTime(), m_accessible, stateName(state()), ids.size(), syncType); | 
					
						
							|  |  |  |     if (syncType == BreakpointsUnchanged) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!m_accessible) { | 
					
						
							|  |  |  |         // No nested calls.
 | 
					
						
							|  |  |  |         if (m_specialStopMode != SpecialStopSynchronizeBreakpoints) | 
					
						
							|  |  |  |             doInterruptInferior(SpecialStopSynchronizeBreakpoints); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // If there are changes/removals, delete all breakpoints and re-insert
 | 
					
						
							|  |  |  |     // all enabled breakpoints. This is the simplest
 | 
					
						
							|  |  |  |     // way to apply changes since CDB ids shift when removing breakpoints and there is no
 | 
					
						
							|  |  |  |     // easy way to re-match them.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (syncType == BreakpointsRemovedChanged) { // Need to clear out all?
 | 
					
						
							|  |  |  |         postCommand("bc *", 0); | 
					
						
							|  |  |  |         m_nextBreakpointNumber = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     foreach (BreakpointId id, ids) { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |         BreakpointResponse response; | 
					
						
							|  |  |  |         const BreakpointParameters &p = handler->breakpointData(id); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         response.fromParameters(p); | 
					
						
							|  |  |  |         switch (handler->state(id)) { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |         case BreakpointInsertRequested: | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             response.number = m_nextBreakpointNumber++; | 
					
						
							|  |  |  |             postCommand(cdbAddBreakpointCommand(p, false, response.number), 0); | 
					
						
							| 
									
										
										
										
											2010-11-18 17:44:04 +01:00
										 |  |  |             handler->notifyBreakpointInsertProceeding(id); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             handler->notifyBreakpointInsertOk(id); | 
					
						
							|  |  |  |             handler->setResponse(id, response); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |         case BreakpointChangeRequested: | 
					
						
							| 
									
										
										
										
											2010-11-18 17:44:04 +01:00
										 |  |  |             // Skip disabled breakpoints, else add.
 | 
					
						
							|  |  |  |             handler->notifyBreakpointChangeProceeding(id); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             if (p.enabled) { | 
					
						
							|  |  |  |                 response.number = m_nextBreakpointNumber++; | 
					
						
							|  |  |  |                 postCommand(cdbAddBreakpointCommand(p, false, response.number), 0); | 
					
						
							|  |  |  |                 handler->notifyBreakpointChangeOk(id); | 
					
						
							|  |  |  |                 handler->setResponse(id, response); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |         case BreakpointRemoveRequested: | 
					
						
							| 
									
										
										
										
											2010-11-22 17:06:08 +01:00
										 |  |  |             handler->notifyBreakpointRemoveProceeding(id); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             handler->notifyBreakpointRemoveOk(id); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |         case BreakpointInserted: | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |             // Existing breakpoints were deleted due to change/removal, re-set
 | 
					
						
							|  |  |  |             if (syncType == BreakpointsRemovedChanged) { | 
					
						
							|  |  |  |                 response.number = m_nextBreakpointNumber++;; | 
					
						
							|  |  |  |                 postCommand(cdbAddBreakpointCommand(p, false, response.number), 0); | 
					
						
							|  |  |  |                 handler->setResponse(id, response); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString CdbEngine::normalizeFileName(const QString &f) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QMap<QString, QString>::const_iterator it = m_normalizedFileCache.constFind(f); | 
					
						
							|  |  |  |     if (it != m_normalizedFileCache.constEnd()) | 
					
						
							|  |  |  |         return it.value(); | 
					
						
							|  |  |  |     const QString winF = QDir::toNativeSeparators(f); | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:50:44 +01:00
										 |  |  |     QString normalized = winNormalizeFileName(winF); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  |     QString normalized = winF; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     if (normalized.isEmpty()) { // At least upper case drive letter
 | 
					
						
							|  |  |  |         normalized = winF; | 
					
						
							|  |  |  |         if (normalized.size() > 2 && normalized.at(1) == QLatin1Char(':')) | 
					
						
							|  |  |  |             normalized[0] = normalized.at(0).toUpper(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     m_normalizedFileCache.insert(f, normalized); | 
					
						
							|  |  |  |     return normalized; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  | // Parse frame from GDBMI. Duplicate of the gdb code, but that
 | 
					
						
							|  |  |  | // has more processing.
 | 
					
						
							|  |  |  | static StackFrames parseFrames(const QByteArray &data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     GdbMi gdbmi; | 
					
						
							|  |  |  |     gdbmi.fromString(data); | 
					
						
							|  |  |  |     if (!gdbmi.isValid()) | 
					
						
							|  |  |  |         return StackFrames(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     StackFrames rc; | 
					
						
							|  |  |  |     const int count = gdbmi.childCount(); | 
					
						
							|  |  |  |     rc.reserve(count); | 
					
						
							|  |  |  |     for (int i = 0; i  < count; i++) { | 
					
						
							|  |  |  |         const GdbMi &frameMi = gdbmi.childAt(i); | 
					
						
							|  |  |  |         StackFrame frame; | 
					
						
							|  |  |  |         frame.level = i; | 
					
						
							|  |  |  |         const GdbMi fullName = frameMi.findChild("fullname"); | 
					
						
							|  |  |  |         if (fullName.isValid()) { | 
					
						
							|  |  |  |             frame.file = QFile::decodeName(fullName.data()); | 
					
						
							|  |  |  |             frame.line = frameMi.findChild("line").data().toInt(); | 
					
						
							| 
									
										
										
										
											2010-12-01 16:37:34 +01:00
										 |  |  |             frame.usable = QFileInfo(frame.file).isFile(); | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         frame.function = QLatin1String(frameMi.findChild("func").data()); | 
					
						
							|  |  |  |         frame.from = QLatin1String(frameMi.findChild("from").data()); | 
					
						
							|  |  |  |         frame.address = frameMi.findChild("addr").data().toULongLong(0, 16); | 
					
						
							|  |  |  |         rc.push_back(frame); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  |     return rc; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  | void CdbEngine::handleStackTrace(const CdbExtensionCommandPtr &command) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-01-05 11:34:35 +01:00
										 |  |  |     // Parse frames, find current. Special handling for step into:
 | 
					
						
							|  |  |  |     // When stepping into on an actual function (source mode) by executing 't', an assembler
 | 
					
						
							|  |  |  |     // frame pointing at the jmp instruction is hit (noticeable by top function being
 | 
					
						
							|  |  |  |     // 'ILT+'). If that is the case, execute another 't' to step into the actual function.    .
 | 
					
						
							|  |  |  |     // Note that executing 't 2' does not work since it steps 2 instructions on a non-call code line.
 | 
					
						
							|  |  |  |     const bool sourceStepInto = m_sourceStepInto; | 
					
						
							|  |  |  |     m_sourceStepInto = false; | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  |     if (command->success) { | 
					
						
							|  |  |  |         int current = -1; | 
					
						
							|  |  |  |         StackFrames frames = parseFrames(command->reply); | 
					
						
							|  |  |  |         const int count = frames.size(); | 
					
						
							|  |  |  |         for (int i = 0; i < count; i++) { | 
					
						
							| 
									
										
										
										
											2011-01-05 11:34:35 +01:00
										 |  |  |             const bool hasFile = !frames.at(i).file.isEmpty(); | 
					
						
							|  |  |  |             // jmp-frame hit by step into, do another 't' and abort sequence.
 | 
					
						
							|  |  |  |             if (!hasFile && i == 0 && sourceStepInto && frames.at(i).function.contains(QLatin1String("ILT+"))) { | 
					
						
							|  |  |  |                 showMessage(QString::fromAscii("Step into: Call instruction hit, performing additional step..."), LogMisc); | 
					
						
							|  |  |  |                 executeStep(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (hasFile) { | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  |                 frames[i].file = QDir::cleanPath(normalizeFileName(frames.at(i).file)); | 
					
						
							| 
									
										
										
										
											2010-12-16 12:17:54 +01:00
										 |  |  |                 if (current == -1 && frames[i].usable) | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  |                     current = i; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (count && current == -1) // No usable frame, use assembly.
 | 
					
						
							|  |  |  |             current = 0; | 
					
						
							|  |  |  |         // Set
 | 
					
						
							|  |  |  |         stackHandler()->setFrames(frames); | 
					
						
							|  |  |  |         activateFrame(current); | 
					
						
							|  |  |  |         postCommandSequence(command->commandSequence); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         showMessage(command->errorMessage, LogError); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CdbEngine::dummyHandler(const CdbBuiltinCommandPtr &command) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     postCommandSequence(command->commandSequence); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Post a sequence of standard commands: Trigger next once one completes successfully
 | 
					
						
							|  |  |  | void CdbEngine::postCommandSequence(unsigned mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("postCommandSequence 0x%x\n", mask); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!mask) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     if (mask & CommandListThreads) { | 
					
						
							|  |  |  |         postExtensionCommand("threads", QByteArray(), 0, &CdbEngine::handleThreads, mask & ~CommandListThreads); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (mask & CommandListStack) { | 
					
						
							| 
									
										
										
										
											2010-11-22 13:50:40 +01:00
										 |  |  |         postExtensionCommand("stack", QByteArray(), 0, &CdbEngine::handleStackTrace, mask & ~CommandListStack); | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (mask & CommandListRegisters) { | 
					
						
							|  |  |  |         QTC_ASSERT(threadsHandler()->currentThread() >= 0,  return; ) | 
					
						
							|  |  |  |         postExtensionCommand("registers", QByteArray(), 0, &CdbEngine::handleRegisters, mask & ~CommandListRegisters); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (mask & CommandListModules) { | 
					
						
							|  |  |  |         postExtensionCommand("modules", QByteArray(), 0, &CdbEngine::handleModules, mask & ~CommandListModules); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-11 11:06:15 +01:00
										 |  |  | } // namespace Internal
 | 
					
						
							| 
									
										
										
										
											2010-11-18 13:51:15 +01:00
										 |  |  | } // namespace Debugger
 |