2013-03-22 10:28:49 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
|
|
|
|
** Contact: http://www.qt-project.org/legal
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
|
|
|
|
**
|
|
|
|
|
** 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.
|
|
|
|
|
**
|
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "lldbengine.h"
|
|
|
|
|
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <debugger/debuggeractions.h>
|
|
|
|
|
#include <debugger/debuggercore.h>
|
|
|
|
|
#include <debugger/debuggerdialogs.h>
|
|
|
|
|
#include <debugger/debuggerplugin.h>
|
|
|
|
|
#include <debugger/debuggerprotocol.h>
|
|
|
|
|
#include <debugger/debuggerstartparameters.h>
|
|
|
|
|
#include <debugger/debuggerstringutils.h>
|
|
|
|
|
#include <debugger/debuggertooltipmanager.h>
|
2013-03-22 10:28:49 +01:00
|
|
|
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <debugger/breakhandler.h>
|
|
|
|
|
#include <debugger/disassemblerlines.h>
|
|
|
|
|
#include <debugger/moduleshandler.h>
|
|
|
|
|
#include <debugger/registerhandler.h>
|
|
|
|
|
#include <debugger/stackhandler.h>
|
|
|
|
|
#include <debugger/sourceutils.h>
|
|
|
|
|
#include <debugger/threadshandler.h>
|
|
|
|
|
#include <debugger/watchhandler.h>
|
|
|
|
|
#include <debugger/watchutils.h>
|
2013-03-22 10:28:49 +01:00
|
|
|
|
|
|
|
|
#include <utils/qtcassert.h>
|
2013-04-08 10:11:02 +02:00
|
|
|
#include <utils/savedaction.h>
|
2013-03-22 10:28:49 +01:00
|
|
|
|
|
|
|
|
#include <texteditor/itexteditor.h>
|
|
|
|
|
#include <coreplugin/idocument.h>
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
|
|
|
|
|
#include <QDateTime>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QVariant>
|
|
|
|
|
|
|
|
|
|
#include <QApplication>
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QToolTip>
|
|
|
|
|
|
2013-04-04 12:23:29 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
|
|
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LldbEngine
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
LldbEngine::LldbEngine(const DebuggerStartParameters &startParameters)
|
|
|
|
|
: DebuggerEngine(startParameters)
|
|
|
|
|
{
|
2013-05-07 08:46:51 +02:00
|
|
|
m_lastAgentId = 0;
|
2013-05-07 16:43:20 +02:00
|
|
|
m_lastToken = 0;
|
2013-03-22 10:28:49 +01:00
|
|
|
setObjectName(QLatin1String("LldbEngine"));
|
2013-05-29 14:54:47 +02:00
|
|
|
|
|
|
|
|
connect(debuggerCore()->action(AutoDerefPointers), SIGNAL(valueChanged(QVariant)),
|
|
|
|
|
SLOT(updateLocals()));
|
|
|
|
|
connect(debuggerCore()->action(CreateFullBacktrace), SIGNAL(triggered()),
|
|
|
|
|
SLOT(updateAll()));
|
|
|
|
|
connect(debuggerCore()->action(UseDebuggingHelpers), SIGNAL(valueChanged(QVariant)),
|
|
|
|
|
SLOT(updateLocals()));
|
|
|
|
|
connect(debuggerCore()->action(UseDynamicType), SIGNAL(valueChanged(QVariant)),
|
|
|
|
|
SLOT(updateLocals()));
|
|
|
|
|
connect(debuggerCore()->action(IntelFlavor), SIGNAL(valueChanged(QVariant)),
|
|
|
|
|
SLOT(updateAll()));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LldbEngine::~LldbEngine()
|
|
|
|
|
{}
|
|
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2013-05-07 16:43:20 +02:00
|
|
|
runCommand(Command("executeDebuggerCommand").arg("command", command));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-05-07 10:45:53 +02:00
|
|
|
void LldbEngine::runCommand(const Command &command)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll());
|
2013-05-07 16:43:20 +02:00
|
|
|
++m_lastToken;
|
|
|
|
|
QByteArray token = QByteArray::number(m_lastToken);
|
2013-05-07 10:45:53 +02:00
|
|
|
QByteArray cmd = "db {'cmd':'" + command.function + "',"
|
2013-05-07 16:43:20 +02:00
|
|
|
+ command.args + "'token':" + token + "}\n";
|
|
|
|
|
showMessage(_(token + cmd), LogInput);
|
2013-05-02 14:31:35 +02:00
|
|
|
m_lldbProc.write(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::shutdownInferior()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
|
2013-05-29 15:38:49 +02:00
|
|
|
runCommand(Command("shutdownInferior"));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::shutdownEngine()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
|
|
|
|
|
m_lldbProc.kill();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::setupEngine()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
|
|
|
|
|
|
2013-05-16 15:09:24 +02:00
|
|
|
m_lldbCmd = startParameters().debuggerCommand;
|
|
|
|
|
showMessage(_("STARTING LLDB ") + m_lldbCmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
|
|
|
|
|
connect(&m_lldbProc, SIGNAL(error(QProcess::ProcessError)),
|
|
|
|
|
SLOT(handleLldbError(QProcess::ProcessError)));
|
|
|
|
|
connect(&m_lldbProc, SIGNAL(finished(int,QProcess::ExitStatus)),
|
|
|
|
|
SLOT(handleLldbFinished(int,QProcess::ExitStatus)));
|
|
|
|
|
connect(&m_lldbProc, SIGNAL(readyReadStandardOutput()),
|
|
|
|
|
SLOT(readLldbStandardOutput()));
|
|
|
|
|
connect(&m_lldbProc, SIGNAL(readyReadStandardError()),
|
|
|
|
|
SLOT(readLldbStandardError()));
|
|
|
|
|
|
|
|
|
|
connect(this, SIGNAL(outputReady(QByteArray)),
|
2013-04-11 17:06:17 +02:00
|
|
|
SLOT(handleResponse(QByteArray)), Qt::QueuedConnection);
|
2013-03-22 10:28:49 +01:00
|
|
|
|
2013-05-16 15:09:24 +02:00
|
|
|
m_lldbProc.start(_("python"), QStringList() << _("-i")
|
2013-09-25 18:22:01 +02:00
|
|
|
<< (Core::ICore::resourcePath() + _("/debugger/lldbbridge.py")) << m_lldbCmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
|
|
|
|
|
if (!m_lldbProc.waitForStarted()) {
|
2013-10-11 12:45:42 +02:00
|
|
|
const QString msg = tr("Unable to start LLDB '%1': %2")
|
2013-05-16 15:09:24 +02:00
|
|
|
.arg(m_lldbCmd, m_lldbProc.errorString());
|
2013-03-22 10:28:49 +01:00
|
|
|
notifyEngineSetupFailed();
|
|
|
|
|
showMessage(_("ADAPTER START FAILED"));
|
2013-04-30 10:46:48 +02:00
|
|
|
if (!msg.isEmpty())
|
2013-05-14 17:36:28 +02:00
|
|
|
Core::ICore::showWarningWithOptions(tr("Adapter start failed."), msg);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::setupInferior()
|
|
|
|
|
{
|
2013-05-07 10:45:53 +02:00
|
|
|
QString executable = QFileInfo(startParameters().executable).absoluteFilePath();
|
|
|
|
|
runCommand(Command("setupInferior").arg("executable", executable));
|
2013-05-30 15:35:52 +02:00
|
|
|
|
|
|
|
|
requestUpdateWatchers();
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::runEngine()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
2013-04-12 14:41:05 +02:00
|
|
|
|
2013-05-07 10:45:53 +02:00
|
|
|
Command cmd("handleBreakpoints");
|
|
|
|
|
if (attemptBreakpointSynchronizationHelper(&cmd)) {
|
2013-05-02 14:31:35 +02:00
|
|
|
runEngine2();
|
2013-05-07 10:45:53 +02:00
|
|
|
} else {
|
|
|
|
|
cmd.arg("continuation", "runEngine2");
|
|
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
2013-05-02 14:31:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::runEngine2()
|
|
|
|
|
{
|
2013-03-22 10:28:49 +01:00
|
|
|
showStatusMessage(tr("Running requested..."), 5000);
|
2013-04-11 17:06:17 +02:00
|
|
|
runCommand("runEngine");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::interruptInferior()
|
|
|
|
|
{
|
|
|
|
|
showStatusMessage(tr("Interrupt requested..."), 5000);
|
2013-05-07 12:34:10 +02:00
|
|
|
runCommand("interruptInferior");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 10:59:36 +02:00
|
|
|
void LldbEngine::executeStep()
|
|
|
|
|
{
|
|
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 12:34:10 +02:00
|
|
|
runCommand("executeStep");
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
void LldbEngine::executeStepI()
|
|
|
|
|
{
|
|
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 12:34:10 +02:00
|
|
|
runCommand("executeStepI");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeStepOut()
|
|
|
|
|
{
|
|
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 12:34:10 +02:00
|
|
|
runCommand("executeStepOut");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeNext()
|
|
|
|
|
{
|
|
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 12:34:10 +02:00
|
|
|
runCommand("executeNext");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeNextI()
|
|
|
|
|
{
|
|
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 12:34:10 +02:00
|
|
|
runCommand("executeNextI");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::continueInferior()
|
|
|
|
|
{
|
|
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 12:34:10 +02:00
|
|
|
runCommand("continueInferior");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-11 17:06:17 +02:00
|
|
|
void LldbEngine::handleResponse(const QByteArray &response)
|
2013-04-09 10:59:36 +02:00
|
|
|
{
|
2013-04-30 10:46:48 +02:00
|
|
|
GdbMi all;
|
|
|
|
|
all.fromStringMultiple(response);
|
2013-04-10 15:54:04 +02:00
|
|
|
|
2013-05-02 14:31:35 +02:00
|
|
|
foreach (const GdbMi &item, all.children()) {
|
|
|
|
|
const QByteArray name = item.name();
|
|
|
|
|
if (name == "data")
|
|
|
|
|
refreshLocals(item);
|
|
|
|
|
else if (name == "stack")
|
|
|
|
|
refreshStack(item);
|
|
|
|
|
else if (name == "registers")
|
|
|
|
|
refreshRegisters(item);
|
|
|
|
|
else if (name == "threads")
|
|
|
|
|
refreshThreads(item);
|
|
|
|
|
else if (name == "typeinfo")
|
|
|
|
|
refreshTypeInfo(item);
|
|
|
|
|
else if (name == "state")
|
|
|
|
|
refreshState(item);
|
|
|
|
|
else if (name == "location")
|
|
|
|
|
refreshLocation(item);
|
|
|
|
|
else if (name == "modules")
|
|
|
|
|
refreshModules(item);
|
2013-05-07 11:39:31 +02:00
|
|
|
else if (name == "symbols")
|
|
|
|
|
refreshSymbols(item);
|
2013-05-02 14:31:35 +02:00
|
|
|
else if (name == "bkpts")
|
|
|
|
|
refreshBreakpoints(item);
|
2013-05-29 12:14:49 +02:00
|
|
|
else if (name == "output")
|
|
|
|
|
refreshOutput(item);
|
2013-05-03 17:18:07 +02:00
|
|
|
else if (name == "disassembly")
|
|
|
|
|
refreshDisassembly(item);
|
2013-05-07 08:46:51 +02:00
|
|
|
else if (name == "memory")
|
|
|
|
|
refreshMemory(item);
|
2013-05-02 14:31:35 +02:00
|
|
|
else if (name == "continuation")
|
|
|
|
|
runContinuation(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::runContinuation(const GdbMi &data)
|
|
|
|
|
{
|
|
|
|
|
const QByteArray target = data.data();
|
|
|
|
|
QMetaObject::invokeMethod(this, target, Qt::QueuedConnection);
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
void LldbEngine::executeRunToLine(const ContextData &data)
|
|
|
|
|
{
|
2013-04-10 15:54:04 +02:00
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(Command("executeRunToLine")
|
|
|
|
|
.arg("file", data.fileName).arg("line", data.address));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeRunToFunction(const QString &functionName)
|
|
|
|
|
{
|
2013-04-10 15:54:04 +02:00
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(Command("executeRunToFunction").arg("function", functionName));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeJumpToLine(const ContextData &data)
|
|
|
|
|
{
|
2013-04-10 15:54:04 +02:00
|
|
|
resetLocation();
|
|
|
|
|
notifyInferiorRunRequested();
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(Command("executeJumpToLine")
|
|
|
|
|
.arg("file", data.fileName).arg("line", data.address));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::activateFrame(int frameIndex)
|
|
|
|
|
{
|
|
|
|
|
resetLocation();
|
|
|
|
|
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
|
|
|
|
return;
|
|
|
|
|
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(Command("activateFrame").arg("index", frameIndex));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::selectThread(ThreadId threadId)
|
|
|
|
|
{
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(Command("selectThread").arg("id", threadId.raw()));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const
|
|
|
|
|
{
|
|
|
|
|
return breakHandler()->breakpointData(id).isCppBreakpoint()
|
|
|
|
|
&& startParameters().startMode != AttachCore;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-07 10:45:53 +02:00
|
|
|
bool LldbEngine::attemptBreakpointSynchronizationHelper(Command *cmd)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
|
|
|
|
BreakHandler *handler = breakHandler();
|
|
|
|
|
|
2013-04-09 10:59:36 +02:00
|
|
|
foreach (BreakpointModelId id, handler->unclaimedBreakpointIds()) {
|
|
|
|
|
// Take ownership of the breakpoint. Requests insertion.
|
|
|
|
|
if (acceptsBreakpoint(id)) {
|
|
|
|
|
showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2")
|
|
|
|
|
.arg(id.toString()).arg(handler->state(id)));
|
|
|
|
|
handler->setEngine(id, this);
|
|
|
|
|
} else {
|
|
|
|
|
showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
|
|
|
|
|
.arg(id.toString()).arg(handler->state(id)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool done = true;
|
2013-05-07 10:45:53 +02:00
|
|
|
cmd->beginList("bkpts");
|
2013-04-09 10:59:36 +02:00
|
|
|
foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) {
|
|
|
|
|
const BreakpointResponse &response = handler->response(id);
|
2013-06-14 15:15:09 +02:00
|
|
|
const BreakpointState bpState = handler->state(id);
|
|
|
|
|
switch (bpState) {
|
2013-04-09 10:59:36 +02:00
|
|
|
case BreakpointNew:
|
|
|
|
|
// Should not happen once claimed.
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
break;
|
|
|
|
|
case BreakpointInsertRequested:
|
|
|
|
|
done = false;
|
2013-05-07 10:45:53 +02:00
|
|
|
cmd->beginGroup()
|
|
|
|
|
.arg("operation", "add")
|
|
|
|
|
.arg("modelid", id.toByteArray())
|
|
|
|
|
.arg("type", handler->type(id))
|
|
|
|
|
.arg("ignorecount", handler->ignoreCount(id))
|
2013-06-14 15:15:09 +02:00
|
|
|
.arg("condition", handler->condition(id).toHex())
|
2013-05-07 10:45:53 +02:00
|
|
|
.arg("function", handler->functionName(id).toUtf8())
|
|
|
|
|
.arg("oneshot", handler->isOneShot(id))
|
|
|
|
|
.arg("enabled", handler->isEnabled(id))
|
|
|
|
|
.arg("file", handler->fileName(id).toUtf8())
|
|
|
|
|
.arg("line", handler->lineNumber(id))
|
2013-06-14 15:15:09 +02:00
|
|
|
.arg("address", handler->address(id))
|
|
|
|
|
.arg("expression", handler->expression(id))
|
2013-05-07 10:45:53 +02:00
|
|
|
.endGroup();
|
2013-04-09 10:59:36 +02:00
|
|
|
handler->notifyBreakpointInsertProceeding(id);
|
|
|
|
|
break;
|
|
|
|
|
case BreakpointChangeRequested:
|
|
|
|
|
done = false;
|
2013-05-07 10:45:53 +02:00
|
|
|
cmd->beginGroup()
|
|
|
|
|
.arg("operation", "change")
|
|
|
|
|
.arg("modelid", id.toByteArray())
|
|
|
|
|
.arg("lldbid", response.id.toByteArray())
|
|
|
|
|
.arg("type", handler->type(id))
|
|
|
|
|
.arg("ignorecount", handler->ignoreCount(id))
|
2013-06-14 15:15:09 +02:00
|
|
|
.arg("condition", handler->condition(id).toHex())
|
2013-05-07 10:45:53 +02:00
|
|
|
.arg("function", handler->functionName(id).toUtf8())
|
|
|
|
|
.arg("oneshot", handler->isOneShot(id))
|
|
|
|
|
.arg("enabled", handler->isEnabled(id))
|
|
|
|
|
.arg("file", handler->fileName(id).toUtf8())
|
|
|
|
|
.arg("line", handler->lineNumber(id))
|
2013-06-14 15:15:09 +02:00
|
|
|
.arg("address", handler->address(id))
|
|
|
|
|
.arg("expression", handler->expression(id))
|
2013-05-07 10:45:53 +02:00
|
|
|
.endGroup();
|
2013-04-09 10:59:36 +02:00
|
|
|
handler->notifyBreakpointChangeProceeding(id);
|
|
|
|
|
break;
|
|
|
|
|
case BreakpointRemoveRequested:
|
|
|
|
|
done = false;
|
2013-05-07 10:45:53 +02:00
|
|
|
cmd->beginGroup()
|
|
|
|
|
.arg("operation", "remove")
|
|
|
|
|
.arg("modelid", id.toByteArray())
|
|
|
|
|
.arg("lldbid", response.id.toByteArray())
|
|
|
|
|
.endGroup();
|
2013-04-09 10:59:36 +02:00
|
|
|
handler->notifyBreakpointRemoveProceeding(id);
|
|
|
|
|
break;
|
|
|
|
|
case BreakpointChangeProceeding:
|
|
|
|
|
case BreakpointInsertProceeding:
|
|
|
|
|
case BreakpointRemoveProceeding:
|
|
|
|
|
case BreakpointInserted:
|
|
|
|
|
case BreakpointDead:
|
2013-06-14 15:15:09 +02:00
|
|
|
QTC_ASSERT(false, qDebug() << "UNEXPECTED STATE" << bpState << "FOR BP " << id);
|
2013-04-09 10:59:36 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
2013-06-14 15:15:09 +02:00
|
|
|
QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << bpState << "FOR BP" << id);
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
|
|
|
|
}
|
2013-05-07 10:45:53 +02:00
|
|
|
cmd->endList();
|
2013-04-12 14:41:05 +02:00
|
|
|
return done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::attemptBreakpointSynchronization()
|
|
|
|
|
{
|
|
|
|
|
showMessage(_("ATTEMPT BREAKPOINT SYNCHRONIZATION"));
|
|
|
|
|
if (!stateAcceptsBreakpointChanges()) {
|
|
|
|
|
showMessage(_("BREAKPOINT SYNCHRONIZATION NOT POSSIBLE IN CURRENT STATE"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-04-09 10:59:36 +02:00
|
|
|
|
2013-05-07 10:45:53 +02:00
|
|
|
Command cmd("handleBreakpoints");
|
|
|
|
|
if (!attemptBreakpointSynchronizationHelper(&cmd)) {
|
2013-04-09 10:59:36 +02:00
|
|
|
showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED"));
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(cmd);
|
2013-04-09 10:59:36 +02:00
|
|
|
} else {
|
|
|
|
|
showMessage(_("BREAKPOINTS ARE SYNCHRONIZED"));
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-03-22 10:28:49 +01:00
|
|
|
|
2013-04-09 10:59:36 +02:00
|
|
|
void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
|
|
|
|
BreakHandler *handler = breakHandler();
|
2013-05-03 18:26:10 +02:00
|
|
|
BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
|
2013-04-09 10:59:36 +02:00
|
|
|
BreakpointResponse response = handler->response(id);
|
2013-05-03 18:26:10 +02:00
|
|
|
BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data());
|
2013-04-09 10:59:36 +02:00
|
|
|
if (added)
|
|
|
|
|
response.id = rid;
|
|
|
|
|
QTC_CHECK(response.id == rid);
|
|
|
|
|
response.address = 0;
|
2013-05-07 12:09:54 +02:00
|
|
|
response.enabled = bkpt["enabled"].toInt();
|
|
|
|
|
response.ignoreCount = bkpt["ignorecount"].toInt();
|
2013-06-14 15:15:09 +02:00
|
|
|
response.condition = QByteArray::fromHex(bkpt["condition"].data());
|
2013-05-07 12:09:54 +02:00
|
|
|
response.hitCount = bkpt["hitcount"].toInt();
|
2013-04-09 10:59:36 +02:00
|
|
|
|
|
|
|
|
if (added) {
|
|
|
|
|
// Added.
|
2013-05-03 18:26:10 +02:00
|
|
|
GdbMi locations = bkpt["locations"];
|
2013-04-09 10:59:36 +02:00
|
|
|
const int numChild = locations.children().size();
|
|
|
|
|
if (numChild > 1) {
|
|
|
|
|
foreach (const GdbMi &location, locations.children()) {
|
2013-05-24 11:02:24 +02:00
|
|
|
const int locid = location["locid"].toInt();
|
2013-04-09 10:59:36 +02:00
|
|
|
BreakpointResponse sub;
|
2013-05-06 13:35:47 +02:00
|
|
|
sub.id = BreakpointResponseId(rid.majorPart(), locid);
|
2013-04-09 10:59:36 +02:00
|
|
|
sub.type = response.type;
|
2013-05-03 18:26:10 +02:00
|
|
|
sub.address = location["addr"].toAddress();
|
2013-05-24 11:02:24 +02:00
|
|
|
sub.functionName = location["func"].toUtf8();
|
2013-04-09 10:59:36 +02:00
|
|
|
handler->insertSubBreakpoint(id, sub);
|
|
|
|
|
}
|
|
|
|
|
} else if (numChild == 1) {
|
|
|
|
|
const GdbMi location = locations.childAt(0);
|
2013-05-03 18:26:10 +02:00
|
|
|
response.address = location["addr"].toAddress();
|
2013-05-24 11:02:24 +02:00
|
|
|
response.functionName = location["func"].toUtf8();
|
2013-04-09 10:59:36 +02:00
|
|
|
} else {
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
}
|
|
|
|
|
handler->setResponse(id, response);
|
|
|
|
|
handler->notifyBreakpointInsertOk(id);
|
|
|
|
|
} else {
|
|
|
|
|
// Changed.
|
|
|
|
|
handler->setResponse(id, response);
|
|
|
|
|
handler->notifyBreakpointChangeOk(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-07 08:46:51 +02:00
|
|
|
void LldbEngine::refreshDisassembly(const GdbMi &data)
|
2013-05-03 17:18:07 +02:00
|
|
|
{
|
|
|
|
|
DisassemblerLines result;
|
|
|
|
|
|
2013-05-07 12:09:54 +02:00
|
|
|
int cookie = data["cookie"].toInt();
|
2013-05-07 08:46:51 +02:00
|
|
|
QPointer<DisassemblerAgent> agent = m_disassemblerAgents.key(cookie);
|
|
|
|
|
if (!agent.isNull()) {
|
|
|
|
|
foreach (const GdbMi &line, data["lines"].children()) {
|
|
|
|
|
DisassemblerLine dl;
|
2013-05-24 10:40:45 +02:00
|
|
|
dl.address = line["address"].toAddress();
|
2013-05-24 11:02:24 +02:00
|
|
|
dl.data = line["inst"].toUtf8();
|
|
|
|
|
dl.function = line["func-name"].toUtf8();
|
2013-05-24 10:40:45 +02:00
|
|
|
dl.offset = line["offset"].toInt();
|
2013-06-11 18:07:59 +02:00
|
|
|
QByteArray comment = line["comment"].data();
|
|
|
|
|
if (!comment.isEmpty())
|
|
|
|
|
dl.data += QString::fromUtf8(" # " + comment);
|
2013-05-07 08:46:51 +02:00
|
|
|
result.appendLine(dl);
|
|
|
|
|
}
|
|
|
|
|
agent->setContents(result);
|
2013-05-03 17:18:07 +02:00
|
|
|
}
|
2013-05-07 08:46:51 +02:00
|
|
|
}
|
2013-05-03 17:18:07 +02:00
|
|
|
|
2013-05-07 08:46:51 +02:00
|
|
|
void LldbEngine::refreshMemory(const GdbMi &data)
|
|
|
|
|
{
|
2013-05-07 12:09:54 +02:00
|
|
|
int cookie = data["cookie"].toInt();
|
2013-05-24 10:40:45 +02:00
|
|
|
qulonglong addr = data["address"].toAddress();
|
2013-05-07 08:46:51 +02:00
|
|
|
QPointer<MemoryAgent> agent = m_memoryAgents.key(cookie);
|
|
|
|
|
if (!agent.isNull()) {
|
|
|
|
|
QPointer<QObject> token = m_memoryAgentTokens.value(cookie);
|
|
|
|
|
QTC_ASSERT(!token.isNull(), return);
|
|
|
|
|
QByteArray ba = QByteArray::fromHex(data["contents"].data());
|
|
|
|
|
agent->addLazyData(token.data(), addr, ba);
|
|
|
|
|
}
|
2013-05-03 17:18:07 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-29 12:14:49 +02:00
|
|
|
void LldbEngine::refreshOutput(const GdbMi &output)
|
|
|
|
|
{
|
|
|
|
|
QByteArray channel = output["channel"].data();
|
|
|
|
|
QByteArray data = QByteArray::fromHex(output["data"].data());
|
|
|
|
|
LogChannel ch = AppStuff;
|
|
|
|
|
if (channel == "stdout")
|
|
|
|
|
ch = AppOutput;
|
|
|
|
|
else if (channel == "stderr")
|
|
|
|
|
ch = AppError;
|
|
|
|
|
showMessage(QString::fromUtf8(data), ch);
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-11 17:06:17 +02:00
|
|
|
void LldbEngine::refreshBreakpoints(const GdbMi &bkpts)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2013-05-02 14:31:35 +02:00
|
|
|
BreakHandler *handler = breakHandler();
|
2013-05-07 10:45:53 +02:00
|
|
|
foreach (const GdbMi &bkpt, bkpts.children()) {
|
|
|
|
|
QByteArray op = bkpt["operation"].data();
|
|
|
|
|
if (op == "added") {
|
|
|
|
|
BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
|
|
|
|
|
QTC_CHECK(handler->state(id) == BreakpointInsertProceeding);
|
|
|
|
|
updateBreakpointData(bkpt, true);
|
|
|
|
|
} else if (op == "changed") {
|
|
|
|
|
BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
|
|
|
|
|
QTC_CHECK(handler->state(id) == BreakpointChangeProceeding);
|
|
|
|
|
updateBreakpointData(bkpt, false);
|
|
|
|
|
} else if (op == "removed") {
|
|
|
|
|
BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
|
|
|
|
|
QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding);
|
|
|
|
|
handler->notifyBreakpointRemoveOk(id);
|
|
|
|
|
}
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::loadSymbols(const QString &moduleName)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(moduleName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::loadAllSymbols()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::reloadModules()
|
|
|
|
|
{
|
2013-04-11 17:06:17 +02:00
|
|
|
runCommand("listModules");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-10 15:54:04 +02:00
|
|
|
void LldbEngine::refreshModules(const GdbMi &modules)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2013-04-10 15:54:04 +02:00
|
|
|
Modules mods;
|
|
|
|
|
foreach (const GdbMi &item, modules.children()) {
|
2013-03-22 10:28:49 +01:00
|
|
|
Module module;
|
2013-05-24 11:02:24 +02:00
|
|
|
module.modulePath = item["file"].toUtf8();
|
|
|
|
|
module.moduleName = item["name"].toUtf8();
|
2013-04-08 11:44:24 +02:00
|
|
|
module.symbolsRead = Module::UnknownReadState;
|
2013-05-07 11:39:31 +02:00
|
|
|
module.startAddress = item["loaded_addr"].toAddress();
|
2013-04-08 11:44:24 +02:00
|
|
|
module.endAddress = 0; // FIXME: End address not easily available.
|
2013-04-10 15:54:04 +02:00
|
|
|
mods.append(module);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
2013-04-10 15:54:04 +02:00
|
|
|
modulesHandler()->setModules(mods);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::requestModuleSymbols(const QString &moduleName)
|
|
|
|
|
{
|
2013-05-07 11:39:31 +02:00
|
|
|
runCommand(Command("listSymbols").arg("module", moduleName));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-05-07 11:39:31 +02:00
|
|
|
void LldbEngine::refreshSymbols(const GdbMi &symbols)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2013-05-24 11:02:24 +02:00
|
|
|
QString moduleName = symbols["module"].toUtf8();
|
2013-05-07 11:39:31 +02:00
|
|
|
Symbols syms;
|
|
|
|
|
foreach (const GdbMi &item, symbols["symbols"].children()) {
|
|
|
|
|
Symbol symbol;
|
2013-05-24 11:02:24 +02:00
|
|
|
symbol.address = item["address"].toUtf8();
|
|
|
|
|
symbol.name = item["name"].toUtf8();
|
|
|
|
|
symbol.state = item["state"].toUtf8();
|
|
|
|
|
symbol.section = item["section"].toUtf8();
|
|
|
|
|
symbol.demangled = item["demangled"].toUtf8();
|
2013-05-07 11:39:31 +02:00
|
|
|
syms.append(symbol);
|
|
|
|
|
}
|
|
|
|
|
debuggerCore()->showModuleSymbols(moduleName, syms);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-10 15:54:04 +02:00
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Tooltip specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
static WatchData m_toolTip;
|
|
|
|
|
static QPoint m_toolTipPos;
|
|
|
|
|
static QHash<QString, WatchData> m_toolTipCache;
|
|
|
|
|
|
|
|
|
|
bool LldbEngine::setToolTipExpression(const QPoint &mousePos,
|
|
|
|
|
TextEditor::ITextEditor *editor, const DebuggerToolTipContext &ctx)
|
|
|
|
|
{
|
2013-04-11 17:06:17 +02:00
|
|
|
Q_UNUSED(mousePos);
|
|
|
|
|
Q_UNUSED(editor);
|
2013-03-22 10:28:49 +01:00
|
|
|
|
|
|
|
|
if (state() != InferiorStopOk) {
|
|
|
|
|
//SDEBUG("SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Check mime type and get expression (borrowing some C++ - functions)
|
|
|
|
|
const QString javaPythonMimeType =
|
|
|
|
|
QLatin1String("application/javascript");
|
|
|
|
|
if (!editor->document() || editor->document()->mimeType() != javaPythonMimeType)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
int line;
|
|
|
|
|
int column;
|
|
|
|
|
QString exp = cppExpressionAt(editor, ctx.position, &line, &column);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if (m_toolTipCache.contains(exp)) {
|
|
|
|
|
const WatchData & data = m_toolTipCache[exp];
|
|
|
|
|
q->watchHandler()->removeChildren(data.iname);
|
|
|
|
|
insertData(data);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
QToolTip::hideText();
|
|
|
|
|
if (exp.isEmpty() || exp.startsWith(QLatin1Char('#'))) {
|
|
|
|
|
QToolTip::hideText();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!hasLetterOrNumber(exp)) {
|
2013-05-14 17:36:28 +02:00
|
|
|
QToolTip::showText(m_toolTipPos, tr("'%1' contains no identifier.").arg(exp));
|
2013-03-22 10:28:49 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exp.startsWith(QLatin1Char('"')) && exp.endsWith(QLatin1Char('"'))) {
|
|
|
|
|
QToolTip::showText(m_toolTipPos, tr("String literal %1").arg(exp));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exp.startsWith(QLatin1String("++")) || exp.startsWith(QLatin1String("--")))
|
|
|
|
|
exp.remove(0, 2);
|
|
|
|
|
|
|
|
|
|
if (exp.endsWith(QLatin1String("++")) || exp.endsWith(QLatin1String("--")))
|
|
|
|
|
exp.remove(0, 2);
|
|
|
|
|
|
|
|
|
|
if (exp.startsWith(QLatin1Char('<')) || exp.startsWith(QLatin1Char('[')))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (hasSideEffects(exp)) {
|
|
|
|
|
QToolTip::showText(m_toolTipPos,
|
|
|
|
|
tr("Cowardly refusing to evaluate expression '%1' "
|
2013-05-14 17:36:28 +02:00
|
|
|
"with potential side effects.").arg(exp));
|
2013-03-22 10:28:49 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
//if (status() != InferiorStopOk)
|
|
|
|
|
// return;
|
|
|
|
|
|
|
|
|
|
// FIXME: 'exp' can contain illegal characters
|
|
|
|
|
m_toolTip = WatchData();
|
|
|
|
|
m_toolTip.exp = exp;
|
|
|
|
|
m_toolTip.name = exp;
|
|
|
|
|
m_toolTip.iname = tooltipIName;
|
|
|
|
|
insertData(m_toolTip);
|
|
|
|
|
#endif
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-29 14:54:47 +02:00
|
|
|
void LldbEngine::updateAll()
|
|
|
|
|
{
|
|
|
|
|
updateLocals();
|
|
|
|
|
}
|
2013-03-22 10:28:49 +01:00
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Watch specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2013-05-30 15:35:52 +02:00
|
|
|
void LldbEngine::assignValueInDebugger(const Internal::WatchData *data,
|
|
|
|
|
const QString &expression, const QVariant &value)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2013-05-30 15:35:52 +02:00
|
|
|
Q_UNUSED(data);
|
|
|
|
|
Command cmd("assignValue");
|
|
|
|
|
cmd.arg("exp", expression.toLatin1().toHex());
|
|
|
|
|
cmd.arg("value", value.toString().toLatin1().toHex());
|
|
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(data);
|
|
|
|
|
Q_UNUSED(flags);
|
2013-05-29 14:54:47 +02:00
|
|
|
updateLocals();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::updateLocals()
|
|
|
|
|
{
|
2013-04-30 10:46:48 +02:00
|
|
|
WatchHandler *handler = watchHandler();
|
2013-05-24 12:54:09 +02:00
|
|
|
|
2013-06-05 11:26:46 +02:00
|
|
|
//requestUpdateWatchers();
|
2013-05-30 15:35:52 +02:00
|
|
|
|
2013-05-24 12:54:09 +02:00
|
|
|
Command cmd("updateData");
|
|
|
|
|
cmd.arg("expanded", handler->expansionRequests());
|
|
|
|
|
cmd.arg("typeformats", handler->typeFormatRequests());
|
|
|
|
|
cmd.arg("formats", handler->individualFormatRequests());
|
|
|
|
|
|
|
|
|
|
// const QString fileName = stackHandler()->currentFrame().file;
|
|
|
|
|
// if (!fileName.isEmpty()) {
|
|
|
|
|
// const QString function = stackHandler()->currentFrame().function;
|
|
|
|
|
// typedef DebuggerToolTipManager::ExpressionInamePair ExpressionInamePair;
|
|
|
|
|
// typedef DebuggerToolTipManager::ExpressionInamePairs ExpressionInamePairs;
|
|
|
|
|
|
|
|
|
|
// // Re-create tooltip items that are not filters on existing local variables in
|
|
|
|
|
// // the tooltip model.
|
|
|
|
|
// ExpressionInamePairs toolTips = DebuggerToolTipManager::instance()
|
|
|
|
|
// ->treeWidgetExpressions(fileName, objectName(), function);
|
|
|
|
|
|
|
|
|
|
// const QString currentExpression = tooltipExpression();
|
|
|
|
|
// if (!currentExpression.isEmpty()) {
|
|
|
|
|
// int currentIndex = -1;
|
|
|
|
|
// for (int i = 0; i < toolTips.size(); ++i) {
|
|
|
|
|
// if (toolTips.at(i).first == currentExpression) {
|
|
|
|
|
// currentIndex = i;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// if (currentIndex < 0)
|
|
|
|
|
// toolTips.push_back(ExpressionInamePair(currentExpression, tooltipIName(currentExpression)));
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// foreach (const ExpressionInamePair &p, toolTips) {
|
|
|
|
|
// if (p.second.startsWith("tooltip")) {
|
|
|
|
|
// QHash<QByteArray, QByteArray> hash;
|
|
|
|
|
// hash["exp"] = p.first.toLatin1();
|
|
|
|
|
// hash["id"] = p.second;
|
|
|
|
|
// watcherData.append(Command::toData(hash));
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
|
2013-06-05 11:26:46 +02:00
|
|
|
cmd.arg("passexceptions", alwaysVerbose);
|
2013-05-24 12:54:09 +02:00
|
|
|
cmd.arg("fancy", debuggerCore()->boolSetting(UseDebuggingHelpers));
|
|
|
|
|
cmd.arg("autoderef", debuggerCore()->boolSetting(AutoDerefPointers));
|
|
|
|
|
cmd.arg("dyntype", debuggerCore()->boolSetting(UseDynamicType));
|
|
|
|
|
//cmd.arg("partial", ??)
|
|
|
|
|
//cmd.arg("tooltipOnly", ??)
|
|
|
|
|
//cmd.arg("resultvarname", m_resultVarName);
|
|
|
|
|
|
|
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::handleLldbError(QProcess::ProcessError error)
|
|
|
|
|
{
|
|
|
|
|
qDebug() << "HANDLE LLDB ERROR";
|
|
|
|
|
showMessage(_("HANDLE LLDB ERROR"));
|
|
|
|
|
switch (error) {
|
|
|
|
|
case QProcess::Crashed:
|
|
|
|
|
break; // will get a processExited() as well
|
|
|
|
|
// impossible case QProcess::FailedToStart:
|
|
|
|
|
case QProcess::ReadError:
|
|
|
|
|
case QProcess::WriteError:
|
|
|
|
|
case QProcess::Timedout:
|
|
|
|
|
default:
|
|
|
|
|
//setState(EngineShutdownRequested, true);
|
|
|
|
|
m_lldbProc.kill();
|
2013-10-11 12:45:42 +02:00
|
|
|
showMessageBox(QMessageBox::Critical, tr("LLDB I/O Error"),
|
2013-03-22 10:28:49 +01:00
|
|
|
errorMessage(error));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString LldbEngine::errorMessage(QProcess::ProcessError error) const
|
|
|
|
|
{
|
|
|
|
|
switch (error) {
|
|
|
|
|
case QProcess::FailedToStart:
|
2013-10-11 12:45:42 +02:00
|
|
|
return tr("The LLDB process failed to start. Either the "
|
2013-03-22 10:28:49 +01:00
|
|
|
"invoked program '%1' is missing, or you may have insufficient "
|
|
|
|
|
"permissions to invoke the program.")
|
2013-05-16 15:09:24 +02:00
|
|
|
.arg(m_lldbCmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
case QProcess::Crashed:
|
2013-10-11 12:45:42 +02:00
|
|
|
return tr("The LLDB process crashed some time after starting "
|
2013-03-22 10:28:49 +01:00
|
|
|
"successfully.");
|
|
|
|
|
case QProcess::Timedout:
|
|
|
|
|
return tr("The last waitFor...() function timed out. "
|
|
|
|
|
"The state of QProcess is unchanged, and you can try calling "
|
|
|
|
|
"waitFor...() again.");
|
|
|
|
|
case QProcess::WriteError:
|
|
|
|
|
return tr("An error occurred when attempting to write "
|
2013-10-11 12:45:42 +02:00
|
|
|
"to the LLDB process. For example, the process may not be running, "
|
2013-03-22 10:28:49 +01:00
|
|
|
"or it may have closed its input channel.");
|
|
|
|
|
case QProcess::ReadError:
|
|
|
|
|
return tr("An error occurred when attempting to read from "
|
|
|
|
|
"the Lldb process. For example, the process may not be running.");
|
|
|
|
|
default:
|
|
|
|
|
return tr("An unknown error in the Lldb process occurred. ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::handleLldbFinished(int code, QProcess::ExitStatus type)
|
|
|
|
|
{
|
|
|
|
|
qDebug() << "LLDB FINISHED";
|
|
|
|
|
showMessage(_("LLDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
|
|
|
|
|
notifyEngineSpontaneousShutdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::readLldbStandardError()
|
|
|
|
|
{
|
|
|
|
|
QByteArray err = m_lldbProc.readAllStandardError();
|
|
|
|
|
qDebug() << "\nLLDB STDERR" << err;
|
|
|
|
|
//qWarning() << "Unexpected lldb stderr:" << err;
|
2013-06-14 15:15:09 +02:00
|
|
|
showMessage(_(err), LogError);
|
2013-06-24 13:19:36 +02:00
|
|
|
if (!err.startsWith("warning:"))
|
|
|
|
|
m_lldbProc.kill();
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::readLldbStandardOutput()
|
|
|
|
|
{
|
|
|
|
|
QByteArray out = m_lldbProc.readAllStandardOutput();
|
2013-06-20 09:31:15 +02:00
|
|
|
//showMessage(_("Lldb stdout: " + out));
|
|
|
|
|
showMessage(_(out), LogDebug);
|
2013-04-30 10:46:48 +02:00
|
|
|
m_inbuffer.append(out);
|
2013-03-22 10:28:49 +01:00
|
|
|
while (true) {
|
2013-04-30 10:46:48 +02:00
|
|
|
int pos = m_inbuffer.indexOf("@\n");
|
2013-03-22 10:28:49 +01:00
|
|
|
if (pos == -1)
|
|
|
|
|
break;
|
|
|
|
|
QByteArray response = m_inbuffer.left(pos).trimmed();
|
2013-04-30 10:46:48 +02:00
|
|
|
m_inbuffer = m_inbuffer.mid(pos + 2);
|
2013-03-22 10:28:49 +01:00
|
|
|
emit outputReady(response);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 15:35:52 +02:00
|
|
|
void LldbEngine::requestUpdateWatchers()
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2013-06-13 14:42:59 +02:00
|
|
|
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
|
2013-05-30 15:35:52 +02:00
|
|
|
QList<QByteArray> watcherData;
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
QHash<QByteArray, QByteArray> hash;
|
|
|
|
|
hash["iname"] = "'watch." + QByteArray::number(it.value()) + '\'';
|
|
|
|
|
hash["exp"] = '\'' + it.key().toHex() + '\'';
|
|
|
|
|
watcherData.append(Command::toData(hash));
|
2013-04-08 10:11:02 +02:00
|
|
|
}
|
2013-05-30 15:35:52 +02:00
|
|
|
Command cmd("setWatchers");
|
|
|
|
|
cmd.args.append("'watchers':" + Command::toData(watcherData) + ',');
|
|
|
|
|
runCommand(cmd);
|
2013-04-11 17:06:17 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 10:59:36 +02:00
|
|
|
void LldbEngine::refreshLocals(const GdbMi &vars)
|
|
|
|
|
{
|
|
|
|
|
//const bool partial = response.cookie.toBool();
|
|
|
|
|
WatchHandler *handler = watchHandler();
|
2013-05-02 14:31:35 +02:00
|
|
|
handler->resetValueCache();
|
2013-04-09 10:59:36 +02:00
|
|
|
QList<WatchData> list;
|
|
|
|
|
|
|
|
|
|
//if (!partial) {
|
|
|
|
|
list.append(*handler->findData("local"));
|
|
|
|
|
list.append(*handler->findData("watch"));
|
|
|
|
|
list.append(*handler->findData("return"));
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
foreach (const GdbMi &child, vars.children()) {
|
|
|
|
|
WatchData dummy;
|
2013-05-03 18:26:10 +02:00
|
|
|
dummy.iname = child["iname"].data();
|
|
|
|
|
GdbMi wname = child["wname"];
|
2013-04-09 10:59:36 +02:00
|
|
|
if (wname.isValid()) {
|
2013-05-30 15:35:52 +02:00
|
|
|
// Happens (only) for watched expressions.
|
|
|
|
|
dummy.exp = QByteArray::fromHex(wname.data());
|
|
|
|
|
dummy.name = QString::fromUtf8(dummy.exp);
|
2013-04-09 10:59:36 +02:00
|
|
|
} else {
|
2013-05-24 11:02:24 +02:00
|
|
|
dummy.name = child["name"].toUtf8();
|
2013-04-05 19:20:11 +02:00
|
|
|
}
|
2013-04-09 10:59:36 +02:00
|
|
|
parseWatchData(handler->expandedINames(), dummy, child, &list);
|
|
|
|
|
}
|
|
|
|
|
handler->insertData(list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::refreshStack(const GdbMi &stack)
|
|
|
|
|
{
|
|
|
|
|
//if (!partial)
|
|
|
|
|
// emit stackFrameCompleted();
|
|
|
|
|
StackHandler *handler = stackHandler();
|
|
|
|
|
StackFrames frames;
|
2013-05-03 18:26:10 +02:00
|
|
|
foreach (const GdbMi &item, stack["frames"].children()) {
|
2013-04-09 10:59:36 +02:00
|
|
|
StackFrame frame;
|
2013-05-07 12:09:54 +02:00
|
|
|
frame.level = item["level"].toInt();
|
2013-05-24 11:02:24 +02:00
|
|
|
frame.file = item["file"].toUtf8();
|
|
|
|
|
frame.function = item["func"].toUtf8();
|
|
|
|
|
frame.from = item["func"].toUtf8();
|
2013-05-07 12:09:54 +02:00
|
|
|
frame.line = item["line"].toInt();
|
2013-05-03 18:26:10 +02:00
|
|
|
frame.address = item["addr"].toAddress();
|
2013-04-09 10:59:36 +02:00
|
|
|
frame.usable = QFileInfo(frame.file).isReadable();
|
|
|
|
|
frames.append(frame);
|
|
|
|
|
}
|
2013-05-07 12:09:54 +02:00
|
|
|
bool canExpand = stack["hasmore"].toInt();
|
2013-04-09 10:59:36 +02:00
|
|
|
debuggerCore()->action(ExpandStack)->setEnabled(canExpand);
|
|
|
|
|
handler->setFrames(frames);
|
2013-05-24 10:14:11 +02:00
|
|
|
|
|
|
|
|
int index = stack["current-frame"].toInt();
|
|
|
|
|
handler->setCurrentIndex(index);
|
2013-04-30 10:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::refreshRegisters(const GdbMi ®isters)
|
|
|
|
|
{
|
|
|
|
|
RegisterHandler *handler = registerHandler();
|
|
|
|
|
Registers regs;
|
|
|
|
|
foreach (const GdbMi &item, registers.children()) {
|
|
|
|
|
Register reg;
|
2013-05-03 18:26:10 +02:00
|
|
|
reg.name = item["name"].data();
|
|
|
|
|
reg.value = item["value"].data();
|
2013-05-07 11:39:31 +02:00
|
|
|
//reg.type = item["type"].data();
|
2013-04-30 10:46:48 +02:00
|
|
|
regs.append(reg);
|
|
|
|
|
}
|
|
|
|
|
//handler->setRegisters(registers);
|
|
|
|
|
handler->setAndMarkRegisters(regs);
|
|
|
|
|
}
|
2013-04-09 10:59:36 +02:00
|
|
|
|
|
|
|
|
void LldbEngine::refreshThreads(const GdbMi &threads)
|
|
|
|
|
{
|
|
|
|
|
ThreadsHandler *handler = threadsHandler();
|
|
|
|
|
handler->updateThreads(threads);
|
|
|
|
|
if (!handler->currentThread().isValid()) {
|
|
|
|
|
ThreadId other = handler->threadAt(0);
|
|
|
|
|
if (other.isValid())
|
|
|
|
|
selectThread(other);
|
2013-04-05 19:20:11 +02:00
|
|
|
}
|
2013-04-09 10:59:36 +02:00
|
|
|
updateViews(); // Adjust Threads combobox.
|
2013-04-04 12:23:29 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-10 15:54:04 +02:00
|
|
|
void LldbEngine::refreshTypeInfo(const GdbMi &typeInfo)
|
2013-04-04 12:23:29 +02:00
|
|
|
{
|
2013-04-10 15:54:04 +02:00
|
|
|
if (typeInfo.type() == GdbMi::List) {
|
|
|
|
|
// foreach (const GdbMi &s, typeInfo.children()) {
|
2013-05-07 11:39:31 +02:00
|
|
|
// const GdbMi name = s["name"];
|
|
|
|
|
// const GdbMi size = s["size"];
|
2013-04-10 15:54:04 +02:00
|
|
|
// if (name.isValid() && size.isValid())
|
|
|
|
|
// m_typeInfoCache.insert(QByteArray::fromBase64(name.data()),
|
|
|
|
|
// TypeInfo(size.data().toUInt()));
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
// for (int i = 0; i != list.size(); ++i) {
|
|
|
|
|
// const TypeInfo ti = m_typeInfoCache.value(list.at(i).type);
|
|
|
|
|
// if (ti.size)
|
|
|
|
|
// list[i].size = ti.size;
|
|
|
|
|
// }
|
|
|
|
|
}
|
2013-04-04 12:23:29 +02:00
|
|
|
|
2013-04-10 15:54:04 +02:00
|
|
|
void LldbEngine::refreshState(const GdbMi &reportedState)
|
|
|
|
|
{
|
2013-05-02 14:31:35 +02:00
|
|
|
QByteArray newState = reportedState.data();
|
|
|
|
|
if (newState == "running")
|
|
|
|
|
notifyInferiorRunOk();
|
|
|
|
|
else if (newState == "inferiorrunfailed")
|
|
|
|
|
notifyInferiorRunFailed();
|
|
|
|
|
else if (newState == "stopped")
|
|
|
|
|
notifyInferiorSpontaneousStop();
|
|
|
|
|
else if (newState == "inferiorstopok")
|
|
|
|
|
notifyInferiorStopOk();
|
|
|
|
|
else if (newState == "inferiorstopfailed")
|
|
|
|
|
notifyInferiorStopFailed();
|
|
|
|
|
else if (newState == "enginesetupok")
|
|
|
|
|
notifyEngineSetupOk();
|
|
|
|
|
else if (newState == "enginesetupfailed")
|
|
|
|
|
notifyEngineSetupFailed();
|
|
|
|
|
else if (newState == "stopped")
|
|
|
|
|
notifyInferiorSpontaneousStop();
|
|
|
|
|
else if (newState == "inferiorsetupok")
|
|
|
|
|
notifyInferiorSetupOk();
|
2013-05-22 14:30:36 +02:00
|
|
|
else if (newState == "enginerunandinferiorrunok")
|
2013-05-02 14:31:35 +02:00
|
|
|
notifyEngineRunAndInferiorRunOk();
|
2013-05-22 14:30:36 +02:00
|
|
|
else if (newState == "enginerunandinferiorstopok")
|
|
|
|
|
notifyEngineRunAndInferiorStopOk();
|
2013-05-29 15:38:49 +02:00
|
|
|
else if (newState == "inferiorshutdownok")
|
|
|
|
|
notifyInferiorShutdownOk();
|
|
|
|
|
else if (newState == "inferiorshutdownfailed")
|
|
|
|
|
notifyInferiorShutdownFailed();
|
|
|
|
|
else if (newState == "engineshutdownok")
|
|
|
|
|
notifyEngineShutdownOk();
|
|
|
|
|
else if (newState == "engineshutdownfailed")
|
|
|
|
|
notifyEngineShutdownFailed();
|
2013-05-22 14:30:36 +02:00
|
|
|
else if (newState == "inferiorexited")
|
|
|
|
|
notifyInferiorExited();
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-10 17:49:35 +02:00
|
|
|
void LldbEngine::refreshLocation(const GdbMi &reportedLocation)
|
|
|
|
|
{
|
2013-06-11 18:07:59 +02:00
|
|
|
if (debuggerCore()->boolSetting(OperateByInstruction)) {
|
|
|
|
|
Location loc(reportedLocation["addr"].toAddress());
|
|
|
|
|
loc.setNeedsMarker(true);
|
|
|
|
|
gotoLocation(loc);
|
|
|
|
|
} else {
|
|
|
|
|
QString file = reportedLocation["file"].toUtf8();
|
|
|
|
|
int line = reportedLocation["line"].toInt();
|
|
|
|
|
gotoLocation(Location(file, line));
|
|
|
|
|
}
|
2013-04-10 17:49:35 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
void LldbEngine::reloadRegisters()
|
|
|
|
|
{
|
2013-05-07 12:34:10 +02:00
|
|
|
runCommand("reportRegisters");
|
2013-04-30 10:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-03 17:18:07 +02:00
|
|
|
void LldbEngine::fetchDisassembler(DisassemblerAgent *agent)
|
|
|
|
|
{
|
2013-05-07 08:46:51 +02:00
|
|
|
QPointer<DisassemblerAgent> p(agent);
|
|
|
|
|
int id = m_disassemblerAgents.value(p, -1);
|
|
|
|
|
if (id == -1) {
|
|
|
|
|
id = ++m_lastAgentId;
|
|
|
|
|
m_disassemblerAgents.insert(p, id);
|
|
|
|
|
}
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(Command("disassemble").arg("cookie", id));
|
2013-05-07 08:46:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LldbEngine::fetchMemory(MemoryAgent *agent, QObject *editorToken,
|
|
|
|
|
quint64 addr, quint64 length)
|
|
|
|
|
{
|
|
|
|
|
int id = m_memoryAgents.value(agent, -1);
|
|
|
|
|
if (id == -1) {
|
|
|
|
|
id = ++m_lastAgentId;
|
|
|
|
|
m_memoryAgents.insert(agent, id);
|
|
|
|
|
m_memoryAgentTokens.insert(id, editorToken);
|
|
|
|
|
}
|
2013-09-11 21:35:39 +02:00
|
|
|
runCommand(Command("fetchMemory")
|
2013-05-07 10:45:53 +02:00
|
|
|
.arg("address", addr)
|
|
|
|
|
.arg("length", length)
|
|
|
|
|
.arg("cookie", id));
|
2013-05-07 08:46:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken,
|
|
|
|
|
quint64 addr, const QByteArray &data)
|
|
|
|
|
{
|
|
|
|
|
int id = m_memoryAgents.value(agent, -1);
|
|
|
|
|
if (id == -1) {
|
|
|
|
|
id = ++m_lastAgentId;
|
|
|
|
|
m_memoryAgents.insert(agent, id);
|
|
|
|
|
m_memoryAgentTokens.insert(id, editorToken);
|
|
|
|
|
}
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(Command("writeMemory")
|
|
|
|
|
.arg("address", addr)
|
|
|
|
|
.arg("data", data.toHex())
|
|
|
|
|
.arg("cookie", id));
|
2013-05-03 17:18:07 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-07 08:46:51 +02:00
|
|
|
void LldbEngine::setRegisterValue(int regnr, const QString &value)
|
|
|
|
|
{
|
|
|
|
|
Register reg = registerHandler()->registers().at(regnr);
|
2013-05-07 10:45:53 +02:00
|
|
|
runCommand(Command("setRegister").arg("name", reg.name).arg("value", value));
|
2013-05-07 08:46:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
bool LldbEngine::hasCapability(unsigned cap) const
|
|
|
|
|
{
|
2013-04-12 16:58:25 +02:00
|
|
|
if (cap & (ReverseSteppingCapability
|
|
|
|
|
| AutoDerefPointersCapability
|
|
|
|
|
| DisassemblerCapability
|
|
|
|
|
| RegisterCapability
|
|
|
|
|
| ShowMemoryCapability
|
|
|
|
|
| JumpToLineCapability
|
|
|
|
|
| ReloadModuleCapability
|
|
|
|
|
| ReloadModuleSymbolsCapability
|
|
|
|
|
| BreakOnThrowAndCatchCapability
|
|
|
|
|
| BreakConditionCapability
|
|
|
|
|
| TracePointCapability
|
|
|
|
|
| ReturnFromFunctionCapability
|
|
|
|
|
| CreateFullBacktraceCapability
|
|
|
|
|
| WatchpointByAddressCapability
|
|
|
|
|
| WatchpointByExpressionCapability
|
|
|
|
|
| AddWatcherCapability
|
|
|
|
|
| WatchWidgetsCapability
|
|
|
|
|
| ShowModuleSymbolsCapability
|
|
|
|
|
| ShowModuleSectionsCapability
|
|
|
|
|
| CatchCapability
|
|
|
|
|
| OperateByInstructionCapability
|
|
|
|
|
| RunToLineCapability
|
|
|
|
|
| WatchComplexExpressionsCapability
|
|
|
|
|
| MemoryAddressCapability))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (startParameters().startMode == AttachCore)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//return cap == SnapshotCapability;
|
|
|
|
|
return false;
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &startParameters)
|
|
|
|
|
{
|
|
|
|
|
return new LldbEngine(startParameters);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-07 10:45:53 +02:00
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Command
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2013-05-24 10:40:45 +02:00
|
|
|
const LldbEngine::Command &LldbEngine::Command::argHelper(const char *name, const QByteArray &data) const
|
2013-05-07 10:45:53 +02:00
|
|
|
{
|
|
|
|
|
args.append('\'');
|
|
|
|
|
args.append(name);
|
|
|
|
|
args.append("':");
|
2013-05-24 10:40:45 +02:00
|
|
|
args.append(data);
|
|
|
|
|
args.append(",");
|
2013-05-07 10:45:53 +02:00
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-24 12:54:09 +02:00
|
|
|
QByteArray LldbEngine::Command::toData(const QList<QByteArray> &value)
|
|
|
|
|
{
|
|
|
|
|
QByteArray res;
|
|
|
|
|
foreach (const QByteArray &item, value) {
|
|
|
|
|
if (!res.isEmpty())
|
|
|
|
|
res.append(',');
|
|
|
|
|
res += item;
|
|
|
|
|
}
|
|
|
|
|
return '[' + res + ']';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray LldbEngine::Command::toData(const QHash<QByteArray, QByteArray> &value)
|
|
|
|
|
{
|
|
|
|
|
QByteArray res;
|
|
|
|
|
QHashIterator<QByteArray, QByteArray> it(value);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
if (!res.isEmpty())
|
|
|
|
|
res.append(',');
|
|
|
|
|
res += '\'' + it.key() + "':" + it.value();
|
|
|
|
|
}
|
|
|
|
|
return '{' + res + '}';
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-24 10:40:45 +02:00
|
|
|
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, int value) const
|
|
|
|
|
{
|
|
|
|
|
return argHelper(name, QByteArray::number(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, qlonglong value) const
|
|
|
|
|
{
|
|
|
|
|
return argHelper(name, QByteArray::number(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, qulonglong value) const
|
|
|
|
|
{
|
|
|
|
|
return argHelper(name, QByteArray::number(value));
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-07 10:45:53 +02:00
|
|
|
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const QString &value) const
|
|
|
|
|
{
|
|
|
|
|
return arg(name, value.toUtf8().data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const QByteArray &value) const
|
|
|
|
|
{
|
|
|
|
|
return arg(name, value.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const char *value) const
|
|
|
|
|
{
|
|
|
|
|
args.append('\'');
|
|
|
|
|
args.append(name);
|
|
|
|
|
args.append("':'");
|
|
|
|
|
args.append(value);
|
|
|
|
|
args.append("',");
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LldbEngine::Command &LldbEngine::Command::beginList(const char *name) const
|
|
|
|
|
{
|
|
|
|
|
if (name) {
|
|
|
|
|
args += '\'';
|
|
|
|
|
args += name;
|
|
|
|
|
args += "':";
|
|
|
|
|
}
|
|
|
|
|
args += '[';
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::Command::endList() const
|
|
|
|
|
{
|
|
|
|
|
if (args.endsWith(','))
|
|
|
|
|
args.chop(1);
|
|
|
|
|
args += "],";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LldbEngine::Command &LldbEngine::Command::beginGroup(const char *name) const
|
|
|
|
|
{
|
|
|
|
|
if (name) {
|
|
|
|
|
args += '\'';
|
|
|
|
|
args += name;
|
|
|
|
|
args += "':";
|
|
|
|
|
}
|
|
|
|
|
args += '{';
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::Command::endGroup() const
|
|
|
|
|
{
|
|
|
|
|
if (args.endsWith(','))
|
|
|
|
|
args.chop(1);
|
|
|
|
|
args += "},";
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|