diff --git a/out.txt b/out.txt new file mode 100644 index 00000000000000..2497b028a63a3a Binary files /dev/null and b/out.txt differ diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index edbbada76af763..e43eb657cf27eb 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -5335,8 +5335,9 @@ decode_vtype (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void if (t && klass != mono_class_from_mono_type_internal (t)) { char *name = mono_type_full_name (t); - char *name2 = mono_type_full_name (m_class_get_byval_arg (klass)); - PRINT_DEBUG_MSG (1, "[%p] Expected value of type %s, got %s.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, name2); + char *name3 = mono_type_full_name (m_class_get_byval_arg (klass)); + HA! my edition + PRINT_DEBUG_MSG (1, "[%p] 1 Expected value of type %s, got %s.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, name2); g_free (name); g_free (name2); return ERR_INVALID_ARGUMENT; @@ -5416,6 +5417,7 @@ static ErrorCode decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit, gboolean check_field_datatype) { ErrorCode err; + PRINT_DEBUG_MSG (1, "[ILONA] decode_value_internal t->type = %d, type = %d\n", t->type, type); if (type != t->type && !MONO_TYPE_IS_REFERENCE (t) && !(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) && @@ -5426,7 +5428,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, !(t->type == MONO_TYPE_GENERICINST && type == MONO_TYPE_VALUETYPE) && !(t->type == MONO_TYPE_VALUETYPE && type == MONO_TYPE_OBJECT)) { char *name = mono_type_full_name (t); - PRINT_DEBUG_MSG (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, type); + PRINT_DEBUG_MSG (1, "[%p] 2 Expected value of type %s, got 0x%0x.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, type); g_free (name); return ERR_INVALID_ARGUMENT; } @@ -5581,7 +5583,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, g_free (vtype_buf); } else { char *name = mono_type_full_name (t); - PRINT_DEBUG_MSG (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, type); + PRINT_DEBUG_MSG (1, "[%p] 3 Expected value of type %s, got 0x%0x. %s, %s\n", (gpointer) (gsize) mono_native_thread_id_get (), name, type, name, type); g_free (name); return ERR_INVALID_ARGUMENT; } @@ -5612,8 +5614,10 @@ decode_value (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void ERROR_DECL (error); ErrorCode err; int type = decode_byte (buf, &buf, limit); + PRINT_DEBUG_MSG (1, "[ILONA] decode_value type = %d, t->type = %d\n", type, t->type); if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { + PRINT_DEBUG_MSG (1, "[ILONA] decode_value type in if 1"); MonoType *targ = t->data.generic_class->context.class_inst->type_argv [0]; guint8 *nullable_buf; @@ -5623,11 +5627,13 @@ decode_value (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void err = decode_value_internal (t, type, domain, addr, buf, endbuf, limit, check_field_datatype); if (err == ERR_NONE) return err; + PRINT_DEBUG_MSG (1, "[ILONA] decode_value type in if 2"); /* * Then try decoding as a primitive value or null. */ if (targ->type == type) { + PRINT_DEBUG_MSG (1, "[ILONA] decode_value type in if 3"); nullable_buf = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (targ))); err = decode_value_internal (targ, type, domain, nullable_buf, buf, endbuf, limit, check_field_datatype); if (err != ERR_NONE) { @@ -6037,14 +6043,14 @@ mono_do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, gu * Invoke this method directly, currently only Environment.Exit () is supported. */ this_arg = NULL; - PRINT_DEBUG_MSG (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer) (gsize) mono_native_thread_id_get (), mono_method_full_name (invoke->method, TRUE), this_arg ? m_class_get_name (this_arg->vtable->klass) : ""); + PRINT_DEBUG_MSG (1, "[%p] 1 Invoking method '%s' on receiver '%s'.\n", (gpointer) (gsize) mono_native_thread_id_get (), mono_method_full_name (invoke->method, TRUE), this_arg ? m_class_get_name (this_arg->vtable->klass) : ""); mono_runtime_try_invoke (invoke->method, NULL, invoke->args, &exc, error); mono_error_assert_ok (error); g_assert_not_reached (); } - m = decode_methodid (p, &p, end, &domain, &err); + m = decode_methodid (p, &p, end, &domain, &err); // exception after it if (err != ERR_NONE) return err; sig = mono_method_signature_internal (m); @@ -6116,7 +6122,7 @@ mono_do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, gu } } - PRINT_DEBUG_MSG (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer) (gsize) mono_native_thread_id_get (), mono_method_full_name (m, TRUE), this_arg ? m_class_get_name (this_arg->vtable->klass) : ""); + PRINT_DEBUG_MSG (1, "[%p] 2 Invoking method '%s' on receiver '%s'.\n", (gpointer) (gsize) mono_native_thread_id_get (), mono_method_full_name (m, TRUE), this_arg ? m_class_get_name (this_arg->vtable->klass) : ""); if (this_arg && this_arg->vtable->domain != domain) NOT_IMPLEMENTED; @@ -6141,6 +6147,7 @@ mono_do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, gu return ERR_INVALID_ARGUMENT; nargs = decode_int (p, &p, end); + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 1, nargs = %d, paramCnt = %d\n", nargs, sig->param_count); if (nargs != sig->param_count) return ERR_INVALID_ARGUMENT; /* Use alloca to get gc tracking */ @@ -6148,32 +6155,42 @@ mono_do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, gu memset (arg_buf, 0, nargs * sizeof (gpointer)); args = (gpointer *)g_alloca (nargs * sizeof (gpointer)); for (i = 0; i < nargs; ++i) { + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method in the loop i = %d\n", i); if (MONO_TYPE_IS_REFERENCE (sig->params [i])) { + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 2\n"); err = decode_value (sig->params [i], domain, (guint8*)&args [i], p, &p, end, TRUE); + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 3, err = %d\n", err); if (err != ERR_NONE) break; if (args [i] && ((MonoObject*)args [i])->vtable->domain != domain) NOT_IMPLEMENTED; + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 4\n"); if (m_type_is_byref (sig->params [i])) { + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 5\n"); arg_buf [i] = g_newa (guint8, sizeof (gpointer)); *(gpointer*)arg_buf [i] = args [i]; args [i] = arg_buf [i]; } } else { + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 6\n"); MonoClass *arg_class = mono_class_from_mono_type_internal (sig->params [i]); arg_buf [i] = (guint8 *)g_alloca (mono_class_instance_size (arg_class)); err = decode_value (sig->params [i], domain, arg_buf [i], p, &p, end, TRUE); + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 7, err = %d\n", err); if (err != ERR_NONE) break; if (mono_class_is_nullable (arg_class)) { + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 8\n"); args [i] = mono_nullable_box (arg_buf [i], arg_class, error); mono_error_assert_ok (error); } else { + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 9\n"); args [i] = arg_buf [i]; } } } + PRINT_DEBUG_MSG (1, "[ILONA] mono_do_invoke_method 10, i = %d\n", i); if (i < nargs) return err; diff --git a/src/mono/mono/component/mini-wasm-debugger.c b/src/mono/mono/component/mini-wasm-debugger.c index 98da53aa693b40..111dc710d524f4 100644 --- a/src/mono/mono/component/mini-wasm-debugger.c +++ b/src/mono/mono/component/mini-wasm-debugger.c @@ -136,7 +136,7 @@ handle_multiple_ss_requests (void) { static void mono_wasm_enable_debugging_internal (int debug_level) { - log_level = debug_level; + log_level = 10; if (debug_level != 0) { wasm_debugger_log(1, "DEBUGGING ENABLED\n"); debugger_enabled = TRUE; @@ -373,6 +373,7 @@ extern void mono_wasm_add_dbg_command_received(mono_bool res_ok, int id, void* b EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size, int valtype, char* newvalue) { + PRINT_DEBUG_MSG (1, "[ILONA] mono_wasm_send_dbg_command_with_parms 1\n"); gboolean result = FALSE; MONO_ENTER_GC_UNSAFE; if (!debugger_enabled) { @@ -389,7 +390,9 @@ mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, i result = TRUE; goto done; } + PRINT_DEBUG_MSG (1, "[ILONA] mono_wasm_send_dbg_command_with_parms 2\n"); mono_wasm_send_dbg_command(id, command_set, command, bufWithParms.buf, m_dbgprot_buffer_len(&bufWithParms)); + PRINT_DEBUG_MSG (1, "[ILONA] mono_wasm_send_dbg_command_with_parms 3\n"); buffer_free (&bufWithParms); result = TRUE; done: @@ -400,6 +403,7 @@ mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, i EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size) { + PRINT_DEBUG_MSG (1, "[ILONA] mono_wasm_send_dbg_command 1\n"); gboolean result = FALSE; MONO_ENTER_GC_UNSAFE; if (!debugger_enabled) { @@ -408,6 +412,7 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, result = TRUE; goto done; } + PRINT_DEBUG_MSG (1, "[ILONA] mono_wasm_send_dbg_command 2\n"); ss_calculate_framecount (NULL, NULL, TRUE, NULL, NULL); MdbgProtBuffer buf; buffer_init (&buf, 128); @@ -415,11 +420,14 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, MdbgProtErrorCode error = 0; if (command_set == MDBGPROT_CMD_SET_VM && command == MDBGPROT_CMD_VM_INVOKE_METHOD ) { + PRINT_DEBUG_MSG (1, "[ILONA] mono_wasm_send_dbg_command 3; command == MDBGPROT_CMD_VM_INVOKE_METHOD\n"); DebuggerTlsData* tls = mono_wasm_get_tls (); InvokeData invoke_data; memset (&invoke_data, 0, sizeof (InvokeData)); invoke_data.endp = data + size; + PRINT_DEBUG_MSG (1, "[ILONA] mono_wasm_send_dbg_command 4\n"); error = mono_do_invoke_method (tls, &buf, &invoke_data, data, &data); + PRINT_DEBUG_MSG (1, "[ILONA] mono_wasm_send_dbg_command 5, error=%d\n", error); } else if (command_set == MDBGPROT_CMD_SET_VM && (command == MDBGPROT_CMD_GET_ASSEMBLY_BYTES)) { @@ -488,4 +496,4 @@ mini_wasm_debugger_add_function_pointers (MonoComponentDebugger* fn_table) fn_table->mono_wasm_single_step_hit = mono_wasm_single_step_hit; } -#endif \ No newline at end of file +#endif diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 92afb5b2d28fba..34eb2108be0f92 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -458,19 +458,27 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, return await ExpressionEvaluator.EvaluateSimpleExpression(this, eaFormatted, elementAccessStr, variableDefinitions, logger, token); } var typeIds = await context.SdbAgent.GetTypeIdsForObject(objectId.Value, true, token); - int[] methodIds = await context.SdbAgent.GetMethodIdsByName(typeIds[0], "ToArray", token); - // ToArray should not have an overload, but if user defined it, take the default one: without params - if (methodIds == null) - throw new InvalidOperationException($"Type '{rootObject?["className"]?.Value()}' cannot be indexed."); - + // int[] methodIds = await context.SdbAgent.GetMethodIdsByName(typeIds[0], "ToArray", token); + // int allowedParamCnt = 0; + // if (methodIds == null) + // { + int allowedParamCnt = 1; + int[] methodIds = await context.SdbAgent.GetMethodIdsByName(typeIds[0], "get_Item", token); + if (methodIds == null) + throw new InvalidOperationException($"Type '{rootObject?["className"]?.Value()}' cannot be indexed."); + // } + + // ToArray / get_Item should not have an overload, but if user defined it, take the default one: without params / with one param: key int toArrayId = methodIds[0]; if (methodIds.Length > 1) { + Console.WriteLine($"methodIds.Length > 1"); foreach (var methodId in methodIds) { MethodInfoWithDebugInformation methodInfo = await context.SdbAgent.GetMethodInfo(methodId, token); ParameterInfo[] paramInfo = methodInfo.GetParametersInfo(); - if (paramInfo.Length == 0) + Console.WriteLine($"name = {methodInfo.Name}; paramInfo = {paramInfo.Length}"); + if (paramInfo.Length == allowedParamCnt) { toArrayId = methodId; break; @@ -479,14 +487,29 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, } try { - var toArrayRetMethod = await context.SdbAgent.InvokeMethod(objectId.Value, toArrayId, isValueType: false, token); - rootObject = await GetValueFromObject(toArrayRetMethod, token); - DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId arrayObjectId); - rootObject["value"] = await context.SdbAgent.GetArrayValues(arrayObjectId.Value, token); - return (JObject)rootObject["value"][elementIdx]["value"]; + Console.WriteLine($"methodIds.Length == 1"); + Console.WriteLine($"rootObject = {rootObject}, elementIdxStr = {elementIdxStr}"); + if (allowedParamCnt == 0) // ToArray result + { + JObject toArrayRetObj = await context.SdbAgent.InvokeMethod(objectId.Value, toArrayId, isValueType: false, token); + rootObject = await GetValueFromObject(toArrayRetObj, token); + DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId arrayObjectId); + rootObject["value"] = await context.SdbAgent.GetArrayValues(arrayObjectId.Value, token); + return (JObject)rootObject["value"][elementIdx]["value"]; + } + // get_Item result + using var ctorArgsWriter = new MonoBinaryWriter(); + ctorArgsWriter.WriteObj(objectId, context.SdbAgent); + ctorArgsWriter.Write(1); // number of method args + // if we learn how to check properly the indexing obj type and pass elementIdx / elementIdxStr when we should, then ToArray won't be needed + if (!await ctorArgsWriter.WriteConst(ElementType.I4, elementIdx, context.SdbAgent, token)) // string? how do you know? + throw new InternalErrorException($"Unable to write index parameter to invoke the method in the runtime."); + JObject getItemRetObj = await context.SdbAgent.InvokeMethod(ctorArgsWriter.GetParameterBuffer(), toArrayId, token); + return (JObject)getItemRetObj["value"]; } - catch + catch (Exception ex) { + Console.WriteLine($"ex = {ex}"); throw new InvalidOperationException($"Cannot apply indexing with [] to an object of type '{rootObject?["className"]?.Value()}'"); } default: diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index cbe0692125b352..993dd43821728f 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -778,7 +778,7 @@ internal sealed class MonoSDBHelper private int VmMinorVersion { get; set; } private int VmMajorVersion { get; set; } - private Dictionary methods; + public Dictionary methods; private Dictionary assemblies; private Dictionary types; diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 30d391700c9afa..508e847fd5e846 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -627,19 +627,51 @@ await EvaluateOnCallFrameAndCheck(id, }); + [Fact] //FIXME: Type 'DebuggerTests.EvaluateLocalsWithIndexingTests.TestEvaluate' cannot be indexed. + public async Task EvaluateIndexingOfObjectsThatDoNotHaveToArrayMethod() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + await EvaluateOnCallFrameAndCheck(id, + ("f[\"longstring\"]", TBool(true)) + // ("f[\"-\"]", TBool(false)) + // ("f.arrIndexedByStr[\"longstring\"]", TBool(true)), + // ("f.arrIndexedByStr[\"-\"]", TBool(false)) + ); + }); + + [Fact] + public async Task EvaluateIndexingByNonNumberType() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + await EvaluateOnCallFrameAndCheck(id, + ("f.indexedByStr[\"11\"]", TBool(true)), + ("f.indexedByStr[\"111\"]", TBool(false)), + ("f.indexedByBool[true]", TString("TRUE")), + ("f.indexedByStr[false]", TString("FALSE")) + ); + }); + + [Fact] - public async Task EvaluateIndexingByExpression() => await CheckInspectLocalsAtBreakpointSite( + public async Task EvaluateIndexingByExpression2() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, - ("f.numList[i + 1]", TNumber(2)), - ("f.textList[(2 * j) - 1]", TString("2")), - ("f.textList[j - 1]", TString("1")), - //("f[\"longstring\"]", TBool(true)), FIXME: Broken case - ("f.numArray[f.numList[j - 1]]", TNumber(2)) + // ("f.numList[i + 1]", TNumber(2)), + // ("f.textList[(2 * j) - 1]", TString("2")), + // ("f.textList[j - 1]", TString("1")), + ("f.indexedByStr[\"1\" + \"1\"]", TBool(true)), + ("f.indexedByStr[\'1\' + \"11\"]", TBool(false)) + // ("f.numArray[f.numList[j - 1]]", TNumber(2)) ); }); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs index c38a64fdce0350..e6a6f6dc987b50 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs @@ -516,10 +516,13 @@ public class TestEvaluate public List> numListOfLists; public string[][] textArrayOfArrays; public List> textListOfLists; + public Dictionary indexedByStr; + public Dictionary indexedByBool; public int idx0; public int idx1; public bool this[string key] => key.Length > 3; + public string this[bool key] => key.ToString(); public void run() { @@ -531,6 +534,8 @@ public void run() numListOfLists = new List> { numList, numList }; textArrayOfArrays = new string[][] { textArray, textArray }; textListOfLists = new List> { textList, textList }; + indexedByStr = new Dictionary() { { "11", true }, { "111", false } }; + indexedByBool = new Dictionary() { { true, "TRUE" }, { false, "FALSE" } }; idx0 = 0; idx1 = 1; }