aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/debugger/qv4debugservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/debugger/qv4debugservice.cpp')
-rw-r--r--src/qml/debugger/qv4debugservice.cpp1265
1 files changed, 0 insertions, 1265 deletions
diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp
deleted file mode 100644
index cefb29e031..0000000000
--- a/src/qml/debugger/qv4debugservice.cpp
+++ /dev/null
@@ -1,1265 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL21$
-** 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.
-**
-** 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.
-**
-** 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.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4debugservice_p.h"
-#include "qqmlconfigurabledebugservice_p_p.h"
-#include "qqmlengine.h"
-#include "qv4debugging_p.h"
-#include "qv4engine_p.h"
-#include "qv4function_p.h"
-#include "qqmldebugserver_p.h"
-
-#include <private/qv8engine_p.h>
-
-#include <QtCore/QJsonArray>
-#include <QtCore/QJsonDocument>
-#include <QtCore/QJsonObject>
-#include <QtCore/QJsonValue>
-
-const char *V4_CONNECT = "connect";
-const char *V4_DISCONNECT = "disconnect";
-const char *V4_BREAK_ON_SIGNAL = "breakonsignal";
-const char *V4_ADD_BREAKPOINT = "addBreakpoint";
-const char *V4_REMOVE_BREAKPOINT = "removeBreakpoint";
-const char *V4_PAUSE = "interrupt";
-const char *V4_ALL = "all";
-const char *V4_BREAK = "break";
-
-const char *V4_FILENAME = "filename";
-const char *V4_LINENUMBER = "linenumber";
-
-#define NO_PROTOCOL_TRACING
-#ifdef NO_PROTOCOL_TRACING
-# define TRACE_PROTOCOL(x)
-#else
-#include <QtCore/QDebug>
-# define TRACE_PROTOCOL(x) x
-#endif
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(QV4DebugService, v4ServiceInstance)
-
-class QV4DebugServicePrivate;
-
-class QV4DebuggerAgent : public QV4::Debugging::DebuggerAgent
-{
-public:
- QV4DebuggerAgent(QV4DebugServicePrivate *debugServicePrivate)
- : debugServicePrivate(debugServicePrivate)
- {}
-
- QV4::Debugging::Debugger *firstDebugger() const
- {
- // Currently only 1 single engine is supported, so:
- if (m_debuggers.isEmpty())
- return 0;
- else
- return m_debuggers.first();
- }
-
- bool isRunning() const
- {
- // Currently only 1 single engine is supported, so:
- if (QV4::Debugging::Debugger *debugger = firstDebugger())
- return debugger->state() == QV4::Debugging::Debugger::Running;
- else
- return false;
- }
-
-public slots:
- virtual void debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason);
- virtual void sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, int requestSequenceNr);
-
-private:
- QV4DebugServicePrivate *debugServicePrivate;
-};
-
-class V8CommandHandler;
-class UnknownV8CommandHandler;
-
-class VariableCollector: public QV4::Debugging::Debugger::Collector
-{
-public:
- VariableCollector(QV4::ExecutionEngine *engine)
- : Collector(engine)
- , destination(0)
- {}
-
- virtual ~VariableCollector() {}
-
- void collectScope(QJsonArray *dest, QV4::Debugging::Debugger *debugger, int frameNr, int scopeNr)
- {
- qSwap(destination, dest);
- bool oldIsProp = isProperty();
- setIsProperty(true);
- debugger->collectArgumentsInContext(this, frameNr, scopeNr);
- debugger->collectLocalsInContext(this, frameNr, scopeNr);
- setIsProperty(oldIsProp);
- qSwap(destination, dest);
- }
-
- void setDestination(QJsonArray *dest)
- { destination = dest; }
-
- QJsonArray retrieveRefsToInclude()
- {
- QJsonArray result;
- qSwap(refsToInclude, result);
- return result;
- }
-
- QJsonValue lookup(int handle, bool addRefs = true)
- {
- if (handle < 0)
- handle = -handle;
-
- if (addRefs)
- foreach (int ref, refsByHandle[handle])
- refsToInclude.append(lookup(ref, false));
- return refs[handle];
- }
-
- QJsonObject makeRef(int refId)
- {
- QJsonObject ref;
- ref[QLatin1String("ref")] = refId;
- return ref;
- }
-
- QJsonObject addFunctionRef(const QString &name)
- {
- const int refId = newRefId();
-
- QJsonObject func;
- func[QLatin1String("handle")] = refId;
- func[QLatin1String("type")] = QStringLiteral("function");
- func[QLatin1String("className")] = QStringLiteral("Function");
- func[QLatin1String("name")] = name;
- insertRef(func, refId);
-
- return makeRef(refId);
- }
-
- QJsonObject addScriptRef(const QString &name)
- {
- const int refId = newRefId();
-
- QJsonObject func;
- func[QLatin1String("handle")] = refId;
- func[QLatin1String("type")] = QStringLiteral("script");
- func[QLatin1String("name")] = name;
- insertRef(func, refId);
-
- return makeRef(refId);
- }
-
- QJsonObject addObjectRef(QJsonObject obj, bool anonymous)
- {
- int ref = newRefId();
-
- if (anonymous)
- ref = -ref;
- obj[QLatin1String("handle")] = ref;
- obj[QLatin1String("type")] = QStringLiteral("object");
- insertRef(obj, ref);
- QSet<int> used;
- qSwap(usedRefs, used);
- refsByHandle.insert(ref, used);
-
- return makeRef(ref);
- }
-
-protected:
- virtual void addUndefined(const QString &name)
- {
- QJsonObject o;
- addHandle(name, o, QStringLiteral("undefined"));
- }
-
- virtual void addNull(const QString &name)
- {
- QJsonObject o;
- addHandle(name, o, QStringLiteral("null"));
- }
-
- virtual void addBoolean(const QString &name, bool value)
- {
- QJsonObject o;
- o[QLatin1String("value")] = value;
- addHandle(name, o, QStringLiteral("boolean"));
- }
-
- virtual void addString(const QString &name, const QString &value)
- {
- QJsonObject o;
- o[QLatin1String("value")] = value;
- addHandle(name, o, QStringLiteral("string"));
- }
-
- virtual void addObject(const QString &name, const QV4::Value &value)
- {
- QV4::Scope scope(engine());
- QV4::ScopedObject obj(scope, value.asObject());
-
- int ref = cachedObjectRef(obj);
- if (ref != -1) {
- addNameRefPair(name, ref);
- } else {
- int ref = newRefId();
- cacheObjectRef(obj, ref);
-
- QJsonArray properties, *prev = &properties;
- QSet<int> used;
- qSwap(usedRefs, used);
- qSwap(destination, prev);
- collect(obj);
- qSwap(destination, prev);
- qSwap(usedRefs, used);
-
- QJsonObject o;
- o[QLatin1String("properties")] = properties;
- addHandle(name, o, QStringLiteral("object"), ref);
- refsByHandle.insert(ref, used);
- }
- }
-
- virtual void addInteger(const QString &name, int value)
- {
- QJsonObject o;
- o[QLatin1String("value")] = value;
- addHandle(name, o, QStringLiteral("number"));
- }
-
- virtual void addDouble(const QString &name, double value)
- {
- QJsonObject o;
- o[QLatin1String("value")] = value;
- addHandle(name, o, QStringLiteral("number"));
- }
-
-private:
- int addHandle(const QString &name, QJsonObject object, const QString &type, int suppliedRef = -1)
- {
- Q_ASSERT(destination);
-
- object[QLatin1String("type")] = type;
-
- QJsonDocument tmp;
- tmp.setObject(object);
- QByteArray key = tmp.toJson(QJsonDocument::Compact);
-
- int ref;
- if (suppliedRef == -1) {
- ref = refCache.value(key, -1);
- if (ref == -1) {
- ref = newRefId();
- object[QLatin1String("handle")] = ref;
- insertRef(object, ref);
- refCache.insert(key, ref);
- }
- } else {
- ref = suppliedRef;
- object[QLatin1String("handle")] = ref;
- insertRef(object, ref);
- refCache.insert(key, ref);
- }
-
- addNameRefPair(name, ref);
- return ref;
- }
-
- void addNameRefPair(const QString &name, int ref)
- {
- QJsonObject nameValuePair;
- nameValuePair[QLatin1String("name")] = name;
- if (isProperty()) {
- nameValuePair[QLatin1String("ref")] = ref;
- } else {
- QJsonObject refObj;
- refObj[QLatin1String("ref")] = ref;
- nameValuePair[QLatin1String("value")] = refObj;
- }
- destination->append(nameValuePair);
- usedRefs.insert(ref);
- }
-
- int newRefId()
- {
- int ref = refs.count();
- refs.insert(ref, QJsonValue());
- return ref;
- }
-
- void insertRef(const QJsonValue &value, int refId)
- {
- if (refId < 0)
- refId = -refId;
-
- refs.insert(refId, value);
- refsToInclude.append(value);
- }
-
- void cacheObjectRef(QV4::Value obj, int ref)
- {
- objectRefs.insert(obj.val, ref);
- }
-
- int cachedObjectRef(QV4::Value obj) const
- {
- return objectRefs.value(obj.val, -1);
- }
-
-private:
- QJsonArray refsToInclude;
- QHash<int, QJsonValue> refs;
- QHash<QByteArray, int> refCache;
- QJsonArray *destination;
- QSet<int> usedRefs;
- QHash<int, QSet<int> > refsByHandle;
- QHash<quint64, int> objectRefs;
-};
-
-class QV4DebugServicePrivate : public QQmlConfigurableDebugServicePrivate
-{
- Q_DECLARE_PUBLIC(QV4DebugService)
-
-public:
- QV4DebugServicePrivate();
- ~QV4DebugServicePrivate() { qDeleteAll(handlers.values()); }
-
- static QByteArray packMessage(const QByteArray &command, const QByteArray &message = QByteArray())
- {
- QByteArray reply;
- QQmlDebugStream rs(&reply, QIODevice::WriteOnly);
- static const QByteArray cmd("V8DEBUG");
- rs << cmd << command << message;
- return reply;
- }
-
- void send(QJsonObject v8Payload)
- {
- v8Payload[QLatin1String("seq")] = sequence++;
- QJsonDocument doc;
- doc.setObject(v8Payload);
-#ifdef NO_PROTOCOL_TRACING
- QByteArray responseData = doc.toJson(QJsonDocument::Compact);
-#else
- QByteArray responseData = doc.toJson(QJsonDocument::Indented);
-#endif
-
- TRACE_PROTOCOL(qDebug() << "sending response for:" << responseData << endl);
-
- q_func()->sendMessage(packMessage("v8message", responseData));
- }
-
- void processCommand(const QByteArray &command, const QByteArray &data);
-
- QV4DebuggerAgent debuggerAgent;
-
- QStringList breakOnSignals;
- QMap<int, QV4::Debugging::Debugger *> debuggerMap;
- static int debuggerIndex;
- static int sequence;
- const int version;
-
- V8CommandHandler *v8CommandHandler(const QString &command) const;
-
- void clearHandles(QV4::ExecutionEngine *engine)
- {
- theCollector.reset(new VariableCollector(engine));
- }
-
- QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
- QV4::Debugging::Debugger *debugger)
- {
- QJsonObject frame;
- frame[QLatin1String("index")] = frameNr;
- frame[QLatin1String("debuggerFrame")] = false;
- frame[QLatin1String("func")] = theCollector->addFunctionRef(stackFrame.function);
- frame[QLatin1String("script")] = theCollector->addScriptRef(stackFrame.source);
- frame[QLatin1String("line")] = stackFrame.line - 1;
- if (stackFrame.column >= 0)
- frame[QLatin1String("column")] = stackFrame.column;
-
- QJsonArray properties;
- theCollector->setDestination(&properties);
- if (debugger->collectThisInContext(theCollector.data(), frameNr)) {
- QJsonObject obj;
- obj[QLatin1String("properties")] = properties;
- frame[QLatin1String("receiver")] = theCollector->addObjectRef(obj, false);
- }
-
- QJsonArray scopes;
- // Only type and index are used by Qt Creator, so we keep it easy:
- QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr);
- for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) {
- int type = encodeScopeType(scopeTypes[i]);
- if (type == -1)
- continue;
-
- QJsonObject scope;
- scope[QLatin1String("index")] = i;
- scope[QLatin1String("type")] = type;
- scopes.push_back(scope);
- }
- frame[QLatin1String("scopes")] = scopes;
-
- return frame;
- }
-
- int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType)
- {
- switch (scopeType) {
- case QV4::Heap::ExecutionContext::Type_GlobalContext:
- return 0;
- break;
- case QV4::Heap::ExecutionContext::Type_CatchContext:
- return 4;
- break;
- case QV4::Heap::ExecutionContext::Type_WithContext:
- return 2;
- break;
- case QV4::Heap::ExecutionContext::Type_SimpleCallContext:
- case QV4::Heap::ExecutionContext::Type_CallContext:
- return 1;
- break;
- case QV4::Heap::ExecutionContext::Type_QmlContext:
- default:
- return -1;
- }
- }
-
- QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::Debugger *debugger)
- {
- QJsonObject scope;
-
- QJsonArray properties;
- theCollector->collectScope(&properties, debugger, frameNr, scopeNr);
-
- QJsonObject anonymous;
- anonymous[QLatin1String("properties")] = properties;
-
- QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr);
- scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
- scope[QLatin1String("index")] = scopeNr;
- scope[QLatin1String("frameIndex")] = frameNr;
- scope[QLatin1String("object")] = theCollector->addObjectRef(anonymous, true);
-
- return scope;
- }
-
- QJsonValue lookup(int refId) const { return theCollector->lookup(refId); }
-
- QJsonArray buildRefs()
- {
- return theCollector->retrieveRefsToInclude();
- }
-
- VariableCollector *collector() const
- {
- return theCollector.data();
- }
-
- void selectFrame(int frameNr)
- { theSelectedFrame = frameNr; }
-
- int selectedFrame() const
- { return theSelectedFrame; }
-
-private:
- QScopedPointer<VariableCollector> theCollector;
- int theSelectedFrame;
-
- void addHandler(V8CommandHandler* handler);
- QHash<QString, V8CommandHandler*> handlers;
- QScopedPointer<UnknownV8CommandHandler> unknownV8CommandHandler;
-};
-
-int QV4DebugServicePrivate::debuggerIndex = 0;
-int QV4DebugServicePrivate::sequence = 0;
-
-class V8CommandHandler
-{
-public:
- V8CommandHandler(const QString &command)
- : cmd(command)
- {}
-
- virtual ~V8CommandHandler()
- {}
-
- QString command() const { return cmd; }
-
- void handle(const QJsonObject &request, QQmlDebugService *s, QV4DebugServicePrivate *p)
- {
- TRACE_PROTOCOL(qDebug() << "handling command" << command() << "...");
-
- req = request;
- seq = req.value(QStringLiteral("seq"));
- debugService = s;
- debugServicePrivate = p;
-
- handleRequest();
- if (!response.isEmpty()) {
- response[QLatin1String("type")] = QStringLiteral("response");
- debugServicePrivate->send(response);
- }
-
- debugServicePrivate = 0;
- debugService = 0;
- seq = QJsonValue();
- req = QJsonObject();
- response = QJsonObject();
- }
-
- virtual void handleRequest() = 0;
-
-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)
- {
- response.insert(QStringLiteral("body"), body);
- }
-
- void addRunning()
- {
- response.insert(QStringLiteral("running"), debugServicePrivate->debuggerAgent.isRunning());
- }
-
- void addRefs()
- {
- response.insert(QStringLiteral("refs"), debugServicePrivate->buildRefs());
- }
-
- void createErrorResponse(const QString &msg)
- {
- QJsonValue command = req.value(QStringLiteral("command"));
- response.insert(QStringLiteral("command"), command);
- addRequestSequence();
- addSuccess(false);
- addRunning();
- response.insert(QStringLiteral("message"), msg);
- }
-
- int requestSequenceNr() const
- { return seq.toInt(-1); }
-
-protected:
- QString cmd;
- QJsonObject req;
- QJsonValue seq;
- QQmlDebugService *debugService;
- QV4DebugServicePrivate *debugServicePrivate;
- QJsonObject response;
-};
-
-class UnknownV8CommandHandler: public V8CommandHandler
-{
-public:
- UnknownV8CommandHandler(): V8CommandHandler(QString()) {}
-
- virtual void handleRequest()
- {
- QString msg = QStringLiteral("unimplemented command \"");
- msg += req.value(QStringLiteral("command")).toString();
- msg += QStringLiteral("\"");
- createErrorResponse(msg);
- }
-};
-
-namespace {
-class V8VersionRequest: public V8CommandHandler
-{
-public:
- V8VersionRequest(): V8CommandHandler(QStringLiteral("version")) {}
-
- virtual void handleRequest()
- {
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- QJsonObject body;
- body.insert(QStringLiteral("V8Version"),
- QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR));
- addBody(body);
- }
-};
-
-class V8SetBreakPointRequest: public V8CommandHandler
-{
-public:
- V8SetBreakPointRequest(): V8CommandHandler(QStringLiteral("setbreakpoint")) {}
-
- virtual void handleRequest()
- {
- // decypher the payload:
- QJsonObject args = req.value(QStringLiteral("arguments")).toObject();
- if (args.isEmpty())
- return;
-
- QString type = args.value(QStringLiteral("type")).toString();
- if (type != QStringLiteral("scriptRegExp")) {
- createErrorResponse(QStringLiteral("breakpoint type \"%1\" is not implemented").arg(type));
- return;
- }
-
- QString fileName = args.value(QStringLiteral("target")).toString();
- if (fileName.isEmpty()) {
- createErrorResponse(QStringLiteral("breakpoint has no file name"));
- return;
- }
-
- int line = args.value(QStringLiteral("line")).toInt(-1);
- if (line < 0) {
- createErrorResponse(QStringLiteral("breakpoint has an invalid line number"));
- return;
- }
-
- bool enabled = args.value(QStringLiteral("enabled")).toBool(true);
- QString condition = args.value(QStringLiteral("condition")).toString();
-
- // set the break point:
- int id = debugServicePrivate->debuggerAgent.addBreakPoint(fileName, line + 1, enabled, condition);
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- QJsonObject body;
- body.insert(QStringLiteral("type"), type);
- body.insert(QStringLiteral("breakpoint"), id);
- // It's undocumented, but V8 sends back an actual_locations array too. However, our
- // Debugger currently doesn't tell us when it resolved a breakpoint, so we'll leave them
- // pending until the breakpoint is hit for the first time.
- addBody(body);
- }
-};
-
-class V8ClearBreakPointRequest: public V8CommandHandler
-{
-public:
- V8ClearBreakPointRequest(): V8CommandHandler(QStringLiteral("clearbreakpoint")) {}
-
- virtual void handleRequest()
- {
- // decypher the payload:
- QJsonObject args = req.value(QStringLiteral("arguments")).toObject();
- if (args.isEmpty())
- return;
-
- int id = args.value(QStringLiteral("breakpoint")).toInt(-1);
- if (id < 0) {
- createErrorResponse(QStringLiteral("breakpoint has an invalid number"));
- return;
- }
-
- // remove the break point:
- debugServicePrivate->debuggerAgent.removeBreakPoint(id);
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- QJsonObject body;
- body.insert(QStringLiteral("type"), QStringLiteral("scriptRegExp"));
- body.insert(QStringLiteral("breakpoint"), id);
- addBody(body);
- }
-};
-
-class V8BacktraceRequest: public V8CommandHandler
-{
-public:
- V8BacktraceRequest(): V8CommandHandler(QStringLiteral("backtrace")) {}
-
- virtual void handleRequest()
- {
- // decypher the payload:
-
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- int fromFrame = arguments.value(QStringLiteral("fromFrame")).toInt(0);
- int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10);
- // no idea what the bottom property is for, so we'll ignore it.
-
- QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
-
- QJsonArray frameArray;
- QVector<QV4::StackFrame> frames = debugger->stackTrace(toFrame);
- for (int i = fromFrame; i < toFrame && i < frames.size(); ++i)
- frameArray.push_back(debugServicePrivate->buildFrame(frames[i], i, debugger));
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- QJsonObject body;
- if (frameArray.isEmpty()) {
- body.insert(QStringLiteral("totalFrames"), 0);
- } else {
- body.insert(QStringLiteral("fromFrame"), fromFrame);
- body.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size());
- body.insert(QStringLiteral("frames"), frameArray);
- }
- addBody(body);
- addRefs();
- }
-};
-
-class V8FrameRequest: public V8CommandHandler
-{
-public:
- V8FrameRequest(): V8CommandHandler(QStringLiteral("frame")) {}
-
- virtual void handleRequest()
- {
- // decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- const int frameNr = arguments.value(QStringLiteral("number")).toInt(debugServicePrivate->selectedFrame());
-
- QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
- QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
- if (frameNr < 0 || frameNr >= frames.size()) {
- createErrorResponse(QStringLiteral("frame command has invalid frame number"));
- return;
- }
-
- debugServicePrivate->selectFrame(frameNr);
- QJsonObject frame = debugServicePrivate->buildFrame(frames[frameNr], frameNr, debugger);
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- addBody(frame);
- addRefs();
- }
-};
-
-class V8ScopeRequest: public V8CommandHandler
-{
-public:
- V8ScopeRequest(): V8CommandHandler(QStringLiteral("scope")) {}
-
- virtual void handleRequest()
- {
- // decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- const int frameNr = arguments.value(QStringLiteral("frameNumber")).toInt(debugServicePrivate->selectedFrame());
- const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0);
-
- QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
- QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
- if (frameNr < 0 || frameNr >= frames.size()) {
- createErrorResponse(QStringLiteral("scope command has invalid frame number"));
- return;
- }
- if (scopeNr < 0) {
- createErrorResponse(QStringLiteral("scope command has invalid scope number"));
- return;
- }
-
- QJsonObject scope = debugServicePrivate->buildScope(frameNr, scopeNr, debugger);
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- addBody(scope);
- addRefs();
- }
-};
-
-class V8LookupRequest: public V8CommandHandler
-{
-public:
- V8LookupRequest(): V8CommandHandler(QStringLiteral("lookup")) {}
-
- virtual void handleRequest()
- {
- // decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray();
-
- QJsonObject body;
- foreach (QJsonValue handle, handles)
- body[QString::number(handle.toInt())] = debugServicePrivate->lookup(handle.toInt());
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- addBody(body);
- addRefs();
- }
-};
-
-class V8ContinueRequest: public V8CommandHandler
-{
-public:
- V8ContinueRequest(): V8CommandHandler(QStringLiteral("continue")) {}
-
- virtual void handleRequest()
- {
- // decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
-
- QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
-
- if (arguments.empty()) {
- debugger->resume(QV4::Debugging::Debugger::FullThrottle);
- } else {
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QString stepAction = arguments.value(QStringLiteral("stepaction")).toString();
- const int stepcount = arguments.value(QStringLiteral("stepcount")).toInt(1);
- if (stepcount != 1)
- qWarning() << "Step count other than 1 is not supported.";
-
- if (stepAction == QStringLiteral("in")) {
- debugger->resume(QV4::Debugging::Debugger::StepIn);
- } else if (stepAction == QStringLiteral("out")) {
- debugger->resume(QV4::Debugging::Debugger::StepOut);
- } else if (stepAction == QStringLiteral("next")) {
- debugger->resume(QV4::Debugging::Debugger::StepOver);
- } else {
- createErrorResponse(QStringLiteral("continue command has invalid stepaction"));
- return;
- }
- }
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- }
-};
-
-class V8DisconnectRequest: public V8CommandHandler
-{
-public:
- V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {}
-
- virtual void handleRequest()
- {
- debugServicePrivate->debuggerAgent.removeAllBreakPoints();
- debugServicePrivate->debuggerAgent.resumeAll();
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- }
-};
-
-class V8SetExceptionBreakRequest: public V8CommandHandler
-{
-public:
- V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {}
-
- virtual void handleRequest()
- {
- bool wasEnabled = debugServicePrivate->debuggerAgent.breakOnThrow();
-
- //decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QString type = arguments.value(QStringLiteral("type")).toString();
- bool enabled = arguments.value(QStringLiteral("number")).toBool(!wasEnabled);
-
- if (type == QStringLiteral("all")) {
- // that's fine
- } else if (type == QStringLiteral("uncaught")) {
- createErrorResponse(QStringLiteral("breaking only on uncaught exceptions is not supported yet"));
- return;
- } else {
- createErrorResponse(QStringLiteral("invalid type for break on exception"));
- return;
- }
-
- // do it:
- debugServicePrivate->debuggerAgent.setBreakOnThrow(enabled);
-
- QJsonObject body;
- body[QLatin1String("type")] = type;
- body[QLatin1String("enabled")] = debugServicePrivate->debuggerAgent.breakOnThrow();
-
- // response:
- addBody(body);
- addRunning();
- addSuccess(true);
- addRequestSequence();
- addCommand();
- }
-};
-
-class V8ScriptsRequest: public V8CommandHandler
-{
-public:
- V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {}
-
- virtual void handleRequest()
- {
- //decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- int types = arguments.value(QStringLiteral("types")).toInt(-1);
- if (types < 0 || types > 7) {
- createErrorResponse(QStringLiteral("invalid types value in scripts command"));
- return;
- } else if (types != 4) {
- createErrorResponse(QStringLiteral("unsupported types value in scripts command"));
- return;
- }
-
- // do it:
- debugServicePrivate->debuggerAgent.firstDebugger()->gatherSources(requestSequenceNr());
-
- // response will be send by
- }
-};
-
-// Request:
-// {
-// "seq": 4,
-// "type": "request",
-// "command": "evaluate",
-// "arguments": {
-// "expression": "a",
-// "frame": 0
-// }
-// }
-//
-// Response:
-// {
-// "body": {
-// "handle": 3,
-// "type": "number",
-// "value": 1
-// },
-// "command": "evaluate",
-// "refs": [],
-// "request_seq": 4,
-// "running": false,
-// "seq": 5,
-// "success": true,
-// "type": "response"
-// }
-//
-// The "value" key in "body" is the result of evaluating the expression in the request.
-class V8EvaluateRequest: public V8CommandHandler
-{
-public:
- V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {}
-
- virtual void handleRequest()
- {
- //decypher the payload:
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QString expression = arguments.value(QStringLiteral("expression")).toString();
- const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
-
- QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
- Q_ASSERT(debugger->state() == QV4::Debugging::Debugger::Paused);
-
- VariableCollector *collector = debugServicePrivate->collector();
- QJsonArray dest;
- collector->setDestination(&dest);
- debugger->evaluateExpression(frame, expression, collector);
-
- const int ref = dest.at(0).toObject().value(QStringLiteral("value")).toObject()
- .value(QStringLiteral("ref")).toInt();
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- addBody(collector->lookup(ref).toObject());
- addRefs();
- }
-};
-} // anonymous namespace
-
-QV4DebugServicePrivate::QV4DebugServicePrivate()
- : debuggerAgent(this)
- , version(1)
- , theSelectedFrame(0)
- , unknownV8CommandHandler(new UnknownV8CommandHandler)
-{
- addHandler(new V8VersionRequest);
- addHandler(new V8SetBreakPointRequest);
- addHandler(new V8ClearBreakPointRequest);
- addHandler(new V8BacktraceRequest);
- addHandler(new V8FrameRequest);
- addHandler(new V8ScopeRequest);
- addHandler(new V8LookupRequest);
- addHandler(new V8ContinueRequest);
- addHandler(new V8DisconnectRequest);
- addHandler(new V8SetExceptionBreakRequest);
- addHandler(new V8ScriptsRequest);
- addHandler(new V8EvaluateRequest);
-}
-
-void QV4DebugServicePrivate::addHandler(V8CommandHandler* handler)
-{
- handlers[handler->command()] = handler;
-}
-
-V8CommandHandler *QV4DebugServicePrivate::v8CommandHandler(const QString &command) const
-{
- V8CommandHandler *handler = handlers.value(command, 0);
- if (handler)
- return handler;
- else
- return unknownV8CommandHandler.data();
-}
-
-QV4DebugService::QV4DebugService(QObject *parent)
- : QQmlConfigurableDebugService(*(new QV4DebugServicePrivate()),
- QStringLiteral("V8Debugger"), 1, parent)
-{}
-
-QV4DebugService::~QV4DebugService()
-{
-}
-
-QV4DebugService *QV4DebugService::instance()
-{
- return v4ServiceInstance();
-}
-
-void QV4DebugService::engineAboutToBeAdded(QQmlEngine *engine)
-{
- Q_D(QV4DebugService);
- QMutexLocker lock(configMutex());
- if (engine) {
- QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
- if (QQmlDebugServer *server = QQmlDebugServer::instance()) {
- if (ee) {
- ee->enableDebugger();
- QV4::Debugging::Debugger *debugger = ee->debugger;
- d->debuggerMap.insert(d->debuggerIndex++, debugger);
- d->debuggerAgent.addDebugger(debugger);
- d->debuggerAgent.moveToThread(server->thread());
- moveToThread(server->thread());
- }
- }
- }
- QQmlConfigurableDebugService::engineAboutToBeAdded(engine);
-}
-
-void QV4DebugService::engineAboutToBeRemoved(QQmlEngine *engine)
-{
- Q_D(QV4DebugService);
- QMutexLocker lock(configMutex());
- if (engine){
- const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
- if (ee) {
- QV4::Debugging::Debugger *debugger = ee->debugger;
- typedef QMap<int, QV4::Debugging::Debugger *>::const_iterator DebuggerMapIterator;
- const DebuggerMapIterator end = d->debuggerMap.constEnd();
- for (DebuggerMapIterator i = d->debuggerMap.constBegin(); i != end; ++i) {
- if (i.value() == debugger) {
- d->debuggerMap.remove(i.key());
- break;
- }
- }
- d->debuggerAgent.removeDebugger(debugger);
- }
- }
- QQmlConfigurableDebugService::engineAboutToBeRemoved(engine);
-}
-
-void QV4DebugService::signalEmitted(const QString &signal)
-{
- //This function is only called by QQmlBoundSignal
- //only if there is a slot connected to the signal. Hence, there
- //is no need for additional check.
- Q_D(QV4DebugService);
-
- //Parse just the name and remove the class info
- //Normalize to Lower case.
- QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower();
-
- foreach (const QString &signal, d->breakOnSignals) {
- if (signal == signalName) {
- // TODO: pause debugger
- break;
- }
- }
-}
-
-void QV4DebugService::messageReceived(const QByteArray &message)
-{
- Q_D(QV4DebugService);
- QMutexLocker lock(configMutex());
-
- QQmlDebugStream ms(message);
- QByteArray header;
- ms >> header;
-
- TRACE_PROTOCOL(qDebug() << "received message with header" << header);
-
- if (header == "V8DEBUG") {
- QByteArray type;
- QByteArray payload;
- ms >> type >> payload;
- TRACE_PROTOCOL(qDebug() << "... type:" << type);
-
- if (type == V4_CONNECT) {
- sendMessage(d->packMessage(type));
- stopWaiting();
- } else if (type == V4_PAUSE) {
- d->debuggerAgent.pauseAll();
- sendSomethingToSomebody(type);
- } else if (type == V4_BREAK_ON_SIGNAL) {
- QByteArray signal;
- bool enabled;
- ms >> signal >> enabled;
- //Normalize to lower case.
- QString signalName(QString::fromUtf8(signal).toLower());
- if (enabled)
- d->breakOnSignals.append(signalName);
- else
- d->breakOnSignals.removeOne(signalName);
- } else if (type == "v8request") {
- handleV8Request(payload);
- } else if (type == V4_DISCONNECT) {
- TRACE_PROTOCOL(qDebug() << "... payload:" << payload);
- handleV8Request(payload);
- } else {
- sendSomethingToSomebody(type, 0);
- }
- }
-}
-
-void QV4DebugService::sendSomethingToSomebody(const char *type, int magicNumber)
-{
- Q_D(QV4DebugService);
-
- QByteArray response;
- QQmlDebugStream rs(&response, QIODevice::WriteOnly);
- rs << QByteArray(type)
- << QByteArray::number(d->version) << QByteArray::number(magicNumber);
- sendMessage(d->packMessage(type, response));
-}
-
-void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason)
-{
- Q_UNUSED(reason);
-
- debugServicePrivate->clearHandles(debugger->engine());
-
- QJsonObject event, body, script;
- event.insert(QStringLiteral("type"), QStringLiteral("event"));
-
- switch (reason) {
- case QV4::Debugging::Step:
- case QV4::Debugging::PauseRequest:
- case QV4::Debugging::BreakPoint: {
- event.insert(QStringLiteral("event"), QStringLiteral("break"));
- QVector<QV4::StackFrame> frames = debugger->stackTrace(1);
- if (frames.isEmpty())
- break;
-
- const QV4::StackFrame &topFrame = frames.first();
- body.insert(QStringLiteral("invocationText"), topFrame.function);
- body.insert(QStringLiteral("sourceLine"), topFrame.line - 1);
- if (topFrame.column > 0)
- body.insert(QStringLiteral("sourceColumn"), topFrame.column);
- QJsonArray breakPoints;
- foreach (int breakPointId, breakPointIds(topFrame.source, topFrame.line))
- breakPoints.push_back(breakPointId);
- body.insert(QStringLiteral("breakpoints"), breakPoints);
- script.insert(QStringLiteral("name"), topFrame.source);
- } break;
- case QV4::Debugging::Throwing:
- // TODO: complete this!
- event.insert(QStringLiteral("event"), QStringLiteral("exception"));
- break;
- }
-
- if (!script.isEmpty())
- body.insert(QStringLiteral("script"), script);
- if (!body.isEmpty())
- event.insert(QStringLiteral("body"), body);
- debugServicePrivate->send(event);
-}
-
-void QV4DebuggerAgent::sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, int requestSequenceNr)
-{
- QJsonArray body;
- foreach (const QString source, sources) {
- QJsonObject src;
- src[QLatin1String("name")] = source;
- src[QLatin1String("scriptType")] = 4;
- body.append(src);
- }
-
- QJsonObject response;
- response[QLatin1String("success")] = true;
- response[QLatin1String("running")] = debugger->state() == QV4::Debugging::Debugger::Running;
- response[QLatin1String("body")] = body;
- response[QLatin1String("command")] = QStringLiteral("scripts");
- response[QLatin1String("request_seq")] = requestSequenceNr;
- response[QLatin1String("type")] = QStringLiteral("response");
- debugServicePrivate->send(response);
-}
-
-void QV4DebugService::handleV8Request(const QByteArray &payload)
-{
- Q_D(QV4DebugService);
-
- TRACE_PROTOCOL(qDebug() << "v8request, payload:" << payload);
-
- QJsonDocument request = QJsonDocument::fromJson(payload);
- QJsonObject o = request.object();
- QJsonValue type = o.value(QStringLiteral("type"));
- if (type.toString() == QStringLiteral("request")) {
- QJsonValue command = o.value(QStringLiteral("command"));
- V8CommandHandler *h = d->v8CommandHandler(command.toString());
- if (h)
- h->handle(o, this, d);
- }
-}
-
-QT_END_NAMESPACE