From: Zoltan Varga Date: Thu, 31 Aug 2017 11:17:02 +0000 (-0400) Subject: [sdb] Fix support for async debugging in optimized mode, roslyn generates valuetype... X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=19046502886ad7697b4c6642337441a7fdafd28a [sdb] Fix support for async debugging in optimized mode, roslyn generates valuetype IAsyncStateMethod implementations. Fixes #58728. (#5476) --- diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index dae5ed21a1c..4a2637c1943 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -4746,25 +4746,17 @@ breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly) return bp->method && bp->method->klass->image->assembly == assembly; } -static MonoObject* -get_this (StackFrame *frame) +static gpointer +get_this_addr (StackFrame *frame) { //Logic inspiered by "add_var" method and took out path that happens in async method for getting this MonoDebugVarInfo *var = frame->jit->this_var; if ((var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) != MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) return NULL; - guint8 * addr = (guint8 *)mono_arch_context_get_int_reg (&frame->ctx, var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS); + guint8 *addr = (guint8 *)mono_arch_context_get_int_reg (&frame->ctx, var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS); addr += (gint32)var->offset; - return *(MonoObject**)addr; -} - -//This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not -//since thread probably changed... -static int -get_this_async_id (StackFrame *frame) -{ - return get_objid (get_this (frame)); + return addr; } static MonoMethod* @@ -4779,25 +4771,100 @@ get_set_notification_method (MonoClass* async_builder_class) return set_notification_method; } -static void -set_set_notification_for_wait_completion_flag (StackFrame *frame) +static MonoMethod* +get_object_id_for_debugger_method (MonoClass* async_builder_class) +{ + MonoError error; + GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, FALSE, FALSE, &error); + mono_error_assert_ok (&error); + g_assert (array->len == 1); + MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0); + g_ptr_array_free (array, TRUE); + return method; +} + +/* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */ +static gpointer +get_async_method_builder (StackFrame *frame) { - MonoObject* obj = get_this (frame); - g_assert (obj); - MonoClassField *builder_field = mono_class_get_field_from_name (obj->vtable->klass, "<>t__builder"); + MonoObject *this_obj; + MonoClassField *builder_field; + gpointer builder; + guint8 *this_addr; + + builder_field = mono_class_get_field_from_name (frame->method->klass, "<>t__builder"); g_assert (builder_field); - MonoObject* builder; + + this_addr = get_this_addr (frame); + if (!this_addr) + return NULL; + + if (frame->method->klass->valuetype) { + guint8 *vtaddr = *(guint8**)this_addr; + builder = (char*)vtaddr + builder_field->offset - sizeof (MonoObject); + } else { + this_obj = *(MonoObject**)this_addr; + builder = (char*)this_obj + builder_field->offset; + } + + return builder; +} + +//This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not +//since thread probably changed... +static int +get_this_async_id (StackFrame *frame) +{ + MonoClassField *builder_field; + gpointer builder; + MonoMethod *method; + MonoObject *ex; MonoError error; - builder = mono_field_get_value_object_checked (frame->domain, builder_field, obj, &error); + MonoObject *obj; + gboolean old_disable_breakpoints = FALSE; + DebuggerTlsData *tls; + + /* + * FRAME points to a method in a state machine class/struct. + * Call the ObjectIdForDebugger method of the associated method builder type. + */ + builder = get_async_method_builder (frame); + if (!builder) + return 0; + + builder_field = mono_class_get_field_from_name (frame->method->klass, "<>t__builder"); + g_assert (builder_field); + + tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); + if (tls) { + old_disable_breakpoints = tls->disable_breakpoints; + tls->disable_breakpoints = TRUE; + } + + method = get_object_id_for_debugger_method (mono_class_from_mono_type (builder_field->type)); + obj = mono_runtime_try_invoke (method, builder, NULL, &ex, &error); mono_error_assert_ok (&error); + + if (tls) + tls->disable_breakpoints = old_disable_breakpoints; + + return get_objid (obj); +} + +static void +set_set_notification_for_wait_completion_flag (StackFrame *frame) +{ + MonoClassField *builder_field = mono_class_get_field_from_name (frame->method->klass, "<>t__builder"); + g_assert (builder_field); + gpointer builder = get_async_method_builder (frame); g_assert (builder); void* args [1]; gboolean arg = TRUE; + MonoError error; args [0] = &arg; - mono_runtime_invoke_checked (get_set_notification_method (builder->vtable->klass), mono_object_unbox (builder), args, &error); + mono_runtime_invoke_checked (get_set_notification_method (mono_class_from_mono_type (builder_field->type)), builder, args, &error); mono_error_assert_ok (&error); - mono_field_set_value (obj, builder_field, mono_object_unbox (builder)); } static MonoMethod* notify_debugger_of_wait_completion_method_cache = NULL;