Skip to content

Commit

Permalink
Merging #42299 to backport together with #42227.
Browse files Browse the repository at this point in the history
  • Loading branch information
thaystg committed Sep 17, 2020
1 parent c7c7055 commit afd438a
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 47 deletions.
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
20 changes: 20 additions & 0 deletions src/mono/mono/mini/debugger-engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
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
81 changes: 55 additions & 26 deletions src/mono/mono/mini/mini-wasm-debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
{
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 @@ -1523,6 +1523,34 @@ async Task<Result> _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
}
}
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;
}
}

0 comments on commit afd438a

Please sign in to comment.