aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp')
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp229
1 files changed, 137 insertions, 92 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index 7a9d4a66a4..5ee9e5e9e9 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
@@ -1,43 +1,51 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** 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 The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qv4debugservice.h"
+#include "qv4debugjob.h"
#include "qqmlengine.h"
+#include "qqmldebugpacket.h"
+
#include <private/qv4engine_p.h>
#include <private/qv4isel_moth_p.h>
#include <private/qv4function_p.h>
#include <private/qqmldebugconnector_p.h>
-
#include <private/qv8engine_p.h>
#include <QtCore/QJsonArray>
@@ -63,7 +71,6 @@ QT_BEGIN_NAMESPACE
class V8CommandHandler;
class UnknownV8CommandHandler;
-int QV4DebugServiceImpl::debuggerIndex = 0;
int QV4DebugServiceImpl::sequence = 0;
class V8CommandHandler
@@ -104,7 +111,7 @@ protected:
void addCommand() { response.insert(QStringLiteral("command"), cmd); }
void addRequestSequence() { response.insert(QStringLiteral("request_seq"), seq); }
void addSuccess(bool success) { response.insert(QStringLiteral("success"), success); }
- void addBody(const QJsonObject &body)
+ void addBody(const QJsonValue &body)
{
response.insert(QStringLiteral("body"), body);
}
@@ -169,6 +176,7 @@ public:
QJsonObject body;
body.insert(QStringLiteral("V8Version"),
QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR));
+ body.insert(QStringLiteral("UnpausedEvaluate"), true);
addBody(body);
}
};
@@ -271,8 +279,14 @@ public:
int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10);
// no idea what the bottom property is for, so we'll ignore it.
- BacktraceJob job(debugService->collector(), fromFrame, toFrame);
- debugService->debuggerAgent.firstDebugger()->runInEngine(&job);
+ QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
+ if (!debugger) {
+ createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve backtraces."));
+ return;
+ }
+
+ BacktraceJob job(debugger->collector(), fromFrame, toFrame);
+ debugger->runInEngine(&job);
// response:
addCommand();
@@ -296,13 +310,19 @@ public:
const int frameNr = arguments.value(QStringLiteral("number")).toInt(
debugService->selectedFrame());
+ QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
+ if (!debugger) {
+ createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve frames."));
+ return;
+ }
+
if (frameNr < 0) {
createErrorResponse(QStringLiteral("frame command has invalid frame number"));
return;
}
- FrameJob job(debugService->collector(), frameNr);
- debugService->debuggerAgent.firstDebugger()->runInEngine(&job);
+ FrameJob job(debugger->collector(), frameNr);
+ debugger->runInEngine(&job);
if (!job.wasSuccessful()) {
createErrorResponse(QStringLiteral("frame retrieval failed"));
return;
@@ -333,6 +353,12 @@ public:
debugService->selectedFrame());
const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0);
+ QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
+ if (!debugger) {
+ createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve scope."));
+ return;
+ }
+
if (frameNr < 0) {
createErrorResponse(QStringLiteral("scope command has invalid frame number"));
return;
@@ -342,8 +368,8 @@ public:
return;
}
- ScopeJob job(debugService->collector(), frameNr, scopeNr);
- debugService->debuggerAgent.firstDebugger()->runInEngine(&job);
+ ScopeJob job(debugger->collector(), frameNr, scopeNr);
+ debugger->runInEngine(&job);
if (!job.wasSuccessful()) {
createErrorResponse(QStringLiteral("scope retrieval failed"));
return;
@@ -370,8 +396,21 @@ public:
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray();
- ValueLookupJob job(handles, debugService->collector());
- debugService->debuggerAgent.firstDebugger()->runInEngine(&job);
+ QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
+ if (!debugger) {
+ const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers();
+ if (debuggers.count() > 1) {
+ createErrorResponse(QStringLiteral("Cannot lookup values if multiple debuggers are running and none is paused"));
+ return;
+ } else if (debuggers.count() == 0) {
+ createErrorResponse(QStringLiteral("No debuggers available to lookup values"));
+ return;
+ }
+ debugger = debuggers.first();
+ }
+
+ ValueLookupJob job(handles, debugger->collector());
+ debugger->runInEngine(&job);
if (!job.exceptionMessage().isEmpty()) {
createErrorResponse(job.exceptionMessage());
} else {
@@ -396,10 +435,15 @@ public:
// decypher the payload:
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
+ if (!debugger) {
+ createErrorResponse(QStringLiteral("Debugger has to be paused in order to continue."));
+ return;
+ }
+ debugService->debuggerAgent.clearAllPauseRequests();
if (arguments.empty()) {
- debugger->resume(QV4::Debugging::V4Debugger::FullThrottle);
+ debugger->resume(QV4Debugger::FullThrottle);
} else {
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
QString stepAction = arguments.value(QStringLiteral("stepaction")).toString();
@@ -408,11 +452,11 @@ public:
qWarning() << "Step count other than 1 is not supported.";
if (stepAction == QStringLiteral("in")) {
- debugger->resume(QV4::Debugging::V4Debugger::StepIn);
+ debugger->resume(QV4Debugger::StepIn);
} else if (stepAction == QStringLiteral("out")) {
- debugger->resume(QV4::Debugging::V4Debugger::StepOut);
+ debugger->resume(QV4Debugger::StepOut);
} else if (stepAction == QStringLiteral("next")) {
- debugger->resume(QV4::Debugging::V4Debugger::StepOver);
+ debugger->resume(QV4Debugger::StepOver);
} else {
createErrorResponse(QStringLiteral("continue command has invalid stepaction"));
return;
@@ -504,11 +548,28 @@ public:
}
// do it:
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
- GatherSourcesJob job(debugger->engine(), requestSequenceNr());
+ QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
+ if (!debugger) {
+ createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve scripts."));
+ return;
+ }
+
+ GatherSourcesJob job(debugger->engine());
debugger->runInEngine(&job);
- // response will be send by
+ QJsonArray body;
+ foreach (const QString &source, job.result()) {
+ QJsonObject src;
+ src[QLatin1String("name")] = source;
+ src[QLatin1String("scriptType")] = 4;
+ body.append(src);
+ }
+
+ addSuccess(true);
+ addRunning();
+ addBody(body);
+ addCommand();
+ addRequestSequence();
}
};
@@ -547,27 +608,36 @@ public:
virtual void handleRequest()
{
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
- if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QString expression = arguments.value(QStringLiteral("expression")).toString();
- const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
-
- QV4DataCollector *collector = debugService->collector();
- ExpressionEvalJob job(debugger->engine(), frame, expression, collector);
- debugger->runInEngine(&job);
- if (job.hasExeption()) {
- createErrorResponse(job.exceptionMessage());
- } else {
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- addBody(job.returnValue());
- addRefs(job.refs());
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ QString expression = arguments.value(QStringLiteral("expression")).toString();
+ int frame = -1;
+
+ QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
+ if (!debugger) {
+ const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers();
+ if (debuggers.count() > 1) {
+ createErrorResponse(QStringLiteral("Cannot evaluate expressions if multiple debuggers are running and none is paused"));
+ return;
+ } else if (debuggers.count() == 0) {
+ createErrorResponse(QStringLiteral("No debuggers available to evaluate expressions"));
+ return;
}
+ debugger = debuggers.first();
} else {
- createErrorResponse(QStringLiteral("Debugger has to be paused for evaluate to work."));
+ frame = arguments.value(QStringLiteral("frame")).toInt(0);
+ }
+
+ ExpressionEvalJob job(debugger->engine(), frame, expression, debugger->collector());
+ debugger->runInEngine(&job);
+ if (job.hasExeption()) {
+ createErrorResponse(job.exceptionMessage());
+ } else {
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
}
};
@@ -589,7 +659,7 @@ V8CommandHandler *QV4DebugServiceImpl::v8CommandHandler(const QString &command)
QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) :
QQmlConfigurableDebugService<QV4DebugService>(1, parent),
- debuggerAgent(this), version(1), theSelectedFrame(0),
+ debuggerAgent(this), theSelectedFrame(0),
unknownV8CommandHandler(new UnknownV8CommandHandler)
{
addHandler(new V8VersionRequest);
@@ -611,7 +681,7 @@ QV4DebugServiceImpl::~QV4DebugServiceImpl()
qDeleteAll(handlers);
}
-void QV4DebugServiceImpl::engineAdded(QQmlEngine *engine)
+void QV4DebugServiceImpl::engineAdded(QJSEngine *engine)
{
QMutexLocker lock(&m_configMutex);
if (engine) {
@@ -619,10 +689,9 @@ void QV4DebugServiceImpl::engineAdded(QQmlEngine *engine)
if (QQmlDebugConnector *server = QQmlDebugConnector::instance()) {
if (ee) {
ee->iselFactory.reset(new QV4::Moth::ISelFactory);
- QV4::Debugging::V4Debugger *debugger = new QV4::Debugging::V4Debugger(ee);
+ QV4Debugger *debugger = new QV4Debugger(ee);
if (state() == Enabled)
ee->setDebugger(debugger);
- debuggerMap.insert(debuggerIndex++, debugger);
debuggerAgent.addDebugger(debugger);
debuggerAgent.moveToThread(server->thread());
}
@@ -631,25 +700,15 @@ void QV4DebugServiceImpl::engineAdded(QQmlEngine *engine)
QQmlConfigurableDebugService<QV4DebugService>::engineAdded(engine);
}
-void QV4DebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine)
+void QV4DebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
{
QMutexLocker lock(&m_configMutex);
if (engine){
const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
if (ee) {
- QV4::Debugging::V4Debugger *debugger
- = qobject_cast<QV4::Debugging::V4Debugger *>(ee->debugger);
- if (debugger) {
- typedef QMap<int, QV4::Debugging::V4Debugger *>::const_iterator DebuggerMapIterator;
- const DebuggerMapIterator end = debuggerMap.constEnd();
- for (DebuggerMapIterator i = debuggerMap.constBegin(); i != end; ++i) {
- if (i.value() == debugger) {
- debuggerMap.remove(i.key());
- break;
- }
- }
+ QV4Debugger *debugger = qobject_cast<QV4Debugger *>(ee->debugger);
+ if (debugger)
debuggerAgent.removeDebugger(debugger);
- }
}
}
QQmlConfigurableDebugService<QV4DebugService>::engineAboutToBeRemoved(engine);
@@ -659,12 +718,10 @@ void QV4DebugServiceImpl::stateAboutToBeChanged(State state)
{
QMutexLocker lock(&m_configMutex);
if (state == Enabled) {
- typedef QMap<int, QV4::Debugging::V4Debugger *>::const_iterator DebuggerMapIterator;
- const DebuggerMapIterator end = debuggerMap.constEnd();
- for (DebuggerMapIterator i = debuggerMap.constBegin(); i != end; ++i) {
- QV4::ExecutionEngine *ee = i.value()->engine();
+ foreach (QV4Debugger *debugger, debuggerAgent.debuggers()) {
+ QV4::ExecutionEngine *ee = debugger->engine();
if (!ee->debugger)
- ee->setDebugger(i.value());
+ ee->setDebugger(debugger);
}
}
QQmlConfigurableDebugService<QV4DebugService>::stateAboutToBeChanged(state);
@@ -692,7 +749,7 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message)
{
QMutexLocker lock(&m_configMutex);
- QQmlDebugStream ms(message);
+ QQmlDebugPacket ms(message);
QByteArray header;
ms >> header;
@@ -733,11 +790,10 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message)
void QV4DebugServiceImpl::sendSomethingToSomebody(const char *type, int magicNumber)
{
- QByteArray response;
- QQmlDebugStream rs(&response, QIODevice::WriteOnly);
+ QQmlDebugPacket rs;
rs << QByteArray(type)
- << QByteArray::number(version) << QByteArray::number(magicNumber);
- emit messageToClient(name(), packMessage(type, response));
+ << QByteArray::number(int(version())) << QByteArray::number(magicNumber);
+ emit messageToClient(name(), packMessage(type, rs.data()));
}
void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload)
@@ -757,11 +813,10 @@ void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload)
QByteArray QV4DebugServiceImpl::packMessage(const QByteArray &command, const QByteArray &message)
{
- QByteArray reply;
- QQmlDebugStream rs(&reply, QIODevice::WriteOnly);
+ QQmlDebugPacket rs;
static const QByteArray cmd("V8DEBUG");
rs << cmd << command << message;
- return reply;
+ return rs.data();
}
void QV4DebugServiceImpl::send(QJsonObject v8Payload)
@@ -780,16 +835,6 @@ void QV4DebugServiceImpl::send(QJsonObject v8Payload)
emit messageToClient(name(), packMessage("v8message", responseData));
}
-void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine)
-{
- theCollector.reset(new QV4DataCollector(engine));
-}
-
-QV4DataCollector *QV4DebugServiceImpl::collector() const
-{
- return theCollector.data();
-}
-
void QV4DebugServiceImpl::selectFrame(int frameNr)
{
theSelectedFrame = frameNr;