Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions src/mono/mono/mini/debugger-agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions src/mono/mono/mini/debugger-engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,27 @@ set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame)
return TRUE;
}

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;
}

gpointer
get_this_addr (DbgEngineStackFrame *the_frame)
{
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/debugger-engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
87 changes: 59 additions & 28 deletions src/mono/mono/mini/mini-wasm-debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,17 @@ 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, "collect_frames: Failed to lookup sequence point. method: %s, native_offset: %d \n", method->name, info->native_offset);

DbgEngineStackFrame *frame = g_new0 (DbgEngineStackFrame, 1);

frame->ji = info->ji;
frame->domain = info->domain;
frame->method = method;
frame->native_offset = info->native_offset;


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->il_offset = info->il_offset;
frame->interp_frame = info->interp_frame;
frame->frame_addr = info->frame_addr;

g_ptr_array_add (frames, frame);

return FALSE;
Expand Down Expand Up @@ -235,11 +239,56 @@ 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 {
Expand Down Expand Up @@ -438,24 +487,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)
{
Expand Down
28 changes: 28 additions & 0 deletions src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1815,6 +1815,34 @@ public async Task StaticMethodWithLocalEmptyStructThatWillGetExpanded(bool is_as
AssertEqual(0, es_props.Values<JToken>().Count(), "es_props");
});

[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

});
}

[Fact]
public async Task PreviousFrameForAReflectedCall() => await CheckInspectLocalsAtBreakpointSite(
"DebuggerTests.GetPropertiesTests.CloneableStruct", "SimpleStaticMethod", 1, "SimpleStaticMethod",
Expand Down
24 changes: 24 additions & 0 deletions src/mono/wasm/debugger/tests/debugger-async-step.cs
Original file line number Diff line number Diff line change
@@ -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<int> TestAsyncStepOut2(string some)
{
var resp = await client.GetAsync("http://localhost:9400/debugger-driver.html");
Console.WriteLine($"resp: {resp}"); /// BP at this line

return 10;
}
}