diff options
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp')
-rw-r--r-- | src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp | 229 |
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; |