Path: blob/master/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
20844 views
/**************************************************************************/1/* debug_adapter_protocol.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "debug_adapter_protocol.h"3132#include "core/config/project_settings.h"33#include "core/debugger/debugger_marshalls.h"34#include "core/io/json.h"35#include "core/io/marshalls.h"36#include "editor/debugger/debug_adapter/debug_adapter_parser.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"4243DebugAdapterProtocol *DebugAdapterProtocol::singleton = nullptr;4445Error DAPeer::handle_data() {46int read = 0;47// Read headers48if (!has_header) {49if (!connection->get_available_bytes()) {50return OK;51}52while (true) {53if (req_pos >= DAP_MAX_BUFFER_SIZE) {54req_pos = 0;55ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Response header too big");56}57Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);58if (err != OK) {59return FAILED;60} else if (read != 1) { // Busy, wait until next poll61return ERR_BUSY;62}63char *r = (char *)req_buf;64int l = req_pos;6566// End of headers67if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {68r[l - 3] = '\0'; // Null terminate to read string69String header = String::utf8(r);70content_length = header.substr(16).to_int();71has_header = true;72req_pos = 0;73break;74}75req_pos++;76}77}78if (has_header) {79while (req_pos < content_length) {80if (content_length >= DAP_MAX_BUFFER_SIZE) {81req_pos = 0;82has_header = false;83ERR_FAIL_COND_V_MSG(req_pos >= DAP_MAX_BUFFER_SIZE, ERR_OUT_OF_MEMORY, "Response content too big");84}85Error err = connection->get_partial_data(&req_buf[req_pos], content_length - req_pos, read);86if (err != OK) {87return FAILED;88} else if (read < content_length - req_pos) {89return ERR_BUSY;90}91req_pos += read;92}9394// Parse data95String msg = String::utf8((const char *)req_buf, req_pos);9697// Apply a timestamp if it there's none yet98if (!timestamp) {99timestamp = OS::get_singleton()->get_ticks_msec();100}101102// Response103if (DebugAdapterProtocol::get_singleton()->process_message(msg)) {104// Reset to read again105req_pos = 0;106has_header = false;107timestamp = 0;108}109}110return OK;111}112113Error DAPeer::send_data() {114while (res_queue.size()) {115Dictionary data = res_queue.front()->get();116if (!data.has("seq")) {117data["seq"] = ++seq;118}119const Vector<uint8_t> &formatted_data = format_output(data);120121int data_sent = 0;122while (data_sent < formatted_data.size()) {123int curr_sent = 0;124Error err = connection->put_partial_data(formatted_data.ptr() + data_sent, formatted_data.size() - data_sent, curr_sent);125if (err != OK) {126return err;127}128data_sent += curr_sent;129}130res_queue.pop_front();131}132return OK;133}134135Vector<uint8_t> DAPeer::format_output(const Dictionary &p_params) const {136const Vector<uint8_t> &content = Variant(p_params).to_json_string().to_utf8_buffer();137Vector<uint8_t> response = vformat("Content-Length: %d\r\n\r\n", content.size()).to_utf8_buffer();138139response.append_array(content);140return response;141}142143Error DebugAdapterProtocol::on_client_connected() {144ERR_FAIL_COND_V_MSG(clients.size() >= DAP_MAX_CLIENTS, FAILED, "Max client limits reached");145146Ref<StreamPeerTCP> tcp_peer = server->take_connection();147ERR_FAIL_COND_V_MSG(tcp_peer.is_null(), FAILED, "Failed to take incoming DAP connection.");148tcp_peer->set_no_delay(true);149Ref<DAPeer> peer = memnew(DAPeer);150peer->connection = tcp_peer;151clients.push_back(peer);152153EditorDebuggerNode::get_singleton()->get_default_debugger()->set_move_to_foreground(false);154EditorNode::get_log()->add_message("[DAP] Connection Taken", EditorLog::MSG_TYPE_EDITOR);155return OK;156}157158void DebugAdapterProtocol::on_client_disconnected(const Ref<DAPeer> &p_peer) {159clients.erase(p_peer);160if (!clients.size()) {161reset_ids();162EditorDebuggerNode::get_singleton()->get_default_debugger()->set_move_to_foreground(true);163}164EditorNode::get_log()->add_message("[DAP] Disconnected", EditorLog::MSG_TYPE_EDITOR);165}166167void DebugAdapterProtocol::reset_current_info() {168_current_request = "";169_current_peer.unref();170}171172void DebugAdapterProtocol::reset_ids() {173breakpoint_id = 0;174breakpoint_list.clear();175breakpoint_source_list.clear();176177reset_stack_info();178}179180void DebugAdapterProtocol::reset_stack_info() {181stackframe_id = 0;182variable_id = 1;183184stackframe_list.clear();185scope_list.clear();186variable_list.clear();187object_list.clear();188object_pending_set.clear();189}190191int DebugAdapterProtocol::parse_variant(const Variant &p_var) {192switch (p_var.get_type()) {193case Variant::VECTOR2:194case Variant::VECTOR2I: {195int id = variable_id++;196Vector2 vec = p_var;197const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::VECTOR2 ? Variant::FLOAT : Variant::INT);198DAP::Variable x, y;199x.name = "x";200y.name = "y";201x.type = type_scalar;202y.type = type_scalar;203x.value = rtos(vec.x);204y.value = rtos(vec.y);205206Array arr = { x.to_json(), y.to_json() };207variable_list.insert(id, arr);208return id;209}210case Variant::RECT2:211case Variant::RECT2I: {212int id = variable_id++;213Rect2 rect = p_var;214const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::RECT2 ? Variant::FLOAT : Variant::INT);215DAP::Variable x, y, w, h;216x.name = "x";217y.name = "y";218w.name = "w";219h.name = "h";220x.type = type_scalar;221y.type = type_scalar;222w.type = type_scalar;223h.type = type_scalar;224x.value = rtos(rect.position.x);225y.value = rtos(rect.position.y);226w.value = rtos(rect.size.x);227h.value = rtos(rect.size.y);228229Array arr = { x.to_json(), y.to_json(), w.to_json(), h.to_json() };230variable_list.insert(id, arr);231return id;232}233case Variant::VECTOR3:234case Variant::VECTOR3I: {235int id = variable_id++;236Vector3 vec = p_var;237const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::VECTOR3 ? Variant::FLOAT : Variant::INT);238DAP::Variable x, y, z;239x.name = "x";240y.name = "y";241z.name = "z";242x.type = type_scalar;243y.type = type_scalar;244z.type = type_scalar;245x.value = rtos(vec.x);246y.value = rtos(vec.y);247z.value = rtos(vec.z);248249Array arr = { x.to_json(), y.to_json(), z.to_json() };250variable_list.insert(id, arr);251return id;252}253case Variant::TRANSFORM2D: {254int id = variable_id++;255Transform2D transform = p_var;256const String type_vec2 = Variant::get_type_name(Variant::VECTOR2);257DAP::Variable x, y, origin;258x.name = "x";259y.name = "y";260origin.name = "origin";261x.type = type_vec2;262y.type = type_vec2;263origin.type = type_vec2;264x.value = String(transform.columns[0]);265y.value = String(transform.columns[1]);266origin.value = String(transform.columns[2]);267x.variablesReference = parse_variant(transform.columns[0]);268y.variablesReference = parse_variant(transform.columns[1]);269origin.variablesReference = parse_variant(transform.columns[2]);270271Array arr = { x.to_json(), y.to_json(), origin.to_json() };272variable_list.insert(id, arr);273return id;274}275case Variant::PLANE: {276int id = variable_id++;277Plane plane = p_var;278DAP::Variable d, normal;279d.name = "d";280normal.name = "normal";281d.type = Variant::get_type_name(Variant::FLOAT);282normal.type = Variant::get_type_name(Variant::VECTOR3);283d.value = rtos(plane.d);284normal.value = String(plane.normal);285normal.variablesReference = parse_variant(plane.normal);286287Array arr = { d.to_json(), normal.to_json() };288variable_list.insert(id, arr);289return id;290}291case Variant::QUATERNION: {292int id = variable_id++;293Quaternion quat = p_var;294const String type_float = Variant::get_type_name(Variant::FLOAT);295DAP::Variable x, y, z, w;296x.name = "x";297y.name = "y";298z.name = "z";299w.name = "w";300x.type = type_float;301y.type = type_float;302z.type = type_float;303w.type = type_float;304x.value = rtos(quat.x);305y.value = rtos(quat.y);306z.value = rtos(quat.z);307w.value = rtos(quat.w);308309Array arr = { x.to_json(), y.to_json(), z.to_json(), w.to_json() };310variable_list.insert(id, arr);311return id;312}313case Variant::AABB: {314int id = variable_id++;315AABB aabb = p_var;316const String type_vec3 = Variant::get_type_name(Variant::VECTOR3);317DAP::Variable position, size;318position.name = "position";319size.name = "size";320position.type = type_vec3;321size.type = type_vec3;322position.value = String(aabb.position);323size.value = String(aabb.size);324position.variablesReference = parse_variant(aabb.position);325size.variablesReference = parse_variant(aabb.size);326327Array arr = { position.to_json(), size.to_json() };328variable_list.insert(id, arr);329return id;330}331case Variant::BASIS: {332int id = variable_id++;333Basis basis = p_var;334const String type_vec3 = Variant::get_type_name(Variant::VECTOR3);335DAP::Variable x, y, z;336x.name = "x";337y.name = "y";338z.name = "z";339x.type = type_vec3;340y.type = type_vec3;341z.type = type_vec3;342x.value = String(basis.rows[0]);343y.value = String(basis.rows[1]);344z.value = String(basis.rows[2]);345x.variablesReference = parse_variant(basis.rows[0]);346y.variablesReference = parse_variant(basis.rows[1]);347z.variablesReference = parse_variant(basis.rows[2]);348349Array arr = { x.to_json(), y.to_json(), z.to_json() };350variable_list.insert(id, arr);351return id;352}353case Variant::TRANSFORM3D: {354int id = variable_id++;355Transform3D transform = p_var;356DAP::Variable basis, origin;357basis.name = "basis";358origin.name = "origin";359basis.type = Variant::get_type_name(Variant::BASIS);360origin.type = Variant::get_type_name(Variant::VECTOR3);361basis.value = String(transform.basis);362origin.value = String(transform.origin);363basis.variablesReference = parse_variant(transform.basis);364origin.variablesReference = parse_variant(transform.origin);365366Array arr = { basis.to_json(), origin.to_json() };367variable_list.insert(id, arr);368return id;369}370case Variant::COLOR: {371int id = variable_id++;372Color color = p_var;373const String type_float = Variant::get_type_name(Variant::FLOAT);374DAP::Variable r, g, b, a;375r.name = "r";376g.name = "g";377b.name = "b";378a.name = "a";379r.type = type_float;380g.type = type_float;381b.type = type_float;382a.type = type_float;383r.value = rtos(color.r);384g.value = rtos(color.g);385b.value = rtos(color.b);386a.value = rtos(color.a);387388Array arr = { r.to_json(), g.to_json(), b.to_json(), a.to_json() };389variable_list.insert(id, arr);390return id;391}392case Variant::ARRAY: {393int id = variable_id++;394Array array = p_var;395DAP::Variable size;396size.name = "size";397size.type = Variant::get_type_name(Variant::INT);398size.value = itos(array.size());399400Array arr = { size.to_json() };401402for (int i = 0; i < array.size(); i++) {403DAP::Variable var;404var.name = itos(i);405var.type = Variant::get_type_name(array[i].get_type());406var.value = array[i];407var.variablesReference = parse_variant(array[i]);408arr.push_back(var.to_json());409}410variable_list.insert(id, arr);411return id;412}413case Variant::DICTIONARY: {414int id = variable_id++;415Dictionary dictionary = p_var;416Array arr;417418for (const KeyValue<Variant, Variant> &kv : dictionary) {419DAP::Variable var;420var.name = kv.key;421Variant value = kv.value;422var.type = Variant::get_type_name(value.get_type());423var.value = value;424var.variablesReference = parse_variant(value);425arr.push_back(var.to_json());426}427variable_list.insert(id, arr);428return id;429}430case Variant::PACKED_BYTE_ARRAY: {431int id = variable_id++;432PackedByteArray array = p_var;433DAP::Variable size;434size.name = "size";435size.type = Variant::get_type_name(Variant::INT);436size.value = itos(array.size());437438Array arr = { size.to_json() };439440for (int i = 0; i < array.size(); i++) {441DAP::Variable var;442var.name = itos(i);443var.type = "byte";444var.value = itos(array[i]);445arr.push_back(var.to_json());446}447variable_list.insert(id, arr);448return id;449}450case Variant::PACKED_INT32_ARRAY: {451int id = variable_id++;452PackedInt32Array array = p_var;453DAP::Variable size;454size.name = "size";455size.type = Variant::get_type_name(Variant::INT);456size.value = itos(array.size());457458Array arr = { size.to_json() };459460for (int i = 0; i < array.size(); i++) {461DAP::Variable var;462var.name = itos(i);463var.type = "int";464var.value = itos(array[i]);465arr.push_back(var.to_json());466}467variable_list.insert(id, arr);468return id;469}470case Variant::PACKED_INT64_ARRAY: {471int id = variable_id++;472PackedInt64Array array = p_var;473DAP::Variable size;474size.name = "size";475size.type = Variant::get_type_name(Variant::INT);476size.value = itos(array.size());477478Array arr = { size.to_json() };479480for (int i = 0; i < array.size(); i++) {481DAP::Variable var;482var.name = itos(i);483var.type = "long";484var.value = itos(array[i]);485arr.push_back(var.to_json());486}487variable_list.insert(id, arr);488return id;489}490case Variant::PACKED_FLOAT32_ARRAY: {491int id = variable_id++;492PackedFloat32Array array = p_var;493DAP::Variable size;494size.name = "size";495size.type = Variant::get_type_name(Variant::INT);496size.value = itos(array.size());497498Array arr = { size.to_json() };499500for (int i = 0; i < array.size(); i++) {501DAP::Variable var;502var.name = itos(i);503var.type = "float";504var.value = rtos(array[i]);505arr.push_back(var.to_json());506}507variable_list.insert(id, arr);508return id;509}510case Variant::PACKED_FLOAT64_ARRAY: {511int id = variable_id++;512PackedFloat64Array array = p_var;513DAP::Variable size;514size.name = "size";515size.type = Variant::get_type_name(Variant::INT);516size.value = itos(array.size());517518Array arr = { size.to_json() };519520for (int i = 0; i < array.size(); i++) {521DAP::Variable var;522var.name = itos(i);523var.type = "double";524var.value = rtos(array[i]);525arr.push_back(var.to_json());526}527variable_list.insert(id, arr);528return id;529}530case Variant::PACKED_STRING_ARRAY: {531int id = variable_id++;532PackedStringArray array = p_var;533DAP::Variable size;534size.name = "size";535size.type = Variant::get_type_name(Variant::INT);536size.value = itos(array.size());537538Array arr = { size.to_json() };539540for (int i = 0; i < array.size(); i++) {541DAP::Variable var;542var.name = itos(i);543var.type = Variant::get_type_name(Variant::STRING);544var.value = array[i];545arr.push_back(var.to_json());546}547variable_list.insert(id, arr);548return id;549}550case Variant::PACKED_VECTOR2_ARRAY: {551int id = variable_id++;552PackedVector2Array array = p_var;553DAP::Variable size;554size.name = "size";555size.type = Variant::get_type_name(Variant::INT);556size.value = itos(array.size());557558Array arr = { size.to_json() };559560for (int i = 0; i < array.size(); i++) {561DAP::Variable var;562var.name = itos(i);563var.type = Variant::get_type_name(Variant::VECTOR2);564var.value = String(array[i]);565var.variablesReference = parse_variant(array[i]);566arr.push_back(var.to_json());567}568variable_list.insert(id, arr);569return id;570}571case Variant::PACKED_VECTOR3_ARRAY: {572int id = variable_id++;573PackedVector3Array array = p_var;574DAP::Variable size;575size.name = "size";576size.type = Variant::get_type_name(Variant::INT);577size.value = itos(array.size());578579Array arr = { size.to_json() };580581for (int i = 0; i < array.size(); i++) {582DAP::Variable var;583var.name = itos(i);584var.type = Variant::get_type_name(Variant::VECTOR3);585var.value = String(array[i]);586var.variablesReference = parse_variant(array[i]);587arr.push_back(var.to_json());588}589variable_list.insert(id, arr);590return id;591}592case Variant::PACKED_COLOR_ARRAY: {593int id = variable_id++;594PackedColorArray array = p_var;595DAP::Variable size;596size.name = "size";597size.type = Variant::get_type_name(Variant::INT);598size.value = itos(array.size());599600Array arr = { size.to_json() };601602for (int i = 0; i < array.size(); i++) {603DAP::Variable var;604var.name = itos(i);605var.type = Variant::get_type_name(Variant::COLOR);606var.value = String(array[i]);607var.variablesReference = parse_variant(array[i]);608arr.push_back(var.to_json());609}610variable_list.insert(id, arr);611return id;612}613case Variant::PACKED_VECTOR4_ARRAY: {614int id = variable_id++;615PackedVector4Array array = p_var;616DAP::Variable size;617size.name = "size";618size.type = Variant::get_type_name(Variant::INT);619size.value = itos(array.size());620621Array arr;622arr.push_back(size.to_json());623624for (int i = 0; i < array.size(); i++) {625DAP::Variable var;626var.name = itos(i);627var.type = Variant::get_type_name(Variant::VECTOR4);628var.value = String(array[i]);629var.variablesReference = parse_variant(array[i]);630arr.push_back(var.to_json());631}632variable_list.insert(id, arr);633return id;634}635case Variant::OBJECT: {636// Objects have to be requested from the debuggee. This has do be done637// in a lazy way, as retrieving object properties takes time.638EncodedObjectAsID *encoded_obj = Object::cast_to<EncodedObjectAsID>(p_var);639640// Object may be null; in that case, return early.641if (!encoded_obj) {642return 0;643}644645// Object may have been already requested.646ObjectID object_id = encoded_obj->get_object_id();647if (object_list.has(object_id)) {648return object_list[object_id];649}650651// Queue requesting the object.652int id = variable_id++;653object_list.insert(object_id, id);654return id;655}656default:657// Simple atomic stuff, or too complex to be manipulated658return 0;659}660}661662void DebugAdapterProtocol::parse_object(SceneDebuggerObject &p_obj) {663// If the object is not on the pending list, we weren't expecting it. Ignore it.664ObjectID object_id = p_obj.id;665if (!object_pending_set.erase(object_id)) {666return;667}668669// Populate DAP::Variable's with the object's properties. These properties will be divided by categories.670Array properties;671Array script_members;672Array script_constants;673Array script_node;674DAP::Variable node_type;675Array node_properties;676677for (SceneDebuggerObject::SceneDebuggerProperty &property : p_obj.properties) {678PropertyInfo &info = property.first;679680// Script members ("Members/" prefix)681if (info.name.begins_with("Members/")) {682info.name = info.name.trim_prefix("Members/");683script_members.push_back(parse_object_variable(property));684}685686// Script constants ("Constants/" prefix)687else if (info.name.begins_with("Constants/")) {688info.name = info.name.trim_prefix("Constants/");689script_constants.push_back(parse_object_variable(property));690}691692// Script node ("Node/" prefix)693else if (info.name.begins_with("Node/")) {694info.name = info.name.trim_prefix("Node/");695script_node.push_back(parse_object_variable(property));696}697698// Regular categories (with type Variant::NIL)699else if (info.type == Variant::NIL) {700if (!node_properties.is_empty()) {701node_type.value = itos(node_properties.size());702variable_list.insert(node_type.variablesReference, node_properties.duplicate());703properties.push_back(node_type.to_json());704}705706node_type.name = info.name;707node_type.type = "Category";708node_type.variablesReference = variable_id++;709node_properties.clear();710}711712// Regular properties.713else {714node_properties.push_back(parse_object_variable(property));715}716}717718// Add the last category.719if (!node_properties.is_empty()) {720node_type.value = itos(node_properties.size());721variable_list.insert(node_type.variablesReference, node_properties.duplicate());722properties.push_back(node_type.to_json());723}724725// Add the script categories, in reverse order to be at the front of the array:726// ( [members; constants; node; category1; category2; ...] )727if (!script_node.is_empty()) {728DAP::Variable node;729node.name = "Node";730node.type = "Category";731node.value = itos(script_node.size());732node.variablesReference = variable_id++;733variable_list.insert(node.variablesReference, script_node);734properties.push_front(node.to_json());735}736737if (!script_constants.is_empty()) {738DAP::Variable constants;739constants.name = "Constants";740constants.type = "Category";741constants.value = itos(script_constants.size());742constants.variablesReference = variable_id++;743variable_list.insert(constants.variablesReference, script_constants);744properties.push_front(constants.to_json());745}746747if (!script_members.is_empty()) {748DAP::Variable members;749members.name = "Members";750members.type = "Category";751members.value = itos(script_members.size());752members.variablesReference = variable_id++;753variable_list.insert(members.variablesReference, script_members);754properties.push_front(members.to_json());755}756757ERR_FAIL_COND(!object_list.has(object_id));758variable_list.insert(object_list[object_id], properties);759}760761void DebugAdapterProtocol::parse_evaluation(DebuggerMarshalls::ScriptStackVariable &p_var) {762// If the eval is not on the pending list, we weren't expecting it. Ignore it.763String eval = p_var.name;764if (!eval_pending_list.erase(eval)) {765return;766}767768DAP::Variable variable;769variable.name = p_var.name;770variable.value = p_var.value;771variable.type = Variant::get_type_name(p_var.value.get_type());772variable.variablesReference = parse_variant(p_var.value);773774eval_list.insert(variable.name, variable);775}776777const Variant DebugAdapterProtocol::parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property) {778const PropertyInfo &info = p_property.first;779const Variant &value = p_property.second;780781DAP::Variable var;782var.name = info.name;783var.type = Variant::get_type_name(info.type);784var.value = value;785var.variablesReference = parse_variant(value);786787return var.to_json();788}789790ObjectID DebugAdapterProtocol::search_object_id(DAPVarID p_var_id) {791for (const KeyValue<ObjectID, DAPVarID> &E : object_list) {792if (E.value == p_var_id) {793return E.key;794}795}796return ObjectID();797}798799bool DebugAdapterProtocol::request_remote_object(const ObjectID &p_object_id) {800// If the object is already on the pending list, we don't need to request it again.801if (object_pending_set.has(p_object_id)) {802return false;803}804805TypedArray<uint64_t> arr;806arr.append(p_object_id);807EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_objects(arr);808object_pending_set.insert(p_object_id);809810return true;811}812813bool DebugAdapterProtocol::request_remote_evaluate(const String &p_eval, int p_stack_frame) {814// If the eval is already on the pending list, we don't need to request it again815if (eval_pending_list.has(p_eval)) {816return false;817}818819EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_evaluate(p_eval, p_stack_frame);820eval_pending_list.insert(p_eval);821822return true;823}824825const DAP::Source &DebugAdapterProtocol::fetch_source(const String &p_path) {826const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);827828HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);829if (E != breakpoint_source_list.end()) {830return E->value;831}832DAP::Source &added_source = breakpoint_source_list.insert(global_path, DAP::Source())->value;833added_source.name = global_path.get_file();834added_source.path = global_path;835added_source.compute_checksums();836837return added_source;838}839840void DebugAdapterProtocol::update_source(const String &p_path) {841const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);842843HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);844if (E != breakpoint_source_list.end()) {845E->value.compute_checksums();846}847}848849bool DebugAdapterProtocol::process_message(const String &p_text) {850JSON json;851ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");852Dictionary params = json.get_data();853bool completed = true;854855// While JSON does not distinguish floats and ints, "seq" is an integer by specification. See https://github.com/godotengine/godot/issues/108288856if (params.has("seq")) {857params["seq"] = (int)params["seq"];858}859860if (OS::get_singleton()->get_ticks_msec() - _current_peer->timestamp > _request_timeout) {861Dictionary response = parser->prepare_error_response(params, DAP::ErrorType::TIMEOUT);862_current_peer->res_queue.push_front(response);863return true;864}865866// Append "req_" to any command received; prevents name clash with existing functions, and possibly exploiting867String command = "req_" + (String)params["command"];868if (parser->has_method(command)) {869_current_request = params["command"];870871Array args = { params };872Dictionary response = parser->callv(command, args);873if (!response.is_empty()) {874_current_peer->res_queue.push_front(response);875} else {876// Launch request needs to be deferred until we receive a configurationDone request.877if (command != "req_launch") {878completed = false;879}880}881}882883reset_current_info();884return completed;885}886887void DebugAdapterProtocol::notify_initialized() {888Dictionary event = parser->ev_initialized();889_current_peer->res_queue.push_back(event);890}891892void DebugAdapterProtocol::notify_process() {893String launch_mode = _current_peer->attached ? "attach" : "launch";894895Dictionary event = parser->ev_process(launch_mode);896for (const Ref<DAPeer> &peer : clients) {897peer->res_queue.push_back(event);898}899}900901void DebugAdapterProtocol::notify_terminated() {902Dictionary event = parser->ev_terminated();903for (const Ref<DAPeer> &peer : clients) {904if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {905continue;906}907peer->res_queue.push_back(event);908}909}910911void DebugAdapterProtocol::notify_exited(const int &p_exitcode) {912Dictionary event = parser->ev_exited(p_exitcode);913for (const Ref<DAPeer> &peer : clients) {914if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {915continue;916}917peer->res_queue.push_back(event);918}919}920921void DebugAdapterProtocol::notify_stopped_paused() {922Dictionary event = parser->ev_stopped_paused();923for (const Ref<DAPeer> &peer : clients) {924peer->res_queue.push_back(event);925}926}927928void DebugAdapterProtocol::notify_stopped_exception(const String &p_error) {929Dictionary event = parser->ev_stopped_exception(p_error);930for (const Ref<DAPeer> &peer : clients) {931peer->res_queue.push_back(event);932}933}934935void DebugAdapterProtocol::notify_stopped_breakpoint(const int &p_id) {936Dictionary event = parser->ev_stopped_breakpoint(p_id);937for (const Ref<DAPeer> &peer : clients) {938peer->res_queue.push_back(event);939}940}941942void DebugAdapterProtocol::notify_stopped_step() {943Dictionary event = parser->ev_stopped_step();944for (const Ref<DAPeer> &peer : clients) {945peer->res_queue.push_back(event);946}947}948949void DebugAdapterProtocol::notify_continued() {950Dictionary event = parser->ev_continued();951for (const Ref<DAPeer> &peer : clients) {952if (_current_request == "continue" && peer == _current_peer) {953continue;954}955peer->res_queue.push_back(event);956}957958reset_stack_info();959}960961void DebugAdapterProtocol::notify_output(const String &p_message, RemoteDebugger::MessageType p_type) {962Dictionary event = parser->ev_output(p_message, p_type);963for (const Ref<DAPeer> &peer : clients) {964peer->res_queue.push_back(event);965}966}967968void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &p_data) {969Dictionary event = parser->ev_custom_data(p_msg, p_data);970for (const Ref<DAPeer> &peer : clients) {971if (peer->supportsCustomData) {972peer->res_queue.push_back(event);973}974}975}976977void DebugAdapterProtocol::notify_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) {978Dictionary event = parser->ev_breakpoint(p_breakpoint, p_enabled);979for (const Ref<DAPeer> &peer : clients) {980if (_current_request == "setBreakpoints" && peer == _current_peer) {981continue;982}983peer->res_queue.push_back(event);984}985}986987Array DebugAdapterProtocol::update_breakpoints(const String &p_path, const Array &p_lines) {988Array updated_breakpoints;989990// Add breakpoints991for (int i = 0; i < p_lines.size(); i++) {992DAP::Breakpoint breakpoint(fetch_source(p_path));993breakpoint.line = p_lines[i];994995// Avoid duplicated entries.996List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);997if (E) {998updated_breakpoints.push_back(E->get().to_json());999continue;1000}10011002EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);10031004// Breakpoints are inserted at the end of the breakpoint list.1005List<DAP::Breakpoint>::Element *added_breakpoint = breakpoint_list.back();1006ERR_FAIL_NULL_V(added_breakpoint, Array());1007ERR_FAIL_COND_V(!(added_breakpoint->get() == breakpoint), Array());1008updated_breakpoints.push_back(added_breakpoint->get().to_json());1009}10101011// Remove breakpoints1012// Must be deferred because we are iterating the breakpoint list.1013Vector<int> to_remove;10141015for (const DAP::Breakpoint &b : breakpoint_list) {1016if (b.source->path == p_path && !p_lines.has(b.line)) {1017to_remove.push_back(b.line);1018}1019}10201021// Safe to remove queued data now.1022for (const int &line : to_remove) {1023EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, line, false);1024}10251026return updated_breakpoints;1027}10281029void DebugAdapterProtocol::on_debug_paused() {1030if (EditorRunBar::get_singleton()->get_pause_button()->is_pressed()) {1031notify_stopped_paused();1032} else {1033notify_continued();1034}1035}10361037void DebugAdapterProtocol::on_debug_stopped() {1038notify_exited();1039notify_terminated();1040reset_ids();1041}10421043void DebugAdapterProtocol::on_debug_output(const String &p_message, int p_type) {1044notify_output(p_message, RemoteDebugger::MessageType(p_type));1045}10461047void DebugAdapterProtocol::on_debug_breaked(const bool &p_reallydid, const bool &p_can_debug, const String &p_reason, const bool &p_has_stackdump) {1048if (!p_reallydid) {1049notify_continued();1050return;1051}10521053if (p_reason == "Breakpoint") {1054if (_stepping) {1055notify_stopped_step();1056_stepping = false;1057} else {1058_processing_breakpoint = true; // Wait for stack_dump to find where the breakpoint happened1059}1060} else {1061notify_stopped_exception(p_reason);1062}10631064_processing_stackdump = p_has_stackdump;1065}10661067void DebugAdapterProtocol::on_debug_breakpoint_toggled(const String &p_path, const int &p_line, const bool &p_enabled) {1068DAP::Breakpoint breakpoint(fetch_source(p_path));1069breakpoint.verified = true;1070breakpoint.line = p_line;10711072if (p_enabled) {1073// Add the breakpoint1074breakpoint.id = breakpoint_id++;1075breakpoint_list.push_back(breakpoint);1076} else {1077// Remove the breakpoint1078List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);1079if (E) {1080breakpoint.id = E->get().id;1081breakpoint_list.erase(E);1082}1083}10841085notify_breakpoint(breakpoint, p_enabled);1086}10871088void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {1089if (_processing_breakpoint && !p_stack_dump.is_empty()) {1090// Find existing breakpoint1091Dictionary d = p_stack_dump[0];1092DAP::Breakpoint breakpoint(fetch_source(d["file"]));1093breakpoint.line = d["line"];10941095List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);1096if (E) {1097notify_stopped_breakpoint(E->get().id);1098}10991100_processing_breakpoint = false;1101}11021103stackframe_id = 0;1104stackframe_list.clear();1105scope_list.clear();11061107// Fill in stacktrace information1108for (int i = 0; i < p_stack_dump.size(); i++) {1109Dictionary stack_info = p_stack_dump[i];11101111DAP::StackFrame stackframe(fetch_source(stack_info["file"]));1112stackframe.id = stackframe_id++;1113stackframe.name = stack_info["function"];1114stackframe.line = stack_info["line"];1115stackframe.column = 0;11161117// Information for "Locals", "Members" and "Globals" variables respectively1118Vector<int> scope_ids;1119for (int j = 0; j < 3; j++) {1120scope_ids.push_back(variable_id++);1121}11221123stackframe_list.push_back(stackframe);1124scope_list.insert(stackframe.id, scope_ids);1125}11261127_current_frame = 0;1128_processing_stackdump = false;1129}11301131void DebugAdapterProtocol::on_debug_stack_frame_vars(const int &p_size) {1132_remaining_vars = p_size;1133ERR_FAIL_COND(!scope_list.has(_current_frame));1134Vector<int> scope_ids = scope_list.find(_current_frame)->value;1135for (const int &var_id : scope_ids) {1136if (variable_list.has(var_id)) {1137variable_list.find(var_id)->value.clear();1138} else {1139variable_list.insert(var_id, Array());1140}1141}1142}11431144void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {1145DebuggerMarshalls::ScriptStackVariable stack_var;1146stack_var.deserialize(p_data);11471148ERR_FAIL_COND(!scope_list.has(_current_frame));1149Vector<int> scope_ids = scope_list.find(_current_frame)->value;11501151ERR_FAIL_COND(scope_ids.size() != 3);1152ERR_FAIL_INDEX(stack_var.type, 4);1153int var_id = scope_ids.get(stack_var.type);11541155DAP::Variable variable;11561157variable.name = stack_var.name;1158variable.value = stack_var.value;1159variable.type = Variant::get_type_name(stack_var.value.get_type());1160variable.variablesReference = parse_variant(stack_var.value);11611162variable_list.find(var_id)->value.push_back(variable.to_json());1163_remaining_vars--;1164}11651166void DebugAdapterProtocol::on_debug_data(const String &p_msg, const Array &p_data) {1167// Ignore data that is already handled by DAP1168if (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") {1169return;1170}11711172if (p_msg == "scene:inspect_objects") {1173if (!p_data.is_empty()) {1174// An object was requested from the debuggee; parse it.1175SceneDebuggerObject remote_obj;1176remote_obj.deserialize(p_data[0]);11771178parse_object(remote_obj);1179}1180#ifndef DISABLE_DEPRECATED1181} else if (p_msg == "scene:inspect_object") {1182if (!p_data.is_empty()) {1183// Legacy single object response format.1184SceneDebuggerObject remote_obj;1185remote_obj.deserialize(p_data);11861187parse_object(remote_obj);1188}1189#endif // DISABLE_DEPRECATED1190} else if (p_msg == "evaluation_return") {1191// An evaluation was requested from the debuggee; parse it.1192DebuggerMarshalls::ScriptStackVariable remote_evaluation;1193remote_evaluation.deserialize(p_data);11941195parse_evaluation(remote_evaluation);1196}11971198notify_custom_data(p_msg, p_data);1199}12001201void DebugAdapterProtocol::poll() {1202if (server->is_connection_available()) {1203on_client_connected();1204}1205List<Ref<DAPeer>> to_delete;1206for (const Ref<DAPeer> &peer : clients) {1207peer->connection->poll();1208StreamPeerTCP::Status status = peer->connection->get_status();1209if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {1210to_delete.push_back(peer);1211} else {1212_current_peer = peer;1213Error err = peer->handle_data();1214if (err != OK && err != ERR_BUSY) {1215to_delete.push_back(peer);1216}1217err = peer->send_data();1218if (err != OK && err != ERR_BUSY) {1219to_delete.push_back(peer);1220}1221}1222}12231224for (const Ref<DAPeer> &peer : to_delete) {1225on_client_disconnected(peer);1226}1227to_delete.clear();1228}12291230Error DebugAdapterProtocol::start(int p_port, const IPAddress &p_bind_ip) {1231_request_timeout = (uint64_t)_EDITOR_GET("network/debug_adapter/request_timeout");1232_sync_breakpoints = (bool)_EDITOR_GET("network/debug_adapter/sync_breakpoints");1233_initialized = true;1234return server->listen(p_port, p_bind_ip);1235}12361237void DebugAdapterProtocol::stop() {1238for (const Ref<DAPeer> &peer : clients) {1239peer->connection->disconnect_from_host();1240}12411242clients.clear();1243server->stop();1244_initialized = false;1245}12461247DebugAdapterProtocol::DebugAdapterProtocol() {1248server.instantiate();1249singleton = this;1250parser = memnew(DebugAdapterParser);12511252reset_ids();12531254EditorRunBar::get_singleton()->get_pause_button()->connect(SceneStringName(pressed), callable_mp(this, &DebugAdapterProtocol::on_debug_paused));12551256EditorDebuggerNode *debugger_node = EditorDebuggerNode::get_singleton();1257debugger_node->connect("breakpoint_toggled", callable_mp(this, &DebugAdapterProtocol::on_debug_breakpoint_toggled));12581259debugger_node->get_default_debugger()->connect("stopped", callable_mp(this, &DebugAdapterProtocol::on_debug_stopped));1260debugger_node->get_default_debugger()->connect(SceneStringName(output), callable_mp(this, &DebugAdapterProtocol::on_debug_output));1261debugger_node->get_default_debugger()->connect("breaked", callable_mp(this, &DebugAdapterProtocol::on_debug_breaked));1262debugger_node->get_default_debugger()->connect("stack_dump", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_dump));1263debugger_node->get_default_debugger()->connect("stack_frame_vars", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_vars));1264debugger_node->get_default_debugger()->connect("stack_frame_var", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_var));1265debugger_node->get_default_debugger()->connect("debug_data", callable_mp(this, &DebugAdapterProtocol::on_debug_data));1266}12671268DebugAdapterProtocol::~DebugAdapterProtocol() {1269memdelete(parser);1270}127112721273