/src/plugins/debugger/cdb/cdbengine.cpp
C++ | 3133 lines | 2646 code | 212 blank | 275 comment | 476 complexity | cd301d975e19f4cd921a1aa3b104caab MD5 | raw file
Possible License(s): LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /**************************************************************************
- **
- ** This file is part of Qt Creator
- **
- ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
- **
- ** Contact: Nokia Corporation (qt-info@nokia.com)
- **
- **
- ** GNU Lesser General Public License Usage
- **
- ** 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.
- **
- ** 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.
- **
- ** Other Usage
- **
- ** Alternatively, this file may be used in accordance with the terms and
- ** conditions contained in a signed written agreement between you and Nokia.
- **
- ** If you have questions regarding the use of this file, please contact
- ** Nokia at qt-info@nokia.com.
- **
- **************************************************************************/
- #include "cdbengine.h"
- #include "breakhandler.h"
- #include "breakpoint.h"
- #include "bytearrayinputstream.h"
- #include "cdboptions.h"
- #include "cdboptionspage.h"
- #include "cdbparsehelpers.h"
- #include "debuggeractions.h"
- #include "debuggercore.h"
- #include "debuggerinternalconstants.h"
- #include "debuggerrunner.h"
- #include "debuggerstartparameters.h"
- #include "debuggertooltipmanager.h"
- #include "disassembleragent.h"
- #include "disassemblerlines.h"
- #include "memoryagent.h"
- #include "moduleshandler.h"
- #include "registerhandler.h"
- #include "stackframe.h"
- #include "stackhandler.h"
- #include "threadshandler.h"
- #include "watchhandler.h"
- #include "watchutils.h"
- #include "gdb/gdbmi.h"
- #include "shared/cdbsymbolpathlisteditor.h"
- #include "shared/hostutils.h"
- #include "procinterrupt.h"
- #include <TranslationUnit.h>
- #include <coreplugin/icore.h>
- #include <texteditor/itexteditor.h>
- #include <projectexplorer/abi.h>
- #include <projectexplorer/projectexplorerconstants.h>
- #include <utils/synchronousprocess.h>
- #include <utils/winutils.h>
- #include <utils/qtcassert.h>
- #include <utils/savedaction.h>
- #include <utils/consoleprocess.h>
- #include <utils/fileutils.h>
- #include <cplusplus/findcdbbreakpoint.h>
- #include <cplusplus/CppDocument.h>
- #include <cpptools/ModelManagerInterface.h>
- #include <QCoreApplication>
- #include <QFileInfo>
- #include <QDir>
- #include <QDebug>
- #include <QTextStream>
- #include <QDateTime>
- #include <QToolTip>
- #include <QMainWindow>
- #include <QMessageBox>
- #include <cctype>
- Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgent*)
- Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
- enum { debug = 0 };
- enum { debugLocals = 0 };
- enum { debugSourceMapping = 0 };
- enum { debugWatches = 0 };
- enum { debugBreakpoints = 0 };
- enum HandleLocalsFlags
- {
- PartialLocalsUpdate = 0x1,
- LocalsUpdateForNewFrame = 0x2
- };
- #if 0
- # define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
- #else
- # define STATE_DEBUG(state, func, line, notifyFunc)
- #endif
- /*!
- \class Debugger::Internal::CdbEngine
- Cdb engine 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
- library (32/64bit), which is loaded into cdb.exe. It serves to:
- \list
- \o Notify the engine about the state of the debugging session:
- \list
- \o idle: (hooked up with .idle_cmd) debuggee stopped
- \o accessible: Debuggee stopped, cdb.exe accepts commands
- \o inaccessible: Debuggee runs, no way to post commands
- \o session active/inactive: Lost debuggee, terminating.
- \endlist
- \o Hook up with output/event callbacks and produce formatted output to be able
- to catch application output and exceptions.
- \o Provide some extension commands that produce output in a standardized (GDBMI)
- format that ends up in handleExtensionMessage(), for example:
- \list
- \o pid Return debuggee pid for interrupting.
- \o locals Print locals from SymbolGroup
- \o expandLocals Expand locals in symbol group
- \o registers, modules, threads
- \endlist
- \endlist
- Debugger commands can be posted by calling:
- \list
- \o postCommand(): Does not expect a reply
- \o 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.
- \o 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).
- \endlist
- Startup sequence:
- [Console: The console stub launches the process. On process startup,
- launchCDB() is called with AttachExternal].
- setupEngine() calls launchCDB() with the startparameters. The debuggee
- runs into the initial breakpoint (session idle). EngineSetupOk is
- notified (inferior still stopped). setupInferior() is then called
- which does breakpoint synchronization and issues the extension 'pid'
- command to obtain the inferior pid (which also hooks up the output callbacks).
- handlePid() notifies notifyInferiorSetupOk.
- runEngine() is then called which issues 'g' to continue the inferior.
- Shutdown mostly uses notifyEngineSpontaneousShutdown() as cdb just quits
- when the inferior exits (except attach modes).
- */
- using namespace ProjectExplorer;
- namespace Debugger {
- namespace Internal {
- static const char localsPrefixC[] = "local.";
- struct MemoryViewCookie
- {
- explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0,
- quint64 addr = 0, quint64 l = 0) :
- agent(a), editorToken(e), address(addr), length(l)
- {}
- MemoryAgent *agent;
- QObject *editorToken;
- quint64 address;
- quint64 length;
- };
- struct MemoryChangeCookie
- {
- explicit MemoryChangeCookie(quint64 addr = 0, const QByteArray &d = QByteArray()) :
- address(addr), data(d) {}
- quint64 address;
- QByteArray data;
- };
- struct ConditionalBreakPointCookie
- {
- ConditionalBreakPointCookie(BreakpointModelId i = BreakpointModelId()) : id(i) {}
- BreakpointModelId id;
- GdbMi stopReason;
- };
- } // namespace Internal
- } // namespace Debugger
- Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
- Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
- Q_DECLARE_METATYPE(Debugger::Internal::ConditionalBreakPointCookie)
- namespace Debugger {
- namespace Internal {
- static inline bool isCreatorConsole(const DebuggerStartParameters &sp, const CdbOptions &o)
- {
- return !o.cdbConsole && sp.useTerminal
- && (sp.startMode == StartInternal || sp.startMode == StartExternal);
- }
- static QMessageBox *
- nonModalMessageBox(QMessageBox::Icon icon, const QString &title, const QString &text)
- {
- QMessageBox *mb = new QMessageBox(icon, title, text, QMessageBox::Ok,
- debuggerCore()->mainWindow());
- mb->setAttribute(Qt::WA_DeleteOnClose);
- mb->show();
- return mb;
- }
- // 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 StartRemoteGdb:
- return false;
- default:
- break;
- }
- return true;
- }
- // Accessed by RunControlFactory
- DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
- DebuggerEngine *masterEngine, QString *errorMessage)
- {
- #ifdef Q_OS_WIN
- CdbOptionsPage *op = CdbOptionsPage::instance();
- if (!op || !op->options()->isValid() || !validMode(sp.startMode)) {
- *errorMessage = QLatin1String("Internal error: Invalid start parameters passed for thre CDB engine.");
- return 0;
- }
- return new CdbEngine(sp, masterEngine, op->options());
- #else
- Q_UNUSED(masterEngine)
- Q_UNUSED(sp)
- #endif
- *errorMessage = QString::fromLatin1("Unsupported debug mode");
- return 0;
- }
- bool isCdbEngineEnabled()
- {
- #ifdef Q_OS_WIN
- return CdbOptionsPage::instance() && CdbOptionsPage::instance()->options()->isValid();
- #else
- return false;
- #endif
- }
- static inline QString msgNoCdbBinaryForToolChain(const Abi &tc)
- {
- return CdbEngine::tr("There is no CDB binary available for binaries in format '%1'").arg(tc.toString());
- }
- static inline bool isMsvcFlavor(Abi::OSFlavor osf)
- {
- return osf == Abi::WindowsMsvc2005Flavor
- || osf == Abi::WindowsMsvc2008Flavor
- || osf == Abi::WindowsMsvc2010Flavor;
- }
- bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check)
- {
- #ifdef Q_OS_WIN
- const Abi abi = sp.toolChainAbi;
- if (!isCdbEngineEnabled()) {
- check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine required for %1 is currently disabled.").
- arg(abi.toString()));
- check->settingsCategory = QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY);
- check->settingsPage = CdbOptionsPage::settingsId();
- return false;
- }
- if (!validMode(sp.startMode)) {
- check->errorDetails.push_back(CdbEngine::tr("The CDB engine does not support start mode %1.").arg(sp.startMode));
- return false;
- }
- if (abi.binaryFormat() != Abi::PEFormat || abi.os() != Abi::WindowsOS) {
- check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine does not support the %1 ABI.").
- arg(abi.toString()));
- return false;
- }
- if (sp.startMode == AttachCore && !isMsvcFlavor(abi.osFlavor())) {
- check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine cannot debug gdb core files."));
- return false;
- }
- if (sp.debuggerCommand.isEmpty()) {
- check->errorDetails.push_back(msgNoCdbBinaryForToolChain(abi));
- check->settingsCategory = QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
- check->settingsPage = QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
- return false;
- }
- return true;
- #else
- Q_UNUSED(sp);
- check->errorDetails.push_back(QString::fromLatin1("Unsupported debug mode"));
- return false;
- #endif
- }
- void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
- {
- #ifdef Q_OS_WIN
- opts->push_back(new CdbOptionsPage);
- #else
- Q_UNUSED(opts);
- #endif
- }
- #define QT_CREATOR_CDB_EXT "qtcreatorcdbext"
- static inline Utils::SavedAction *theAssemblerAction()
- {
- return debuggerCore()->action(OperateByInstruction);
- }
- CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
- DebuggerEngine *masterEngine, const OptionsPtr &options) :
- DebuggerEngine(sp, CppLanguage, masterEngine),
- m_creatorExtPrefix("<qtcreatorcdbext>|"),
- m_tokenPrefix("<token>"),
- m_options(options),
- m_effectiveStartMode(NoStartMode),
- m_accessible(false),
- m_specialStopMode(NoSpecialStop),
- m_nextCommandToken(0),
- m_currentBuiltinCommandIndex(-1),
- m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
- m_operateByInstructionPending(true),
- m_operateByInstruction(true), // Default CDB setting
- m_notifyEngineShutdownOnTermination(false),
- m_hasDebuggee(false),
- m_elapsedLogTime(0),
- m_sourceStepInto(false),
- m_watchPointX(0),
- m_watchPointY(0),
- m_ignoreCdbOutput(false)
- {
- connect(theAssemblerAction(), 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()));
- }
- void CdbEngine::init()
- {
- m_effectiveStartMode = NoStartMode;
- notifyInferiorPid(0);
- m_accessible = false;
- m_specialStopMode = NoSpecialStop;
- m_nextCommandToken = 0;
- m_currentBuiltinCommandIndex = -1;
- m_operateByInstructionPending = theAssemblerAction()->isChecked();
- m_operateByInstruction = true; // Default CDB setting
- m_notifyEngineShutdownOnTermination = false;
- m_hasDebuggee = false;
- m_sourceStepInto = false;
- m_watchPointX = m_watchPointY = 0;
- m_ignoreCdbOutput = false;
- m_outputBuffer.clear();
- m_builtinCommandQueue.clear();
- m_extensionCommandQueue.clear();
- m_extensionMessageBuffer.clear();
- m_pendingBreakpointMap.clear();
- m_customSpecialStopData.clear();
- m_symbolAddressCache.clear();
- m_coreStopReason.reset();
- // Create local list of mappings in native separators
- m_sourcePathMappings.clear();
- const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions();
- if (!globalOptions->sourcePathMap.isEmpty()) {
- typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator;
- m_sourcePathMappings.reserve(globalOptions->sourcePathMap.size());
- const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd();
- for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) {
- m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
- QDir::toNativeSeparators(it.value())));
- }
- }
- QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process));
- }
- CdbEngine::~CdbEngine()
- {
- }
- void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
- {
- // To be set next time session becomes accessible
- m_operateByInstructionPending = operateByInstruction;
- if (state() == InferiorStopOk)
- syncOperateByInstruction(operateByInstruction);
- }
- void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
- {
- if (debug)
- qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, 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);
- }
- bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
- TextEditor::ITextEditor *editor,
- const DebuggerToolTipContext &contextIn)
- {
- 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 false;
- // Determine expression and function
- int line;
- int column;
- DebuggerToolTipContext context = contextIn;
- QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
- // Are we in the current stack frame
- if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
- return false;
- // No numerical or any other expressions [yet]
- if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_')))
- return false;
- // Can this be found as a local variable?
- const QByteArray localsPrefix(localsPrefixC);
- QByteArray iname = localsPrefix + exp.toAscii();
- if (!watchHandler()->hasItem(iname)) {
- // Nope, try a 'local.this.m_foo'.
- exp.prepend(QLatin1String("this."));
- iname.insert(localsPrefix.size(), "this.");
- if (!watchHandler()->hasItem(iname))
- return false;
- }
- DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
- tw->setContext(context);
- tw->setDebuggerModel(LocalsType);
- tw->setExpression(exp);
- tw->acquireEngine(this);
- DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
- return true;
- }
- // Determine full path to the CDB extension library.
- QString CdbEngine::extensionLibraryName(bool is64Bit)
- {
- // 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;
- }
- // Start the console stub with the sub process. Continue in consoleStubProcessStarted.
- bool CdbEngine::startConsole(const DebuggerStartParameters &sp, QString *errorMessage)
- {
- if (debug)
- qDebug("startConsole %s", qPrintable(sp.executable));
- m_consoleStub.reset(new Utils::ConsoleProcess);
- m_consoleStub->setMode(Utils::ConsoleProcess::Suspend);
- connect(m_consoleStub.data(), SIGNAL(processError(QString)),
- SLOT(consoleStubError(QString)));
- connect(m_consoleStub.data(), SIGNAL(processStarted()),
- SLOT(consoleStubProcessStarted()));
- connect(m_consoleStub.data(), SIGNAL(wrapperStopped()),
- SLOT(consoleStubExited()));
- m_consoleStub->setWorkingDirectory(sp.workingDirectory);
- if (sp.environment.size())
- m_consoleStub->setEnvironment(sp.environment);
- if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
- *errorMessage = tr("The console process '%1' could not be started.").arg(sp.executable);
- return false;
- }
- return true;
- }
- void CdbEngine::consoleStubError(const QString &msg)
- {
- if (debug)
- qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
- if (state() == EngineSetupRequested) {
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
- notifyEngineSetupFailed();
- } else {
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
- notifyEngineIll();
- }
- nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
- }
- void CdbEngine::consoleStubProcessStarted()
- {
- if (debug)
- qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
- // Attach to console process.
- DebuggerStartParameters attachParameters = startParameters();
- attachParameters.executable.clear();
- attachParameters.processArgs.clear();
- attachParameters.attachPID = m_consoleStub->applicationPID();
- attachParameters.startMode = AttachExternal;
- attachParameters.useTerminal = false;
- showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
- QString errorMessage;
- if (!launchCDB(attachParameters, &errorMessage)) {
- showMessage(errorMessage, LogError);
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
- notifyEngineSetupFailed();
- }
- }
- void CdbEngine::consoleStubExited()
- {
- }
- void CdbEngine::setupEngine()
- {
- if (debug)
- qDebug(">setupEngine");
- // Nag to add symbol server
- if (CdbSymbolPathListEditor::promptToAddSymbolServer(CdbOptions::settingsGroup(),
- &(m_options->symbolPaths)))
- m_options->toSettings(Core::ICore::settings());
- init();
- if (!m_logTime.elapsed())
- m_logTime.start();
- QString errorMessage;
- // Console: Launch the stub with the suspended application and attach to it
- // CDB in theory has a command line option '-2' that launches a
- // console, too, but that immediately closes when the debuggee quits.
- // Use the Creator stub instead.
- const DebuggerStartParameters &sp = startParameters();
- const bool launchConsole = isCreatorConsole(sp, *m_options);
- m_effectiveStartMode = launchConsole ? AttachExternal : sp.startMode;
- const bool ok = launchConsole ?
- startConsole(startParameters(), &errorMessage) :
- launchCDB(startParameters(), &errorMessage);
- if (debug)
- qDebug("<setupEngine ok=%d", ok);
- if (!ok) {
- showMessage(errorMessage, LogError);
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
- notifyEngineSetupFailed();
- }
- }
- bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessage)
- {
- if (debug)
- qDebug("launchCDB startMode=%d", sp.startMode);
- const QChar blank(QLatin1Char(' '));
- // Start engine which will run until initial breakpoint:
- // Determine binary (force MSVC), 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)
- const QString executable = sp.debuggerCommand;
- if (executable.isEmpty()) {
- *errorMessage = tr("There is no CDB executable specified.");
- return false;
- }
- const bool is64bit =
- #ifdef Q_OS_WIN
- Utils::winIs64BitBinary(executable);
- #else
- false;
- #endif
- const QFileInfo extensionFi(CdbEngine::extensionLibraryName(is64bit));
- if (!extensionFi.isFile()) {
- *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
- arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
- return false;
- }
- const QString extensionFileName = extensionFi.fileName();
- // Prepare arguments
- QStringList arguments;
- const bool isRemote = sp.startMode == AttachToRemoteServer;
- if (isRemote) { // Must be first
- arguments << QLatin1String("-remote") << sp.remoteChannel;
- } else {
- arguments << (QLatin1String("-a") + extensionFileName);
- }
- // Source line info/No terminal breakpoint / Pull extension
- arguments << QLatin1String("-lines") << QLatin1String("-G")
- // register idle (debuggee stop) notification
- << QLatin1String("-c")
- << QLatin1String(".idle_cmd ") + QString::fromLatin1(m_extensionCommandPrefixBA) + QLatin1String("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(';')));
- // Compile argument string preserving quotes
- QString nativeArguments = m_options->additionalArguments;
- switch (sp.startMode) {
- case StartInternal:
- case StartExternal:
- if (!nativeArguments.isEmpty())
- nativeArguments.push_back(blank);
- nativeArguments += QDir::toNativeSeparators(sp.executable);
- break;
- case AttachToRemoteServer:
- break;
- case AttachExternal:
- case AttachCrashedExternal:
- arguments << QLatin1String("-p") << QString::number(sp.attachPID);
- if (sp.startMode == AttachCrashedExternal) {
- arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
- } else {
- if (isCreatorConsole(startParameters(), *m_options))
- arguments << QLatin1String("-pr") << QLatin1String("-pb");
- }
- break;
- case AttachCore:
- arguments << QLatin1String("-z") << sp.coreFile;
- break;
- default:
- *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
- return false;
- }
- if (!sp.processArgs.isEmpty()) { // Complete native argument string.
- if (!nativeArguments.isEmpty())
- nativeArguments.push_back(blank);
- nativeArguments += sp.processArgs;
- }
- const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
- arg(QDir::toNativeSeparators(executable),
- arguments.join(QString(blank)) + blank + nativeArguments,
- QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
- extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
- showMessage(msg, LogMisc);
- m_outputBuffer.clear();
- const QStringList environment = sp.environment.size() == 0 ?
- QProcessEnvironment::systemEnvironment().toStringList() :
- sp.environment.toStringList();
- m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
- if (!sp.workingDirectory.isEmpty())
- m_process.setWorkingDirectory(sp.workingDirectory);
- #ifdef Q_OS_WIN
- if (!nativeArguments.isEmpty()) // Appends
- m_process.setNativeArguments(nativeArguments);
- #endif
- 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;
- 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);
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
- notifyEngineSetupOk();
- }
- return true;
- }
- void CdbEngine::setupInferior()
- {
- if (debug)
- qDebug("setupInferior");
- // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
- // (attemptBreakpointSynchronization() will be directly called then)
- attemptBreakpointSynchronization();
- if (startParameters().breakOnMain) {
- const BreakpointParameters bp(BreakpointAtMain);
- postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings,
- BreakpointModelId(quint16(-1)), true), 0);
- }
- postCommand("sxn 0x4000001f", 0); // Do not break on WowX86 exceptions.
- postCommand(".asm source_line", 0); // Source line in assembly
- postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
- }
- void CdbEngine::runEngine()
- {
- if (debug)
- qDebug("runEngine");
- foreach (const QString &breakEvent, m_options->breakEvents)
- postCommand(QByteArray("sxe ") + breakEvent.toAscii(), 0);
- if (startParameters().startMode == AttachCore) {
- QTC_ASSERT(!m_coreStopReason.isNull(), return; );
- notifyInferiorUnrunnable();
- processStop(*m_coreStopReason, false);
- } else {
- postCommand("g", 0);
- }
- }
- bool CdbEngine::commandsPending() const
- {
- return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
- }
- 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");
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
- notifyInferiorShutdownOk();
- return;
- }
- if (m_accessible) { // except console.
- if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
- detachDebugger();
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
- notifyInferiorShutdownOk();
- } else {
- // A command got stuck.
- if (commandsPending()) {
- showMessage(QLatin1String("Cannot shut down inferior due to pending commands."), LogWarning);
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
- notifyInferiorShutdownFailed();
- return;
- }
- if (!canInterruptInferior()) {
- showMessage(QLatin1String("Cannot interrupt the inferior."), LogWarning);
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
- notifyInferiorShutdownFailed();
- return;
- }
- 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)
- qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
- "accessible=%d,commands pending=%d",
- stateName(state()), isCdbProcessRunning(), m_accessible,
- commandsPending());
- if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
- notifyEngineShutdownOk();
- return;
- }
- // No longer trigger anything from messages
- m_ignoreCdbOutput = true;
- // Go for kill if there are commands pending.
- if (m_accessible && !commandsPending()) {
- // detach (except console): Wait for debugger to finish.
- if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
- detachDebugger();
- // Remote requires a bit more force to quit.
- if (m_effectiveStartMode == AttachToRemoteServer) {
- postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
- postCommand("qq", 0);
- } else {
- postCommand("q", 0);
- }
- m_notifyEngineShutdownOnTermination = true;
- return;
- } else {
- // Remote process. No can do, currently
- m_notifyEngineShutdownOnTermination = true;
- Utils::SynchronousProcess::stopProcess(m_process);
- 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");
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
- notifyEngineIll();
- } else {
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
- notifyEngineShutdownOk();
- }
- } else {
- // The QML/CPP engine relies on the standard sequence of InferiorShutDown,etc.
- // Otherwise, we take a shortcut.
- if (isSlaveEngine()) {
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorExited")
- notifyInferiorExited();
- } else {
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
- notifyEngineSpontaneousShutdown();
- }
- }
- }
- void CdbEngine::detachDebugger()
- {
- postCommand(".detach", 0);
- }
- static inline bool isWatchIName(const QByteArray &iname)
- {
- return iname.startsWith("watch");
- }
- void CdbEngine::updateWatchData(const WatchData &dataIn,
- const WatchUpdateFlags & flags)
- {
- if (debug || debugLocals || debugWatches)
- qDebug("CdbEngine::updateWatchData() %dms accessible=%d %s incr=%d: %s",
- elapsedLogTime(), m_accessible, stateName(state()),
- flags.tryIncremental,
- qPrintable(dataIn.toString()));
- if (!m_accessible) // Add watch data while running?
- return;
- // New watch item?
- if (isWatchIName(dataIn.iname) && dataIn.isValueNeeded()) {
- QByteArray args;
- ByteArrayInputStream str(args);
- str << dataIn.iname << " \"" << dataIn.exp << '"';
- postExtensionCommand("addwatch", args, 0,
- &CdbEngine::handleAddWatch, 0,
- qVariantFromValue(dataIn));
- return;
- }
- if (!dataIn.hasChildren && !dataIn.isValueNeeded()) {
- WatchData data = dataIn;
- data.setAllUnneeded();
- watchHandler()->insertData(data);
- return;
- }
- updateLocalVariable(dataIn.iname);
- }
- void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
- {
- WatchData item = qvariant_cast<WatchData>(reply->cookie);
- if (debugWatches)
- qDebug() << "handleAddWatch ok=" << reply->success << item.iname;
- if (reply->success) {
- updateLocalVariable(item.iname);
- } else {
- item.setError(tr("Unable to add expression"));
- watchHandler()->insertIncompleteData(item);
- showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
- arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
- QString::fromLocal8Bit(reply->errorMessage)), LogError);
- }
- }
- void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
- {
- if (debuggerCore()->boolSetting(VerboseLog))
- str << blankSeparator << "-v";
- 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;
- }
- void CdbEngine::updateLocalVariable(const QByteArray &iname)
- {
- const bool isWatch = isWatchIName(iname);
- if (debugWatches)
- qDebug() << "updateLocalVariable watch=" << isWatch << iname;
- QByteArray localsArguments;
- ByteArrayInputStream str(localsArguments);
- addLocalsOptions(str);
- if (!isWatch) {
- const int stackFrame = stackHandler()->currentIndex();
- if (stackFrame < 0) {
- qWarning("Internal error; no stack frame in updateLocalVariable");
- return;
- }
- str << blankSeparator << stackFrame;
- }
- str << blankSeparator << iname;
- postExtensionCommand(isWatch ? "watches" : "locals",
- localsArguments, 0,
- &CdbEngine::handleLocals,
- 0, QVariant(int(PartialLocalsUpdate)));
- }
- bool CdbEngine::hasCapability(unsigned cap) const
- {
- return cap & (DisassemblerCapability | RegisterCapability
- | ShowMemoryCapability
- |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability|WatchWidgetsCapability
- |ReloadModuleCapability
- |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
- |BreakConditionCapability|TracePointCapability
- |BreakModuleCapability
- |OperateByInstructionCapability
- |RunToLineCapability
- |MemoryAddressCapability);
- }
- void CdbEngine::executeStep()
- {
- if (!m_operateByInstruction)
- m_sourceStepInto = true; // See explanation at handleStackTrace().
- postCommand(QByteArray("t"), 0); // Step into-> t (trace)
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
- notifyInferiorRunRequested();
- }
- void CdbEngine::executeStepOut()
- {
- postCommand(QByteArray("gu"), 0); // Step out-> gu (go up)
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
- notifyInferiorRunRequested();
- }
- void CdbEngine::executeNext()
- {
- postCommand(QByteArray("p"), 0); // Step over -> p
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
- notifyInferiorRunRequested();
- }
- void CdbEngine::executeStepI()
- {
- executeStep();
- }
- void CdbEngine::executeNextI()
- {
- executeNext();
- }
- void CdbEngine::continueInferior()
- {
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
- notifyInferiorRunRequested();
- doContinueInferior();
- }
- void CdbEngine::doContinueInferior()
- {
- postCommand(QByteArray("g"), 0);
- }
- bool CdbEngine::canInterruptInferior() const
- {
- return m_effectiveStartMode != AttachToRemoteServer && inferiorPid();
- }
- void CdbEngine::interruptInferior()
- {
- if (debug)
- qDebug() << "CdbEngine::interruptInferior()" << stateName(state());
- bool ok = false;
- if (!canInterruptInferior()) {
- showMessage(tr("Interrupting is not possible in remote sessions."), LogError);
- } else {
- ok = doInterruptInferior(NoSpecialStop);
- }
- // Restore running state if stop failed.
- if (!ok) {
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorStopOk")
- notifyInferiorStopOk();
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
- notifyInferiorRunRequested();
- STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk")
- notifyInferiorRunOk();
- }
- }
- void CdbEngine::doInterruptInferiorCustomSpecialStop(const QVariant &v)
- {
- if (m_specialStopMode == NoSpecialStop)
- doInterruptInferior(CustomSpecialStop);
- m_customSpecialStopData.push_back(v);
- }
- bool CdbEngine::doInterruptInferior(SpecialStopMode sm)
- {
- const SpecialStopMode oldSpecialMode = m_specialStopMode;
- m_specialStopMode = sm;
- showMessage(QString::fromLatin1("Interrupting process %1...").arg(inferiorPid()), LogMisc);
- QString errorMessage;
- const bool ok = interruptProcess(inferiorPid(), CdbEngineType, &errorMessage);
- if (!ok) {
- m_specialStopMode = oldSpecialMode;
- showMessage(errorMessage, LogError);
- }
- return ok;
- }
- void CdbEngine::executeRunToLine(const ContextData &data)
- {
- // Add one-shot breakpoint
- BreakpointParameters bp;
- if (data.address) {
- bp.type =BreakpointByAddress;
- bp.address = data.address;
- } else {
- bp.type =BreakpointByFileAndLine;
- bp.fileName = data.fileName;
- bp.lineNumber = data.lineNumber;
- }
- postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(quint16(-1)), true), 0);
- continueInferior();
- }
- void CdbEngine::executeRunToFunction(const QString &functionName)
- {
- // Add one-shot breakpoint
- BreakpointParameters bp(BreakpointByFunction);
- bp.functionName = functionName;
- postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(quint16(-1)), true), 0);
- continueInferior();
- }
- void CdbEngine::setRegisterValue(int regnr, const QString &value)
- {
- const Registers registers = registerHandler()->registers();
- 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 ContextData &data)
- {
- if (data.address) {
- // Goto address directly.
- jumpToAddress(data.address);
- gotoLocation(Location(data.address));
- } else {
- // Jump to source line: Resolve source line address and go to that location
- QByteArray cmd;
- ByteArrayInputStream str(cmd);
- str << "? `" << QDir::toNativeSeparators(data.fileName) << ':' << data.lineNumber << '`';
- const QVariant cookie = qVariantFromValue(data);
- postBuiltinCommand(cmd, 0, &CdbEngine::handleJumpToLineAddressResolution, 0, cookie);
- }
- }
- void CdbEngine::jumpToAddress(quint64 address)
- {
- // Fake a jump to address by setting the PC register.
- QByteArray registerCmd;
- ByteArrayInputStream str(registerCmd);
- // PC-register depending on 64/32bit.
- str << "r " << (startParameters().toolChainAbi.wordWidth() == 64 ? "rip" : "eip") << '=';
- str.setHexPrefix(true);
- str.setIntegerBase(16);
- str << address;
- postCommand(registerCmd, 0);
- }
- 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().trimmed();
- const int equalPos = answer.indexOf(" = ");
- if (equalPos == -1)
- return;
- answer.remove(0, equalPos + 3);
- const int apPos = answer.indexOf('`');
- if (apPos != -1)
- answer.remove(apPos, 1);
- bool ok;
- const quint64 address = answer.toLongLong(&ok, 16);
- if (ok && address) {
- QTC_ASSERT(qVariantCanConvert<ContextData>(cmd->cookie), return);
- const ContextData cookie = qvariant_cast<ContextData>(cmd->cookie);
- jumpToAddress(address);
- gotoLocation(Location(cookie.fileName, cookie.lineNumber));
- }
- }
- static inline bool isAsciiWord(const QString &s)
- {
- foreach (const QChar &c, s) {
- if (!c.isLetterOrNumber() || c.toAscii() == 0)
- return false;
- }
- return true;
- }
- void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value)
- {
- 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);
- switch (value.type()) {
- case QVariant::String: {
- // Convert qstring to Utf16 data not considering endianness for Windows.
- const QString s = value.toString();
- if (isAsciiWord(s)) {
- str << m_extensionCommandPrefixBA << "assign \"" << w->iname << '='
- << s.toLatin1() << '"';
- } else {
- const QByteArray utf16(reinterpret_cast<const char *>(s.utf16()), 2 * s.size());
- str << m_extensionCommandPrefixBA << "assign -u " << w->iname << '='
- << utf16.toHex();
- }
- }
- break;
- default:
- str << m_extensionCommandPrefixBA << "assign " << w->iname << '='
- << value.toString();
- break;
- }
- postCommand(cmd, 0);
- // Update all locals in case we change a union or something pointed to
- // that affects other variables, too.
- updateLocals();
- }
- void CdbEngine::parseThreads(const GdbMi &data, int forceCurrentThreadId /* = -1 */)
- {
- int currentThreadId;
- Threads threads = ThreadsHandler::parseGdbmiThreads(data, ¤tThreadId);
- threadsHandler()->setThreads(threads);
- threadsHandler()->setCurrentThreadId(forceCurrentThreadId >= 0 ?
- forceCurrentThreadId : currentThreadId);
- }
- void CdbEngine::handleThreads(const CdbExtensionCommandPtr &reply)
- {
- if (debug)
- qDebug("CdbEngine::handleThreads success=%d", reply->success);
- if (reply->success) {
- GdbMi data;
- data.fromString(reply->reply);
- parseThreads(data);
- // Continue sequence
- postCommandSequence(reply->commandSequence);
- } else {
- showMessage(QString::fromLatin1(reply->errorMessage), LogError);
- }
- }
- void CdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
- {
- if (languages & CppLanguage)
- 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::fromLatin1(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, co…
Large files files are truncated, but you can click here to view the full file