Path: blob/master/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
9906 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/script_editor_debugger.h"37#include "editor/editor_log.h"38#include "editor/editor_node.h"39#include "editor/run/editor_run_bar.h"40#include "editor/settings/editor_settings.h"4142DebugAdapterProtocol *DebugAdapterProtocol::singleton = nullptr;4344Error DAPeer::handle_data() {45int read = 0;46// Read headers47if (!has_header) {48if (!connection->get_available_bytes()) {49return OK;50}51while (true) {52if (req_pos >= DAP_MAX_BUFFER_SIZE) {53req_pos = 0;54ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Response header too big");55}56Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);57if (err != OK) {58return FAILED;59} else if (read != 1) { // Busy, wait until next poll60return ERR_BUSY;61}62char *r = (char *)req_buf;63int l = req_pos;6465// End of headers66if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {67r[l - 3] = '\0'; // Null terminate to read string68String header = String::utf8(r);69content_length = header.substr(16).to_int();70has_header = true;71req_pos = 0;72break;73}74req_pos++;75}76}77if (has_header) {78while (req_pos < content_length) {79if (content_length >= DAP_MAX_BUFFER_SIZE) {80req_pos = 0;81has_header = false;82ERR_FAIL_COND_V_MSG(req_pos >= DAP_MAX_BUFFER_SIZE, ERR_OUT_OF_MEMORY, "Response content too big");83}84Error err = connection->get_partial_data(&req_buf[req_pos], content_length - req_pos, read);85if (err != OK) {86return FAILED;87} else if (read < content_length - req_pos) {88return ERR_BUSY;89}90req_pos += read;91}9293// Parse data94String msg = String::utf8((const char *)req_buf, req_pos);9596// Apply a timestamp if it there's none yet97if (!timestamp) {98timestamp = OS::get_singleton()->get_ticks_msec();99}100101// Response102if (DebugAdapterProtocol::get_singleton()->process_message(msg)) {103// Reset to read again104req_pos = 0;105has_header = false;106timestamp = 0;107}108}109return OK;110}111112Error DAPeer::send_data() {113while (res_queue.size()) {114Dictionary data = res_queue.front()->get();115if (!data.has("seq")) {116data["seq"] = ++seq;117}118const Vector<uint8_t> &formatted_data = format_output(data);119120int data_sent = 0;121while (data_sent < formatted_data.size()) {122int curr_sent = 0;123Error err = connection->put_partial_data(formatted_data.ptr() + data_sent, formatted_data.size() - data_sent, curr_sent);124if (err != OK) {125return err;126}127data_sent += curr_sent;128}129res_queue.pop_front();130}131return OK;132}133134Vector<uint8_t> DAPeer::format_output(const Dictionary &p_params) const {135const Vector<uint8_t> &content = Variant(p_params).to_json_string().to_utf8_buffer();136Vector<uint8_t> response = vformat("Content-Length: %d\r\n\r\n", content.size()).to_utf8_buffer();137138response.append_array(content);139return response;140}141142Error DebugAdapterProtocol::on_client_connected() {143ERR_FAIL_COND_V_MSG(clients.size() >= DAP_MAX_CLIENTS, FAILED, "Max client limits reached");144145Ref<StreamPeerTCP> tcp_peer = server->take_connection();146tcp_peer->set_no_delay(true);147Ref<DAPeer> peer = memnew(DAPeer);148peer->connection = tcp_peer;149clients.push_back(peer);150151EditorDebuggerNode::get_singleton()->get_default_debugger()->set_move_to_foreground(false);152EditorNode::get_log()->add_message("[DAP] Connection Taken", EditorLog::MSG_TYPE_EDITOR);153return OK;154}155156void DebugAdapterProtocol::on_client_disconnected(const Ref<DAPeer> &p_peer) {157clients.erase(p_peer);158if (!clients.size()) {159reset_ids();160EditorDebuggerNode::get_singleton()->get_default_debugger()->set_move_to_foreground(true);161}162EditorNode::get_log()->add_message("[DAP] Disconnected", EditorLog::MSG_TYPE_EDITOR);163}164165void DebugAdapterProtocol::reset_current_info() {166_current_request = "";167_current_peer.unref();168}169170void DebugAdapterProtocol::reset_ids() {171breakpoint_id = 0;172breakpoint_list.clear();173breakpoint_source_list.clear();174175reset_stack_info();176}177178void DebugAdapterProtocol::reset_stack_info() {179stackframe_id = 0;180variable_id = 1;181182stackframe_list.clear();183scope_list.clear();184variable_list.clear();185object_list.clear();186object_pending_set.clear();187}188189int DebugAdapterProtocol::parse_variant(const Variant &p_var) {190switch (p_var.get_type()) {191case Variant::VECTOR2:192case Variant::VECTOR2I: {193int id = variable_id++;194Vector2 vec = p_var;195const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::VECTOR2 ? Variant::FLOAT : Variant::INT);196DAP::Variable x, y;197x.name = "x";198y.name = "y";199x.type = type_scalar;200y.type = type_scalar;201x.value = rtos(vec.x);202y.value = rtos(vec.y);203204Array arr = { x.to_json(), y.to_json() };205variable_list.insert(id, arr);206return id;207}208case Variant::RECT2:209case Variant::RECT2I: {210int id = variable_id++;211Rect2 rect = p_var;212const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::RECT2 ? Variant::FLOAT : Variant::INT);213DAP::Variable x, y, w, h;214x.name = "x";215y.name = "y";216w.name = "w";217h.name = "h";218x.type = type_scalar;219y.type = type_scalar;220w.type = type_scalar;221h.type = type_scalar;222x.value = rtos(rect.position.x);223y.value = rtos(rect.position.y);224w.value = rtos(rect.size.x);225h.value = rtos(rect.size.y);226227Array arr = { x.to_json(), y.to_json(), w.to_json(), h.to_json() };228variable_list.insert(id, arr);229return id;230}231case Variant::VECTOR3:232case Variant::VECTOR3I: {233int id = variable_id++;234Vector3 vec = p_var;235const String type_scalar = Variant::get_type_name(p_var.get_type() == Variant::VECTOR3 ? Variant::FLOAT : Variant::INT);236DAP::Variable x, y, z;237x.name = "x";238y.name = "y";239z.name = "z";240x.type = type_scalar;241y.type = type_scalar;242z.type = type_scalar;243x.value = rtos(vec.x);244y.value = rtos(vec.y);245z.value = rtos(vec.z);246247Array arr = { x.to_json(), y.to_json(), z.to_json() };248variable_list.insert(id, arr);249return id;250}251case Variant::TRANSFORM2D: {252int id = variable_id++;253Transform2D transform = p_var;254const String type_vec2 = Variant::get_type_name(Variant::VECTOR2);255DAP::Variable x, y, origin;256x.name = "x";257y.name = "y";258origin.name = "origin";259x.type = type_vec2;260y.type = type_vec2;261origin.type = type_vec2;262x.value = String(transform.columns[0]);263y.value = String(transform.columns[1]);264origin.value = String(transform.columns[2]);265x.variablesReference = parse_variant(transform.columns[0]);266y.variablesReference = parse_variant(transform.columns[1]);267origin.variablesReference = parse_variant(transform.columns[2]);268269Array arr = { x.to_json(), y.to_json(), origin.to_json() };270variable_list.insert(id, arr);271return id;272}273case Variant::PLANE: {274int id = variable_id++;275Plane plane = p_var;276DAP::Variable d, normal;277d.name = "d";278normal.name = "normal";279d.type = Variant::get_type_name(Variant::FLOAT);280normal.type = Variant::get_type_name(Variant::VECTOR3);281d.value = rtos(plane.d);282normal.value = String(plane.normal);283normal.variablesReference = parse_variant(plane.normal);284285Array arr = { d.to_json(), normal.to_json() };286variable_list.insert(id, arr);287return id;288}289case Variant::QUATERNION: {290int id = variable_id++;291Quaternion quat = p_var;292const String type_float = Variant::get_type_name(Variant::FLOAT);293DAP::Variable x, y, z, w;294x.name = "x";295y.name = "y";296z.name = "z";297w.name = "w";298x.type = type_float;299y.type = type_float;300z.type = type_float;301w.type = type_float;302x.value = rtos(quat.x);303y.value = rtos(quat.y);304z.value = rtos(quat.z);305w.value = rtos(quat.w);306307Array arr = { x.to_json(), y.to_json(), z.to_json(), w.to_json() };308variable_list.insert(id, arr);309return id;310}311case Variant::AABB: {312int id = variable_id++;313AABB aabb = p_var;314const String type_vec3 = Variant::get_type_name(Variant::VECTOR3);315DAP::Variable position, size;316position.name = "position";317size.name = "size";318position.type = type_vec3;319size.type = type_vec3;320position.value = String(aabb.position);321size.value = String(aabb.size);322position.variablesReference = parse_variant(aabb.position);323size.variablesReference = parse_variant(aabb.size);324325Array arr = { position.to_json(), size.to_json() };326variable_list.insert(id, arr);327return id;328}329case Variant::BASIS: {330int id = variable_id++;331Basis basis = p_var;332const String type_vec3 = Variant::get_type_name(Variant::VECTOR3);333DAP::Variable x, y, z;334x.name = "x";335y.name = "y";336z.name = "z";337x.type = type_vec3;338y.type = type_vec3;339z.type = type_vec3;340x.value = String(basis.rows[0]);341y.value = String(basis.rows[1]);342z.value = String(basis.rows[2]);343x.variablesReference = parse_variant(basis.rows[0]);344y.variablesReference = parse_variant(basis.rows[1]);345z.variablesReference = parse_variant(basis.rows[2]);346347Array arr = { x.to_json(), y.to_json(), z.to_json() };348variable_list.insert(id, arr);349return id;350}351case Variant::TRANSFORM3D: {352int id = variable_id++;353Transform3D transform = p_var;354DAP::Variable basis, origin;355basis.name = "basis";356origin.name = "origin";357basis.type = Variant::get_type_name(Variant::BASIS);358origin.type = Variant::get_type_name(Variant::VECTOR3);359basis.value = String(transform.basis);360origin.value = String(transform.origin);361basis.variablesReference = parse_variant(transform.basis);362origin.variablesReference = parse_variant(transform.origin);363364Array arr = { basis.to_json(), origin.to_json() };365variable_list.insert(id, arr);366return id;367}368case Variant::COLOR: {369int id = variable_id++;370Color color = p_var;371const String type_float = Variant::get_type_name(Variant::FLOAT);372DAP::Variable r, g, b, a;373r.name = "r";374g.name = "g";375b.name = "b";376a.name = "a";377r.type = type_float;378g.type = type_float;379b.type = type_float;380a.type = type_float;381r.value = rtos(color.r);382g.value = rtos(color.g);383b.value = rtos(color.b);384a.value = rtos(color.a);385386Array arr = { r.to_json(), g.to_json(), b.to_json(), a.to_json() };387variable_list.insert(id, arr);388return id;389}390case Variant::ARRAY: {391int id = variable_id++;392Array array = p_var;393DAP::Variable size;394size.name = "size";395size.type = Variant::get_type_name(Variant::INT);396size.value = itos(array.size());397398Array arr = { size.to_json() };399400for (int i = 0; i < array.size(); i++) {401DAP::Variable var;402var.name = itos(i);403var.type = Variant::get_type_name(array[i].get_type());404var.value = array[i];405var.variablesReference = parse_variant(array[i]);406arr.push_back(var.to_json());407}408variable_list.insert(id, arr);409return id;410}411case Variant::DICTIONARY: {412int id = variable_id++;413Dictionary dictionary = p_var;414Array arr;415416for (const KeyValue<Variant, Variant> &kv : dictionary) {417DAP::Variable var;418var.name = kv.key;419Variant value = kv.value;420var.type = Variant::get_type_name(value.get_type());421var.value = value;422var.variablesReference = parse_variant(value);423arr.push_back(var.to_json());424}425variable_list.insert(id, arr);426return id;427}428case Variant::PACKED_BYTE_ARRAY: {429int id = variable_id++;430PackedByteArray array = p_var;431DAP::Variable size;432size.name = "size";433size.type = Variant::get_type_name(Variant::INT);434size.value = itos(array.size());435436Array arr = { size.to_json() };437438for (int i = 0; i < array.size(); i++) {439DAP::Variable var;440var.name = itos(i);441var.type = "byte";442var.value = itos(array[i]);443arr.push_back(var.to_json());444}445variable_list.insert(id, arr);446return id;447}448case Variant::PACKED_INT32_ARRAY: {449int id = variable_id++;450PackedInt32Array array = p_var;451DAP::Variable size;452size.name = "size";453size.type = Variant::get_type_name(Variant::INT);454size.value = itos(array.size());455456Array arr = { size.to_json() };457458for (int i = 0; i < array.size(); i++) {459DAP::Variable var;460var.name = itos(i);461var.type = "int";462var.value = itos(array[i]);463arr.push_back(var.to_json());464}465variable_list.insert(id, arr);466return id;467}468case Variant::PACKED_INT64_ARRAY: {469int id = variable_id++;470PackedInt64Array array = p_var;471DAP::Variable size;472size.name = "size";473size.type = Variant::get_type_name(Variant::INT);474size.value = itos(array.size());475476Array arr = { size.to_json() };477478for (int i = 0; i < array.size(); i++) {479DAP::Variable var;480var.name = itos(i);481var.type = "long";482var.value = itos(array[i]);483arr.push_back(var.to_json());484}485variable_list.insert(id, arr);486return id;487}488case Variant::PACKED_FLOAT32_ARRAY: {489int id = variable_id++;490PackedFloat32Array array = p_var;491DAP::Variable size;492size.name = "size";493size.type = Variant::get_type_name(Variant::INT);494size.value = itos(array.size());495496Array arr = { size.to_json() };497498for (int i = 0; i < array.size(); i++) {499DAP::Variable var;500var.name = itos(i);501var.type = "float";502var.value = rtos(array[i]);503arr.push_back(var.to_json());504}505variable_list.insert(id, arr);506return id;507}508case Variant::PACKED_FLOAT64_ARRAY: {509int id = variable_id++;510PackedFloat64Array array = p_var;511DAP::Variable size;512size.name = "size";513size.type = Variant::get_type_name(Variant::INT);514size.value = itos(array.size());515516Array arr = { size.to_json() };517518for (int i = 0; i < array.size(); i++) {519DAP::Variable var;520var.name = itos(i);521var.type = "double";522var.value = rtos(array[i]);523arr.push_back(var.to_json());524}525variable_list.insert(id, arr);526return id;527}528case Variant::PACKED_STRING_ARRAY: {529int id = variable_id++;530PackedStringArray array = p_var;531DAP::Variable size;532size.name = "size";533size.type = Variant::get_type_name(Variant::INT);534size.value = itos(array.size());535536Array arr = { size.to_json() };537538for (int i = 0; i < array.size(); i++) {539DAP::Variable var;540var.name = itos(i);541var.type = Variant::get_type_name(Variant::STRING);542var.value = array[i];543arr.push_back(var.to_json());544}545variable_list.insert(id, arr);546return id;547}548case Variant::PACKED_VECTOR2_ARRAY: {549int id = variable_id++;550PackedVector2Array array = p_var;551DAP::Variable size;552size.name = "size";553size.type = Variant::get_type_name(Variant::INT);554size.value = itos(array.size());555556Array arr = { size.to_json() };557558for (int i = 0; i < array.size(); i++) {559DAP::Variable var;560var.name = itos(i);561var.type = Variant::get_type_name(Variant::VECTOR2);562var.value = String(array[i]);563var.variablesReference = parse_variant(array[i]);564arr.push_back(var.to_json());565}566variable_list.insert(id, arr);567return id;568}569case Variant::PACKED_VECTOR3_ARRAY: {570int id = variable_id++;571PackedVector3Array array = p_var;572DAP::Variable size;573size.name = "size";574size.type = Variant::get_type_name(Variant::INT);575size.value = itos(array.size());576577Array arr = { size.to_json() };578579for (int i = 0; i < array.size(); i++) {580DAP::Variable var;581var.name = itos(i);582var.type = Variant::get_type_name(Variant::VECTOR3);583var.value = String(array[i]);584var.variablesReference = parse_variant(array[i]);585arr.push_back(var.to_json());586}587variable_list.insert(id, arr);588return id;589}590case Variant::PACKED_COLOR_ARRAY: {591int id = variable_id++;592PackedColorArray array = p_var;593DAP::Variable size;594size.name = "size";595size.type = Variant::get_type_name(Variant::INT);596size.value = itos(array.size());597598Array arr = { size.to_json() };599600for (int i = 0; i < array.size(); i++) {601DAP::Variable var;602var.name = itos(i);603var.type = Variant::get_type_name(Variant::COLOR);604var.value = String(array[i]);605var.variablesReference = parse_variant(array[i]);606arr.push_back(var.to_json());607}608variable_list.insert(id, arr);609return id;610}611case Variant::PACKED_VECTOR4_ARRAY: {612int id = variable_id++;613PackedVector4Array array = p_var;614DAP::Variable size;615size.name = "size";616size.type = Variant::get_type_name(Variant::INT);617size.value = itos(array.size());618619Array arr;620arr.push_back(size.to_json());621622for (int i = 0; i < array.size(); i++) {623DAP::Variable var;624var.name = itos(i);625var.type = Variant::get_type_name(Variant::VECTOR4);626var.value = String(array[i]);627var.variablesReference = parse_variant(array[i]);628arr.push_back(var.to_json());629}630variable_list.insert(id, arr);631return id;632}633case Variant::OBJECT: {634// Objects have to be requested from the debuggee. This has do be done635// in a lazy way, as retrieving object properties takes time.636EncodedObjectAsID *encoded_obj = Object::cast_to<EncodedObjectAsID>(p_var);637638// Object may be null; in that case, return early.639if (!encoded_obj) {640return 0;641}642643// Object may have been already requested.644ObjectID object_id = encoded_obj->get_object_id();645if (object_list.has(object_id)) {646return object_list[object_id];647}648649// Queue requesting the object.650int id = variable_id++;651object_list.insert(object_id, id);652return id;653}654default:655// Simple atomic stuff, or too complex to be manipulated656return 0;657}658}659660void DebugAdapterProtocol::parse_object(SceneDebuggerObject &p_obj) {661// If the object is not on the pending list, we weren't expecting it. Ignore it.662ObjectID object_id = p_obj.id;663if (!object_pending_set.erase(object_id)) {664return;665}666667// Populate DAP::Variable's with the object's properties. These properties will be divided by categories.668Array properties;669Array script_members;670Array script_constants;671Array script_node;672DAP::Variable node_type;673Array node_properties;674675for (SceneDebuggerObject::SceneDebuggerProperty &property : p_obj.properties) {676PropertyInfo &info = property.first;677678// Script members ("Members/" prefix)679if (info.name.begins_with("Members/")) {680info.name = info.name.trim_prefix("Members/");681script_members.push_back(parse_object_variable(property));682}683684// Script constants ("Constants/" prefix)685else if (info.name.begins_with("Constants/")) {686info.name = info.name.trim_prefix("Constants/");687script_constants.push_back(parse_object_variable(property));688}689690// Script node ("Node/" prefix)691else if (info.name.begins_with("Node/")) {692info.name = info.name.trim_prefix("Node/");693script_node.push_back(parse_object_variable(property));694}695696// Regular categories (with type Variant::NIL)697else if (info.type == Variant::NIL) {698if (!node_properties.is_empty()) {699node_type.value = itos(node_properties.size());700variable_list.insert(node_type.variablesReference, node_properties.duplicate());701properties.push_back(node_type.to_json());702}703704node_type.name = info.name;705node_type.type = "Category";706node_type.variablesReference = variable_id++;707node_properties.clear();708}709710// Regular properties.711else {712node_properties.push_back(parse_object_variable(property));713}714}715716// Add the last category.717if (!node_properties.is_empty()) {718node_type.value = itos(node_properties.size());719variable_list.insert(node_type.variablesReference, node_properties.duplicate());720properties.push_back(node_type.to_json());721}722723// Add the script categories, in reverse order to be at the front of the array:724// ( [members; constants; node; category1; category2; ...] )725if (!script_node.is_empty()) {726DAP::Variable node;727node.name = "Node";728node.type = "Category";729node.value = itos(script_node.size());730node.variablesReference = variable_id++;731variable_list.insert(node.variablesReference, script_node);732properties.push_front(node.to_json());733}734735if (!script_constants.is_empty()) {736DAP::Variable constants;737constants.name = "Constants";738constants.type = "Category";739constants.value = itos(script_constants.size());740constants.variablesReference = variable_id++;741variable_list.insert(constants.variablesReference, script_constants);742properties.push_front(constants.to_json());743}744745if (!script_members.is_empty()) {746DAP::Variable members;747members.name = "Members";748members.type = "Category";749members.value = itos(script_members.size());750members.variablesReference = variable_id++;751variable_list.insert(members.variablesReference, script_members);752properties.push_front(members.to_json());753}754755ERR_FAIL_COND(!object_list.has(object_id));756variable_list.insert(object_list[object_id], properties);757}758759void DebugAdapterProtocol::parse_evaluation(DebuggerMarshalls::ScriptStackVariable &p_var) {760// If the eval is not on the pending list, we weren't expecting it. Ignore it.761String eval = p_var.name;762if (!eval_pending_list.erase(eval)) {763return;764}765766DAP::Variable variable;767variable.name = p_var.name;768variable.value = p_var.value;769variable.type = Variant::get_type_name(p_var.value.get_type());770variable.variablesReference = parse_variant(p_var.value);771772eval_list.insert(variable.name, variable);773}774775const Variant DebugAdapterProtocol::parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property) {776const PropertyInfo &info = p_property.first;777const Variant &value = p_property.second;778779DAP::Variable var;780var.name = info.name;781var.type = Variant::get_type_name(info.type);782var.value = value;783var.variablesReference = parse_variant(value);784785return var.to_json();786}787788ObjectID DebugAdapterProtocol::search_object_id(DAPVarID p_var_id) {789for (const KeyValue<ObjectID, DAPVarID> &E : object_list) {790if (E.value == p_var_id) {791return E.key;792}793}794return ObjectID();795}796797bool DebugAdapterProtocol::request_remote_object(const ObjectID &p_object_id) {798// If the object is already on the pending list, we don't need to request it again.799if (object_pending_set.has(p_object_id)) {800return false;801}802803TypedArray<uint64_t> arr;804arr.append(p_object_id);805EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_objects(arr);806object_pending_set.insert(p_object_id);807808return true;809}810811bool DebugAdapterProtocol::request_remote_evaluate(const String &p_eval, int p_stack_frame) {812// If the eval is already on the pending list, we don't need to request it again813if (eval_pending_list.has(p_eval)) {814return false;815}816817EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_evaluate(p_eval, p_stack_frame);818eval_pending_list.insert(p_eval);819820return true;821}822823const DAP::Source &DebugAdapterProtocol::fetch_source(const String &p_path) {824const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);825826HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);827if (E != breakpoint_source_list.end()) {828return E->value;829}830DAP::Source &added_source = breakpoint_source_list.insert(global_path, DAP::Source())->value;831added_source.name = global_path.get_file();832added_source.path = global_path;833added_source.compute_checksums();834835return added_source;836}837838void DebugAdapterProtocol::update_source(const String &p_path) {839const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);840841HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);842if (E != breakpoint_source_list.end()) {843E->value.compute_checksums();844}845}846847bool DebugAdapterProtocol::process_message(const String &p_text) {848JSON json;849ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");850Dictionary params = json.get_data();851bool completed = true;852853// While JSON does not distinguish floats and ints, "seq" is an integer by specification. See https://github.com/godotengine/godot/issues/108288854if (params.has("seq")) {855params["seq"] = (int)params["seq"];856}857858if (OS::get_singleton()->get_ticks_msec() - _current_peer->timestamp > _request_timeout) {859Dictionary response = parser->prepare_error_response(params, DAP::ErrorType::TIMEOUT);860_current_peer->res_queue.push_front(response);861return true;862}863864// Append "req_" to any command received; prevents name clash with existing functions, and possibly exploiting865String command = "req_" + (String)params["command"];866if (parser->has_method(command)) {867_current_request = params["command"];868869Array args = { params };870Dictionary response = parser->callv(command, args);871if (!response.is_empty()) {872_current_peer->res_queue.push_front(response);873} else {874// Launch request needs to be deferred until we receive a configurationDone request.875if (command != "req_launch") {876completed = false;877}878}879}880881reset_current_info();882return completed;883}884885void DebugAdapterProtocol::notify_initialized() {886Dictionary event = parser->ev_initialized();887_current_peer->res_queue.push_back(event);888}889890void DebugAdapterProtocol::notify_process() {891String launch_mode = _current_peer->attached ? "attach" : "launch";892893Dictionary event = parser->ev_process(launch_mode);894for (const Ref<DAPeer> &peer : clients) {895peer->res_queue.push_back(event);896}897}898899void DebugAdapterProtocol::notify_terminated() {900Dictionary event = parser->ev_terminated();901for (const Ref<DAPeer> &peer : clients) {902if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {903continue;904}905peer->res_queue.push_back(event);906}907}908909void DebugAdapterProtocol::notify_exited(const int &p_exitcode) {910Dictionary event = parser->ev_exited(p_exitcode);911for (const Ref<DAPeer> &peer : clients) {912if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {913continue;914}915peer->res_queue.push_back(event);916}917}918919void DebugAdapterProtocol::notify_stopped_paused() {920Dictionary event = parser->ev_stopped_paused();921for (const Ref<DAPeer> &peer : clients) {922peer->res_queue.push_back(event);923}924}925926void DebugAdapterProtocol::notify_stopped_exception(const String &p_error) {927Dictionary event = parser->ev_stopped_exception(p_error);928for (const Ref<DAPeer> &peer : clients) {929peer->res_queue.push_back(event);930}931}932933void DebugAdapterProtocol::notify_stopped_breakpoint(const int &p_id) {934Dictionary event = parser->ev_stopped_breakpoint(p_id);935for (const Ref<DAPeer> &peer : clients) {936peer->res_queue.push_back(event);937}938}939940void DebugAdapterProtocol::notify_stopped_step() {941Dictionary event = parser->ev_stopped_step();942for (const Ref<DAPeer> &peer : clients) {943peer->res_queue.push_back(event);944}945}946947void DebugAdapterProtocol::notify_continued() {948Dictionary event = parser->ev_continued();949for (const Ref<DAPeer> &peer : clients) {950if (_current_request == "continue" && peer == _current_peer) {951continue;952}953peer->res_queue.push_back(event);954}955956reset_stack_info();957}958959void DebugAdapterProtocol::notify_output(const String &p_message, RemoteDebugger::MessageType p_type) {960Dictionary event = parser->ev_output(p_message, p_type);961for (const Ref<DAPeer> &peer : clients) {962peer->res_queue.push_back(event);963}964}965966void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &p_data) {967Dictionary event = parser->ev_custom_data(p_msg, p_data);968for (const Ref<DAPeer> &peer : clients) {969if (peer->supportsCustomData) {970peer->res_queue.push_back(event);971}972}973}974975void DebugAdapterProtocol::notify_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) {976Dictionary event = parser->ev_breakpoint(p_breakpoint, p_enabled);977for (const Ref<DAPeer> &peer : clients) {978if (_current_request == "setBreakpoints" && peer == _current_peer) {979continue;980}981peer->res_queue.push_back(event);982}983}984985Array DebugAdapterProtocol::update_breakpoints(const String &p_path, const Array &p_lines) {986Array updated_breakpoints;987988// Add breakpoints989for (int i = 0; i < p_lines.size(); i++) {990DAP::Breakpoint breakpoint(fetch_source(p_path));991breakpoint.line = p_lines[i];992993// Avoid duplicated entries.994List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);995if (E) {996updated_breakpoints.push_back(E->get().to_json());997continue;998}9991000EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);10011002// Breakpoints are inserted at the end of the breakpoint list.1003List<DAP::Breakpoint>::Element *added_breakpoint = breakpoint_list.back();1004ERR_FAIL_NULL_V(added_breakpoint, Array());1005ERR_FAIL_COND_V(!(added_breakpoint->get() == breakpoint), Array());1006updated_breakpoints.push_back(added_breakpoint->get().to_json());1007}10081009// Remove breakpoints1010// Must be deferred because we are iterating the breakpoint list.1011Vector<int> to_remove;10121013for (const DAP::Breakpoint &b : breakpoint_list) {1014if (b.source->path == p_path && !p_lines.has(b.line)) {1015to_remove.push_back(b.line);1016}1017}10181019// Safe to remove queued data now.1020for (const int &line : to_remove) {1021EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, line, false);1022}10231024return updated_breakpoints;1025}10261027void DebugAdapterProtocol::on_debug_paused() {1028if (EditorRunBar::get_singleton()->get_pause_button()->is_pressed()) {1029notify_stopped_paused();1030} else {1031notify_continued();1032}1033}10341035void DebugAdapterProtocol::on_debug_stopped() {1036notify_exited();1037notify_terminated();1038reset_ids();1039}10401041void DebugAdapterProtocol::on_debug_output(const String &p_message, int p_type) {1042notify_output(p_message, RemoteDebugger::MessageType(p_type));1043}10441045void DebugAdapterProtocol::on_debug_breaked(const bool &p_reallydid, const bool &p_can_debug, const String &p_reason, const bool &p_has_stackdump) {1046if (!p_reallydid) {1047notify_continued();1048return;1049}10501051if (p_reason == "Breakpoint") {1052if (_stepping) {1053notify_stopped_step();1054_stepping = false;1055} else {1056_processing_breakpoint = true; // Wait for stack_dump to find where the breakpoint happened1057}1058} else {1059notify_stopped_exception(p_reason);1060}10611062_processing_stackdump = p_has_stackdump;1063}10641065void DebugAdapterProtocol::on_debug_breakpoint_toggled(const String &p_path, const int &p_line, const bool &p_enabled) {1066DAP::Breakpoint breakpoint(fetch_source(p_path));1067breakpoint.verified = true;1068breakpoint.line = p_line;10691070if (p_enabled) {1071// Add the breakpoint1072breakpoint.id = breakpoint_id++;1073breakpoint_list.push_back(breakpoint);1074} else {1075// Remove the breakpoint1076List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);1077if (E) {1078breakpoint.id = E->get().id;1079breakpoint_list.erase(E);1080}1081}10821083notify_breakpoint(breakpoint, p_enabled);1084}10851086void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {1087if (_processing_breakpoint && !p_stack_dump.is_empty()) {1088// Find existing breakpoint1089Dictionary d = p_stack_dump[0];1090DAP::Breakpoint breakpoint(fetch_source(d["file"]));1091breakpoint.line = d["line"];10921093List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);1094if (E) {1095notify_stopped_breakpoint(E->get().id);1096}10971098_processing_breakpoint = false;1099}11001101stackframe_id = 0;1102stackframe_list.clear();1103scope_list.clear();11041105// Fill in stacktrace information1106for (int i = 0; i < p_stack_dump.size(); i++) {1107Dictionary stack_info = p_stack_dump[i];11081109DAP::StackFrame stackframe(fetch_source(stack_info["file"]));1110stackframe.id = stackframe_id++;1111stackframe.name = stack_info["function"];1112stackframe.line = stack_info["line"];1113stackframe.column = 0;11141115// Information for "Locals", "Members" and "Globals" variables respectively1116Vector<int> scope_ids;1117for (int j = 0; j < 3; j++) {1118scope_ids.push_back(variable_id++);1119}11201121stackframe_list.push_back(stackframe);1122scope_list.insert(stackframe.id, scope_ids);1123}11241125_current_frame = 0;1126_processing_stackdump = false;1127}11281129void DebugAdapterProtocol::on_debug_stack_frame_vars(const int &p_size) {1130_remaining_vars = p_size;1131ERR_FAIL_COND(!scope_list.has(_current_frame));1132Vector<int> scope_ids = scope_list.find(_current_frame)->value;1133for (const int &var_id : scope_ids) {1134if (variable_list.has(var_id)) {1135variable_list.find(var_id)->value.clear();1136} else {1137variable_list.insert(var_id, Array());1138}1139}1140}11411142void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {1143DebuggerMarshalls::ScriptStackVariable stack_var;1144stack_var.deserialize(p_data);11451146ERR_FAIL_COND(!scope_list.has(_current_frame));1147Vector<int> scope_ids = scope_list.find(_current_frame)->value;11481149ERR_FAIL_COND(scope_ids.size() != 3);1150ERR_FAIL_INDEX(stack_var.type, 4);1151int var_id = scope_ids.get(stack_var.type);11521153DAP::Variable variable;11541155variable.name = stack_var.name;1156variable.value = stack_var.value;1157variable.type = Variant::get_type_name(stack_var.value.get_type());1158variable.variablesReference = parse_variant(stack_var.value);11591160variable_list.find(var_id)->value.push_back(variable.to_json());1161_remaining_vars--;1162}11631164void DebugAdapterProtocol::on_debug_data(const String &p_msg, const Array &p_data) {1165// Ignore data that is already handled by DAP1166if (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") {1167return;1168}11691170if (p_msg == "scene:inspect_objects") {1171if (!p_data.is_empty()) {1172// An object was requested from the debuggee; parse it.1173SceneDebuggerObject remote_obj;1174remote_obj.deserialize(p_data[0]);11751176parse_object(remote_obj);1177}1178#ifndef DISABLE_DEPRECATED1179} else if (p_msg == "scene:inspect_object") {1180if (!p_data.is_empty()) {1181// Legacy single object response format.1182SceneDebuggerObject remote_obj;1183remote_obj.deserialize(p_data);11841185parse_object(remote_obj);1186}1187#endif // DISABLE_DEPRECATED1188} else if (p_msg == "evaluation_return") {1189// An evaluation was requested from the debuggee; parse it.1190DebuggerMarshalls::ScriptStackVariable remote_evaluation;1191remote_evaluation.deserialize(p_data);11921193parse_evaluation(remote_evaluation);1194}11951196notify_custom_data(p_msg, p_data);1197}11981199void DebugAdapterProtocol::poll() {1200if (server->is_connection_available()) {1201on_client_connected();1202}1203List<Ref<DAPeer>> to_delete;1204for (const Ref<DAPeer> &peer : clients) {1205peer->connection->poll();1206StreamPeerTCP::Status status = peer->connection->get_status();1207if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {1208to_delete.push_back(peer);1209} else {1210_current_peer = peer;1211Error err = peer->handle_data();1212if (err != OK && err != ERR_BUSY) {1213to_delete.push_back(peer);1214}1215err = peer->send_data();1216if (err != OK && err != ERR_BUSY) {1217to_delete.push_back(peer);1218}1219}1220}12211222for (const Ref<DAPeer> &peer : to_delete) {1223on_client_disconnected(peer);1224}1225to_delete.clear();1226}12271228Error DebugAdapterProtocol::start(int p_port, const IPAddress &p_bind_ip) {1229_request_timeout = (uint64_t)_EDITOR_GET("network/debug_adapter/request_timeout");1230_sync_breakpoints = (bool)_EDITOR_GET("network/debug_adapter/sync_breakpoints");1231_initialized = true;1232return server->listen(p_port, p_bind_ip);1233}12341235void DebugAdapterProtocol::stop() {1236for (const Ref<DAPeer> &peer : clients) {1237peer->connection->disconnect_from_host();1238}12391240clients.clear();1241server->stop();1242_initialized = false;1243}12441245DebugAdapterProtocol::DebugAdapterProtocol() {1246server.instantiate();1247singleton = this;1248parser = memnew(DebugAdapterParser);12491250reset_ids();12511252EditorRunBar::get_singleton()->get_pause_button()->connect(SceneStringName(pressed), callable_mp(this, &DebugAdapterProtocol::on_debug_paused));12531254EditorDebuggerNode *debugger_node = EditorDebuggerNode::get_singleton();1255debugger_node->connect("breakpoint_toggled", callable_mp(this, &DebugAdapterProtocol::on_debug_breakpoint_toggled));12561257debugger_node->get_default_debugger()->connect("stopped", callable_mp(this, &DebugAdapterProtocol::on_debug_stopped));1258debugger_node->get_default_debugger()->connect(SceneStringName(output), callable_mp(this, &DebugAdapterProtocol::on_debug_output));1259debugger_node->get_default_debugger()->connect("breaked", callable_mp(this, &DebugAdapterProtocol::on_debug_breaked));1260debugger_node->get_default_debugger()->connect("stack_dump", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_dump));1261debugger_node->get_default_debugger()->connect("stack_frame_vars", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_vars));1262debugger_node->get_default_debugger()->connect("stack_frame_var", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_var));1263debugger_node->get_default_debugger()->connect("debug_data", callable_mp(this, &DebugAdapterProtocol::on_debug_data));1264}12651266DebugAdapterProtocol::~DebugAdapterProtocol() {1267memdelete(parser);1268}126912701271