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 "editor/debugger/script_editor_debugger.h"
37#include "editor/doc_tools.h"
38#include "editor/editor_log.h"
39#include "editor/editor_node.h"
40#include "editor/editor_settings.h"
41#include "editor/gui/editor_run_bar.h"
42
43DebugAdapterProtocol *DebugAdapterProtocol::singleton = nullptr;
44
45Error 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;
70 header.parse_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;
97 msg.parse_utf8((const char *)req_buf, req_pos);
98
99 // Apply a timestamp if it there's none yet
100 if (!timestamp) {
101 timestamp = OS::get_singleton()->get_ticks_msec();
102 }
103
104 // Response
105 if (DebugAdapterProtocol::get_singleton()->process_message(msg)) {
106 // Reset to read again
107 req_pos = 0;
108 has_header = false;
109 timestamp = 0;
110 }
111 }
112 return OK;
113}
114
115Error DAPeer::send_data() {
116 while (res_queue.size()) {
117 Dictionary data = res_queue.front()->get();
118 if (!data.has("seq")) {
119 data["seq"] = ++seq;
120 }
121 String formatted_data = format_output(data);
122
123 int data_sent = 0;
124 while (data_sent < formatted_data.length()) {
125 int curr_sent = 0;
126 Error err = connection->put_partial_data((const uint8_t *)formatted_data.utf8().get_data(), formatted_data.size() - data_sent - 1, curr_sent);
127 if (err != OK) {
128 return err;
129 }
130 data_sent += curr_sent;
131 }
132 res_queue.pop_front();
133 }
134 return OK;
135}
136
137String DAPeer::format_output(const Dictionary &p_params) const {
138 String response = Variant(p_params).to_json_string();
139 String header = "Content-Length: ";
140 CharString charstr = response.utf8();
141 size_t len = charstr.length();
142 header += itos(len);
143 header += "\r\n\r\n";
144
145 return header + response;
146}
147
148Error DebugAdapterProtocol::on_client_connected() {
149 ERR_FAIL_COND_V_MSG(clients.size() >= DAP_MAX_CLIENTS, FAILED, "Max client limits reached");
150
151 Ref<StreamPeerTCP> tcp_peer = server->take_connection();
152 tcp_peer->set_no_delay(true);
153 Ref<DAPeer> peer = memnew(DAPeer);
154 peer->connection = tcp_peer;
155 clients.push_back(peer);
156
157 EditorDebuggerNode::get_singleton()->get_default_debugger()->set_move_to_foreground(false);
158 EditorNode::get_log()->add_message("[DAP] Connection Taken", EditorLog::MSG_TYPE_EDITOR);
159 return OK;
160}
161
162void DebugAdapterProtocol::on_client_disconnected(const Ref<DAPeer> &p_peer) {
163 clients.erase(p_peer);
164 if (!clients.size()) {
165 reset_ids();
166 EditorDebuggerNode::get_singleton()->get_default_debugger()->set_move_to_foreground(true);
167 }
168 EditorNode::get_log()->add_message("[DAP] Disconnected", EditorLog::MSG_TYPE_EDITOR);
169}
170
171void DebugAdapterProtocol::reset_current_info() {
172 _current_request = "";
173 _current_peer.unref();
174}
175
176void DebugAdapterProtocol::reset_ids() {
177 breakpoint_id = 0;
178 breakpoint_list.clear();
179
180 reset_stack_info();
181}
182
183void DebugAdapterProtocol::reset_stack_info() {
184 stackframe_id = 0;
185 variable_id = 1;
186
187 stackframe_list.clear();
188 variable_list.clear();
189}
190
191int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
192 switch (p_var.get_type()) {
193 case Variant::VECTOR2:
194 case Variant::VECTOR2I: {
195 int id = variable_id++;
196 Vector2 vec = p_var;
197 const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::VECTOR2 ? Variant::FLOAT : Variant::INT);
198 DAP::Variable x, y;
199 x.name = "x";
200 y.name = "y";
201 x.type = type_scalar;
202 y.type = type_scalar;
203 x.value = rtos(vec.x);
204 y.value = rtos(vec.y);
205
206 Array arr;
207 arr.push_back(x.to_json());
208 arr.push_back(y.to_json());
209 variable_list.insert(id, arr);
210 return id;
211 }
212 case Variant::RECT2:
213 case Variant::RECT2I: {
214 int id = variable_id++;
215 Rect2 rect = p_var;
216 const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::RECT2 ? Variant::FLOAT : Variant::INT);
217 DAP::Variable x, y, w, h;
218 x.name = "x";
219 y.name = "y";
220 w.name = "w";
221 h.name = "h";
222 x.type = type_scalar;
223 y.type = type_scalar;
224 w.type = type_scalar;
225 h.type = type_scalar;
226 x.value = rtos(rect.position.x);
227 y.value = rtos(rect.position.y);
228 w.value = rtos(rect.size.x);
229 h.value = rtos(rect.size.y);
230
231 Array arr;
232 arr.push_back(x.to_json());
233 arr.push_back(y.to_json());
234 arr.push_back(w.to_json());
235 arr.push_back(h.to_json());
236 variable_list.insert(id, arr);
237 return id;
238 }
239 case Variant::VECTOR3:
240 case Variant::VECTOR3I: {
241 int id = variable_id++;
242 Vector3 vec = p_var;
243 const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::VECTOR3 ? Variant::FLOAT : Variant::INT);
244 DAP::Variable x, y, z;
245 x.name = "x";
246 y.name = "y";
247 z.name = "z";
248 x.type = type_scalar;
249 y.type = type_scalar;
250 z.type = type_scalar;
251 x.value = rtos(vec.x);
252 y.value = rtos(vec.y);
253 z.value = rtos(vec.z);
254
255 Array arr;
256 arr.push_back(x.to_json());
257 arr.push_back(y.to_json());
258 arr.push_back(z.to_json());
259 variable_list.insert(id, arr);
260 return id;
261 }
262 case Variant::TRANSFORM2D: {
263 int id = variable_id++;
264 Transform2D transform = p_var;
265 const String type_vec2 = Variant::get_type_name(Variant::VECTOR2);
266 DAP::Variable x, y, origin;
267 x.name = "x";
268 y.name = "y";
269 origin.name = "origin";
270 x.type = type_vec2;
271 y.type = type_vec2;
272 origin.type = type_vec2;
273 x.value = transform.columns[0];
274 y.value = transform.columns[1];
275 origin.value = transform.columns[2];
276 x.variablesReference = parse_variant(transform.columns[0]);
277 y.variablesReference = parse_variant(transform.columns[1]);
278 origin.variablesReference = parse_variant(transform.columns[2]);
279
280 Array arr;
281 arr.push_back(x.to_json());
282 arr.push_back(y.to_json());
283 arr.push_back(origin.to_json());
284 variable_list.insert(id, arr);
285 return id;
286 }
287 case Variant::PLANE: {
288 int id = variable_id++;
289 Plane plane = p_var;
290 DAP::Variable d, normal;
291 d.name = "d";
292 normal.name = "normal";
293 d.type = Variant::get_type_name(Variant::FLOAT);
294 normal.type = Variant::get_type_name(Variant::VECTOR3);
295 d.value = rtos(plane.d);
296 normal.value = plane.normal;
297 normal.variablesReference = parse_variant(plane.normal);
298
299 Array arr;
300 arr.push_back(d.to_json());
301 arr.push_back(normal.to_json());
302 variable_list.insert(id, arr);
303 return id;
304 }
305 case Variant::QUATERNION: {
306 int id = variable_id++;
307 Quaternion quat = p_var;
308 const String type_float = Variant::get_type_name(Variant::FLOAT);
309 DAP::Variable x, y, z, w;
310 x.name = "x";
311 y.name = "y";
312 z.name = "z";
313 w.name = "w";
314 x.type = type_float;
315 y.type = type_float;
316 z.type = type_float;
317 w.type = type_float;
318 x.value = rtos(quat.x);
319 y.value = rtos(quat.y);
320 z.value = rtos(quat.z);
321 w.value = rtos(quat.w);
322
323 Array arr;
324 arr.push_back(x.to_json());
325 arr.push_back(y.to_json());
326 arr.push_back(z.to_json());
327 arr.push_back(w.to_json());
328 variable_list.insert(id, arr);
329 return id;
330 }
331 case Variant::AABB: {
332 int id = variable_id++;
333 AABB aabb = p_var;
334 const String type_vec3 = Variant::get_type_name(Variant::VECTOR3);
335 DAP::Variable position, size;
336 position.name = "position";
337 size.name = "size";
338 position.type = type_vec3;
339 size.type = type_vec3;
340 position.value = aabb.position;
341 size.value = aabb.size;
342 position.variablesReference = parse_variant(aabb.position);
343 size.variablesReference = parse_variant(aabb.size);
344
345 Array arr;
346 arr.push_back(position.to_json());
347 arr.push_back(size.to_json());
348 variable_list.insert(id, arr);
349 return id;
350 }
351 case Variant::BASIS: {
352 int id = variable_id++;
353 Basis basis = p_var;
354 const String type_vec3 = Variant::get_type_name(Variant::VECTOR3);
355 DAP::Variable x, y, z;
356 x.name = "x";
357 y.name = "y";
358 z.name = "z";
359 x.type = type_vec3;
360 y.type = type_vec3;
361 z.type = type_vec3;
362 x.value = basis.rows[0];
363 y.value = basis.rows[1];
364 z.value = basis.rows[2];
365 x.variablesReference = parse_variant(basis.rows[0]);
366 y.variablesReference = parse_variant(basis.rows[1]);
367 z.variablesReference = parse_variant(basis.rows[2]);
368
369 Array arr;
370 arr.push_back(x.to_json());
371 arr.push_back(y.to_json());
372 arr.push_back(z.to_json());
373 variable_list.insert(id, arr);
374 return id;
375 }
376 case Variant::TRANSFORM3D: {
377 int id = variable_id++;
378 Transform3D transform = p_var;
379 DAP::Variable basis, origin;
380 basis.name = "basis";
381 origin.name = "origin";
382 basis.type = Variant::get_type_name(Variant::BASIS);
383 origin.type = Variant::get_type_name(Variant::VECTOR3);
384 basis.value = transform.basis;
385 origin.value = transform.origin;
386 basis.variablesReference = parse_variant(transform.basis);
387 origin.variablesReference = parse_variant(transform.origin);
388
389 Array arr;
390 arr.push_back(basis.to_json());
391 arr.push_back(origin.to_json());
392 variable_list.insert(id, arr);
393 return id;
394 }
395 case Variant::COLOR: {
396 int id = variable_id++;
397 Color color = p_var;
398 const String type_float = Variant::get_type_name(Variant::FLOAT);
399 DAP::Variable r, g, b, a;
400 r.name = "r";
401 g.name = "g";
402 b.name = "b";
403 a.name = "a";
404 r.type = type_float;
405 g.type = type_float;
406 b.type = type_float;
407 a.type = type_float;
408 r.value = rtos(color.r);
409 g.value = rtos(color.g);
410 b.value = rtos(color.b);
411 a.value = rtos(color.a);
412
413 Array arr;
414 arr.push_back(r.to_json());
415 arr.push_back(g.to_json());
416 arr.push_back(b.to_json());
417 arr.push_back(a.to_json());
418 variable_list.insert(id, arr);
419 return id;
420 }
421 case Variant::ARRAY: {
422 int id = variable_id++;
423 Array array = p_var;
424 DAP::Variable size;
425 size.name = "size";
426 size.type = Variant::get_type_name(Variant::INT);
427 size.value = itos(array.size());
428
429 Array arr;
430 arr.push_back(size.to_json());
431
432 for (int i = 0; i < array.size(); i++) {
433 DAP::Variable var;
434 var.name = itos(i);
435 var.type = Variant::get_type_name(array[i].get_type());
436 var.value = array[i];
437 var.variablesReference = parse_variant(array[i]);
438 arr.push_back(var.to_json());
439 }
440 variable_list.insert(id, arr);
441 return id;
442 }
443 case Variant::DICTIONARY: {
444 int id = variable_id++;
445 Dictionary dictionary = p_var;
446 Array arr;
447
448 for (int i = 0; i < dictionary.size(); i++) {
449 DAP::Variable var;
450 var.name = dictionary.get_key_at_index(i);
451 Variant value = dictionary.get_value_at_index(i);
452 var.type = Variant::get_type_name(value.get_type());
453 var.value = value;
454 var.variablesReference = parse_variant(value);
455 arr.push_back(var.to_json());
456 }
457 variable_list.insert(id, arr);
458 return id;
459 }
460 case Variant::PACKED_BYTE_ARRAY: {
461 int id = variable_id++;
462 PackedByteArray array = p_var;
463 DAP::Variable size;
464 size.name = "size";
465 size.type = Variant::get_type_name(Variant::INT);
466 size.value = itos(array.size());
467
468 Array arr;
469 arr.push_back(size.to_json());
470
471 for (int i = 0; i < array.size(); i++) {
472 DAP::Variable var;
473 var.name = itos(i);
474 var.type = "byte";
475 var.value = itos(array[i]);
476 arr.push_back(var.to_json());
477 }
478 variable_list.insert(id, arr);
479 return id;
480 }
481 case Variant::PACKED_INT32_ARRAY: {
482 int id = variable_id++;
483 PackedInt32Array array = p_var;
484 DAP::Variable size;
485 size.name = "size";
486 size.type = Variant::get_type_name(Variant::INT);
487 size.value = itos(array.size());
488
489 Array arr;
490 arr.push_back(size.to_json());
491
492 for (int i = 0; i < array.size(); i++) {
493 DAP::Variable var;
494 var.name = itos(i);
495 var.type = "int";
496 var.value = itos(array[i]);
497 arr.push_back(var.to_json());
498 }
499 variable_list.insert(id, arr);
500 return id;
501 }
502 case Variant::PACKED_INT64_ARRAY: {
503 int id = variable_id++;
504 PackedInt64Array array = p_var;
505 DAP::Variable size;
506 size.name = "size";
507 size.type = Variant::get_type_name(Variant::INT);
508 size.value = itos(array.size());
509
510 Array arr;
511 arr.push_back(size.to_json());
512
513 for (int i = 0; i < array.size(); i++) {
514 DAP::Variable var;
515 var.name = itos(i);
516 var.type = "long";
517 var.value = itos(array[i]);
518 arr.push_back(var.to_json());
519 }
520 variable_list.insert(id, arr);
521 return id;
522 }
523 case Variant::PACKED_FLOAT32_ARRAY: {
524 int id = variable_id++;
525 PackedFloat32Array array = p_var;
526 DAP::Variable size;
527 size.name = "size";
528 size.type = Variant::get_type_name(Variant::INT);
529 size.value = itos(array.size());
530
531 Array arr;
532 arr.push_back(size.to_json());
533
534 for (int i = 0; i < array.size(); i++) {
535 DAP::Variable var;
536 var.name = itos(i);
537 var.type = "float";
538 var.value = rtos(array[i]);
539 arr.push_back(var.to_json());
540 }
541 variable_list.insert(id, arr);
542 return id;
543 }
544 case Variant::PACKED_FLOAT64_ARRAY: {
545 int id = variable_id++;
546 PackedFloat64Array array = p_var;
547 DAP::Variable size;
548 size.name = "size";
549 size.type = Variant::get_type_name(Variant::INT);
550 size.value = itos(array.size());
551
552 Array arr;
553 arr.push_back(size.to_json());
554
555 for (int i = 0; i < array.size(); i++) {
556 DAP::Variable var;
557 var.name = itos(i);
558 var.type = "double";
559 var.value = rtos(array[i]);
560 arr.push_back(var.to_json());
561 }
562 variable_list.insert(id, arr);
563 return id;
564 }
565 case Variant::PACKED_STRING_ARRAY: {
566 int id = variable_id++;
567 PackedStringArray array = p_var;
568 DAP::Variable size;
569 size.name = "size";
570 size.type = Variant::get_type_name(Variant::INT);
571 size.value = itos(array.size());
572
573 Array arr;
574 arr.push_back(size.to_json());
575
576 for (int i = 0; i < array.size(); i++) {
577 DAP::Variable var;
578 var.name = itos(i);
579 var.type = Variant::get_type_name(Variant::STRING);
580 var.value = array[i];
581 arr.push_back(var.to_json());
582 }
583 variable_list.insert(id, arr);
584 return id;
585 }
586 case Variant::PACKED_VECTOR2_ARRAY: {
587 int id = variable_id++;
588 PackedVector2Array array = p_var;
589 DAP::Variable size;
590 size.name = "size";
591 size.type = Variant::get_type_name(Variant::INT);
592 size.value = itos(array.size());
593
594 Array arr;
595 arr.push_back(size.to_json());
596
597 for (int i = 0; i < array.size(); i++) {
598 DAP::Variable var;
599 var.name = itos(i);
600 var.type = Variant::get_type_name(Variant::VECTOR2);
601 var.value = array[i];
602 var.variablesReference = parse_variant(array[i]);
603 arr.push_back(var.to_json());
604 }
605 variable_list.insert(id, arr);
606 return id;
607 }
608 case Variant::PACKED_VECTOR3_ARRAY: {
609 int id = variable_id++;
610 PackedVector2Array array = p_var;
611 DAP::Variable size;
612 size.name = "size";
613 size.type = Variant::get_type_name(Variant::INT);
614 size.value = itos(array.size());
615
616 Array arr;
617 arr.push_back(size.to_json());
618
619 for (int i = 0; i < array.size(); i++) {
620 DAP::Variable var;
621 var.name = itos(i);
622 var.type = Variant::get_type_name(Variant::VECTOR3);
623 var.value = array[i];
624 var.variablesReference = parse_variant(array[i]);
625 arr.push_back(var.to_json());
626 }
627 variable_list.insert(id, arr);
628 return id;
629 }
630 case Variant::PACKED_COLOR_ARRAY: {
631 int id = variable_id++;
632 PackedColorArray array = p_var;
633 DAP::Variable size;
634 size.name = "size";
635 size.type = Variant::get_type_name(Variant::INT);
636 size.value = itos(array.size());
637
638 Array arr;
639 arr.push_back(size.to_json());
640
641 for (int i = 0; i < array.size(); i++) {
642 DAP::Variable var;
643 var.name = itos(i);
644 var.type = Variant::get_type_name(Variant::COLOR);
645 var.value = array[i];
646 var.variablesReference = parse_variant(array[i]);
647 arr.push_back(var.to_json());
648 }
649 variable_list.insert(id, arr);
650 return id;
651 }
652 default:
653 // Simple atomic stuff, or too complex to be manipulated
654 return 0;
655 }
656}
657
658bool DebugAdapterProtocol::process_message(const String &p_text) {
659 JSON json;
660 ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");
661 Dictionary params = json.get_data();
662 bool completed = true;
663
664 if (OS::get_singleton()->get_ticks_msec() - _current_peer->timestamp > _request_timeout) {
665 Dictionary response = parser->prepare_error_response(params, DAP::ErrorType::TIMEOUT);
666 _current_peer->res_queue.push_front(response);
667 return true;
668 }
669
670 // Append "req_" to any command received; prevents name clash with existing functions, and possibly exploiting
671 String command = "req_" + (String)params["command"];
672 if (parser->has_method(command)) {
673 _current_request = params["command"];
674
675 Array args;
676 args.push_back(params);
677 Dictionary response = parser->callv(command, args);
678 if (!response.is_empty()) {
679 _current_peer->res_queue.push_front(response);
680 } else {
681 completed = false;
682 }
683 }
684
685 reset_current_info();
686 return completed;
687}
688
689void DebugAdapterProtocol::notify_initialized() {
690 Dictionary event = parser->ev_initialized();
691 _current_peer->res_queue.push_back(event);
692}
693
694void DebugAdapterProtocol::notify_process() {
695 String launch_mode = _current_peer->attached ? "attach" : "launch";
696
697 Dictionary event = parser->ev_process(launch_mode);
698 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
699 E->get()->res_queue.push_back(event);
700 }
701}
702
703void DebugAdapterProtocol::notify_terminated() {
704 Dictionary event = parser->ev_terminated();
705 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
706 if ((_current_request == "launch" || _current_request == "restart") && _current_peer == E->get()) {
707 continue;
708 }
709 E->get()->res_queue.push_back(event);
710 }
711}
712
713void DebugAdapterProtocol::notify_exited(const int &p_exitcode) {
714 Dictionary event = parser->ev_exited(p_exitcode);
715 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
716 if ((_current_request == "launch" || _current_request == "restart") && _current_peer == E->get()) {
717 continue;
718 }
719 E->get()->res_queue.push_back(event);
720 }
721}
722
723void DebugAdapterProtocol::notify_stopped_paused() {
724 Dictionary event = parser->ev_stopped_paused();
725 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
726 E->get()->res_queue.push_back(event);
727 }
728}
729
730void DebugAdapterProtocol::notify_stopped_exception(const String &p_error) {
731 Dictionary event = parser->ev_stopped_exception(p_error);
732 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
733 E->get()->res_queue.push_back(event);
734 }
735}
736
737void DebugAdapterProtocol::notify_stopped_breakpoint(const int &p_id) {
738 Dictionary event = parser->ev_stopped_breakpoint(p_id);
739 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
740 E->get()->res_queue.push_back(event);
741 }
742}
743
744void DebugAdapterProtocol::notify_stopped_step() {
745 Dictionary event = parser->ev_stopped_step();
746 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
747 E->get()->res_queue.push_back(event);
748 }
749}
750
751void DebugAdapterProtocol::notify_continued() {
752 Dictionary event = parser->ev_continued();
753 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
754 if (_current_request == "continue" && E->get() == _current_peer) {
755 continue;
756 }
757 E->get()->res_queue.push_back(event);
758 }
759
760 reset_stack_info();
761}
762
763void DebugAdapterProtocol::notify_output(const String &p_message) {
764 Dictionary event = parser->ev_output(p_message);
765 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
766 E->get()->res_queue.push_back(event);
767 }
768}
769
770void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &p_data) {
771 Dictionary event = parser->ev_custom_data(p_msg, p_data);
772 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
773 Ref<DAPeer> peer = E->get();
774 if (peer->supportsCustomData) {
775 peer->res_queue.push_back(event);
776 }
777 }
778}
779
780void DebugAdapterProtocol::notify_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) {
781 Dictionary event = parser->ev_breakpoint(p_breakpoint, p_enabled);
782 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
783 if (_current_request == "setBreakpoints" && E->get() == _current_peer) {
784 continue;
785 }
786 E->get()->res_queue.push_back(event);
787 }
788}
789
790Array DebugAdapterProtocol::update_breakpoints(const String &p_path, const Array &p_lines) {
791 Array updated_breakpoints;
792
793 // Add breakpoints
794 for (int i = 0; i < p_lines.size(); i++) {
795 EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);
796 DAP::Breakpoint breakpoint;
797 breakpoint.line = p_lines[i];
798 breakpoint.source.path = p_path;
799
800 ERR_FAIL_COND_V(!breakpoint_list.find(breakpoint), Array());
801 updated_breakpoints.push_back(breakpoint_list.find(breakpoint)->get().to_json());
802 }
803
804 // Remove breakpoints
805 for (List<DAP::Breakpoint>::Element *E = breakpoint_list.front(); E; E = E->next()) {
806 DAP::Breakpoint b = E->get();
807 if (b.source.path == p_path && !p_lines.has(b.line)) {
808 EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, b.line, false);
809 }
810 }
811
812 return updated_breakpoints;
813}
814
815void DebugAdapterProtocol::on_debug_paused() {
816 if (EditorRunBar::get_singleton()->get_pause_button()->is_pressed()) {
817 notify_stopped_paused();
818 } else {
819 notify_continued();
820 }
821}
822
823void DebugAdapterProtocol::on_debug_stopped() {
824 notify_exited();
825 notify_terminated();
826}
827
828void DebugAdapterProtocol::on_debug_output(const String &p_message) {
829 notify_output(p_message);
830}
831
832void DebugAdapterProtocol::on_debug_breaked(const bool &p_reallydid, const bool &p_can_debug, const String &p_reason, const bool &p_has_stackdump) {
833 if (!p_reallydid) {
834 notify_continued();
835 return;
836 }
837
838 if (p_reason == "Breakpoint") {
839 if (_stepping) {
840 notify_stopped_step();
841 _stepping = false;
842 } else {
843 _processing_breakpoint = true; // Wait for stack_dump to find where the breakpoint happened
844 }
845 } else {
846 notify_stopped_exception(p_reason);
847 }
848
849 _processing_stackdump = p_has_stackdump;
850}
851
852void DebugAdapterProtocol::on_debug_breakpoint_toggled(const String &p_path, const int &p_line, const bool &p_enabled) {
853 DAP::Breakpoint breakpoint;
854 breakpoint.verified = true;
855 breakpoint.source.path = ProjectSettings::get_singleton()->globalize_path(p_path);
856 breakpoint.source.compute_checksums();
857 breakpoint.line = p_line;
858
859 if (p_enabled) {
860 // Add the breakpoint
861 breakpoint.id = breakpoint_id++;
862 breakpoint_list.push_back(breakpoint);
863 } else {
864 // Remove the breakpoint
865 List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
866 if (E) {
867 breakpoint.id = E->get().id;
868 breakpoint_list.erase(E);
869 }
870 }
871
872 notify_breakpoint(breakpoint, p_enabled);
873}
874
875void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
876 if (_processing_breakpoint && !p_stack_dump.is_empty()) {
877 // Find existing breakpoint
878 Dictionary d = p_stack_dump[0];
879 DAP::Breakpoint breakpoint;
880 breakpoint.source.path = ProjectSettings::get_singleton()->globalize_path(d["file"]);
881 breakpoint.line = d["line"];
882
883 List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
884 if (E) {
885 notify_stopped_breakpoint(E->get().id);
886 }
887
888 _processing_breakpoint = false;
889 }
890
891 stackframe_id = 0;
892 stackframe_list.clear();
893
894 // Fill in stacktrace information
895 for (int i = 0; i < p_stack_dump.size(); i++) {
896 Dictionary stack_info = p_stack_dump[i];
897 DAP::StackFrame stackframe;
898 stackframe.id = stackframe_id++;
899 stackframe.name = stack_info["function"];
900 stackframe.line = stack_info["line"];
901 stackframe.column = 0;
902 stackframe.source.path = ProjectSettings::get_singleton()->globalize_path(stack_info["file"]);
903 stackframe.source.compute_checksums();
904
905 // Information for "Locals", "Members" and "Globals" variables respectively
906 List<int> scope_ids;
907 for (int j = 0; j < 3; j++) {
908 scope_ids.push_back(variable_id++);
909 }
910
911 stackframe_list.insert(stackframe, scope_ids);
912 }
913
914 _current_frame = 0;
915 _processing_stackdump = false;
916}
917
918void DebugAdapterProtocol::on_debug_stack_frame_vars(const int &p_size) {
919 _remaining_vars = p_size;
920 DAP::StackFrame frame;
921 frame.id = _current_frame;
922 ERR_FAIL_COND(!stackframe_list.has(frame));
923 List<int> scope_ids = stackframe_list.find(frame)->value;
924 for (List<int>::Element *E = scope_ids.front(); E; E = E->next()) {
925 int var_id = E->get();
926 if (variable_list.has(var_id)) {
927 variable_list.find(var_id)->value.clear();
928 } else {
929 variable_list.insert(var_id, Array());
930 }
931 }
932}
933
934void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {
935 DebuggerMarshalls::ScriptStackVariable stack_var;
936 stack_var.deserialize(p_data);
937
938 ERR_FAIL_COND(stackframe_list.is_empty());
939 DAP::StackFrame frame;
940 frame.id = _current_frame;
941
942 List<int> scope_ids = stackframe_list.find(frame)->value;
943 ERR_FAIL_COND(scope_ids.size() != 3);
944 ERR_FAIL_INDEX(stack_var.type, 3);
945 int var_id = scope_ids[stack_var.type];
946
947 DAP::Variable variable;
948
949 variable.name = stack_var.name;
950 variable.value = stack_var.value;
951 variable.type = Variant::get_type_name(stack_var.value.get_type());
952 variable.variablesReference = parse_variant(stack_var.value);
953
954 variable_list.find(var_id)->value.push_back(variable.to_json());
955 _remaining_vars--;
956}
957
958void DebugAdapterProtocol::on_debug_data(const String &p_msg, const Array &p_data) {
959 // Ignore data that is already handled by DAP
960 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") {
961 return;
962 }
963
964 notify_custom_data(p_msg, p_data);
965}
966
967void DebugAdapterProtocol::poll() {
968 if (server->is_connection_available()) {
969 on_client_connected();
970 }
971 List<Ref<DAPeer>> to_delete;
972 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
973 Ref<DAPeer> peer = E->get();
974 peer->connection->poll();
975 StreamPeerTCP::Status status = peer->connection->get_status();
976 if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
977 to_delete.push_back(peer);
978 } else {
979 _current_peer = peer;
980 Error err = peer->handle_data();
981 if (err != OK && err != ERR_BUSY) {
982 to_delete.push_back(peer);
983 }
984 err = peer->send_data();
985 if (err != OK && err != ERR_BUSY) {
986 to_delete.push_back(peer);
987 }
988 }
989 }
990
991 for (List<Ref<DAPeer>>::Element *E = to_delete.front(); E; E = E->next()) {
992 on_client_disconnected(E->get());
993 }
994 to_delete.clear();
995}
996
997Error DebugAdapterProtocol::start(int p_port, const IPAddress &p_bind_ip) {
998 _request_timeout = (uint64_t)_EDITOR_GET("network/debug_adapter/request_timeout");
999 _sync_breakpoints = (bool)_EDITOR_GET("network/debug_adapter/sync_breakpoints");
1000 _initialized = true;
1001 return server->listen(p_port, p_bind_ip);
1002}
1003
1004void DebugAdapterProtocol::stop() {
1005 for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
1006 E->get()->connection->disconnect_from_host();
1007 }
1008
1009 clients.clear();
1010 server->stop();
1011 _initialized = false;
1012}
1013
1014DebugAdapterProtocol::DebugAdapterProtocol() {
1015 server.instantiate();
1016 singleton = this;
1017 parser = memnew(DebugAdapterParser);
1018
1019 reset_ids();
1020
1021 EditorRunBar::get_singleton()->get_pause_button()->connect("pressed", callable_mp(this, &DebugAdapterProtocol::on_debug_paused));
1022
1023 EditorDebuggerNode *debugger_node = EditorDebuggerNode::get_singleton();
1024 debugger_node->connect("breakpoint_toggled", callable_mp(this, &DebugAdapterProtocol::on_debug_breakpoint_toggled));
1025
1026 debugger_node->get_default_debugger()->connect("stopped", callable_mp(this, &DebugAdapterProtocol::on_debug_stopped));
1027 debugger_node->get_default_debugger()->connect("output", callable_mp(this, &DebugAdapterProtocol::on_debug_output));
1028 debugger_node->get_default_debugger()->connect("breaked", callable_mp(this, &DebugAdapterProtocol::on_debug_breaked));
1029 debugger_node->get_default_debugger()->connect("stack_dump", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_dump));
1030 debugger_node->get_default_debugger()->connect("stack_frame_vars", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_vars));
1031 debugger_node->get_default_debugger()->connect("stack_frame_var", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_var));
1032 debugger_node->get_default_debugger()->connect("debug_data", callable_mp(this, &DebugAdapterProtocol::on_debug_data));
1033}
1034
1035DebugAdapterProtocol::~DebugAdapterProtocol() {
1036 memdelete(parser);
1037}
1038