2013-03-22 10:28:49 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2013-03-22 10:28:49 +01:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2013-03-22 10:28:49 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2013-03-22 10:28:49 +01:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "lldbengine.h"
|
|
|
|
|
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <debugger/debuggeractions.h>
|
|
|
|
|
#include <debugger/debuggercore.h>
|
|
|
|
|
#include <debugger/debuggerdialogs.h>
|
2013-10-10 15:15:49 +02:00
|
|
|
#include <debugger/debuggerinternalconstants.h>
|
2013-11-08 16:11:01 +01:00
|
|
|
#include <debugger/debuggermainwindow.h>
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <debugger/debuggerprotocol.h>
|
|
|
|
|
#include <debugger/debuggerstartparameters.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
|
|
|
|
2014-11-25 13:08:18 +01:00
|
|
|
#include <coreplugin/messagebox.h>
|
2013-03-22 10:28:49 +01:00
|
|
|
#include <coreplugin/idocument.h>
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
|
2015-01-23 15:53:09 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <utils/savedaction.h>
|
|
|
|
|
#include <utils/qtcprocess.h>
|
|
|
|
|
|
|
|
|
|
#include <QApplication>
|
2013-03-22 10:28:49 +01:00
|
|
|
#include <QDateTime>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QToolTip>
|
2015-01-23 15:53:09 +01:00
|
|
|
#include <QVariant>
|
2015-09-14 13:40:35 +02:00
|
|
|
#include <QJsonArray>
|
2016-12-06 16:06:08 +01:00
|
|
|
#include <QRegularExpression>
|
2013-03-22 10:28:49 +01:00
|
|
|
|
2015-01-23 15:53:09 +01:00
|
|
|
using namespace Core;
|
2014-03-03 16:59:56 +01:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2015-03-05 10:41:16 +01:00
|
|
|
static int ¤tToken()
|
|
|
|
|
{
|
|
|
|
|
static int token = 0;
|
|
|
|
|
return token;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LldbEngine
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
LldbEngine::LldbEngine(const DebuggerRunParameters &startParameters)
|
2013-11-19 10:45:00 +01:00
|
|
|
: DebuggerEngine(startParameters), m_continueAtNextSpontaneousStop(false)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2013-05-07 08:46:51 +02:00
|
|
|
m_lastAgentId = 0;
|
2013-03-22 10:28:49 +01:00
|
|
|
setObjectName(QLatin1String("LldbEngine"));
|
2013-05-29 14:54:47 +02:00
|
|
|
|
2015-01-23 15:53:09 +01:00
|
|
|
connect(action(AutoDerefPointers), &SavedAction::valueChanged,
|
|
|
|
|
this, &LldbEngine::updateLocals);
|
|
|
|
|
connect(action(CreateFullBacktrace), &QAction::triggered,
|
2015-09-09 16:34:09 +02:00
|
|
|
this, &LldbEngine::fetchFullBacktrace);
|
2015-01-23 15:53:09 +01:00
|
|
|
connect(action(UseDebuggingHelpers), &SavedAction::valueChanged,
|
|
|
|
|
this, &LldbEngine::updateLocals);
|
|
|
|
|
connect(action(UseDynamicType), &SavedAction::valueChanged,
|
|
|
|
|
this, &LldbEngine::updateLocals);
|
|
|
|
|
connect(action(IntelFlavor), &SavedAction::valueChanged,
|
|
|
|
|
this, &LldbEngine::updateAll);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LldbEngine::~LldbEngine()
|
2014-03-03 16:59:56 +01:00
|
|
|
{
|
|
|
|
|
m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub
|
2015-03-03 18:05:00 +01:00
|
|
|
m_lldbProc.disconnect();
|
2014-03-03 16:59:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2015-02-05 14:39:59 +01:00
|
|
|
DebuggerCommand cmd("executeDebuggerCommand");
|
|
|
|
|
cmd.arg("command", command);
|
|
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-13 09:46:51 +01:00
|
|
|
void LldbEngine::runCommand(const DebuggerCommand &command)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2016-06-07 15:51:38 +02:00
|
|
|
if (m_lldbProc.state() != QProcess::Running) {
|
|
|
|
|
// This can legally happen e.g. through a reloadModule()
|
|
|
|
|
// triggered by changes in view visibility.
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("NO LLDB PROCESS RUNNING, CMD IGNORED: %1 %2")
|
2016-12-13 09:46:51 +01:00
|
|
|
.arg(command.function).arg(state()));
|
2016-06-07 15:51:38 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2015-03-05 10:41:16 +01:00
|
|
|
const int tok = ++currentToken();
|
2016-12-13 09:46:51 +01:00
|
|
|
DebuggerCommand cmd = command;
|
|
|
|
|
cmd.arg("token", tok);
|
2016-06-09 11:42:37 +02:00
|
|
|
QString token = QString::number(tok);
|
2016-12-13 09:46:51 +01:00
|
|
|
QString function = cmd.function + "(" + cmd.argsToPython() + ")";
|
2016-12-06 16:06:08 +01:00
|
|
|
QString msg = token + function + '\n';
|
2016-12-13 09:46:51 +01:00
|
|
|
if (cmd.flags == Silent)
|
2016-12-06 16:06:08 +01:00
|
|
|
msg.replace(QRegularExpression("\"environment\":.[^]]*."), "<environment suppressed>");
|
2016-12-13 09:46:51 +01:00
|
|
|
if (cmd.flags == NeedsFullStop) {
|
|
|
|
|
cmd.flags &= ~NeedsFullStop;
|
|
|
|
|
if (state() == InferiorRunOk) {
|
|
|
|
|
showStatusMessage(tr("Stopping temporarily"), 1000);
|
|
|
|
|
m_onStop.append(cmd, false);
|
|
|
|
|
requestInterruptInferior();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-06 16:06:08 +01:00
|
|
|
showMessage(msg, LogInput);
|
2016-12-13 09:46:51 +01:00
|
|
|
m_commandForToken[currentToken()] = cmd;
|
2016-06-07 17:04:53 +02:00
|
|
|
m_lldbProc.write("script theDumper." + function.toUtf8() + "\n");
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-09 15:37:04 +01:00
|
|
|
void LldbEngine::debugLastCommand()
|
|
|
|
|
{
|
|
|
|
|
runCommand(m_lastDebuggableCommand);
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
void LldbEngine::shutdownInferior()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"shutdownInferior"});
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::shutdownEngine()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
|
|
|
|
|
m_lldbProc.kill();
|
2015-05-27 13:59:56 +02:00
|
|
|
if (runParameters().useTerminal)
|
2014-03-03 16:59:56 +01:00
|
|
|
m_stubProc.stop();
|
2014-03-25 16:56:37 +01:00
|
|
|
notifyEngineShutdownOk();
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-06 14:23:08 +01:00
|
|
|
void LldbEngine::abortDebugger()
|
|
|
|
|
{
|
|
|
|
|
if (targetState() == DebuggerFinished) {
|
|
|
|
|
// We already tried. Try harder.
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ABORTING DEBUGGER. SECOND TIME.");
|
2013-11-06 14:23:08 +01:00
|
|
|
m_lldbProc.kill();
|
|
|
|
|
} else {
|
|
|
|
|
// Be friendly the first time. This will change targetState().
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ABORTING DEBUGGER. FIRST TIME.");
|
2013-11-06 14:23:08 +01:00
|
|
|
quitDebugger();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-03 16:59:56 +01:00
|
|
|
// FIXME: Merge with GdbEngine/QtcProcess
|
|
|
|
|
bool LldbEngine::prepareCommand()
|
|
|
|
|
{
|
|
|
|
|
if (HostOsInfo::isWindowsHost()) {
|
2015-05-27 13:59:56 +02:00
|
|
|
DebuggerRunParameters &rp = runParameters();
|
2014-03-03 16:59:56 +01:00
|
|
|
QtcProcess::SplitError perr;
|
2016-01-28 10:31:24 +01:00
|
|
|
rp.inferior.commandLineArguments
|
|
|
|
|
= QtcProcess::prepareArgs(rp.inferior.commandLineArguments, &perr, HostOsInfo::hostOs(),
|
|
|
|
|
nullptr, &rp.inferior.workingDirectory).toWindowsArgs();
|
2015-01-23 15:53:09 +01:00
|
|
|
if (perr != QtcProcess::SplitOk) {
|
2014-03-03 16:59:56 +01:00
|
|
|
// perr == BadQuoting is never returned on Windows
|
|
|
|
|
// FIXME? QTCREATORBUG-2809
|
|
|
|
|
notifyEngineSetupFailed();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
void LldbEngine::setupEngine()
|
|
|
|
|
{
|
2016-05-30 15:33:29 +02:00
|
|
|
// FIXME: We can't handle terminals yet.
|
2015-05-27 13:59:56 +02:00
|
|
|
if (runParameters().useTerminal) {
|
2016-05-30 15:33:29 +02:00
|
|
|
qWarning("Run in Terminal is not supported yet with the LLDB backend");
|
2016-06-21 14:58:55 +02:00
|
|
|
showMessage(tr("Run in Terminal is not supported with the LLDB backend."), AppError);
|
2016-05-30 15:33:29 +02:00
|
|
|
runParameters().useTerminal = false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
if (runParameters().useTerminal) {
|
2016-05-30 15:33:29 +02:00
|
|
|
QTC_CHECK(false); // See above.
|
2016-09-10 22:58:25 +03:00
|
|
|
if (HostOsInfo::isWindowsHost()) {
|
2016-05-30 13:50:20 +02:00
|
|
|
// Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
|
|
|
|
|
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
|
|
|
|
|
m_stubProc.setMode(ConsoleProcess::Suspend);
|
|
|
|
|
else
|
|
|
|
|
m_stubProc.setMode(ConsoleProcess::Debug);
|
2016-09-10 22:58:25 +03:00
|
|
|
} else {
|
2016-05-30 13:50:20 +02:00
|
|
|
m_stubProc.setMode(ConsoleProcess::Debug);
|
|
|
|
|
m_stubProc.setSettings(ICore::settings());
|
2016-09-10 22:58:25 +03:00
|
|
|
}
|
2016-05-30 13:50:20 +02:00
|
|
|
|
2014-03-03 16:59:56 +01:00
|
|
|
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("TRYING TO START ADAPTER");
|
2014-03-03 16:59:56 +01:00
|
|
|
|
|
|
|
|
// Currently, adapters are not re-used
|
|
|
|
|
// // We leave the console open, so recycle it now.
|
|
|
|
|
// m_stubProc.blockSignals(true);
|
|
|
|
|
// m_stubProc.stop();
|
|
|
|
|
// m_stubProc.blockSignals(false);
|
|
|
|
|
|
|
|
|
|
if (!prepareCommand()) {
|
|
|
|
|
notifyEngineSetupFailed();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-28 10:31:24 +01:00
|
|
|
m_stubProc.setWorkingDirectory(runParameters().inferior.workingDirectory);
|
2014-03-03 16:59:56 +01:00
|
|
|
// Set environment + dumper preload.
|
2015-12-08 12:39:10 +01:00
|
|
|
m_stubProc.setEnvironment(runParameters().stubEnvironment);
|
2014-03-03 16:59:56 +01:00
|
|
|
|
2015-01-23 15:53:09 +01:00
|
|
|
connect(&m_stubProc, &ConsoleProcess::processError, this, &LldbEngine::stubError);
|
|
|
|
|
connect(&m_stubProc, &ConsoleProcess::processStarted, this, &LldbEngine::stubStarted);
|
|
|
|
|
connect(&m_stubProc, &ConsoleProcess::stubStopped, this, &LldbEngine::stubExited);
|
2014-03-03 16:59:56 +01:00
|
|
|
// FIXME: Starting the stub implies starting the inferior. This is
|
|
|
|
|
// fairly unclean as far as the state machine and error reporting go.
|
|
|
|
|
|
2016-01-28 10:31:24 +01:00
|
|
|
if (!m_stubProc.start(runParameters().inferior.executable,
|
|
|
|
|
runParameters().inferior.commandLineArguments)) {
|
2014-03-03 16:59:56 +01:00
|
|
|
// Error message for user is delivered via a signal.
|
|
|
|
|
//handleAdapterStartFailed(QString());
|
|
|
|
|
notifyEngineSetupFailed();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
|
2015-05-27 13:59:56 +02:00
|
|
|
if (runParameters().remoteSetupNeeded)
|
2014-03-03 16:59:56 +01:00
|
|
|
notifyEngineRequestRemoteSetup();
|
|
|
|
|
else
|
|
|
|
|
startLldb();
|
|
|
|
|
}
|
2013-10-10 15:15:49 +02:00
|
|
|
}
|
2013-03-22 10:28:49 +01:00
|
|
|
|
2013-10-10 15:15:49 +02:00
|
|
|
void LldbEngine::startLldb()
|
|
|
|
|
{
|
2016-07-29 15:55:15 +02:00
|
|
|
QString lldbCmd = runParameters().debugger.executable;
|
2016-08-03 19:43:54 +03:00
|
|
|
connect(&m_lldbProc, &QProcess::errorOccurred, this, &LldbEngine::handleLldbError);
|
2015-01-23 15:53:09 +01:00
|
|
|
connect(&m_lldbProc, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
|
|
|
|
this, &LldbEngine::handleLldbFinished);
|
|
|
|
|
connect(&m_lldbProc, &QProcess::readyReadStandardOutput,
|
|
|
|
|
this, &LldbEngine::readLldbStandardOutput);
|
|
|
|
|
connect(&m_lldbProc, &QProcess::readyReadStandardError,
|
|
|
|
|
this, &LldbEngine::readLldbStandardError);
|
|
|
|
|
|
|
|
|
|
connect(this, &LldbEngine::outputReady,
|
|
|
|
|
this, &LldbEngine::handleResponse, Qt::QueuedConnection);
|
2013-03-22 10:28:49 +01:00
|
|
|
|
2016-07-29 15:55:15 +02:00
|
|
|
showMessage("STARTING LLDB: " + lldbCmd);
|
|
|
|
|
m_lldbProc.setEnvironment(runParameters().debugger.environment);
|
|
|
|
|
if (QFileInfo(runParameters().debugger.workingDirectory).isDir())
|
|
|
|
|
m_lldbProc.setWorkingDirectory(runParameters().debugger.workingDirectory);
|
2013-10-20 21:45:47 +02:00
|
|
|
|
2016-07-29 15:55:15 +02:00
|
|
|
m_lldbProc.setCommand(lldbCmd, QString());
|
2015-06-05 12:31:39 +02:00
|
|
|
m_lldbProc.start();
|
2013-03-22 10:28:49 +01:00
|
|
|
|
|
|
|
|
if (!m_lldbProc.waitForStarted()) {
|
2013-10-24 12:16:26 +02:00
|
|
|
const QString msg = tr("Unable to start LLDB \"%1\": %2")
|
2016-07-29 15:55:15 +02:00
|
|
|
.arg(lldbCmd, m_lldbProc.errorString());
|
2013-03-22 10:28:49 +01:00
|
|
|
notifyEngineSetupFailed();
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ADAPTER START FAILED");
|
2013-04-30 10:46:48 +02:00
|
|
|
if (!msg.isEmpty())
|
2015-01-23 15:53:09 +01:00
|
|
|
ICore::showWarningWithOptions(tr("Adapter start failed."), msg);
|
2015-03-09 13:30:22 +01:00
|
|
|
return;
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
2015-03-09 13:30:22 +01:00
|
|
|
m_lldbProc.waitForReadyRead(1000);
|
|
|
|
|
m_lldbProc.write("sc print('@\\nlldbstartupok@\\n')\n");
|
|
|
|
|
}
|
2015-01-30 12:36:04 +01:00
|
|
|
|
2015-03-09 13:30:22 +01:00
|
|
|
// FIXME: splitting of startLldb() necessary to support LLDB <= 310 - revert asap
|
|
|
|
|
void LldbEngine::startLldbStage2()
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ADAPTER STARTED");
|
2015-01-30 12:36:04 +01:00
|
|
|
showStatusMessage(tr("Setting up inferior..."));
|
|
|
|
|
|
|
|
|
|
const QByteArray dumperSourcePath =
|
|
|
|
|
ICore::resourcePath().toLocal8Bit() + "/debugger/";
|
|
|
|
|
|
2015-02-13 10:02:35 +01:00
|
|
|
m_lldbProc.write("script sys.path.insert(1, '" + dumperSourcePath + "')\n");
|
|
|
|
|
m_lldbProc.write("script from lldbbridge import *\n");
|
|
|
|
|
m_lldbProc.write("script print(dir())\n");
|
|
|
|
|
m_lldbProc.write("script theDumper = Dumper()\n"); // This triggers reportState("enginesetupok")
|
2016-04-13 18:55:35 +02:00
|
|
|
|
2017-01-20 09:38:59 +01:00
|
|
|
const QString commands = nativeStartupCommands();
|
2016-04-13 18:55:35 +02:00
|
|
|
if (!commands.isEmpty())
|
2016-09-26 16:42:37 +02:00
|
|
|
m_lldbProc.write(commands.toLocal8Bit() + '\n');
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::setupInferior()
|
|
|
|
|
{
|
2014-07-28 14:23:52 +02:00
|
|
|
const QString path = stringSetting(ExtraDumperFile);
|
2015-06-22 08:00:47 +03:00
|
|
|
if (!path.isEmpty() && QFileInfo(path).isReadable()) {
|
2015-02-11 12:20:21 +01:00
|
|
|
DebuggerCommand cmd("addDumperModule");
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.arg("path", path);
|
2015-01-28 17:17:31 +01:00
|
|
|
runCommand(cmd);
|
2014-06-23 16:33:19 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-28 14:23:52 +02:00
|
|
|
const QString commands = stringSetting(ExtraDumperCommands);
|
2014-06-23 16:33:19 +02:00
|
|
|
if (!commands.isEmpty()) {
|
2015-02-02 12:47:51 +01:00
|
|
|
DebuggerCommand cmd("executeDebuggerCommand");
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.arg("command", commands);
|
2014-06-23 16:33:19 +02:00
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 16:48:57 +01:00
|
|
|
DebuggerCommand cmd1("loadDumpers");
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd1.callback = [this](const DebuggerResponse &response) {
|
2016-04-14 16:18:25 +02:00
|
|
|
watchHandler()->addDumpers(response.data["dumpers"]);
|
2015-09-09 16:34:09 +02:00
|
|
|
};
|
2015-01-23 19:09:08 +01:00
|
|
|
runCommand(cmd1);
|
2015-03-09 13:30:22 +01:00
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
2015-01-23 19:09:08 +01:00
|
|
|
|
2014-02-04 13:32:17 +01:00
|
|
|
QString executable;
|
2015-01-23 15:53:09 +01:00
|
|
|
QtcProcess::Arguments args;
|
2016-01-28 10:31:24 +01:00
|
|
|
QtcProcess::prepareCommand(QFileInfo(rp.inferior.executable).absoluteFilePath(),
|
|
|
|
|
rp.inferior.commandLineArguments, &executable, &args);
|
2014-02-04 13:32:17 +01:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd2("setupInferior");
|
|
|
|
|
cmd2.arg("executable", executable);
|
2015-10-27 15:50:41 +01:00
|
|
|
cmd2.arg("breakonmain", rp.breakOnMain);
|
|
|
|
|
cmd2.arg("useterminal", rp.useTerminal);
|
|
|
|
|
cmd2.arg("startmode", rp.startMode);
|
2015-10-09 15:00:20 +02:00
|
|
|
cmd2.arg("nativemixed", isNativeMixedActive());
|
2016-09-26 13:47:19 +02:00
|
|
|
cmd2.arg("workingdirectory", rp.inferior.workingDirectory);
|
2016-12-07 13:31:10 +01:00
|
|
|
cmd2.arg("environment", rp.inferior.environment.toStringList());
|
|
|
|
|
cmd2.arg("processargs", args.toUnixArgs());
|
2013-11-19 10:45:00 +01:00
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
if (rp.useTerminal) {
|
2014-03-03 16:59:56 +01:00
|
|
|
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
|
|
|
|
|
const qint64 attachedPID = m_stubProc.applicationPID();
|
|
|
|
|
const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID();
|
|
|
|
|
const QString msg = (attachedMainThreadID != -1)
|
|
|
|
|
? QString::fromLatin1("Attaching to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
|
|
|
|
|
: QString::fromLatin1("Attaching to %1").arg(attachedPID);
|
|
|
|
|
showMessage(msg, LogMisc);
|
2015-10-27 15:50:41 +01:00
|
|
|
cmd2.arg("attachpid", attachedPID);
|
2014-03-03 16:59:56 +01:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2015-10-27 15:50:41 +01:00
|
|
|
cmd2.arg("startmode", rp.startMode);
|
2014-03-03 16:59:56 +01:00
|
|
|
// it is better not to check the start mode on the python sid (as we would have to duplicate the
|
2015-05-27 13:59:56 +02:00
|
|
|
// enum values), and thus we assume that if the rp.attachPID is valid we really have to attach
|
|
|
|
|
QTC_CHECK(rp.attachPID <= 0 || (rp.startMode == AttachCrashedExternal
|
|
|
|
|
|| rp.startMode == AttachExternal));
|
2015-10-27 15:50:41 +01:00
|
|
|
cmd2.arg("attachpid", rp.attachPID);
|
|
|
|
|
cmd2.arg("sysroot", rp.deviceSymbolsRoot.isEmpty() ? rp.sysRoot : rp.deviceSymbolsRoot);
|
|
|
|
|
cmd2.arg("remotechannel", ((rp.startMode == AttachToRemoteProcess
|
2015-05-27 13:59:56 +02:00
|
|
|
|| rp.startMode == AttachToRemoteServer)
|
|
|
|
|
? rp.remoteChannel : QString()));
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd2.arg("platform", rp.platform);
|
2015-05-27 13:59:56 +02:00
|
|
|
QTC_CHECK(!rp.continueAfterAttach || (rp.startMode == AttachToRemoteProcess
|
|
|
|
|
|| rp.startMode == AttachExternal
|
|
|
|
|
|| rp.startMode == AttachToRemoteServer));
|
2014-03-03 16:59:56 +01:00
|
|
|
m_continueAtNextSpontaneousStop = false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd2.callback = [this](const DebuggerResponse &response) {
|
|
|
|
|
bool success = response.data["success"].toInt();
|
|
|
|
|
if (success) {
|
|
|
|
|
foreach (Breakpoint bp, breakHandler()->unclaimedBreakpoints()) {
|
|
|
|
|
if (acceptsBreakpoint(bp)) {
|
|
|
|
|
bp.setEngine(this);
|
|
|
|
|
insertBreakpoint(bp);
|
|
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
|
2015-09-09 16:34:09 +02:00
|
|
|
.arg(bp.id().toString()).arg(bp.state()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
notifyInferiorSetupOk();
|
|
|
|
|
} else {
|
|
|
|
|
notifyInferiorSetupFailed();
|
|
|
|
|
}
|
|
|
|
|
};
|
2016-12-06 16:06:08 +01:00
|
|
|
|
2016-12-13 13:37:05 +01:00
|
|
|
cmd2.flags = Silent;
|
2015-09-09 16:34:09 +02:00
|
|
|
runCommand(cmd2);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::runEngine()
|
|
|
|
|
{
|
2015-05-27 13:59:56 +02:00
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
2015-01-30 12:36:04 +01:00
|
|
|
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state(); return);
|
2013-03-22 10:28:49 +01:00
|
|
|
showStatusMessage(tr("Running requested..."), 5000);
|
2015-02-27 11:56:03 +01:00
|
|
|
DebuggerCommand cmd("runEngine");
|
2015-09-09 16:34:09 +02:00
|
|
|
if (rp.startMode == AttachCore)
|
2015-05-27 13:59:56 +02:00
|
|
|
cmd.arg("coreFile", rp.coreFile);
|
2015-02-27 11:56:03 +01:00
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::interruptInferior()
|
|
|
|
|
{
|
|
|
|
|
showStatusMessage(tr("Interrupt requested..."), 5000);
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"interruptInferior"});
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 10:59:36 +02:00
|
|
|
void LldbEngine::executeStep()
|
|
|
|
|
{
|
|
|
|
|
notifyInferiorRunRequested();
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"executeStep"});
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
void LldbEngine::executeStepI()
|
|
|
|
|
{
|
|
|
|
|
notifyInferiorRunRequested();
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"executeStepI"});
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeStepOut()
|
|
|
|
|
{
|
|
|
|
|
notifyInferiorRunRequested();
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"executeStepOut"});
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeNext()
|
|
|
|
|
{
|
|
|
|
|
notifyInferiorRunRequested();
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"executeNext"});
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeNextI()
|
|
|
|
|
{
|
|
|
|
|
notifyInferiorRunRequested();
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"executeNextI"});
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::continueInferior()
|
|
|
|
|
{
|
|
|
|
|
notifyInferiorRunRequested();
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd("continueInferior");
|
|
|
|
|
cmd.callback = [this](const DebuggerResponse &response) {
|
|
|
|
|
if (response.resultClass == ResultError)
|
|
|
|
|
notifyEngineIll();
|
|
|
|
|
};
|
|
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
void LldbEngine::handleResponse(const QString &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()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString name = item.name();
|
2015-09-09 16:34:09 +02:00
|
|
|
if (name == "result") {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = item["status"].data();
|
2014-02-06 16:47:07 +01:00
|
|
|
if (msg.size())
|
|
|
|
|
msg[0] = msg.at(0).toUpper();
|
|
|
|
|
showStatusMessage(msg);
|
2013-05-02 14:31:35 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
int token = item["token"].toInt();
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("%1^").arg(token), LogOutput);
|
2015-09-09 16:34:09 +02:00
|
|
|
if (m_commandForToken.contains(token)) {
|
|
|
|
|
DebuggerCommand cmd = m_commandForToken.take(token);
|
|
|
|
|
DebuggerResponse response;
|
|
|
|
|
response.token = token;
|
|
|
|
|
response.data = item;
|
|
|
|
|
if (cmd.callback)
|
|
|
|
|
cmd.callback(response);
|
|
|
|
|
}
|
|
|
|
|
} else if (name == "state")
|
|
|
|
|
handleStateNotification(item);
|
|
|
|
|
else if (name == "location")
|
|
|
|
|
handleLocationNotification(item);
|
|
|
|
|
else if (name == "output")
|
|
|
|
|
handleOutputNotification(item);
|
2017-01-17 13:27:14 +01:00
|
|
|
else if (name == "pid")
|
|
|
|
|
notifyInferiorPid(item.toLongLong());
|
2015-02-24 11:33:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
void LldbEngine::executeRunToLine(const ContextData &data)
|
|
|
|
|
{
|
2013-04-10 15:54:04 +02:00
|
|
|
notifyInferiorRunRequested();
|
2015-02-02 12:47:51 +01:00
|
|
|
DebuggerCommand cmd("executeRunToLocation");
|
2014-02-06 16:47:07 +01:00
|
|
|
cmd.arg("file", data.fileName);
|
|
|
|
|
cmd.arg("line", data.lineNumber);
|
|
|
|
|
cmd.arg("address", data.address);
|
|
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeRunToFunction(const QString &functionName)
|
|
|
|
|
{
|
2013-04-10 15:54:04 +02:00
|
|
|
notifyInferiorRunRequested();
|
2015-02-05 14:39:59 +01:00
|
|
|
DebuggerCommand cmd("executeRunToFunction");
|
|
|
|
|
cmd.arg("function", functionName);
|
|
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::executeJumpToLine(const ContextData &data)
|
|
|
|
|
{
|
2015-02-02 12:47:51 +01:00
|
|
|
DebuggerCommand cmd("executeJumpToLocation");
|
2014-02-06 15:40:23 +01:00
|
|
|
cmd.arg("file", data.fileName);
|
|
|
|
|
cmd.arg("line", data.lineNumber);
|
|
|
|
|
cmd.arg("address", data.address);
|
|
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::activateFrame(int frameIndex)
|
|
|
|
|
{
|
|
|
|
|
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-02-27 16:53:48 +01:00
|
|
|
StackHandler *handler = stackHandler();
|
2015-09-09 16:34:09 +02:00
|
|
|
if (frameIndex == handler->stackSize()) {
|
|
|
|
|
fetchStack(handler->stackSize() * 10 + 3);
|
2014-04-09 13:16:27 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2014-02-03 13:47:26 +01:00
|
|
|
|
2015-02-27 16:53:48 +01:00
|
|
|
QTC_ASSERT(frameIndex < handler->stackSize(), return);
|
|
|
|
|
handler->setCurrentIndex(frameIndex);
|
|
|
|
|
gotoLocation(handler->currentFrame());
|
|
|
|
|
|
2015-02-02 12:47:51 +01:00
|
|
|
DebuggerCommand cmd("activateFrame");
|
2014-02-03 13:47:26 +01:00
|
|
|
cmd.arg("index", frameIndex);
|
|
|
|
|
cmd.arg("thread", threadsHandler()->currentThread().raw());
|
|
|
|
|
runCommand(cmd);
|
2015-09-09 16:34:09 +02:00
|
|
|
|
|
|
|
|
updateLocals();
|
|
|
|
|
reloadRegisters();
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::selectThread(ThreadId threadId)
|
|
|
|
|
{
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd("selectThread");
|
|
|
|
|
cmd.arg("id", threadId.raw());
|
|
|
|
|
cmd.callback = [this](const DebuggerResponse &) {
|
2016-02-10 12:53:45 +01:00
|
|
|
fetchStack(action(MaximalStackDepth)->value().toInt());
|
2015-09-09 16:34:09 +02:00
|
|
|
};
|
2015-02-05 14:39:59 +01:00
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-02 13:48:33 +01:00
|
|
|
bool LldbEngine::stateAcceptsBreakpointChanges() const
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2015-02-02 13:48:33 +01:00
|
|
|
switch (state()) {
|
|
|
|
|
case InferiorSetupRequested:
|
|
|
|
|
case InferiorRunRequested:
|
|
|
|
|
case InferiorRunOk:
|
|
|
|
|
case InferiorStopRequested:
|
|
|
|
|
case InferiorStopOk:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-02 13:48:33 +01:00
|
|
|
bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2015-05-27 13:59:56 +02:00
|
|
|
if (runParameters().startMode == AttachCore)
|
2015-02-02 13:48:33 +01:00
|
|
|
return false;
|
2015-10-08 16:19:57 +02:00
|
|
|
if (bp.parameters().isCppBreakpoint())
|
2015-02-02 13:48:33 +01:00
|
|
|
return true;
|
2015-10-08 16:19:57 +02:00
|
|
|
return isNativeMixedEnabled();
|
2015-02-02 13:48:33 +01:00
|
|
|
}
|
2013-03-22 10:28:49 +01:00
|
|
|
|
2015-02-02 13:48:33 +01:00
|
|
|
void LldbEngine::insertBreakpoint(Breakpoint bp)
|
|
|
|
|
{
|
|
|
|
|
DebuggerCommand cmd("insertBreakpoint");
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &response) {
|
|
|
|
|
QTC_CHECK(bp.state() == BreakpointInsertProceeding);
|
|
|
|
|
updateBreakpointData(bp, response.data, true);
|
|
|
|
|
};
|
2015-02-04 16:27:46 +01:00
|
|
|
bp.addToCommand(&cmd);
|
2015-02-02 13:48:33 +01:00
|
|
|
bp.notifyBreakpointInsertProceeding();
|
2015-02-04 16:27:46 +01:00
|
|
|
runCommand(cmd);
|
2013-04-12 14:41:05 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-02 13:48:33 +01:00
|
|
|
void LldbEngine::changeBreakpoint(Breakpoint bp)
|
2013-04-12 14:41:05 +02:00
|
|
|
{
|
2015-02-02 13:48:33 +01:00
|
|
|
const BreakpointResponse &response = bp.response();
|
|
|
|
|
DebuggerCommand cmd("changeBreakpoint");
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.arg("lldbid", response.id.toString());
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &response) {
|
|
|
|
|
QTC_CHECK(!bp.isValid() || bp.state() == BreakpointChangeProceeding);
|
|
|
|
|
updateBreakpointData(bp, response.data, false);
|
|
|
|
|
};
|
2015-02-04 16:27:46 +01:00
|
|
|
bp.addToCommand(&cmd);
|
2015-02-02 13:48:33 +01:00
|
|
|
bp.notifyBreakpointChangeProceeding();
|
|
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
2013-04-09 10:59:36 +02:00
|
|
|
|
2015-02-02 13:48:33 +01:00
|
|
|
void LldbEngine::removeBreakpoint(Breakpoint bp)
|
|
|
|
|
{
|
|
|
|
|
const BreakpointResponse &response = bp.response();
|
2015-09-09 16:34:09 +02:00
|
|
|
if (response.id.isValid()) {
|
|
|
|
|
DebuggerCommand cmd("removeBreakpoint");
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.arg("lldbid", response.id.toString());
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &) {
|
|
|
|
|
QTC_CHECK(bp.state() == BreakpointRemoveProceeding);
|
|
|
|
|
Breakpoint bp0 = bp;
|
|
|
|
|
bp0.notifyBreakpointRemoveOk();
|
|
|
|
|
};
|
|
|
|
|
bp.notifyBreakpointRemoveProceeding();
|
|
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
2013-03-22 10:28:49 +01:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
void LldbEngine::updateBreakpointData(Breakpoint bp, const GdbMi &bkpt, bool added)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
|
|
|
|
BreakHandler *handler = breakHandler();
|
2014-03-05 19:06:24 +01:00
|
|
|
BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data());
|
2015-01-10 01:07:01 +01:00
|
|
|
if (!bp.isValid())
|
|
|
|
|
bp = handler->findBreakpointByResponseId(rid);
|
|
|
|
|
BreakpointResponse response = bp.response();
|
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();
|
2016-06-07 17:04:53 +02:00
|
|
|
response.condition = fromHex(bkpt["condition"].data());
|
2013-05-07 12:09:54 +02:00
|
|
|
response.hitCount = bkpt["hitcount"].toInt();
|
2016-06-07 17:04:53 +02:00
|
|
|
response.fileName = bkpt["file"].data();
|
2014-03-05 19:06:24 +01:00
|
|
|
response.lineNumber = bkpt["line"].toInt();
|
|
|
|
|
|
|
|
|
|
GdbMi locations = bkpt["locations"];
|
2015-02-19 16:44:58 +01:00
|
|
|
const int numChild = int(locations.children().size());
|
2014-03-05 19:06:24 +01:00
|
|
|
if (numChild > 1) {
|
|
|
|
|
foreach (const GdbMi &location, locations.children()) {
|
|
|
|
|
const int locid = location["locid"].toInt();
|
|
|
|
|
BreakpointResponse sub;
|
|
|
|
|
sub.id = BreakpointResponseId(rid.majorPart(), locid);
|
|
|
|
|
sub.type = response.type;
|
|
|
|
|
sub.address = location["addr"].toAddress();
|
2016-06-07 17:04:53 +02:00
|
|
|
sub.functionName = location["func"].data();
|
|
|
|
|
sub.fileName = location["file"].data();
|
2014-03-05 19:06:24 +01:00
|
|
|
sub.lineNumber = location["line"].toInt();
|
2015-01-10 01:07:01 +01:00
|
|
|
bp.insertSubBreakpoint(sub);
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
2016-04-06 18:08:52 +02:00
|
|
|
response.pending = false;
|
2014-03-05 19:06:24 +01:00
|
|
|
} else if (numChild == 1) {
|
|
|
|
|
const GdbMi location = locations.childAt(0);
|
|
|
|
|
response.address = location["addr"].toAddress();
|
2016-06-07 17:04:53 +02:00
|
|
|
response.functionName = location["func"].data();
|
2016-04-06 18:08:52 +02:00
|
|
|
response.pending = false;
|
2013-04-09 10:59:36 +02:00
|
|
|
} else {
|
2014-11-17 13:09:36 +01:00
|
|
|
// This can happen for pending breakpoints.
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("NO LOCATIONS (YET) FOR BP %1").arg(response.toString()));
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
2015-01-10 01:07:01 +01:00
|
|
|
bp.setResponse(response);
|
2014-03-05 19:06:24 +01:00
|
|
|
if (added)
|
2015-01-10 01:07:01 +01:00
|
|
|
bp.notifyBreakpointInsertOk();
|
2014-03-05 19:06:24 +01:00
|
|
|
else
|
2015-01-10 01:07:01 +01:00
|
|
|
bp.notifyBreakpointChangeOk();
|
2013-04-09 10:59:36 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
void LldbEngine::handleOutputNotification(const GdbMi &output)
|
2013-05-29 12:14:49 +02:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString channel = output["channel"].data();
|
|
|
|
|
QString data = fromHex(output["data"].data());
|
2013-05-29 12:14:49 +02:00
|
|
|
LogChannel ch = AppStuff;
|
|
|
|
|
if (channel == "stdout")
|
|
|
|
|
ch = AppOutput;
|
|
|
|
|
else if (channel == "stderr")
|
|
|
|
|
ch = AppError;
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(data, ch);
|
2013-05-29 12:14:49 +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()
|
|
|
|
|
{
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd("fetchModules");
|
|
|
|
|
cmd.callback = [this](const DebuggerResponse &response) {
|
|
|
|
|
const GdbMi &modules = response.data["modules"];
|
|
|
|
|
ModulesHandler *handler = modulesHandler();
|
|
|
|
|
handler->beginUpdateAll();
|
|
|
|
|
foreach (const GdbMi &item, modules.children()) {
|
|
|
|
|
Module module;
|
2016-06-07 17:04:53 +02:00
|
|
|
module.modulePath = item["file"].data();
|
|
|
|
|
module.moduleName = item["name"].data();
|
2015-09-09 16:34:09 +02:00
|
|
|
module.symbolsRead = Module::UnknownReadState;
|
|
|
|
|
module.startAddress = item["loaded_addr"].toAddress();
|
|
|
|
|
module.endAddress = 0; // FIXME: End address not easily available.
|
|
|
|
|
handler->updateModule(module);
|
|
|
|
|
}
|
|
|
|
|
handler->endUpdateAll();
|
|
|
|
|
};
|
|
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::requestModuleSymbols(const QString &moduleName)
|
|
|
|
|
{
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd("fetchSymbols");
|
2015-02-05 14:39:59 +01:00
|
|
|
cmd.arg("module", moduleName);
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.callback = [this, moduleName](const DebuggerResponse &response) {
|
|
|
|
|
const GdbMi &symbols = response.data["symbols"];
|
2016-06-07 17:04:53 +02:00
|
|
|
QString moduleName = response.data["module"].data();
|
2015-09-09 16:34:09 +02:00
|
|
|
Symbols syms;
|
|
|
|
|
foreach (const GdbMi &item, symbols.children()) {
|
|
|
|
|
Symbol symbol;
|
2016-06-07 17:04:53 +02:00
|
|
|
symbol.address = item["address"].data();
|
|
|
|
|
symbol.name = item["name"].data();
|
|
|
|
|
symbol.state = item["state"].data();
|
|
|
|
|
symbol.section = item["section"].data();
|
|
|
|
|
symbol.demangled = item["demangled"].data();
|
2015-09-09 16:34:09 +02:00
|
|
|
syms.append(symbol);
|
|
|
|
|
}
|
|
|
|
|
Internal::showModuleSymbols(moduleName, syms);
|
|
|
|
|
};
|
2015-02-05 14:39:59 +01:00
|
|
|
runCommand(cmd);
|
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
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2015-06-08 18:07:11 +02:00
|
|
|
bool LldbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2015-06-08 18:07:11 +02:00
|
|
|
return state() == InferiorStopOk && context.isCppEditor;
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-05-29 14:54:47 +02:00
|
|
|
void LldbEngine::updateAll()
|
|
|
|
|
{
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd("fetchThreads");
|
|
|
|
|
cmd.callback = [this](const DebuggerResponse &response) {
|
|
|
|
|
threadsHandler()->updateThreads(response.data);
|
|
|
|
|
fetchStack(action(MaximalStackDepth)->value().toInt());
|
|
|
|
|
reloadRegisters();
|
|
|
|
|
};
|
2014-04-09 13:16:27 +02:00
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 11:33:25 +01:00
|
|
|
void LldbEngine::reloadFullStack()
|
2014-04-09 13:16:27 +02:00
|
|
|
{
|
2015-09-09 16:34:09 +02:00
|
|
|
fetchStack(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::fetchStack(int limit)
|
|
|
|
|
{
|
|
|
|
|
DebuggerCommand cmd("fetchStack");
|
2015-10-08 16:19:57 +02:00
|
|
|
cmd.arg("nativemixed", isNativeMixedActive());
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.arg("stacklimit", limit);
|
2015-10-08 16:19:57 +02:00
|
|
|
cmd.arg("context", stackHandler()->currentFrame().context);
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.callback = [this](const DebuggerResponse &response) {
|
|
|
|
|
const GdbMi &stack = response.data["stack"];
|
2015-10-09 15:00:20 +02:00
|
|
|
const bool isFull = !stack["hasmore"].toInt();
|
|
|
|
|
stackHandler()->setFramesAndCurrentIndex(stack["frames"], isFull);
|
|
|
|
|
activateFrame(stackHandler()->currentIndex());
|
2015-09-09 16:34:09 +02:00
|
|
|
};
|
2014-04-09 13:16:27 +02:00
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Watch specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
void LldbEngine::assignValueInDebugger(WatchItem *,
|
2013-05-30 15:35:52 +02:00
|
|
|
const QString &expression, const QVariant &value)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2015-02-02 12:47:51 +01:00
|
|
|
DebuggerCommand cmd("assignValue");
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.arg("exp", toHex(expression));
|
|
|
|
|
cmd.arg("value", toHex(value.toString()));
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.callback = [this](const DebuggerResponse &) { updateLocals(); };
|
2013-05-30 15:35:52 +02:00
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-08 18:07:11 +02:00
|
|
|
void LldbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
2013-05-29 14:54:47 +02:00
|
|
|
{
|
2016-11-03 13:28:28 +01:00
|
|
|
watchHandler()->notifyUpdateStarted(params);
|
2015-06-16 16:38:14 +02:00
|
|
|
|
2015-10-09 15:00:20 +02:00
|
|
|
DebuggerCommand cmd("fetchVariables");
|
2015-02-12 11:31:02 +01:00
|
|
|
watchHandler()->appendFormatRequests(&cmd);
|
2015-09-14 12:53:35 +02:00
|
|
|
watchHandler()->appendWatchersAndTooltipRequests(&cmd);
|
2013-05-24 12:54:09 +02:00
|
|
|
|
|
|
|
|
const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
|
2013-06-05 11:26:46 +02:00
|
|
|
cmd.arg("passexceptions", alwaysVerbose);
|
2014-07-28 14:23:52 +02:00
|
|
|
cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
|
|
|
|
|
cmd.arg("autoderef", boolSetting(AutoDerefPointers));
|
|
|
|
|
cmd.arg("dyntype", boolSetting(UseDynamicType));
|
2015-10-27 15:50:41 +01:00
|
|
|
cmd.arg("partialvar", params.partialVariable);
|
2015-12-16 14:13:44 +01:00
|
|
|
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
|
2013-11-05 09:45:38 +01:00
|
|
|
|
2015-10-09 15:00:20 +02:00
|
|
|
StackFrame frame = stackHandler()->currentFrame();
|
|
|
|
|
cmd.arg("context", frame.context);
|
|
|
|
|
cmd.arg("nativemixed", isNativeMixedActive());
|
|
|
|
|
|
2016-09-20 08:39:26 +02:00
|
|
|
cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
|
|
|
|
|
cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());
|
|
|
|
|
|
2013-05-24 12:54:09 +02:00
|
|
|
//cmd.arg("resultvarname", m_resultVarName);
|
2016-09-20 08:39:26 +02:00
|
|
|
cmd.arg("partialvar", params.partialVariable);
|
2013-05-24 12:54:09 +02:00
|
|
|
|
2014-01-09 15:37:04 +01:00
|
|
|
m_lastDebuggableCommand = cmd;
|
2016-01-05 13:08:58 +01:00
|
|
|
m_lastDebuggableCommand.arg("passexceptions", "1");
|
2014-01-09 15:37:04 +01:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.callback = [this](const DebuggerResponse &response) {
|
|
|
|
|
updateLocalsView(response.data);
|
|
|
|
|
watchHandler()->notifyUpdateFinished();
|
|
|
|
|
};
|
2013-11-08 16:11:01 +01:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
runCommand(cmd);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::handleLldbError(QProcess::ProcessError error)
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("LLDB PROCESS ERROR: %1").arg(error));
|
2013-03-22 10:28:49 +01:00
|
|
|
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();
|
2015-01-23 15:53:09 +01:00
|
|
|
AsynchronousMessageBox::critical(tr("LLDB I/O Error"), errorMessage(error));
|
2013-03-22 10:28:49 +01:00
|
|
|
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-10-24 12:16:26 +02:00
|
|
|
"invoked program \"%1\" is missing, or you may have insufficient "
|
2013-03-22 10:28:49 +01:00
|
|
|
"permissions to invoke the program.")
|
2016-07-29 15:55:15 +02:00
|
|
|
.arg(runParameters().debugger.executable);
|
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:
|
2016-06-07 17:04:53 +02:00
|
|
|
return tr("An unknown error in the LLDB process occurred.") + ' ';
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-05 11:11:32 +01:00
|
|
|
void LldbEngine::handleLldbFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
2015-03-05 11:11:32 +01:00
|
|
|
notifyDebuggerProcessFinished(exitCode, exitStatus, QLatin1String("LLDB"));
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::readLldbStandardError()
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString err = QString::fromUtf8(m_lldbProc.readAllStandardError());
|
2014-11-15 10:10:51 +01:00
|
|
|
qDebug() << "\nLLDB STDERR UNEXPECTED: " << err;
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("Lldb stderr: " + err, LogError);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::readLldbStandardOutput()
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QByteArray outba = m_lldbProc.readAllStandardOutput();
|
|
|
|
|
outba.replace("\r\n", "\n");
|
|
|
|
|
QString out = QString::fromUtf8(outba);
|
|
|
|
|
showMessage(out, LogOutput);
|
2013-04-30 10:46:48 +02:00
|
|
|
m_inbuffer.append(out);
|
2013-03-22 10:28:49 +01:00
|
|
|
while (true) {
|
2013-11-01 10:32:37 +01:00
|
|
|
int pos = m_inbuffer.indexOf("@\n");
|
2013-03-22 10:28:49 +01:00
|
|
|
if (pos == -1)
|
|
|
|
|
break;
|
2016-06-07 17:04:53 +02:00
|
|
|
QString response = m_inbuffer.left(pos).trimmed();
|
2013-11-01 10:32:37 +01:00
|
|
|
m_inbuffer = m_inbuffer.mid(pos + 2);
|
2015-03-09 13:30:22 +01:00
|
|
|
if (response == "lldbstartupok")
|
|
|
|
|
startLldbStage2();
|
|
|
|
|
else
|
|
|
|
|
emit outputReady(response);
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
void LldbEngine::handleStateNotification(const GdbMi &reportedState)
|
2013-04-10 15:54:04 +02:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString newState = reportedState.data();
|
2013-05-02 14:31:35 +02:00
|
|
|
if (newState == "running")
|
|
|
|
|
notifyInferiorRunOk();
|
|
|
|
|
else if (newState == "inferiorrunfailed")
|
|
|
|
|
notifyInferiorRunFailed();
|
2016-04-13 18:19:45 +02:00
|
|
|
else if (newState == "continueafternextstop")
|
|
|
|
|
m_continueAtNextSpontaneousStop = true;
|
2013-11-19 10:45:00 +01:00
|
|
|
else if (newState == "stopped") {
|
2013-05-02 14:31:35 +02:00
|
|
|
notifyInferiorSpontaneousStop();
|
2016-12-13 09:46:51 +01:00
|
|
|
if (m_onStop.isEmpty()) {
|
|
|
|
|
if (m_continueAtNextSpontaneousStop) {
|
|
|
|
|
m_continueAtNextSpontaneousStop = false;
|
|
|
|
|
continueInferior();
|
|
|
|
|
} else {
|
|
|
|
|
updateAll();
|
|
|
|
|
}
|
2014-03-11 15:49:34 +01:00
|
|
|
} else {
|
2016-12-13 09:46:51 +01:00
|
|
|
showMessage("HANDLING QUEUED COMMANDS AFTER TEMPORARY STOP", LogMisc);
|
|
|
|
|
DebuggerCommandSequence seq = m_onStop;
|
|
|
|
|
m_onStop = DebuggerCommandSequence();
|
|
|
|
|
for (const DebuggerCommand &cmd : seq.commands())
|
|
|
|
|
runCommand(cmd);
|
|
|
|
|
if (seq.wantContinue())
|
|
|
|
|
continueInferior();
|
2013-11-19 10:45:00 +01:00
|
|
|
}
|
2015-03-25 16:34:03 +01:00
|
|
|
} else if (newState == "inferiorstopok") {
|
2013-05-02 14:31:35 +02:00
|
|
|
notifyInferiorStopOk();
|
2015-03-25 16:34:03 +01:00
|
|
|
} else if (newState == "inferiorstopfailed")
|
2013-05-02 14:31:35 +02:00
|
|
|
notifyInferiorStopFailed();
|
2014-06-02 16:45:12 +02:00
|
|
|
else if (newState == "inferiorill")
|
|
|
|
|
notifyInferiorIll();
|
2013-05-02 14:31:35 +02:00
|
|
|
else if (newState == "enginesetupok")
|
|
|
|
|
notifyEngineSetupOk();
|
|
|
|
|
else if (newState == "enginesetupfailed")
|
|
|
|
|
notifyEngineSetupFailed();
|
2013-11-11 16:16:58 +01:00
|
|
|
else if (newState == "enginerunfailed")
|
|
|
|
|
notifyEngineRunFailed();
|
2013-11-19 10:45:00 +01:00
|
|
|
else if (newState == "enginerunandinferiorrunok") {
|
2015-05-27 13:59:56 +02:00
|
|
|
if (runParameters().continueAfterAttach)
|
2013-11-19 10:45:00 +01:00
|
|
|
m_continueAtNextSpontaneousStop = true;
|
2013-05-02 14:31:35 +02:00
|
|
|
notifyEngineRunAndInferiorRunOk();
|
2016-09-14 14:31:27 +02:00
|
|
|
} else if (newState == "enginerunandinferiorstopok") {
|
2013-05-22 14:30:36 +02:00
|
|
|
notifyEngineRunAndInferiorStopOk();
|
2016-09-14 14:31:27 +02:00
|
|
|
continueInferior();
|
|
|
|
|
} else if (newState == "enginerunokandinferiorunrunnable")
|
2015-02-27 11:56:03 +01:00
|
|
|
notifyEngineRunOkAndInferiorUnrunnable();
|
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
|
|
|
}
|
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
void LldbEngine::handleLocationNotification(const GdbMi &reportedLocation)
|
2013-04-10 17:49:35 +02:00
|
|
|
{
|
2015-10-09 15:00:20 +02:00
|
|
|
qulonglong address = reportedLocation["address"].toAddress();
|
2016-06-07 17:04:53 +02:00
|
|
|
QString fileName = reportedLocation["file"].data();
|
|
|
|
|
QString function = reportedLocation["function"].data();
|
2015-10-09 15:00:20 +02:00
|
|
|
int lineNumber = reportedLocation["line"].toInt();
|
|
|
|
|
Location loc = Location(fileName, lineNumber);
|
|
|
|
|
if (boolSetting(OperateByInstruction) || !QFileInfo::exists(fileName) || lineNumber <= 0) {
|
|
|
|
|
loc = Location(address);
|
2013-06-11 18:07:59 +02:00
|
|
|
loc.setNeedsMarker(true);
|
2014-11-15 13:13:29 +01:00
|
|
|
loc.setUseAssembler(true);
|
2013-06-11 18:07:59 +02:00
|
|
|
}
|
2015-10-09 15:00:20 +02:00
|
|
|
|
|
|
|
|
// Quickly set the location marker.
|
|
|
|
|
if (lineNumber > 0
|
|
|
|
|
&& QFileInfo::exists(fileName)
|
2015-10-14 13:26:22 +02:00
|
|
|
&& function != "::qt_qmlDebugMessageAvailable()")
|
2015-10-09 15:00:20 +02:00
|
|
|
gotoLocation(Location(fileName, lineNumber));
|
2013-04-10 17:49:35 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
void LldbEngine::reloadRegisters()
|
|
|
|
|
{
|
2016-03-14 18:14:06 +01:00
|
|
|
if (!Internal::isRegistersWindowVisible())
|
2015-09-09 16:34:09 +02:00
|
|
|
return;
|
|
|
|
|
|
2016-11-25 10:15:45 +01:00
|
|
|
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd("fetchRegisters");
|
|
|
|
|
cmd.callback = [this](const DebuggerResponse &response) {
|
|
|
|
|
RegisterHandler *handler = registerHandler();
|
|
|
|
|
GdbMi regs = response.data["registers"];
|
|
|
|
|
foreach (const GdbMi &item, regs.children()) {
|
|
|
|
|
Register reg;
|
|
|
|
|
reg.name = item["name"].data();
|
2016-06-07 17:04:53 +02:00
|
|
|
reg.value.fromString(item["value"].data(), HexadecimalFormat);
|
2015-09-09 16:34:09 +02:00
|
|
|
reg.size = item["size"].data().toInt();
|
|
|
|
|
reg.reportedType = item["type"].data();
|
|
|
|
|
if (reg.reportedType.startsWith("unsigned"))
|
|
|
|
|
reg.kind = IntegerRegister;
|
|
|
|
|
handler->updateRegister(reg);
|
|
|
|
|
}
|
|
|
|
|
handler->commitUpdates();
|
|
|
|
|
};
|
|
|
|
|
runCommand(cmd);
|
2013-04-30 10:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-18 16:48:57 +01:00
|
|
|
void LldbEngine::reloadDebuggingHelpers()
|
|
|
|
|
{
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"reloadDumpers"});
|
2015-03-18 16:48:57 +01:00
|
|
|
updateAll();
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2014-03-06 12:04:47 +01:00
|
|
|
const Location &loc = agent->location();
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd("fetchDisassembler");
|
2014-03-06 12:04:47 +01:00
|
|
|
cmd.arg("address", loc.address());
|
|
|
|
|
cmd.arg("function", loc.functionName());
|
2014-07-28 14:23:52 +02:00
|
|
|
cmd.arg("flavor", boolSetting(IntelFlavor) ? "intel" : "att");
|
2015-09-09 16:34:09 +02:00
|
|
|
cmd.callback = [this, id](const DebuggerResponse &response) {
|
|
|
|
|
DisassemblerLines result;
|
|
|
|
|
QPointer<DisassemblerAgent> agent = m_disassemblerAgents.key(id);
|
|
|
|
|
if (!agent.isNull()) {
|
|
|
|
|
foreach (const GdbMi &line, response.data["lines"].children()) {
|
|
|
|
|
DisassemblerLine dl;
|
|
|
|
|
dl.address = line["address"].toAddress();
|
2016-06-07 17:04:53 +02:00
|
|
|
//dl.data = line["data"].data();
|
2015-09-09 16:34:09 +02:00
|
|
|
//dl.rawData = line["rawdata"].data();
|
2016-06-07 17:04:53 +02:00
|
|
|
dl.data = line["rawdata"].data();
|
2015-09-09 16:34:09 +02:00
|
|
|
if (!dl.data.isEmpty())
|
|
|
|
|
dl.data += QString(30 - dl.data.size(), QLatin1Char(' '));
|
2016-06-07 17:04:53 +02:00
|
|
|
dl.data += line["data"].data();
|
2015-09-09 16:34:09 +02:00
|
|
|
dl.offset = line["offset"].toInt();
|
|
|
|
|
dl.lineNumber = line["line"].toInt();
|
2016-06-07 17:04:53 +02:00
|
|
|
dl.fileName = line["file"].data();
|
|
|
|
|
dl.function = line["function"].data();
|
2015-09-09 16:34:09 +02:00
|
|
|
dl.hunk = line["hunk"].toInt();
|
2016-06-07 17:04:53 +02:00
|
|
|
QString comment = fromHex(line["comment"].data());
|
2015-09-09 16:34:09 +02:00
|
|
|
if (!comment.isEmpty())
|
2016-06-07 17:04:53 +02:00
|
|
|
dl.data += " # " + comment;
|
2015-09-09 16:34:09 +02:00
|
|
|
result.appendLine(dl);
|
|
|
|
|
}
|
|
|
|
|
agent->setContents(result);
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-03-06 12:04:47 +01:00
|
|
|
runCommand(cmd);
|
2013-05-07 08:46:51 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
void LldbEngine::fetchFullBacktrace()
|
2014-03-11 16:40:07 +01:00
|
|
|
{
|
2015-09-09 16:34:09 +02:00
|
|
|
DebuggerCommand cmd("fetchFullBacktrace");
|
|
|
|
|
cmd.callback = [](const DebuggerResponse &response) {
|
2016-06-07 17:04:53 +02:00
|
|
|
Internal::openTextEditor("Backtrace $", fromHex(response.data.data()));
|
2015-09-09 16:34:09 +02:00
|
|
|
};
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand(cmd);
|
2014-03-11 16:40:07 +01:00
|
|
|
}
|
2013-05-07 08:46:51 +02:00
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
void LldbEngine::fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length)
|
2013-05-07 08:46:51 +02:00
|
|
|
{
|
2015-02-02 12:47:51 +01:00
|
|
|
DebuggerCommand cmd("fetchMemory");
|
2014-03-06 12:04:47 +01:00
|
|
|
cmd.arg("address", addr);
|
|
|
|
|
cmd.arg("length", length);
|
2016-07-14 10:00:15 +02:00
|
|
|
cmd.callback = [this, agent](const DebuggerResponse &response) {
|
2015-09-09 16:34:09 +02:00
|
|
|
qulonglong addr = response.data["address"].toAddress();
|
2016-07-14 10:00:15 +02:00
|
|
|
QByteArray ba = QByteArray::fromHex(response.data["contents"].data().toUtf8());
|
|
|
|
|
agent->addData(addr, ba);
|
2015-09-09 16:34:09 +02:00
|
|
|
};
|
2014-03-06 12:04:47 +01:00
|
|
|
runCommand(cmd);
|
2013-05-07 08:46:51 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
void LldbEngine::changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data)
|
2013-05-07 08:46:51 +02:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
Q_UNUSED(agent)
|
2015-02-02 12:47:51 +01:00
|
|
|
DebuggerCommand cmd("writeMemory");
|
2014-03-06 12:04:47 +01:00
|
|
|
cmd.arg("address", addr);
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.arg("data", QString::fromUtf8(data.toHex()));
|
2016-07-14 10:00:15 +02:00
|
|
|
cmd.callback = [this](const DebuggerResponse &response) { Q_UNUSED(response); };
|
2014-03-06 12:04:47 +01:00
|
|
|
runCommand(cmd);
|
2013-05-03 17:18:07 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
void LldbEngine::setRegisterValue(const QString &name, const QString &value)
|
2013-05-07 08:46:51 +02:00
|
|
|
{
|
2015-02-05 14:39:59 +01:00
|
|
|
DebuggerCommand cmd("setRegister");
|
|
|
|
|
cmd.arg("name", name);
|
|
|
|
|
cmd.arg("value", value);
|
|
|
|
|
runCommand(cmd);
|
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
|
|
|
|
|
| WatchWidgetsCapability
|
2016-12-13 09:46:51 +01:00
|
|
|
| AddWatcherCapability
|
2013-04-12 16:58:25 +02:00
|
|
|
| ShowModuleSymbolsCapability
|
|
|
|
|
| ShowModuleSectionsCapability
|
|
|
|
|
| CatchCapability
|
|
|
|
|
| OperateByInstructionCapability
|
|
|
|
|
| RunToLineCapability
|
|
|
|
|
| WatchComplexExpressionsCapability
|
|
|
|
|
| MemoryAddressCapability))
|
|
|
|
|
return true;
|
|
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
if (runParameters().startMode == AttachCore)
|
2013-04-12 16:58:25 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//return cap == SnapshotCapability;
|
|
|
|
|
return false;
|
2013-03-22 10:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
DebuggerEngine *createLldbEngine(const DebuggerRunParameters &startParameters)
|
2013-03-22 10:28:49 +01:00
|
|
|
{
|
|
|
|
|
return new LldbEngine(startParameters);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-18 19:21:27 +02:00
|
|
|
void LldbEngine::notifyEngineRemoteSetupFinished(const RemoteSetupResult &result)
|
2013-10-10 15:15:49 +02:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
|
2014-09-18 19:21:27 +02:00
|
|
|
DebuggerEngine::notifyEngineRemoteSetupFinished(result);
|
2013-10-10 15:15:49 +02:00
|
|
|
|
2014-09-18 20:01:19 +02:00
|
|
|
if (result.success) {
|
|
|
|
|
startLldb();
|
|
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ADAPTER START FAILED");
|
2014-09-18 19:21:27 +02:00
|
|
|
if (!result.reason.isEmpty()) {
|
|
|
|
|
const QString title = tr("Adapter start failed");
|
2015-01-23 15:53:09 +01:00
|
|
|
ICore::showWarningWithOptions(title, result.reason);
|
2014-09-18 19:21:27 +02:00
|
|
|
}
|
|
|
|
|
notifyEngineSetupFailed();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-10-10 15:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2014-03-03 16:59:56 +01:00
|
|
|
void LldbEngine::stubStarted()
|
|
|
|
|
{
|
|
|
|
|
startLldb();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::stubError(const QString &msg)
|
|
|
|
|
{
|
2015-01-23 15:53:09 +01:00
|
|
|
AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
|
2014-03-03 16:59:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LldbEngine::stubExited()
|
|
|
|
|
{
|
|
|
|
|
if (state() == EngineShutdownRequested || state() == DebuggerFinished) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("STUB EXITED EXPECTEDLY");
|
2014-03-03 16:59:56 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("STUB EXITED");
|
2014-03-03 16:59:56 +01:00
|
|
|
notifyEngineIll();
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 10:28:49 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|