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
qv4debugclient.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 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
8
9#include <private/qpacket_p.h>
10
11#include <QJsonDocument>
12#include <QJsonObject>
13#include <QJsonValue>
14#include <QJsonArray>
15
17
18const char *V8REQUEST = "v8request";
19const char *V8MESSAGE = "v8message";
20const char *SEQ = "seq";
21const char *TYPE = "type";
22const char *COMMAND = "command";
23const char *ARGUMENTS = "arguments";
24const char *STEPACTION = "stepaction";
25const char *STEPCOUNT = "stepcount";
26const char *EXPRESSION = "expression";
27const char *FRAME = "frame";
28const char *CONTEXT = "context";
29const char *GLOBAL = "global";
30const char *DISABLEBREAK = "disable_break";
31const char *HANDLES = "handles";
32const char *INCLUDESOURCE = "includeSource";
33const char *FROMFRAME = "fromFrame";
34const char *TOFRAME = "toFrame";
35const char *BOTTOM = "bottom";
36const char *NUMBER = "number";
37const char *FRAMENUMBER = "frameNumber";
38const char *TYPES = "types";
39const char *IDS = "ids";
40const char *FILTER = "filter";
41const char *FROMLINE = "fromLine";
42const char *TOLINE = "toLine";
43const char *TARGET = "target";
44const char *LINE = "line";
45const char *COLUMN = "column";
46const char *ENABLED = "enabled";
47const char *CONDITION = "condition";
48const char *IGNORECOUNT = "ignoreCount";
49const char *BREAKPOINT = "breakpoint";
50const char *FLAGS = "flags";
51
52const char *CONTINEDEBUGGING = "continue";
53const char *EVALUATE = "evaluate";
54const char *LOOKUP = "lookup";
55const char *BACKTRACE = "backtrace";
56const char *SCOPE = "scope";
57const char *SCOPES = "scopes";
58const char *SCRIPTS = "scripts";
59const char *SOURCE = "source";
60const char *SETBREAKPOINT = "setbreakpoint";
61const char *CLEARBREAKPOINT = "clearbreakpoint";
62const char *CHANGEBREAKPOINT = "changebreakpoint";
63const char *SETEXCEPTIONBREAK = "setexceptionbreak";
64const char *VERSION = "version";
65const char *DISCONNECT = "disconnect";
66const char *GARBAGECOLLECTOR = "gc";
67
68const char *CONNECT = "connect";
69const char *INTERRUPT = "interrupt";
70
71const char *REQUEST = "request";
72const char *IN = "in";
73const char *NEXT = "next";
74const char *OUT = "out";
75
76const char *SCRIPT = "script";
77const char *SCRIPTREGEXP = "scriptRegExp";
78const char *EVENT = "event";
79
80const char *ALL = "all";
81const char *UNCAUGHT = "uncaught";
82
83#define VARIANTMAPINIT
84 Q_D(QV4DebugClient);
85 QJsonObject jsonVal;
86 jsonVal.insert(QLatin1String(SEQ), d->seq++);
87 jsonVal.insert(QLatin1String(TYPE), QLatin1String(REQUEST));
88
91{
92 QObject::connect(this, &QQmlDebugClient::stateChanged,
93 this, [this](State state) { d_func()->onStateChanged(state); });
94}
95
96QV4DebugClientPrivate::QV4DebugClientPrivate(QQmlDebugConnection *connection) :
97 QQmlDebugClientPrivate(QLatin1String("V8Debugger"), connection)
98{
99}
100
102{
103 Q_D(QV4DebugClient);
104 d->sendMessage(CONNECT);
105}
106
108{
109 Q_D(QV4DebugClient);
110 d->sendMessage(INTERRUPT);
111}
112
113void QV4DebugClient::continueDebugging(StepAction action)
114{
115 // { "seq" : <number>,
116 // "type" : "request",
117 // "command" : "continue",
118 // "arguments" : { "stepaction" : <"in", "next" or "out">,
119 // "stepcount" : <number of steps (default 1)>
120 // }
121 // }
123 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(CONTINEDEBUGGING));
124
125 if (action != Continue) {
126 QJsonObject args;
127 switch (action) {
128 case In:
129 args.insert(QLatin1String(STEPACTION), QLatin1String(IN));
130 break;
131 case Out:
132 args.insert(QLatin1String(STEPACTION), QLatin1String(OUT));
133 break;
134 case Next:
135 args.insert(QLatin1String(STEPACTION), QLatin1String(NEXT));
136 break;
137 default:
138 break;
139 }
140 jsonVal.insert(QLatin1String(ARGUMENTS), args);
141 }
142
143 d->sendMessage(V8REQUEST, jsonVal);
144}
145
146void QV4DebugClient::evaluate(const QString &expr, int frame, int context)
147{
148 // { "seq" : <number>,
149 // "type" : "request",
150 // "command" : "evaluate",
151 // "arguments" : { "expression" : <expression to evaluate>,
152 // "frame" : <number>,
153 // "context" : <object ID>
154 // }
155 // }
157 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(EVALUATE));
158
159 QJsonObject args;
160 args.insert(QLatin1String(EXPRESSION), expr);
161
162 if (frame != -1)
163 args.insert(QLatin1String(FRAME), frame);
164
165 if (context != -1)
166 args.insert(QLatin1String(CONTEXT), context);
167
168 jsonVal.insert(QLatin1String(ARGUMENTS), args);
169
170 d->sendMessage(V8REQUEST, jsonVal);
171}
172
173void QV4DebugClient::lookup(const QList<int> &handles, bool includeSource)
174{
175 // { "seq" : <number>,
176 // "type" : "request",
177 // "command" : "lookup",
178 // "arguments" : { "handles" : <array of handles>,
179 // "includeSource" : <boolean indicating whether the source will be included when script objects are returned>,
180 // }
181 // }
183 jsonVal.insert(QLatin1String(COMMAND),(QLatin1String(LOOKUP)));
184
185 QJsonObject args;
186 QJsonArray array;
187
188 for (int handle : handles)
189 array.append(handle);
190
191 args.insert(QLatin1String(HANDLES), array);
192
193 if (includeSource)
194 args.insert(QLatin1String(INCLUDESOURCE), includeSource);
195
196 jsonVal.insert(QLatin1String(ARGUMENTS), args);
197
198 d->sendMessage(V8REQUEST, jsonVal);
199}
200
201void QV4DebugClient::backtrace(int fromFrame, int toFrame, bool bottom)
202{
203 // { "seq" : <number>,
204 // "type" : "request",
205 // "command" : "backtrace",
206 // "arguments" : { "fromFrame" : <number>
207 // "toFrame" : <number>
208 // "bottom" : <boolean, set to true if the bottom of the stack is requested>
209 // }
210 // }
212 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(BACKTRACE));
213
214 QJsonObject args;
215
216 if (fromFrame != -1)
217 args.insert(QLatin1String(FROMFRAME), fromFrame);
218
219 if (toFrame != -1)
220 args.insert(QLatin1String(TOFRAME), toFrame);
221
222 if (bottom)
223 args.insert(QLatin1String(BOTTOM), bottom);
224
225 jsonVal.insert(QLatin1String(ARGUMENTS), args);
226 d->sendMessage(V8REQUEST, jsonVal);
227}
228
229void QV4DebugClient::frame(int number)
230{
231 // { "seq" : <number>,
232 // "type" : "request",
233 // "command" : "frame",
234 // "arguments" : { "number" : <frame number>
235 // }
236 // }
238 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(FRAME));
239
240 if (number != -1) {
241 QJsonObject args;
242 args.insert(QLatin1String(NUMBER), number);
243 jsonVal.insert(QLatin1String(ARGUMENTS), args);
244 }
245
246 d->sendMessage(V8REQUEST, jsonVal);
247}
248
249void QV4DebugClient::scope(int number, int frameNumber)
250{
251 // { "seq" : <number>,
252 // "type" : "request",
253 // "command" : "scope",
254 // "arguments" : { "number" : <scope number>
255 // "frameNumber" : <frame number, optional uses selected frame if missing>
256 // }
257 // }
259 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(SCOPE));
260
261 if (number != -1) {
262 QJsonObject args;
263 args.insert(QLatin1String(NUMBER), number);
264
265 if (frameNumber != -1)
266 args.insert(QLatin1String(FRAMENUMBER), frameNumber);
267
268 jsonVal.insert(QLatin1String(ARGUMENTS), args);
269 }
270
271 d->sendMessage(V8REQUEST, jsonVal);
272}
273
274void QV4DebugClient::scripts(int types, const QList<int> &ids, bool includeSource)
275{
276 // { "seq" : <number>,
277 // "type" : "request",
278 // "command" : "scripts",
279 // "arguments" : { "types" : <types of scripts to retrieve
280 // set bit 0 for native scripts
281 // set bit 1 for extension scripts
282 // set bit 2 for normal scripts
283 // (default is 4 for normal scripts)>
284 // "ids" : <array of id's of scripts to return. If this is not specified all scripts are requrned>
285 // "includeSource" : <boolean indicating whether the source code should be included for the scripts returned>
286 // "filter" : <string or number: filter string or script id.
287 // If a number is specified, then only the script with the same number as its script id will be retrieved.
288 // If a string is specified, then only scripts whose names contain the filter string will be retrieved.>
289 // }
290 // }
292 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(SCRIPTS));
293
294 QJsonObject args;
295 args.insert(QLatin1String(TYPES), types);
296
297 if (ids.size()) {
298 QJsonArray array;
299 for (int id : ids)
300 array.append(id);
301
302 args.insert(QLatin1String(IDS), array);
303 }
304
305 if (includeSource)
306 args.insert(QLatin1String(INCLUDESOURCE), includeSource);
307
308 jsonVal.insert(QLatin1String(ARGUMENTS), args);
309 d->sendMessage(V8REQUEST, jsonVal);
310}
311
312void QV4DebugClient::setBreakpoint(const QString &target, int line, int column, bool enabled,
313 const QString &condition, int ignoreCount)
314{
315 // { "seq" : <number>,
316 // "type" : "request",
317 // "command" : "setbreakpoint",
318 // "arguments" : { "type" : "scriptRegExp"
319 // "target" : <function expression or script identification>
320 // "line" : <line in script or function>
321 // "column" : <character position within the line>
322 // "enabled" : <initial enabled state. True or false, default is true>
323 // "condition" : <string with break point condition>
324 // "ignoreCount" : <number specifying the number of break point hits to ignore, default value is 0>
325 // }
326 // }
327
329 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(SETBREAKPOINT));
330
331 QJsonObject args;
332
333 args.insert(QLatin1String(TYPE), QLatin1String(SCRIPTREGEXP));
334 args.insert(QLatin1String(TARGET), target);
335
336 if (line != -1)
337 args.insert(QLatin1String(LINE), line);
338
339 if (column != -1)
340 args.insert(QLatin1String(COLUMN), column);
341
342 args.insert(QLatin1String(ENABLED), enabled);
343
344 if (!condition.isEmpty())
345 args.insert(QLatin1String(CONDITION), condition);
346
347 if (ignoreCount != -1)
348 args.insert(QLatin1String(IGNORECOUNT), ignoreCount);
349
350 jsonVal.insert(QLatin1String(ARGUMENTS),args);
351 d->sendMessage(V8REQUEST, jsonVal);
352}
353
354void QV4DebugClient::clearBreakpoint(int breakpoint)
355{
356 // { "seq" : <number>,
357 // "type" : "request",
358 // "command" : "clearbreakpoint",
359 // "arguments" : { "breakpoint" : <number of the break point to clear>
360 // }
361 // }
363 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(CLEARBREAKPOINT));
364
365 QJsonObject args;
366 args.insert(QLatin1String(BREAKPOINT), breakpoint);
367 jsonVal.insert(QLatin1String(ARGUMENTS),args);
368
369 d->sendMessage(V8REQUEST, jsonVal);
370}
371
372void QV4DebugClient::changeBreakpoint(int breakpoint, bool enabled)
373{
374 // { "seq" : <number>,
375 // "type" : "request",
376 // "command" : "changebreakpoint",
377 // "arguments" : { "breakpoint" : <number of the break point to change>
378 // "enabled" : <bool: enables the break type if true, disables if false>
379 // }
380 // }
382 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(CHANGEBREAKPOINT));
383
384 QJsonObject args;
385 args.insert(QLatin1String(BREAKPOINT), breakpoint);
386 args.insert(QLatin1String(ENABLED), enabled);
387
388 jsonVal.insert(QLatin1String(ARGUMENTS), args);
389 d->sendMessage(V8REQUEST, jsonVal);
390}
391
393{
394 // { "seq" : <number>,
395 // "type" : "request",
396 // "command" : "setexceptionbreak",
397 // "arguments" : { "type" : <string: "all", or "uncaught">,
398 // "enabled" : <optional bool: enables the break type if true>
399 // }
400 // }
402 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(SETEXCEPTIONBREAK));
403
404 QJsonObject args;
405
406 if (type == All)
407 args.insert(QLatin1String(TYPE), QLatin1String(ALL));
408 else if (type == Uncaught)
409 args.insert(QLatin1String(TYPE), QLatin1String(UNCAUGHT));
410
411 if (enabled)
412 args.insert(QLatin1String(ENABLED), enabled);
413
414 jsonVal.insert(QLatin1String(ARGUMENTS), args);
415 d->sendMessage(V8REQUEST, jsonVal);
416}
417
419{
420 // { "seq" : <number>,
421 // "type" : "request",
422 // "command" : "version",
423 // }
425 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(VERSION));
426 d->sendMessage(V8REQUEST, jsonVal);
427}
428
430{
431 Q_D(const QV4DebugClient);
432 const QJsonObject value = QJsonDocument::fromJson(d->response).object();
433 return {
434 value.value(QLatin1String(COMMAND)).toString(),
435 value.value(QLatin1String("body"))
436 };
437}
438
440{
441 // { "seq" : <number>,
442 // "type" : "request",
443 // "command" : "disconnect",
444 // }
446 jsonVal.insert(QLatin1String(COMMAND), QLatin1String(DISCONNECT));
447 d->sendMessage(DISCONNECT, jsonVal);
448}
449
450void QV4DebugClientPrivate::onStateChanged(QQmlDebugClient::State state)
451{
452 if (state == QQmlDebugClient::Enabled)
454}
455
456void QV4DebugClient::messageReceived(const QByteArray &data)
457{
458 Q_D(QV4DebugClient);
459 QPacket ds(connection()->currentDataStreamVersion(), data);
460 QByteArray command;
461 ds >> command;
462
463 if (command == "V8DEBUG") {
464 QByteArray type;
465 ds >> type >> d->response;
466
467 if (type == CONNECT) {
468 emit connected();
469
470 } else if (type == INTERRUPT) {
471 emit interrupted();
472
473 } else if (type == V8MESSAGE) {
474 const QJsonObject value = QJsonDocument::fromJson(d->response).object();
475 QString type = value.value(QLatin1String(TYPE)).toString();
476
477 if (type == QLatin1String("response")) {
478
479 if (!value.value(QLatin1String("success")).toBool()) {
480 emit failure();
481 qDebug() << "Received success == false response from application:"
482 << value.value(QLatin1String("message")).toString();
483 return;
484 }
485
486 QString debugCommand(value.value(QLatin1String(COMMAND)).toString());
487 if (debugCommand == QLatin1String(BACKTRACE) ||
488 debugCommand == QLatin1String(LOOKUP) ||
489 debugCommand == QLatin1String(SETBREAKPOINT) ||
490 debugCommand == QLatin1String(EVALUATE) ||
491 debugCommand == QLatin1String(VERSION) ||
492 debugCommand == QLatin1String(DISCONNECT) ||
493 debugCommand == QLatin1String(GARBAGECOLLECTOR) ||
494 debugCommand == QLatin1String(CHANGEBREAKPOINT) ||
495 debugCommand == QLatin1String(CLEARBREAKPOINT) ||
496 debugCommand == QLatin1String(FRAME) ||
497 debugCommand == QLatin1String(SCOPE) ||
498 debugCommand == QLatin1String(SCOPES) ||
499 debugCommand == QLatin1String(SCRIPTS) ||
500 debugCommand == QLatin1String(SOURCE) ||
501 debugCommand == QLatin1String(SETEXCEPTIONBREAK)) {
502 emit result();
503 } else {
504 // DO NOTHING
505 }
506
507 } else if (type == QLatin1String(EVENT)) {
508 QString event(value.value(QLatin1String(EVENT)).toString());
509
510 if (event == QLatin1String("break") || event == QLatin1String("exception"))
511 emit stopped();
512 }
513 }
514 }
515}
516
517void QV4DebugClientPrivate::sendMessage(const QByteArray &command, const QJsonObject &args)
518{
519 Q_Q(QV4DebugClient);
520 const QByteArray msg = packMessage(command, args);
521 if (q->state() == QQmlDebugClient::Enabled) {
522 q->sendMessage(msg);
523 } else {
524 sendBuffer.append(msg);
525 }
526}
527
529{
530 for (const QByteArray &msg : std::as_const(sendBuffer))
531 sendMessage(msg);
532 sendBuffer.clear();
533}
534
535QByteArray QV4DebugClientPrivate::packMessage(const QByteArray &type, const QJsonObject &object)
536{
537 QPacket rs(connection->currentDataStreamVersion());
538 QByteArray cmd = "V8DEBUG";
539 rs << cmd << type << QJsonDocument(object).toJson(QJsonDocument::Compact);
540 return rs.data();
541}
542
543QT_END_NAMESPACE
544
545#include "moc_qv4debugclient_p.cpp"
QQmlDebugConnection * connection() const
void sendMessage(const QByteArray &command, const QJsonObject &args=QJsonObject())
QByteArray packMessage(const QByteArray &type, const QJsonObject &object)
void onStateChanged(QQmlDebugClient::State state)
void scripts(int types=4, const QList< int > &ids=QList< int >(), bool includeSource=false)
void frame(int number=-1)
void changeBreakpoint(int breakpoint, bool enabled)
QV4DebugClient(QQmlDebugConnection *connection)
void messageReceived(const QByteArray &data) override
void evaluate(const QString &expr, int frame=-1, int context=-1)
void setBreakpoint(const QString &target, int line=-1, int column=-1, bool enabled=true, const QString &condition=QString(), int ignoreCount=-1)
void lookup(const QList< int > &handles, bool includeSource=false)
void continueDebugging(StepAction stepAction)
void scope(int number=-1, int frameNumber=-1)
void setExceptionBreak(Exception type, bool enabled=false)
Response response() const
void backtrace(int fromFrame=-1, int toFrame=-1, bool bottom=false)
void clearBreakpoint(int breakpoint)
Combined button and popup list for selecting options.
const char * SCOPE
const char * SETEXCEPTIONBREAK
const char * LINE
const char * ALL
const char * CLEARBREAKPOINT
const char * FLAGS
const char * SCRIPTREGEXP
const char * SEQ
const char * TYPES
const char * TYPE
const char * COMMAND
const char * EVENT
const char * HANDLES
const char * TOLINE
const char * REQUEST
const char * SCRIPT
const char * IGNORECOUNT
QT_BEGIN_NAMESPACE const char * V8REQUEST
const char * NEXT
const char * INTERRUPT
const char * NUMBER
const char * EVALUATE
const char * BOTTOM
const char * BREAKPOINT
const char * GARBAGECOLLECTOR
const char * FILTER
const char * STEPCOUNT
const char * OUT
const char * DISCONNECT
const char * CONDITION
const char * CONTINEDEBUGGING
const char * CHANGEBREAKPOINT
const char * GLOBAL
const char * FRAME
const char * SOURCE
const char * UNCAUGHT
const char * TARGET
const char * SCOPES
const char * INCLUDESOURCE
const char * STEPACTION
const char * SCRIPTS
const char * BACKTRACE
const char * ENABLED
#define VARIANTMAPINIT
const char * LOOKUP
const char * VERSION
const char * IN
const char * SETBREAKPOINT
const char * CONNECT
const char * FROMLINE
const char * TOFRAME
const char * FRAMENUMBER
const char * FROMFRAME
const char * CONTEXT
const char * ARGUMENTS
const char * IDS
const char * V8MESSAGE
const char * DISABLEBREAK
const char * COLUMN
const char * EXPRESSION