Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4debugservice.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
6#include "qv4debugjob.h"
7#include "qqmlengine.h"
8
9#include <private/qv4engine_p.h>
10#include <private/qv4function_p.h>
11#include <private/qqmldebugconnector_p.h>
12#include <private/qversionedpacket_p.h>
13
14#include <QtCore/QJsonArray>
15#include <QtCore/QJsonDocument>
16#include <QtCore/QJsonObject>
17#include <QtCore/QJsonValue>
18
19const char *const V4_CONNECT = "connect";
20const char *const V4_DISCONNECT = "disconnect";
21const char *const V4_BREAK_ON_SIGNAL = "breakonsignal";
22const char *const V4_PAUSE = "interrupt";
23
24#define NO_PROTOCOL_TRACING
26# define TRACE_PROTOCOL(x)
27#else
28#include <QtCore/QDebug>
29# define TRACE_PROTOCOL(x) x
30#endif
31
32QT_BEGIN_NAMESPACE
33
34class V4CommandHandler;
36
37using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>;
38
39int QV4DebugServiceImpl::sequence = 0;
40
42{
43public:
44 V4CommandHandler(const QString &command)
45 : cmd(command)
46 {}
47
49 {}
50
51 QString command() const { return cmd; }
52
53 void handle(const QJsonObject &request, QV4DebugServiceImpl *s)
54 {
55 TRACE_PROTOCOL(qDebug() << "handling command" << command() << "...");
56
57 req = request;
58 seq = req.value(QLatin1String("seq"));
59 debugService = s;
60
62 if (!response.isEmpty()) {
63 response[QLatin1String("type")] = QStringLiteral("response");
64 debugService->send(response);
65 }
66
67 debugService = nullptr;
68 seq = QJsonValue();
69 req = QJsonObject();
70 response = QJsonObject();
71 }
72
73 virtual void handleRequest() = 0;
74
75protected:
76 void addCommand() { response.insert(QStringLiteral("command"), cmd); }
77 void addRequestSequence() { response.insert(QStringLiteral("request_seq"), seq); }
78 void addSuccess(bool success) { response.insert(QStringLiteral("success"), success); }
79 void addBody(const QJsonValue &body)
80 {
81 response.insert(QStringLiteral("body"), body);
82 }
83
85 {
86 response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning());
87 }
88
89 void createErrorResponse(const QString &msg)
90 {
91 QJsonValue command = req.value(QLatin1String("command"));
92 response.insert(QStringLiteral("command"), command);
94 addSuccess(false);
96 response.insert(QStringLiteral("message"), msg);
97 }
98
100 { return seq.toInt(-1); }
101
102protected:
108};
109
111{
112public:
114
115 void handleRequest() override
116 {
117 QString msg = QLatin1String("unimplemented command \"")
118 + req.value(QLatin1String("command")).toString()
119 + QLatin1Char('"');
120 createErrorResponse(msg);
121 }
122};
123
124namespace {
125class V4VersionRequest: public V4CommandHandler
126{
127public:
128 V4VersionRequest(): V4CommandHandler(QStringLiteral("version")) {}
129
130 void handleRequest() override
131 {
132 addCommand();
134 addSuccess(true);
135 addRunning();
136 QJsonObject body;
137 body.insert(QStringLiteral("V8Version"),
138 QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR));
139 body.insert(QStringLiteral("UnpausedEvaluate"), true);
140 body.insert(QStringLiteral("ContextEvaluate"), true);
141 body.insert(QStringLiteral("ChangeBreakpoint"), true);
142 addBody(body);
143 }
144};
145
146class V4BreakPointRequest: public V4CommandHandler
147{
148public:
149 V4BreakPointRequest(const QString &name): V4CommandHandler(name) {}
150
151 void handleRequest() final
152 {
153 // Other types are currently not supported
154 m_type = QStringLiteral("scriptRegExp");
155
156 // decypher the payload:
157 m_args = req.value(QLatin1String("arguments")).toObject();
158 if (m_args.isEmpty()) {
159 createErrorResponse(QStringLiteral("breakpoint request with empty arguments object"));
160 return;
161 }
162
163 const int id = handleBreakPointRequest();
164 if (id < 0) {
165 createErrorResponse(m_error);
166 } else {
167 // response:
168 addCommand();
170 addSuccess(true);
171 addRunning();
172 QJsonObject body;
173 body.insert(QStringLiteral("type"), m_type);
174 body.insert(QStringLiteral("breakpoint"), id);
175 addBody(body);
176 }
177 }
178
179protected:
180 virtual int handleBreakPointRequest() = 0;
181
182 QJsonObject m_args;
183 QString m_type;
184 QString m_error;
185};
186
187class V4SetBreakPointRequest: public V4BreakPointRequest
188{
189public:
190 V4SetBreakPointRequest(): V4BreakPointRequest(QStringLiteral("setbreakpoint")) {}
191
192 int handleBreakPointRequest() final
193 {
194 // decypher the payload:
195 const QString type = m_args.value(QLatin1String("type")).toString();
196 if (type != QLatin1String("scriptRegExp")) {
197 m_error = QStringLiteral("breakpoint type \"%1\" is not implemented").arg(type);
198 return -1;
199 }
200
201 const QString fileName = m_args.value(QLatin1String("target")).toString();
202 if (fileName.isEmpty()) {
203 m_error = QStringLiteral("breakpoint has no file name");
204 return -1;
205 }
206
207
208 const int line = m_args.value(QLatin1String("line")).toInt(-1);
209 if (line < 0) {
210 m_error = QStringLiteral("breakpoint has an invalid line number");
211 return -1;
212 }
213
214 const bool enabled = m_args.value(QStringLiteral("enabled")).toBool(true);
215 const QString condition = m_args.value(QStringLiteral("condition")).toString();
216
217 // set the break point:
218 return debugService->debuggerAgent.addBreakPoint(fileName, line + 1, enabled, condition);
219
220 // It's undocumented, but V8 sends back an actual_locations array too. However, our
221 // Debugger currently doesn't tell us when it resolved a breakpoint, so we'll leave them
222 // pending until the breakpoint is hit for the first time.
223 }
224};
225
226class V4ClearBreakPointRequest: public V4BreakPointRequest
227{
228public:
229 V4ClearBreakPointRequest(): V4BreakPointRequest(QStringLiteral("clearbreakpoint")) {}
230
231 int handleBreakPointRequest() final
232 {
233 const int id = m_args.value(QLatin1String("breakpoint")).toInt(-1);
234 if (id < 0)
235 m_error = QStringLiteral("breakpoint has an invalid number");
236 else // remove the break point:
237 debugService->debuggerAgent.removeBreakPoint(id);
238
239 return id;
240 }
241};
242
243class V4ChangeBreakPointRequest: public V4BreakPointRequest
244{
245public:
246 V4ChangeBreakPointRequest(): V4BreakPointRequest(QStringLiteral("changebreakpoint")) {}
247
248 int handleBreakPointRequest() final
249 {
250 const int id = m_args.value(QLatin1String("breakpoint")).toInt(-1);
251 if (id < 0) {
252 m_error = QStringLiteral("breakpoint has an invalid number");
253 return id;
254 }
255
256 const QJsonValue enabled = m_args.value(QLatin1String("enabled"));
257 if (!enabled.isBool()) {
258 m_error = QStringLiteral("missing bool \"enabled\" in breakpoint change request");
259 return -1;
260 }
261
262 // enable or disable the break point:
263 debugService->debuggerAgent.enableBreakPoint(id, enabled.toBool());
264 return id;
265 }
266};
267
268class V4BacktraceRequest: public V4CommandHandler
269{
270public:
271 V4BacktraceRequest(): V4CommandHandler(QStringLiteral("backtrace")) {}
272
273 void handleRequest() override
274 {
275 // decypher the payload:
276
277 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
278 int fromFrame = arguments.value(QLatin1String("fromFrame")).toInt(0);
279 int toFrame = arguments.value(QLatin1String("toFrame")).toInt(fromFrame + 10);
280 // no idea what the bottom property is for, so we'll ignore it.
281
282 QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
283 if (!debugger) {
284 createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve backtraces."));
285 return;
286 }
287
288 BacktraceJob job(debugger->collector(), fromFrame, toFrame);
289 debugger->runInEngine(&job);
290
291 // response:
292 addCommand();
294 addSuccess(true);
295 addRunning();
296 addBody(job.returnValue());
297 }
298};
299
300class V4FrameRequest: public V4CommandHandler
301{
302public:
303 V4FrameRequest(): V4CommandHandler(QStringLiteral("frame")) {}
304
305 void handleRequest() override
306 {
307 // decypher the payload:
308 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
309 const int frameNr = arguments.value(QLatin1String("number")).toInt(
311
312 QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
313 if (!debugger) {
314 createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve frames."));
315 return;
316 }
317
318 if (frameNr < 0) {
319 createErrorResponse(QStringLiteral("frame command has invalid frame number"));
320 return;
321 }
322
323 FrameJob job(debugger->collector(), frameNr);
324 debugger->runInEngine(&job);
325 if (!job.wasSuccessful()) {
326 createErrorResponse(QStringLiteral("frame retrieval failed"));
327 return;
328 }
329
331
332 // response:
333 addCommand();
335 addSuccess(true);
336 addRunning();
337 addBody(job.returnValue());
338 }
339};
340
341class V4ScopeRequest: public V4CommandHandler
342{
343public:
344 V4ScopeRequest(): V4CommandHandler(QStringLiteral("scope")) {}
345
346 void handleRequest() override
347 {
348 // decypher the payload:
349 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
350 const int frameNr = arguments.value(QLatin1String("frameNumber")).toInt(
352 const int scopeNr = arguments.value(QLatin1String("number")).toInt(0);
353
354 QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
355 if (!debugger) {
356 createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve scope."));
357 return;
358 }
359
360 if (frameNr < 0) {
361 createErrorResponse(QStringLiteral("scope command has invalid frame number"));
362 return;
363 }
364 if (scopeNr < 0) {
365 createErrorResponse(QStringLiteral("scope command has invalid scope number"));
366 return;
367 }
368
369 ScopeJob job(debugger->collector(), frameNr, scopeNr);
370 debugger->runInEngine(&job);
371 if (!job.wasSuccessful()) {
372 createErrorResponse(QStringLiteral("scope retrieval failed"));
373 return;
374 }
375
376 // response:
377 addCommand();
379 addSuccess(true);
380 addRunning();
381 addBody(job.returnValue());
382 }
383};
384
385class V4LookupRequest: public V4CommandHandler
386{
387public:
388 V4LookupRequest(): V4CommandHandler(QStringLiteral("lookup")) {}
389
390 void handleRequest() override
391 {
392 // decypher the payload:
393 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
394 QJsonArray handles = arguments.value(QLatin1String("handles")).toArray();
395
396 QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
397 if (!debugger) {
398 const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers();
399 if (debuggers.size() > 1) {
400 createErrorResponse(QStringLiteral("Cannot lookup values if multiple debuggers are running and none is paused"));
401 return;
402 } else if (debuggers.size() == 0) {
403 createErrorResponse(QStringLiteral("No debuggers available to lookup values"));
404 return;
405 }
406 debugger = debuggers.first();
407 }
408
409 ValueLookupJob job(handles, debugger->collector());
410 debugger->runInEngine(&job);
411 if (!job.exceptionMessage().isEmpty()) {
412 createErrorResponse(job.exceptionMessage());
413 } else {
414 // response:
415 addCommand();
417 addSuccess(true);
418 addRunning();
419 addBody(job.returnValue());
420 }
421 }
422};
423
424class V4ContinueRequest: public V4CommandHandler
425{
426public:
427 V4ContinueRequest(): V4CommandHandler(QStringLiteral("continue")) {}
428
429 void handleRequest() override
430 {
431 // decypher the payload:
432 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
433
434 QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
435 if (!debugger) {
436 createErrorResponse(QStringLiteral("Debugger has to be paused in order to continue."));
437 return;
438 }
439 debugService->debuggerAgent.clearAllPauseRequests();
440
441 if (arguments.empty()) {
443 } else {
444 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
445 QString stepAction = arguments.value(QLatin1String("stepaction")).toString();
446 const int stepcount = arguments.value(QLatin1String("stepcount")).toInt(1);
447 if (stepcount != 1)
448 qWarning() << "Step count other than 1 is not supported.";
449
450 if (stepAction == QLatin1String("in")) {
452 } else if (stepAction == QLatin1String("out")) {
454 } else if (stepAction == QLatin1String("next")) {
456 } else {
457 createErrorResponse(QStringLiteral("continue command has invalid stepaction"));
458 return;
459 }
460 }
461
462 // response:
463 addCommand();
465 addSuccess(true);
466 addRunning();
467 }
468};
469
470class V4DisconnectRequest: public V4CommandHandler
471{
472public:
473 V4DisconnectRequest(): V4CommandHandler(QStringLiteral("disconnect")) {}
474
475 void handleRequest() override
476 {
477 debugService->debuggerAgent.removeAllBreakPoints();
478 debugService->debuggerAgent.resumeAll();
479
480 // response:
481 addCommand();
483 addSuccess(true);
484 addRunning();
485 }
486};
487
488class V4SetExceptionBreakRequest: public V4CommandHandler
489{
490public:
491 V4SetExceptionBreakRequest(): V4CommandHandler(QStringLiteral("setexceptionbreak")) {}
492
493 void handleRequest() override
494 {
495 bool wasEnabled = debugService->debuggerAgent.breakOnThrow();
496
497 //decypher the payload:
498 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
499 QString type = arguments.value(QLatin1String("type")).toString();
500 bool enabled = arguments.value(QLatin1String("number")).toBool(!wasEnabled);
501
502 if (type == QLatin1String("all")) {
503 // that's fine
504 } else if (type == QLatin1String("uncaught")) {
505 createErrorResponse(QStringLiteral("breaking only on uncaught exceptions is not supported yet"));
506 return;
507 } else {
508 createErrorResponse(QStringLiteral("invalid type for break on exception"));
509 return;
510 }
511
512 // do it:
513 debugService->debuggerAgent.setBreakOnThrow(enabled);
514
515 QJsonObject body;
516 body[QLatin1String("type")] = type;
517 body[QLatin1String("enabled")] = debugService->debuggerAgent.breakOnThrow();
518
519 // response:
520 addBody(body);
521 addRunning();
522 addSuccess(true);
524 addCommand();
525 }
526};
527
528class V4ScriptsRequest: public V4CommandHandler
529{
530public:
531 V4ScriptsRequest(): V4CommandHandler(QStringLiteral("scripts")) {}
532
533 void handleRequest() override
534 {
535 //decypher the payload:
536 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
537 int types = arguments.value(QLatin1String("types")).toInt(-1);
538 if (types < 0 || types > 7) {
539 createErrorResponse(QStringLiteral("invalid types value in scripts command"));
540 return;
541 } else if (types != 4) {
542 createErrorResponse(QStringLiteral("unsupported types value in scripts command"));
543 return;
544 }
545
546 // do it:
547 QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
548 if (!debugger) {
549 createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve scripts."));
550 return;
551 }
552
553 GatherSourcesJob job(debugger->engine());
554 debugger->runInEngine(&job);
555
556 QJsonArray body;
557 for (const QString &source : job.result()) {
558 QJsonObject src;
559 src[QLatin1String("name")] = source;
560 src[QLatin1String("scriptType")] = 4;
561 body.append(src);
562 }
563
564 addSuccess(true);
565 addRunning();
566 addBody(body);
567 addCommand();
569 }
570};
571
572// Request:
573// {
574// "seq": 4,
575// "type": "request",
576// "command": "evaluate",
577// "arguments": {
578// "expression": "a",
579// "frame": 0
580// }
581// }
582//
583// Response:
584// {
585// "body": {
586// "handle": 3,
587// "type": "number",
588// "value": 1
589// },
590// "command": "evaluate",
591// "refs": [],
592// "request_seq": 4,
593// "running": false,
594// "seq": 5,
595// "success": true,
596// "type": "response"
597// }
598//
599// The "value" key in "body" is the result of evaluating the expression in the request.
600class V4EvaluateRequest: public V4CommandHandler
601{
602public:
603 V4EvaluateRequest(): V4CommandHandler(QStringLiteral("evaluate")) {}
604
605 void handleRequest() override
606 {
607 QJsonObject arguments = req.value(QLatin1String("arguments")).toObject();
608 QString expression = arguments.value(QLatin1String("expression")).toString();
609 int context = arguments.value(QLatin1String("context")).toInt(-1);
610 int frame = -1;
611
612 QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
613 if (!debugger) {
614 const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers();
615 if (debuggers.size() > 1) {
616 createErrorResponse(QStringLiteral("Cannot evaluate expressions if multiple debuggers are running and none is paused"));
617 return;
618 } else if (debuggers.size() == 0) {
619 createErrorResponse(QStringLiteral("No debuggers available to evaluate expressions"));
620 return;
621 }
622 debugger = debuggers.first();
623 } else {
624 frame = arguments.value(QLatin1String("frame")).toInt(0);
625 }
626
627 ExpressionEvalJob job(debugger->engine(), frame, context, expression,
628 debugger->collector());
629 debugger->runInEngine(&job);
630 if (job.hasExeption()) {
631 createErrorResponse(job.exceptionMessage());
632 } else {
633 addCommand();
635 addSuccess(true);
636 addRunning();
637 addBody(job.returnValue());
638 }
639 }
640};
641} // anonymous namespace
642
643void QV4DebugServiceImpl::addHandler(V4CommandHandler* handler)
644{
645 handlers[handler->command()] = handler;
646}
647
648V4CommandHandler *QV4DebugServiceImpl::v4CommandHandler(const QString &command) const
649{
650 V4CommandHandler *handler = handlers.value(command, 0);
651 if (handler)
652 return handler;
653 else
654 return unknownV4CommandHandler.data();
655}
656
657QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) :
658 QQmlConfigurableDebugService<QV4DebugService>(1, parent),
659 debuggerAgent(this), theSelectedFrame(0),
660 unknownV4CommandHandler(new UnknownV4CommandHandler)
661{
662 addHandler(new V4VersionRequest);
663 addHandler(new V4SetBreakPointRequest);
664 addHandler(new V4ClearBreakPointRequest);
665 addHandler(new V4ChangeBreakPointRequest);
666 addHandler(new V4BacktraceRequest);
667 addHandler(new V4FrameRequest);
668 addHandler(new V4ScopeRequest);
669 addHandler(new V4LookupRequest);
670 addHandler(new V4ContinueRequest);
671 addHandler(new V4DisconnectRequest);
672 addHandler(new V4SetExceptionBreakRequest);
673 addHandler(new V4ScriptsRequest);
674 addHandler(new V4EvaluateRequest);
675}
676
678{
679 qDeleteAll(handlers);
680}
681
682void QV4DebugServiceImpl::engineAdded(QJSEngine *engine)
683{
684 QMutexLocker lock(&m_configMutex);
685 if (engine) {
686 QV4::ExecutionEngine *ee = engine->handle();
687 if (QQmlDebugConnector *server = QQmlDebugConnector::instance()) {
688 if (ee) {
689 QV4Debugger *debugger = new QV4Debugger(ee);
690 if (state() == Enabled)
691 ee->setDebugger(debugger);
692 debuggerAgent.addDebugger(debugger);
693 debuggerAgent.moveToThread(server->thread());
694 }
695 }
696 }
697 QQmlConfigurableDebugService<QV4DebugService>::engineAdded(engine);
698}
699
701{
702 QMutexLocker lock(&m_configMutex);
703 if (engine){
704 const QV4::ExecutionEngine *ee = engine->handle();
705 if (ee) {
706 QV4Debugger *debugger = qobject_cast<QV4Debugger *>(ee->debugger());
707 if (debugger)
708 debuggerAgent.removeDebugger(debugger);
709 }
710 }
711 QQmlConfigurableDebugService<QV4DebugService>::engineAboutToBeRemoved(engine);
712}
713
715{
716 QMutexLocker lock(&m_configMutex);
717 if (state == Enabled) {
718 const auto debuggers = debuggerAgent.debuggers();
719 for (QV4Debugger *debugger : debuggers) {
720 QV4::ExecutionEngine *ee = debugger->engine();
721 if (!ee->debugger())
722 ee->setDebugger(debugger);
723 }
724 }
725 QQmlConfigurableDebugService<QV4DebugService>::stateAboutToBeChanged(state);
726}
727
728void QV4DebugServiceImpl::signalEmitted(const QString &signal)
729{
730 //This function is only called by QQmlBoundSignal
731 //only if there is a slot connected to the signal. Hence, there
732 //is no need for additional check.
733
734 //Parse just the name and remove the class info
735 //Normalize to Lower case.
736 QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower();
737
738 for (const QString &signal : std::as_const(breakOnSignals)) {
739 if (signal == signalName) {
740 // TODO: pause debugger
741 break;
742 }
743 }
744}
745
746void QV4DebugServiceImpl::messageReceived(const QByteArray &message)
747{
748 QMutexLocker lock(&m_configMutex);
749
750 QQmlDebugPacket ms(message);
751 QByteArray header;
752 ms >> header;
753
754 TRACE_PROTOCOL(qDebug() << "received message with header" << header);
755
756 if (header == "V8DEBUG") {
757 QByteArray type;
758 QByteArray payload;
759 ms >> type >> payload;
760 TRACE_PROTOCOL(qDebug() << "... type:" << type);
761
762 if (type == V4_CONNECT) {
763 QJsonObject parameters = QJsonDocument::fromJson(payload).object();
764 Q_UNUSED(parameters); // For future protocol changes
765
766 emit messageToClient(name(), packMessage(type));
767 stopWaiting();
768 } else if (type == V4_PAUSE) {
769 debuggerAgent.pauseAll();
771 } else if (type == V4_BREAK_ON_SIGNAL) {
772 QByteArray signal;
773 bool enabled;
774 ms >> signal >> enabled;
775 //Normalize to lower case.
776 QString signalName(QString::fromUtf8(signal).toLower());
777 if (enabled)
778 breakOnSignals.append(signalName);
779 else
780 breakOnSignals.removeOne(signalName);
781 } else if (type == "v8request") {
782 handleV4Request(payload);
783 } else if (type == V4_DISCONNECT) {
784 TRACE_PROTOCOL(qDebug() << "... payload:" << payload.constData());
785 handleV4Request(payload);
786 } else {
788 }
789 }
790}
791
792void QV4DebugServiceImpl::sendSomethingToSomebody(const char *type, int magicNumber)
793{
794 QQmlDebugPacket rs;
795 rs << QByteArray(type)
796 << QByteArray::number(int(version())) << QByteArray::number(magicNumber);
797 emit messageToClient(name(), packMessage(type, rs.data()));
798}
799
800void QV4DebugServiceImpl::handleV4Request(const QByteArray &payload)
801{
802 TRACE_PROTOCOL(qDebug() << "v8request, payload:" << payload.constData());
803
804 QJsonDocument request = QJsonDocument::fromJson(payload);
805 QJsonObject o = request.object();
806 QJsonValue type = o.value(QLatin1String("type"));
807 if (type.toString() == QLatin1String("request")) {
808 QJsonValue command = o.value(QLatin1String("command"));
809 V4CommandHandler *h = v4CommandHandler(command.toString());
810 if (h)
811 h->handle(o, this);
812 }
813}
814
815QByteArray QV4DebugServiceImpl::packMessage(const QByteArray &command, const QByteArray &message)
816{
817 QQmlDebugPacket rs;
818 static const QByteArray cmd("V8DEBUG");
819 rs << cmd << command << message;
820 return rs.data();
821}
822
823void QV4DebugServiceImpl::send(QJsonObject v4Payload)
824{
825 v4Payload[QLatin1String("seq")] = sequence++;
826 QJsonDocument doc;
827 doc.setObject(v4Payload);
829 QByteArray responseData = doc.toJson(QJsonDocument::Compact);
830#else
831 QByteArray responseData = doc.toJson(QJsonDocument::Indented);
832#endif
833
834 TRACE_PROTOCOL(qDebug() << "sending response for:" << responseData.constData() << endl);
835
836 emit messageToClient(name(), packMessage("v8message", responseData));
837}
838
840{
841 theSelectedFrame = frameNr;
842}
843
845{
846 return theSelectedFrame;
847}
848
849QT_END_NAMESPACE
850
851#include "moc_qv4debugservice.cpp"
BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame)
bool wasSuccessful() const
FrameJob(QV4DataCollector *collector, int frameNr)
bool hasExeption() const
void send(QJsonObject v4Payload)
void engineAboutToBeRemoved(QJSEngine *engine) override
void messageReceived(const QByteArray &) override
void stateAboutToBeChanged(State state) override
void signalEmitted(const QString &signal) override
void sendSomethingToSomebody(const char *type, int magicNumber=1)
void engineAdded(QJSEngine *engine) override
void selectFrame(int frameNr)
void runInEngine(QV4DebugJob *job)
QV4DataCollector * collector()
void resume(Speed speed)
bool wasSuccessful() const
ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr)
virtual ~V4CommandHandler()
QV4DebugServiceImpl * debugService
int requestSequenceNr() const
void addSuccess(bool success)
void createErrorResponse(const QString &msg)
void addBody(const QJsonValue &body)
V4CommandHandler(const QString &command)
virtual void handleRequest()=0
void handle(const QJsonObject &request, QV4DebugServiceImpl *s)
QString command() const
Definition qjsvalue.h:23
const char *const V4_CONNECT
const char *const V4_BREAK_ON_SIGNAL
#define NO_PROTOCOL_TRACING
const char *const V4_PAUSE
#define TRACE_PROTOCOL(x)
const char *const V4_DISCONNECT