From d1da2c29955c851d74037a5196168a0a90507f9a Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Tue, 4 Aug 2015 09:47:32 -0300 Subject: [PATCH] error debugger shows the list of errors that happened during running the game, traces can be analyzed --- core/script_debugger_remote.cpp | 123 ++++++++++++++++++++++- core/script_debugger_remote.h | 27 +++++ core/script_language.h | 7 ++ main/main.cpp | 2 +- modules/gdscript/gd_script.h | 13 +++ tools/editor/script_editor_debugger.cpp | 126 ++++++++++++++++++++++++ tools/editor/script_editor_debugger.h | 12 +++ 7 files changed, 307 insertions(+), 3 deletions(-) diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 15be8b1d002..2ec858eb8bd 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -289,6 +289,37 @@ void ScriptDebuggerRemote::_get_output() { messages.pop_front(); locking=false; } + + while (errors.size()) { + locking=true; + packet_peer_stream->put_var("error"); + OutputError oe = errors.front()->get(); + + packet_peer_stream->put_var(oe.callstack.size()+2); + + Array error_data; + + error_data.push_back(oe.hr); + error_data.push_back(oe.min); + error_data.push_back(oe.sec); + error_data.push_back(oe.msec); + error_data.push_back(oe.source_func); + error_data.push_back(oe.source_file); + error_data.push_back(oe.source_line); + error_data.push_back(oe.error); + error_data.push_back(oe.error_descr); + error_data.push_back(oe.warning); + packet_peer_stream->put_var(error_data); + packet_peer_stream->put_var(oe.callstack.size()); + for(int i=0;iput_var(oe.callstack[i]); + + } + + errors.pop_front(); + locking=false; + + } mutex->unlock(); } @@ -303,6 +334,61 @@ void ScriptDebuggerRemote::line_poll() { } +void ScriptDebuggerRemote::_err_handler(void* ud,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) + return; //ignore script errors, those go through debugger + + ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote*)ud; + + OutputError oe; + oe.error=p_err; + oe.error_descr=p_descr; + oe.source_file=p_file; + oe.source_line=p_line; + oe.source_func=p_func; + oe.warning=p_type==ERR_HANDLER_WARNING; + uint64_t time = OS::get_singleton()->get_ticks_msec(); + oe.hr=time/3600000; + oe.min=(time/60000)%60; + oe.sec=(time/1000)%60; + oe.msec=time%1000; + Array cstack; + + Vector si; + + for(int i=0;idebug_get_current_stack_info(); + if (si.size()) + break; + } + + cstack.resize(si.size()*2); + for(int i=0;iget_path(); + line=si[i].line; + } + cstack[i*2+0]=path; + cstack[i*2+1]=line; + } + + oe.callstack=cstack; + + + sdr->mutex->lock(); + + if (!sdr->locking && sdr->tcp_client->is_connected()) { + + sdr->errors.push_back(oe); + } + + sdr->mutex->unlock(); +} + + bool ScriptDebuggerRemote::_parse_live_edit(const Array& cmd) { String cmdstr = cmd[0]; @@ -497,10 +583,35 @@ void ScriptDebuggerRemote::_print_handler(void *p_this,const String& p_string) { ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote*)p_this; + uint64_t ticks = OS::get_singleton()->get_ticks_usec()/1000; + sdr->msec_count+=ticks-sdr->last_msec; + sdr->last_msec=ticks; + + if (sdr->msec_count>1000) { + sdr->char_count=0; + sdr->msec_count=0; + } + + String s = p_string; + int allowed_chars = MIN(MAX(sdr->max_cps - sdr->char_count,0), s.length()); + + if (allowed_chars==0) + return; + + if (allowed_charschar_count+=allowed_chars; + + if (sdr->char_count>=sdr->max_cps) { + s+="\n[output overflow, print less text!]\n"; + } + sdr->mutex->lock(); if (!sdr->locking && sdr->tcp_client->is_connected()) { - sdr->output_strings .push_back(p_string); + sdr->output_strings.push_back(s); } sdr->mutex->unlock(); } @@ -538,13 +649,21 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() { poll_every=0; request_scene_tree=NULL; live_edit_funcs=NULL; + max_cps = GLOBAL_DEF("debug/max_remote_stdout_chars_per_second",2048); + char_count=0; + msec_count=0; + last_msec=0; + + eh.errfunc=_err_handler; + eh.userdata=this; + add_error_handler(&eh); } ScriptDebuggerRemote::~ScriptDebuggerRemote() { remove_print_handler(&phl); + remove_error_handler(&eh); memdelete(mutex); - } diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h index 748b77eccd4..c2642782a9c 100644 --- a/core/script_debugger_remote.h +++ b/core/script_debugger_remote.h @@ -49,8 +49,31 @@ class ScriptDebuggerRemote : public ScriptDebugger { Object *performance; bool requested_quit; Mutex *mutex; + + struct OutputError { + + int hr; + int min; + int sec; + int msec; + String source_file; + String source_func; + int source_line; + String error; + String error_descr; + bool warning; + Array callstack; + + }; + List output_strings; List messages; + List errors; + + int max_cps; + int char_count; + uint64_t last_msec; + uint64_t msec_count; bool locking; //hack to avoid a deadloop static void _print_handler(void *p_this,const String& p_string); @@ -69,6 +92,10 @@ class ScriptDebuggerRemote : public ScriptDebugger { LiveEditFuncs *live_edit_funcs; + ErrorHandlerList eh; + static void _err_handler(void*,const char*,const char*,int p_line,const char *, const char *,ErrorHandlerType p_type); + + public: Error connect_to_host(const String& p_host,uint16_t p_port); diff --git a/core/script_language.h b/core/script_language.h index d5fb83deb16..5a0f673b94c 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -176,6 +176,13 @@ public: virtual void debug_get_globals(List *p_locals, List *p_values, int p_max_subitems=-1,int p_max_depth=-1)=0; virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1)=0; + struct StackInfo { + Ref