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