Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
9906 views
1
/**************************************************************************/
2
/* debug_adapter_protocol.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "debug_adapter_protocol.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/debugger/debugger_marshalls.h"
35
#include "core/io/json.h"
36
#include "core/io/marshalls.h"
37
#include "editor/debugger/script_editor_debugger.h"
38
#include "editor/editor_log.h"
39
#include "editor/editor_node.h"
40
#include "editor/run/editor_run_bar.h"
41
#include "editor/settings/editor_settings.h"
42
43
DebugAdapterProtocol *DebugAdapterProtocol::singleton = nullptr;
44
45
Error DAPeer::handle_data() {
46
int read = 0;
47
// Read headers
48
if (!has_header) {
49
if (!connection->get_available_bytes()) {
50
return OK;
51
}
52
while (true) {
53
if (req_pos >= DAP_MAX_BUFFER_SIZE) {
54
req_pos = 0;
55
ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Response header too big");
56
}
57
Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
58
if (err != OK) {
59
return FAILED;
60
} else if (read != 1) { // Busy, wait until next poll
61
return ERR_BUSY;
62
}
63
char *r = (char *)req_buf;
64
int l = req_pos;
65
66
// End of headers
67
if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
68
r[l - 3] = '\0'; // Null terminate to read string
69
String header = String::utf8(r);
70
content_length = header.substr(16).to_int();
71
has_header = true;
72
req_pos = 0;
73
break;
74
}
75
req_pos++;
76
}
77
}
78
if (has_header) {
79
while (req_pos < content_length) {
80
if (content_length >= DAP_MAX_BUFFER_SIZE) {
81
req_pos = 0;
82
has_header = false;
83
ERR_FAIL_COND_V_MSG(req_pos >= DAP_MAX_BUFFER_SIZE, ERR_OUT_OF_MEMORY, "Response content too big");
84
}
85
Error err = connection->get_partial_data(&req_buf[req_pos], content_length - req_pos, read);
86
if (err != OK) {
87
return FAILED;
88
} else if (read < content_length - req_pos) {
89
return ERR_BUSY;
90
}
91
req_pos += read;
92
}
93
94
// Parse data
95
String msg = String::utf8((const char *)req_buf, req_pos);
96
97
// Apply a timestamp if it there's none yet
98
if (!timestamp) {
99
timestamp = OS::get_singleton()->get_ticks_msec();
100
}
101
102
// Response
103
if (DebugAdapterProtocol::get_singleton()->process_message(msg)) {
104
// Reset to read again
105
req_pos = 0;
106
has_header = false;
107
timestamp = 0;
108
}
109
}
110
return OK;
111
}
112
113
Error DAPeer::send_data() {
114
while (res_queue.size()) {
115
Dictionary data = res_queue.front()->get();
116
if (!data.has("seq")) {
117
data["seq"] = ++seq;
118
}
119
const Vector<uint8_t> &formatted_data = format_output(data);
120
121
int data_sent = 0;
122
while (data_sent < formatted_data.size()) {
123
int curr_sent = 0;
124
Error err = connection->put_partial_data(formatted_data.ptr() + data_sent, formatted_data.size() - data_sent, curr_sent);
125
if (err != OK) {
126
return err;
127
}
128
data_sent += curr_sent;
129
}
130
res_queue.pop_front();
131
}
132
return OK;
133
}
134
135
Vector<uint8_t> DAPeer::format_output(const Dictionary &p_params) const {
136
const Vector<uint8_t> &content = Variant(p_params).to_json_string().to_utf8_buffer();
137
Vector<uint8_t> response = vformat("Content-Length: %d\r\n\r\n", content.size()).to_utf8_buffer();
138
139
response.append_array(content);
140
return response;
141
}
142
143
Error DebugAdapterProtocol::on_client_connected() {
144
ERR_FAIL_COND_V_MSG(clients.size() >= DAP_MAX_CLIENTS, FAILED, "Max client limits reached");
145
146
Ref<StreamPeerTCP> tcp_peer = server->take_connection();
147
tcp_peer->set_no_delay(true);
148
Ref<DAPeer> peer = memnew(DAPeer);
149
peer->connection = tcp_peer;
150
clients.push_back(peer);
151
152
EditorDebuggerNode::get_singleton()->get_default_debugger()->set_move_to_foreground(false);
153
EditorNode::get_log()->add_message("[DAP] Connection Taken", EditorLog::MSG_TYPE_EDITOR);
154
return OK;
155
}
156
157
void DebugAdapterProtocol::on_client_disconnected(const Ref<DAPeer> &p_peer) {
158
clients.erase(p_peer);
159
if (!clients.size()) {
160
reset_ids();
161
EditorDebuggerNode::get_singleton()->get_default_debugger()->set_move_to_foreground(true);
162
}
163
EditorNode::get_log()->add_message("[DAP] Disconnected", EditorLog::MSG_TYPE_EDITOR);
164
}
165
166
void DebugAdapterProtocol::reset_current_info() {
167
_current_request = "";
168
_current_peer.unref();
169
}
170
171
void DebugAdapterProtocol::reset_ids() {
172
breakpoint_id = 0;
173
breakpoint_list.clear();
174
breakpoint_source_list.clear();
175
176
reset_stack_info();
177
}
178
179
void DebugAdapterProtocol::reset_stack_info() {
180
stackframe_id = 0;
181
variable_id = 1;
182
183
stackframe_list.clear();
184
scope_list.clear();
185
variable_list.clear();
186
object_list.clear();
187
object_pending_set.clear();
188
}
189
190
int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
191
switch (p_var.get_type()) {
192
case Variant::VECTOR2:
193
case Variant::VECTOR2I: {
194
int id = variable_id++;
195
Vector2 vec = p_var;
196
const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::VECTOR2 ? Variant::FLOAT : Variant::INT);
197
DAP::Variable x, y;
198
x.name = "x";
199
y.name = "y";
200
x.type = type_scalar;
201
y.type = type_scalar;
202
x.value = rtos(vec.x);
203
y.value = rtos(vec.y);
204
205
Array arr = { x.to_json(), y.to_json() };
206
variable_list.insert(id, arr);
207
return id;
208
}
209
case Variant::RECT2:
210
case Variant::RECT2I: {
211
int id = variable_id++;
212
Rect2 rect = p_var;
213
const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::RECT2 ? Variant::FLOAT : Variant::INT);
214
DAP::Variable x, y, w, h;
215
x.name = "x";
216
y.name = "y";
217
w.name = "w";
218
h.name = "h";
219
x.type = type_scalar;
220
y.type = type_scalar;
221
w.type = type_scalar;
222
h.type = type_scalar;
223
x.value = rtos(rect.position.x);
224
y.value = rtos(rect.position.y);
225
w.value = rtos(rect.size.x);
226
h.value = rtos(rect.size.y);
227
228
Array arr = { x.to_json(), y.to_json(), w.to_json(), h.to_json() };
229
variable_list.insert(id, arr);
230
return id;
231
}
232
case Variant::VECTOR3:
233
case Variant::VECTOR3I: {
234
int id = variable_id++;
235
Vector3 vec = p_var;
236
const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::VECTOR3 ? Variant::FLOAT : Variant::INT);
237
DAP::Variable x, y, z;
238
x.name = "x";
239
y.name = "y";
240
z.name = "z";
241
x.type = type_scalar;
242
y.type = type_scalar;
243
z.type = type_scalar;
244
x.value = rtos(vec.x);
245
y.value = rtos(vec.y);
246
z.value = rtos(vec.z);
247
248
Array arr = { x.to_json(), y.to_json(), z.to_json() };
249
variable_list.insert(id, arr);
250
return id;
251
}
252
case Variant::TRANSFORM2D: {
253
int id = variable_id++;
254
Transform2D transform = p_var;
255
const String type_vec2 = Variant::get_type_name(Variant::VECTOR2);
256
DAP::Variable x, y, origin;
257
x.name = "x";
258
y.name = "y";
259
origin.name = "origin";
260
x.type = type_vec2;
261
y.type = type_vec2;
262
origin.type = type_vec2;
263
x.value = String(transform.columns[0]);
264
y.value = String(transform.columns[1]);
265
origin.value = String(transform.columns[2]);
266
x.variablesReference = parse_variant(transform.columns[0]);
267
y.variablesReference = parse_variant(transform.columns[1]);
268
origin.variablesReference = parse_variant(transform.columns[2]);
269
270
Array arr = { x.to_json(), y.to_json(), origin.to_json() };
271
variable_list.insert(id, arr);
272
return id;
273
}
274
case Variant::PLANE: {
275
int id = variable_id++;
276
Plane plane = p_var;
277
DAP::Variable d, normal;
278
d.name = "d";
279
normal.name = "normal";
280
d.type = Variant::get_type_name(Variant::FLOAT);
281
normal.type = Variant::get_type_name(Variant::VECTOR3);
282
d.value = rtos(plane.d);
283
normal.value = String(plane.normal);
284
normal.variablesReference = parse_variant(plane.normal);
285
286
Array arr = { d.to_json(), normal.to_json() };
287
variable_list.insert(id, arr);
288
return id;
289
}
290
case Variant::QUATERNION: {
291
int id = variable_id++;
292
Quaternion quat = p_var;
293
const String type_float = Variant::get_type_name(Variant::FLOAT);
294
DAP::Variable x, y, z, w;
295
x.name = "x";
296
y.name = "y";
297
z.name = "z";
298
w.name = "w";
299
x.type = type_float;
300
y.type = type_float;
301
z.type = type_float;
302
w.type = type_float;
303
x.value = rtos(quat.x);
304
y.value = rtos(quat.y);
305
z.value = rtos(quat.z);
306
w.value = rtos(quat.w);
307
308
Array arr = { x.to_json(), y.to_json(), z.to_json(), w.to_json() };
309
variable_list.insert(id, arr);
310
return id;
311
}
312
case Variant::AABB: {
313
int id = variable_id++;
314
AABB aabb = p_var;
315
const String type_vec3 = Variant::get_type_name(Variant::VECTOR3);
316
DAP::Variable position, size;
317
position.name = "position";
318
size.name = "size";
319
position.type = type_vec3;
320
size.type = type_vec3;
321
position.value = String(aabb.position);
322
size.value = String(aabb.size);
323
position.variablesReference = parse_variant(aabb.position);
324
size.variablesReference = parse_variant(aabb.size);
325
326
Array arr = { position.to_json(), size.to_json() };
327
variable_list.insert(id, arr);
328
return id;
329
}
330
case Variant::BASIS: {
331
int id = variable_id++;
332
Basis basis = p_var;
333
const String type_vec3 = Variant::get_type_name(Variant::VECTOR3);
334
DAP::Variable x, y, z;
335
x.name = "x";
336
y.name = "y";
337
z.name = "z";
338
x.type = type_vec3;
339
y.type = type_vec3;
340
z.type = type_vec3;
341
x.value = String(basis.rows[0]);
342
y.value = String(basis.rows[1]);
343
z.value = String(basis.rows[2]);
344
x.variablesReference = parse_variant(basis.rows[0]);
345
y.variablesReference = parse_variant(basis.rows[1]);
346
z.variablesReference = parse_variant(basis.rows[2]);
347
348
Array arr = { x.to_json(), y.to_json(), z.to_json() };
349
variable_list.insert(id, arr);
350
return id;
351
}
352
case Variant::TRANSFORM3D: {
353
int id = variable_id++;
354
Transform3D transform = p_var;
355
DAP::Variable basis, origin;
356
basis.name = "basis";
357
origin.name = "origin";
358
basis.type = Variant::get_type_name(Variant::BASIS);
359
origin.type = Variant::get_type_name(Variant::VECTOR3);
360
basis.value = String(transform.basis);
361
origin.value = String(transform.origin);
362
basis.variablesReference = parse_variant(transform.basis);
363
origin.variablesReference = parse_variant(transform.origin);
364
365
Array arr = { basis.to_json(), origin.to_json() };
366
variable_list.insert(id, arr);
367
return id;
368
}
369
case Variant::COLOR: {
370
int id = variable_id++;
371
Color color = p_var;
372
const String type_float = Variant::get_type_name(Variant::FLOAT);
373
DAP::Variable r, g, b, a;
374
r.name = "r";
375
g.name = "g";
376
b.name = "b";
377
a.name = "a";
378
r.type = type_float;
379
g.type = type_float;
380
b.type = type_float;
381
a.type = type_float;
382
r.value = rtos(color.r);
383
g.value = rtos(color.g);
384
b.value = rtos(color.b);
385
a.value = rtos(color.a);
386
387
Array arr = { r.to_json(), g.to_json(), b.to_json(), a.to_json() };
388
variable_list.insert(id, arr);
389
return id;
390
}
391
case Variant::ARRAY: {
392
int id = variable_id++;
393
Array array = p_var;
394
DAP::Variable size;
395
size.name = "size";
396
size.type = Variant::get_type_name(Variant::INT);
397
size.value = itos(array.size());
398
399
Array arr = { size.to_json() };
400
401
for (int i = 0; i < array.size(); i++) {
402
DAP::Variable var;
403
var.name = itos(i);
404
var.type = Variant::get_type_name(array[i].get_type());
405
var.value = array[i];
406
var.variablesReference = parse_variant(array[i]);
407
arr.push_back(var.to_json());
408
}
409
variable_list.insert(id, arr);
410
return id;
411
}
412
case Variant::DICTIONARY: {
413
int id = variable_id++;
414
Dictionary dictionary = p_var;
415
Array arr;
416
417
for (const KeyValue<Variant, Variant> &kv : dictionary) {
418
DAP::Variable var;
419
var.name = kv.key;
420
Variant value = kv.value;
421
var.type = Variant::get_type_name(value.get_type());
422
var.value = value;
423
var.variablesReference = parse_variant(value);
424
arr.push_back(var.to_json());
425
}
426
variable_list.insert(id, arr);
427
return id;
428
}
429
case Variant::PACKED_BYTE_ARRAY: {
430
int id = variable_id++;
431
PackedByteArray array = p_var;
432
DAP::Variable size;
433
size.name = "size";
434
size.type = Variant::get_type_name(Variant::INT);
435
size.value = itos(array.size());
436
437
Array arr = { size.to_json() };
438
439
for (int i = 0; i < array.size(); i++) {
440
DAP::Variable var;
441
var.name = itos(i);
442
var.type = "byte";
443
var.value = itos(array[i]);
444
arr.push_back(var.to_json());
445
}
446
variable_list.insert(id, arr);
447
return id;
448
}
449
case Variant::PACKED_INT32_ARRAY: {
450
int id = variable_id++;
451
PackedInt32Array array = p_var;
452
DAP::Variable size;
453
size.name = "size";
454
size.type = Variant::get_type_name(Variant::INT);
455
size.value = itos(array.size());
456
457
Array arr = { size.to_json() };
458
459
for (int i = 0; i < array.size(); i++) {
460
DAP::Variable var;
461
var.name = itos(i);
462
var.type = "int";
463
var.value = itos(array[i]);
464
arr.push_back(var.to_json());
465
}
466
variable_list.insert(id, arr);
467
return id;
468
}
469
case Variant::PACKED_INT64_ARRAY: {
470
int id = variable_id++;
471
PackedInt64Array array = p_var;
472
DAP::Variable size;
473
size.name = "size";
474
size.type = Variant::get_type_name(Variant::INT);
475
size.value = itos(array.size());
476
477
Array arr = { size.to_json() };
478
479
for (int i = 0; i < array.size(); i++) {
480
DAP::Variable var;
481
var.name = itos(i);
482
var.type = "long";
483
var.value = itos(array[i]);
484
arr.push_back(var.to_json());
485
}
486
variable_list.insert(id, arr);
487
return id;
488
}
489
case Variant::PACKED_FLOAT32_ARRAY: {
490
int id = variable_id++;
491
PackedFloat32Array array = p_var;
492
DAP::Variable size;
493
size.name = "size";
494
size.type = Variant::get_type_name(Variant::INT);
495
size.value = itos(array.size());
496
497
Array arr = { size.to_json() };
498
499
for (int i = 0; i < array.size(); i++) {
500
DAP::Variable var;
501
var.name = itos(i);
502
var.type = "float";
503
var.value = rtos(array[i]);
504
arr.push_back(var.to_json());
505
}
506
variable_list.insert(id, arr);
507
return id;
508
}
509
case Variant::PACKED_FLOAT64_ARRAY: {
510
int id = variable_id++;
511
PackedFloat64Array array = p_var;
512
DAP::Variable size;
513
size.name = "size";
514
size.type = Variant::get_type_name(Variant::INT);
515
size.value = itos(array.size());
516
517
Array arr = { size.to_json() };
518
519
for (int i = 0; i < array.size(); i++) {
520
DAP::Variable var;
521
var.name = itos(i);
522
var.type = "double";
523
var.value = rtos(array[i]);
524
arr.push_back(var.to_json());
525
}
526
variable_list.insert(id, arr);
527
return id;
528
}
529
case Variant::PACKED_STRING_ARRAY: {
530
int id = variable_id++;
531
PackedStringArray array = p_var;
532
DAP::Variable size;
533
size.name = "size";
534
size.type = Variant::get_type_name(Variant::INT);
535
size.value = itos(array.size());
536
537
Array arr = { size.to_json() };
538
539
for (int i = 0; i < array.size(); i++) {
540
DAP::Variable var;
541
var.name = itos(i);
542
var.type = Variant::get_type_name(Variant::STRING);
543
var.value = array[i];
544
arr.push_back(var.to_json());
545
}
546
variable_list.insert(id, arr);
547
return id;
548
}
549
case Variant::PACKED_VECTOR2_ARRAY: {
550
int id = variable_id++;
551
PackedVector2Array array = p_var;
552
DAP::Variable size;
553
size.name = "size";
554
size.type = Variant::get_type_name(Variant::INT);
555
size.value = itos(array.size());
556
557
Array arr = { size.to_json() };
558
559
for (int i = 0; i < array.size(); i++) {
560
DAP::Variable var;
561
var.name = itos(i);
562
var.type = Variant::get_type_name(Variant::VECTOR2);
563
var.value = String(array[i]);
564
var.variablesReference = parse_variant(array[i]);
565
arr.push_back(var.to_json());
566
}
567
variable_list.insert(id, arr);
568
return id;
569
}
570
case Variant::PACKED_VECTOR3_ARRAY: {
571
int id = variable_id++;
572
PackedVector3Array array = p_var;
573
DAP::Variable size;
574
size.name = "size";
575
size.type = Variant::get_type_name(Variant::INT);
576
size.value = itos(array.size());
577
578
Array arr = { size.to_json() };
579
580
for (int i = 0; i < array.size(); i++) {
581
DAP::Variable var;
582
var.name = itos(i);
583
var.type = Variant::get_type_name(Variant::VECTOR3);
584
var.value = String(array[i]);
585
var.variablesReference = parse_variant(array[i]);
586
arr.push_back(var.to_json());
587
}
588
variable_list.insert(id, arr);
589
return id;
590
}
591
case Variant::PACKED_COLOR_ARRAY: {
592
int id = variable_id++;
593
PackedColorArray array = p_var;
594
DAP::Variable size;
595
size.name = "size";
596
size.type = Variant::get_type_name(Variant::INT);
597
size.value = itos(array.size());
598
599
Array arr = { size.to_json() };
600
601
for (int i = 0; i < array.size(); i++) {
602
DAP::Variable var;
603
var.name = itos(i);
604
var.type = Variant::get_type_name(Variant::COLOR);
605
var.value = String(array[i]);
606
var.variablesReference = parse_variant(array[i]);
607
arr.push_back(var.to_json());
608
}
609
variable_list.insert(id, arr);
610
return id;
611
}
612
case Variant::PACKED_VECTOR4_ARRAY: {
613
int id = variable_id++;
614
PackedVector4Array array = p_var;
615
DAP::Variable size;
616
size.name = "size";
617
size.type = Variant::get_type_name(Variant::INT);
618
size.value = itos(array.size());
619
620
Array arr;
621
arr.push_back(size.to_json());
622
623
for (int i = 0; i < array.size(); i++) {
624
DAP::Variable var;
625
var.name = itos(i);
626
var.type = Variant::get_type_name(Variant::VECTOR4);
627
var.value = String(array[i]);
628
var.variablesReference = parse_variant(array[i]);
629
arr.push_back(var.to_json());
630
}
631
variable_list.insert(id, arr);
632
return id;
633
}
634
case Variant::OBJECT: {
635
// Objects have to be requested from the debuggee. This has do be done
636
// in a lazy way, as retrieving object properties takes time.
637
EncodedObjectAsID *encoded_obj = Object::cast_to<EncodedObjectAsID>(p_var);
638
639
// Object may be null; in that case, return early.
640
if (!encoded_obj) {
641
return 0;
642
}
643
644
// Object may have been already requested.
645
ObjectID object_id = encoded_obj->get_object_id();
646
if (object_list.has(object_id)) {
647
return object_list[object_id];
648
}
649
650
// Queue requesting the object.
651
int id = variable_id++;
652
object_list.insert(object_id, id);
653
return id;
654
}
655
default:
656
// Simple atomic stuff, or too complex to be manipulated
657
return 0;
658
}
659
}
660
661
void DebugAdapterProtocol::parse_object(SceneDebuggerObject &p_obj) {
662
// If the object is not on the pending list, we weren't expecting it. Ignore it.
663
ObjectID object_id = p_obj.id;
664
if (!object_pending_set.erase(object_id)) {
665
return;
666
}
667
668
// Populate DAP::Variable's with the object's properties. These properties will be divided by categories.
669
Array properties;
670
Array script_members;
671
Array script_constants;
672
Array script_node;
673
DAP::Variable node_type;
674
Array node_properties;
675
676
for (SceneDebuggerObject::SceneDebuggerProperty &property : p_obj.properties) {
677
PropertyInfo &info = property.first;
678
679
// Script members ("Members/" prefix)
680
if (info.name.begins_with("Members/")) {
681
info.name = info.name.trim_prefix("Members/");
682
script_members.push_back(parse_object_variable(property));
683
}
684
685
// Script constants ("Constants/" prefix)
686
else if (info.name.begins_with("Constants/")) {
687
info.name = info.name.trim_prefix("Constants/");
688
script_constants.push_back(parse_object_variable(property));
689
}
690
691
// Script node ("Node/" prefix)
692
else if (info.name.begins_with("Node/")) {
693
info.name = info.name.trim_prefix("Node/");
694
script_node.push_back(parse_object_variable(property));
695
}
696
697
// Regular categories (with type Variant::NIL)
698
else if (info.type == Variant::NIL) {
699
if (!node_properties.is_empty()) {
700
node_type.value = itos(node_properties.size());
701
variable_list.insert(node_type.variablesReference, node_properties.duplicate());
702
properties.push_back(node_type.to_json());
703
}
704
705
node_type.name = info.name;
706
node_type.type = "Category";
707
node_type.variablesReference = variable_id++;
708
node_properties.clear();
709
}
710
711
// Regular properties.
712
else {
713
node_properties.push_back(parse_object_variable(property));
714
}
715
}
716
717
// Add the last category.
718
if (!node_properties.is_empty()) {
719
node_type.value = itos(node_properties.size());
720
variable_list.insert(node_type.variablesReference, node_properties.duplicate());
721
properties.push_back(node_type.to_json());
722
}
723
724
// Add the script categories, in reverse order to be at the front of the array:
725
// ( [members; constants; node; category1; category2; ...] )
726
if (!script_node.is_empty()) {
727
DAP::Variable node;
728
node.name = "Node";
729
node.type = "Category";
730
node.value = itos(script_node.size());
731
node.variablesReference = variable_id++;
732
variable_list.insert(node.variablesReference, script_node);
733
properties.push_front(node.to_json());
734
}
735
736
if (!script_constants.is_empty()) {
737
DAP::Variable constants;
738
constants.name = "Constants";
739
constants.type = "Category";
740
constants.value = itos(script_constants.size());
741
constants.variablesReference = variable_id++;
742
variable_list.insert(constants.variablesReference, script_constants);
743
properties.push_front(constants.to_json());
744
}
745
746
if (!script_members.is_empty()) {
747
DAP::Variable members;
748
members.name = "Members";
749
members.type = "Category";
750
members.value = itos(script_members.size());
751
members.variablesReference = variable_id++;
752
variable_list.insert(members.variablesReference, script_members);
753
properties.push_front(members.to_json());
754
}
755
756
ERR_FAIL_COND(!object_list.has(object_id));
757
variable_list.insert(object_list[object_id], properties);
758
}
759
760
void DebugAdapterProtocol::parse_evaluation(DebuggerMarshalls::ScriptStackVariable &p_var) {
761
// If the eval is not on the pending list, we weren't expecting it. Ignore it.
762
String eval = p_var.name;
763
if (!eval_pending_list.erase(eval)) {
764
return;
765
}
766
767
DAP::Variable variable;
768
variable.name = p_var.name;
769
variable.value = p_var.value;
770
variable.type = Variant::get_type_name(p_var.value.get_type());
771
variable.variablesReference = parse_variant(p_var.value);
772
773
eval_list.insert(variable.name, variable);
774
}
775
776
const Variant DebugAdapterProtocol::parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property) {
777
const PropertyInfo &info = p_property.first;
778
const Variant &value = p_property.second;
779
780
DAP::Variable var;
781
var.name = info.name;
782
var.type = Variant::get_type_name(info.type);
783
var.value = value;
784
var.variablesReference = parse_variant(value);
785
786
return var.to_json();
787
}
788
789
ObjectID DebugAdapterProtocol::search_object_id(DAPVarID p_var_id) {
790
for (const KeyValue<ObjectID, DAPVarID> &E : object_list) {
791
if (E.value == p_var_id) {
792
return E.key;
793
}
794
}
795
return ObjectID();
796
}
797
798
bool DebugAdapterProtocol::request_remote_object(const ObjectID &p_object_id) {
799
// If the object is already on the pending list, we don't need to request it again.
800
if (object_pending_set.has(p_object_id)) {
801
return false;
802
}
803
804
TypedArray<uint64_t> arr;
805
arr.append(p_object_id);
806
EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_objects(arr);
807
object_pending_set.insert(p_object_id);
808
809
return true;
810
}
811
812
bool DebugAdapterProtocol::request_remote_evaluate(const String &p_eval, int p_stack_frame) {
813
// If the eval is already on the pending list, we don't need to request it again
814
if (eval_pending_list.has(p_eval)) {
815
return false;
816
}
817
818
EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_evaluate(p_eval, p_stack_frame);
819
eval_pending_list.insert(p_eval);
820
821
return true;
822
}
823
824
const DAP::Source &DebugAdapterProtocol::fetch_source(const String &p_path) {
825
const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);
826
827
HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);
828
if (E != breakpoint_source_list.end()) {
829
return E->value;
830
}
831
DAP::Source &added_source = breakpoint_source_list.insert(global_path, DAP::Source())->value;
832
added_source.name = global_path.get_file();
833
added_source.path = global_path;
834
added_source.compute_checksums();
835
836
return added_source;
837
}
838
839
void DebugAdapterProtocol::update_source(const String &p_path) {
840
const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);
841
842
HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);
843
if (E != breakpoint_source_list.end()) {
844
E->value.compute_checksums();
845
}
846
}
847
848
bool DebugAdapterProtocol::process_message(const String &p_text) {
849
JSON json;
850
ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");
851
Dictionary params = json.get_data();
852
bool completed = true;
853
854
// While JSON does not distinguish floats and ints, "seq" is an integer by specification. See https://github.com/godotengine/godot/issues/108288
855
if (params.has("seq")) {
856
params["seq"] = (int)params["seq"];
857
}
858
859
if (OS::get_singleton()->get_ticks_msec() - _current_peer->timestamp > _request_timeout) {
860
Dictionary response = parser->prepare_error_response(params, DAP::ErrorType::TIMEOUT);
861
_current_peer->res_queue.push_front(response);
862
return true;
863
}
864
865
// Append "req_" to any command received; prevents name clash with existing functions, and possibly exploiting
866
String command = "req_" + (String)params["command"];
867
if (parser->has_method(command)) {
868
_current_request = params["command"];
869
870
Array args = { params };
871
Dictionary response = parser->callv(command, args);
872
if (!response.is_empty()) {
873
_current_peer->res_queue.push_front(response);
874
} else {
875
// Launch request needs to be deferred until we receive a configurationDone request.
876
if (command != "req_launch") {
877
completed = false;
878
}
879
}
880
}
881
882
reset_current_info();
883
return completed;
884
}
885
886
void DebugAdapterProtocol::notify_initialized() {
887
Dictionary event = parser->ev_initialized();
888
_current_peer->res_queue.push_back(event);
889
}
890
891
void DebugAdapterProtocol::notify_process() {
892
String launch_mode = _current_peer->attached ? "attach" : "launch";
893
894
Dictionary event = parser->ev_process(launch_mode);
895
for (const Ref<DAPeer> &peer : clients) {
896
peer->res_queue.push_back(event);
897
}
898
}
899
900
void DebugAdapterProtocol::notify_terminated() {
901
Dictionary event = parser->ev_terminated();
902
for (const Ref<DAPeer> &peer : clients) {
903
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {
904
continue;
905
}
906
peer->res_queue.push_back(event);
907
}
908
}
909
910
void DebugAdapterProtocol::notify_exited(const int &p_exitcode) {
911
Dictionary event = parser->ev_exited(p_exitcode);
912
for (const Ref<DAPeer> &peer : clients) {
913
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {
914
continue;
915
}
916
peer->res_queue.push_back(event);
917
}
918
}
919
920
void DebugAdapterProtocol::notify_stopped_paused() {
921
Dictionary event = parser->ev_stopped_paused();
922
for (const Ref<DAPeer> &peer : clients) {
923
peer->res_queue.push_back(event);
924
}
925
}
926
927
void DebugAdapterProtocol::notify_stopped_exception(const String &p_error) {
928
Dictionary event = parser->ev_stopped_exception(p_error);
929
for (const Ref<DAPeer> &peer : clients) {
930
peer->res_queue.push_back(event);
931
}
932
}
933
934
void DebugAdapterProtocol::notify_stopped_breakpoint(const int &p_id) {
935
Dictionary event = parser->ev_stopped_breakpoint(p_id);
936
for (const Ref<DAPeer> &peer : clients) {
937
peer->res_queue.push_back(event);
938
}
939
}
940
941
void DebugAdapterProtocol::notify_stopped_step() {
942
Dictionary event = parser->ev_stopped_step();
943
for (const Ref<DAPeer> &peer : clients) {
944
peer->res_queue.push_back(event);
945
}
946
}
947
948
void DebugAdapterProtocol::notify_continued() {
949
Dictionary event = parser->ev_continued();
950
for (const Ref<DAPeer> &peer : clients) {
951
if (_current_request == "continue" && peer == _current_peer) {
952
continue;
953
}
954
peer->res_queue.push_back(event);
955
}
956
957
reset_stack_info();
958
}
959
960
void DebugAdapterProtocol::notify_output(const String &p_message, RemoteDebugger::MessageType p_type) {
961
Dictionary event = parser->ev_output(p_message, p_type);
962
for (const Ref<DAPeer> &peer : clients) {
963
peer->res_queue.push_back(event);
964
}
965
}
966
967
void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &p_data) {
968
Dictionary event = parser->ev_custom_data(p_msg, p_data);
969
for (const Ref<DAPeer> &peer : clients) {
970
if (peer->supportsCustomData) {
971
peer->res_queue.push_back(event);
972
}
973
}
974
}
975
976
void DebugAdapterProtocol::notify_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) {
977
Dictionary event = parser->ev_breakpoint(p_breakpoint, p_enabled);
978
for (const Ref<DAPeer> &peer : clients) {
979
if (_current_request == "setBreakpoints" && peer == _current_peer) {
980
continue;
981
}
982
peer->res_queue.push_back(event);
983
}
984
}
985
986
Array DebugAdapterProtocol::update_breakpoints(const String &p_path, const Array &p_lines) {
987
Array updated_breakpoints;
988
989
// Add breakpoints
990
for (int i = 0; i < p_lines.size(); i++) {
991
DAP::Breakpoint breakpoint(fetch_source(p_path));
992
breakpoint.line = p_lines[i];
993
994
// Avoid duplicated entries.
995
List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
996
if (E) {
997
updated_breakpoints.push_back(E->get().to_json());
998
continue;
999
}
1000
1001
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);
1002
1003
// Breakpoints are inserted at the end of the breakpoint list.
1004
List<DAP::Breakpoint>::Element *added_breakpoint = breakpoint_list.back();
1005
ERR_FAIL_NULL_V(added_breakpoint, Array());
1006
ERR_FAIL_COND_V(!(added_breakpoint->get() == breakpoint), Array());
1007
updated_breakpoints.push_back(added_breakpoint->get().to_json());
1008
}
1009
1010
// Remove breakpoints
1011
// Must be deferred because we are iterating the breakpoint list.
1012
Vector<int> to_remove;
1013
1014
for (const DAP::Breakpoint &b : breakpoint_list) {
1015
if (b.source->path == p_path && !p_lines.has(b.line)) {
1016
to_remove.push_back(b.line);
1017
}
1018
}
1019
1020
// Safe to remove queued data now.
1021
for (const int &line : to_remove) {
1022
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, line, false);
1023
}
1024
1025
return updated_breakpoints;
1026
}
1027
1028
void DebugAdapterProtocol::on_debug_paused() {
1029
if (EditorRunBar::get_singleton()->get_pause_button()->is_pressed()) {
1030
notify_stopped_paused();
1031
} else {
1032
notify_continued();
1033
}
1034
}
1035
1036
void DebugAdapterProtocol::on_debug_stopped() {
1037
notify_exited();
1038
notify_terminated();
1039
reset_ids();
1040
}
1041
1042
void DebugAdapterProtocol::on_debug_output(const String &p_message, int p_type) {
1043
notify_output(p_message, RemoteDebugger::MessageType(p_type));
1044
}
1045
1046
void DebugAdapterProtocol::on_debug_breaked(const bool &p_reallydid, const bool &p_can_debug, const String &p_reason, const bool &p_has_stackdump) {
1047
if (!p_reallydid) {
1048
notify_continued();
1049
return;
1050
}
1051
1052
if (p_reason == "Breakpoint") {
1053
if (_stepping) {
1054
notify_stopped_step();
1055
_stepping = false;
1056
} else {
1057
_processing_breakpoint = true; // Wait for stack_dump to find where the breakpoint happened
1058
}
1059
} else {
1060
notify_stopped_exception(p_reason);
1061
}
1062
1063
_processing_stackdump = p_has_stackdump;
1064
}
1065
1066
void DebugAdapterProtocol::on_debug_breakpoint_toggled(const String &p_path, const int &p_line, const bool &p_enabled) {
1067
DAP::Breakpoint breakpoint(fetch_source(p_path));
1068
breakpoint.verified = true;
1069
breakpoint.line = p_line;
1070
1071
if (p_enabled) {
1072
// Add the breakpoint
1073
breakpoint.id = breakpoint_id++;
1074
breakpoint_list.push_back(breakpoint);
1075
} else {
1076
// Remove the breakpoint
1077
List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
1078
if (E) {
1079
breakpoint.id = E->get().id;
1080
breakpoint_list.erase(E);
1081
}
1082
}
1083
1084
notify_breakpoint(breakpoint, p_enabled);
1085
}
1086
1087
void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
1088
if (_processing_breakpoint && !p_stack_dump.is_empty()) {
1089
// Find existing breakpoint
1090
Dictionary d = p_stack_dump[0];
1091
DAP::Breakpoint breakpoint(fetch_source(d["file"]));
1092
breakpoint.line = d["line"];
1093
1094
List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
1095
if (E) {
1096
notify_stopped_breakpoint(E->get().id);
1097
}
1098
1099
_processing_breakpoint = false;
1100
}
1101
1102
stackframe_id = 0;
1103
stackframe_list.clear();
1104
scope_list.clear();
1105
1106
// Fill in stacktrace information
1107
for (int i = 0; i < p_stack_dump.size(); i++) {
1108
Dictionary stack_info = p_stack_dump[i];
1109
1110
DAP::StackFrame stackframe(fetch_source(stack_info["file"]));
1111
stackframe.id = stackframe_id++;
1112
stackframe.name = stack_info["function"];
1113
stackframe.line = stack_info["line"];
1114
stackframe.column = 0;
1115
1116
// Information for "Locals", "Members" and "Globals" variables respectively
1117
Vector<int> scope_ids;
1118
for (int j = 0; j < 3; j++) {
1119
scope_ids.push_back(variable_id++);
1120
}
1121
1122
stackframe_list.push_back(stackframe);
1123
scope_list.insert(stackframe.id, scope_ids);
1124
}
1125
1126
_current_frame = 0;
1127
_processing_stackdump = false;
1128
}
1129
1130
void DebugAdapterProtocol::on_debug_stack_frame_vars(const int &p_size) {
1131
_remaining_vars = p_size;
1132
ERR_FAIL_COND(!scope_list.has(_current_frame));
1133
Vector<int> scope_ids = scope_list.find(_current_frame)->value;
1134
for (const int &var_id : scope_ids) {
1135
if (variable_list.has(var_id)) {
1136
variable_list.find(var_id)->value.clear();
1137
} else {
1138
variable_list.insert(var_id, Array());
1139
}
1140
}
1141
}
1142
1143
void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {
1144
DebuggerMarshalls::ScriptStackVariable stack_var;
1145
stack_var.deserialize(p_data);
1146
1147
ERR_FAIL_COND(!scope_list.has(_current_frame));
1148
Vector<int> scope_ids = scope_list.find(_current_frame)->value;
1149
1150
ERR_FAIL_COND(scope_ids.size() != 3);
1151
ERR_FAIL_INDEX(stack_var.type, 4);
1152
int var_id = scope_ids.get(stack_var.type);
1153
1154
DAP::Variable variable;
1155
1156
variable.name = stack_var.name;
1157
variable.value = stack_var.value;
1158
variable.type = Variant::get_type_name(stack_var.value.get_type());
1159
variable.variablesReference = parse_variant(stack_var.value);
1160
1161
variable_list.find(var_id)->value.push_back(variable.to_json());
1162
_remaining_vars--;
1163
}
1164
1165
void DebugAdapterProtocol::on_debug_data(const String &p_msg, const Array &p_data) {
1166
// Ignore data that is already handled by DAP
1167
if (p_msg == "debug_enter" || p_msg == "debug_exit" || p_msg == "stack_dump" || p_msg == "stack_frame_vars" || p_msg == "stack_frame_var" || p_msg == "output" || p_msg == "request_quit") {
1168
return;
1169
}
1170
1171
if (p_msg == "scene:inspect_objects") {
1172
if (!p_data.is_empty()) {
1173
// An object was requested from the debuggee; parse it.
1174
SceneDebuggerObject remote_obj;
1175
remote_obj.deserialize(p_data[0]);
1176
1177
parse_object(remote_obj);
1178
}
1179
#ifndef DISABLE_DEPRECATED
1180
} else if (p_msg == "scene:inspect_object") {
1181
if (!p_data.is_empty()) {
1182
// Legacy single object response format.
1183
SceneDebuggerObject remote_obj;
1184
remote_obj.deserialize(p_data);
1185
1186
parse_object(remote_obj);
1187
}
1188
#endif // DISABLE_DEPRECATED
1189
} else if (p_msg == "evaluation_return") {
1190
// An evaluation was requested from the debuggee; parse it.
1191
DebuggerMarshalls::ScriptStackVariable remote_evaluation;
1192
remote_evaluation.deserialize(p_data);
1193
1194
parse_evaluation(remote_evaluation);
1195
}
1196
1197
notify_custom_data(p_msg, p_data);
1198
}
1199
1200
void DebugAdapterProtocol::poll() {
1201
if (server->is_connection_available()) {
1202
on_client_connected();
1203
}
1204
List<Ref<DAPeer>> to_delete;
1205
for (const Ref<DAPeer> &peer : clients) {
1206
peer->connection->poll();
1207
StreamPeerTCP::Status status = peer->connection->get_status();
1208
if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
1209
to_delete.push_back(peer);
1210
} else {
1211
_current_peer = peer;
1212
Error err = peer->handle_data();
1213
if (err != OK && err != ERR_BUSY) {
1214
to_delete.push_back(peer);
1215
}
1216
err = peer->send_data();
1217
if (err != OK && err != ERR_BUSY) {
1218
to_delete.push_back(peer);
1219
}
1220
}
1221
}
1222
1223
for (const Ref<DAPeer> &peer : to_delete) {
1224
on_client_disconnected(peer);
1225
}
1226
to_delete.clear();
1227
}
1228
1229
Error DebugAdapterProtocol::start(int p_port, const IPAddress &p_bind_ip) {
1230
_request_timeout = (uint64_t)_EDITOR_GET("network/debug_adapter/request_timeout");
1231
_sync_breakpoints = (bool)_EDITOR_GET("network/debug_adapter/sync_breakpoints");
1232
_initialized = true;
1233
return server->listen(p_port, p_bind_ip);
1234
}
1235
1236
void DebugAdapterProtocol::stop() {
1237
for (const Ref<DAPeer> &peer : clients) {
1238
peer->connection->disconnect_from_host();
1239
}
1240
1241
clients.clear();
1242
server->stop();
1243
_initialized = false;
1244
}
1245
1246
DebugAdapterProtocol::DebugAdapterProtocol() {
1247
server.instantiate();
1248
singleton = this;
1249
parser = memnew(DebugAdapterParser);
1250
1251
reset_ids();
1252
1253
EditorRunBar::get_singleton()->get_pause_button()->connect(SceneStringName(pressed), callable_mp(this, &DebugAdapterProtocol::on_debug_paused));
1254
1255
EditorDebuggerNode *debugger_node = EditorDebuggerNode::get_singleton();
1256
debugger_node->connect("breakpoint_toggled", callable_mp(this, &DebugAdapterProtocol::on_debug_breakpoint_toggled));
1257
1258
debugger_node->get_default_debugger()->connect("stopped", callable_mp(this, &DebugAdapterProtocol::on_debug_stopped));
1259
debugger_node->get_default_debugger()->connect(SceneStringName(output), callable_mp(this, &DebugAdapterProtocol::on_debug_output));
1260
debugger_node->get_default_debugger()->connect("breaked", callable_mp(this, &DebugAdapterProtocol::on_debug_breaked));
1261
debugger_node->get_default_debugger()->connect("stack_dump", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_dump));
1262
debugger_node->get_default_debugger()->connect("stack_frame_vars", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_vars));
1263
debugger_node->get_default_debugger()->connect("stack_frame_var", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_var));
1264
debugger_node->get_default_debugger()->connect("debug_data", callable_mp(this, &DebugAdapterProtocol::on_debug_data));
1265
}
1266
1267
DebugAdapterProtocol::~DebugAdapterProtocol() {
1268
memdelete(parser);
1269
}
1270
1271