diff options
Diffstat (limited to 'core/debugger')
-rw-r--r-- | core/debugger/debugger_marshalls.cpp | 5 | ||||
-rw-r--r-- | core/debugger/debugger_marshalls.h | 32 | ||||
-rw-r--r-- | core/debugger/engine_debugger.cpp | 71 | ||||
-rw-r--r-- | core/debugger/engine_debugger.h | 21 | ||||
-rw-r--r-- | core/debugger/local_debugger.cpp | 57 | ||||
-rw-r--r-- | core/debugger/local_debugger.h | 3 | ||||
-rw-r--r-- | core/debugger/remote_debugger.cpp | 153 | ||||
-rw-r--r-- | core/debugger/remote_debugger.h | 21 | ||||
-rw-r--r-- | core/debugger/remote_debugger_peer.cpp | 42 | ||||
-rw-r--r-- | core/debugger/remote_debugger_peer.h | 6 | ||||
-rw-r--r-- | core/debugger/script_debugger.cpp | 27 | ||||
-rw-r--r-- | core/debugger/script_debugger.h | 3 |
12 files changed, 228 insertions, 213 deletions
diff --git a/core/debugger/debugger_marshalls.cpp b/core/debugger/debugger_marshalls.cpp index 427c005b60..3f949b0ae1 100644 --- a/core/debugger/debugger_marshalls.cpp +++ b/core/debugger/debugger_marshalls.cpp @@ -227,9 +227,10 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) { } int len = 0; - Error err = encode_variant(var, NULL, len, true); - if (err != OK) + Error err = encode_variant(var, nullptr, len, true); + if (err != OK) { ERR_PRINT("Failed to encode variant."); + } if (len > max_size) { arr.push_back(Variant()); diff --git a/core/debugger/debugger_marshalls.h b/core/debugger/debugger_marshalls.h index 04229c0afc..7b7f4ac4b5 100644 --- a/core/debugger/debugger_marshalls.h +++ b/core/debugger/debugger_marshalls.h @@ -35,18 +35,14 @@ #include "servers/rendering_server.h" struct DebuggerMarshalls { - // Memory usage struct ResourceInfo { String path; String format; String type; RID id; - int vram; + int vram = 0; bool operator<(const ResourceInfo &p_img) const { return vram == p_img.vram ? id < p_img.id : vram > p_img.vram; } - ResourceInfo() { - vram = 0; - } }; struct ResourceUsage { @@ -119,10 +115,7 @@ struct DebuggerMarshalls { struct ScriptStackVariable { String name; Variant value; - int type; - ScriptStackVariable() { - type = -1; - } + int type = -1; Array serialize(int max_size = 1 << 20); // 1 MiB default. bool deserialize(const Array &p_arr); @@ -137,27 +130,18 @@ struct DebuggerMarshalls { }; struct OutputError { - int hr; - int min; - int sec; - int msec; + int hr = -1; + int min = -1; + int sec = -1; + int msec = -1; String source_file; String source_func; - int source_line; + int source_line = -1; String error; String error_descr; - bool warning; + bool warning = false; Vector<ScriptLanguage::StackInfo> callstack; - OutputError() { - hr = -1; - min = -1; - sec = -1; - msec = -1; - source_line = -1; - warning = false; - } - Array serialize(); bool deserialize(const Array &p_arr); }; diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp index c64d886800..5c9fb67de4 100644 --- a/core/debugger/engine_debugger.cpp +++ b/core/debugger/engine_debugger.cpp @@ -32,14 +32,16 @@ #include "core/debugger/local_debugger.h" #include "core/debugger/remote_debugger.h" +#include "core/debugger/remote_debugger_peer.h" #include "core/debugger/script_debugger.h" #include "core/os/os.h" -EngineDebugger *EngineDebugger::singleton = NULL; -ScriptDebugger *EngineDebugger::script_debugger = NULL; +EngineDebugger *EngineDebugger::singleton = nullptr; +ScriptDebugger *EngineDebugger::script_debugger = nullptr; Map<StringName, EngineDebugger::Profiler> EngineDebugger::profilers; Map<StringName, EngineDebugger::Capture> EngineDebugger::captures; +Map<String, EngineDebugger::CreatePeerFunc> EngineDebugger::protocols; void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) { ERR_FAIL_COND_MSG(profilers.has(p_name), "Profiler already registered: " + p_name); @@ -66,6 +68,11 @@ void EngineDebugger::unregister_message_capture(const StringName &p_name) { captures.erase(p_name); } +void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) { + ERR_FAIL_COND_MSG(protocols.has(p_protocol), "Protocol handler already registered: " + p_protocol); + protocols.insert(p_protocol, p_func); +} + void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) { ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't change profiler state, no profiler: " + p_name); Profiler &p = profilers[p_name]; @@ -104,8 +111,9 @@ Error EngineDebugger::capture_parse(const StringName &p_name, const String &p_ms void EngineDebugger::line_poll() { // The purpose of this is just processing events every now and then when the script might get too busy otherwise bugs like infinite loops can't be caught - if (poll_every % 2048 == 0) + if (poll_every % 2048 == 0) { poll_events(false); + } poll_every++; } @@ -117,40 +125,49 @@ void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_idle_ticks, ui // Notify tick to running profilers for (Map<StringName, Profiler>::Element *E = profilers.front(); E; E = E->next()) { Profiler &p = E->get(); - if (!p.active || !p.tick) + if (!p.active || !p.tick) { continue; + } p.tick(p.data, frame_time, idle_time, physics_time, physics_frame_time); } singleton->poll_events(true); } void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Vector<String> p_breakpoints) { - if (p_uri.empty()) + register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more. + if (p_uri.empty()) { return; + } if (p_uri == "local://") { singleton = memnew(LocalDebugger); script_debugger = memnew(ScriptDebugger); // Tell the OS that we want to handle termination signals. OS::get_singleton()->initialize_debugging(); - } else { - singleton = RemoteDebugger::create_for_uri(p_uri); - if (!singleton) + } else if (p_uri.find("://") >= 0) { + const String proto = p_uri.substr(0, p_uri.find("://") + 3); + if (!protocols.has(proto)) { + return; + } + RemoteDebuggerPeer *peer = protocols[proto](p_uri); + if (!peer) { return; + } + singleton = memnew(RemoteDebugger(Ref<RemoteDebuggerPeer>(peer))); script_debugger = memnew(ScriptDebugger); // Notify editor of our pid (to allow focus stealing). Array msg; msg.push_back(OS::get_singleton()->get_process_id()); singleton->send_message("set_pid", msg); } - if (!singleton) + if (!singleton) { return; + } // There is a debugger, parse breakpoints. ScriptDebugger *singleton_script_debugger = singleton->get_script_debugger(); singleton_script_debugger->set_skip_breakpoints(p_skip_breakpoints); for (int i = 0; i < p_breakpoints.size(); i++) { - String bp = p_breakpoints[i]; int sp = bp.find_last(":"); ERR_CONTINUE_MSG(sp == -1, "Invalid breakpoint: '" + bp + "', expected file:line format."); @@ -160,27 +177,31 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Ve } void EngineDebugger::deinitialize() { - if (!singleton) - return; - - // Stop all profilers - for (Map<StringName, Profiler>::Element *E = profilers.front(); E; E = E->next()) { - if (E->get().active) - singleton->profiler_enable(E->key(), false); + if (singleton) { + // Stop all profilers + for (Map<StringName, Profiler>::Element *E = profilers.front(); E; E = E->next()) { + if (E->get().active) { + singleton->profiler_enable(E->key(), false); + } + } + + // Flush any remaining message + singleton->poll_events(false); + + memdelete(singleton); + singleton = nullptr; } - // Flush any remaining message - singleton->poll_events(false); - - memdelete(singleton); - singleton = NULL; + // Clear profilers/captuers/protocol handlers. profilers.clear(); captures.clear(); + protocols.clear(); } EngineDebugger::~EngineDebugger() { - if (script_debugger) + if (script_debugger) { memdelete(script_debugger); - script_debugger = NULL; - singleton = NULL; + } + script_debugger = nullptr; + singleton = nullptr; } diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h index 9e01aeba18..8d5ebb2394 100644 --- a/core/debugger/engine_debugger.h +++ b/core/debugger/engine_debugger.h @@ -38,6 +38,7 @@ #include "core/variant.h" #include "core/vector.h" +class RemoteDebuggerPeer; class ScriptDebugger; class EngineDebugger { @@ -45,15 +46,18 @@ public: typedef void (*ProfilingToggle)(void *p_user, bool p_enable, const Array &p_opts); typedef void (*ProfilingTick)(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time); typedef void (*ProfilingAdd)(void *p_user, const Array &p_arr); + typedef Error (*CaptureFunc)(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured); + typedef RemoteDebuggerPeer *(*CreatePeerFunc)(const String &p_uri); + class Profiler { friend class EngineDebugger; - ProfilingToggle toggle = NULL; - ProfilingAdd add = NULL; - ProfilingTick tick = NULL; - void *data = NULL; + ProfilingToggle toggle = nullptr; + ProfilingAdd add = nullptr; + ProfilingTick tick = nullptr; + void *data = nullptr; bool active = false; public: @@ -69,8 +73,8 @@ public: class Capture { friend class EngineDebugger; - CaptureFunc capture = NULL; - void *data = NULL; + CaptureFunc capture = nullptr; + void *data = nullptr; public: Capture() {} @@ -94,10 +98,11 @@ protected: static Map<StringName, Profiler> profilers; static Map<StringName, Capture> captures; + static Map<String, CreatePeerFunc> protocols; public: _FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; } - _FORCE_INLINE_ static bool is_active() { return singleton != NULL && script_debugger != NULL; } + _FORCE_INLINE_ static bool is_active() { return singleton != nullptr && script_debugger != nullptr; } _FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; }; @@ -113,6 +118,8 @@ public: static void unregister_message_capture(const StringName &p_name); static bool has_capture(const StringName &p_name); + static void register_uri_handler(const String &p_protocol, CreatePeerFunc p_func); + void iteration(uint64_t p_frame_ticks, uint64_t p_idle_ticks, uint64_t p_physics_ticks, float p_physics_frame_time); void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array()); Error capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured); diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp index 01e30fb621..876be79418 100644 --- a/core/debugger/local_debugger.cpp +++ b/core/debugger/local_debugger.cpp @@ -36,7 +36,6 @@ struct LocalDebugger::ScriptsProfiler { struct ProfileInfoSort { - bool operator()(const ScriptLanguage::ProfilingInfo &A, const ScriptLanguage::ProfilingInfo &B) const { return A.total_time > B.total_time; } @@ -70,17 +69,19 @@ struct LocalDebugger::ScriptsProfiler { void _print_frame_data(bool p_accumulated) { uint64_t diff = OS::get_singleton()->get_ticks_usec() - idle_accum; - if (!p_accumulated && diff < 1000000) //show every one second + if (!p_accumulated && diff < 1000000) { //show every one second return; + } idle_accum = OS::get_singleton()->get_ticks_usec(); int ofs = 0; for (int i = 0; i < ScriptServer::get_language_count(); i++) { - if (p_accumulated) + if (p_accumulated) { ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&pinfo.write[ofs], pinfo.size() - ofs); - else + } else { ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&pinfo.write[ofs], pinfo.size() - ofs); + } } SortArray<ScriptLanguage::ProfilingInfo, ProfileInfoSort> sort; @@ -89,7 +90,6 @@ struct LocalDebugger::ScriptsProfiler { // compute total script frame time uint64_t script_time_us = 0; for (int i = 0; i < ofs; i++) { - script_time_us += pinfo[i].self_time; } float script_time = USEC_TO_SEC(script_time_us); @@ -102,7 +102,6 @@ struct LocalDebugger::ScriptsProfiler { } for (int i = 0; i < ofs; i++) { - print_line(itos(i) + ":" + pinfo[i].signature); float tt = USEC_TO_SEC(pinfo[i].total_time); float st = USEC_TO_SEC(pinfo[i].self_time); @@ -116,7 +115,6 @@ struct LocalDebugger::ScriptsProfiler { }; void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { - ScriptLanguage *script_lang = script_debugger->get_break_language(); if (!target_function.empty()) { @@ -135,7 +133,6 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { int current_frame = 0; int total_frames = script_lang->debug_get_stack_level_count(); while (true) { - OS::get_singleton()->print("debug> "); String line = OS::get_singleton()->get_stdin_string().strip_edges(); @@ -146,18 +143,15 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'"); print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'"); print_line("Enter \"help\" for assistance."); - } else if (line == "c" || line == "continue") + } else if (line == "c" || line == "continue") { break; - else if (line == "bt" || line == "breakpoint") { - + } else if (line == "bt" || line == "breakpoint") { for (int i = 0; i < total_frames; i++) { - String cfi = (current_frame == i) ? "*" : " "; //current frame indicator print_line(cfi + "Frame " + itos(i) + " - " + script_lang->debug_get_stack_level_source(i) + ":" + itos(script_lang->debug_get_stack_level_line(i)) + " in function '" + script_lang->debug_get_stack_level_function(i) + "'"); } } else if (line.begins_with("fr") || line.begins_with("frame")) { - if (line.get_slice_count(" ") == 1) { print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'"); } else { @@ -171,9 +165,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } } else if (line.begins_with("set")) { - if (line.get_slice_count(" ") == 1) { - for (Map<String, String>::Element *E = options.front(); E; E = E->next()) { print_line("\t" + E->key() + "=" + E->value()); } @@ -185,13 +177,11 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { if (value_pos < 0) { print_line("Error: Invalid set format. Use: set key=value"); } else { - String key = key_value.left(value_pos); if (!options.has(key)) { print_line("Error: Unknown option " + key); } else { - // Allow explicit tab character String value = key_value.right(value_pos + 1).replace("\\t", "\t"); @@ -201,49 +191,41 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } } else if (line == "lv" || line == "locals") { - List<String> locals; List<Variant> values; script_lang->debug_get_stack_level_locals(current_frame, &locals, &values); print_variables(locals, values, variable_prefix); } else if (line == "gv" || line == "globals") { - List<String> globals; List<Variant> values; script_lang->debug_get_globals(&globals, &values); print_variables(globals, values, variable_prefix); } else if (line == "mv" || line == "members") { - List<String> members; List<Variant> values; script_lang->debug_get_stack_level_members(current_frame, &members, &values); print_variables(members, values, variable_prefix); } else if (line.begins_with("p") || line.begins_with("print")) { - if (line.get_slice_count(" ") <= 1) { print_line("Usage: print <expre>"); } else { - String expr = line.get_slicec(' ', 2); String res = script_lang->debug_parse_stack_level_expression(current_frame, expr); print_line(res); } } else if (line == "s" || line == "step") { - script_debugger->set_depth(-1); script_debugger->set_lines_left(1); break; } else if (line == "n" || line == "next") { - script_debugger->set_depth(0); script_debugger->set_lines_left(1); break; } else if (line == "fin" || line == "finish") { - String current_function = script_lang->debug_get_stack_level_function(0); for (int i = 0; i < total_frames; i++) { @@ -259,9 +241,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { target_function = ""; } else if (line.begins_with("br") || line.begins_with("break")) { - if (line.get_slice_count(" ") <= 1) { - const Map<int, Set<StringName>> &breakpoints = script_debugger->get_breakpoints(); if (breakpoints.size() == 0) { print_line("No Breakpoints."); @@ -274,14 +254,14 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } } else { - Pair<String, int> breakpoint = to_breakpoint(line); String source = breakpoint.first; int linenr = breakpoint.second; - if (source.empty()) + if (source.empty()) { continue; + } script_debugger->insert_breakpoint(linenr, source); @@ -289,7 +269,6 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } } else if (line == "q" || line == "quit") { - // Do not stop again on quit script_debugger->clear_breakpoints(); script_debugger->set_depth(-1); @@ -298,18 +277,17 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { SceneTree::get_singleton()->quit(); break; } else if (line.begins_with("delete")) { - if (line.get_slice_count(" ") <= 1) { script_debugger->clear_breakpoints(); } else { - Pair<String, int> breakpoint = to_breakpoint(line); String source = breakpoint.first; int linenr = breakpoint.second; - if (source.empty()) + if (source.empty()) { continue; + } script_debugger->remove_breakpoint(linenr, source); @@ -317,7 +295,6 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } } else if (line == "h" || line == "help") { - print_line("Built-In Debugger command list:\n"); print_line("\tc,continue\t\t Continue execution."); print_line("\tbt,backtrace\t\t Show stack trace (frames)."); @@ -340,18 +317,15 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } void LocalDebugger::print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix) { - String value; Vector<String> value_lines; const List<Variant>::Element *V = values.front(); for (const List<String>::Element *E = names.front(); E; E = E->next()) { - value = String(V->get()); if (variable_prefix.empty()) { print_line(E->get() + ": " + String(V->get())); } else { - print_line(E->get() + ":"); value_lines = value.split("\n"); for (int i = 0; i < value_lines.size(); ++i) { @@ -364,7 +338,6 @@ void LocalDebugger::print_variables(const List<String> &names, const List<Varian } Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) { - String breakpoint_part = p_line.get_slicec(' ', 1); Pair<String, int> breakpoint; @@ -381,18 +354,15 @@ Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) { } void LocalDebugger::send_message(const String &p_message, const Array &p_args) { - // This needs to be cleaned up entirely. // print_line("MESSAGE: '" + p_message + "' - " + String(Variant(p_args))); } void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type) { - print_line("ERROR: '" + (p_descr.empty() ? p_err : p_descr) + "'"); } LocalDebugger::LocalDebugger() { - options["variable_prefix"] = ""; // Bind scripts profiler. @@ -402,7 +372,7 @@ LocalDebugger::LocalDebugger() { [](void *p_user, bool p_enable, const Array &p_opts) { ((ScriptsProfiler *)p_user)->toggle(p_enable, p_opts); }, - NULL, + nullptr, [](void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { ((ScriptsProfiler *)p_user)->tick(p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time); }); @@ -411,6 +381,7 @@ LocalDebugger::LocalDebugger() { LocalDebugger::~LocalDebugger() { unregister_profiler("scripts"); - if (scripts_profiler) + if (scripts_profiler) { memdelete(scripts_profiler); + } } diff --git a/core/debugger/local_debugger.h b/core/debugger/local_debugger.h index e299df0546..d342da6d44 100644 --- a/core/debugger/local_debugger.h +++ b/core/debugger/local_debugger.h @@ -36,11 +36,10 @@ #include "core/script_language.h" class LocalDebugger : public EngineDebugger { - private: struct ScriptsProfiler; - ScriptsProfiler *scripts_profiler = NULL; + ScriptsProfiler *scripts_profiler = nullptr; String target_function; Map<String, String> options; diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 66b890be23..62f600c5e5 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -33,7 +33,7 @@ #include "core/debugger/debugger_marshalls.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" -#include "core/input/input_filter.h" +#include "core/input/input.h" #include "core/os/os.h" #include "core/project_settings.h" #include "core/script_language.h" @@ -57,7 +57,6 @@ void RemoteDebugger::_bind_profiler(const String &p_name, T *p_prof) { } struct RemoteDebugger::NetworkProfiler { - public: typedef DebuggerMarshalls::MultiplayerNodeInfo NodeInfo; struct BandwidthFrame { @@ -97,8 +96,9 @@ public: } void init_node(const ObjectID p_node) { - if (multiplayer_node_data.has(p_node)) + if (multiplayer_node_data.has(p_node)) { return; + } multiplayer_node_data.insert(p_node, DebuggerMarshalls::MultiplayerNodeInfo()); multiplayer_node_data[p_node].node = p_node; multiplayer_node_data[p_node].node_path = Object::cast_to<Node>(ObjectDB::get_instance(p_node))->get_path(); @@ -191,7 +191,6 @@ struct RemoteDebugger::ScriptsProfiler { typedef DebuggerMarshalls::ScriptFunctionSignature FunctionSignature; typedef DebuggerMarshalls::ScriptFunctionInfo FunctionInfo; struct ProfileInfoSort { - bool operator()(ScriptLanguage::ProfilingInfo *A, ScriptLanguage::ProfilingInfo *B) const { return A->total_time < B->total_time; } @@ -220,10 +219,11 @@ struct RemoteDebugger::ScriptsProfiler { void write_frame_data(Vector<FunctionInfo> &r_funcs, uint64_t &r_total, bool p_accumulated) { int ofs = 0; for (int i = 0; i < ScriptServer::get_language_count(); i++) { - if (p_accumulated) + if (p_accumulated) { ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&info.write[ofs], info.size() - ofs); - else + } else { ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&info.write[ofs], info.size() - ofs); + } } for (int i = 0; i < ofs; i++) { @@ -270,7 +270,6 @@ struct RemoteDebugger::ScriptsProfiler { }; struct RemoteDebugger::ServersProfiler { - bool skip_profile_frame = false; typedef DebuggerMarshalls::ServerInfo ServerInfo; typedef DebuggerMarshalls::ServerFunctionInfo ServerFunctionInfo; @@ -318,7 +317,7 @@ struct RemoteDebugger::ServersProfiler { void _send_frame_data(bool p_final) { DebuggerMarshalls::ServersProfilerFrame frame; - frame.frame_number = Engine::get_singleton()->get_frames_drawn(); + frame.frame_number = Engine::get_singleton()->get_idle_frames(); frame.frame_time = frame_time; frame.idle_time = idle_time; frame.physics_time = physics_time; @@ -347,7 +346,6 @@ struct RemoteDebugger::ServersProfiler { }; struct RemoteDebugger::VisualProfiler { - typedef DebuggerMarshalls::ServerInfo ServerInfo; typedef DebuggerMarshalls::ServerFunctionInfo ServerFunctionInfo; @@ -362,8 +360,9 @@ struct RemoteDebugger::VisualProfiler { void tick(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { Vector<RS::FrameProfileArea> profile_areas = RS::get_singleton()->get_frame_profile(); DebuggerMarshalls::VisualProfilerFrame frame; - if (!profile_areas.size()) + if (!profile_areas.size()) { return; + } frame.frame_number = RS::get_singleton()->get_frame_profile_frame(); frame.areas.append_array(profile_areas); @@ -372,19 +371,20 @@ struct RemoteDebugger::VisualProfiler { }; struct RemoteDebugger::PerformanceProfiler { - - Object *performance = NULL; + Object *performance = nullptr; int last_perf_time = 0; void toggle(bool p_enable, const Array &p_opts) {} void add(const Array &p_data) {} void tick(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { - if (!performance) + if (!performance) { return; + } uint64_t pt = OS::get_singleton()->get_ticks_msec(); - if (pt - last_perf_time < 1000) + if (pt - last_perf_time < 1000) { return; + } last_perf_time = pt; int max = performance->get("MONITOR_MAX"); Array arr; @@ -401,14 +401,12 @@ struct RemoteDebugger::PerformanceProfiler { }; void RemoteDebugger::_send_resource_usage() { - DebuggerMarshalls::ResourceUsage usage; List<RS::TextureInfo> tinfo; RS::get_singleton()->texture_debug_usage(&tinfo); for (List<RS::TextureInfo>::Element *E = tinfo.front(); E; E = E->next()) { - DebuggerMarshalls::ResourceInfo info; info.path = E->get().path; info.vram = E->get().bytes; @@ -430,26 +428,29 @@ Error RemoteDebugger::_put_msg(String p_message, Array p_data) { msg.push_back(p_message); msg.push_back(p_data); Error err = peer->put_message(msg); - if (err != OK) + if (err != OK) { n_messages_dropped++; + } return err; } void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, ErrorHandlerType p_type) { - - if (p_type == ERR_HANDLER_SCRIPT) + if (p_type == ERR_HANDLER_SCRIPT) { return; //ignore script errors, those go through debugger + } RemoteDebugger *rd = (RemoteDebugger *)p_this; - if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) // Can't handle recursive errors during flush. + if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive errors during flush. return; + } Vector<ScriptLanguage::StackInfo> si; for (int i = 0; i < ScriptServer::get_language_count(); i++) { si = ScriptServer::get_language(i)->debug_get_current_stack_info(); - if (si.size()) + if (si.size()) { break; + } } // send_error will lock internally. @@ -457,17 +458,18 @@ void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char * } void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p_error) { - RemoteDebugger *rd = (RemoteDebugger *)p_this; - if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) // Can't handle recursive prints during flush. + if (rd->flushing && Thread::get_caller_id() == rd->flush_thread) { // Can't handle recursive prints during flush. return; + } String s = p_string; int allowed_chars = MIN(MAX(rd->max_chars_per_second - rd->char_count, 0), s.length()); - if (allowed_chars == 0) + if (allowed_chars == 0 && s.length() > 0) { return; + } if (allowed_chars < s.length()) { s = s.substr(0, allowed_chars); @@ -478,12 +480,19 @@ void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p rd->char_count += allowed_chars; bool overflowed = rd->char_count >= rd->max_chars_per_second; if (rd->is_peer_connected()) { - if (overflowed) + if (overflowed) { s += "[...]"; - rd->output_strings.push_back(s); + } + + OutputString output_string; + output_string.message = s; + output_string.type = p_error ? MESSAGE_TYPE_ERROR : MESSAGE_TYPE_LOG; + rd->output_strings.push_back(output_string); if (overflowed) { - rd->output_strings.push_back("[output overflow, print less text!]"); + output_string.message = "[output overflow, print less text!]"; + output_string.type = MESSAGE_TYPE_ERROR; + rd->output_strings.push_back(output_string); } } } @@ -505,27 +514,45 @@ void RemoteDebugger::flush_output() { flush_thread = Thread::get_caller_id(); flushing = true; MutexLock lock(mutex); - if (!is_peer_connected()) + if (!is_peer_connected()) { return; + } if (n_messages_dropped > 0) { ErrorMessage err_msg = _create_overflow_error("TOO_MANY_MESSAGES", "Too many messages! " + String::num_int64(n_messages_dropped) + " messages were dropped. Profiling might misbheave, try raising 'network/limits/debugger/max_queued_messages' in project setting."); - if (_put_msg("error", err_msg.serialize()) == OK) + if (_put_msg("error", err_msg.serialize()) == OK) { n_messages_dropped = 0; + } } if (output_strings.size()) { - // Join output strings so we generate less messages. + Vector<String> joined_log_strings; Vector<String> strings; - strings.resize(output_strings.size()); - String *w = strings.ptrw(); + Vector<int> types; for (int i = 0; i < output_strings.size(); i++) { - w[i] = output_strings[i]; + const OutputString &output_string = output_strings[i]; + if (output_string.type == MESSAGE_TYPE_ERROR) { + if (!joined_log_strings.empty()) { + strings.push_back(String("\n").join(joined_log_strings)); + types.push_back(MESSAGE_TYPE_LOG); + joined_log_strings.clear(); + } + strings.push_back(output_string.message); + types.push_back(MESSAGE_TYPE_ERROR); + } else { + joined_log_strings.push_back(output_string.message); + } + } + + if (!joined_log_strings.empty()) { + strings.push_back(String("\n").join(joined_log_strings)); + types.push_back(MESSAGE_TYPE_LOG); } Array arr; arr.push_back(strings); + arr.push_back(types); _put_msg("output", arr); output_strings.clear(); } @@ -551,7 +578,6 @@ void RemoteDebugger::flush_output() { } void RemoteDebugger::send_message(const String &p_message, const Array &p_args) { - MutexLock lock(mutex); if (is_peer_connected()) { _put_msg(p_message, p_args); @@ -559,7 +585,6 @@ void RemoteDebugger::send_message(const String &p_message, const Array &p_args) } void RemoteDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type) { - ErrorMessage oe; oe.error = p_err; oe.error_descr = p_descr; @@ -574,8 +599,9 @@ void RemoteDebugger::send_error(const String &p_func, const String &p_file, int oe.msec = time % 1000; oe.callstack.append_array(script_debugger->get_error_stack_info()); - if (flushing && Thread::get_caller_id() == flush_thread) // Can't handle recursive errors during flush. + if (flushing && Thread::get_caller_id() == flush_thread) { // Can't handle recursive errors during flush. return; + } MutexLock lock(mutex); @@ -586,7 +612,6 @@ void RemoteDebugger::send_error(const String &p_func, const String &p_file, int } if (is_peer_connected()) { - if (oe.warning) { if (warn_count > max_warnings_per_second) { n_warnings_dropped++; @@ -634,22 +659,27 @@ Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, boo return OK; } const String cap = p_msg.substr(0, idx); - if (!has_capture(cap)) + if (!has_capture(cap)) { return ERR_UNAVAILABLE; // Unknown message... + } const String msg = p_msg.substr(idx + 1); return capture_parse(cap, msg, p_data, r_captured); } void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { - //this function is called when there is a debugger break (bug on script) //or when execution is paused from editor - if (script_debugger->is_skipping_breakpoints() && !p_is_error_breakpoint) + if (script_debugger->is_skipping_breakpoints() && !p_is_error_breakpoint) { return; + } ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway."); + if (!peer->can_block()) { + return; // Peer does not support blocking IO. We could at least send the error though. + } + ScriptLanguage *script_lang = script_debugger->get_break_language(); const String error_str = script_lang ? script_lang->debug_get_error() : ""; Array msg; @@ -659,9 +689,10 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { servers_profiler->skip_profile_frame = true; // Avoid frame time spike in debug. - InputFilter::MouseMode mouse_mode = InputFilter::get_singleton()->get_mouse_mode(); - if (mouse_mode != InputFilter::MOUSE_MODE_VISIBLE) - InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE); + Input::MouseMode mouse_mode = Input::get_singleton()->get_mouse_mode(); + if (mouse_mode != Input::MOUSE_MODE_VISIBLE) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + } uint64_t loop_begin_usec = 0; uint64_t loop_time_sec = 0; @@ -672,7 +703,6 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { peer->poll(); if (peer->has_message()) { - Array cmd = peer->get_message(); ERR_CONTINUE(cmd.size() != 2); @@ -750,10 +780,11 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } else if (command == "breakpoint") { ERR_FAIL_COND(data.size() < 3); bool set = data[2]; - if (set) + if (set) { script_debugger->insert_breakpoint(data[1], data[0]); - else + } else { script_debugger->remove_breakpoint(data[1], data[0]); + } } else if (command == "set_skip_breakpoints") { ERR_FAIL_COND(data.size() < 1); @@ -761,8 +792,9 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } else { bool captured = false; ERR_CONTINUE(_try_capture(command, data, captured) != OK); - if (!captured) + if (!captured) { WARN_PRINT("Unknown message received from debugger: " + command); + } } } else { OS::get_singleton()->delay_usec(10000); @@ -779,18 +811,19 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { send_message("debug_exit", Array()); - if (mouse_mode != InputFilter::MOUSE_MODE_VISIBLE) - InputFilter::get_singleton()->set_mouse_mode(mouse_mode); + if (mouse_mode != Input::MOUSE_MODE_VISIBLE) { + Input::get_singleton()->set_mouse_mode(mouse_mode); + } } void RemoteDebugger::poll_events(bool p_is_idle) { - if (peer.is_null()) + if (peer.is_null()) { return; + } flush_output(); peer->poll(); while (peer->has_message()) { - Array arr = peer->get_message(); ERR_CONTINUE(arr.size() != 2); @@ -806,8 +839,9 @@ void RemoteDebugger::poll_events(bool p_is_idle) { } const String cap = cmd.substr(0, idx); - if (!has_capture(cap)) + if (!has_capture(cap)) { continue; // Unknown message... + } const String msg = cmd.substr(idx + 1); capture_parse(cap, msg, arr[1], parsed); @@ -830,10 +864,11 @@ Error RemoteDebugger::_core_capture(const String &p_cmd, const Array &p_data, bo } else if (p_cmd == "breakpoint") { ERR_FAIL_COND_V(p_data.size() < 3, ERR_INVALID_DATA); bool set = p_data[2]; - if (set) + if (set) { script_debugger->insert_breakpoint(p_data[1], p_data[0]); - else + } else { script_debugger->remove_breakpoint(p_data[1], p_data[0]); + } } else if (p_cmd == "set_skip_breakpoints") { ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA); @@ -863,13 +898,6 @@ Error RemoteDebugger::_profiler_capture(const String &p_cmd, const Array &p_data return OK; } -RemoteDebugger *RemoteDebugger::create_for_uri(const String &p_uri) { - Ref<RemoteDebuggerPeer> peer = RemoteDebuggerPeer::create_from_uri(p_uri); - if (peer.is_valid()) - return memnew(RemoteDebugger(peer)); - return NULL; -} - RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) { peer = p_peer; max_chars_per_second = GLOBAL_GET("network/limits/debugger/max_chars_per_second"); @@ -931,6 +959,7 @@ RemoteDebugger::~RemoteDebugger() { memdelete(servers_profiler); memdelete(network_profiler); memdelete(visual_profiler); - if (performance_profiler) + if (performance_profiler) { memdelete(performance_profiler); + } } diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h index 83789c67f9..dc7e4436e1 100644 --- a/core/debugger/remote_debugger.h +++ b/core/debugger/remote_debugger.h @@ -40,6 +40,11 @@ #include "core/ustring.h" class RemoteDebugger : public EngineDebugger { +public: + enum MessageType { + MESSAGE_TYPE_LOG, + MESSAGE_TYPE_ERROR, + }; private: typedef DebuggerMarshalls::OutputError ErrorMessage; @@ -50,14 +55,18 @@ private: struct VisualProfiler; struct PerformanceProfiler; - NetworkProfiler *network_profiler = NULL; - ServersProfiler *servers_profiler = NULL; - VisualProfiler *visual_profiler = NULL; - PerformanceProfiler *performance_profiler = NULL; + NetworkProfiler *network_profiler = nullptr; + ServersProfiler *servers_profiler = nullptr; + VisualProfiler *visual_profiler = nullptr; + PerformanceProfiler *performance_profiler = nullptr; Ref<RemoteDebuggerPeer> peer; - List<String> output_strings; + struct OutputString { + String message; + MessageType type; + }; + List<OutputString> output_strings; List<ErrorMessage> errors; int n_messages_dropped = 0; @@ -99,8 +108,6 @@ private: Error _try_capture(const String &p_name, const Array &p_data, bool &r_captured); public: - static RemoteDebugger *create_for_uri(const String &p_uri); - // Overrides void poll_events(bool p_is_idle); void send_message(const String &p_message, const Array &p_args); diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp index 42c2c8e309..faa3a75fda 100644 --- a/core/debugger/remote_debugger_peer.cpp +++ b/core/debugger/remote_debugger_peer.cpp @@ -52,8 +52,9 @@ Array RemoteDebuggerPeerTCP::get_message() { Error RemoteDebuggerPeerTCP::put_message(const Array &p_arr) { MutexLock lock(mutex); - if (out_queue.size() >= max_queued_messages) + if (out_queue.size() >= max_queued_messages) { return ERR_OUT_OF_MEMORY; + } out_queue.push_back(p_arr); return OK; @@ -68,7 +69,7 @@ void RemoteDebuggerPeerTCP::close() { running = false; Thread::wait_to_finish(thread); memdelete(thread); - thread = NULL; + thread = nullptr; } tcp_client->disconnect_from_host(); out_buf.resize(0); @@ -99,14 +100,15 @@ void RemoteDebuggerPeerTCP::_write_out() { while (tcp_client->poll(NetSocket::POLL_TYPE_OUT) == OK) { uint8_t *buf = out_buf.ptrw(); if (out_left <= 0) { - if (out_queue.size() == 0) + if (out_queue.size() == 0) { break; // Nothing left to send + } mutex.lock(); Variant var = out_queue[0]; out_queue.pop_front(); mutex.unlock(); int size = 0; - Error err = encode_variant(var, NULL, size); + Error err = encode_variant(var, nullptr, size); ERR_CONTINUE(err != OK || size > out_buf.size() - 4); // 4 bytes separator. encode_uint32(size, buf); encode_variant(var, buf + 4, size); @@ -154,12 +156,12 @@ void RemoteDebuggerPeerTCP::_read_in() { } Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_port) { - IP_Address ip; - if (p_host.is_valid_ip_address()) + if (p_host.is_valid_ip_address()) { ip = p_host; - else + } else { ip = IP::get_singleton()->resolve_hostname(p_host); + } int port = p_port; @@ -169,23 +171,20 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po tcp_client->connect_to_host(ip, port); for (int i = 0; i < tries; i++) { - if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) { print_verbose("Remote Debugger: Connected!"); break; } else { - const int ms = waits[i]; OS::get_singleton()->delay_usec(ms * 1000); print_verbose("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in " + String::num(ms) + " msec."); - }; - }; + } + } if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) { - ERR_PRINT("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status()) + "."); return FAILED; - }; + } connected = true; #ifndef NO_THREADS running = true; @@ -198,8 +197,9 @@ void RemoteDebuggerPeerTCP::_thread_func(void *p_ud) { RemoteDebuggerPeerTCP *peer = (RemoteDebuggerPeerTCP *)p_ud; while (peer->running && peer->is_peer_connected()) { peer->_poll(); - if (!peer->is_peer_connected()) + if (!peer->is_peer_connected()) { break; + } peer->tcp_client->poll(NetSocket::POLL_TYPE_IN_OUT, 1); } } @@ -218,9 +218,8 @@ void RemoteDebuggerPeerTCP::_poll() { } } -Ref<RemoteDebuggerPeer> RemoteDebuggerPeer::create_from_uri(const String p_uri) { - if (!p_uri.begins_with("tcp://")) - return Ref<RemoteDebuggerPeer>(); // Only TCP supported for now, more to come. +RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) { + ERR_FAIL_COND_V(!p_uri.begins_with("tcp://"), nullptr); String debug_host = p_uri.replace("tcp://", ""); uint16_t debug_port = 6007; @@ -230,10 +229,13 @@ Ref<RemoteDebuggerPeer> RemoteDebuggerPeer::create_from_uri(const String p_uri) debug_port = debug_host.substr(sep_pos + 1).to_int(); debug_host = debug_host.substr(0, sep_pos); } - Ref<RemoteDebuggerPeerTCP> peer = Ref<RemoteDebuggerPeer>(memnew(RemoteDebuggerPeerTCP)); + + RemoteDebuggerPeerTCP *peer = memnew(RemoteDebuggerPeerTCP); Error err = peer->connect_to_host(debug_host, debug_port); - if (err != OK) - return Ref<RemoteDebuggerPeer>(); + if (err != OK) { + memdelete(peer); + return nullptr; + } return peer; } diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h index 6fc3214a51..3a75a2a02b 100644 --- a/core/debugger/remote_debugger_peer.h +++ b/core/debugger/remote_debugger_peer.h @@ -42,7 +42,6 @@ protected: int max_queued_messages = 4096; public: - static Ref<RemoteDebuggerPeer> create_from_uri(const String p_uri); virtual bool is_peer_connected() = 0; virtual bool has_message() = 0; virtual Error put_message(const Array &p_arr) = 0; @@ -50,6 +49,7 @@ public: virtual void close() = 0; virtual void poll() = 0; virtual int get_max_message_size() const = 0; + virtual bool can_block() const { return true; } // If blocking io is allowed on main thread (debug). RemoteDebuggerPeer(); }; @@ -58,7 +58,7 @@ class RemoteDebuggerPeerTCP : public RemoteDebuggerPeer { private: Ref<StreamPeerTCP> tcp_client; Mutex mutex; - Thread *thread = NULL; + Thread *thread = nullptr; List<Array> in_queue; List<Array> out_queue; int out_left = 0; @@ -77,6 +77,8 @@ private: void _read_in(); public: + static RemoteDebuggerPeer *create(const String &p_uri); + Error connect_to_host(const String &p_host, uint16_t p_port); void poll(); diff --git a/core/debugger/script_debugger.cpp b/core/debugger/script_debugger.cpp index 935ad01d80..0cd3238efb 100644 --- a/core/debugger/script_debugger.cpp +++ b/core/debugger/script_debugger.cpp @@ -33,69 +33,63 @@ #include "core/debugger/engine_debugger.h" void ScriptDebugger::set_lines_left(int p_left) { - lines_left = p_left; } int ScriptDebugger::get_lines_left() const { - return lines_left; } void ScriptDebugger::set_depth(int p_depth) { - depth = p_depth; } int ScriptDebugger::get_depth() const { - return depth; } void ScriptDebugger::insert_breakpoint(int p_line, const StringName &p_source) { - - if (!breakpoints.has(p_line)) + if (!breakpoints.has(p_line)) { breakpoints[p_line] = Set<StringName>(); + } breakpoints[p_line].insert(p_source); } void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) { - - if (!breakpoints.has(p_line)) + if (!breakpoints.has(p_line)) { return; + } breakpoints[p_line].erase(p_source); - if (breakpoints[p_line].size() == 0) + if (breakpoints[p_line].size() == 0) { breakpoints.erase(p_line); + } } -bool ScriptDebugger::is_breakpoint(int p_line, const StringName &p_source) const { - if (!breakpoints.has(p_line)) +bool ScriptDebugger::is_breakpoint(int p_line, const StringName &p_source) const { + if (!breakpoints.has(p_line)) { return false; + } return breakpoints[p_line].has(p_source); } -bool ScriptDebugger::is_breakpoint_line(int p_line) const { +bool ScriptDebugger::is_breakpoint_line(int p_line) const { return breakpoints.has(p_line); } String ScriptDebugger::breakpoint_find_source(const String &p_source) const { - return p_source; } void ScriptDebugger::clear_breakpoints() { - breakpoints.clear(); } void ScriptDebugger::set_skip_breakpoints(bool p_skip_breakpoints) { - skip_breakpoints = p_skip_breakpoints; } bool ScriptDebugger::is_skipping_breakpoints() { - return skip_breakpoints; } @@ -118,6 +112,5 @@ Vector<ScriptLanguage::StackInfo> ScriptDebugger::get_error_stack_info() const { } ScriptLanguage *ScriptDebugger::get_break_language() const { - return break_lang; } diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h index a60b57c637..0068691825 100644 --- a/core/debugger/script_debugger.h +++ b/core/debugger/script_debugger.h @@ -38,7 +38,6 @@ #include "core/vector.h" class ScriptDebugger { - typedef ScriptLanguage::StackInfo StackInfo; int lines_left = -1; @@ -47,7 +46,7 @@ class ScriptDebugger { Map<int, Set<StringName>> breakpoints; - ScriptLanguage *break_lang = NULL; + ScriptLanguage *break_lang = nullptr; Vector<StackInfo> error_stack_info; public: |