From 887ccb8b68264688966225ddda7677e453402dbe Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Mon, 14 Sep 2020 13:01:37 -0300 Subject: [PATCH 1/3] Fix assert when calling set_set_notification_for_wait_completion_flag --- src/mono/mono/mini/debugger-agent.c | 157 ------------------------ src/mono/mono/mini/debugger-engine.c | 129 +++++++++++++++++++ src/mono/mono/mini/debugger-engine.h | 36 ++++++ src/mono/mono/mini/mini-wasm-debugger.c | 13 -- 4 files changed, 165 insertions(+), 170 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 780332672fc68f..a0d5a92da1db02 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -136,35 +136,6 @@ typedef struct { gboolean setpgid; } AgentConfig; -typedef struct -{ - //Must be the first field to ensure pointer equivalence - DbgEngineStackFrame de; - int id; - guint32 il_offset; - /* - * If method is gshared, this is the actual instance, otherwise this is equal to - * method. - */ - MonoMethod *actual_method; - /* - * This is the method which is visible to debugger clients. Same as method, - * except for native-to-managed wrappers. - */ - MonoMethod *api_method; - MonoContext ctx; - MonoDebugMethodJitInfo *jit; - MonoInterpFrameHandle interp_frame; - gpointer frame_addr; - int flags; - host_mgreg_t *reg_locations [MONO_MAX_IREGS]; - /* - * Whenever ctx is set. This is FALSE for the last frame of running threads, since - * the frame can become invalid. - */ - gboolean has_ctx; -} StackFrame; - typedef struct _InvokeData InvokeData; struct _InvokeData @@ -740,7 +711,6 @@ static void ss_calculate_framecount (void *tls, MonoContext *ctx, gboolean force static gboolean ensure_jit (DbgEngineStackFrame* the_frame); static int ensure_runtime_is_suspended (void); static int get_this_async_id (DbgEngineStackFrame *frame); -static gboolean set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame); static MonoMethod* get_notify_debugger_of_wait_completion_method (void); static void* create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind); static void process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset); @@ -4551,37 +4521,6 @@ breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly) return bp->method && m_class_get_image (bp->method->klass)->assembly == assembly; } -static gpointer -get_this_addr (DbgEngineStackFrame *the_frame) -{ - StackFrame *frame = (StackFrame *)the_frame; - if (frame->de.ji->is_interp) - return mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame); - - 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); - addr += (gint32)var->offset; - return addr; -} - -static MonoMethod* -get_set_notification_method (MonoClass* async_builder_class) -{ - ERROR_DECL (error); - GPtrArray* array = mono_class_get_methods_by_name (async_builder_class, "SetNotificationForWaitCompletion", 0x24, 1, FALSE, error); - mono_error_assert_ok (error); - if (array->len == 0) { - g_ptr_array_free (array, TRUE); - return NULL; - } - MonoMethod* set_notification_method = (MonoMethod *)g_ptr_array_index (array, 0); - g_ptr_array_free (array, TRUE); - return set_notification_method; -} - static MonoMethod* get_object_id_for_debugger_method (MonoClass* async_builder_class) { @@ -4603,62 +4542,6 @@ get_object_id_for_debugger_method (MonoClass* async_builder_class) return method; } -static MonoClass * -get_class_to_get_builder_field(DbgEngineStackFrame *frame) -{ - ERROR_DECL (error); - gpointer this_addr = get_this_addr (frame); - MonoClass *original_class = frame->method->klass; - MonoClass *ret; - if (!m_class_is_valuetype (original_class) && mono_class_is_open_constructed_type (m_class_get_byval_arg (original_class))) { - MonoObject *this_obj = *(MonoObject**)this_addr; - MonoGenericContext context; - MonoType *inflated_type; - - if (!this_obj) - return NULL; - - context = mono_get_generic_context_from_stack_frame (frame->ji, this_obj->vtable); - inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (original_class), &context, error); - mono_error_assert_ok (error); /* FIXME don't swallow the error */ - - ret = mono_class_from_mono_type_internal (inflated_type); - mono_metadata_free_type (inflated_type); - return ret; - } - return original_class; -} - - -/* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */ -static gpointer -get_async_method_builder (DbgEngineStackFrame *frame) -{ - MonoObject *this_obj; - MonoClassField *builder_field; - gpointer builder; - gpointer this_addr; - MonoClass* klass = frame->method->klass; - - klass = get_class_to_get_builder_field(frame); - builder_field = mono_class_get_field_from_name_full (klass, "<>t__builder", NULL); - if (!builder_field) - return NULL; - - this_addr = get_this_addr (frame); - if (!this_addr) - return NULL; - - if (m_class_is_valuetype (klass)) { - builder = mono_vtype_get_field_addr (*(guint8**)this_addr, builder_field); - } 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 @@ -4706,46 +4589,6 @@ get_this_async_id (DbgEngineStackFrame *frame) return get_objid (obj); } -// Returns true if TaskBuilder has NotifyDebuggerOfWaitCompletion method -// false if not(AsyncVoidBuilder) -static gboolean -set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame) -{ - MonoClassField *builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL); - if (!builder_field) - return FALSE; - gpointer builder = get_async_method_builder (frame); - if (!builder) - return FALSE; - - MonoMethod* method = get_set_notification_method (mono_class_from_mono_type_internal (builder_field->type)); - if (method == NULL) - return FALSE; - gboolean arg = TRUE; - ERROR_DECL (error); - void *args [ ] = { &arg }; - mono_runtime_invoke_checked (method, builder, args, error); - mono_error_assert_ok (error); - return TRUE; -} - -static MonoMethod* notify_debugger_of_wait_completion_method_cache; - -static MonoMethod* -get_notify_debugger_of_wait_completion_method (void) -{ - if (notify_debugger_of_wait_completion_method_cache != NULL) - return notify_debugger_of_wait_completion_method_cache; - ERROR_DECL (error); - MonoClass* task_class = mono_class_load_from_name (mono_defaults.corlib, "System.Threading.Tasks", "Task"); - GPtrArray* array = mono_class_get_methods_by_name (task_class, "NotifyDebuggerOfWaitCompletion", 0x24, 1, FALSE, error); - mono_error_assert_ok (error); - g_assert (array->len == 1); - notify_debugger_of_wait_completion_method_cache = (MonoMethod *)g_ptr_array_index (array, 0); - g_ptr_array_free (array, TRUE); - return notify_debugger_of_wait_completion_method_cache; -} - static gboolean begin_breakpoint_processing (void *the_tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal) { diff --git a/src/mono/mono/mini/debugger-engine.c b/src/mono/mono/mini/debugger-engine.c index 53726f05023505..1df1d2f7e3ec22 100644 --- a/src/mono/mono/mini/debugger-engine.c +++ b/src/mono/mono/mini/debugger-engine.c @@ -1606,4 +1606,133 @@ mono_debugger_free_objref (gpointer value) g_free (o); } + +// Returns true if TaskBuilder has NotifyDebuggerOfWaitCompletion method +// false if not(AsyncVoidBuilder) +MonoClass * +get_class_to_get_builder_field(DbgEngineStackFrame *frame) +{ + ERROR_DECL (error); + gpointer this_addr = get_this_addr (frame); + MonoClass *original_class = frame->method->klass; + MonoClass *ret; + if (!m_class_is_valuetype (original_class) && mono_class_is_open_constructed_type (m_class_get_byval_arg (original_class))) { + MonoObject *this_obj = *(MonoObject**)this_addr; + MonoGenericContext context; + MonoType *inflated_type; + + if (!this_obj) + return NULL; + + context = mono_get_generic_context_from_stack_frame (frame->ji, this_obj->vtable); + inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (original_class), &context, error); + mono_error_assert_ok (error); /* FIXME don't swallow the error */ + + ret = mono_class_from_mono_type_internal (inflated_type); + mono_metadata_free_type (inflated_type); + return ret; + } + return original_class; +} + + +gboolean +set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame) +{ + MonoClassField *builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL); + if (!builder_field) + return FALSE; + gpointer builder = get_async_method_builder (frame); + if (!builder) + return FALSE; + + MonoMethod* method = get_set_notification_method (mono_class_from_mono_type_internal (builder_field->type)); + if (method == NULL) + return FALSE; + gboolean arg = TRUE; + ERROR_DECL (error); + void *args [ ] = { &arg }; + mono_runtime_invoke_checked (method, builder, args, error); + mono_error_assert_ok (error); + return TRUE; +} + +gpointer +get_this_addr (DbgEngineStackFrame *the_frame) +{ + StackFrame *frame = (StackFrame *)the_frame; + if (frame->de.ji->is_interp) + return mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame); + + 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); + addr += (gint32)var->offset; + return addr; +} + +/* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */ +gpointer +get_async_method_builder (DbgEngineStackFrame *frame) +{ + MonoObject *this_obj; + MonoClassField *builder_field; + gpointer builder; + gpointer this_addr; + MonoClass* klass = frame->method->klass; + + klass = get_class_to_get_builder_field(frame); + builder_field = mono_class_get_field_from_name_full (klass, "<>t__builder", NULL); + if (!builder_field) + return NULL; + + this_addr = get_this_addr (frame); + if (!this_addr) + return NULL; + + if (m_class_is_valuetype (klass)) { + builder = mono_vtype_get_field_addr (*(guint8**)this_addr, builder_field); + } else { + this_obj = *(MonoObject**)this_addr; + builder = (char*)this_obj + builder_field->offset; + } + + return builder; +} + +MonoMethod* +get_set_notification_method (MonoClass* async_builder_class) +{ + ERROR_DECL (error); + GPtrArray* array = mono_class_get_methods_by_name (async_builder_class, "SetNotificationForWaitCompletion", 0x24, 1, FALSE, error); + mono_error_assert_ok (error); + if (array->len == 0) { + g_ptr_array_free (array, TRUE); + return NULL; + } + MonoMethod* set_notification_method = (MonoMethod *)g_ptr_array_index (array, 0); + g_ptr_array_free (array, TRUE); + return set_notification_method; +} + +static MonoMethod* notify_debugger_of_wait_completion_method_cache; + +MonoMethod* +get_notify_debugger_of_wait_completion_method (void) +{ + if (notify_debugger_of_wait_completion_method_cache != NULL) + return notify_debugger_of_wait_completion_method_cache; + ERROR_DECL (error); + MonoClass* task_class = mono_class_load_from_name (mono_defaults.corlib, "System.Threading.Tasks", "Task"); + GPtrArray* array = mono_class_get_methods_by_name (task_class, "NotifyDebuggerOfWaitCompletion", 0x24, 1, FALSE, error); + mono_error_assert_ok (error); + g_assert (array->len == 1); + notify_debugger_of_wait_completion_method_cache = (MonoMethod *)g_ptr_array_index (array, 0); + g_ptr_array_free (array, TRUE); + return notify_debugger_of_wait_completion_method_cache; +} + + #endif diff --git a/src/mono/mono/mini/debugger-engine.h b/src/mono/mono/mini/debugger-engine.h index 7a62e2142fbed4..8c86ed5ca0525b 100644 --- a/src/mono/mono/mini/debugger-engine.h +++ b/src/mono/mono/mini/debugger-engine.h @@ -8,6 +8,8 @@ #include "mini.h" #include #include +#include +#include /* FIXME: @@ -206,6 +208,34 @@ typedef struct { MonoGCHandle handle; } ObjRef; +typedef struct +{ + //Must be the first field to ensure pointer equivalence + DbgEngineStackFrame de; + int id; + guint32 il_offset; + /* + * If method is gshared, this is the actual instance, otherwise this is equal to + * method. + */ + MonoMethod *actual_method; + /* + * This is the method which is visible to debugger clients. Same as method, + * except for native-to-managed wrappers. + */ + MonoMethod *api_method; + MonoContext ctx; + MonoDebugMethodJitInfo *jit; + MonoInterpFrameHandle interp_frame; + gpointer frame_addr; + int flags; + host_mgreg_t *reg_locations [MONO_MAX_IREGS]; + /* + * Whenever ctx is set. This is FALSE for the last frame of running threads, since + * the frame can become invalid. + */ + gboolean has_ctx; +} StackFrame; void mono_debugger_free_objref (gpointer value); @@ -287,4 +317,10 @@ DbgEngineErrorCode mono_de_ss_create (MonoInternalThread *thread, StepSize size, void mono_de_cancel_ss (SingleStepReq *req); void mono_de_cancel_all_ss (void); +gboolean set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame); +MonoClass * get_class_to_get_builder_field(DbgEngineStackFrame *frame); +gpointer get_this_addr (DbgEngineStackFrame *the_frame); +gpointer get_async_method_builder (DbgEngineStackFrame *frame); +MonoMethod* get_set_notification_method (MonoClass* async_builder_class); +MonoMethod* get_notify_debugger_of_wait_completion_method (void); #endif diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index baef84e824cb60..aed8e0cf0b4b6b 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -236,19 +236,6 @@ get_this_async_id (DbgEngineStackFrame *f) return 0; } -static gboolean -set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *f) -{ - g_error ("set_set_notification_for_wait_completion_flag"); - return FALSE; -} - -static MonoMethod* -get_notify_debugger_of_wait_completion_method (void) -{ - g_error ("get_notify_debugger_of_wait_completion_method"); -} - typedef struct { gboolean is_ss; //do I need this? } BpEvents; From c7c7055b79223ffcbfd708b041c03c0ac4611a8a Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 14 Sep 2020 22:06:29 -0300 Subject: [PATCH 2/3] Fix compilation error. --- src/mono/mono/mini/debugger-agent.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index a0d5a92da1db02..dd8401199d8c4e 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -711,7 +711,6 @@ static void ss_calculate_framecount (void *tls, MonoContext *ctx, gboolean force static gboolean ensure_jit (DbgEngineStackFrame* the_frame); static int ensure_runtime_is_suspended (void); static int get_this_async_id (DbgEngineStackFrame *frame); -static MonoMethod* get_notify_debugger_of_wait_completion_method (void); static void* create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind); static void process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset); static int ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args); From afd438a70a6aac0822c6a0b3625de1d375773327 Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 16 Sep 2020 23:13:33 -0300 Subject: [PATCH 3/3] Merging #42299 to backport together with #42227. --- src/mono/mono/mini/debugger-agent.c | 21 ----- src/mono/mono/mini/debugger-engine.c | 20 +++++ src/mono/mono/mini/debugger-engine.h | 1 + src/mono/mono/mini/mini-wasm-debugger.c | 81 +++++++++++++------ .../wasm/debugger/DebuggerTestSuite/Tests.cs | 28 +++++++ .../debugger/tests/debugger-async-step.cs | 24 ++++++ 6 files changed, 128 insertions(+), 47 deletions(-) create mode 100644 src/mono/wasm/debugger/tests/debugger-async-step.cs diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index dd8401199d8c4e..181b5d8967bc1f 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -4520,27 +4520,6 @@ breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly) return bp->method && m_class_get_image (bp->method->klass)->assembly == assembly; } -static MonoMethod* -get_object_id_for_debugger_method (MonoClass* async_builder_class) -{ - ERROR_DECL (error); - GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, 1, FALSE, error); - mono_error_assert_ok (error); - if (array->len != 1) { - g_ptr_array_free (array, TRUE); - //if we don't find method get_ObjectIdForDebugger we try to find the property Task to continue async debug. - MonoProperty *prop = mono_class_get_property_from_name_internal (async_builder_class, "Task"); - if (!prop) { - DEBUG_PRINTF (1, "Impossible to debug async methods.\n"); - return NULL; - } - return prop->get; - } - MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0); - g_ptr_array_free (array, TRUE); - return method; -} - //This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not //since thread probably changed... static int diff --git a/src/mono/mono/mini/debugger-engine.c b/src/mono/mono/mini/debugger-engine.c index 1df1d2f7e3ec22..0a4870a972f100 100644 --- a/src/mono/mono/mini/debugger-engine.c +++ b/src/mono/mono/mini/debugger-engine.c @@ -1635,6 +1635,26 @@ get_class_to_get_builder_field(DbgEngineStackFrame *frame) return original_class; } +MonoMethod* +get_object_id_for_debugger_method (MonoClass* async_builder_class) +{ + ERROR_DECL (error); + GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, 1, FALSE, error); + mono_error_assert_ok (error); + if (array->len != 1) { + g_ptr_array_free (array, TRUE); + //if we don't find method get_ObjectIdForDebugger we try to find the property Task to continue async debug. + MonoProperty *prop = mono_class_get_property_from_name_internal (async_builder_class, "Task"); + if (!prop) { + DEBUG_PRINTF (1, "Impossible to debug async methods.\n"); + return NULL; + } + return prop->get; + } + MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0); + g_ptr_array_free (array, TRUE); + return method; +} gboolean set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame) diff --git a/src/mono/mono/mini/debugger-engine.h b/src/mono/mono/mini/debugger-engine.h index 8c86ed5ca0525b..ef332db4a59215 100644 --- a/src/mono/mono/mini/debugger-engine.h +++ b/src/mono/mono/mini/debugger-engine.h @@ -323,4 +323,5 @@ gpointer get_this_addr (DbgEngineStackFrame *the_frame); gpointer get_async_method_builder (DbgEngineStackFrame *frame); MonoMethod* get_set_notification_method (MonoClass* async_builder_class); MonoMethod* get_notify_debugger_of_wait_completion_method (void); +MonoMethod* get_object_id_for_debugger_method (MonoClass* async_builder_class); #endif diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index aed8e0cf0b4b6b..b282c34de86c6e 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -142,12 +142,15 @@ collect_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method, info->native_offset, NULL, &sp)) DEBUG_PRINTF (2, "Failed to lookup sequence point\n"); - DbgEngineStackFrame *frame = g_new0 (DbgEngineStackFrame, 1); + StackFrame *frame = g_new0 (StackFrame, 1); + frame->de.ji = info->ji; + frame->de.domain = info->domain; + frame->de.method = method; + frame->de.native_offset = info->native_offset; - frame->ji = info->ji; - frame->domain = info->domain; - frame->method = method; - frame->native_offset = info->native_offset; + frame->il_offset = info->il_offset; + frame->interp_frame = info->interp_frame; + frame->frame_addr = info->frame_addr; g_ptr_array_add (frames, frame); @@ -229,11 +232,55 @@ ensure_runtime_is_suspended (void) return DE_ERR_NONE; } +static int +get_object_id(MonoObject *obj) +{ + ObjRef *ref; + if (!obj) + return 0; + + ref = (ObjRef *)g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj))); + if (ref) + return ref->id; + ref = g_new0 (ObjRef, 1); + ref->id = mono_atomic_inc_i32 (&objref_id); + ref->handle = mono_gchandle_new_weakref_internal (obj, FALSE); + g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref); + g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref); + return ref->id; +} + static int -get_this_async_id (DbgEngineStackFrame *f) +get_this_async_id (DbgEngineStackFrame *frame) { - g_error ("get_this_async_id"); - return 0; + MonoClassField *builder_field; + gpointer builder; + MonoMethod *method; + MonoObject *ex; + ERROR_DECL (error); + MonoObject *obj; + + /* + * 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_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL); + if (!builder_field) + return 0; + + method = get_object_id_for_debugger_method (mono_class_from_mono_type_internal (builder_field->type)); + if (!method) { + return 0; + } + + obj = mono_runtime_try_invoke (method, builder, NULL, &ex, error); + mono_error_assert_ok (error); + + return get_object_id (obj); } typedef struct { @@ -432,24 +479,6 @@ mono_wasm_setup_single_step (int kind) return isBPOnNativeCode; } -static int -get_object_id(MonoObject *obj) -{ - ObjRef *ref; - if (!obj) - return 0; - - ref = (ObjRef *)g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj))); - if (ref) - return ref->id; - ref = g_new0 (ObjRef, 1); - ref->id = mono_atomic_inc_i32 (&objref_id); - ref->handle = mono_gchandle_new_weakref_internal (obj, FALSE); - g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref); - g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref); - return ref->id; -} - static void handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame) { diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs index 34dc5ef605de1b..4f5cdecf4cc4aa 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs @@ -1523,6 +1523,34 @@ async Task _invoke_getter(string obj_id, string property_name, bool expe } } + [Fact] + public async Task StepOverAsyncMethod() + { + var insp = new Inspector(); + //Collect events + var scripts = SubscribeToScripts(insp); + + await Ready(); + await insp.Ready(async (cli, token) => + { + ctx = new DebugTestContext(cli, insp, token, scripts); + + var bp = await SetBreakpointInMethod("debugger-test.dll", "AsyncStepClass", "TestAsyncStepOut2", 2); + System.Console.WriteLine(bp); + await EvaluateAndCheck( + "window.setTimeout(function() { invoke_static_method_async('[debugger-test] AsyncStepClass:TestAsyncStepOut'); }, 1);", + "dotnet://debugger-test.dll/debugger-async-step.cs", 19, 8, + "MoveNext"); + + await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-async-step.cs", 21, 8, "MoveNext"); + + await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-async-step.cs", 22, 4, "MoveNext"); + + await StepAndCheck(StepKind.Over, null, 0, 0, "get_IsCompletedSuccessfully"); //not check the line number and the file name because this can be changed + + }); + } + //TODO add tests covering basic stepping behavior as step in/out/over } } diff --git a/src/mono/wasm/debugger/tests/debugger-async-step.cs b/src/mono/wasm/debugger/tests/debugger-async-step.cs new file mode 100644 index 00000000000000..029f98982307b9 --- /dev/null +++ b/src/mono/wasm/debugger/tests/debugger-async-step.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading.Tasks; +using System.Net; +using System.Net.Http; + +public class AsyncStepClass +{ + static HttpClient client = new HttpClient(); + public static async Task TestAsyncStepOut() + { + await TestAsyncStepOut2("foobar"); + } + + public static async Task TestAsyncStepOut2(string some) + { + var resp = await client.GetAsync("http://localhost:9400/debugger-driver.html"); + Console.WriteLine($"resp: {resp}"); /// BP at this line + + return 10; + } +} \ No newline at end of file