diff options
author | Ignacio Etcheverry <ignalfonsore@gmail.com> | 2018-01-09 17:19:03 +0100 |
---|---|---|
committer | Ignacio Etcheverry <ignalfonsore@gmail.com> | 2018-01-09 17:19:03 +0100 |
commit | 5be356b72f5b765cdec069c2c4a4011a42fabc47 (patch) | |
tree | 5a8bc0f7a3e9cb0646634e5df57d9c73d98d6a09 /modules/mono/mono_gd/gd_mono_utils.cpp | |
parent | 52165fa12de7ca76898a7c1855a2f23797b2c2ed (diff) | |
download | redot-engine-5be356b72f5b765cdec069c2c4a4011a42fabc47.tar.gz |
Mono: Implement stack info for errors and exceptions
Diffstat (limited to 'modules/mono/mono_gd/gd_mono_utils.cpp')
-rw-r--r-- | modules/mono/mono_gd/gd_mono_utils.cpp | 73 |
1 files changed, 70 insertions, 3 deletions
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index ff999b36f2..4aa2c007c2 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -31,6 +31,7 @@ #include "gd_mono_utils.h" #include "os/dir_access.h" +#include "os/os.h" #include "project_settings.h" #include "reference.h" @@ -53,6 +54,7 @@ MonoCache mono_cache; #define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_ns##_##m_class, m_val) #define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.rawclass_##m_class, m_val) #define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val) +#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val) #define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val) void MonoCache::clear_members() { @@ -72,6 +74,13 @@ void MonoCache::clear_members() { class_String = NULL; class_IntPtr = NULL; +#ifdef DEBUG_ENABLED + class_System_Diagnostics_StackTrace = NULL; + methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL; + method_System_Diagnostics_StackTrace_ctor_bool = NULL; + method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL; +#endif + rawclass_Dictionary = NULL; class_Vector2 = NULL; @@ -94,6 +103,11 @@ void MonoCache::clear_members() { class_WeakRef = NULL; class_MarshalUtils = NULL; +#ifdef DEBUG_ENABLED + class_DebuggingUtils = NULL; + methodthunk_DebuggingUtils_GetStackFrameInfo = NULL; +#endif + class_ExportAttribute = NULL; field_ExportAttribute_hint = NULL; field_ExportAttribute_hintString = NULL; @@ -137,6 +151,13 @@ void update_corlib_cache() { CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class())); CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class())); CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class())); + +#ifdef DEBUG_ENABLED + CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace")); + CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method("GetFrames")->get_thunk()); + CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true)); + CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true)); +#endif } void update_godot_api_cache() { @@ -161,6 +182,10 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef)); CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils)); +#ifdef DEBUG_ENABLED + CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils)); +#endif + // Attributes CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); @@ -183,6 +208,10 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk()); CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk()); +#ifdef DEBUG_ENABLED + CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)->get_thunk()); +#endif + { /* * TODO Right now we only support Dictionary<object, object>. @@ -366,9 +395,47 @@ String get_exception_name_and_message(MonoObject *p_ex) { return res; } -void print_unhandled_exception(MonoObject *p_ex) { - ERR_PRINT(GDMonoUtils::get_exception_name_and_message(p_ex).utf8()); - mono_print_unhandled_exception(p_ex); +void print_unhandled_exception(MonoObject *p_exc) { + print_unhandled_exception(p_exc, false); +} + +void print_unhandled_exception(MonoObject *p_exc, bool p_fail_silently) { + mono_print_unhandled_exception(p_exc); +#ifdef DEBUG_ENABLED + GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace); + MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr()); + + MonoBoolean need_file_info = true; + void *ctor_args[2] = { p_exc, &need_file_info }; + + MonoObject *unexpected_exc = NULL; + CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc); + + if (unexpected_exc != NULL) { + mono_print_unhandled_exception(unexpected_exc); + + if (p_fail_silently) { + // Called from CSharpLanguage::get_current_stack_info, + // so printing an error here could result in endless recursion + OS::get_singleton()->printerr("Mono: Method GDMonoUtils::print_unhandled_exception failed"); + return; + } else { + ERR_FAIL(); + } + } + + Vector<ScriptLanguage::StackInfo> si; + if (stack_trace != NULL) + si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace); + + String file = si.size() ? si[0].file : __FILE__; + String func = si.size() ? si[0].func : FUNCTION_STR; + int line = si.size() ? si[0].line : __LINE__; + String error_msg = "Unhandled exception"; + String exc_msg = GDMonoUtils::get_exception_name_and_message(p_exc); + + ScriptDebugger::get_singleton()->send_error(func, file, line, error_msg, exc_msg, ERR_HANDLER_ERROR, si); +#endif } } // namespace GDMonoUtils |