From 7d8de9cbbfebb8e6a289a2c50c317dcaff4c00aa Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 5 May 2021 11:14:05 -0300 Subject: [PATCH 01/48] Trying to reuse debugger-agent on wasm debugger. This will remove a lot of code that does the same thing on mini-wasm-debugger. --- src/mono/mono/mini/debugger-agent.c | 160 +++++++---- src/mono/mono/mini/debugger-agent.h | 8 + src/mono/mono/mini/debugger-protocol.c | 11 + src/mono/mono/mini/debugger-protocol.h | 3 +- src/mono/mono/mini/mini-wasm-debugger.c | 22 +- .../BrowserDebugProxy/DevToolsHelper.cs | 5 + .../debugger/BrowserDebugProxy/MonoProxy.cs | 266 +++++++++++++++++- src/mono/wasm/runtime/library_mono.js | 34 ++- 8 files changed, 443 insertions(+), 66 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 754abed0ddf3f..43606f4259a55 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -109,8 +109,7 @@ #define DISABLE_SOCKET_TRANSPORT #endif -#ifndef DISABLE_SDB - +#if !defined (DISABLE_SDB) || defined(TARGET_WASM) #include #include @@ -460,6 +459,7 @@ static void objrefs_init (void); static void objrefs_cleanup (void); static void ids_init (void); + static void ids_cleanup (void); static void suspend_init (void); @@ -491,6 +491,13 @@ static int handle_multiple_ss_requests (void); static GENERATE_TRY_GET_CLASS_WITH_CACHE (fixed_buffer, "System.Runtime.CompilerServices", "FixedBufferAttribute") +void mono_init_debugger_agent_for_wasm (int log_level_parm) +{ + ids_init(); + log_level = log_level; + event_requests = g_ptr_array_new (); +} + #ifndef DISABLE_SOCKET_TRANSPORT static void register_socket_transport (void); @@ -4161,8 +4168,11 @@ begin_breakpoint_processing (void *the_tls, MonoContext *ctx, MonoJitInfo *ji, g * Skip the instruction causing the breakpoint signal. */ if (from_signal) +#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED mono_arch_skip_breakpoint (ctx, ji); - +#else + NOT_IMPLEMENTED; +#endif if (tls->disable_breakpoints) return FALSE; return TRUE; @@ -4332,7 +4342,11 @@ static void begin_single_step_processing (MonoContext *ctx, gboolean from_signal) { if (from_signal) +#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED mono_arch_skip_single_step (ctx); +#else + NOT_IMPLEMENTED; +#endif } static void @@ -4364,7 +4378,11 @@ debugger_agent_single_step_event (void *sigctx) MonoContext ctx; mono_sigctx_to_monoctx (sigctx, &ctx); +#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED mono_arch_skip_single_step (&ctx); +#else + NOT_IMPLEMENTED; +#endif mono_monoctx_to_sigctx (&ctx, sigctx); return; } @@ -6934,6 +6952,34 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) buffer_add_byte_array (buf, memory, size); break; } + case MDBGPROT_CMD_GET_ASSEMBLY_BY_NAME: { + int i; + char* assembly_name = decode_string (p, &p, end); + //we get 'foo.dll' but mono_assembly_load expects 'foo' so we strip the last dot + char *lookup_name = g_strdup (assembly_name); + for (i = strlen (lookup_name) - 1; i >= 0; --i) { + if (lookup_name [i] == '.') { + lookup_name [i] = 0; + break; + } + } + + //resolve the assembly + MonoImageOpenStatus status; + MonoAssemblyName* aname = mono_assembly_name_new (lookup_name); + MonoAssemblyByNameRequest byname_req; + mono_assembly_request_prepare_byname (&byname_req, MONO_ASMCTX_DEFAULT, mono_alc_get_default ()); + MonoAssembly *assembly = mono_assembly_request_byname (aname, &byname_req, &status); + g_free (lookup_name); + if (!assembly) { + PRINT_DEBUG_MSG (1, "Could not resolve assembly %s\n", assembly_name); + buffer_add_int(buf, -1); + break; + } + mono_assembly_name_free_internal (aname); + buffer_add_assemblyid (buf, mono_get_root_domain (), assembly); + break; + } default: return ERR_NOT_IMPLEMENTED; } @@ -9897,6 +9943,62 @@ wait_for_attach (void) return TRUE; } +ErrorCode +mono_process_dbg_packet (int id, CommandSet command_set, int command, gboolean *no_reply, guint8 *p, guint8 *end, Buffer *buf) +{ + ErrorCode err; + /* Process the request */ + switch (command_set) { + case CMD_SET_VM: + err = vm_commands (command, id, p, end, buf); + if (err == ERR_NONE && command == CMD_VM_INVOKE_METHOD) + /* Sent after the invoke is complete */ + *no_reply = TRUE; + break; + case CMD_SET_EVENT_REQUEST: + err = event_commands (command, p, end, buf); + break; + case CMD_SET_APPDOMAIN: + err = domain_commands (command, p, end, buf); + break; + case CMD_SET_ASSEMBLY: + err = assembly_commands (command, p, end, buf); + break; + case CMD_SET_MODULE: + err = module_commands (command, p, end, buf); + break; + case CMD_SET_FIELD: + err = field_commands (command, p, end, buf); + break; + case CMD_SET_TYPE: + err = type_commands (command, p, end, buf); + break; + case CMD_SET_METHOD: + err = method_commands (command, p, end, buf); + break; + case CMD_SET_THREAD: + err = thread_commands (command, p, end, buf); + break; + case CMD_SET_STACK_FRAME: + err = frame_commands (command, p, end, buf); + break; + case CMD_SET_ARRAY_REF: + err = array_commands (command, p, end, buf); + break; + case CMD_SET_STRING_REF: + err = string_commands (command, p, end, buf); + break; + case CMD_SET_POINTER: + err = pointer_commands (command, p, end, buf); + break; + case CMD_SET_OBJECT_REF: + err = object_commands (command, p, end, buf); + break; + default: + err = ERR_NOT_IMPLEMENTED; + } + return err; +} /* * debugger_thread: * @@ -9992,57 +10094,7 @@ debugger_thread (void *arg) err = ERR_NONE; no_reply = FALSE; - - /* Process the request */ - switch (command_set) { - case CMD_SET_VM: - err = vm_commands (command, id, p, end, &buf); - if (err == ERR_NONE && command == CMD_VM_INVOKE_METHOD) - /* Sent after the invoke is complete */ - no_reply = TRUE; - break; - case CMD_SET_EVENT_REQUEST: - err = event_commands (command, p, end, &buf); - break; - case CMD_SET_APPDOMAIN: - err = domain_commands (command, p, end, &buf); - break; - case CMD_SET_ASSEMBLY: - err = assembly_commands (command, p, end, &buf); - break; - case CMD_SET_MODULE: - err = module_commands (command, p, end, &buf); - break; - case CMD_SET_FIELD: - err = field_commands (command, p, end, &buf); - break; - case CMD_SET_TYPE: - err = type_commands (command, p, end, &buf); - break; - case CMD_SET_METHOD: - err = method_commands (command, p, end, &buf); - break; - case CMD_SET_THREAD: - err = thread_commands (command, p, end, &buf); - break; - case CMD_SET_STACK_FRAME: - err = frame_commands (command, p, end, &buf); - break; - case CMD_SET_ARRAY_REF: - err = array_commands (command, p, end, &buf); - break; - case CMD_SET_STRING_REF: - err = string_commands (command, p, end, &buf); - break; - case CMD_SET_POINTER: - err = pointer_commands (command, p, end, &buf); - break; - case CMD_SET_OBJECT_REF: - err = object_commands (command, p, end, &buf); - break; - default: - err = ERR_NOT_IMPLEMENTED; - } + err = mono_process_dbg_packet (id, command_set, command, &no_reply, p, end, &buf); if (command_set == CMD_SET_VM && command == CMD_VM_START_BUFFERING) { buffer_replies = TRUE; diff --git a/src/mono/mono/mini/debugger-agent.h b/src/mono/mono/mini/debugger-agent.h index 500e8e610c3b5..05fbe1a07dabe 100644 --- a/src/mono/mono/mini/debugger-agent.h +++ b/src/mono/mono/mini/debugger-agent.h @@ -6,6 +6,8 @@ #define __MONO_DEBUGGER_AGENT_H__ #include "mini.h" +#include "debugger-protocol.h" + #include #define MONO_DBG_CALLBACKS_VERSION (4) @@ -46,4 +48,10 @@ mono_debugger_agent_stub_init (void); MONO_API MONO_RT_EXTERNAL_ONLY gboolean mono_debugger_agent_transport_handshake (void); +MdbgProtErrorCode +mono_process_dbg_packet (int id, MdbgProtCommandSet command_set, int command, gboolean *no_reply, guint8 *p, guint8 *end, MdbgProtBuffer *buf); + +void +mono_init_debugger_agent_for_wasm (int log_level); + #endif diff --git a/src/mono/mono/mini/debugger-protocol.c b/src/mono/mono/mini/debugger-protocol.c index 1402dae3d36ef..1340f8f6945dc 100644 --- a/src/mono/mono/mini/debugger-protocol.c +++ b/src/mono/mono/mini/debugger-protocol.c @@ -57,7 +57,11 @@ m_dbgprot_decode_int (uint8_t *buf, uint8_t **endbuf, uint8_t *limit) *endbuf = buf + 4; g_assert (*endbuf <= limit); +#ifndef HOST_WASM return (((int)buf [0]) << 24) | (((int)buf [1]) << 16) | (((int)buf [2]) << 8) | (((int)buf [3]) << 0); +#else + return (((int)buf [0]) << 0) | (((int)buf [1]) << 8) | (((int)buf [2]) << 16) | (((int)buf [3]) << 24); +#endif } int64_t @@ -194,10 +198,17 @@ void m_dbgprot_buffer_add_int (MdbgProtBuffer *buf, uint32_t val) { m_dbgprot_buffer_make_room (buf, 4); +#ifndef HOST_WASM buf->p [0] = (val >> 24) & 0xff; buf->p [1] = (val >> 16) & 0xff; buf->p [2] = (val >> 8) & 0xff; buf->p [3] = (val >> 0) & 0xff; +#else + buf->p [0] = (val >> 0) & 0xff; + buf->p [1] = (val >> 8) & 0xff; + buf->p [2] = (val >> 16) & 0xff; + buf->p [3] = (val >> 24) & 0xff; +#endif buf->p += 4; } diff --git a/src/mono/mono/mini/debugger-protocol.h b/src/mono/mono/mini/debugger-protocol.h index b2c4cf454ed46..871d124f009fb 100644 --- a/src/mono/mono/mini/debugger-protocol.h +++ b/src/mono/mono/mini/debugger-protocol.h @@ -41,7 +41,8 @@ typedef enum { MDBGPROT_CMD_VM_START_BUFFERING = 14, MDBGPROT_CMD_VM_STOP_BUFFERING = 15, MDBGPROT_CMD_VM_READ_MEMORY = 16, - MDBGPROT_CMD_VM_WRITE_MEMORY = 17 + MDBGPROT_CMD_VM_WRITE_MEMORY = 17, + MDBGPROT_CMD_GET_ASSEMBLY_BY_NAME = 18 } MdbgProtCmdVM; typedef enum { diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 52a79089ad590..d8c598d4dc8bf 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include //XXX This is dirty, extend ee.h to support extracting info from MonoInterpFrameHandle #include @@ -55,6 +57,7 @@ EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_deref_ptr_value (void *value_addr, M EMSCRIPTEN_KEEPALIVE void mono_wasm_set_is_debugger_attached (gboolean is_attached); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_set_variable_on_frame (int scope, int index, const char* name, const char* value); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_set_value_on_object (int object_id, const char* name, const char* value); +EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size); //JS functions imported that we use extern void mono_wasm_add_frame (int il_offset, int method_token, int frame_id, const char *assembly_name, const char *method_name); @@ -449,6 +452,9 @@ mono_wasm_debugger_init (void) mini_get_dbg_callbacks ()->handle_exception = handle_exception; mini_get_dbg_callbacks ()->user_break = mono_wasm_user_break; + +//debugger-agent initialization + mono_init_debugger_agent_for_wasm (log_level); } MONO_API void @@ -577,7 +583,6 @@ handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch if (error_message != NULL) g_free (error_message); - PRINT_DEBUG_MSG (2, "handle exception - done\n"); } @@ -1931,11 +1936,18 @@ mono_wasm_set_is_debugger_attached (gboolean is_attached) } } -// Functions required by debugger-state-machine. -gsize -mono_debugger_tls_thread_id (DebuggerTlsData *debuggerTlsData) +EMSCRIPTEN_KEEPALIVE gboolean +mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size) { - return 1; + MdbgProtBuffer buf; + buffer_init (&buf, 128); + gboolean no_reply; + mono_process_dbg_packet(id, command_set, command, &no_reply, data, data + size, &buf); + + EM_ASM ({ + MONO.mono_wasm_add_dbg_command_received ($0, $1, $2); + }, id, buf.buf, buf.p-buf.buf); + return TRUE; } #else // HOST_WASM diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index 7cc78357f9e41..3f44eae4ad41d 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -205,6 +205,11 @@ public static MonoCommands EvaluateMemberAccess(int scopeId, string expr, params public static MonoCommands SetBreakpoint(string assemblyName, int methodToken, int ilOffset) => new MonoCommands($"MONO.mono_wasm_set_breakpoint (\"{assemblyName}\", {methodToken}, {ilOffset})"); + public static MonoCommands SendDebuggerAgentCommand(int id, int command_set, int command, string command_parameters) + { + return new MonoCommands($"MONO.mono_wasm_send_dbg_command ({id}, {command_set}, {command},'{command_parameters}')"); + } + public static MonoCommands RemoveBreakpoint(int breakpointId) => new MonoCommands($"MONO.mono_wasm_remove_breakpoint({breakpointId})"); public static MonoCommands ReleaseObject(DotnetObjectId objectId) => new MonoCommands($"MONO.mono_wasm_release_object('{objectId}')"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index b80a4483ca02d..e798eca3c16e2 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -18,6 +18,228 @@ namespace Microsoft.WebAssembly.Diagnostics { internal class MonoProxy : DevToolsProxy { + internal class MonoBinaryWriter : BinaryWriter + { + public MonoBinaryWriter(Stream stream) : base(stream) {} + public void WriteString(string val) + { + Write(val.Length); + Write(val.ToCharArray()); + } + public void WriteLong(long val) + { + Write((int)((val >> 32) & 0xffffffff)); + Write((int)((val >> 0) & 0xffffffff)); + } + } + private enum TokenType + { + mdtModule = 0x00000000, // + mdtTypeRef = 0x01000000, // + mdtTypeDef = 0x02000000, // + mdtFieldDef = 0x04000000, // + mdtMethodDef = 0x06000000, // + mdtParamDef = 0x08000000, // + mdtInterfaceImpl = 0x09000000, // + mdtMemberRef = 0x0a000000, // + mdtCustomAttribute = 0x0c000000, // + mdtPermission = 0x0e000000, // + mdtSignature = 0x11000000, // + mdtEvent = 0x14000000, // + mdtProperty = 0x17000000, // + mdtModuleRef = 0x1a000000, // + mdtTypeSpec = 0x1b000000, // + mdtAssembly = 0x20000000, // + mdtAssemblyRef = 0x23000000, // + mdtFile = 0x26000000, // + mdtExportedType = 0x27000000, // + mdtManifestResource = 0x28000000, // + mdtGenericParam = 0x2a000000, // + mdtMethodSpec = 0x2b000000, // + mdtGenericParamConstraint = 0x2c000000, + + mdtString = 0x70000000, // + mdtName = 0x71000000, // + mdtBaseType = 0x72000000, // Leave this on the high end value. This does not correspond to metadata table + } + + private enum CommandSet { + VM = 1, + OBJECT_REF = 9, + STRING_REF = 10, + THREAD = 11, + ARRAY_REF = 13, + EVENT_REQUEST = 15, + STACK_FRAME = 16, + APPDOMAIN = 20, + ASSEMBLY = 21, + METHOD = 22, + TYPE = 23, + MODULE = 24, + FIELD = 25, + EVENT = 64, + POINTER = 65 + } + + private enum EventKind { + VM_START = 0, + VM_DEATH = 1, + THREAD_START = 2, + THREAD_DEATH = 3, + APPDOMAIN_CREATE = 4, // Not in JDI + APPDOMAIN_UNLOAD = 5, // Not in JDI + METHOD_ENTRY = 6, + METHOD_EXIT = 7, + ASSEMBLY_LOAD = 8, + ASSEMBLY_UNLOAD = 9, + BREAKPOINT = 10, + STEP = 11, + TYPE_LOAD = 12, + EXCEPTION = 13, + KEEPALIVE = 14, + USER_BREAK = 15, + USER_LOG = 16, + CRASH = 17 + } + + private enum ModifierKind { + COUNT = 1, + THREAD_ONLY = 3, + LOCATION_ONLY = 7, + EXCEPTION_ONLY = 8, + STEP = 10, + ASSEMBLY_ONLY = 11, + SOURCE_FILE_ONLY = 12, + TYPE_NAME_ONLY = 13 + } + + + private enum SuspendPolicy { + SUSPEND_POLICY_NONE = 0, + SUSPEND_POLICY_EVENT_THREAD = 1, + SUSPEND_POLICY_ALL = 2 + } + + private enum CmdVM { + VERSION = 1, + ALL_THREADS = 2, + SUSPEND = 3, + RESUME = 4, + EXIT = 5, + DISPOSE = 6, + INVOKE_METHOD = 7, + SET_PROTOCOL_VERSION = 8, + ABORT_INVOKE = 9, + SET_KEEPALIVE = 10, + GET_TYPES_FOR_SOURCE_FILE = 11, + GET_TYPES = 12, + INVOKE_METHODS = 13, + START_BUFFERING = 14, + STOP_BUFFERING = 15, + VM_READ_MEMORY = 16, + VM_WRITE_MEMORY = 17, + GET_ASSEMBLY_BY_NAME = 18 + } + + private enum CmdEvent { + COMPOSITE = 100 + } + + private enum CmdThread { + GET_FRAME_INFO = 1, + GET_NAME = 2, + GET_STATE = 3, + GET_INFO = 4, + /* FIXME: Merge into GET_INFO when the major protocol version is increased */ + GET_ID = 5, + /* Ditto */ + GET_TID = 6, + SET_IP = 7, + GET_ELAPSED_TIME = 8 + } + + private enum CmdEventRequest { + SET = 1, + CLEAR = 2, + CLEAR_ALL_BREAKPOINTS = 3 + } + + private enum CmdAppDomain { + GET_ROOT_DOMAIN = 1, + GET_FRIENDLY_NAME = 2, + GET_ASSEMBLIES = 3, + GET_ENTRY_ASSEMBLY = 4, + CREATE_STRING = 5, + GET_CORLIB = 6, + CREATE_BOXED_VALUE = 7, + CREATE_BYTE_ARRAY = 8, + } + + private enum CmdAssembly { + GET_LOCATION = 1, + GET_ENTRY_POINT = 2, + GET_MANIFEST_MODULE = 3, + GET_OBJECT = 4, + GET_TYPE = 5, + GET_NAME = 6, + GET_DOMAIN = 7, + GET_METADATA_BLOB = 8, + GET_IS_DYNAMIC = 9, + GET_PDB_BLOB = 10, + GET_TYPE_FROM_TOKEN = 11, + GET_METHOD_FROM_TOKEN = 12, + HAS_DEBUG_INFO = 13, + } + + private enum CmdModule { + GET_INFO = 1, + APPLY_CHANGES = 2, + } + + private enum CmdMethod { + GET_NAME = 1, + GET_DECLARING_TYPE = 2, + GET_DEBUG_INFO = 3, + GET_PARAM_INFO = 4, + GET_LOCALS_INFO = 5, + GET_INFO = 6, + GET_BODY = 7, + RESOLVE_TOKEN = 8, + GET_CATTRS = 9, + MAKE_GENERIC_METHOD = 10 + } + + private enum CmdType { + GET_INFO = 1, + GET_METHODS = 2, + GET_FIELDS = 3, + GET_VALUES = 4, + GET_OBJECT = 5, + GET_SOURCE_FILES = 6, + SET_VALUES = 7, + IS_ASSIGNABLE_FROM = 8, + GET_PROPERTIES = 9, + GET_CATTRS = 10, + GET_FIELD_CATTRS = 11, + GET_PROPERTY_CATTRS = 12, + /* FIXME: Merge into GET_SOURCE_FILES when the major protocol version is increased */ + GET_SOURCE_FILES_2 = 13, + /* FIXME: Merge into GET_VALUES when the major protocol version is increased */ + GET_VALUES_2 = 14, + CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15, + GET_INTERFACES = 16, + GET_INTERFACE_MAP = 17, + IS_INITIALIZED = 18, + CREATE_INSTANCE = 19, + GET_VALUE_SIZE = 20 + } + + private enum CmdField { + GET_INFO = 1 + } + + private static int cmd_id; + private static int GetId() {return cmd_id++;} private IList urlSymbolServerList; private static HttpClient client = new HttpClient(); private HashSet sessions = new HashSet(); @@ -997,6 +1219,14 @@ internal async Task GetScopeProperties(SessionId msg_id, int scope_id, C } } + private async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) + { + Result res = await SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); + return ret_debugger_cmd_reader; + } private async Task SetMonoBreakpoint(SessionId sessionId, string reqId, SourceLocation location, string condition, CancellationToken token) { var bp = new Breakpoint(reqId, location, condition, BreakpointState.Pending); @@ -1004,12 +1234,40 @@ private async Task SetMonoBreakpoint(SessionId sessionId, string req int method_token = bp.Location.CliLocation.Method.Token; int il_offset = bp.Location.CliLocation.Offset; - Result res = await SendMonoCommand(sessionId, MonoCommands.SetBreakpoint(asm_name, method_token, il_offset), token); - int? ret_code = res.Value?["result"]?["value"]?.Value(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.WriteString(asm_name); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.GET_ASSEMBLY_BY_NAME, command_params, token); + var assembly_id = ret_debugger_cmd_reader.ReadInt32(); + + Console.WriteLine("SendDebuggerAgentCommand - assembly_id - " + assembly_id); + + command_params = new MemoryStream(); + command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(assembly_id); + command_params_writer.Write(method_token | (int)TokenType.mdtMethodDef); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_METHOD_FROM_TOKEN, command_params, token); + var method_id = ret_debugger_cmd_reader.ReadInt32(); + + Console.WriteLine("SendDebuggerAgentCommand - method_id - " + method_id); + + command_params = new MemoryStream(); + command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((byte)EventKind.BREAKPOINT); + command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_ALL); + command_params_writer.Write((byte)1); + command_params_writer.Write((byte)ModifierKind.LOCATION_ONLY); + command_params_writer.Write(method_id); + command_params_writer.WriteLong(il_offset); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + var breakpoint_id = ret_debugger_cmd_reader.ReadInt32(); + + Console.WriteLine("SendDebuggerAgentCommand - breakpoint_id - " + breakpoint_id); - if (ret_code.HasValue) + if (breakpoint_id > 0) { - bp.RemoteId = ret_code.Value; + bp.RemoteId = breakpoint_id; bp.State = BreakpointState.Active; //Log ("verbose", $"BP local id {bp.LocalId} enabled with remote id {bp.RemoteId}"); } diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 685aaaf375d85..ce585041da68d 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -832,7 +832,24 @@ var MonoSupportLib = { return vars; }, - // + mono_wasm_send_dbg_command: function (id, command_set, command, command_parameters) + { + console.log(`mono_wasm_send_dbg_command ${id} - ${command_set} - ${command} - ${command_parameters.length}`); + + const dataPtr = Module._malloc (command_parameters.length); + const dataHeap = new Uint8Array (Module.HEAPU8.buffer, command_parameters, command_parameters.length); + dataHeap.set (new Uint8Array (this._base64_to_uint8 (command_parameters))); + + let res_ok = this._c_fn_table.mono_wasm_send_dbg_command_wrapper (id, command_set, command, dataHeap.byteOffset, command_parameters.length); + Module._free (dataHeap.byteOffset); + + let res = MONO.commands_received; + if (res_ok) { + return { res_ok, res }; + } + MONO.commands_received = null; + }, + // @var_list: [ { index: , name: }, .. ] mono_wasm_get_variables: function(scope, var_list) { const numBytes = var_list.length * Int32Array.BYTES_PER_ELEMENT; @@ -1428,7 +1445,8 @@ var MonoSupportLib = { this._register_c_var_fn ('mono_wasm_get_local_vars', 'bool', [ 'number', 'number', 'number']); this._register_c_var_fn ('mono_wasm_get_deref_ptr_value', 'bool', [ 'number', 'number']); this._register_c_fn ('mono_wasm_set_value_on_object', 'bool', [ 'number', 'string', 'string' ]); - this._register_c_fn ('mono_wasm_set_variable_on_frame', 'bool', [ 'number', 'number', 'string', 'string']); + this._register_c_fn ('mono_wasm_set_variable_on_frame', 'bool', [ 'number', 'number', 'string', 'string']); + this._register_c_fn ('mono_wasm_send_dbg_command', 'bool', [ 'number', 'number', 'number', 'number', 'number']); // DO NOT REMOVE - magic debugger init function if (globalThis.dotnetDebugger) debugger; @@ -2043,6 +2061,18 @@ var MonoSupportLib = { return new Uint8Array (byteNumbers); }, + mono_wasm_add_dbg_command_received: function(id, buffer, buffer_len) { + console.log(`mono_wasm_add_dbg_command_received`); + const assembly_data = new Uint8Array(Module.HEAPU8.buffer, buffer, buffer_len); + const base64String = MONO._base64Converter.toBase64StringImpl(assembly_data); + //const base64String = btoa (String.fromCharCode (...new Uint8Array (Module.HEAPU8.buffer, buffer, buffer_len))); + const buffer_obj = { + id, + value: base64String + } + MONO.commands_received = buffer_obj; + }, + _begin_value_type_var: function(className, args) { if (args === undefined || (typeof args !== 'object')) { console.debug (`_begin_value_type_var: Expected an args object`); From 8be82ed88dcb5b56949cef61acadfb5bd205a267 Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 5 May 2021 15:41:39 -0300 Subject: [PATCH 02/48] Replace remove_breakpoint and clear_all_breakpoints with the ones on debugger-agent and remove unused code. --- src/mono/mono/mini/debugger-engine.c | 7 -- src/mono/mono/mini/debugger-engine.h | 1 - src/mono/mono/mini/mini-wasm-debugger.c | 83 +------------------ .../BrowserDebugProxy/DevToolsHelper.cs | 6 -- .../debugger/BrowserDebugProxy/MonoProxy.cs | 26 +++--- src/mono/wasm/runtime/library_mono.js | 46 +++------- 6 files changed, 25 insertions(+), 144 deletions(-) diff --git a/src/mono/mono/mini/debugger-engine.c b/src/mono/mono/mini/debugger-engine.c index 2008b51338ac8..38ac2d081f594 100644 --- a/src/mono/mono/mini/debugger-engine.c +++ b/src/mono/mono/mini/debugger-engine.c @@ -388,13 +388,6 @@ collect_domain_bp (gpointer key, gpointer value, gpointer user_data) jit_mm_unlock (jit_mm); } -void -mono_de_clear_all_breakpoints (void) -{ - while (breakpoints->len) - mono_de_clear_breakpoint ((MonoBreakpoint*)g_ptr_array_index (breakpoints, 0)); -} - /* * mono_de_set_breakpoint: * diff --git a/src/mono/mono/mini/debugger-engine.h b/src/mono/mono/mini/debugger-engine.h index 24ad575093e69..27f59f0aa3384 100644 --- a/src/mono/mono/mini/debugger-engine.h +++ b/src/mono/mono/mini/debugger-engine.h @@ -497,7 +497,6 @@ MonoBreakpoint* mono_de_set_breakpoint (MonoMethod *method, long il_offset, Even void mono_de_collect_breakpoints_by_sp (SeqPoint *sp, MonoJitInfo *ji, GPtrArray *ss_reqs, GPtrArray *bp_reqs); void mono_de_clear_breakpoints_for_domain (MonoDomain *domain); void mono_de_add_pending_breakpoints (MonoMethod *method, MonoJitInfo *ji); -void mono_de_clear_all_breakpoints (void); MonoBreakpoint * mono_de_get_breakpoint_by_id (int id); //single stepping diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index d8c598d4dc8bf..59819e19e9d7c 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -41,12 +41,9 @@ enum { //functions exported to be used by JS G_BEGIN_DECLS -EMSCRIPTEN_KEEPALIVE int mono_wasm_set_breakpoint (const char *assembly_name, int method_token, int il_offset); -EMSCRIPTEN_KEEPALIVE int mono_wasm_remove_breakpoint (int bp_id); EMSCRIPTEN_KEEPALIVE int mono_wasm_current_bp_id (void); EMSCRIPTEN_KEEPALIVE void mono_wasm_enum_frames (void); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_local_vars (int scope, int* pos, int len); -EMSCRIPTEN_KEEPALIVE void mono_wasm_clear_all_breakpoints (void); EMSCRIPTEN_KEEPALIVE int mono_wasm_setup_single_step (int kind); EMSCRIPTEN_KEEPALIVE int mono_wasm_pause_on_exceptions (int state); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_object_properties (int object_id, int gpflags); @@ -547,7 +544,7 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) MonoDebugHandle *handle = mono_debug_get_handle (assembly_image); if (handle) { MonoPPDBFile *ppdb = handle->ppdb; - if (!mono_ppdb_is_embedded (ppdb)) { //if it's an embedded pdb we don't need to send pdb extrated to DebuggerProxy. + if (!mono_ppdb_is_embedded (ppdb)) { //if it's an embedded pdb we don't need to send pdb extrated to DebuggerProxy. pdb_image = mono_ppdb_get_image (ppdb); mono_wasm_asm_loaded (assembly_image->assembly_name, assembly_image->raw_data, assembly_image->raw_data_len, pdb_image->raw_data, pdb_image->raw_data_len); return; @@ -587,84 +584,6 @@ handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch } -EMSCRIPTEN_KEEPALIVE void -mono_wasm_clear_all_breakpoints (void) -{ - PRINT_DEBUG_MSG (1, "CLEAR BREAKPOINTS\n"); - mono_de_clear_all_breakpoints (); -} - -EMSCRIPTEN_KEEPALIVE int -mono_wasm_set_breakpoint (const char *assembly_name, int method_token, int il_offset) -{ - int i; - ERROR_DECL (error); - PRINT_DEBUG_MSG (1, "SET BREAKPOINT: assembly %s method %x offset %x\n", assembly_name, method_token, il_offset); - - - //we get 'foo.dll' but mono_assembly_load expects 'foo' so we strip the last dot - char *lookup_name = g_strdup (assembly_name); - for (i = strlen (lookup_name) - 1; i >= 0; --i) { - if (lookup_name [i] == '.') { - lookup_name [i] = 0; - break; - } - } - - //resolve the assembly - MonoImageOpenStatus status; - MonoAssemblyName* aname = mono_assembly_name_new (lookup_name); - MonoAssemblyByNameRequest byname_req; - mono_assembly_request_prepare_byname (&byname_req, MONO_ASMCTX_DEFAULT, mono_alc_get_default ()); - MonoAssembly *assembly = mono_assembly_request_byname (aname, &byname_req, &status); - g_free (lookup_name); - if (!assembly) { - PRINT_DEBUG_MSG (1, "Could not resolve assembly %s\n", assembly_name); - return -1; - } - - mono_assembly_name_free_internal (aname); - - MonoMethod *method = mono_get_method_checked (assembly->image, MONO_TOKEN_METHOD_DEF | method_token, NULL, NULL, error); - if (!method) { - //FIXME don't swallow the error - PRINT_DEBUG_MSG (1, "Could not find method due to %s\n", mono_error_get_message (error)); - mono_error_cleanup (error); - return -1; - } - - //FIXME right now none of the EventRequest fields are used by debugger-engine - EventRequest *req = g_new0 (EventRequest, 1); - req->id = ++event_request_id; - req->event_kind = EVENT_KIND_BREAKPOINT; - //DE doesn't care about suspend_policy - // req->suspend_policy = SUSPEND_POLICY_ALL; - req->nmodifiers = 0; //funny thing, - - // BreakPointRequest *req = breakpoint_request_new (assembly, method, il_offset); - MonoBreakpoint *bp = mono_de_set_breakpoint (method, il_offset, req, error); - - if (!bp) { - PRINT_DEBUG_MSG (1, "Could not set breakpoint to %s\n", mono_error_get_message (error)); - mono_error_cleanup (error); - return 0; - } - - PRINT_DEBUG_MSG (1, "NEW BP %p has id %d\n", req, req->id); - return req->id; -} - -EMSCRIPTEN_KEEPALIVE int -mono_wasm_remove_breakpoint (int bp_id) -{ - MonoBreakpoint *bp = mono_de_get_breakpoint_by_id (bp_id); - if (!bp) - return 0; - - mono_de_clear_breakpoint (bp); - return 1; -} - void mono_wasm_single_step_hit (void) { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index 3f44eae4ad41d..4b987a14bfb66 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -182,8 +182,6 @@ internal class MonoCommands public static MonoCommands GetLoadedFiles() => new MonoCommands("MONO.mono_wasm_get_loaded_files()"); - public static MonoCommands ClearAllBreakpoints() => new MonoCommands("MONO.mono_wasm_clear_all_breakpoints()"); - public static MonoCommands GetDetails(DotnetObjectId objectId, JToken args = null) => new MonoCommands($"MONO.mono_wasm_get_details ('{objectId}', {(args ?? "{ }")})"); public static MonoCommands GetScopeVariables(int scopeId, params VarInfo[] vars) @@ -203,15 +201,11 @@ public static MonoCommands EvaluateMemberAccess(int scopeId, string expr, params return new MonoCommands($"MONO.mono_wasm_eval_member_access({scopeId}, {JsonConvert.SerializeObject(var_ids)}, '', '{expr}')"); } - public static MonoCommands SetBreakpoint(string assemblyName, int methodToken, int ilOffset) => new MonoCommands($"MONO.mono_wasm_set_breakpoint (\"{assemblyName}\", {methodToken}, {ilOffset})"); - public static MonoCommands SendDebuggerAgentCommand(int id, int command_set, int command, string command_parameters) { return new MonoCommands($"MONO.mono_wasm_send_dbg_command ({id}, {command_set}, {command},'{command_parameters}')"); } - public static MonoCommands RemoveBreakpoint(int breakpointId) => new MonoCommands($"MONO.mono_wasm_remove_breakpoint({breakpointId})"); - public static MonoCommands ReleaseObject(DotnetObjectId objectId) => new MonoCommands($"MONO.mono_wasm_release_object('{objectId}')"); public static MonoCommands CallFunctionOn(JToken args) => new MonoCommands($"MONO.mono_wasm_call_function_on ({args.ToString()})"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index e798eca3c16e2..543492a881637 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -1222,6 +1222,8 @@ internal async Task GetScopeProperties(SessionId msg_id, int scope_id, C private async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) { Result res = await SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); + if (res.IsErr) + return null; byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); @@ -1241,8 +1243,6 @@ private async Task SetMonoBreakpoint(SessionId sessionId, string req var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.GET_ASSEMBLY_BY_NAME, command_params, token); var assembly_id = ret_debugger_cmd_reader.ReadInt32(); - Console.WriteLine("SendDebuggerAgentCommand - assembly_id - " + assembly_id); - command_params = new MemoryStream(); command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(assembly_id); @@ -1250,8 +1250,6 @@ private async Task SetMonoBreakpoint(SessionId sessionId, string req ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_METHOD_FROM_TOKEN, command_params, token); var method_id = ret_debugger_cmd_reader.ReadInt32(); - Console.WriteLine("SendDebuggerAgentCommand - method_id - " + method_id); - command_params = new MemoryStream(); command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write((byte)EventKind.BREAKPOINT); @@ -1263,15 +1261,12 @@ private async Task SetMonoBreakpoint(SessionId sessionId, string req ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); var breakpoint_id = ret_debugger_cmd_reader.ReadInt32(); - Console.WriteLine("SendDebuggerAgentCommand - breakpoint_id - " + breakpoint_id); - if (breakpoint_id > 0) { bp.RemoteId = breakpoint_id; bp.State = BreakpointState.Active; //Log ("verbose", $"BP local id {bp.LocalId} enabled with remote id {bp.RemoteId}"); } - return bp; } @@ -1330,10 +1325,11 @@ private async Task RuntimeReady(SessionId sessionId, CancellationTok if (Interlocked.CompareExchange(ref context.ready, new TaskCompletionSource(), null) != null) return await context.ready.Task; - Result clear_result = await SendMonoCommand(sessionId, MonoCommands.ClearAllBreakpoints(), token); - if (clear_result.IsErr) + var command_params = new MemoryStream(); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR_ALL_BREAKPOINTS, command_params, token); + if (ret_debugger_cmd_reader == null) { - Log("verbose", $"Failed to clear breakpoints due to {clear_result}"); + Log("verbose", $"Failed to clear breakpoints"); } DebugStore store = await LoadStore(sessionId, token); @@ -1353,10 +1349,14 @@ private async Task RemoveBreakpoint(MessageId msg_id, JObject args, Cancellation foreach (Breakpoint bp in breakpointRequest.Locations) { - Result res = await SendMonoCommand(msg_id, MonoCommands.RemoveBreakpoint(bp.RemoteId), token); - int? ret_code = res.Value?["result"]?["value"]?.Value(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((byte)EventKind.BREAKPOINT); + command_params_writer.Write((int) bp.RemoteId); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(msg_id, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR, command_params, token); - if (ret_code.HasValue) + if (ret_debugger_cmd_reader != null) { bp.RemoteId = -1; bp.State = BreakpointState.Disabled; diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index ce585041da68d..0cd7e3de0f649 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -832,16 +832,25 @@ var MonoSupportLib = { return vars; }, + mono_wasm_add_dbg_command_received: function(id, buffer, buffer_len) { + console.log(`mono_wasm_add_dbg_command_received`); + const assembly_data = new Uint8Array(Module.HEAPU8.buffer, buffer, buffer_len); + const base64String = MONO._base64Converter.toBase64StringImpl(assembly_data); + const buffer_obj = { + id, + value: base64String + } + MONO.commands_received = buffer_obj; + }, + mono_wasm_send_dbg_command: function (id, command_set, command, command_parameters) { console.log(`mono_wasm_send_dbg_command ${id} - ${command_set} - ${command} - ${command_parameters.length}`); - const dataPtr = Module._malloc (command_parameters.length); const dataHeap = new Uint8Array (Module.HEAPU8.buffer, command_parameters, command_parameters.length); dataHeap.set (new Uint8Array (this._base64_to_uint8 (command_parameters))); let res_ok = this._c_fn_table.mono_wasm_send_dbg_command_wrapper (id, command_set, command, dataHeap.byteOffset, command_parameters.length); - Module._free (dataHeap.byteOffset); let res = MONO.commands_received; if (res_ok) { @@ -1454,20 +1463,6 @@ var MonoSupportLib = { console.debug ("mono_wasm_runtime_ready", "fe00e07a-5519-4dfe-b35a-f867dbaf2e28"); }, - mono_wasm_set_breakpoint: function (assembly, method_token, il_offset) { - if (!this.mono_wasm_set_bp) - this.mono_wasm_set_bp = Module.cwrap ('mono_wasm_set_breakpoint', 'number', ['string', 'number', 'number']); - - return this.mono_wasm_set_bp (assembly, method_token, il_offset) - }, - - mono_wasm_remove_breakpoint: function (breakpoint_id) { - if (!this.mono_wasm_del_bp) - this.mono_wasm_del_bp = Module.cwrap ('mono_wasm_remove_breakpoint', 'number', ['number']); - - return this.mono_wasm_del_bp (breakpoint_id); - }, - // Set environment variable NAME to VALUE // Should be called before mono_load_runtime_and_bcl () in most cases mono_wasm_setenv: function (name, value) { @@ -1978,13 +1973,6 @@ var MonoSupportLib = { return MONO.loaded_assets; }, - mono_wasm_clear_all_breakpoints: function() { - if (!this.mono_clear_bps) - this.mono_clear_bps = Module.cwrap ('mono_wasm_clear_all_breakpoints', null); - - this.mono_clear_bps (); - }, - mono_wasm_add_null_var: function(className) { let fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); @@ -2061,18 +2049,6 @@ var MonoSupportLib = { return new Uint8Array (byteNumbers); }, - mono_wasm_add_dbg_command_received: function(id, buffer, buffer_len) { - console.log(`mono_wasm_add_dbg_command_received`); - const assembly_data = new Uint8Array(Module.HEAPU8.buffer, buffer, buffer_len); - const base64String = MONO._base64Converter.toBase64StringImpl(assembly_data); - //const base64String = btoa (String.fromCharCode (...new Uint8Array (Module.HEAPU8.buffer, buffer, buffer_len))); - const buffer_obj = { - id, - value: base64String - } - MONO.commands_received = buffer_obj; - }, - _begin_value_type_var: function(className, args) { if (args === undefined || (typeof args !== 'object')) { console.debug (`_begin_value_type_var: Expected an args object`); From 1fa738de8edcfb785a322b60c9287328e7ee8002 Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 6 May 2021 15:27:21 -0300 Subject: [PATCH 03/48] Stepping and callstack using debugger-agent. --- src/mono/mono/mini/debugger-agent.c | 101 ++-- src/mono/mono/mini/debugger-agent.h | 18 + src/mono/mono/mini/mini-wasm-debugger.c | 191 ++---- .../BrowserDebugProxy/DevToolsHelper.cs | 11 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 544 +++++------------- .../BrowserDebugProxy/MonoSDBHelper.cs | 391 +++++++++++++ .../DebuggerTestSuite/SteppingTests.cs | 2 +- src/mono/wasm/runtime/library_mono.js | 45 +- 8 files changed, 639 insertions(+), 664 deletions(-) create mode 100644 src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 43606f4259a55..f1a68b18b4e58 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -261,15 +261,6 @@ struct _DebuggerTlsData { gboolean gc_finalizing; }; -typedef struct { - const char *name; - void (*connect) (const char *address); - void (*close1) (void); - void (*close2) (void); - gboolean (*send) (void *buf, int len); - int (*recv) (void *buf, int len); -} DebuggerTransport; - /* Buffered reply packets */ static ReplyPacket reply_packets [128]; static int nreply_packets; @@ -310,6 +301,17 @@ typedef struct { #define CHECK_ICORDBG(status) \ (protocol_version_set && using_icordbg == status) +#ifndef TARGET_WASM +#define GET_TLS_DATA(thread) \ + mono_loader_lock(); \ + tls = (DebuggerTlsData*)mono_g_hash_table_lookup(thread_to_tls, thread); \ + mono_loader_unlock(); +#else +#define GET_TLS_DATA(thread) \ + DebuggerTlsData local_data;\ + memset(&local_data, 0, sizeof(DebuggerTlsData)); \ + tls = &local_data; +#endif /* * Globals */ @@ -483,20 +485,12 @@ 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 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); static void ss_args_destroy (SingleStepArgs *ss_args); static int handle_multiple_ss_requests (void); static GENERATE_TRY_GET_CLASS_WITH_CACHE (fixed_buffer, "System.Runtime.CompilerServices", "FixedBufferAttribute") -void mono_init_debugger_agent_for_wasm (int log_level_parm) -{ - ids_init(); - log_level = log_level; - event_requests = g_ptr_array_new (); -} #ifndef DISABLE_SOCKET_TRANSPORT static void @@ -724,8 +718,8 @@ debugger_agent_init (void) cbs.get_this_async_id = get_this_async_id; cbs.set_set_notification_for_wait_completion_flag = set_set_notification_for_wait_completion_flag; cbs.get_notify_debugger_of_wait_completion_method = get_notify_debugger_of_wait_completion_method; - cbs.create_breakpoint_events = create_breakpoint_events; - cbs.process_breakpoint_events = process_breakpoint_events; + cbs.create_breakpoint_events = mono_dbg_create_breakpoint_events; + cbs.process_breakpoint_events = mono_dbg_process_breakpoint_events; cbs.ss_create_init_args = ss_create_init_args; cbs.ss_args_destroy = ss_args_destroy; cbs.handle_multiple_ss_requests = handle_multiple_ss_requests; @@ -1294,9 +1288,6 @@ static DebuggerTransport *transport; static DebuggerTransport transports [MAX_TRANSPORTS]; static int ntransports; -MONO_API void -mono_debugger_agent_register_transport (DebuggerTransport *trans); - void mono_debugger_agent_register_transport (DebuggerTransport *trans) { @@ -1598,6 +1589,21 @@ static GHashTable *obj_to_objref; static MonoGHashTable *suspended_objs; +void mono_init_debugger_agent_for_wasm (int log_level_parm) +{ + ids_init(); + objrefs = g_hash_table_new_full (NULL, NULL, NULL, mono_debugger_free_objref); + obj_to_objref = g_hash_table_new (NULL, NULL); + + log_level = log_level; + event_requests = g_ptr_array_new (); + if (mono_atomic_cas_i32 (&agent_inited, 1, 0) == 1) + return; + vm_start_event_sent = TRUE; + transport = &transports [0]; +} + + static void objrefs_init (void) @@ -2707,7 +2713,8 @@ static int count_threads_to_wait_for (void) { int count = 0; - + if (thread_to_tls == NULL) + return 0; mono_loader_lock (); mono_g_hash_table_foreach (thread_to_tls, count_thread, &count); mono_loader_unlock (); @@ -3021,9 +3028,7 @@ compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls, gboolean f } else if (tls->context.valid) { mono_walk_stack_with_state (process_frame, &tls->context, opts, &user_data); } else { - // FIXME: - tls->frame_count = 0; - return; + mono_walk_stack_with_ctx (process_frame, NULL, opts, &user_data); } new_frame_count = g_slist_length (user_data.frames); @@ -3437,7 +3442,15 @@ create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo return events; } - +static void mono_stop_timer_watch (int debugger_tls_id) +{ +#ifndef TARGET_WASM + DebuggerTlsData *tls; + tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); + g_assert (tls); + mono_stopwatch_stop (&tls->step_time); +#endif +} /* * process_event: * @@ -3559,12 +3572,8 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx break; case EVENT_KIND_BREAKPOINT: case EVENT_KIND_STEP: { - DebuggerTlsData *tls; - tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); - g_assert (tls); - mono_stopwatch_stop (&tls->step_time); + mono_stop_timer_watch (debugger_tls_id); MonoMethod *method = (MonoMethod *)arg; - buffer_add_methodid (&buf, domain, method); buffer_add_long (&buf, il_offset); break; @@ -4184,8 +4193,8 @@ typedef struct { int suspend_policy; } BreakPointEvents; -static void* -create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind) +void* +mono_dbg_create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind) { int suspend_policy = 0; BreakPointEvents *evts = g_new0 (BreakPointEvents, 1); @@ -4201,8 +4210,8 @@ create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *j return evts; } -static void -process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset) +void +mono_dbg_process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset) { BreakPointEvents *evts = (BreakPointEvents*)_evts; /* @@ -7142,10 +7151,10 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf) g_free (req); return err; } + + DebuggerTlsData* tls; + GET_TLS_DATA(THREAD_TO_INTERNAL(step_thread)); - mono_loader_lock (); - DebuggerTlsData *tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, THREAD_TO_INTERNAL(step_thread)); - mono_loader_unlock (); g_assert (tls); if (tls->terminated) { @@ -8793,10 +8802,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) } int context_size = 0; uint8_t * contextMemoryReceived = m_dbgprot_decode_byte_array(p, &p, end, &context_size); - - mono_loader_lock(); - tls = (DebuggerTlsData*)mono_g_hash_table_lookup(thread_to_tls, thread); - mono_loader_unlock(); + GET_TLS_DATA(thread); if (tls == NULL) return ERR_UNLOADED; @@ -8824,9 +8830,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) } start_frame = decode_int (p, &p, end); - mono_loader_lock (); - tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread); - mono_loader_unlock (); + GET_TLS_DATA(thread); if (tls == NULL) return ERR_UNLOADED; @@ -8860,10 +8864,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (start_frame != 0 || length != -1) return ERR_NOT_IMPLEMENTED; - - mono_loader_lock (); - tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread); - mono_loader_unlock (); + GET_TLS_DATA(thread); if (tls == NULL) return ERR_UNLOADED; diff --git a/src/mono/mono/mini/debugger-agent.h b/src/mono/mono/mini/debugger-agent.h index 05fbe1a07dabe..abefdee2b5529 100644 --- a/src/mono/mono/mini/debugger-agent.h +++ b/src/mono/mono/mini/debugger-agent.h @@ -14,6 +14,15 @@ // 2. debug_log parameters changed from MonoString* to MonoStringHandle // 3. debug_log parameters changed from MonoStringHandle back to MonoString* +typedef struct { + const char *name; + void (*connect) (const char *address); + void (*close1) (void); + void (*close2) (void); + gboolean (*send) (void *buf, int len); + int (*recv) (void *buf, int len); +} DebuggerTransport; + struct _MonoDebuggerCallbacks { int version; void (*parse_options) (char *options); @@ -48,10 +57,19 @@ mono_debugger_agent_stub_init (void); MONO_API MONO_RT_EXTERNAL_ONLY gboolean mono_debugger_agent_transport_handshake (void); +MONO_API void +mono_debugger_agent_register_transport (DebuggerTransport *trans); + MdbgProtErrorCode mono_process_dbg_packet (int id, MdbgProtCommandSet command_set, int command, gboolean *no_reply, guint8 *p, guint8 *end, MdbgProtBuffer *buf); void mono_init_debugger_agent_for_wasm (int log_level); +void* +mono_dbg_create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, MdbgProtEventKind kind); + +void +mono_dbg_process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset); + #endif diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 59819e19e9d7c..184f33e444daf 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -41,10 +41,7 @@ enum { //functions exported to be used by JS G_BEGIN_DECLS -EMSCRIPTEN_KEEPALIVE int mono_wasm_current_bp_id (void); -EMSCRIPTEN_KEEPALIVE void mono_wasm_enum_frames (void); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_local_vars (int scope, int* pos, int len); -EMSCRIPTEN_KEEPALIVE int mono_wasm_setup_single_step (int kind); EMSCRIPTEN_KEEPALIVE int mono_wasm_pause_on_exceptions (int state); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_object_properties (int object_id, int gpflags); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_array_values (int object_id, int start_idx, int count, int gpflags); @@ -59,6 +56,7 @@ EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtComman //JS functions imported that we use extern void mono_wasm_add_frame (int il_offset, int method_token, int frame_id, const char *assembly_name, const char *method_name); extern void mono_wasm_fire_bp (void); +extern void mono_wasm_fire_debugger_agent_message (void); extern void mono_wasm_fire_exception (int exception_obj_id, const char* message, const char* class_name, gboolean uncaught); extern void mono_wasm_add_obj_var (const char*, const char*, guint64); extern void mono_wasm_add_enum_var (const char*, const char*, guint64); @@ -73,6 +71,7 @@ G_END_DECLS static void describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAsyncLocalThis, int gpflags); static void handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame); +static gboolean receive_debugger_agent_message (void *data, int len); static void assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly); static MonoObject* mono_runtime_try_invoke_internal (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error); @@ -82,6 +81,7 @@ static gboolean debugger_enabled; static gboolean has_pending_lazy_loaded_assemblies; static int event_request_id; +static int current_bp_id; static GHashTable *objrefs; static GHashTable *obj_to_objref; static int objref_id = 0; @@ -333,6 +333,12 @@ create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *j { PRINT_DEBUG_MSG (1, "ss_reqs %d bp_reqs %d\n", ss_reqs->len, bp_reqs->len); if ((ss_reqs && ss_reqs->len) || (bp_reqs && bp_reqs->len)) { + EventRequest *req = NULL; + if ((bp_reqs && bp_reqs->len)) + req = (EventRequest *)g_ptr_array_index (bp_reqs, 0); + if ((ss_reqs && ss_reqs->len)) + req = (EventRequest *)g_ptr_array_index (ss_reqs, 0); + current_bp_id = req->id; BpEvents *evts = g_new0 (BpEvents, 1); //just a non-null value to make sure we can raise it on process_breakpoint_events evts->is_ss = (ss_reqs && ss_reqs->len); return evts; @@ -422,8 +428,8 @@ mono_wasm_debugger_init (void) .get_this_async_id = get_this_async_id, .set_set_notification_for_wait_completion_flag = set_set_notification_for_wait_completion_flag, .get_notify_debugger_of_wait_completion_method = get_notify_debugger_of_wait_completion_method, - .create_breakpoint_events = create_breakpoint_events, - .process_breakpoint_events = process_breakpoint_events, + .create_breakpoint_events = mono_dbg_create_breakpoint_events, + .process_breakpoint_events = mono_dbg_process_breakpoint_events, .ss_create_init_args = ss_create_init_args, .ss_args_destroy = ss_args_destroy, .handle_multiple_ss_requests = handle_multiple_ss_requests, @@ -431,7 +437,7 @@ mono_wasm_debugger_init (void) mono_debug_init (MONO_DEBUG_FORMAT_MONO); mono_de_init (&cbs); - mono_de_set_log_level (log_level, stdout); + mono_de_set_log_level (10, stdout); mini_debug_options.gen_sdb_seq_points = TRUE; mini_debug_options.mdb_optimizations = TRUE; @@ -451,7 +457,12 @@ mono_wasm_debugger_init (void) mini_get_dbg_callbacks ()->user_break = mono_wasm_user_break; //debugger-agent initialization - mono_init_debugger_agent_for_wasm (log_level); + DebuggerTransport trans; + trans.name = "buffer-wasm-communication"; + trans.send = receive_debugger_agent_message; + + mono_debugger_agent_register_transport (&trans); + mono_init_debugger_agent_for_wasm (10); } MONO_API void @@ -470,61 +481,6 @@ mono_wasm_pause_on_exceptions (int state) return 1; } -EMSCRIPTEN_KEEPALIVE int -mono_wasm_setup_single_step (int kind) -{ - int nmodifiers = 1; - - PRINT_DEBUG_MSG (2, ">>>> mono_wasm_setup_single_step %d\n", kind); - EventRequest *req = (EventRequest *)g_malloc0 (sizeof (EventRequest) + (nmodifiers * sizeof (Modifier))); - req->id = ++event_request_id; - req->event_kind = EVENT_KIND_STEP; - // DE doesn't care about suspend_policy - // req->suspend_policy = SUSPEND_POLICY_ALL; - req->nmodifiers = nmodifiers; - - StepSize size = STEP_SIZE_MIN; - - //FIXME I DON'T KNOW WHAT I'M DOING!!!!! filter all the things. - StepFilter filter = (StepFilter)(STEP_FILTER_STATIC_CTOR | STEP_FILTER_DEBUGGER_HIDDEN | STEP_FILTER_DEBUGGER_STEP_THROUGH | STEP_FILTER_DEBUGGER_NON_USER_CODE); - req->modifiers [0].data.filter = filter; - - StepDepth depth; - switch (kind) { - case 0: //into - depth = STEP_DEPTH_INTO; - break; - case 1: //out - depth = STEP_DEPTH_OUT; - break; - case 2: //over - depth = STEP_DEPTH_OVER; - break; - default: - g_error ("[dbg] unknown step kind %d", kind); - } - - DbgEngineErrorCode err = mono_de_ss_create (THREAD_TO_INTERNAL (mono_thread_current ()), size, depth, filter, req); - if (err != DE_ERR_NONE) { - PRINT_DEBUG_MSG (1, "[dbg] Failed to setup single step request"); - } - PRINT_DEBUG_MSG (1, "[dbg] single step is in place, now what?\n"); - SingleStepReq *ss_req = req->info; - int isBPOnNativeCode = 0; - if (ss_req && ss_req->bps) { - GSList *l; - - for (l = ss_req->bps; l; l = l->next) { - if (((MonoBreakpoint *)l->data)->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) - isBPOnNativeCode = 1; - } - } - if (!isBPOnNativeCode) { - mono_de_cancel_all_ss (); - } - return isBPOnNativeCode; -} - static void assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) { @@ -603,54 +559,6 @@ mono_wasm_user_break (void) mono_wasm_fire_bp (); } -EMSCRIPTEN_KEEPALIVE int -mono_wasm_current_bp_id (void) -{ - PRINT_DEBUG_MSG (2, "COMPUTING breakpoint ID\n"); - //FIXME handle compiled case - - /* Interpreter */ - MonoLMF *lmf = mono_get_lmf (); - - g_assert (((guint64)lmf->previous_lmf) & 2); - MonoLMFExt *ext = (MonoLMFExt*)lmf; - - g_assert (ext->kind == MONO_LMFEXT_INTERP_EXIT || ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX); - MonoInterpFrameHandle *frame = (MonoInterpFrameHandle*)ext->interp_exit_data; - MonoJitInfo *ji = mini_get_interp_callbacks ()->frame_get_jit_info (frame); - guint8 *ip = (guint8*)mini_get_interp_callbacks ()->frame_get_ip (frame); - - g_assert (ji && !ji->is_trampoline); - MonoMethod *method = jinfo_get_method (ji); - - /* Compute the native offset of the breakpoint from the ip */ - guint32 native_offset = ip - (guint8*)ji->code_start; - - MonoSeqPointInfo *info = NULL; - SeqPoint sp; - gboolean found_sp = mono_find_prev_seq_point_for_native_offset (method, native_offset, &info, &sp); - if (!found_sp) - PRINT_DEBUG_MSG (1, "Could not find SP\n"); - - - GPtrArray *bp_reqs = g_ptr_array_new (); - mono_de_collect_breakpoints_by_sp (&sp, ji, NULL, bp_reqs); - - if (bp_reqs->len == 0) { - PRINT_DEBUG_MSG (1, "BP NOT FOUND for method %s JI %p il_offset %d\n", method->name, ji, sp.il_offset); - return -1; - } - - if (bp_reqs->len > 1) - PRINT_DEBUG_MSG (1, "Multiple breakpoints (%d) at the same location, returning the first one.", bp_reqs->len); - - EventRequest *evt = (EventRequest *)g_ptr_array_index (bp_reqs, 0); - g_ptr_array_free (bp_reqs, TRUE); - - PRINT_DEBUG_MSG (1, "Found BP %p with id %d\n", evt, evt->id); - return evt->id; -} - static MonoObject* get_object_from_id (int objectId) { @@ -667,55 +575,6 @@ get_object_from_id (int objectId) return obj; } -static gboolean -list_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) -{ - SeqPoint sp; - MonoMethod *method; - char *method_full_name; - - int* frame_id_p = (int*)data; - (*frame_id_p)++; - - //skip wrappers - if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) - return FALSE; - - if (info->ji) - method = jinfo_get_method (info->ji); - else - method = info->method; - - if (!method || method->wrapper_type != MONO_WRAPPER_NONE) - return FALSE; - - PRINT_DEBUG_MSG (2, "list_frames: Reporting method %s native_offset %d, wrapper_type: %d\n", method->name, info->native_offset, method->wrapper_type); - - if (!mono_find_prev_seq_point_for_native_offset (method, info->native_offset, NULL, &sp)) - PRINT_DEBUG_MSG (2, "list_frames: Failed to lookup sequence point. method: %s, native_offset: %d\n", method->name, info->native_offset); - - method_full_name = mono_method_full_name (method, FALSE); - while (method->is_inflated) - method = ((MonoMethodInflated*)method)->declaring; - - char *assembly_name = g_strdup (m_class_get_image (method->klass)->module_name); - inplace_tolower (assembly_name); - - PRINT_DEBUG_MSG (2, "adding off %d token %d assembly name %s\n", sp.il_offset, mono_metadata_token_index (method->token), assembly_name); - mono_wasm_add_frame (sp.il_offset, mono_metadata_token_index (method->token), *frame_id_p, assembly_name, method_full_name); - - g_free (assembly_name); - - return FALSE; -} - -EMSCRIPTEN_KEEPALIVE void -mono_wasm_enum_frames (void) -{ - int frame_id = -1; - mono_walk_stack_with_ctx (list_frames, NULL, MONO_UNWIND_NONE, &frame_id); -} - static char* invoke_to_string (const char *class_name, MonoClass *klass, gpointer addr) { @@ -1866,9 +1725,23 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, EM_ASM ({ MONO.mono_wasm_add_dbg_command_received ($0, $1, $2); }, id, buf.buf, buf.p-buf.buf); + + buffer_free (&buf); return TRUE; } +static gboolean +receive_debugger_agent_message (void *data, int len) +{ + PRINT_DEBUG_MSG (1, "receive_debugger_agent_message - %d\n", len); + EM_ASM ({ + MONO.mono_wasm_add_dbg_command_received (-1, $0, $1); + }, data, len); + mono_wasm_fire_debugger_agent_message (); + return FALSE; +} + + #else // HOST_WASM void diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index 4b987a14bfb66..9b230738c5fb6 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -172,13 +172,11 @@ internal class MonoCommands public MonoCommands(string expression) => this.expression = expression; - public static MonoCommands GetCallStack() => new MonoCommands("MONO.mono_wasm_get_call_stack()"); - public static MonoCommands GetExceptionObject() => new MonoCommands("MONO.mono_wasm_get_exception_object()"); - public static MonoCommands IsRuntimeReady() => new MonoCommands("MONO.mono_wasm_runtime_is_ready"); + public static MonoCommands GetDebuggerAgentBufferReceived() => new MonoCommands("MONO.mono_wasm_get_dbg_command_info()"); - public static MonoCommands StartSingleStepping(StepKind kind) => new MonoCommands($"MONO.mono_wasm_start_single_stepping ({(int)kind})"); + public static MonoCommands IsRuntimeReady() => new MonoCommands("MONO.mono_wasm_runtime_is_ready"); public static MonoCommands GetLoadedFiles() => new MonoCommands("MONO.mono_wasm_get_loaded_files()"); @@ -279,8 +277,8 @@ internal enum BreakpointState internal enum StepKind { Into, - Out, - Over + Over, + Out } internal class ExecutionContext @@ -291,6 +289,7 @@ internal class ExecutionContext public TaskCompletionSource ready; public bool IsRuntimeReady => ready != null && ready.Task.IsCompleted; + public int ThreadId { get; set; } public int Id { get; set; } public object AuxData { get; set; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 543492a881637..e2d4b24197c7e 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -18,228 +18,7 @@ namespace Microsoft.WebAssembly.Diagnostics { internal class MonoProxy : DevToolsProxy { - internal class MonoBinaryWriter : BinaryWriter - { - public MonoBinaryWriter(Stream stream) : base(stream) {} - public void WriteString(string val) - { - Write(val.Length); - Write(val.ToCharArray()); - } - public void WriteLong(long val) - { - Write((int)((val >> 32) & 0xffffffff)); - Write((int)((val >> 0) & 0xffffffff)); - } - } - private enum TokenType - { - mdtModule = 0x00000000, // - mdtTypeRef = 0x01000000, // - mdtTypeDef = 0x02000000, // - mdtFieldDef = 0x04000000, // - mdtMethodDef = 0x06000000, // - mdtParamDef = 0x08000000, // - mdtInterfaceImpl = 0x09000000, // - mdtMemberRef = 0x0a000000, // - mdtCustomAttribute = 0x0c000000, // - mdtPermission = 0x0e000000, // - mdtSignature = 0x11000000, // - mdtEvent = 0x14000000, // - mdtProperty = 0x17000000, // - mdtModuleRef = 0x1a000000, // - mdtTypeSpec = 0x1b000000, // - mdtAssembly = 0x20000000, // - mdtAssemblyRef = 0x23000000, // - mdtFile = 0x26000000, // - mdtExportedType = 0x27000000, // - mdtManifestResource = 0x28000000, // - mdtGenericParam = 0x2a000000, // - mdtMethodSpec = 0x2b000000, // - mdtGenericParamConstraint = 0x2c000000, - - mdtString = 0x70000000, // - mdtName = 0x71000000, // - mdtBaseType = 0x72000000, // Leave this on the high end value. This does not correspond to metadata table - } - - private enum CommandSet { - VM = 1, - OBJECT_REF = 9, - STRING_REF = 10, - THREAD = 11, - ARRAY_REF = 13, - EVENT_REQUEST = 15, - STACK_FRAME = 16, - APPDOMAIN = 20, - ASSEMBLY = 21, - METHOD = 22, - TYPE = 23, - MODULE = 24, - FIELD = 25, - EVENT = 64, - POINTER = 65 - } - - private enum EventKind { - VM_START = 0, - VM_DEATH = 1, - THREAD_START = 2, - THREAD_DEATH = 3, - APPDOMAIN_CREATE = 4, // Not in JDI - APPDOMAIN_UNLOAD = 5, // Not in JDI - METHOD_ENTRY = 6, - METHOD_EXIT = 7, - ASSEMBLY_LOAD = 8, - ASSEMBLY_UNLOAD = 9, - BREAKPOINT = 10, - STEP = 11, - TYPE_LOAD = 12, - EXCEPTION = 13, - KEEPALIVE = 14, - USER_BREAK = 15, - USER_LOG = 16, - CRASH = 17 - } - - private enum ModifierKind { - COUNT = 1, - THREAD_ONLY = 3, - LOCATION_ONLY = 7, - EXCEPTION_ONLY = 8, - STEP = 10, - ASSEMBLY_ONLY = 11, - SOURCE_FILE_ONLY = 12, - TYPE_NAME_ONLY = 13 - } - - - private enum SuspendPolicy { - SUSPEND_POLICY_NONE = 0, - SUSPEND_POLICY_EVENT_THREAD = 1, - SUSPEND_POLICY_ALL = 2 - } - - private enum CmdVM { - VERSION = 1, - ALL_THREADS = 2, - SUSPEND = 3, - RESUME = 4, - EXIT = 5, - DISPOSE = 6, - INVOKE_METHOD = 7, - SET_PROTOCOL_VERSION = 8, - ABORT_INVOKE = 9, - SET_KEEPALIVE = 10, - GET_TYPES_FOR_SOURCE_FILE = 11, - GET_TYPES = 12, - INVOKE_METHODS = 13, - START_BUFFERING = 14, - STOP_BUFFERING = 15, - VM_READ_MEMORY = 16, - VM_WRITE_MEMORY = 17, - GET_ASSEMBLY_BY_NAME = 18 - } - - private enum CmdEvent { - COMPOSITE = 100 - } - - private enum CmdThread { - GET_FRAME_INFO = 1, - GET_NAME = 2, - GET_STATE = 3, - GET_INFO = 4, - /* FIXME: Merge into GET_INFO when the major protocol version is increased */ - GET_ID = 5, - /* Ditto */ - GET_TID = 6, - SET_IP = 7, - GET_ELAPSED_TIME = 8 - } - - private enum CmdEventRequest { - SET = 1, - CLEAR = 2, - CLEAR_ALL_BREAKPOINTS = 3 - } - - private enum CmdAppDomain { - GET_ROOT_DOMAIN = 1, - GET_FRIENDLY_NAME = 2, - GET_ASSEMBLIES = 3, - GET_ENTRY_ASSEMBLY = 4, - CREATE_STRING = 5, - GET_CORLIB = 6, - CREATE_BOXED_VALUE = 7, - CREATE_BYTE_ARRAY = 8, - } - - private enum CmdAssembly { - GET_LOCATION = 1, - GET_ENTRY_POINT = 2, - GET_MANIFEST_MODULE = 3, - GET_OBJECT = 4, - GET_TYPE = 5, - GET_NAME = 6, - GET_DOMAIN = 7, - GET_METADATA_BLOB = 8, - GET_IS_DYNAMIC = 9, - GET_PDB_BLOB = 10, - GET_TYPE_FROM_TOKEN = 11, - GET_METHOD_FROM_TOKEN = 12, - HAS_DEBUG_INFO = 13, - } - - private enum CmdModule { - GET_INFO = 1, - APPLY_CHANGES = 2, - } - - private enum CmdMethod { - GET_NAME = 1, - GET_DECLARING_TYPE = 2, - GET_DEBUG_INFO = 3, - GET_PARAM_INFO = 4, - GET_LOCALS_INFO = 5, - GET_INFO = 6, - GET_BODY = 7, - RESOLVE_TOKEN = 8, - GET_CATTRS = 9, - MAKE_GENERIC_METHOD = 10 - } - - private enum CmdType { - GET_INFO = 1, - GET_METHODS = 2, - GET_FIELDS = 3, - GET_VALUES = 4, - GET_OBJECT = 5, - GET_SOURCE_FILES = 6, - SET_VALUES = 7, - IS_ASSIGNABLE_FROM = 8, - GET_PROPERTIES = 9, - GET_CATTRS = 10, - GET_FIELD_CATTRS = 11, - GET_PROPERTY_CATTRS = 12, - /* FIXME: Merge into GET_SOURCE_FILES when the major protocol version is increased */ - GET_SOURCE_FILES_2 = 13, - /* FIXME: Merge into GET_VALUES when the major protocol version is increased */ - GET_VALUES_2 = 14, - CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15, - GET_INTERFACES = 16, - GET_INTERFACE_MAP = 17, - IS_INITIALIZED = 18, - CREATE_INSTANCE = 19, - GET_VALUE_SIZE = 20 - } - - private enum CmdField { - GET_INFO = 1 - } - - private static int cmd_id; - private static int GetId() {return cmd_id++;} + private MonoSDBHelper sdbHelper; private IList urlSymbolServerList; private static HttpClient client = new HttpClient(); private HashSet sessions = new HashSet(); @@ -248,6 +27,7 @@ private enum CmdField { public MonoProxy(ILoggerFactory loggerFactory, IList urlSymbolServerList) : base(loggerFactory) { this.urlSymbolServerList = urlSymbolServerList ?? new List(); + sdbHelper = new MonoSDBHelper(this); } internal ExecutionContext GetContext(SessionId sessionId) @@ -358,7 +138,11 @@ protected override async Task AcceptEvent(SessionId sessionId, string meth case "_mono_wasm_fire_bp": case "_mono_wasm_fire_exception": { - return await OnPause(sessionId, args, token); + return false;//await OnPause(sessionId, args, token); + } + case "_mono_wasm_fire_debugger_agent_message": + { + return await OnReceiveDebuggerAgentEvent(sessionId, args, token); } } break; @@ -796,180 +580,149 @@ private async Task EvaluateCondition(SessionId sessionId, ExecutionContext return false; } - private async Task OnPause(SessionId sessionId, JObject args, CancellationToken token) + private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObject args, CancellationToken token) { - //FIXME we should send release objects every now and then? Or intercept those we inject and deal in the runtime - Result res = await SendMonoCommand(sessionId, MonoCommands.GetCallStack(), token); - IEnumerable orig_callframes = args?["callFrames"]?.Values(); - ExecutionContext context = GetContext(sessionId); - JObject data = null; - string reason = "other";//other means breakpoint - + Result res = await SendMonoCommand(sessionId, MonoCommands.GetDebuggerAgentBufferReceived(), token); if (res.IsErr) - { - //Give up and send the original call stack return false; - } - - //step one, figure out where did we hit - JToken res_value = res.Value?["result"]?["value"]; - if (res_value == null || res_value is JValue) - { - //Give up and send the original call stack - return false; - } - Log("verbose", $"call stack (err is {res.Error} value is:\n{res.Value}"); - int? bp_id = res_value?["breakpoint_id"]?.Value(); - Log("verbose", $"We just hit bp {bp_id}"); - if (!bp_id.HasValue) - { - //Give up and send the original call stack - return false; - } - - Breakpoint bp = context.BreakpointRequests.Values.SelectMany(v => v.Locations).FirstOrDefault(b => b.RemoteId == bp_id.Value); + JObject data = null; + string reason = "other";//other means breakpoint + ExecutionContext context = GetContext(sessionId); + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadBytes(11); //skip HEADER_LEN + ret_debugger_cmd_reader.ReadByte(); //suspend_policy + var number_of_events = ret_debugger_cmd_reader.ReadInt32(); //number of events -> should be always one var callFrames = new List(); - foreach (JObject frame in orig_callframes) - { - string function_name = frame["functionName"]?.Value(); - string url = frame["url"]?.Value(); - if ("mono_wasm_fire_bp" == function_name || "_mono_wasm_fire_bp" == function_name || - "_mono_wasm_fire_exception" == function_name) + var frames = new List(); + for (int i = 0 ; i < number_of_events; i++) { + var event_kind = ret_debugger_cmd_reader.ReadByte(); //event kind + var request_id = ret_debugger_cmd_reader.ReadInt32(); //request id + if ((EventKind)event_kind == EventKind.STEP) + await sdbHelper.ClearSingleStep(sessionId, request_id, token); + Breakpoint bp = context.BreakpointRequests.Values.SelectMany(v => v.Locations).FirstOrDefault(b => b.RemoteId == request_id); + switch ((EventKind)event_kind) { - if ("_mono_wasm_fire_exception" == function_name) - { - Result exception_obj_id = await SendMonoCommand(sessionId, MonoCommands.GetExceptionObject(), token); - JToken res_val = exception_obj_id.Value?["result"]?["value"]; - var exception_dotnet_obj_id = new DotnetObjectId("object", res_val?["exception_id"]?.Value()); - data = JObject.FromObject(new - { - type = "object", - subtype = "error", - className = res_val?["class_name"]?.Value(), - uncaught = res_val?["uncaught"]?.Value(), - description = res_val?["message"]?.Value() + "\n", - objectId = exception_dotnet_obj_id.ToString() - }); - reason = "exception"; - } - - var frames = new List(); - IEnumerable the_mono_frames = res.Value?["result"]?["value"]?["frames"]?.Values(); - - foreach (JObject mono_frame in the_mono_frames) + case EventKind.STEP: + case EventKind.BREAKPOINT: { - int frame_id = mono_frame["frame_id"].Value(); - int il_pos = mono_frame["il_pos"].Value(); - int method_token = mono_frame["method_token"].Value(); - string assembly_name = mono_frame["assembly_name"].Value(); - - // This can be different than `method.Name`, like in case of generic methods - string method_name = mono_frame["method_name"]?.Value(); - - DebugStore store = await LoadStore(sessionId, token); - AssemblyInfo asm = store.GetAssemblyByName(assembly_name); - if (asm == null) - { - Log("debug", $"Unable to find assembly: {assembly_name}"); - continue; - } + int thread_id = ret_debugger_cmd_reader.ReadInt32(); + int method_id = ret_debugger_cmd_reader.ReadInt32(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(thread_id); + command_params_writer.Write(0); + command_params_writer.Write(-1); + + ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, (int) CommandSet.THREAD, (int) CmdThread.GET_FRAME_INFO, command_params, token); + var frame_count = ret_debugger_cmd_reader.ReadInt32(); + for (int j = 0; j < frame_count; j++) { + var frame_id = ret_debugger_cmd_reader.ReadInt32(); + frame_id = j+1; + method_id = ret_debugger_cmd_reader.ReadInt32(); + var il_pos = ret_debugger_cmd_reader.ReadInt32(); + var flags = ret_debugger_cmd_reader.ReadByte(); + var method_token = await sdbHelper.GetMethodToken(sessionId, method_id, token); + var assembly_id = await sdbHelper.GetAssemblyIdFromMethod(sessionId, method_id, token); + var assembly_name = await sdbHelper.GetAssemblyName(sessionId, assembly_id, token); + var method_name = await sdbHelper.GetMethodName(sessionId, method_id, token); + DebugStore store = await LoadStore(sessionId, token); + AssemblyInfo asm = store.GetAssemblyByName(assembly_name); + if (asm == null) + { + Log("debug", $"Unable to find assembly: {assembly_name}"); + continue; + } - MethodInfo method = asm.GetMethodByToken(method_token); + MethodInfo method = asm.GetMethodByToken(method_token); - if (method == null && !asm.HasSymbols) - { - try + if (method == null && !asm.HasSymbols) { - method = await LoadSymbolsOnDemand(asm, method_token, sessionId, token); + try + { + method = await LoadSymbolsOnDemand(asm, method_token, sessionId, token); + } + catch (Exception e) + { + Log("info", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name} exception: {e}"); + continue; + } } - catch (Exception e) + + if (method == null) { - Log("info", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name} exception: {e}"); + Log("debug", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}"); continue; } - } - if (method == null) - { - Log("debug", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}"); - continue; - } + SourceLocation location = method?.GetLocationByIl(il_pos); - SourceLocation location = method?.GetLocationByIl(il_pos); - - // When hitting a breakpoint on the "IncrementCount" method in the standard - // Blazor project template, one of the stack frames is inside mscorlib.dll - // and we get location==null for it. It will trigger a NullReferenceException - // if we don't skip over that stack frame. - if (location == null) - { - continue; - } + // When hitting a breakpoint on the "IncrementCount" method in the standard + // Blazor project template, one of the stack frames is inside mscorlib.dll + // and we get location==null for it. It will trigger a NullReferenceException + // if we don't skip over that stack frame. + if (location == null) + { + continue; + } - Log("debug", $"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}"); - Log("debug", $"\tmethod {method_name} location: {location}"); - frames.Add(new Frame(method, location, frame_id)); + Log("debug", $"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}"); + Log("debug", $"\tmethod {method_name} location: {location}"); + frames.Add(new Frame(method, location, frame_id)); - callFrames.Add(new - { - functionName = method_name, - callFrameId = $"dotnet:scope:{frame_id}", - functionLocation = method.StartLocation.AsLocation(), + callFrames.Add(new + { + functionName = method_name, + callFrameId = $"dotnet:scope:{frame_id}", + functionLocation = method.StartLocation.AsLocation(), - location = location.AsLocation(), + location = location.AsLocation(), - url = store.ToUrl(location), + url = store.ToUrl(location), - scopeChain = new[] - { - new + scopeChain = new[] { - type = "local", - @object = new - { - @type = "object", - className = "Object", - description = "Object", - objectId = $"dotnet:scope:{frame_id}", - }, - name = method_name, - startLocation = method.StartLocation.AsLocation(), - endLocation = method.EndLocation.AsLocation(), + new + { + type = "local", + @object = new + { + @type = "object", + className = "Object", + description = "Object", + objectId = $"dotnet:scope:{frame_id}", + }, + name = method_name, + startLocation = method.StartLocation.AsLocation(), + endLocation = method.EndLocation.AsLocation(), + } } - } - }); - - context.CallStack = frames; + }); + context.CallStack = frames; + context.ThreadId = thread_id; + } + string[] bp_list = new string[bp == null ? 0 : 1]; + if (bp != null) + bp_list[0] = bp.StackId; + var o = JObject.FromObject(new + { + callFrames, + reason, + data, + hitBreakpoints = bp_list, + }); + Console.WriteLine(o); + SendEvent(sessionId, "Debugger.paused", o, token); + break; } - if (!await EvaluateCondition(sessionId, context, the_mono_frames?.First(), bp, token)) - { - await SendCommand(sessionId, "Debugger.resume", new JObject(), token); - return true; - } - } - else if (!(function_name.StartsWith("wasm-function", StringComparison.Ordinal) || - url.StartsWith("wasm://wasm/", StringComparison.Ordinal))) - { - callFrames.Add(frame); } } - string[] bp_list = new string[bp == null ? 0 : 1]; - if (bp != null) - bp_list[0] = bp.StackId; - var o = JObject.FromObject(new - { - callFrames, - reason, - data, - hitBreakpoints = bp_list, - }); - - SendEvent(sessionId, "Debugger.paused", o, token); return true; } @@ -1060,12 +813,8 @@ private async Task Step(MessageId msg_id, StepKind kind, CancellationToken if (context.CallStack.Count <= 1 && kind == StepKind.Out) return false; - Result res = await SendMonoCommand(msg_id, MonoCommands.StartSingleStepping(kind), token); - - int? ret_code = res.Value?["result"]?["value"]?.Value(); - - if (ret_code.HasValue && ret_code.Value == 0) - { + var step = await sdbHelper.Step(msg_id, context.ThreadId, kind, token); + if (step == false) { context.ClearState(); await SendCommand(msg_id, "Debugger.stepOut", new JObject(), token); return false; @@ -1219,16 +968,6 @@ internal async Task GetScopeProperties(SessionId msg_id, int scope_id, C } } - private async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) - { - Result res = await SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); - if (res.IsErr) - return null; - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); - var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); - return ret_debugger_cmd_reader; - } private async Task SetMonoBreakpoint(SessionId sessionId, string reqId, SourceLocation location, string condition, CancellationToken token) { var bp = new Breakpoint(reqId, location, condition, BreakpointState.Pending); @@ -1236,30 +975,9 @@ private async Task SetMonoBreakpoint(SessionId sessionId, string req int method_token = bp.Location.CliLocation.Method.Token; int il_offset = bp.Location.CliLocation.Offset; - var command_params = new MemoryStream(); - var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.WriteString(asm_name); - - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.GET_ASSEMBLY_BY_NAME, command_params, token); - var assembly_id = ret_debugger_cmd_reader.ReadInt32(); - - command_params = new MemoryStream(); - command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write(assembly_id); - command_params_writer.Write(method_token | (int)TokenType.mdtMethodDef); - ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_METHOD_FROM_TOKEN, command_params, token); - var method_id = ret_debugger_cmd_reader.ReadInt32(); - - command_params = new MemoryStream(); - command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.BREAKPOINT); - command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_ALL); - command_params_writer.Write((byte)1); - command_params_writer.Write((byte)ModifierKind.LOCATION_ONLY); - command_params_writer.Write(method_id); - command_params_writer.WriteLong(il_offset); - ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); - var breakpoint_id = ret_debugger_cmd_reader.ReadInt32(); + var assembly_id = await sdbHelper.GetAssemblyId(sessionId, asm_name, token); + var method_id = await sdbHelper.GetMethodIdByToken(sessionId, assembly_id, method_token, token); + var breakpoint_id = await sdbHelper.SetBreakpoint(sessionId, method_id, il_offset, token); if (breakpoint_id > 0) { @@ -1326,7 +1044,7 @@ private async Task RuntimeReady(SessionId sessionId, CancellationTok return await context.ready.Task; var command_params = new MemoryStream(); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR_ALL_BREAKPOINTS, command_params, token); + var ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR_ALL_BREAKPOINTS, command_params, token); if (ret_debugger_cmd_reader == null) { Log("verbose", $"Failed to clear breakpoints"); @@ -1349,14 +1067,8 @@ private async Task RemoveBreakpoint(MessageId msg_id, JObject args, Cancellation foreach (Breakpoint bp in breakpointRequest.Locations) { - var command_params = new MemoryStream(); - var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.BREAKPOINT); - command_params_writer.Write((int) bp.RemoteId); - - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(msg_id, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR, command_params, token); - - if (ret_debugger_cmd_reader != null) + var breakpoint_removed = await sdbHelper.RemoveBreakpoint(msg_id, bp.RemoteId, token); + if (breakpoint_removed) { bp.RemoteId = -1; bp.State = BreakpointState.Disabled; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs new file mode 100644 index 0000000000000..ae99242614f62 --- /dev/null +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -0,0 +1,391 @@ +// 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.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Net.Http; + +namespace Microsoft.WebAssembly.Diagnostics +{ + internal enum TokenType + { + mdtModule = 0x00000000, // + mdtTypeRef = 0x01000000, // + mdtTypeDef = 0x02000000, // + mdtFieldDef = 0x04000000, // + mdtMethodDef = 0x06000000, // + mdtParamDef = 0x08000000, // + mdtInterfaceImpl = 0x09000000, // + mdtMemberRef = 0x0a000000, // + mdtCustomAttribute = 0x0c000000, // + mdtPermission = 0x0e000000, // + mdtSignature = 0x11000000, // + mdtEvent = 0x14000000, // + mdtProperty = 0x17000000, // + mdtModuleRef = 0x1a000000, // + mdtTypeSpec = 0x1b000000, // + mdtAssembly = 0x20000000, // + mdtAssemblyRef = 0x23000000, // + mdtFile = 0x26000000, // + mdtExportedType = 0x27000000, // + mdtManifestResource = 0x28000000, // + mdtGenericParam = 0x2a000000, // + mdtMethodSpec = 0x2b000000, // + mdtGenericParamConstraint = 0x2c000000, + + mdtString = 0x70000000, // + mdtName = 0x71000000, // + mdtBaseType = 0x72000000, // Leave this on the high end value. This does not correspond to metadata table + } + + internal enum CommandSet { + VM = 1, + OBJECT_REF = 9, + STRING_REF = 10, + THREAD = 11, + ARRAY_REF = 13, + EVENT_REQUEST = 15, + STACK_FRAME = 16, + APPDOMAIN = 20, + ASSEMBLY = 21, + METHOD = 22, + TYPE = 23, + MODULE = 24, + FIELD = 25, + EVENT = 64, + POINTER = 65 + } + + internal enum EventKind { + VM_START = 0, + VM_DEATH = 1, + THREAD_START = 2, + THREAD_DEATH = 3, + APPDOMAIN_CREATE = 4, // Not in JDI + APPDOMAIN_UNLOAD = 5, // Not in JDI + METHOD_ENTRY = 6, + METHOD_EXIT = 7, + ASSEMBLY_LOAD = 8, + ASSEMBLY_UNLOAD = 9, + BREAKPOINT = 10, + STEP = 11, + TYPE_LOAD = 12, + EXCEPTION = 13, + KEEPALIVE = 14, + USER_BREAK = 15, + USER_LOG = 16, + CRASH = 17 + } + + internal enum ModifierKind { + COUNT = 1, + THREAD_ONLY = 3, + LOCATION_ONLY = 7, + EXCEPTION_ONLY = 8, + STEP = 10, + ASSEMBLY_ONLY = 11, + SOURCE_FILE_ONLY = 12, + TYPE_NAME_ONLY = 13 + } + + + internal enum SuspendPolicy { + SUSPEND_POLICY_NONE = 0, + SUSPEND_POLICY_EVENT_THREAD = 1, + SUSPEND_POLICY_ALL = 2 + } + + internal enum CmdVM { + VERSION = 1, + ALL_THREADS = 2, + SUSPEND = 3, + RESUME = 4, + EXIT = 5, + DISPOSE = 6, + INVOKE_METHOD = 7, + SET_PROTOCOL_VERSION = 8, + ABORT_INVOKE = 9, + SET_KEEPALIVE = 10, + GET_TYPES_FOR_SOURCE_FILE = 11, + GET_TYPES = 12, + INVOKE_METHODS = 13, + START_BUFFERING = 14, + STOP_BUFFERING = 15, + VM_READ_MEMORY = 16, + VM_WRITE_MEMORY = 17, + GET_ASSEMBLY_BY_NAME = 18 + } + + internal enum CmdEvent { + COMPOSITE = 100 + } + + internal enum CmdThread { + GET_FRAME_INFO = 1, + GET_NAME = 2, + GET_STATE = 3, + GET_INFO = 4, + /* FIXME: Merge into GET_INFO when the major protocol version is increased */ + GET_ID = 5, + /* Ditto */ + GET_TID = 6, + SET_IP = 7, + GET_ELAPSED_TIME = 8 + } + + internal enum CmdEventRequest { + SET = 1, + CLEAR = 2, + CLEAR_ALL_BREAKPOINTS = 3 + } + + internal enum CmdAppDomain { + GET_ROOT_DOMAIN = 1, + GET_FRIENDLY_NAME = 2, + GET_ASSEMBLIES = 3, + GET_ENTRY_ASSEMBLY = 4, + CREATE_STRING = 5, + GET_CORLIB = 6, + CREATE_BOXED_VALUE = 7, + CREATE_BYTE_ARRAY = 8, + } + + internal enum CmdAssembly { + GET_LOCATION = 1, + GET_ENTRY_POINT = 2, + GET_MANIFEST_MODULE = 3, + GET_OBJECT = 4, + GET_TYPE = 5, + GET_NAME = 6, + GET_DOMAIN = 7, + GET_METADATA_BLOB = 8, + GET_IS_DYNAMIC = 9, + GET_PDB_BLOB = 10, + GET_TYPE_FROM_TOKEN = 11, + GET_METHOD_FROM_TOKEN = 12, + HAS_DEBUG_INFO = 13, + } + + internal enum CmdModule { + GET_INFO = 1, + APPLY_CHANGES = 2, + } + + internal enum CmdMethod { + GET_NAME = 1, + GET_DECLARING_TYPE = 2, + GET_DEBUG_INFO = 3, + GET_PARAM_INFO = 4, + GET_LOCALS_INFO = 5, + GET_INFO = 6, + GET_BODY = 7, + RESOLVE_TOKEN = 8, + GET_CATTRS = 9, + MAKE_GENERIC_METHOD = 10, + TOKEN = 11, + ASSEMBLY = 12 + } + + internal enum CmdType { + GET_INFO = 1, + GET_METHODS = 2, + GET_FIELDS = 3, + GET_VALUES = 4, + GET_OBJECT = 5, + GET_SOURCE_FILES = 6, + SET_VALUES = 7, + IS_ASSIGNABLE_FROM = 8, + GET_PROPERTIES = 9, + GET_CATTRS = 10, + GET_FIELD_CATTRS = 11, + GET_PROPERTY_CATTRS = 12, + /* FIXME: Merge into GET_SOURCE_FILES when the major protocol version is increased */ + GET_SOURCE_FILES_2 = 13, + /* FIXME: Merge into GET_VALUES when the major protocol version is increased */ + GET_VALUES_2 = 14, + CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15, + GET_INTERFACES = 16, + GET_INTERFACE_MAP = 17, + IS_INITIALIZED = 18, + CREATE_INSTANCE = 19, + GET_VALUE_SIZE = 20 + } + + internal enum CmdField { + GET_INFO = 1 + } + + internal class MonoBinaryWriter : BinaryWriter + { + public MonoBinaryWriter(Stream stream) : base(stream) {} + public void WriteString(string val) + { + Write(val.Length); + Write(val.ToCharArray()); + } + public void WriteLong(long val) + { + Write((int)((val >> 32) & 0xffffffff)); + Write((int)((val >> 0) & 0xffffffff)); + } + } + + + internal class MonoSDBHelper + { + private static int cmd_id; + private static int GetId() {return cmd_id++;} + private MonoProxy proxy; + + public MonoSDBHelper(MonoProxy proxy) + { + this.proxy = proxy; + } + + internal async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) + { + Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); + if (res.IsErr) + return null; + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); + return ret_debugger_cmd_reader; + } + + public async Task GetMethodToken(SessionId sessionId, int method_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(method_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.TOKEN, command_params, token); + return ret_debugger_cmd_reader.ReadInt32() & 0xffffff; //token + } + + public async Task GetMethodIdByToken(SessionId sessionId, int assembly_id, int method_token, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(assembly_id); + command_params_writer.Write(method_token | (int)TokenType.mdtMethodDef); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_METHOD_FROM_TOKEN, command_params, token); + return ret_debugger_cmd_reader.ReadInt32(); + } + + public async Task GetAssemblyIdFromMethod(SessionId sessionId, int method_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(method_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.ASSEMBLY, command_params, token); + return ret_debugger_cmd_reader.ReadInt32(); //assembly_id + } + + public async Task GetAssemblyId(SessionId sessionId, string asm_name, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.WriteString(asm_name); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.GET_ASSEMBLY_BY_NAME, command_params, token); + return ret_debugger_cmd_reader.ReadInt32(); + } + + public async Task GetAssemblyName(SessionId sessionId, int assembly_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(assembly_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_LOCATION, command_params, token); + var stringSize = ret_debugger_cmd_reader.ReadInt32(); + char[] memoryData = new char[stringSize]; + ret_debugger_cmd_reader.Read(memoryData, 0, stringSize); + return new string(memoryData); + } + + public async Task GetMethodName(SessionId sessionId, int method_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(method_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME, command_params, token); + var stringSize = ret_debugger_cmd_reader.ReadInt32(); + char[] memoryData = new char[stringSize]; + ret_debugger_cmd_reader.Read(memoryData, 0, stringSize); + return new string(memoryData); + } + + public async Task SetBreakpoint(SessionId sessionId, int method_id, long il_offset, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((byte)EventKind.BREAKPOINT); + command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_NONE); + command_params_writer.Write((byte)1); + command_params_writer.Write((byte)ModifierKind.LOCATION_ONLY); + command_params_writer.Write(method_id); + command_params_writer.WriteLong(il_offset); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + return ret_debugger_cmd_reader.ReadInt32(); + } + + public async Task RemoveBreakpoint(SessionId sessionId, int breakpoint_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((byte)EventKind.BREAKPOINT); + command_params_writer.Write((int) breakpoint_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR, command_params, token); + + if (ret_debugger_cmd_reader != null) + return true; + return false; + } + + public async Task Step(SessionId sessionId, int thread_id, StepKind kind, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((byte)EventKind.STEP); + command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_NONE); + command_params_writer.Write((byte)1); + command_params_writer.Write((byte)ModifierKind.STEP); + command_params_writer.Write(thread_id); + command_params_writer.Write((int)0); + command_params_writer.Write((int)kind); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + if (ret_debugger_cmd_reader != null) + return true; + return false; + } + + public async Task ClearSingleStep(SessionId sessionId, int req_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((byte)EventKind.STEP); + command_params_writer.Write((int) req_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR, command_params, token); + + if (ret_debugger_cmd_reader != null) + return true; + return false; + } + + } +} \ No newline at end of file diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs index eed238c6f5902..f9914dbd10185 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs @@ -42,7 +42,7 @@ await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", } [Fact] - public async Task InspectLocalsDuringStepping() + public async Task InspectLocalsDuringStepping2() { var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs"; await SetBreakpoint(debugger_test_loc, 10, 8); diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 0cd7e3de0f649..6ad578369b35e 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -531,24 +531,6 @@ var MonoSupportLib = { return exception_obj ; }, - mono_wasm_get_call_stack: function() { - if (!this.mono_wasm_current_bp_id) - this.mono_wasm_current_bp_id = Module.cwrap ("mono_wasm_current_bp_id", 'number'); - if (!this.mono_wasm_enum_frames) - this.mono_wasm_enum_frames = Module.cwrap ("mono_wasm_enum_frames", null); - - var bp_id = this.mono_wasm_current_bp_id (); - this.active_frames = []; - this.mono_wasm_enum_frames (); - - var the_frames = this.active_frames; - this.active_frames = []; - return { - "breakpoint_id": bp_id, - "frames": the_frames, - }; - }, - _fixup_name_value_objects: function (var_list) { let out_list = []; @@ -833,7 +815,6 @@ var MonoSupportLib = { }, mono_wasm_add_dbg_command_received: function(id, buffer, buffer_len) { - console.log(`mono_wasm_add_dbg_command_received`); const assembly_data = new Uint8Array(Module.HEAPU8.buffer, buffer, buffer_len); const base64String = MONO._base64Converter.toBase64StringImpl(assembly_data); const buffer_obj = { @@ -845,21 +826,26 @@ var MonoSupportLib = { mono_wasm_send_dbg_command: function (id, command_set, command, command_parameters) { - console.log(`mono_wasm_send_dbg_command ${id} - ${command_set} - ${command} - ${command_parameters.length}`); - const dataHeap = new Uint8Array (Module.HEAPU8.buffer, command_parameters, command_parameters.length); dataHeap.set (new Uint8Array (this._base64_to_uint8 (command_parameters))); let res_ok = this._c_fn_table.mono_wasm_send_dbg_command_wrapper (id, command_set, command, dataHeap.byteOffset, command_parameters.length); let res = MONO.commands_received; + MONO.commands_received = null; if (res_ok) { return { res_ok, res }; } + }, + + mono_wasm_get_dbg_command_info: function () + { + let res = MONO.commands_received; MONO.commands_received = null; + return { res }; }, - // @var_list: [ { index: , name: }, .. ] + // @var_list: [ { index: , name: }, .. ] mono_wasm_get_variables: function(scope, var_list) { const numBytes = var_list.length * Int32Array.BYTES_PER_ELEMENT; const ptr = Module._malloc(numBytes); @@ -1371,16 +1357,6 @@ var MonoSupportLib = { this._clear_per_step_state (); }, - mono_wasm_start_single_stepping: function (kind) { - console.debug (">> mono_wasm_start_single_stepping " + kind); - if (!this.mono_wasm_setup_single_step) - this.mono_wasm_setup_single_step = Module.cwrap ("mono_wasm_setup_single_step", 'number', [ 'number']); - - this._clear_per_step_state (); - - return this.mono_wasm_setup_single_step (kind); - }, - mono_wasm_set_pause_on_exceptions: function (state) { if (!this.mono_wasm_pause_on_exceptions) this.mono_wasm_pause_on_exceptions = Module.cwrap ("mono_wasm_pause_on_exceptions", 'number', [ 'number']); @@ -2494,6 +2470,11 @@ var MonoSupportLib = { debugger; }, + mono_wasm_fire_debugger_agent_message: function () { + // eslint-disable-next-line no-debugger + debugger; + }, + mono_wasm_asm_loaded: function (assembly_name, assembly_ptr, assembly_len, pdb_ptr, pdb_len) { // Only trigger this codepath for assemblies loaded after app is ready if (MONO.mono_wasm_runtime_is_ready !== true) From f97cf27f4eab553a441e4392c09f944ab2c8b5af Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 6 May 2021 16:33:03 -0300 Subject: [PATCH 04/48] Remove more code. --- src/mono/mono/mini/debugger-agent.c | 63 +++++++++------ src/mono/mono/mini/debugger-agent.h | 3 + src/mono/mono/mini/debugger-engine.h | 6 ++ src/mono/mono/mini/mini-wasm-debugger.c | 77 ++----------------- .../BrowserDebugProxy/MonoSDBHelper.cs | 2 +- 5 files changed, 54 insertions(+), 97 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index f1a68b18b4e58..e4567beb24f8a 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -301,21 +301,12 @@ typedef struct { #define CHECK_ICORDBG(status) \ (protocol_version_set && using_icordbg == status) -#ifndef TARGET_WASM -#define GET_TLS_DATA(thread) \ - mono_loader_lock(); \ - tls = (DebuggerTlsData*)mono_g_hash_table_lookup(thread_to_tls, thread); \ - mono_loader_unlock(); -#else -#define GET_TLS_DATA(thread) \ - DebuggerTlsData local_data;\ - memset(&local_data, 0, sizeof(DebuggerTlsData)); \ - tls = &local_data; -#endif /* * Globals */ - +#ifdef TARGET_WASM +static DebuggerTlsData debugger_wasm_thread; +#endif static AgentConfig agent_config; /* @@ -398,6 +389,18 @@ static gint32 suspend_count; /* Whenever to buffer reply messages and send them together */ static gboolean buffer_replies; + +#ifndef TARGET_WASM +#define GET_TLS_DATA(thread) \ + mono_loader_lock(); \ + tls = (DebuggerTlsData*)mono_g_hash_table_lookup(thread_to_tls, thread); \ + mono_loader_unlock(); +#else +#define GET_TLS_DATA(thread) \ + tls = &debugger_wasm_thread; +#endif + + #define dbg_lock mono_de_lock #define dbg_unlock mono_de_unlock @@ -485,8 +488,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 int ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args); -static void ss_args_destroy (SingleStepArgs *ss_args); static int handle_multiple_ss_requests (void); static GENERATE_TRY_GET_CLASS_WITH_CACHE (fixed_buffer, "System.Runtime.CompilerServices", "FixedBufferAttribute") @@ -720,8 +721,8 @@ debugger_agent_init (void) cbs.get_notify_debugger_of_wait_completion_method = get_notify_debugger_of_wait_completion_method; cbs.create_breakpoint_events = mono_dbg_create_breakpoint_events; cbs.process_breakpoint_events = mono_dbg_process_breakpoint_events; - cbs.ss_create_init_args = ss_create_init_args; - cbs.ss_args_destroy = ss_args_destroy; + cbs.ss_create_init_args = mono_ss_create_init_args; + cbs.ss_args_destroy = mono_ss_args_destroy; cbs.handle_multiple_ss_requests = handle_multiple_ss_requests; mono_de_init (&cbs); @@ -1601,6 +1602,7 @@ void mono_init_debugger_agent_for_wasm (int log_level_parm) return; vm_start_event_sent = TRUE; transport = &transports [0]; + memset(&debugger_wasm_thread, 0, sizeof(DebuggerTlsData)); } @@ -2189,6 +2191,14 @@ save_thread_context (MonoContext *ctx) mono_thread_state_init_from_current (&tls->context); } +#ifdef TARGET_WASM +void +mono_wasm_save_thread_context (void) +{ + mono_thread_state_init_from_current (&debugger_wasm_thread.context); +} +#endif + static MonoCoopMutex suspend_mutex; /* Cond variable used to wait for suspend_count becoming 0 */ @@ -3028,7 +3038,9 @@ compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls, gboolean f } else if (tls->context.valid) { mono_walk_stack_with_state (process_frame, &tls->context, opts, &user_data); } else { - mono_walk_stack_with_ctx (process_frame, NULL, opts, &user_data); + // FIXME: + tls->frame_count = 0; + return; } new_frame_count = g_slist_length (user_data.frames); @@ -4471,8 +4483,8 @@ debugger_agent_breakpoint_from_context (MonoContext *ctx) if (MONO_CONTEXT_GET_IP (ctx) == orig_ip - 1) MONO_CONTEXT_SET_IP (ctx, orig_ip); } -static void -ss_args_destroy (SingleStepArgs *ss_args) +void +mono_ss_args_destroy (SingleStepArgs *ss_args) { if (ss_args->frames) free_frames ((StackFrame**)ss_args->frames, ss_args->nframes); @@ -4497,8 +4509,8 @@ ensure_runtime_is_suspended (void) return ERR_NONE; } -static int -ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) +int +mono_ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) { MonoSeqPointInfo *info = NULL; gboolean found_sp; @@ -4508,12 +4520,13 @@ ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) gboolean set_ip = FALSE; StackFrame **frames = NULL; int nframes = 0; - - mono_loader_lock (); - DebuggerTlsData *tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, ss_req->thread); - mono_loader_unlock (); + + DebuggerTlsData *tls; + GET_TLS_DATA(ss_req->thread); + g_assert (tls); if (!tls->context.valid) { + printf("Received a single step request on a thread with no managed frames.\n"); PRINT_DEBUG_MSG (1, "Received a single step request on a thread with no managed frames.\n"); return ERR_INVALID_ARGUMENT; } diff --git a/src/mono/mono/mini/debugger-agent.h b/src/mono/mono/mini/debugger-agent.h index abefdee2b5529..14c983ffb66ed 100644 --- a/src/mono/mono/mini/debugger-agent.h +++ b/src/mono/mono/mini/debugger-agent.h @@ -72,4 +72,7 @@ mono_dbg_create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJ void mono_dbg_process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset); +void +mono_wasm_save_thread_context (void); + #endif diff --git a/src/mono/mono/mini/debugger-engine.h b/src/mono/mono/mini/debugger-engine.h index 27f59f0aa3384..0a1a1afa116b4 100644 --- a/src/mono/mono/mini/debugger-engine.h +++ b/src/mono/mono/mini/debugger-engine.h @@ -544,3 +544,9 @@ void win32_debugger_log(FILE *stream, const gchar *format, ...); #define PRINT_ERROR_MSG(...) g_printerr (__VA_ARGS__) #define PRINT_MSG(...) g_print (__VA_ARGS__) #endif + +int +mono_ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args); + +void +mono_ss_args_destroy (SingleStepArgs *ss_args); \ No newline at end of file diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 184f33e444daf..d6cac5f256cd0 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -80,8 +80,6 @@ static gboolean debugger_enabled; static gboolean has_pending_lazy_loaded_assemblies; -static int event_request_id; -static int current_bp_id; static GHashTable *objrefs; static GHashTable *obj_to_objref; static int objref_id = 0; @@ -328,36 +326,6 @@ typedef struct { gboolean is_ss; //do I need this? } BpEvents; -static void* -create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind) -{ - PRINT_DEBUG_MSG (1, "ss_reqs %d bp_reqs %d\n", ss_reqs->len, bp_reqs->len); - if ((ss_reqs && ss_reqs->len) || (bp_reqs && bp_reqs->len)) { - EventRequest *req = NULL; - if ((bp_reqs && bp_reqs->len)) - req = (EventRequest *)g_ptr_array_index (bp_reqs, 0); - if ((ss_reqs && ss_reqs->len)) - req = (EventRequest *)g_ptr_array_index (ss_reqs, 0); - current_bp_id = req->id; - BpEvents *evts = g_new0 (BpEvents, 1); //just a non-null value to make sure we can raise it on process_breakpoint_events - evts->is_ss = (ss_reqs && ss_reqs->len); - return evts; - } - return NULL; -} - -static void -process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offsets) -{ - BpEvents *evts = (BpEvents*)_evts; - if (evts) { - if (evts->is_ss) - mono_de_cancel_all_ss (); - mono_wasm_fire_bp (); - g_free (evts); - } -} - static void no_seq_points_found (MonoMethod *method, int offset) { @@ -369,41 +337,6 @@ no_seq_points_found (MonoMethod *method, int offset) #define DBG_NOT_SUSPENDED 1 -static int -ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *ss_args) -{ - PRINT_DEBUG_MSG (1, "ss_create_init_args\n"); - int dummy = 0; - ss_req->start_sp = ss_req->last_sp = &dummy; - compute_frames (); - memset (ss_args, 0, sizeof (*ss_args)); - - // This shouldn't happen - maybe should assert here ? - if (frames->len == 0) { - PRINT_DEBUG_MSG (1, "SINGLE STEPPING FOUND NO FRAMES"); - return DBG_NOT_SUSPENDED; - } - - DbgEngineStackFrame *frame = (DbgEngineStackFrame*)g_ptr_array_index (frames, 0); - ss_req->start_method = ss_args->method = frame->method; - gboolean found_sp = mono_find_prev_seq_point_for_native_offset (frame->method, frame->native_offset, &ss_args->info, &ss_args->sp); - if (!found_sp) - no_seq_points_found (frame->method, frame->native_offset); - g_assert (found_sp); - - ss_args->frames = (DbgEngineStackFrame**)frames->pdata; - ss_args->nframes = frames->len; - //XXX do sp - - return DE_ERR_NONE; -} - -static void -ss_args_destroy (SingleStepArgs *ss_args) -{ - //nothing to do -} - static int handle_multiple_ss_requests (void) { mono_de_cancel_all_ss (); @@ -430,14 +363,14 @@ mono_wasm_debugger_init (void) .get_notify_debugger_of_wait_completion_method = get_notify_debugger_of_wait_completion_method, .create_breakpoint_events = mono_dbg_create_breakpoint_events, .process_breakpoint_events = mono_dbg_process_breakpoint_events, - .ss_create_init_args = ss_create_init_args, - .ss_args_destroy = ss_args_destroy, + .ss_create_init_args = mono_ss_create_init_args, + .ss_args_destroy = mono_ss_args_destroy, .handle_multiple_ss_requests = handle_multiple_ss_requests, }; mono_debug_init (MONO_DEBUG_FORMAT_MONO); mono_de_init (&cbs); - mono_de_set_log_level (10, stdout); + mono_de_set_log_level (log_level, stdout); mini_debug_options.gen_sdb_seq_points = TRUE; mini_debug_options.mdb_optimizations = TRUE; @@ -462,7 +395,7 @@ mono_wasm_debugger_init (void) trans.send = receive_debugger_agent_message; mono_debugger_agent_register_transport (&trans); - mono_init_debugger_agent_for_wasm (10); + mono_init_debugger_agent_for_wasm (log_level); } MONO_API void @@ -543,12 +476,14 @@ handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch void mono_wasm_single_step_hit (void) { + mono_wasm_save_thread_context(); mono_de_process_single_step (NULL, FALSE); } void mono_wasm_breakpoint_hit (void) { + mono_wasm_save_thread_context(); mono_de_process_breakpoint (NULL, FALSE); // mono_wasm_fire_bp (); } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index ae99242614f62..52bf4de956e04 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -388,4 +388,4 @@ public async Task ClearSingleStep(SessionId sessionId, int req_id, Cancell } } -} \ No newline at end of file +} From 0242f6a1c1f0df4e13d00a6f142ac8e2237bb244 Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 6 May 2021 20:55:56 -0300 Subject: [PATCH 05/48] Get frame values using debugger-agent. --- src/mono/mono/mini/debugger-agent.c | 7 +- .../debugger/BrowserDebugProxy/DebugStore.cs | 2 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 29 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 278 ++++++++++++++++++ 4 files changed, 294 insertions(+), 22 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index e4567beb24f8a..623c5e1769bc9 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -2195,6 +2195,7 @@ save_thread_context (MonoContext *ctx) void mono_wasm_save_thread_context (void) { + debugger_wasm_thread.really_suspended = TRUE; mono_thread_state_init_from_current (&debugger_wasm_thread.context); } #endif @@ -9066,9 +9067,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) id = decode_id (p, &p, end); - mono_loader_lock (); - tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread); - mono_loader_unlock (); + GET_TLS_DATA(thread); g_assert (tls); for (i = 0; i < tls->frame_count; ++i) { @@ -9079,7 +9078,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) return ERR_INVALID_FRAMEID; /* The thread is still running native code, can't get frame variables info */ - if (!tls->really_suspended && !tls->async_state.valid) + if (!tls->really_suspended && !tls->async_state.valid) return ERR_NOT_SUSPENDED; frame_idx = i; frame = tls->frames [frame_idx]; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 1f31e044653ab..62013cd935d96 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -325,7 +325,7 @@ internal class MethodInfo public SourceLocation EndLocation { get; } public AssemblyInfo Assembly { get; } public int Token { get; } - + public bool IsStatic() => (methodDef.Attributes & MethodAttributes.Static) != 0; public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type) { this.Assembly = assembly; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index e2d4b24197c7e..d09f1ffca359d 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -621,7 +621,6 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec var frame_count = ret_debugger_cmd_reader.ReadInt32(); for (int j = 0; j < frame_count; j++) { var frame_id = ret_debugger_cmd_reader.ReadInt32(); - frame_id = j+1; method_id = ret_debugger_cmd_reader.ReadInt32(); var il_pos = ret_debugger_cmd_reader.ReadInt32(); var flags = ret_debugger_cmd_reader.ReadByte(); @@ -715,7 +714,6 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec data, hitBreakpoints = bp_list, }); - Console.WriteLine(o); SendEvent(sessionId, "Debugger.paused", o, token); break; } @@ -942,24 +940,21 @@ internal async Task GetScopeProperties(SessionId msg_id, int scope_id, C return Result.Err(JObject.FromObject(new { message = $"Could not find scope with id #{scope_id}" })); VarInfo[] var_ids = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); - Result res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, var_ids), token); - //if we fail we just buble that to the IDE (and let it panic over it) - if (res.IsErr) - return res; - - JObject[] values = res.Value?["result"]?["value"]?.Values().ToArray(); - - if (values == null || values.Length == 0) - return Result.OkFromObject(new { result = Array.Empty() }); - - PerScopeCache frameCache = ctx.GetCacheForScope(scope_id); - foreach (JObject value in values) + var values = await sdbHelper.StackFrameGetValues(msg_id, scope.Method, ctx.ThreadId, scope_id, var_ids, token); + if (values != null) { - frameCache.Locals[value["name"]?.Value()] = value; - } + if (values == null || values.Count == 0) + return Result.OkFromObject(new { result = Array.Empty() }); - return Result.OkFromObject(new { result = values }); + PerScopeCache frameCache = ctx.GetCacheForScope(scope_id); + foreach (JObject value in values) + { + frameCache.Locals[value["name"]?.Value()] = value; + } + return Result.OkFromObject(new { result = values }); + } + return Result.OkFromObject(new { result = Array.Empty() }); } catch (Exception exception) { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 52bf4de956e04..2e173279cfa13 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -125,6 +125,16 @@ internal enum CmdVM { GET_ASSEMBLY_BY_NAME = 18 } + internal enum CmdFrame { + GET_VALUES = 1, + GET_THIS = 2, + SET_VALUES = 3, + GET_DOMAIN = 4, + SET_THIS = 5, + GET_ARGUMENT = 6, + GET_ARGUMENTS = 7 + } + internal enum CmdEvent { COMPOSITE = 100 } @@ -224,6 +234,72 @@ internal enum CmdField { GET_INFO = 1 } + internal enum CmdString { + GET_VALUE = 1, + GET_LENGTH = 2, + GET_CHARS = 3 + } + + internal enum CmdObject { + REF_GET_TYPE = 1, + REF_GET_VALUES = 2, + REF_IS_COLLECTED = 3, + REF_GET_ADDRESS = 4, + REF_GET_DOMAIN = 5, + REF_SET_VALUES = 6, + REF_GET_INFO = 7, + GET_VALUES_ICORDBG = 8 + } + + internal enum ElementType { + End = 0x00, + Void = 0x01, + Boolean = 0x02, + Char = 0x03, + I1 = 0x04, + U1 = 0x05, + I2 = 0x06, + U2 = 0x07, + I4 = 0x08, + U4 = 0x09, + I8 = 0x0a, + U8 = 0x0b, + R4 = 0x0c, + R8 = 0x0d, + String = 0x0e, + Ptr = 0x0f, + ByRef = 0x10, + ValueType = 0x11, + Class = 0x12, + Var = 0x13, + Array = 0x14, + GenericInst = 0x15, + TypedByRef = 0x16, + I = 0x18, + U = 0x19, + FnPtr = 0x1b, + Object = 0x1c, + SzArray = 0x1d, + MVar = 0x1e, + CModReqD = 0x1f, + CModOpt = 0x20, + Internal = 0x21, + Modifier = 0x40, + Sentinel = 0x41, + Pinned = 0x45, + + Type = 0x50, + Boxed = 0x51, + Enum = 0x55 + } + + internal enum ValueTypeId { + VALUE_TYPE_ID_NULL = 0xf0, + VALUE_TYPE_ID_TYPE = 0xf1, + VALUE_TYPE_ID_PARENT_VTYPE = 0xf2, + VALUE_TYPE_ID_FIXED_ARRAY = 0xf3 + } + internal class MonoBinaryWriter : BinaryWriter { public MonoBinaryWriter(Stream stream) : base(stream) {} @@ -387,5 +463,207 @@ public async Task ClearSingleStep(SessionId sessionId, int req_id, Cancell return false; } + public async Task GetTypeName(SessionId sessionId, int type_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(type_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_INFO, command_params, token); + + var namespaceLen = ret_debugger_cmd_reader.ReadInt32(); + char[] namespaceValue = new char[namespaceLen]; + ret_debugger_cmd_reader.Read(namespaceValue, 0, namespaceLen); + + var classLen = ret_debugger_cmd_reader.ReadInt32(); + char[] classValue = new char[classLen]; + ret_debugger_cmd_reader.Read(classValue, 0, classLen); + + var classFullNameLen = ret_debugger_cmd_reader.ReadInt32(); + char[] classFullName = new char[classFullNameLen]; + ret_debugger_cmd_reader.Read(classFullName, 0, classFullNameLen); + + string className = new string(classFullName); + className = className.Replace("+", "."); + return className; + } + + public async Task GetStringValue(SessionId sessionId, int string_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(string_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STRING_REF, (int) CmdString.GET_VALUE, command_params, token); + var stringSize = ret_debugger_cmd_reader.ReadInt32(); + char[] memoryData = new char[stringSize]; + ret_debugger_cmd_reader.Read(memoryData, 0, stringSize); + return new string(memoryData); + } + + public async Task GetClassNameFromObject(SessionId sessionId, int object_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(object_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_GET_TYPE, command_params, token); + var type_id = ret_debugger_cmd_reader.ReadInt32(); + + return await GetTypeName(sessionId, type_id, token); + } + + public async Task CreateJObjectForVariableValue(SessionId sessionId, BinaryReader ret_debugger_cmd_reader, string name, CancellationToken token) + { + ElementType etype = (ElementType)ret_debugger_cmd_reader.ReadByte(); + switch (etype) { + case ElementType.Void: + return new JObject{{"Type", "void"}}; + case ElementType.Boolean: + { + var value = ret_debugger_cmd_reader.ReadInt32(); + return JObject.FromObject(new { + value = new + { + type = "boolean", + value = value == 0 ? false : true, + description = value == 0 ? "false" : "true" + }, + writable = true, + name + }); + } + case ElementType.I1: + case ElementType.U1: + case ElementType.I2: + case ElementType.U2: + case ElementType.I4: + case ElementType.U4: + { + var value = ret_debugger_cmd_reader.ReadInt32(); + return JObject.FromObject(new { + value = new + { + type = "number", + value, + description = value.ToString() + }, + writable = true, + name + }); + } + case ElementType.Char: + { + var value = ret_debugger_cmd_reader.ReadInt32(); + return JObject.FromObject(new { + value = new + { + type = "char", + value, + description = value.ToString() + }, + writable = true, + name + }); + } + case ElementType.I8: + return new JObject{{"Type", "number"}}; + case ElementType.U8: + return new JObject{{"Type", "number"}}; + case ElementType.R4: + return new JObject{{"Type", "void"}}; + case ElementType.R8: + return new JObject{{"Type", "void"}}; + case ElementType.I: + case ElementType.U: + // FIXME: The client and the debuggee might have different word sizes + return new JObject{{"Type", "void"}}; + case ElementType.Ptr: + return new JObject{{"Type", "void"}}; + case ElementType.String: + { + var string_id = ret_debugger_cmd_reader.ReadInt32(); + var value = await GetStringValue(sessionId, string_id, token); + return JObject.FromObject(new { + value = new + { + type = "string", + value, + description = value.ToString() + }, + writable = false, + name + }); + } + case ElementType.SzArray: + case ElementType.Array: + return new JObject{{"Type", "void"}}; + case ElementType.Class: + case ElementType.Object: + { + var objectId = ret_debugger_cmd_reader.ReadInt32(); + var value = await GetClassNameFromObject(sessionId, objectId, token); + return JObject.FromObject(new { + value = new + { + type = "object", + objectId = "dotnet:object:" + objectId, + description = value.ToString(), + className = value.ToString(), + }, + name + }); + } + case ElementType.ValueType: + return new JObject{{"Type", "void"}}; + case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL: + { + return JObject.FromObject(new { + value = new + { + type = "object", + subtype = "null", + className = "string" //TODO get classname of null + }, + name + }); + } + case (ElementType)ValueTypeId.VALUE_TYPE_ID_TYPE: + return new JObject{{"Type", "void"}}; + case (ElementType)ValueTypeId.VALUE_TYPE_ID_PARENT_VTYPE: + return new JObject{{"Type", "void"}}; + case (ElementType)ValueTypeId.VALUE_TYPE_ID_FIXED_ARRAY: + return new JObject{{"Type", "void"}}; + } + return null; + } + public async Task StackFrameGetValues(SessionId sessionId, MethodInfo method, int thread_id, int frame_id, VarInfo[] var_ids, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(thread_id); + command_params_writer.Write(frame_id); + command_params_writer.Write(var_ids.Length); + foreach (var var in var_ids) + { + command_params_writer.Write(var.Index); + } + JArray array = new JArray(); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_VALUES, command_params, token); + foreach (var var in var_ids) + { + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, var.Name, token); + array.Add(var_json); + } + if (!method.IsStatic()) + { + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "this", token); + var_json.Add("fieldOffset", -1); + array.Add(var_json); + } + return array; + + } } } From adae934f3a1c0d13ddadcc7f16947b9049dad36a Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 11 May 2021 00:20:53 -0300 Subject: [PATCH 06/48] Working valuetypes and call function on valuetypes. make -C src/mono/wasm/ run-debugger-tests TEST_FILTER=DebuggerTests.SteppingTests.InspectValueTypeMethodArgsWhileStepping is working without use_cfo. --- src/mono/mono/mini/debugger-agent.c | 51 +-- src/mono/mono/mini/debugger-agent.h | 28 ++ src/mono/mono/mini/mini-wasm-debugger.c | 29 +- .../BrowserDebugProxy/DevToolsHelper.cs | 11 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 25 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 327 +++++++++++++++++- src/mono/wasm/runtime/library_mono.js | 33 +- 7 files changed, 434 insertions(+), 70 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 623c5e1769bc9..78393b3e4eb69 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -144,28 +144,6 @@ typedef struct { gboolean using_icordbg; } AgentConfig; -typedef struct _InvokeData InvokeData; - -struct _InvokeData -{ - int id; - int flags; - guint8 *p; - guint8 *endp; - /* This is the context which needs to be restored after the invoke */ - MonoContext ctx; - gboolean has_ctx; - /* - * If this is set, invoke this method with the arguments given by ARGS. - */ - MonoMethod *method; - gpointer *args; - guint32 suspend_count; - int nmethods; - - InvokeData *last_invoke; -}; - struct _DebuggerTlsData { MonoThreadUnwindState context; @@ -2001,7 +1979,6 @@ static int buffer_add_ptr_id (Buffer *buf, MonoDomain *domain, IdType type, gpointer val) { int id = get_id (domain, type, val); - buffer_add_id (buf, id); return id; } @@ -2198,6 +2175,12 @@ mono_wasm_save_thread_context (void) debugger_wasm_thread.really_suspended = TRUE; mono_thread_state_init_from_current (&debugger_wasm_thread.context); } + +DebuggerTlsData* +mono_wasm_get_tls (void) +{ + return &debugger_wasm_thread; +} #endif static MonoCoopMutex suspend_mutex; @@ -5263,9 +5246,7 @@ decode_vtype (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void ErrorCode err; is_enum = decode_byte (buf, &buf, limit); - /* Enums are sent as a normal vtype */ - if (is_enum) - return ERR_NOT_IMPLEMENTED; + klass = decode_typeid (buf, &buf, limit, &d, &err); if (err != ERR_NONE) return err; @@ -5454,7 +5435,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, handle_ref: default: if (MONO_TYPE_IS_REFERENCE (t)) { - if (type == MONO_TYPE_OBJECT || type == MONO_TYPE_STRING) { + if (type == MONO_TYPE_CLASS || type == MONO_TYPE_OBJECT || type == MONO_TYPE_STRING) { int objid = decode_objid (buf, &buf, limit); ErrorCode err; MonoObject *obj; @@ -5493,8 +5474,6 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, */ buf2 = buf; is_enum = decode_byte (buf, &buf, limit); - if (is_enum) - return ERR_NOT_IMPLEMENTED; klass = decode_typeid (buf, &buf, limit, &d, &err); if (err != ERR_NONE) return err; @@ -5954,8 +5933,8 @@ add_thread (gpointer key, gpointer value, gpointer user_data) } -static ErrorCode -do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp) +ErrorCode +mono_do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp) { ERROR_DECL (error); guint8 *end = invoke->endp; @@ -6022,7 +6001,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 return err; } } else { - if (!(m->flags & METHOD_ATTRIBUTE_STATIC && CHECK_PROTOCOL_VERSION (2, 59))) { //on icordbg I couldn't find an object when invoking a static method maybe I can change this later + if (!(m->flags & METHOD_ATTRIBUTE_STATIC) || (m->flags & METHOD_ATTRIBUTE_STATIC && !CHECK_PROTOCOL_VERSION (2, 59))) { //on icordbg I couldn't find an object when invoking a static method maybe I can change this later err = decode_value(m_class_get_byval_arg(m->klass), domain, this_buf, p, &p, end, FALSE); if (err != ERR_NONE) return err; @@ -6277,7 +6256,7 @@ invoke_method (void) if (err) { /* Fail the other invokes as well */ } else { - err = do_invoke_method (tls, &buf, invoke, p, &p); + err = mono_do_invoke_method (tls, &buf, invoke, p, &p); } if (tls->abort_requested) { @@ -7812,7 +7791,11 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint buffer_add_string (buf, m_class_get_name_space (klass)); buffer_add_string (buf, m_class_get_name (klass)); // FIXME: byref - name = mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME); + + MonoTypeNameFormat format = MONO_TYPE_NAME_FORMAT_FULL_NAME; + if (CHECK_PROTOCOL_VERSION(2, 61)) + format = (MonoTypeNameFormat) decode_int (p, &p, end); + name = mono_type_get_name_full (m_class_get_byval_arg (klass), format); buffer_add_string (buf, name); g_free (name); buffer_add_assemblyid (buf, domain, m_class_get_image (klass)->assembly); diff --git a/src/mono/mono/mini/debugger-agent.h b/src/mono/mono/mini/debugger-agent.h index 14c983ffb66ed..410d0a6162002 100644 --- a/src/mono/mono/mini/debugger-agent.h +++ b/src/mono/mono/mini/debugger-agent.h @@ -14,6 +14,28 @@ // 2. debug_log parameters changed from MonoString* to MonoStringHandle // 3. debug_log parameters changed from MonoStringHandle back to MonoString* +typedef struct _InvokeData InvokeData; + +struct _InvokeData +{ + int id; + int flags; + guint8 *p; + guint8 *endp; + /* This is the context which needs to be restored after the invoke */ + MonoContext ctx; + gboolean has_ctx; + /* + * If this is set, invoke this method with the arguments given by ARGS. + */ + MonoMethod *method; + gpointer *args; + guint32 suspend_count; + int nmethods; + + InvokeData *last_invoke; +}; + typedef struct { const char *name; void (*connect) (const char *address); @@ -75,4 +97,10 @@ mono_dbg_process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext void mono_wasm_save_thread_context (void); +DebuggerTlsData* +mono_wasm_get_tls (void); + +MdbgProtErrorCode +mono_do_invoke_method (DebuggerTlsData *tls, MdbgProtBuffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp); + #endif diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index d6cac5f256cd0..bad899d4044d7 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -52,6 +52,7 @@ EMSCRIPTEN_KEEPALIVE void mono_wasm_set_is_debugger_attached (gboolean is_attach EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_set_variable_on_frame (int scope, int index, const char* name, const char* value); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_set_value_on_object (int object_id, const char* name, const char* value); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size); +EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_method_debugger_agent (guint8* data, unsigned int size); //JS functions imported that we use extern void mono_wasm_add_frame (int il_offset, int method_token, int frame_id, const char *assembly_name, const char *method_name); @@ -788,6 +789,12 @@ describe_value(MonoType * type, gpointer addr, int gpflags) case MONO_TYPE_ARRAY: case MONO_TYPE_CLASS: { MonoObject *obj = *(MonoObject**)addr; + if (!obj) { + char *class_name = mono_type_full_name (type); + mono_wasm_add_func_var (class_name, NULL, 0); + g_free (class_name); + return TRUE; + } MonoClass *klass = type->data.klass; if (m_class_is_valuetype (mono_object_class (obj))) { @@ -1649,6 +1656,27 @@ mono_wasm_set_is_debugger_attached (gboolean is_attached) } } +EMSCRIPTEN_KEEPALIVE gboolean +mono_wasm_invoke_method_debugger_agent (guint8* data, unsigned int size) +{ + MdbgProtBuffer buf; + buffer_init (&buf, 128); + InvokeData invoke_data; + memset(&invoke_data, 0, sizeof(InvokeData)); + invoke_data.endp = data + size; + DebuggerTlsData* tls = mono_wasm_get_tls(); + + MdbgProtErrorCode error = mono_do_invoke_method(tls, &buf, &invoke_data, data, &data); + if (error != 0) + printf("error - mono_wasm_invoke_method_debugger_agent - %d\n", error); + EM_ASM ({ + MONO.mono_wasm_add_dbg_command_received ($0, $1, $2); + }, -1, buf.buf, buf.p-buf.buf); + + buffer_free (&buf); + return TRUE; +} + EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size) { @@ -1668,7 +1696,6 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, static gboolean receive_debugger_agent_message (void *data, int len) { - PRINT_DEBUG_MSG (1, "receive_debugger_agent_message - %d\n", len); EM_ASM ({ MONO.mono_wasm_add_dbg_command_received (-1, $0, $1); }, data, len); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index 9b230738c5fb6..f8a75c214c58c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -182,12 +182,6 @@ internal class MonoCommands public static MonoCommands GetDetails(DotnetObjectId objectId, JToken args = null) => new MonoCommands($"MONO.mono_wasm_get_details ('{objectId}', {(args ?? "{ }")})"); - public static MonoCommands GetScopeVariables(int scopeId, params VarInfo[] vars) - { - var var_ids = vars.Select(v => new { index = v.Index, name = v.Name }).ToArray(); - return new MonoCommands($"MONO.mono_wasm_get_variables({scopeId}, {JsonConvert.SerializeObject(var_ids)})"); - } - public static MonoCommands SetVariableValue(int scopeId, int index, string name, string newValue) { return new MonoCommands($"MONO.mono_wasm_set_variable_value({scopeId}, {index}, '{name}', '{newValue}')"); @@ -204,6 +198,11 @@ public static MonoCommands SendDebuggerAgentCommand(int id, int command_set, int return new MonoCommands($"MONO.mono_wasm_send_dbg_command ({id}, {command_set}, {command},'{command_parameters}')"); } + public static MonoCommands InvokeMethod(string command_parameters) + { + return new MonoCommands($"MONO.mono_wasm_invoke_method_debugger_agent ('{command_parameters}')"); + } + public static MonoCommands ReleaseObject(DotnetObjectId objectId) => new MonoCommands($"MONO.mono_wasm_release_object('{objectId}')"); public static MonoCommands CallFunctionOn(JToken args) => new MonoCommands($"MONO.mono_wasm_call_function_on ({args.ToString()})"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index d09f1ffca359d..a6d377414e76c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -478,11 +478,17 @@ protected override async Task AcceptCommand(MessageId id, string method, J return true; } - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type; + if (objectId.Scheme == "valuetype") + args["details"] = await sdbHelper.GetValueTypeProxy(id, int.Parse(objectId.Value), token); - if (res.IsOk && res_value_type == JTokenType.Object || res_value_type == JTokenType.Object) - res = Result.OkFromObject(new { result = res.Value["result"]["value"] }); + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadByte(); //number of objects returned. + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "seila", token); + /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ + res = Result.OkFromObject(new { result = obj["value"]}); SendResponse(id, res, token); return true; @@ -518,7 +524,12 @@ private async Task RuntimeGetProperties(MessageId id, DotnetObjectId obj { return await GetScopeProperties(id, int.Parse(objectId.Value), token); } - + if (objectId.Scheme == "valuetype") + { + var ret = await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), token); + Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); + return res2; + } Result res = await SendMonoCommand(id, MonoCommands.GetDetails(objectId, args), token); if (res.IsErr) return res; @@ -999,7 +1010,7 @@ private async Task OnSourceFileAdded(SessionId sessionId, SourceFile source, Exe } } - private async Task LoadStore(SessionId sessionId, CancellationToken token) + internal async Task LoadStore(SessionId sessionId, CancellationToken token) { ExecutionContext context = GetContext(sessionId); @@ -1045,6 +1056,8 @@ private async Task RuntimeReady(SessionId sessionId, CancellationTok Log("verbose", $"Failed to clear breakpoints"); } + await sdbHelper.SetProtocolVersion(sessionId, token); + DebugStore store = await LoadStore(sessionId, token); context.ready.SetResult(store); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 2e173279cfa13..2ee0663b0e083 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -13,6 +13,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Net.Http; +using System.Text.RegularExpressions; namespace Microsoft.WebAssembly.Diagnostics { @@ -222,7 +223,7 @@ internal enum CmdType { GET_SOURCE_FILES_2 = 13, /* FIXME: Merge into GET_VALUES when the major protocol version is increased */ GET_VALUES_2 = 14, - CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15, + GET_METHODS_BY_NAME_FLAGS = 15, GET_INTERFACES = 16, GET_INTERFACE_MAP = 17, IS_INITIALIZED = 18, @@ -299,6 +300,12 @@ internal enum ValueTypeId { VALUE_TYPE_ID_PARENT_VTYPE = 0xf2, VALUE_TYPE_ID_FIXED_ARRAY = 0xf3 } + internal enum MonoTypeNameFormat{ + MONO_TYPE_NAME_FORMAT_IL, + MONO_TYPE_NAME_FORMAT_REFLECTION, + MONO_TYPE_NAME_FORMAT_FULL_NAME, + MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED + } internal class MonoBinaryWriter : BinaryWriter { @@ -315,23 +322,68 @@ public void WriteLong(long val) } } - + internal class ValueTypeClass + { + public byte[] valueTypeBuffer; + public JArray valueTypeJson; + public JArray valueTypeJsonProps; + public int typeId; + public JArray valueTypeProxy; + public string valueTypeVarName; + public bool valueTypeAutoExpand; + public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool expand_properties) + { + valueTypeBuffer = buffer; + valueTypeJson = json; + typeId = id; + valueTypeJsonProps = null; + valueTypeProxy = null; + valueTypeVarName = varName; + valueTypeAutoExpand = expand_properties; + } + public bool HasFieldWithSameName(string propName) + { + foreach (var field in valueTypeJson) + { + if (field["name"].Value().Equals(propName)) + return true; + } + return false; + } + } internal class MonoSDBHelper { + private Dictionary valueTypes = new Dictionary(); + private static int valuetype_id; private static int cmd_id; private static int GetId() {return cmd_id++;} private MonoProxy proxy; - + private static int MINOR_VERSION = 61; + private static int MAJOR_VERSION = 2; public MonoSDBHelper(MonoProxy proxy) { this.proxy = proxy; } + public async Task SetProtocolVersion(SessionId sessionId, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(MAJOR_VERSION); + command_params_writer.Write(MINOR_VERSION); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.SET_PROTOCOL_VERSION, command_params, token); + return true; + } + internal async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) { Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); - if (res.IsErr) + if (res.IsErr) { + Console.WriteLine(res); + Console.WriteLine("has error"); return null; + } byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); @@ -404,6 +456,17 @@ public async Task GetMethodName(SessionId sessionId, int method_id, Canc return new string(memoryData); } + public async Task MethodIsStatic(SessionId sessionId, int method_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(method_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_INFO, command_params, token); + var flags = ret_debugger_cmd_reader.ReadInt32(); + return (flags & 0x0010) > 0; //check method is static + } + public async Task SetBreakpoint(SessionId sessionId, int method_id, long il_offset, CancellationToken token) { var command_params = new MemoryStream(); @@ -463,12 +526,39 @@ public async Task ClearSingleStep(SessionId sessionId, int req_id, Cancell return false; } - public async Task GetTypeName(SessionId sessionId, int type_id, CancellationToken token) + public async Task> GetTypeFieldsName(SessionId sessionId, int type_id, CancellationToken token) { + var ret = new List(); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(type_id); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_FIELDS, command_params, token); + var nFields = ret_debugger_cmd_reader.ReadInt32(); + + for (int i = 0 ; i < nFields; i++) + { + ret_debugger_cmd_reader.ReadInt32(); //fieldId + + var fieldNameLen = ret_debugger_cmd_reader.ReadInt32(); + char[] fieldName = new char[fieldNameLen]; + ret_debugger_cmd_reader.Read(fieldName, 0, fieldNameLen); + string fieldNameStr = new string(fieldName); + fieldNameStr = fieldNameStr.Replace("k__BackingField", ""); + fieldNameStr = fieldNameStr.Replace("<", ""); + fieldNameStr = fieldNameStr.Replace(">", ""); + ret.Add(fieldNameStr); + ret_debugger_cmd_reader.ReadInt32(); //typeId + ret_debugger_cmd_reader.ReadInt32(); //attrs + } + return ret; + } + public async Task GetTypeName(SessionId sessionId, int type_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(type_id); + command_params_writer.Write((int) MonoTypeNameFormat.MONO_TYPE_NAME_FORMAT_REFLECTION); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_INFO, command_params, token); var namespaceLen = ret_debugger_cmd_reader.ReadInt32(); @@ -485,6 +575,9 @@ public async Task GetTypeName(SessionId sessionId, int type_id, Cancella string className = new string(classFullName); className = className.Replace("+", "."); + className = Regex.Replace(className, @"`\d+", ""); + className = className.Replace("[", "<"); + className = className.Replace("]", ">"); return className; } @@ -495,10 +588,14 @@ public async Task GetStringValue(SessionId sessionId, int string_id, Can command_params_writer.Write(string_id); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STRING_REF, (int) CmdString.GET_VALUE, command_params, token); - var stringSize = ret_debugger_cmd_reader.ReadInt32(); - char[] memoryData = new char[stringSize]; - ret_debugger_cmd_reader.Read(memoryData, 0, stringSize); - return new string(memoryData); + var isUtf16 = ret_debugger_cmd_reader.ReadByte(); + if (isUtf16 == 0) { + var stringSize = ret_debugger_cmd_reader.ReadInt32(); + char[] memoryData = new char[stringSize]; + ret_debugger_cmd_reader.Read(memoryData, 0, stringSize); + return new string(memoryData); + } + return null; } public async Task GetClassNameFromObject(SessionId sessionId, int object_id, CancellationToken token) @@ -512,9 +609,94 @@ public async Task GetClassNameFromObject(SessionId sessionId, int object return await GetTypeName(sessionId, type_id, token); } + public async Task GetMethodIdByName(SessionId sessionId, int type_id, string method_name, CancellationToken token) + { + var ret = new List(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((int)type_id); + command_params_writer.WriteString(method_name); + command_params_writer.Write((int)(0x10 | 4)); //instance methods + command_params_writer.Write((int)1); //case sensitive + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_METHODS_BY_NAME_FLAGS, command_params, token); + var nMethods = ret_debugger_cmd_reader.ReadInt32(); + return ret_debugger_cmd_reader.ReadInt32(); + } + public async Task InvokeMethod(SessionId sessionId, byte[] valueTypeBuffer, int method_id, string varName, CancellationToken token) + { + MemoryStream parms = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(parms); + command_params_writer.Write(method_id); + command_params_writer.Write(valueTypeBuffer); + command_params_writer.Write(0); + Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.InvokeMethod(Convert.ToBase64String(parms.ToArray())), token); + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); + if (newBytes.Length == 0) + return null; + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadByte(); //number of objects returned. + return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, token); + } + public async Task GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token) + { + var valueType = valueTypes[valueTypeId]; + JArray valueTypeFields = valueType.valueTypeJsonProps; + var ret = new List(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(valueType.typeId); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); + var nProperties = ret_debugger_cmd_reader.ReadInt32(); + + for (int i = 0 ; i < nProperties; i++) + { + ret_debugger_cmd_reader.ReadInt32(); //propertyId + var propertyNameLen = ret_debugger_cmd_reader.ReadInt32(); + char[] propertyName = new char[propertyNameLen]; + ret_debugger_cmd_reader.Read(propertyName, 0, propertyNameLen); + var getMethodId = ret_debugger_cmd_reader.ReadInt32(); + ret_debugger_cmd_reader.ReadInt32(); //setmethod + ret_debugger_cmd_reader.ReadInt32(); //attrs + if (await MethodIsStatic(sessionId, getMethodId, token)) + continue; + JObject propRet = null; + string propertyNameStr = new string(propertyName); + if (valueType.HasFieldWithSameName(propertyNameStr)) + continue; + if (valueType.valueTypeAutoExpand) + { + propRet = await InvokeMethod(sessionId, valueType.valueTypeBuffer, getMethodId, propertyNameStr, token); + } + else + { + propRet = JObject.FromObject(new { + get = new + { + type = "function", + objectId = "dotnet:valuetype:" + valueType.typeId + ":method_id:" + getMethodId, + className = "Function", + description = "get " + new string(propertyName) + " ()", + }, + name = new string(propertyName) + }); + } + valueTypeFields.Add(propRet); + } + return valueTypeFields; + } + public bool AutoInvokeToString(string className) { + if (className == "System.DateTime" || + className == "System.DateTimeOffset" || + className == "System.TimeSpan") + return true; + return false; + } public async Task CreateJObjectForVariableValue(SessionId sessionId, BinaryReader ret_debugger_cmd_reader, string name, CancellationToken token) { + long initialPos = ret_debugger_cmd_reader == null ? 0 : ret_debugger_cmd_reader.BaseStream.Position; ElementType etype = (ElementType)ret_debugger_cmd_reader.ReadByte(); switch (etype) { case ElementType.Void: @@ -534,11 +716,8 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi }); } case ElementType.I1: - case ElementType.U1: case ElementType.I2: - case ElementType.U2: case ElementType.I4: - case ElementType.U4: { var value = ret_debugger_cmd_reader.ReadInt32(); return JObject.FromObject(new { @@ -552,6 +731,22 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi name }); } + case ElementType.U1: + case ElementType.U2: + case ElementType.U4: + { + var value = ret_debugger_cmd_reader.ReadUInt32(); + return JObject.FromObject(new { + value = new + { + type = "number", + value, + description = value.ToString() + }, + writable = true, + name + }); + } case ElementType.Char: { var value = ret_debugger_cmd_reader.ReadInt32(); @@ -567,9 +762,22 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi }); } case ElementType.I8: - return new JObject{{"Type", "number"}}; case ElementType.U8: - return new JObject{{"Type", "number"}}; + { + ulong high = (ulong) ret_debugger_cmd_reader.ReadInt32(); + ulong low = (ulong) ret_debugger_cmd_reader.ReadInt32(); + var value = ((high << 32) | low); + return JObject.FromObject(new { + value = new + { + type = "number", + value, + description = value.ToString() + }, + writable = true, + name + }); + } case ElementType.R4: return new JObject{{"Type", "void"}}; case ElementType.R8: @@ -615,7 +823,48 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi }); } case ElementType.ValueType: - return new JObject{{"Type", "void"}}; + { + var isEnum = ret_debugger_cmd_reader.ReadByte(); + var typeId = ret_debugger_cmd_reader.ReadInt32(); + var className = await GetTypeName(sessionId, typeId, token); + var description = className; + var numFields = ret_debugger_cmd_reader.ReadInt32(); + var fieldsName = await GetTypeFieldsName(sessionId, typeId, token); + JArray valueTypeFields = new JArray(); + for (int i = 0; i < numFields ; i++) + { + var fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fieldsName.ElementAt(i), token); + valueTypeFields.Add(fieldValueType); + } + + long endPos = ret_debugger_cmd_reader.BaseStream.Position; + var valueTypeId = Interlocked.Increment(ref valuetype_id); + + ret_debugger_cmd_reader.BaseStream.Position = initialPos; + byte[] valueTypeBuffer = new byte[endPos - initialPos]; + ret_debugger_cmd_reader.Read(valueTypeBuffer, 0, (int)(endPos - initialPos)); + ret_debugger_cmd_reader.BaseStream.Position = endPos; + valueTypes[valueTypeId] = new ValueTypeClass(name, valueTypeBuffer, valueTypeFields, typeId, className == "System.DateTime"); + if (AutoInvokeToString(className) || isEnum == 1) { + int method_id = await GetMethodIdByName(sessionId, typeId, "ToString", token); + var retMethod = await InvokeMethod(sessionId, valueTypeBuffer, method_id, "methodRet", token); + description = retMethod["value"]?["value"].Value(); + } + + return JObject.FromObject(new { + value = new + { + type = "object", + objectId = "dotnet:valuetype:" + valueTypeId, + description, + className, + expanded = true, + isValueType = true, + isEnum = isEnum == 1 ? true : false + }, + name + }); + } case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL: { return JObject.FromObject(new { @@ -665,5 +914,53 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me return array; } + public async Task GetValueTypeValues(SessionId sessionId, int valueTypeId, CancellationToken token) + { + if (valueTypes[valueTypeId].valueTypeJsonProps == null) + { + valueTypes[valueTypeId].valueTypeJsonProps = new JArray(); + valueTypes[valueTypeId].valueTypeJsonProps = await GetPropertiesValuesOfValueType(sessionId, valueTypeId, token); + } + return new JArray(valueTypes[valueTypeId].valueTypeJson.Union(valueTypes[valueTypeId].valueTypeJsonProps)); + } + + public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId, CancellationToken token) + { + if (valueTypes[valueTypeId].valueTypeProxy != null) + return valueTypes[valueTypeId].valueTypeProxy; + valueTypes[valueTypeId].valueTypeProxy = new JArray(valueTypes[valueTypeId].valueTypeJson); + + var ret = new List(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(valueTypes[valueTypeId].typeId); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); + var nProperties = ret_debugger_cmd_reader.ReadInt32(); + + for (int i = 0 ; i < nProperties; i++) + { + ret_debugger_cmd_reader.ReadInt32(); //propertyId + var propertyNameLen = ret_debugger_cmd_reader.ReadInt32(); + char[] propertyName = new char[propertyNameLen]; + ret_debugger_cmd_reader.Read(propertyName, 0, propertyNameLen); + + var getMethodId = ret_debugger_cmd_reader.ReadInt32(); + ret_debugger_cmd_reader.ReadInt32(); //setmethod + ret_debugger_cmd_reader.ReadInt32(); //attrs + if (await MethodIsStatic(sessionId, getMethodId, token)) + continue; + var command_params_to_proxy = new MemoryStream(); + var command_params_writer_to_proxy = new MonoBinaryWriter(command_params_to_proxy); + command_params_writer_to_proxy.Write(getMethodId); + command_params_writer_to_proxy.Write(valueTypes[valueTypeId].valueTypeBuffer); + command_params_writer_to_proxy.Write(0); + valueTypes[valueTypeId].valueTypeProxy.Add(JObject.FromObject(new { + get = Convert.ToBase64String(command_params_to_proxy.ToArray()), + name = new string(propertyName) + })); + } + return valueTypes[valueTypeId].valueTypeProxy; + } } } diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 6ad578369b35e..d56700f94ce9f 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -824,6 +824,18 @@ var MonoSupportLib = { MONO.commands_received = buffer_obj; }, + mono_wasm_invoke_method_debugger_agent: function (command_parameters) + { + const dataHeap = new Uint8Array (Module.HEAPU8.buffer, command_parameters, command_parameters.length); + dataHeap.set (new Uint8Array (this._base64_to_uint8 (command_parameters))); + let res_ok = this._c_fn_table.mono_wasm_invoke_method_debugger_agent_wrapper (dataHeap.byteOffset, command_parameters.length); + let res = MONO.commands_received; + MONO.commands_received = null; + if (res_ok) { + return { res_ok, res }; + } + }, + mono_wasm_send_dbg_command: function (id, command_set, command, command_parameters) { const dataHeap = new Uint8Array (Module.HEAPU8.buffer, command_parameters, command_parameters.length); @@ -1270,9 +1282,7 @@ var MonoSupportLib = { return setter_res; }, - _create_proxy_from_object_id: function (objectId) { - const details = this.mono_wasm_get_details(objectId); - + _create_proxy_from_object_id: function (objectId, details) { if (objectId.startsWith ('dotnet:array:')) return details.map (p => p.value); @@ -1284,7 +1294,7 @@ var MonoSupportLib = { Object.defineProperty (proxy, prop.name, - { get () { return MONO._invoke_getter (objectId, prop.name); } } + { get () { return MONO.mono_wasm_invoke_method_debugger_agent (prop.get); } } ); } else { proxy [prop.name] = prop.value; @@ -1302,6 +1312,7 @@ var MonoSupportLib = { throw new Error (`"arguments" should be an array, but was ${request.arguments}`); const objId = request.objectId; + const details = request.details; let proxy; if (objId.startsWith ('dotnet:cfo_res:')) { @@ -1310,7 +1321,7 @@ var MonoSupportLib = { else throw new Error (`Unknown object id ${objId}`); } else { - proxy = this._create_proxy_from_object_id (objId); + proxy = this._create_proxy_from_object_id (objId, details); } const fn_args = request.arguments != undefined ? request.arguments.map(a => JSON.stringify(a.value)) : []; @@ -1320,8 +1331,13 @@ var MonoSupportLib = { if (fn_res === undefined) return { type: "undefined" }; - if (fn_res === null || (fn_res.subtype === 'null' && fn_res.value === undefined)) + if (fn_res.res.value !== undefined ) { return fn_res; + } + + if (fn_res === null || (fn_res.subtype === 'null' && fn_res.value === undefined)) { + return fn_res; + } // primitive type if (Object (fn_res) !== fn_res) @@ -1430,8 +1446,9 @@ var MonoSupportLib = { this._register_c_var_fn ('mono_wasm_get_local_vars', 'bool', [ 'number', 'number', 'number']); this._register_c_var_fn ('mono_wasm_get_deref_ptr_value', 'bool', [ 'number', 'number']); this._register_c_fn ('mono_wasm_set_value_on_object', 'bool', [ 'number', 'string', 'string' ]); - this._register_c_fn ('mono_wasm_set_variable_on_frame', 'bool', [ 'number', 'number', 'string', 'string']); - this._register_c_fn ('mono_wasm_send_dbg_command', 'bool', [ 'number', 'number', 'number', 'number', 'number']); + this._register_c_fn ('mono_wasm_set_variable_on_frame', 'bool', [ 'number', 'number', 'string', 'string' ]); + this._register_c_fn ('mono_wasm_send_dbg_command', 'bool', [ 'number', 'number', 'number', 'number', 'number' ]); + this._register_c_fn ('mono_wasm_invoke_method_debugger_agent', 'bool', [ 'number', 'number' ]); // DO NOT REMOVE - magic debugger init function if (globalThis.dotnetDebugger) debugger; From 1f620dcbf41979a8e8f0691b6a07304fe938d3fb Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 12 May 2021 14:29:00 -0300 Subject: [PATCH 07/48] Failed: 316, Passed: 175 --- src/mono/mono/mini/debugger-agent.c | 1 + src/mono/mono/mini/debugger-protocol.c | 12 - .../debugger/BrowserDebugProxy/MonoProxy.cs | 41 ++- .../BrowserDebugProxy/MonoSDBHelper.cs | 342 +++++++++++++++--- .../DebuggerTestSuite/SteppingTests.cs | 2 +- 5 files changed, 325 insertions(+), 73 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 78393b3e4eb69..1b16eb7f2cc58 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -4989,6 +4989,7 @@ buffer_add_info_for_null_value (Buffer* buf, MonoType* t, MonoDomain* domain) buffer_add_int (buf, m_class_get_rank (mono_class_from_mono_type_internal (t))); if (m_class_get_byval_arg (m_class_get_element_class (mono_class_from_mono_type_internal (t)))->type == MONO_TYPE_CLASS) buffer_add_typeid (buf, domain, m_class_get_element_class (mono_class_from_mono_type_internal (t))); + buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t)); break; } } diff --git a/src/mono/mono/mini/debugger-protocol.c b/src/mono/mono/mini/debugger-protocol.c index 1340f8f6945dc..2fe3096608a51 100644 --- a/src/mono/mono/mini/debugger-protocol.c +++ b/src/mono/mono/mini/debugger-protocol.c @@ -56,12 +56,7 @@ m_dbgprot_decode_int (uint8_t *buf, uint8_t **endbuf, uint8_t *limit) { *endbuf = buf + 4; g_assert (*endbuf <= limit); - -#ifndef HOST_WASM return (((int)buf [0]) << 24) | (((int)buf [1]) << 16) | (((int)buf [2]) << 8) | (((int)buf [3]) << 0); -#else - return (((int)buf [0]) << 0) | (((int)buf [1]) << 8) | (((int)buf [2]) << 16) | (((int)buf [3]) << 24); -#endif } int64_t @@ -198,17 +193,10 @@ void m_dbgprot_buffer_add_int (MdbgProtBuffer *buf, uint32_t val) { m_dbgprot_buffer_make_room (buf, 4); -#ifndef HOST_WASM buf->p [0] = (val >> 24) & 0xff; buf->p [1] = (val >> 16) & 0xff; buf->p [2] = (val >> 8) & 0xff; buf->p [3] = (val >> 0) & 0xff; -#else - buf->p [0] = (val >> 0) & 0xff; - buf->p [1] = (val >> 8) & 0xff; - buf->p [2] = (val >> 16) & 0xff; - buf->p [3] = (val >> 24) & 0xff; -#endif buf->p += 4; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index a6d377414e76c..d4e1dc44988f7 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -477,21 +477,30 @@ protected override async Task AcceptCommand(MessageId id, string method, J token); return true; } - if (objectId.Scheme == "valuetype") + { args["details"] = await sdbHelper.GetValueTypeProxy(id, int.Parse(objectId.Value), token); + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadByte(); //number of objects returned. + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "seila", token); + /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ + res = Result.OkFromObject(new { result = obj["value"]}); + SendResponse(id, res, token); + return true; - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); - var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); - ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "seila", token); - /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ - res = Result.OkFromObject(new { result = obj["value"]}); - - SendResponse(id, res, token); - return true; + } + /*if (objectId.Scheme == "array") + { + args["details"] = await sdbHelper.GetArrayProxy(id, int.Parse(objectId.Value), token); + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + Console.WriteLine(res); + SendResponse(id, res, token); + }*/ + return false; } } @@ -530,6 +539,12 @@ private async Task RuntimeGetProperties(MessageId id, DotnetObjectId obj Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); return res2; } + if (objectId.Scheme == "array") + { + var ret = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); + Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); + return res2; + } Result res = await SendMonoCommand(id, MonoCommands.GetDetails(objectId, args), token); if (res.IsErr) return res; @@ -603,7 +618,7 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); ret_debugger_cmd_reader.ReadBytes(11); //skip HEADER_LEN ret_debugger_cmd_reader.ReadByte(); //suspend_policy var number_of_events = ret_debugger_cmd_reader.ReadInt32(); //number of events -> should be always one diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 2ee0663b0e083..89678afd2ba18 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -231,6 +231,14 @@ internal enum CmdType { GET_VALUE_SIZE = 20 } + internal enum CmdArray { + GET_LENGTH = 1, + GET_VALUES = 2, + SET_VALUES = 3, + REF_GET_TYPE = 4 + } + + internal enum CmdField { GET_INFO = 1 } @@ -307,6 +315,103 @@ internal enum MonoTypeNameFormat{ MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED } + internal class MonoBinaryReader : BinaryReader + { + public MonoBinaryReader(Stream stream) : base(stream) {} + + internal static unsafe void PutBytesBE (byte *dest, byte *src, int count) + { + int i = 0; + + if (BitConverter.IsLittleEndian){ + dest += count; + for (; i < count; i++) + *(--dest) = *src++; + } else { + for (; i < count; i++) + *dest++ = *src++; + } + } + + public override string ReadString() + { + var valueLen = ReadInt32(); + char[] value = new char[valueLen]; + Read(value, 0, valueLen); + return new string(value); + } + public unsafe long ReadLong() + { + byte[] data = new byte[8]; + Read(data, 0, 8); + + long ret; + fixed (byte *src = &data[0]){ + PutBytesBE ((byte *) &ret, src, 8); + } + + return ret; + } + public override unsafe sbyte ReadSByte() + { + byte[] data = new byte[4]; + Read(data, 0, 4); + + int ret; + fixed (byte *src = &data[0]){ + PutBytesBE ((byte *) &ret, src, 4); + } + return (sbyte)ret; + } + + public unsafe byte ReadUByte() + { + byte[] data = new byte[4]; + Read(data, 0, 4); + + int ret; + fixed (byte *src = &data[0]){ + PutBytesBE ((byte *) &ret, src, 4); + } + return (byte)ret; + } + + public override unsafe int ReadInt32() + { + byte[] data = new byte[4]; + Read(data, 0, 4); + + int ret; + fixed (byte *src = &data[0]){ + PutBytesBE ((byte *) &ret, src, 4); + } + return ret; + } + + public override unsafe uint ReadUInt32() + { + byte[] data = new byte[4]; + Read(data, 0, 4); + + uint ret; + fixed (byte *src = &data[0]){ + PutBytesBE ((byte *) &ret, src, 4); + } + return ret; + } + public unsafe ushort ReadUShort() + { + byte[] data = new byte[4]; + Read(data, 0, 4); + + uint ret; + fixed (byte *src = &data[0]){ + PutBytesBE ((byte *) &ret, src, 4); + } + return (ushort)ret; + } + } + internal class MonoBinaryWriter : BinaryWriter { public MonoBinaryWriter(Stream stream) : base(stream) {} @@ -320,6 +425,12 @@ public void WriteLong(long val) Write((int)((val >> 32) & 0xffffffff)); Write((int)((val >> 0) & 0xffffffff)); } + public override void Write(int val) + { + byte[] bytes = BitConverter.GetBytes(val); + Array.Reverse(bytes, 0, bytes.Length); + Write(bytes); + } } internal class ValueTypeClass @@ -376,7 +487,7 @@ public async Task SetProtocolVersion(SessionId sessionId, CancellationToke return true; } - internal async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) + internal async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) { Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); if (res.IsErr) { @@ -386,7 +497,7 @@ internal async Task SendDebuggerAgentCommand(SessionId sessionId, } byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); return ret_debugger_cmd_reader; } @@ -437,10 +548,7 @@ public async Task GetAssemblyName(SessionId sessionId, int assembly_id, command_params_writer.Write(assembly_id); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_LOCATION, command_params, token); - var stringSize = ret_debugger_cmd_reader.ReadInt32(); - char[] memoryData = new char[stringSize]; - ret_debugger_cmd_reader.Read(memoryData, 0, stringSize); - return new string(memoryData); + return ret_debugger_cmd_reader.ReadString(); } public async Task GetMethodName(SessionId sessionId, int method_id, CancellationToken token) @@ -450,10 +558,7 @@ public async Task GetMethodName(SessionId sessionId, int method_id, Canc command_params_writer.Write(method_id); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME, command_params, token); - var stringSize = ret_debugger_cmd_reader.ReadInt32(); - char[] memoryData = new char[stringSize]; - ret_debugger_cmd_reader.Read(memoryData, 0, stringSize); - return new string(memoryData); + return ret_debugger_cmd_reader.ReadString(); } public async Task MethodIsStatic(SessionId sessionId, int method_id, CancellationToken token) @@ -540,10 +645,7 @@ public async Task> GetTypeFieldsName(SessionId sessionId, int type_ { ret_debugger_cmd_reader.ReadInt32(); //fieldId - var fieldNameLen = ret_debugger_cmd_reader.ReadInt32(); - char[] fieldName = new char[fieldNameLen]; - ret_debugger_cmd_reader.Read(fieldName, 0, fieldNameLen); - string fieldNameStr = new string(fieldName); + string fieldNameStr = ret_debugger_cmd_reader.ReadString(); fieldNameStr = fieldNameStr.Replace("k__BackingField", ""); fieldNameStr = fieldNameStr.Replace("<", ""); fieldNameStr = fieldNameStr.Replace(">", ""); @@ -561,23 +663,19 @@ public async Task GetTypeName(SessionId sessionId, int type_id, Cancella command_params_writer.Write((int) MonoTypeNameFormat.MONO_TYPE_NAME_FORMAT_REFLECTION); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_INFO, command_params, token); - var namespaceLen = ret_debugger_cmd_reader.ReadInt32(); - char[] namespaceValue = new char[namespaceLen]; - ret_debugger_cmd_reader.Read(namespaceValue, 0, namespaceLen); + ret_debugger_cmd_reader.ReadString(); - var classLen = ret_debugger_cmd_reader.ReadInt32(); - char[] classValue = new char[classLen]; - ret_debugger_cmd_reader.Read(classValue, 0, classLen); + ret_debugger_cmd_reader.ReadString(); - var classFullNameLen = ret_debugger_cmd_reader.ReadInt32(); - char[] classFullName = new char[classFullNameLen]; - ret_debugger_cmd_reader.Read(classFullName, 0, classFullNameLen); + string className = ret_debugger_cmd_reader.ReadString(); - string className = new string(classFullName); className = className.Replace("+", "."); className = Regex.Replace(className, @"`\d+", ""); + className = className.Replace("[]", "__SQUARED_BRACKETS__"); className = className.Replace("[", "<"); className = className.Replace("]", ">"); + className = className.Replace("__SQUARED_BRACKETS__", "[]"); + className = className.Replace("System.String", "string"); return className; } @@ -590,14 +688,21 @@ public async Task GetStringValue(SessionId sessionId, int string_id, Can var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STRING_REF, (int) CmdString.GET_VALUE, command_params, token); var isUtf16 = ret_debugger_cmd_reader.ReadByte(); if (isUtf16 == 0) { - var stringSize = ret_debugger_cmd_reader.ReadInt32(); - char[] memoryData = new char[stringSize]; - ret_debugger_cmd_reader.Read(memoryData, 0, stringSize); - return new string(memoryData); + return ret_debugger_cmd_reader.ReadString(); } return null; } + public async Task GetArrayLength(SessionId sessionId, int object_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(object_id); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ARRAY_REF, (int) CmdArray.GET_LENGTH, command_params, token); + var length = ret_debugger_cmd_reader.ReadInt32(); + length = ret_debugger_cmd_reader.ReadInt32(); + return length; + } public async Task GetClassNameFromObject(SessionId sessionId, int object_id, CancellationToken token) { var command_params = new MemoryStream(); @@ -634,7 +739,7 @@ public async Task InvokeMethod(SessionId sessionId, byte[] valueTypeBuf if (newBytes.Length == 0) return null; var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new BinaryReader(ret_debugger_cmd); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, token); } @@ -654,16 +759,13 @@ public async Task GetPropertiesValuesOfValueType(SessionId sessionId, in for (int i = 0 ; i < nProperties; i++) { ret_debugger_cmd_reader.ReadInt32(); //propertyId - var propertyNameLen = ret_debugger_cmd_reader.ReadInt32(); - char[] propertyName = new char[propertyNameLen]; - ret_debugger_cmd_reader.Read(propertyName, 0, propertyNameLen); + string propertyNameStr = ret_debugger_cmd_reader.ReadString(); var getMethodId = ret_debugger_cmd_reader.ReadInt32(); ret_debugger_cmd_reader.ReadInt32(); //setmethod ret_debugger_cmd_reader.ReadInt32(); //attrs if (await MethodIsStatic(sessionId, getMethodId, token)) continue; JObject propRet = null; - string propertyNameStr = new string(propertyName); if (valueType.HasFieldWithSameName(propertyNameStr)) continue; if (valueType.valueTypeAutoExpand) @@ -678,9 +780,9 @@ public async Task GetPropertiesValuesOfValueType(SessionId sessionId, in type = "function", objectId = "dotnet:valuetype:" + valueType.typeId + ":method_id:" + getMethodId, className = "Function", - description = "get " + new string(propertyName) + " ()", + description = "get " + propertyNameStr + " ()", }, - name = new string(propertyName) + name = propertyNameStr }); } valueTypeFields.Add(propRet); @@ -694,7 +796,7 @@ public bool AutoInvokeToString(string className) { return true; return false; } - public async Task CreateJObjectForVariableValue(SessionId sessionId, BinaryReader ret_debugger_cmd_reader, string name, CancellationToken token) + public async Task CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, string name, CancellationToken token) { long initialPos = ret_debugger_cmd_reader == null ? 0 : ret_debugger_cmd_reader.BaseStream.Position; ElementType etype = (ElementType)ret_debugger_cmd_reader.ReadByte(); @@ -716,6 +818,19 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi }); } case ElementType.I1: + { + var value = ret_debugger_cmd_reader.ReadSByte(); + return JObject.FromObject(new { + value = new + { + type = "number", + value, + description = value.ToString() + }, + writable = true, + name + }); + } case ElementType.I2: case ElementType.I4: { @@ -732,7 +847,33 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi }); } case ElementType.U1: + { + var value = ret_debugger_cmd_reader.ReadUByte(); + return JObject.FromObject(new { + value = new + { + type = "number", + value, + description = value.ToString() + }, + writable = true, + name + }); + } case ElementType.U2: + { + var value = ret_debugger_cmd_reader.ReadUShort(); + return JObject.FromObject(new { + value = new + { + type = "number", + value, + description = value.ToString() + }, + writable = true, + name + }); + } case ElementType.U4: { var value = ret_debugger_cmd_reader.ReadUInt32(); @@ -747,13 +888,42 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi name }); } + case ElementType.R4: + { + float value = BitConverter.Int32BitsToSingle(ret_debugger_cmd_reader.ReadInt32()); + return JObject.FromObject(new { + value = new + { + type = "number", + value, + description = value.ToString() + }, + writable = true, + name + }); + } case ElementType.Char: { var value = ret_debugger_cmd_reader.ReadInt32(); + var description = $"{value.ToString()} '{Convert.ToChar(value)}'"; return JObject.FromObject(new { value = new { - type = "char", + type = "symbol", + value = description, + description + }, + writable = true, + name + }); + } + case ElementType.I8: + { + long value = ret_debugger_cmd_reader.ReadLong(); + return JObject.FromObject(new { + value = new + { + type = "number", value, description = value.ToString() }, @@ -761,7 +931,6 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi name }); } - case ElementType.I8: case ElementType.U8: { ulong high = (ulong) ret_debugger_cmd_reader.ReadInt32(); @@ -778,10 +947,22 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi name }); } - case ElementType.R4: - return new JObject{{"Type", "void"}}; case ElementType.R8: - return new JObject{{"Type", "void"}}; + { + long high = (long) ret_debugger_cmd_reader.ReadInt32(); + long low = (long) ret_debugger_cmd_reader.ReadInt32(); + double value = BitConverter.Int64BitsToDouble(((high << 32) | low)); + return JObject.FromObject(new { + value = new + { + type = "number", + value, + description = value.ToString() + }, + writable = true, + name + }); + } case ElementType.I: case ElementType.U: // FIXME: The client and the debuggee might have different word sizes @@ -805,7 +986,22 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi } case ElementType.SzArray: case ElementType.Array: - return new JObject{{"Type", "void"}}; + { + var objectId = ret_debugger_cmd_reader.ReadInt32(); + var value = await GetClassNameFromObject(sessionId, objectId, token); + var length = await GetArrayLength(sessionId, objectId, token); + return JObject.FromObject(new { + value = new + { + type = "object", + objectId = "dotnet:array:" + objectId, + description = $"{value.ToString()}({length})", + className = value.ToString(), + subtype = "array" + }, + name + }); + } case ElementType.Class: case ElementType.Object: { @@ -867,22 +1063,58 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Bi } case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL: { + string className = ""; + ElementType variableType = (ElementType)ret_debugger_cmd_reader.ReadByte(); + switch (variableType) + { + case ElementType.String: + case ElementType.Class: + { + var type_id = ret_debugger_cmd_reader.ReadInt32(); + className = await GetTypeName(sessionId, type_id, token); + break; + } + case ElementType.SzArray: + case ElementType.Array: + { + ElementType byte_type = (ElementType)ret_debugger_cmd_reader.ReadByte(); + var rank = ret_debugger_cmd_reader.ReadInt32(); + if (byte_type == ElementType.Class) { + var internal_type_id = ret_debugger_cmd_reader.ReadInt32(); + } + var type_id = ret_debugger_cmd_reader.ReadInt32(); + className = await GetTypeName(sessionId, type_id, token); + break; + } + default: + { + className = "unknown"; + break; + } + } return JObject.FromObject(new { value = new { type = "object", subtype = "null", - className = "string" //TODO get classname of null + className, + description = className }, name }); } case (ElementType)ValueTypeId.VALUE_TYPE_ID_TYPE: + { return new JObject{{"Type", "void"}}; + } case (ElementType)ValueTypeId.VALUE_TYPE_ID_PARENT_VTYPE: + { return new JObject{{"Type", "void"}}; + } case (ElementType)ValueTypeId.VALUE_TYPE_ID_FIXED_ARRAY: + { return new JObject{{"Type", "void"}}; + } } return null; } @@ -941,9 +1173,7 @@ public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId for (int i = 0 ; i < nProperties; i++) { ret_debugger_cmd_reader.ReadInt32(); //propertyId - var propertyNameLen = ret_debugger_cmd_reader.ReadInt32(); - char[] propertyName = new char[propertyNameLen]; - ret_debugger_cmd_reader.Read(propertyName, 0, propertyNameLen); + string propertyNameStr = ret_debugger_cmd_reader.ReadString(); var getMethodId = ret_debugger_cmd_reader.ReadInt32(); ret_debugger_cmd_reader.ReadInt32(); //setmethod @@ -957,10 +1187,28 @@ public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId command_params_writer_to_proxy.Write(0); valueTypes[valueTypeId].valueTypeProxy.Add(JObject.FromObject(new { get = Convert.ToBase64String(command_params_to_proxy.ToArray()), - name = new string(propertyName) + name = propertyNameStr })); } return valueTypes[valueTypeId].valueTypeProxy; } + + public async Task GetArrayValues(SessionId sessionId, int arrayId, CancellationToken token) + { + var length = await GetArrayLength(sessionId, arrayId, token); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(arrayId); + command_params_writer.Write(0); + command_params_writer.Write(length); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ARRAY_REF, (int) CmdArray.GET_VALUES, command_params, token); + JArray array = new JArray(); + for (int i = 0 ; i < length ; i++) + { + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, i.ToString(), token); + array.Add(var_json); + } + return array; + } } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs index f9914dbd10185..643aa5c1e46fa 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs @@ -251,7 +251,7 @@ await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", } [Fact] - public async Task InspectLocalsDuringSteppingIn() + public async Task InspectLocalsDuringSteppingIn2() { await SetBreakpoint("dotnet://debugger-test.dll/debugger-test.cs", 86, 8); From 4bf5e0c6b532f9c3646f006e4523368bbf4d1739 Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 12 May 2021 16:35:44 -0300 Subject: [PATCH 08/48] Failed: 307, Passed: 184, Skipped: 0, Total: 491 --- src/mono/wasm/build/WasmApp.InTree.targets | 2 +- .../BrowserDebugProxy/DevToolsHelper.cs | 2 - .../debugger/BrowserDebugProxy/MonoProxy.cs | 27 ++---- .../BrowserDebugProxy/MonoSDBHelper.cs | 86 ++++++++++++++++--- 4 files changed, 80 insertions(+), 37 deletions(-) diff --git a/src/mono/wasm/build/WasmApp.InTree.targets b/src/mono/wasm/build/WasmApp.InTree.targets index cde8075f0874c..f92f2abd62bc6 100644 --- a/src/mono/wasm/build/WasmApp.InTree.targets +++ b/src/mono/wasm/build/WasmApp.InTree.targets @@ -25,7 +25,7 @@ + Targets="Build"/> new MonoCommands("MONO.mono_wasm_get_loaded_files()"); - public static MonoCommands GetDetails(DotnetObjectId objectId, JToken args = null) => new MonoCommands($"MONO.mono_wasm_get_details ('{objectId}', {(args ?? "{ }")})"); - public static MonoCommands SetVariableValue(int scopeId, int index, string name, string newValue) { return new MonoCommands($"MONO.mono_wasm_set_variable_value({scopeId}, {index}, '{name}', '{newValue}')"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index d4e1dc44988f7..0755df046d4bb 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -545,31 +545,14 @@ private async Task RuntimeGetProperties(MessageId id, DotnetObjectId obj Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); return res2; } - Result res = await SendMonoCommand(id, MonoCommands.GetDetails(objectId, args), token); - if (res.IsErr) - return res; - - if (objectId.Scheme == "cfo_res") + if (objectId.Scheme == "object") { - // Runtime.callFunctionOn result object - string value_json_str = res.Value["result"]?["value"]?["__value_as_json_string__"]?.Value(); - if (value_json_str != null) - { - res = Result.OkFromObject(new - { - result = JArray.Parse(value_json_str) - }); - } - else - { - res = Result.OkFromObject(new { result = new { } }); - } - } - else - { - res = Result.Ok(JObject.FromObject(new { result = res.Value["result"]["value"] })); + var ret = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), token); + Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); + return res2; } + Result res = Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); return res; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 89678afd2ba18..5ebae617d66d5 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -432,7 +432,16 @@ public override void Write(int val) Write(bytes); } } - + internal class FieldTypeClass + { + public int Id { get; } + public string Name { get; } + public FieldTypeClass(int id, string name) + { + Id = id; + Name = name; + } + } internal class ValueTypeClass { public byte[] valueTypeBuffer; @@ -631,9 +640,9 @@ public async Task ClearSingleStep(SessionId sessionId, int req_id, Cancell return false; } - public async Task> GetTypeFieldsName(SessionId sessionId, int type_id, CancellationToken token) + public async Task> GetTypeFields(SessionId sessionId, int type_id, CancellationToken token) { - var ret = new List(); + var ret = new List(); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(type_id); @@ -643,18 +652,26 @@ public async Task> GetTypeFieldsName(SessionId sessionId, int type_ for (int i = 0 ; i < nFields; i++) { - ret_debugger_cmd_reader.ReadInt32(); //fieldId + int fieldId = ret_debugger_cmd_reader.ReadInt32(); //fieldId string fieldNameStr = ret_debugger_cmd_reader.ReadString(); fieldNameStr = fieldNameStr.Replace("k__BackingField", ""); fieldNameStr = fieldNameStr.Replace("<", ""); fieldNameStr = fieldNameStr.Replace(">", ""); - ret.Add(fieldNameStr); + ret.Add(new FieldTypeClass(fieldId, fieldNameStr)); ret_debugger_cmd_reader.ReadInt32(); //typeId ret_debugger_cmd_reader.ReadInt32(); //attrs } return ret; } + public string ReplaceCommonClassNames(string className) + { + className = className.Replace("System.String", "string"); + className = className.Replace("System.Boolean", "bool"); + className = className.Replace("System.Char", "char"); + className = className.Replace("System.Int32", "int"); + return className; + } public async Task GetTypeName(SessionId sessionId, int type_id, CancellationToken token) { var command_params = new MemoryStream(); @@ -675,7 +692,7 @@ public async Task GetTypeName(SessionId sessionId, int type_id, Cancella className = className.Replace("[", "<"); className = className.Replace("]", ">"); className = className.Replace("__SQUARED_BRACKETS__", "[]"); - className = className.Replace("System.String", "string"); + className = ReplaceCommonClassNames(className); return className; } @@ -703,7 +720,7 @@ public async Task GetArrayLength(SessionId sessionId, int object_id, Cancel length = ret_debugger_cmd_reader.ReadInt32(); return length; } - public async Task GetClassNameFromObject(SessionId sessionId, int object_id, CancellationToken token) + public async Task GetTypeIdFromObject(SessionId sessionId, int object_id, CancellationToken token) { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); @@ -711,9 +728,15 @@ public async Task GetClassNameFromObject(SessionId sessionId, int object var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_GET_TYPE, command_params, token); var type_id = ret_debugger_cmd_reader.ReadInt32(); + return type_id; + } + public async Task GetClassNameFromObject(SessionId sessionId, int object_id, CancellationToken token) + { + int type_id = await GetTypeIdFromObject(sessionId, object_id, token); return await GetTypeName(sessionId, type_id, token); } + public async Task GetMethodIdByName(SessionId sessionId, int type_id, string method_name, CancellationToken token) { var ret = new List(); @@ -789,13 +812,25 @@ public async Task GetPropertiesValuesOfValueType(SessionId sessionId, in } return valueTypeFields; } - public bool AutoInvokeToString(string className) { + + public bool AutoExpandable(string className) { if (className == "System.DateTime" || className == "System.DateTimeOffset" || className == "System.TimeSpan") return true; return false; } + + public bool AutoInvokeToString(string className) { + if (className == "System.DateTime" || + className == "System.DateTimeOffset" || + className == "System.TimeSpan" || + className == "System.Decimal" || + className == "System.Guid") + return true; + return false; + } + public async Task CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, string name, CancellationToken token) { long initialPos = ret_debugger_cmd_reader == null ? 0 : ret_debugger_cmd_reader.BaseStream.Position; @@ -1011,7 +1046,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo value = new { type = "object", - objectId = "dotnet:object:" + objectId, + objectId = $"dotnet:object:{objectId}", //maybe pass here the typeId and avoid another call to debugger-agent when getting fields description = value.ToString(), className = value.ToString(), }, @@ -1025,11 +1060,11 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo var className = await GetTypeName(sessionId, typeId, token); var description = className; var numFields = ret_debugger_cmd_reader.ReadInt32(); - var fieldsName = await GetTypeFieldsName(sessionId, typeId, token); + var fields = await GetTypeFields(sessionId, typeId, token); JArray valueTypeFields = new JArray(); for (int i = 0; i < numFields ; i++) { - var fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fieldsName.ElementAt(i), token); + var fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, token); valueTypeFields.Add(fieldValueType); } @@ -1040,11 +1075,13 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo byte[] valueTypeBuffer = new byte[endPos - initialPos]; ret_debugger_cmd_reader.Read(valueTypeBuffer, 0, (int)(endPos - initialPos)); ret_debugger_cmd_reader.BaseStream.Position = endPos; - valueTypes[valueTypeId] = new ValueTypeClass(name, valueTypeBuffer, valueTypeFields, typeId, className == "System.DateTime"); + valueTypes[valueTypeId] = new ValueTypeClass(name, valueTypeBuffer, valueTypeFields, typeId, AutoExpandable(className)); if (AutoInvokeToString(className) || isEnum == 1) { int method_id = await GetMethodIdByName(sessionId, typeId, "ToString", token); var retMethod = await InvokeMethod(sessionId, valueTypeBuffer, method_id, "methodRet", token); description = retMethod["value"]?["value"].Value(); + if (className.Equals("System.Guid")) + description = description.ToUpper(); //to keep the old behavior } return JObject.FromObject(new { @@ -1210,5 +1247,30 @@ public async Task GetArrayValues(SessionId sessionId, int arrayId, Cance } return array; } + + public async Task GetObjectValues(SessionId sessionId, int objectId, CancellationToken token) + { + var typeId = await GetTypeIdFromObject(sessionId, objectId, token); + var fields = await GetTypeFields(sessionId, typeId, token); + JArray objectFields = new JArray(); + + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(objectId); + command_params_writer.Write(fields.Count); + foreach (var field in fields) + { + command_params_writer.Write(field.Id); + } + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_GET_VALUES, command_params, token); + + foreach (var field in fields) + { + var fieldValue = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, field.Name, token); + objectFields.Add(fieldValue); + } + return objectFields; + } } } From c853b1be4317ceb2adfb165f08b2cb2794379463 Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 12 May 2021 18:41:17 -0300 Subject: [PATCH 09/48] Failed: 280, Passed: 211 --- src/mono/mono/mini/debugger-agent.c | 12 ++++ src/mono/mono/mini/debugger-protocol.h | 3 +- .../debugger/BrowserDebugProxy/DebugStore.cs | 1 + .../debugger/BrowserDebugProxy/MonoProxy.cs | 2 + .../BrowserDebugProxy/MonoSDBHelper.cs | 71 ++++++++++++++++--- 5 files changed, 78 insertions(+), 11 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 1b16eb7f2cc58..548f80ca09270 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -4991,6 +4991,8 @@ buffer_add_info_for_null_value (Buffer* buf, MonoType* t, MonoDomain* domain) buffer_add_typeid (buf, domain, m_class_get_element_class (mono_class_from_mono_type_internal (t))); buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t)); break; + default: + buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t)); } } /* @@ -8734,6 +8736,16 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g buffer_add_assemblyid(buf, mono_domain_get (), m_class_get_image(method->klass)->assembly); break; } + case MDBGPROT_CMD_METHOD_HAS_ASYNC_DEBUG_INFO: { + MonoDebugMethodAsyncInfo* async_method = mono_debug_lookup_method_async_debug_info (method); + if (async_method) { + buffer_add_byte(buf, TRUE); + mono_debug_free_method_async_debug_info (async_method); + } + else + buffer_add_byte(buf, FALSE); + break; + } default: return ERR_NOT_IMPLEMENTED; } diff --git a/src/mono/mono/mini/debugger-protocol.h b/src/mono/mono/mini/debugger-protocol.h index 871d124f009fb..29e79d9065345 100644 --- a/src/mono/mono/mini/debugger-protocol.h +++ b/src/mono/mono/mini/debugger-protocol.h @@ -181,7 +181,8 @@ typedef enum { MDBGPROT_CMD_METHOD_MAKE_GENERIC_METHOD = 10, MDBGPROT_CMD_METHOD_TOKEN = 11, MDBGPROT_CMD_METHOD_ASSEMBLY = 12, - MDBGPROT_CMD_METHOD_GET_CLASS_TOKEN = 13 + MDBGPROT_CMD_METHOD_GET_CLASS_TOKEN = 13, + MDBGPROT_CMD_METHOD_HAS_ASYNC_DEBUG_INFO = 14 } MdbgProtCmdMethod; typedef enum { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 62013cd935d96..81c419e4c5850 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -317,6 +317,7 @@ internal class MethodInfo public SourceId SourceId => source.SourceId; + public int DebuggerId { get; set; } public string Name { get; } public MethodDebugInformation DebugInformation; public MethodDefinitionHandle methodDefHandle; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 0755df046d4bb..a9998a200b87a 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -666,6 +666,8 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec continue; } + method.DebuggerId = method_id; + SourceLocation location = method?.GetLocationByIl(il_pos); // When hitting a breakpoint on the "IncrementCount" method in the standard diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 5ebae617d66d5..29aac14da0222 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -203,7 +203,9 @@ internal enum CmdMethod { GET_CATTRS = 9, MAKE_GENERIC_METHOD = 10, TOKEN = 11, - ASSEMBLY = 12 + ASSEMBLY = 12, + CLASS_TOKEN = 13, + ASYNC_DEBUG_INFO = 14 } internal enum CmdType { @@ -655,9 +657,12 @@ public async Task> GetTypeFields(SessionId sessionId, int t int fieldId = ret_debugger_cmd_reader.ReadInt32(); //fieldId string fieldNameStr = ret_debugger_cmd_reader.ReadString(); - fieldNameStr = fieldNameStr.Replace("k__BackingField", ""); - fieldNameStr = fieldNameStr.Replace("<", ""); - fieldNameStr = fieldNameStr.Replace(">", ""); + if (fieldNameStr.Contains("k__BackingField")) + { + fieldNameStr = fieldNameStr.Replace("k__BackingField", ""); + fieldNameStr = fieldNameStr.Replace("<", ""); + fieldNameStr = fieldNameStr.Replace(">", ""); + } ret.Add(new FieldTypeClass(fieldId, fieldNameStr)); ret_debugger_cmd_reader.ReadInt32(); //typeId ret_debugger_cmd_reader.ReadInt32(); //attrs @@ -1062,6 +1067,25 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo var numFields = ret_debugger_cmd_reader.ReadInt32(); var fields = await GetTypeFields(sessionId, typeId, token); JArray valueTypeFields = new JArray(); + if (className.IndexOf("System.Nullable<") == 0) //should we call something on debugger-agent to check??? + { + ret_debugger_cmd_reader.ReadByte(); //ignoring the boolean type + var isNull = ret_debugger_cmd_reader.ReadInt32(); + var value = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, name, token); + if (isNull != 0) + return value; + else + return JObject.FromObject(new { + value = new + { + type = "object", + subtype = "null", + className, + description = className + }, + name + }); + } for (int i = 0; i < numFields ; i++) { var fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, token); @@ -1125,7 +1149,8 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo } default: { - className = "unknown"; + var type_id = ret_debugger_cmd_reader.ReadInt32(); + className = await GetTypeName(sessionId, type_id, token); break; } } @@ -1155,10 +1180,22 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo } return null; } + public async Task IsAsyncMethod(SessionId sessionId, int methodId, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(methodId); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.ASYNC_DEBUG_INFO, command_params, token); + return ret_debugger_cmd_reader.ReadByte() == 1 ; //token + } + public async Task StackFrameGetValues(SessionId sessionId, MethodInfo method, int thread_id, int frame_id, VarInfo[] var_ids, CancellationToken token) { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); + MonoBinaryReader ret_debugger_cmd_reader = null; + command_params_writer.Write(thread_id); command_params_writer.Write(frame_id); command_params_writer.Write(var_ids.Length); @@ -1166,21 +1203,35 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me { command_params_writer.Write(var.Index); } - JArray array = new JArray(); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_VALUES, command_params, token); + if (await IsAsyncMethod(sessionId, method.DebuggerId, token)) + { + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); + ret_debugger_cmd_reader.ReadByte(); //ignore type + var objectId = ret_debugger_cmd_reader.ReadInt32(); + var asyncLocals = await GetObjectValues(sessionId, objectId, token); + asyncLocals = new JArray(asyncLocals.Where( asyncLocal => !asyncLocal["name"].Value().Contains("<>"))); + foreach (var asyncLocal in asyncLocals) + { + asyncLocal["name"] = Regex.Match(asyncLocal["name"].Value(), @"\<([^)]*)\>").Groups[1].Value; + } + return asyncLocals; + } + + JArray locals = new JArray(); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_VALUES, command_params, token); foreach (var var in var_ids) { var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, var.Name, token); - array.Add(var_json); + locals.Add(var_json); } if (!method.IsStatic()) { ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "this", token); var_json.Add("fieldOffset", -1); - array.Add(var_json); + locals.Add(var_json); } - return array; + return locals; } public async Task GetValueTypeValues(SessionId sessionId, int valueTypeId, CancellationToken token) From 372157aaf63c9c3b425b1484122169a38a7196ee Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 12 May 2021 19:57:02 -0300 Subject: [PATCH 10/48] Failed: 277, Passed: 214 --- src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 29aac14da0222..f37d77c7b3b4c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1203,6 +1203,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me { command_params_writer.Write(var.Index); } + if (await IsAsyncMethod(sessionId, method.DebuggerId, token)) { ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); @@ -1212,7 +1213,8 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me asyncLocals = new JArray(asyncLocals.Where( asyncLocal => !asyncLocal["name"].Value().Contains("<>"))); foreach (var asyncLocal in asyncLocals) { - asyncLocal["name"] = Regex.Match(asyncLocal["name"].Value(), @"\<([^)]*)\>").Groups[1].Value; + if (asyncLocal["name"].Value().Contains("<")) + asyncLocal["name"] = Regex.Match(asyncLocal["name"].Value(), @"\<([^)]*)\>").Groups[1].Value; } return asyncLocals; } From d8374441fa34d998d728ed68673f2786805831a0 Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 13 May 2021 12:06:09 -0300 Subject: [PATCH 11/48] Implemented boxed value. Failed: 271, Passed: 220 --- src/mono/mono/mini/debugger-agent.c | 7 ++++++- .../wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 12 ++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 548f80ca09270..41e506dd598aa 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -5176,6 +5176,9 @@ buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain, buffer_add_byte (buf, MONO_TYPE_VALUETYPE); buffer_add_byte (buf, m_class_is_enumtype (klass)); + + if (CHECK_PROTOCOL_VERSION(2, 61)) + buffer_add_byte(buf, boxed_vtype); buffer_add_typeid (buf, domain, klass); nfields = 0; @@ -5249,7 +5252,8 @@ decode_vtype (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void ErrorCode err; is_enum = decode_byte (buf, &buf, limit); - + if (CHECK_PROTOCOL_VERSION(2, 61)) + decode_byte (buf, &buf, limit); klass = decode_typeid (buf, &buf, limit, &d, &err); if (err != ERR_NONE) return err; @@ -5477,6 +5481,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, */ buf2 = buf; is_enum = decode_byte (buf, &buf, limit); + decode_byte (buf, &buf, limit); //ignore is boxed klass = decode_typeid (buf, &buf, limit, &d, &err); if (err != ERR_NONE) return err; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index f37d77c7b3b4c..7fed466bcbe86 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -675,6 +675,7 @@ public string ReplaceCommonClassNames(string className) className = className.Replace("System.Boolean", "bool"); className = className.Replace("System.Char", "char"); className = className.Replace("System.Int32", "int"); + className = className.Replace("System.Object", "object"); return className; } public async Task GetTypeName(SessionId sessionId, int type_id, CancellationToken token) @@ -697,6 +698,7 @@ public async Task GetTypeName(SessionId sessionId, int type_id, Cancella className = className.Replace("[", "<"); className = className.Replace("]", ">"); className = className.Replace("__SQUARED_BRACKETS__", "[]"); + className = className.Replace(",", ", "); className = ReplaceCommonClassNames(className); return className; } @@ -783,7 +785,6 @@ public async Task GetPropertiesValuesOfValueType(SessionId sessionId, in var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); var nProperties = ret_debugger_cmd_reader.ReadInt32(); - for (int i = 0 ; i < nProperties; i++) { ret_debugger_cmd_reader.ReadInt32(); //propertyId @@ -840,6 +841,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo { long initialPos = ret_debugger_cmd_reader == null ? 0 : ret_debugger_cmd_reader.BaseStream.Position; ElementType etype = (ElementType)ret_debugger_cmd_reader.ReadByte(); + JObject fieldValueType = null; switch (etype) { case ElementType.Void: return new JObject{{"Type", "void"}}; @@ -1061,6 +1063,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo case ElementType.ValueType: { var isEnum = ret_debugger_cmd_reader.ReadByte(); + var isBoxed = ret_debugger_cmd_reader.ReadByte() == 1; var typeId = ret_debugger_cmd_reader.ReadInt32(); var className = await GetTypeName(sessionId, typeId, token); var description = className; @@ -1080,6 +1083,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo { type = "object", subtype = "null", + isValueType = true, className, description = className }, @@ -1088,7 +1092,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo } for (int i = 0; i < numFields ; i++) { - var fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, token); + fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, token); valueTypeFields.Add(fieldValueType); } @@ -1107,6 +1111,10 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo if (className.Equals("System.Guid")) description = description.ToUpper(); //to keep the old behavior } + else if (isBoxed && numFields == 1) { + fieldValueType["name"] = name; + return fieldValueType; + } return JObject.FromObject(new { value = new From 07ff48aa4e1bdb51e0dc372085b5a2d338120573 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 14 May 2021 09:22:00 -0300 Subject: [PATCH 12/48] Implementing get properties on objects. Implementing handling error on debugger-agent. --- src/mono/mono/mini/mini-wasm-debugger.c | 14 ++--- .../BrowserDebugProxy/MonoSDBHelper.cs | 55 ++++++++----------- .../DebuggerTestSuite/DebuggerTestBase.cs | 1 - src/mono/wasm/runtime/library_mono.js | 38 +++++++------ 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index bad899d4044d7..a9adfadb970d2 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -1670,8 +1670,8 @@ mono_wasm_invoke_method_debugger_agent (guint8* data, unsigned int size) if (error != 0) printf("error - mono_wasm_invoke_method_debugger_agent - %d\n", error); EM_ASM ({ - MONO.mono_wasm_add_dbg_command_received ($0, $1, $2); - }, -1, buf.buf, buf.p-buf.buf); + MONO.mono_wasm_add_dbg_command_received ($0, $1, $2, $3); + }, error == MDBGPROT_ERR_NONE, -1, buf.buf, buf.p-buf.buf); buffer_free (&buf); return TRUE; @@ -1683,11 +1683,11 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, MdbgProtBuffer buf; buffer_init (&buf, 128); gboolean no_reply; - mono_process_dbg_packet(id, command_set, command, &no_reply, data, data + size, &buf); - + MdbgProtErrorCode error = mono_process_dbg_packet(id, command_set, command, &no_reply, data, data + size, &buf); + EM_ASM ({ - MONO.mono_wasm_add_dbg_command_received ($0, $1, $2); - }, id, buf.buf, buf.p-buf.buf); + MONO.mono_wasm_add_dbg_command_received ($0, $1, $2, $3); + }, error == MDBGPROT_ERR_NONE, id, buf.buf, buf.p-buf.buf); buffer_free (&buf); return TRUE; @@ -1697,7 +1697,7 @@ static gboolean receive_debugger_agent_message (void *data, int len) { EM_ASM ({ - MONO.mono_wasm_add_dbg_command_received (-1, $0, $1); + MONO.mono_wasm_add_dbg_command_received (1, -1, $0, $1); }, data, len); mono_wasm_fire_debugger_agent_message (); return FALSE; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 7fed466bcbe86..5e6f47f19f0a4 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -463,15 +463,6 @@ public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool e valueTypeVarName = varName; valueTypeAutoExpand = expand_properties; } - public bool HasFieldWithSameName(string propName) - { - foreach (var field in valueTypeJson) - { - if (field["name"].Value().Equals(propName)) - return true; - } - return false; - } } internal class MonoSDBHelper { @@ -502,11 +493,9 @@ internal async Task SendDebuggerAgentCommand(SessionId session { Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); if (res.IsErr) { - Console.WriteLine(res); - Console.WriteLine("has error"); - return null; + throw new Exception("SendDebuggerAgentCommand Error"); } - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); return ret_debugger_cmd_reader; @@ -721,7 +710,6 @@ public async Task GetArrayLength(SessionId sessionId, int object_id, Cancel var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(object_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ARRAY_REF, (int) CmdArray.GET_LENGTH, command_params, token); var length = ret_debugger_cmd_reader.ReadInt32(); length = ret_debugger_cmd_reader.ReadInt32(); @@ -765,29 +753,28 @@ public async Task InvokeMethod(SessionId sessionId, byte[] valueTypeBuf command_params_writer.Write(valueTypeBuffer); command_params_writer.Write(0); Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.InvokeMethod(Convert.ToBase64String(parms.ToArray())), token); - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); - if (newBytes.Length == 0) + if (res.IsErr) { return null; + } + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, token); } - - public async Task GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token) + public async Task CreateJArrayForProperties(SessionId sessionId, int typeId, byte[] object_buffer, JArray attributes, bool isAutoExpandable, string objectId, CancellationToken token) { - var valueType = valueTypes[valueTypeId]; - JArray valueTypeFields = valueType.valueTypeJsonProps; - var ret = new List(); + JArray ret = new JArray(); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write(valueType.typeId); + command_params_writer.Write(typeId); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); var nProperties = ret_debugger_cmd_reader.ReadInt32(); for (int i = 0 ; i < nProperties; i++) { ret_debugger_cmd_reader.ReadInt32(); //propertyId + string propertyNameStr = ret_debugger_cmd_reader.ReadString(); var getMethodId = ret_debugger_cmd_reader.ReadInt32(); ret_debugger_cmd_reader.ReadInt32(); //setmethod @@ -795,11 +782,11 @@ public async Task GetPropertiesValuesOfValueType(SessionId sessionId, in if (await MethodIsStatic(sessionId, getMethodId, token)) continue; JObject propRet = null; - if (valueType.HasFieldWithSameName(propertyNameStr)) + if (attributes.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any()) continue; - if (valueType.valueTypeAutoExpand) + if (isAutoExpandable) { - propRet = await InvokeMethod(sessionId, valueType.valueTypeBuffer, getMethodId, propertyNameStr, token); + propRet = await InvokeMethod(sessionId, object_buffer, getMethodId, propertyNameStr, token); } else { @@ -807,16 +794,22 @@ public async Task GetPropertiesValuesOfValueType(SessionId sessionId, in get = new { type = "function", - objectId = "dotnet:valuetype:" + valueType.typeId + ":method_id:" + getMethodId, + objectId = $"{objectId}:method_id:{getMethodId}", className = "Function", description = "get " + propertyNameStr + " ()", }, name = propertyNameStr }); } - valueTypeFields.Add(propRet); + ret.Add(propRet); } - return valueTypeFields; + return ret; + } + public async Task GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token) + { + var valueType = valueTypes[valueTypeId]; + var properties = await CreateJArrayForProperties(sessionId, valueType.typeId, valueType.valueTypeBuffer, valueType.valueTypeJson, valueType.valueTypeAutoExpand, $"dotnet:valuetype:{valueType.typeId}", token); + return properties; } public bool AutoExpandable(string className) { @@ -1203,7 +1196,6 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); MonoBinaryReader ret_debugger_cmd_reader = null; - command_params_writer.Write(thread_id); command_params_writer.Write(frame_id); command_params_writer.Write(var_ids.Length); @@ -1212,6 +1204,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me command_params_writer.Write(var.Index); } + if (await IsAsyncMethod(sessionId, method.DebuggerId, token)) { ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); @@ -1248,7 +1241,6 @@ public async Task GetValueTypeValues(SessionId sessionId, int valueTypeI { if (valueTypes[valueTypeId].valueTypeJsonProps == null) { - valueTypes[valueTypeId].valueTypeJsonProps = new JArray(); valueTypes[valueTypeId].valueTypeJsonProps = await GetPropertiesValuesOfValueType(sessionId, valueTypeId, token); } return new JArray(valueTypes[valueTypeId].valueTypeJson.Union(valueTypes[valueTypeId].valueTypeJsonProps)); @@ -1331,7 +1323,8 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, Can var fieldValue = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, field.Name, token); objectFields.Add(fieldValue); } - return objectFields; + var props = await CreateJArrayForProperties(sessionId, typeId, Array.Empty(), objectFields, false, $"dotnet:object:{objectId}", token); + return new JArray(objectFields.Union(props)); } } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index 826dc212d1525..717fc9eaac05d 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -687,7 +687,6 @@ internal async Task CheckValue(JToken actual_val, JToken exp_val, string label) var exp_val_str = jp.Value.Value(); bool null_or_empty_exp_val = String.IsNullOrEmpty(exp_val_str); - var actual_field_val = actual_val?.Values()?.FirstOrDefault(a_jp => a_jp.Name == jp.Name); var actual_field_val_str = actual_field_val?.Value?.Value(); if (null_or_empty_exp_val && String.IsNullOrEmpty(actual_field_val_str)) diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index d56700f94ce9f..d26fc0a9e3be1 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -814,12 +814,15 @@ var MonoSupportLib = { return vars; }, - mono_wasm_add_dbg_command_received: function(id, buffer, buffer_len) { + mono_wasm_add_dbg_command_received: function(res_ok, id, buffer, buffer_len) { const assembly_data = new Uint8Array(Module.HEAPU8.buffer, buffer, buffer_len); const base64String = MONO._base64Converter.toBase64StringImpl(assembly_data); const buffer_obj = { - id, - value: base64String + res_ok, + res: { + id, + value: base64String + } } MONO.commands_received = buffer_obj; }, @@ -828,12 +831,12 @@ var MonoSupportLib = { { const dataHeap = new Uint8Array (Module.HEAPU8.buffer, command_parameters, command_parameters.length); dataHeap.set (new Uint8Array (this._base64_to_uint8 (command_parameters))); - let res_ok = this._c_fn_table.mono_wasm_invoke_method_debugger_agent_wrapper (dataHeap.byteOffset, command_parameters.length); - let res = MONO.commands_received; + this._c_fn_table.mono_wasm_invoke_method_debugger_agent_wrapper (dataHeap.byteOffset, command_parameters.length); + let { res_ok, res } = MONO.commands_received; MONO.commands_received = null; - if (res_ok) { - return { res_ok, res }; - } + if (!res_ok) + throw new Error (`Failed on mono_wasm_invoke_method_debugger_agent`); + return res; }, mono_wasm_send_dbg_command: function (id, command_set, command, command_parameters) @@ -841,20 +844,23 @@ var MonoSupportLib = { const dataHeap = new Uint8Array (Module.HEAPU8.buffer, command_parameters, command_parameters.length); dataHeap.set (new Uint8Array (this._base64_to_uint8 (command_parameters))); - let res_ok = this._c_fn_table.mono_wasm_send_dbg_command_wrapper (id, command_set, command, dataHeap.byteOffset, command_parameters.length); + this._c_fn_table.mono_wasm_send_dbg_command_wrapper (id, command_set, command, dataHeap.byteOffset, command_parameters.length); - let res = MONO.commands_received; + let { res_ok, res } = MONO.commands_received; MONO.commands_received = null; - if (res_ok) { - return { res_ok, res }; - } + if (!res_ok) + throw new Error (`Failed on mono_wasm_send_dbg_command`); + return res; + }, mono_wasm_get_dbg_command_info: function () { - let res = MONO.commands_received; + let { res_ok, res } = MONO.commands_received; MONO.commands_received = null; - return { res }; + if (!res_ok) + throw new Error (`Failed on mono_wasm_get_dbg_command_info`); + return res; }, // @var_list: [ { index: , name: }, .. ] @@ -1331,7 +1337,7 @@ var MonoSupportLib = { if (fn_res === undefined) return { type: "undefined" }; - if (fn_res.res.value !== undefined ) { + if (fn_res.value !== undefined ) { return fn_res; } From 6585dce9ce4231b291e9a677b347014d18d27779 Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 17 May 2021 11:37:47 -0300 Subject: [PATCH 13/48] Implementing callfunctionon object. Failed: 248, Passed: 243 --- src/mono/mono/mini/debugger-agent.c | 6 +- src/mono/mono/mini/debugger-protocol.h | 3 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 107 ++++++++++++------ .../BrowserDebugProxy/MonoSDBHelper.cs | 64 ++++++++++- src/mono/wasm/runtime/library_mono.js | 19 ++-- 5 files changed, 148 insertions(+), 51 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 41e506dd598aa..ef265413ac90d 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -8302,7 +8302,11 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g switch (command) { case CMD_METHOD_GET_NAME: { buffer_add_string (buf, method->name); - break; + break; + } + case MDBGPROT_CMD_METHOD_GET_NAME_FULL: { + buffer_add_string (buf, mono_method_full_name (method, FALSE)); + break; } case MDBGPROT_CMD_METHOD_GET_CLASS_TOKEN: { buffer_add_int (buf, m_class_get_type_token (method->klass)); diff --git a/src/mono/mono/mini/debugger-protocol.h b/src/mono/mono/mini/debugger-protocol.h index 29e79d9065345..a12962ed1286c 100644 --- a/src/mono/mono/mini/debugger-protocol.h +++ b/src/mono/mono/mini/debugger-protocol.h @@ -182,7 +182,8 @@ typedef enum { MDBGPROT_CMD_METHOD_TOKEN = 11, MDBGPROT_CMD_METHOD_ASSEMBLY = 12, MDBGPROT_CMD_METHOD_GET_CLASS_TOKEN = 13, - MDBGPROT_CMD_METHOD_HAS_ASYNC_DEBUG_INFO = 14 + MDBGPROT_CMD_METHOD_HAS_ASYNC_DEBUG_INFO = 14, + MDBGPROT_CMD_METHOD_GET_NAME_FULL = 15 } MdbgProtCmdMethod; typedef enum { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index a9998a200b87a..a98b7fcada73a 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -409,8 +409,6 @@ protected override async Task AcceptCommand(MessageId id, string method, J } case "DotnetDebugger.getMethodLocation": { - Console.WriteLine("set-breakpoint-by-method: " + id + " " + args); - DebugStore store = await RuntimeReady(id, token); string aname = args["assemblyName"]?.Value(); string typeName = args["typeName"]?.Value(); @@ -466,6 +464,7 @@ protected override async Task AcceptCommand(MessageId id, string method, J } case "Runtime.callFunctionOn": { + if (!DotnetObjectId.TryParse(args["objectId"], out DotnetObjectId objectId)) return false; @@ -481,13 +480,42 @@ protected override async Task AcceptCommand(MessageId id, string method, J { args["details"] = await sdbHelper.GetValueTypeProxy(id, int.Parse(objectId.Value), token); Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); - var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); - ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "seila", token); - /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ - res = Result.OkFromObject(new { result = obj["value"]}); + if (res.IsErr) + return false; + if (res.Value?["result"]?["value"]?["value"] != null) + { + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadByte(); //number of objects returned. + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", token); + /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ + res = Result.OkFromObject(new { result = obj["value"]}); + SendResponse(id, res, token); + return true; + } + res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + SendResponse(id, res, token); + return true; + } + if (objectId.Scheme == "object") + { + args["details"] = await sdbHelper.GetObjectProxy(id, int.Parse(objectId.Value), token); + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + if (res.IsErr) + return false; + if (res.Value?["result"]?["value"]?["value"] != null) + { + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadByte(); //number of objects returned. + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", token); + res = Result.OkFromObject(new { result = obj["value"]}); + SendResponse(id, res, token); + return true; + } + res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); SendResponse(id, res, token); return true; @@ -529,29 +557,34 @@ private async Task OnSetVariableValue(MessageId id, int scopeId, string va private async Task RuntimeGetProperties(MessageId id, DotnetObjectId objectId, JToken args, CancellationToken token) { - if (objectId.Scheme == "scope") - { - return await GetScopeProperties(id, int.Parse(objectId.Value), token); - } - if (objectId.Scheme == "valuetype") - { - var ret = await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), token); - Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); - return res2; - } - if (objectId.Scheme == "array") - { - var ret = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); - Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); - return res2; + try { + if (objectId.Scheme == "scope") + { + return await GetScopeProperties(id, int.Parse(objectId.Value), token); + } + if (objectId.Scheme == "valuetype") + { + var ret = await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), token); + Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); + return res2; + } + if (objectId.Scheme == "array") + { + var ret = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); + Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); + return res2; + } + if (objectId.Scheme == "object") + { + var ret = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, token); + Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); + return res2; + } } - if (objectId.Scheme == "object") - { - var ret = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), token); - Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); + catch (Exception) { + Result res2 = Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); return res2; } - Result res = Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); return res; } @@ -598,8 +631,10 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec JObject data = null; string reason = "other";//other means breakpoint ExecutionContext context = GetContext(sessionId); - - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["res"]?["value"]?.Value()); + if (res.IsErr) { + return false; + } + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); ret_debugger_cmd_reader.ReadBytes(11); //skip HEADER_LEN @@ -641,8 +676,13 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec AssemblyInfo asm = store.GetAssemblyByName(assembly_name); if (asm == null) { - Log("debug", $"Unable to find assembly: {assembly_name}"); - continue; + assembly_name = await sdbHelper.GetAssemblyNameFull(sessionId, assembly_id, token); //maybe is a lazy loaded assembly + asm = store.GetAssemblyByName(assembly_name); + if (asm == null) + { + Log("debug", $"Unable to find assembly: {assembly_name}"); + continue; + } } MethodInfo method = asm.GetMethodByToken(method_token); @@ -998,7 +1038,6 @@ private async Task OnSourceFileAdded(SessionId sessionId, SourceFile source, Exe { JObject scriptSource = JObject.FromObject(source.ToScriptSource(context.Id, context.AuxData)); Log("debug", $"sending {source.Url} {context.Id} {sessionId.sessionId}"); - SendEvent(sessionId, "Debugger.scriptParsed", scriptSource, token); foreach (var req in context.BreakpointRequests.Values) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 5e6f47f19f0a4..3e9508715467a 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -205,7 +205,8 @@ internal enum CmdMethod { TOKEN = 11, ASSEMBLY = 12, CLASS_TOKEN = 13, - ASYNC_DEBUG_INFO = 14 + ASYNC_DEBUG_INFO = 14, + GET_NAME_FULL = 15 } internal enum CmdType { @@ -551,14 +552,27 @@ public async Task GetAssemblyName(SessionId sessionId, int assembly_id, return ret_debugger_cmd_reader.ReadString(); } + + public async Task GetAssemblyNameFull(SessionId sessionId, int assembly_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(assembly_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_NAME, command_params, token); + var name = ret_debugger_cmd_reader.ReadString(); + return name.Remove(name.IndexOf(",")) + ".dll"; + } + public async Task GetMethodName(SessionId sessionId, int method_id, CancellationToken token) { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(method_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME, command_params, token); - return ret_debugger_cmd_reader.ReadString(); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME_FULL, command_params, token); + var methodName = ret_debugger_cmd_reader.ReadString(); + return methodName.Substring(methodName.IndexOf(":")+1); } public async Task MethodIsStatic(SessionId sessionId, int method_id, CancellationToken token) @@ -1210,7 +1224,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); ret_debugger_cmd_reader.ReadByte(); //ignore type var objectId = ret_debugger_cmd_reader.ReadInt32(); - var asyncLocals = await GetObjectValues(sessionId, objectId, token); + var asyncLocals = await GetObjectValues(sessionId, objectId, true, token); asyncLocals = new JArray(asyncLocals.Where( asyncLocal => !asyncLocal["name"].Value().Contains("<>"))); foreach (var asyncLocal in asyncLocals) { @@ -1252,7 +1266,6 @@ public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId return valueTypes[valueTypeId].valueTypeProxy; valueTypes[valueTypeId].valueTypeProxy = new JArray(valueTypes[valueTypeId].valueTypeJson); - var ret = new List(); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(valueTypes[valueTypeId].typeId); @@ -1301,7 +1314,7 @@ public async Task GetArrayValues(SessionId sessionId, int arrayId, Cance return array; } - public async Task GetObjectValues(SessionId sessionId, int objectId, CancellationToken token) + public async Task GetObjectValues(SessionId sessionId, int objectId, bool withProperties, CancellationToken token) { var typeId = await GetTypeIdFromObject(sessionId, objectId, token); var fields = await GetTypeFields(sessionId, typeId, token); @@ -1323,8 +1336,47 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, Can var fieldValue = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, field.Name, token); objectFields.Add(fieldValue); } + + if (!withProperties) + return objectFields; + var props = await CreateJArrayForProperties(sessionId, typeId, Array.Empty(), objectFields, false, $"dotnet:object:{objectId}", token); return new JArray(objectFields.Union(props)); } + + public async Task GetObjectProxy(SessionId sessionId, int objectId, CancellationToken token) + { + var ret = await GetObjectValues(sessionId, objectId, false, token); + var typeId = await GetTypeIdFromObject(sessionId, objectId, token); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(typeId); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); + var nProperties = ret_debugger_cmd_reader.ReadInt32(); + + for (int i = 0 ; i < nProperties; i++) + { + ret_debugger_cmd_reader.ReadInt32(); //propertyId + string propertyNameStr = ret_debugger_cmd_reader.ReadString(); + + var getMethodId = ret_debugger_cmd_reader.ReadInt32(); + ret_debugger_cmd_reader.ReadInt32(); //setmethod + ret_debugger_cmd_reader.ReadInt32(); //attrs + if (await MethodIsStatic(sessionId, getMethodId, token)) + continue; + var command_params_to_proxy = new MemoryStream(); + var command_params_writer_to_proxy = new MonoBinaryWriter(command_params_to_proxy); + command_params_writer_to_proxy.Write(getMethodId); + command_params_writer_to_proxy.Write((byte)ElementType.Class); + command_params_writer_to_proxy.Write(objectId); + command_params_writer_to_proxy.Write(0); + ret.Add(JObject.FromObject(new { + get = Convert.ToBase64String(command_params_to_proxy.ToArray()), + name = propertyNameStr + })); + } + return ret; + } } } diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index d26fc0a9e3be1..fbd447d0ff95e 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -1340,24 +1340,25 @@ var MonoSupportLib = { if (fn_res.value !== undefined ) { return fn_res; } - - if (fn_res === null || (fn_res.subtype === 'null' && fn_res.value === undefined)) { + return { type: "object", className: "Object", description: "Object", objectId: objId }; + /*if (fn_res === null || (fn_res.subtype === 'null' && fn_res.value === undefined)) { return fn_res; - } + }*/ - // primitive type + /*// primitive type if (Object (fn_res) !== fn_res) - return fn_res; + return fn_res;*/ + /* // return .value, if it is a primitive type if (fn_res.value !== undefined && Object (fn_res.value.value) !== fn_res.value.value) return fn_res.value; if (request.returnByValue) - return {type: "object", value: fn_res}; + return {type: "object", value: fn_res};*/ - const fn_res_id = this._cache_call_function_res (fn_res); - if (Object.getPrototypeOf (fn_res) == Array.prototype) { + //const fn_res_id = this._cache_call_function_res (fn_res); + /*if (Object.getPrototypeOf (fn_res) == Array.prototype) { return { type: "object", subtype: "array", @@ -1367,7 +1368,7 @@ var MonoSupportLib = { }; } else { return { type: "object", className: "Object", description: "Object", objectId: fn_res_id }; - } + }*/ }, _clear_per_step_state: function () { From adbe8de9726fea204251f423e88938640fb6e535 Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 17 May 2021 13:44:01 -0300 Subject: [PATCH 14/48] Implementing get pointer values. Failed: 243, Passed: 248 --- .../debugger/BrowserDebugProxy/MonoProxy.cs | 6 ++ .../BrowserDebugProxy/MonoSDBHelper.cs | 59 ++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index a98b7fcada73a..4fe4b8ead6279 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -580,6 +580,12 @@ private async Task RuntimeGetProperties(MessageId id, DotnetObjectId obj Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); return res2; } + if (objectId.Scheme == "pointer") + { + var ret = new JArray(await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token)); + Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); + return res2; + } } catch (Exception) { Result res2 = Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 3e9508715467a..b570f1aad16d2 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -191,6 +191,10 @@ internal enum CmdModule { APPLY_CHANGES = 2, } + internal enum CmdPointer{ + GET_VALUE = 1 + } + internal enum CmdMethod { GET_NAME = 1, GET_DECLARING_TYPE = 2, @@ -465,9 +469,21 @@ public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool e valueTypeAutoExpand = expand_properties; } } + internal class PointerValue + { + public int typeId; + public string varName; + public PointerValue(int typeId, string varName) + { + this.typeId = typeId; + this.varName = varName; + } + + } internal class MonoSDBHelper { private Dictionary valueTypes = new Dictionary(); + private Dictionary pointerValues = new Dictionary(); private static int valuetype_id; private static int cmd_id; private static int GetId() {return cmd_id++;} @@ -679,6 +695,7 @@ public string ReplaceCommonClassNames(string className) className = className.Replace("System.Char", "char"); className = className.Replace("System.Int32", "int"); className = className.Replace("System.Object", "object"); + className = className.Replace("System.Void", "void"); return className; } public async Task GetTypeName(SessionId sessionId, int type_id, CancellationToken token) @@ -819,6 +836,16 @@ public async Task CreateJArrayForProperties(SessionId sessionId, int typ } return ret; } + public async Task GetPointerContent(SessionId sessionId, long address, CancellationToken token) + { + var ret = new List(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.WriteLong(address); + command_params_writer.Write(pointerValues[address].typeId); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.POINTER, (int) CmdPointer.GET_VALUE, command_params, token); + return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "*" + pointerValues[address].varName, token); + } public async Task GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token) { var valueType = valueTypes[valueTypeId]; @@ -1017,7 +1044,37 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo // FIXME: The client and the debuggee might have different word sizes return new JObject{{"Type", "void"}}; case ElementType.Ptr: - return new JObject{{"Type", "void"}}; + { + string type; + string value; + long valueAddress = ret_debugger_cmd_reader.ReadLong(); + var typeId = ret_debugger_cmd_reader.ReadInt32(); + var className = "(" + await GetTypeName(sessionId, typeId, token) + ")"; + if (valueAddress != 0 && className != "(void*)") + { + type = "object"; + value = className; + pointerValues[valueAddress] = new PointerValue(typeId, name); + } + else + { + type = "symbol"; + value = className + " " + valueAddress; + } + return JObject.FromObject(new { + value = new + { + type, + __custom_type = "pointer", + value = value, + description = value, + className, + objectId = $"dotnet:pointer:{valueAddress}" + }, + writable = false, + name + }); + } case ElementType.String: { var string_id = ret_debugger_cmd_reader.ReadInt32(); From 7be985cef9f1621a1bd5b0ee3b104e15eb152ddc Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 17 May 2021 14:57:21 -0300 Subject: [PATCH 15/48] Fixing pointer values and implement call on function with pointers. Failed: 226, Passed: 265 --- .../debugger/BrowserDebugProxy/MonoProxy.cs | 22 +++++++++++++++ .../BrowserDebugProxy/MonoSDBHelper.cs | 27 ++++++++++++------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 4fe4b8ead6279..5af2d7830effc 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -519,6 +519,28 @@ protected override async Task AcceptCommand(MessageId id, string method, J SendResponse(id, res, token); return true; + } + if (objectId.Scheme == "pointer") + { + args["details"] = await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token); + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + if (res.IsErr) + return false; + if (res.Value?["result"]?["value"]?["value"] != null) + { + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadByte(); //number of objects returned. + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", token); + res = Result.OkFromObject(new { result = obj["value"]}); + SendResponse(id, res, token); + return true; + } + res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + SendResponse(id, res, token); + return true; + } /*if (objectId.Scheme == "array") { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index b570f1aad16d2..18e393ff941c8 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -471,10 +471,12 @@ public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool e } internal class PointerValue { + public long address; public int typeId; public string varName; - public PointerValue(int typeId, string varName) + public PointerValue(long address, int typeId, string varName) { + this.address = address; this.typeId = typeId; this.varName = varName; } @@ -483,8 +485,8 @@ public PointerValue(int typeId, string varName) internal class MonoSDBHelper { private Dictionary valueTypes = new Dictionary(); - private Dictionary pointerValues = new Dictionary(); - private static int valuetype_id; + private Dictionary pointerValues = new Dictionary(); + private static int debugger_object_id; private static int cmd_id; private static int GetId() {return cmd_id++;} private MonoProxy proxy; @@ -836,15 +838,18 @@ public async Task CreateJArrayForProperties(SessionId sessionId, int typ } return ret; } - public async Task GetPointerContent(SessionId sessionId, long address, CancellationToken token) + public async Task GetPointerContent(SessionId sessionId, int pointerId, CancellationToken token) { var ret = new List(); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.WriteLong(address); - command_params_writer.Write(pointerValues[address].typeId); + command_params_writer.WriteLong(pointerValues[pointerId].address); + command_params_writer.Write(pointerValues[pointerId].typeId); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.POINTER, (int) CmdPointer.GET_VALUE, command_params, token); - return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "*" + pointerValues[address].varName, token); + var varName = pointerValues[pointerId].varName; + if (int.TryParse(varName, out _)) + varName = $"[{varName}]"; + return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "*" + varName, token); } public async Task GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token) { @@ -1050,11 +1055,13 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo long valueAddress = ret_debugger_cmd_reader.ReadLong(); var typeId = ret_debugger_cmd_reader.ReadInt32(); var className = "(" + await GetTypeName(sessionId, typeId, token) + ")"; + int pointerId = 0; if (valueAddress != 0 && className != "(void*)") { + pointerId = Interlocked.Increment(ref debugger_object_id); type = "object"; value = className; - pointerValues[valueAddress] = new PointerValue(typeId, name); + pointerValues[pointerId] = new PointerValue(valueAddress, typeId, name); } else { @@ -1069,7 +1076,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo value = value, description = value, className, - objectId = $"dotnet:pointer:{valueAddress}" + objectId = $"dotnet:pointer:{pointerId}" }, writable = false, name @@ -1161,7 +1168,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo } long endPos = ret_debugger_cmd_reader.BaseStream.Position; - var valueTypeId = Interlocked.Increment(ref valuetype_id); + var valueTypeId = Interlocked.Increment(ref debugger_object_id); ret_debugger_cmd_reader.BaseStream.Position = initialPos; byte[] valueTypeBuffer = new byte[endPos - initialPos]; From 8f886122c4887cc4c1956905af60ccb17935638c Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 19 May 2021 00:36:33 -0300 Subject: [PATCH 16/48] Reimplement call function on, and implement set values. Failed: 192, Passed: 299 --- .../BrowserDebugProxy/DevToolsHelper.cs | 9 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 14 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 129 +++++++++++++++--- src/mono/wasm/runtime/library_mono.js | 113 +++++---------- 4 files changed, 153 insertions(+), 112 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index 8c87c347d821f..f9cb8391a2804 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -180,11 +180,6 @@ internal class MonoCommands public static MonoCommands GetLoadedFiles() => new MonoCommands("MONO.mono_wasm_get_loaded_files()"); - public static MonoCommands SetVariableValue(int scopeId, int index, string name, string newValue) - { - return new MonoCommands($"MONO.mono_wasm_set_variable_value({scopeId}, {index}, '{name}', '{newValue}')"); - } - public static MonoCommands EvaluateMemberAccess(int scopeId, string expr, params VarInfo[] vars) { var var_ids = vars.Select(v => new { index = v.Index, name = v.Name }).ToArray(); @@ -196,9 +191,9 @@ public static MonoCommands SendDebuggerAgentCommand(int id, int command_set, int return new MonoCommands($"MONO.mono_wasm_send_dbg_command ({id}, {command_set}, {command},'{command_parameters}')"); } - public static MonoCommands InvokeMethod(string command_parameters) + public static MonoCommands SendDebuggerAgentCommandWithParms(int id, int command_set, int command, string command_parameters, int len, int type, string parm) { - return new MonoCommands($"MONO.mono_wasm_invoke_method_debugger_agent ('{command_parameters}')"); + return new MonoCommands($"MONO.mono_wasm_send_dbg_command_with_parms ({id}, {command_set}, {command},'{command_parameters}', {len}, {type}, '{parm}')"); } public static MonoCommands ReleaseObject(DotnetObjectId objectId) => new MonoCommands($"MONO.mono_wasm_release_object('{objectId}')"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 5af2d7830effc..86708196cffe4 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -542,14 +542,14 @@ protected override async Task AcceptCommand(MessageId id, string method, J return true; } - /*if (objectId.Scheme == "array") + if (objectId.Scheme == "array") { - args["details"] = await sdbHelper.GetArrayProxy(id, int.Parse(objectId.Value), token); + args["details"] = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); - Console.WriteLine(res); SendResponse(id, res, token); - }*/ + return true; + } return false; } } @@ -569,8 +569,8 @@ private async Task OnSetVariableValue(MessageId id, int scopeId, string va var varToSetValue = varIds.FirstOrDefault(v => v.Name == varName); if (varToSetValue == null) return false; - Result res = await SendMonoCommand(id, MonoCommands.SetVariableValue(scopeId, varToSetValue.Index, varName, varValue["value"].Value()), token); - if (res.IsOk) + var res = await sdbHelper.SetVariableValue(id, ctx.ThreadId, scopeId, varToSetValue.Index, varValue["value"].Value(), token); + if (res) SendResponse(id, Result.Ok(new JObject()), token); else SendResponse(id, Result.Err($"Unable to set '{varValue["value"].Value()}' to variable '{varName}'"), token); @@ -598,7 +598,7 @@ private async Task RuntimeGetProperties(MessageId id, DotnetObjectId obj } if (objectId.Scheme == "object") { - var ret = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, token); + var ret = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, false, token); Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); return res2; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 18e393ff941c8..0c5ec83431e41 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -520,6 +520,18 @@ internal async Task SendDebuggerAgentCommand(SessionId session return ret_debugger_cmd_reader; } + internal async Task SendDebuggerAgentCommandWithParms(SessionId sessionId, int command_set, int command, MemoryStream parms, int type, string extraParm, CancellationToken token) + { + Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommandWithParms(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray()), parms.ToArray().Length, type, extraParm), token); + if (res.IsErr) { + throw new Exception("SendDebuggerAgentCommandWithParms Error"); + } + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); + return ret_debugger_cmd_reader; + } + public async Task GetMethodToken(SessionId sessionId, int method_id, CancellationToken token) { var command_params = new MemoryStream(); @@ -785,13 +797,7 @@ public async Task InvokeMethod(SessionId sessionId, byte[] valueTypeBuf command_params_writer.Write(method_id); command_params_writer.Write(valueTypeBuffer); command_params_writer.Write(0); - Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.InvokeMethod(Convert.ToBase64String(parms.ToArray())), token); - if (res.IsErr) { - return null; - } - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); - var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.INVOKE_METHOD, parms, token); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, token); } @@ -1288,7 +1294,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); ret_debugger_cmd_reader.ReadByte(); //ignore type var objectId = ret_debugger_cmd_reader.ReadInt32(); - var asyncLocals = await GetObjectValues(sessionId, objectId, true, token); + var asyncLocals = await GetObjectValues(sessionId, objectId, true, false, token); asyncLocals = new JArray(asyncLocals.Where( asyncLocal => !asyncLocal["name"].Value().Contains("<>"))); foreach (var asyncLocal in asyncLocals) { @@ -1353,10 +1359,16 @@ public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId command_params_writer_to_proxy.Write(valueTypes[valueTypeId].valueTypeBuffer); command_params_writer_to_proxy.Write(0); valueTypes[valueTypeId].valueTypeProxy.Add(JObject.FromObject(new { - get = Convert.ToBase64String(command_params_to_proxy.ToArray()), + get = JObject.FromObject(new { + commandSet = CommandSet.VM, + command = CmdVM.INVOKE_METHOD, + buffer = Convert.ToBase64String(command_params_to_proxy.ToArray()), + length = command_params_to_proxy.ToArray().Length + }), name = propertyNameStr })); } + //Console.WriteLine("GetValueTypeProxy - " + valueTypes[valueTypeId].valueTypeProxy); return valueTypes[valueTypeId].valueTypeProxy; } @@ -1378,7 +1390,7 @@ public async Task GetArrayValues(SessionId sessionId, int arrayId, Cance return array; } - public async Task GetObjectValues(SessionId sessionId, int objectId, bool withProperties, CancellationToken token) + public async Task GetObjectValues(SessionId sessionId, int objectId, bool withProperties, bool withSetter, CancellationToken token) { var typeId = await GetTypeIdFromObject(sessionId, objectId, token); var fields = await GetTypeFields(sessionId, typeId, token); @@ -1397,7 +1409,27 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, boo foreach (var field in fields) { + long initialPos = ret_debugger_cmd_reader.BaseStream.Position; + int valtype = ret_debugger_cmd_reader.ReadByte(); + ret_debugger_cmd_reader.BaseStream.Position = initialPos; var fieldValue = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, field.Name, token); + if (withSetter) + { + var command_params_to_set = new MemoryStream(); + var command_params_writer_to_set = new MonoBinaryWriter(command_params_to_set); + command_params_writer_to_set.Write(objectId); + command_params_writer_to_set.Write(1); + command_params_writer_to_set.Write(field.Id); + + fieldValue.Add("set", JObject.FromObject(new { + commandSet = CommandSet.OBJECT_REF, + command = CmdObject.REF_SET_VALUES, + buffer = Convert.ToBase64String(command_params_to_set.ToArray()), + valtype, + length = command_params_to_set.ToArray().Length + })); + } + objectFields.Add(fieldValue); } @@ -1410,7 +1442,7 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, boo public async Task GetObjectProxy(SessionId sessionId, int objectId, CancellationToken token) { - var ret = await GetObjectValues(sessionId, objectId, false, token); + var ret = await GetObjectValues(sessionId, objectId, false, true, token); var typeId = await GetTypeIdFromObject(sessionId, objectId, token); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); @@ -1423,24 +1455,77 @@ public async Task GetObjectProxy(SessionId sessionId, int objectId, Canc { ret_debugger_cmd_reader.ReadInt32(); //propertyId string propertyNameStr = ret_debugger_cmd_reader.ReadString(); - var getMethodId = ret_debugger_cmd_reader.ReadInt32(); - ret_debugger_cmd_reader.ReadInt32(); //setmethod + var setMethodId = ret_debugger_cmd_reader.ReadInt32(); //setmethod ret_debugger_cmd_reader.ReadInt32(); //attrs - if (await MethodIsStatic(sessionId, getMethodId, token)) + if (ret.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any()) + { + var attr = ret.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).First(); + + var command_params_to_set = new MemoryStream(); + var command_params_writer_to_set = new MonoBinaryWriter(command_params_to_set); + command_params_writer_to_set.Write(setMethodId); + command_params_writer_to_set.Write((byte)ElementType.Class); + command_params_writer_to_set.Write(objectId); + command_params_writer_to_set.Write(1); + + attr["set"] = JObject.FromObject(new { + commandSet = CommandSet.VM, + command = CmdVM.INVOKE_METHOD, + buffer = Convert.ToBase64String(command_params_to_set.ToArray()), + valtype = attr["set"]["valtype"], + length = command_params_to_set.ToArray().Length + }); continue; - var command_params_to_proxy = new MemoryStream(); - var command_params_writer_to_proxy = new MonoBinaryWriter(command_params_to_proxy); - command_params_writer_to_proxy.Write(getMethodId); - command_params_writer_to_proxy.Write((byte)ElementType.Class); - command_params_writer_to_proxy.Write(objectId); - command_params_writer_to_proxy.Write(0); - ret.Add(JObject.FromObject(new { - get = Convert.ToBase64String(command_params_to_proxy.ToArray()), + } + else + { + var command_params_to_get = new MemoryStream(); + var command_params_writer_to_get = new MonoBinaryWriter(command_params_to_get); + command_params_writer_to_get.Write(getMethodId); + command_params_writer_to_get.Write((byte)ElementType.Class); + command_params_writer_to_get.Write(objectId); + command_params_writer_to_get.Write(0); + + ret.Add(JObject.FromObject(new { + get = JObject.FromObject(new { + commandSet = CommandSet.VM, + command = CmdVM.INVOKE_METHOD, + buffer = Convert.ToBase64String(command_params_to_get.ToArray()), + length = command_params_to_get.ToArray().Length + }), name = propertyNameStr })); + } + if (await MethodIsStatic(sessionId, getMethodId, token)) + continue; } + //Console.WriteLine("GetObjectProxy - " + ret); return ret; } + + public async Task SetVariableValue(SessionId sessionId, int thread_id, int frame_id, int varId, string newValue, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + MonoBinaryReader ret_debugger_cmd_reader = null; + command_params_writer.Write(thread_id); + command_params_writer.Write(frame_id); + command_params_writer.Write(1); + command_params_writer.Write(varId); + JArray locals = new JArray(); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_VALUES, command_params, token); + int etype = ret_debugger_cmd_reader.ReadByte(); + try + { + ret_debugger_cmd_reader = await SendDebuggerAgentCommandWithParms(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.SET_VALUES, command_params, etype, newValue, token); + } + catch (Exception) + { + return false; + } + + return true; + } } } diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index fbd447d0ff95e..22a7a5089235d 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -743,14 +743,6 @@ var MonoSupportLib = { return this._resolve_member_by_name(rootObject, root, parts); }, - mono_wasm_set_variable_value: function (scope, index, name, newValue) { - console.debug (">> mono_wasm_set_variable_value " + name + " - " + newValue); - var ret = this._c_fn_table.mono_wasm_set_variable_on_frame_wrapper(scope, index, name, newValue); - if (ret == false) - throw new Error(`Could not get a value for ${name}`); - return ret; - }, - /** * @param {WasmId} id * @returns {object[]} @@ -827,15 +819,14 @@ var MonoSupportLib = { MONO.commands_received = buffer_obj; }, - mono_wasm_invoke_method_debugger_agent: function (command_parameters) + mono_wasm_send_dbg_command_with_parms: function (id, command_set, command, command_parameters, length, valtype, newvalue) { const dataHeap = new Uint8Array (Module.HEAPU8.buffer, command_parameters, command_parameters.length); dataHeap.set (new Uint8Array (this._base64_to_uint8 (command_parameters))); - this._c_fn_table.mono_wasm_invoke_method_debugger_agent_wrapper (dataHeap.byteOffset, command_parameters.length); + this._c_fn_table.mono_wasm_send_dbg_command_with_parms_wrapper (id, command_set, command, dataHeap.byteOffset, length, valtype, newvalue.toString()); let { res_ok, res } = MONO.commands_received; - MONO.commands_received = null; if (!res_ok) - throw new Error (`Failed on mono_wasm_invoke_method_debugger_agent`); + throw new Error (`Failed on mono_wasm_invoke_method_debugger_agent_with_parms`); return res; }, @@ -847,7 +838,6 @@ var MonoSupportLib = { this._c_fn_table.mono_wasm_send_dbg_command_wrapper (id, command_set, command, dataHeap.byteOffset, command_parameters.length); let { res_ok, res } = MONO.commands_received; - MONO.commands_received = null; if (!res_ok) throw new Error (`Failed on mono_wasm_send_dbg_command`); return res; @@ -857,7 +847,6 @@ var MonoSupportLib = { mono_wasm_get_dbg_command_info: function () { let { res_ok, res } = MONO.commands_received; - MONO.commands_received = null; if (!res_ok) throw new Error (`Failed on mono_wasm_get_dbg_command_info`); return res; @@ -1149,30 +1138,6 @@ var MonoSupportLib = { return this._id_table [objectId]; }, - _get_deref_ptr_value: function (objectId) { - const ptr_args = this._get_id_props (objectId); - if (ptr_args === undefined) - throw new Error (`Unknown pointer id: ${objectId}`); - - if (ptr_args.ptr_addr == 0 || ptr_args.klass_addr == 0) - throw new Error (`Both ptr_addr and klass_addr need to be non-zero, to dereference a pointer. objectId: ${objectId}`); - - const value_addr = new DataView (Module.HEAPU8.buffer).getUint32 (ptr_args.ptr_addr, /* littleEndian */ true); - let { res_ok, res } = this.mono_wasm_get_deref_ptr_value_info (value_addr, ptr_args.klass_addr); - if (!res_ok) - throw new Error (`Failed to dereference pointer ${objectId}`); - - if (res.length > 0) { - if (ptr_args.varName === undefined) - throw new Error (`Bug: no varName found for the pointer. objectId: ${objectId}`); - - res [0].name = `*${ptr_args.varName}`; - } - - res = this._post_process_details (res); - return res; - }, - mono_wasm_get_details: function (objectId, args={}) { let id = this._parse_object_id (objectId, true); @@ -1267,50 +1232,43 @@ var MonoSupportLib = { * @param {string} name property name * @returns {object} return true if it works and false if it doesn't */ - _set_value_on_object: function (objectIdStr, name, newvalue) { - const id = this._parse_object_id (objectIdStr); - if (id === undefined) - throw new Error (`Invalid object id: ${objectIdStr}`); - - let setter_res; - if (id.scheme == 'object') { - if (isNaN (id.o) || id.o < 0) - throw new Error (`Invalid object id: ${objectIdStr}`); - - var ret = this._c_fn_table.mono_wasm_set_value_on_object_wrapper (id.o, name, newvalue); - if (!ret) - throw new Error (`Invoking setter on ${objectIdStr} failed`); - - setter_res = ret; - } - else - throw new Error (`Only object is supported for setters, id: ${objectIdStr}`); - return setter_res; + _set_value_on_object: function (objectIdStr, name, newValue) { + let res = MONO.mono_wasm_raise_debug_event({ + eventName: 'SetValueOnObject', + objectIdStr, + name, + newValue + }); + return true; }, _create_proxy_from_object_id: function (objectId, details) { if (objectId.startsWith ('dotnet:array:')) - return details.map (p => p.value); + { + let ret = details.map (p => p.value); + return ret; + } let proxy = {}; Object.keys (details).forEach (p => { var prop = details [p]; if (prop.get !== undefined) { - // TODO: `set` - Object.defineProperty (proxy, prop.name, - { get () { return MONO.mono_wasm_invoke_method_debugger_agent (prop.get); } } + { get () { return MONO.mono_wasm_send_dbg_command(-1, prop.get.commandSet, prop.get.command, prop.get.buffer, prop.get.length); }, + set: function (newValue) { MONO.mono_wasm_send_dbg_command_with_parms(-1, prop.set.commandSet, prop.set.command, prop.set.buffer, prop.set.length, prop.set.valtype, newValue); return MONO.commands_received.res_ok;}} + ); + } else if (prop.set !== undefined ){ + Object.defineProperty (proxy, + prop.name, + { get () { return prop.value.value; }, + set: function (newValue) { MONO.mono_wasm_send_dbg_command_with_parms(-1, prop.set.commandSet, prop.set.command, prop.set.buffer, prop.set.length, prop.set.valtype, newValue); return MONO.commands_received.res_ok;}} ); } else { proxy [prop.name] = prop.value; } }); - - const handler1 = { - set (obj, prop, newValue) {return MONO._set_value_on_object (objectId, prop, newValue.toString());}, - }; - return new Proxy(proxy, handler1); + return proxy; }, mono_wasm_call_function_on: function (request) { @@ -1401,6 +1359,10 @@ var MonoSupportLib = { this.mono_wasm_set_is_debugger_attached(false); }, + mono_wasm_set_return_value: function (ret) { + MONO.return_value = ret; + }, + _register_c_fn: function (name, ...args) { Object.defineProperty (this._c_fn_table, name + '_wrapper', { value: Module.cwrap (name, ...args) }); }, @@ -1446,16 +1408,15 @@ var MonoSupportLib = { this._call_function_res_cache = {}; this._c_fn_table = {}; - this._register_c_var_fn ('mono_wasm_get_object_properties', 'bool', [ 'number', 'number' ]); - this._register_c_var_fn ('mono_wasm_get_array_values', 'bool', [ 'number', 'number', 'number', 'number' ]); - this._register_c_var_fn ('mono_wasm_invoke_getter_on_object', 'bool', [ 'number', 'string' ]); - this._register_c_var_fn ('mono_wasm_invoke_getter_on_value', 'bool', [ 'number', 'number', 'string' ]); - this._register_c_var_fn ('mono_wasm_get_local_vars', 'bool', [ 'number', 'number', 'number']); - this._register_c_var_fn ('mono_wasm_get_deref_ptr_value', 'bool', [ 'number', 'number']); - this._register_c_fn ('mono_wasm_set_value_on_object', 'bool', [ 'number', 'string', 'string' ]); - this._register_c_fn ('mono_wasm_set_variable_on_frame', 'bool', [ 'number', 'number', 'string', 'string' ]); - this._register_c_fn ('mono_wasm_send_dbg_command', 'bool', [ 'number', 'number', 'number', 'number', 'number' ]); - this._register_c_fn ('mono_wasm_invoke_method_debugger_agent', 'bool', [ 'number', 'number' ]); + this._register_c_var_fn ('mono_wasm_get_object_properties', 'bool', [ 'number', 'number' ]); + this._register_c_var_fn ('mono_wasm_get_array_values', 'bool', [ 'number', 'number', 'number', 'number' ]); + this._register_c_var_fn ('mono_wasm_invoke_getter_on_object', 'bool', [ 'number', 'string' ]); + this._register_c_var_fn ('mono_wasm_invoke_getter_on_value', 'bool', [ 'number', 'number', 'string' ]); + this._register_c_var_fn ('mono_wasm_get_local_vars', 'bool', [ 'number', 'number', 'number']); + this._register_c_fn ('mono_wasm_set_value_on_object', 'bool', [ 'number', 'string', 'string' ]); + this._register_c_fn ('mono_wasm_send_dbg_command', 'bool', [ 'number', 'number', 'number', 'number', 'number' ]); + this._register_c_fn ('mono_wasm_send_dbg_command_with_parms', 'bool', [ 'number', 'number', 'number', 'number', 'number', 'number', 'string' ]); + // DO NOT REMOVE - magic debugger init function if (globalThis.dotnetDebugger) debugger; From 478016d3f2669d9d56b31965493e966905579bec Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 19 May 2021 00:37:00 -0300 Subject: [PATCH 17/48] Failed: 192, Passed: 299 --- src/mono/mono/mini/mini-wasm-debugger.c | 265 ++++-------------------- 1 file changed, 42 insertions(+), 223 deletions(-) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index a9adfadb970d2..5ca0ab67f0ba6 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -47,12 +47,10 @@ EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_object_properties (int object_id, in EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_array_values (int object_id, int start_idx, int count, int gpflags); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_getter_on_object (int object_id, const char* name); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_getter_on_value (void *value, MonoClass *klass, const char *name); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_deref_ptr_value (void *value_addr, MonoClass *klass); EMSCRIPTEN_KEEPALIVE void mono_wasm_set_is_debugger_attached (gboolean is_attached); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_set_variable_on_frame (int scope, int index, const char* name, const char* value); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_set_value_on_object (int object_id, const char* name, const char* value); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_method_debugger_agent (guint8* data, unsigned int size); +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); + //JS functions imported that we use extern void mono_wasm_add_frame (int il_offset, int method_token, int frame_id, const char *assembly_name, const char *method_name); @@ -434,7 +432,7 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) MonoDebugHandle *handle = mono_debug_get_handle (assembly_image); if (handle) { MonoPPDBFile *ppdb = handle->ppdb; - if (!mono_ppdb_is_embedded (ppdb)) { //if it's an embedded pdb we don't need to send pdb extrated to DebuggerProxy. + if (ppdb && !mono_ppdb_is_embedded (ppdb)) { //if it's an embedded pdb we don't need to send pdb extrated to DebuggerProxy. pdb_image = mono_ppdb_get_image (ppdb); mono_wasm_asm_loaded (assembly_image->assembly_name, assembly_image->raw_data, assembly_image->raw_data_len, pdb_image->raw_data, pdb_image->raw_data_len); return; @@ -585,16 +583,6 @@ typedef struct { gboolean found; } FrameDescData; - -typedef struct { - int cur_frame; - int target_frame; - int pos; - const char* new_value; - gboolean found; - gboolean error; -} SetVariableValueData; - /* * this returns a string formatted like * @@ -1254,30 +1242,31 @@ describe_variable (InterpFrame *frame, MonoMethod *method, MonoMethodHeader *hea } static gboolean -decode_value (MonoType *t, guint8 *addr, const char* variableValue) +write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* variableValue) { char* endptr; errno = 0; - switch (t->type) { + buffer_add_byte (buf, type); + switch (type) { case MONO_TYPE_BOOLEAN: if (!strcasecmp (variableValue, "True")) - *(guint8*)addr = 1; + buffer_add_int (buf, 1); else if (!strcasecmp (variableValue, "False")) - *(guint8*)addr = 0; + buffer_add_int (buf, 0); else return FALSE; break; case MONO_TYPE_CHAR: if (strlen (variableValue) > 1) return FALSE; - *(gunichar2*)addr = variableValue [0]; + buffer_add_int (buf, (variableValue [0])); break; case MONO_TYPE_I1: { intmax_t val = strtoimax (variableValue, &endptr, 10); if (errno != 0) return FALSE; if (val >= -128 && val <= 127) - *(gint8*)addr = val; + buffer_add_int (buf, val); else return FALSE; break; @@ -1287,7 +1276,7 @@ decode_value (MonoType *t, guint8 *addr, const char* variableValue) if (errno != 0) return FALSE; if (val >= 0 && val <= 255) - *(guint8*)addr = val; + buffer_add_int (buf, val); else return FALSE; break; @@ -1297,7 +1286,7 @@ decode_value (MonoType *t, guint8 *addr, const char* variableValue) if (errno != 0) return FALSE; if (val >= -32768 && val <= 32767) - *(gint16*)addr = val; + buffer_add_int (buf, val); else return FALSE; break; @@ -1307,7 +1296,7 @@ decode_value (MonoType *t, guint8 *addr, const char* variableValue) if (errno != 0) return FALSE; if (val >= 0 && val <= 65535) - *(guint16*)addr = val; + buffer_add_int (buf, val); else return FALSE; break; @@ -1317,7 +1306,7 @@ decode_value (MonoType *t, guint8 *addr, const char* variableValue) if (errno != 0) return FALSE; if (val >= -2147483648 && val <= 2147483647) - *(gint32*)addr = val; + buffer_add_int (buf, val); else return FALSE; break; @@ -1327,7 +1316,7 @@ decode_value (MonoType *t, guint8 *addr, const char* variableValue) if (errno != 0) return FALSE; if (val >= 0 && val <= 4294967295) - *(guint32*)addr = val; + buffer_add_int (buf, val); else return FALSE; break; @@ -1336,28 +1325,28 @@ decode_value (MonoType *t, guint8 *addr, const char* variableValue) long long val = strtoll (variableValue, &endptr, 10); if (errno != 0) return FALSE; - *(gint64*)addr = val; + buffer_add_long (buf, val); break; } case MONO_TYPE_U8: { long long val = strtoll (variableValue, &endptr, 10); if (errno != 0) return FALSE; - *(guint64*)addr = val; + buffer_add_long (buf, val); break; } case MONO_TYPE_R4: { gfloat val = strtof (variableValue, &endptr); if (errno != 0) return FALSE; - *(gfloat*)addr = val; + buffer_add_int (buf, *((gint32*)(&val))); break; } case MONO_TYPE_R8: { gdouble val = strtof (variableValue, &endptr); if (errno != 0) return FALSE; - *(gdouble*)addr = val; + buffer_add_long (buf, *((guint64*)(&val))); break; } default: @@ -1366,81 +1355,6 @@ decode_value (MonoType *t, guint8 *addr, const char* variableValue) return TRUE; } -static gboolean -set_variable_value_on_frame (MonoStackFrameInfo *info, MonoContext *ctx, gpointer ud) -{ - ERROR_DECL (error); - SetVariableValueData *data = (SetVariableValueData*)ud; - gboolean is_arg = FALSE; - MonoType *t = NULL; - guint8 *val_buf = NULL; - - ++data->cur_frame; - - //skip wrappers - if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) { - return FALSE; - } - - if (data->cur_frame != data->target_frame) - return FALSE; - - data->found = TRUE; - - InterpFrame *frame = (InterpFrame*)info->interp_frame; - MonoMethod *method = frame->imethod->method; - MonoMethodSignature *sig = mono_method_signature_internal (method); - MonoMethodHeader *header = mono_method_get_header_checked (method, error); - - if (!header) { - mono_error_cleanup(error); - data->error = TRUE; - return TRUE; - } - - if (!sig) - goto exit_with_error; - - int pos = data->pos; - - if (pos < 0) { - pos = - pos - 1; - if (pos >= sig->param_count) - goto exit_with_error; - is_arg = TRUE; - t = sig->params [pos]; - } - else { - if (pos >= header->num_locals) - goto exit_with_error; - t = header->locals [pos]; - } - - guint8 *addr; - if (is_arg) - addr = (guint8*)mini_get_interp_callbacks ()->frame_get_arg (frame, pos); - else - addr = (guint8*)mini_get_interp_callbacks ()->frame_get_local (frame, pos); - - val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type_internal (t))); - - if (!decode_value(t, val_buf, data->new_value)) - goto exit_with_error; - - DbgEngineErrorCode errorCode = mono_de_set_interp_var (t, addr, val_buf); - if (errorCode != ERR_NONE) { - goto exit_with_error; - } - - mono_metadata_free_mh (header); - return TRUE; - -exit_with_error: - data->error = TRUE; - mono_metadata_free_mh (header); - return TRUE; -} - static gboolean describe_variables_on_frame (MonoStackFrameInfo *info, MonoContext *ctx, gpointer ud) { @@ -1479,38 +1393,6 @@ describe_variables_on_frame (MonoStackFrameInfo *info, MonoContext *ctx, gpointe mono_metadata_free_mh (header); return TRUE; } - -EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_set_variable_on_frame (int scope, int index, const char* name, const char* value) -{ - if (scope < 0) - return FALSE; - - SetVariableValueData data; - data.target_frame = scope; - data.cur_frame = -1; - data.pos = index; - data.found = FALSE; - data.new_value = value; - data.error = FALSE; - - mono_walk_stack_with_ctx (set_variable_value_on_frame, NULL, MONO_UNWIND_NONE, &data); - return !data.error; -} - -EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_get_deref_ptr_value (void *value_addr, MonoClass *klass) -{ - MonoType *type = m_class_get_byval_arg (klass); - if (type->type != MONO_TYPE_PTR && type->type != MONO_TYPE_FNPTR) { - PRINT_DEBUG_MSG (2, "BUG: mono_wasm_get_deref_ptr_value: Expected to get a ptr type, but got 0x%x\n", type->type); - return FALSE; - } - - mono_wasm_add_properties_var ("deref", -1); - return describe_value (type->data.type, value_addr, GPFLAG_EXPAND_VALUETYPES); -} - //FIXME this doesn't support getting the return value pseudo-var EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_local_vars (int scope, int* pos, int len) @@ -1556,75 +1438,6 @@ mono_wasm_invoke_getter_on_object (int object_id, const char* name) return invoke_getter (obj, mono_object_class (obj), name); } -EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_set_value_on_object (int object_id, const char* name, const char* value) -{ - PRINT_DEBUG_MSG (1, "mono_wasm_set_value_on_object %d, name: %s, value: %s\n", object_id, name, value); - MonoObject *obj = get_object_from_id (object_id); - - if (!obj || !name) { - PRINT_DEBUG_MSG (2, "mono_wasm_set_value_on_object: none of the arguments can be null"); - return FALSE; - } - MonoClass* klass = mono_object_class (obj); - - gpointer iter; -handle_parent: - iter = NULL; - MonoClassField *f; - while ((f = mono_class_get_fields_internal (klass, &iter))) { - if (!f->name || strcasecmp (f->name, name) != 0) - continue; - guint8 *val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type_internal (f->type))); - - if (!decode_value(f->type, val_buf, value)) { - return FALSE; - } - DbgEngineErrorCode errorCode = mono_de_set_interp_var (f->type, (guint8*)obj + f->offset, val_buf); - if (errorCode != ERR_NONE) { - return FALSE; - } - return TRUE; - } - - iter = NULL; - MonoProperty *p; - MonoObject *exc; - ERROR_DECL (error); - while ((p = mono_class_get_properties (klass, &iter))) { - if (!p->name || strcasecmp (p->name, name) != 0) - continue; - if (!p->set) - break; - MonoType *type = mono_method_signature_internal (p->set)->params [0]; - guint8 *val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type_internal (type))); - - if (!decode_value(type, val_buf, value)) { - return FALSE; - } - mono_runtime_try_invoke (p->set, obj, (void **)&val_buf, &exc, error); - if (!is_ok (error) && exc == NULL) - exc = (MonoObject*) mono_error_convert_to_exception (error); - if (exc) { - char *error_message = mono_string_to_utf8_checked_internal (((MonoException *)exc)->message, error); - if (is_ok (error)) { - PRINT_DEBUG_MSG (2, "mono_wasm_set_value_on_object exception: %s\n", error_message); - g_free (error_message); - mono_error_cleanup (error); - } - else { - PRINT_DEBUG_MSG (2, "mono_wasm_set_value_on_object exception\n"); - } - return FALSE; - } - return TRUE; - } - - if ((klass = m_class_get_parent(klass))) - goto handle_parent; - return FALSE; -} - EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_getter_on_value (void *value, MonoClass *klass, const char *name) { @@ -1657,23 +1470,19 @@ mono_wasm_set_is_debugger_attached (gboolean is_attached) } EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_invoke_method_debugger_agent (guint8* data, unsigned int size) +mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size, int valtype, char* newvalue) { - MdbgProtBuffer buf; - buffer_init (&buf, 128); - InvokeData invoke_data; - memset(&invoke_data, 0, sizeof(InvokeData)); - invoke_data.endp = data + size; - DebuggerTlsData* tls = mono_wasm_get_tls(); - - MdbgProtErrorCode error = mono_do_invoke_method(tls, &buf, &invoke_data, data, &data); - if (error != 0) - printf("error - mono_wasm_invoke_method_debugger_agent - %d\n", error); - EM_ASM ({ - MONO.mono_wasm_add_dbg_command_received ($0, $1, $2, $3); - }, error == MDBGPROT_ERR_NONE, -1, buf.buf, buf.p-buf.buf); - - buffer_free (&buf); + MdbgProtBuffer bufWithParms; + buffer_init (&bufWithParms, 128); + m_dbgprot_buffer_add_data (&bufWithParms, data, size); + if (!write_value_to_buffer(&bufWithParms, valtype, newvalue)) { + EM_ASM ({ + MONO.mono_wasm_add_dbg_command_received ($0, $1, $2, $3); + }, 0, id, 0, 0); + return TRUE; + } + gboolean ret = mono_wasm_send_dbg_command(id, command_set, command, bufWithParms.buf, m_dbgprot_buffer_len(&bufWithParms)); + buffer_free (&bufWithParms); return TRUE; } @@ -1683,7 +1492,17 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, MdbgProtBuffer buf; buffer_init (&buf, 128); gboolean no_reply; - MdbgProtErrorCode error = mono_process_dbg_packet(id, command_set, command, &no_reply, data, data + size, &buf); + MdbgProtErrorCode error = 0; + if (command_set == MDBGPROT_CMD_SET_VM && command == MDBGPROT_CMD_VM_INVOKE_METHOD ) + { + DebuggerTlsData* tls = mono_wasm_get_tls(); + InvokeData invoke_data; + memset(&invoke_data, 0, sizeof(InvokeData)); + invoke_data.endp = data + size; + error = mono_do_invoke_method(tls, &buf, &invoke_data, data, &data); + } + else + error = mono_process_dbg_packet(id, command_set, command, &no_reply, data, data + size, &buf); EM_ASM ({ MONO.mono_wasm_add_dbg_command_received ($0, $1, $2, $3); From 50d657e7eddf7053b81cf0eaf69eeaea3dfcf0e7 Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 20 May 2021 12:37:48 -0300 Subject: [PATCH 18/48] Fixing valuetype with null values. Failed: 184, Passed: 307 --- src/mono/mono/mini/debugger-agent.c | 5 +++++ src/mono/mono/mini/mini-wasm-debugger.c | 3 +-- src/mono/wasm/runtime/library_mono.js | 13 ------------- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index ef265413ac90d..08aa9634b8235 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -5464,7 +5464,12 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, mono_gc_wbarrier_generic_store_internal (addr, obj); } else if (type == VALUE_TYPE_ID_NULL) { + if (CHECK_PROTOCOL_VERSION (2, 59)) { + decode_byte (buf, &buf, limit); + decode_int (buf, &buf, limit); //not used + } *(MonoObject**)addr = NULL; + } else if (type == MONO_TYPE_VALUETYPE) { ERROR_DECL (error); guint8 *buf2; diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 5ca0ab67f0ba6..0d31b8dd58456 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -53,7 +53,6 @@ EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command_with_parms (int id, Mdb //JS functions imported that we use -extern void mono_wasm_add_frame (int il_offset, int method_token, int frame_id, const char *assembly_name, const char *method_name); extern void mono_wasm_fire_bp (void); extern void mono_wasm_fire_debugger_agent_message (void); extern void mono_wasm_fire_exception (int exception_obj_id, const char* message, const char* class_name, gboolean uncaught); @@ -1503,7 +1502,7 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, } else error = mono_process_dbg_packet(id, command_set, command, &no_reply, data, data + size, &buf); - + EM_ASM ({ MONO.mono_wasm_add_dbg_command_received ($0, $1, $2, $3); }, error == MDBGPROT_ERR_NONE, id, buf.buf, buf.p-buf.buf); diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 22a7a5089235d..2575184c1688b 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -1413,7 +1413,6 @@ var MonoSupportLib = { this._register_c_var_fn ('mono_wasm_invoke_getter_on_object', 'bool', [ 'number', 'string' ]); this._register_c_var_fn ('mono_wasm_invoke_getter_on_value', 'bool', [ 'number', 'number', 'string' ]); this._register_c_var_fn ('mono_wasm_get_local_vars', 'bool', [ 'number', 'number', 'number']); - this._register_c_fn ('mono_wasm_set_value_on_object', 'bool', [ 'number', 'string', 'string' ]); this._register_c_fn ('mono_wasm_send_dbg_command', 'bool', [ 'number', 'number', 'number', 'number', 'number' ]); this._register_c_fn ('mono_wasm_send_dbg_command_with_parms', 'bool', [ 'number', 'number', 'number', 'number', 'number', 'number', 'string' ]); @@ -2405,18 +2404,6 @@ var MonoSupportLib = { } }, - mono_wasm_add_frame: function(il, method, frame_id, assembly_name, method_full_name) { - var parts = Module.UTF8ToString (method_full_name).split (":", 2); - MONO.active_frames.push( { - il_pos: il, - method_token: method, - assembly_name: Module.UTF8ToString (assembly_name), - // Extract just the method name from `{class_name}:{method_name}` - method_name: parts [parts.length - 1], - frame_id - }); - }, - schedule_background_exec: function () { ++MONO.pump_count; if (typeof globalThis.setTimeout === 'function') { From 212c0811e4668c89978a00f26bd88fa542910208 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 21 May 2021 13:59:49 -0300 Subject: [PATCH 19/48] Implemented Evaluate expressions, conditional breakpoints, all breakpoints tests are passing. Failed: 172, Passed: 319 --- src/mono/mono/mini/debugger-agent.c | 13 ++- src/mono/mono/mini/debugger-agent.h | 3 + src/mono/mono/mini/mini-wasm-debugger.c | 4 +- .../MemberReferenceResolver.cs | 110 +++++++++++++----- .../debugger/BrowserDebugProxy/MonoProxy.cs | 27 +++-- .../BrowserDebugProxy/MonoSDBHelper.cs | 38 +++++- 6 files changed, 142 insertions(+), 53 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 08aa9634b8235..9476040e4b5dd 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -1581,6 +1581,7 @@ void mono_init_debugger_agent_for_wasm (int log_level_parm) vm_start_event_sent = TRUE; transport = &transports [0]; memset(&debugger_wasm_thread, 0, sizeof(DebuggerTlsData)); + agent_config.enabled = TRUE; } @@ -3510,7 +3511,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx return; } } - + if (event == EVENT_KIND_VM_START) suspend_policy = agent_config.suspend ? SUSPEND_POLICY_ALL : SUSPEND_POLICY_NONE; @@ -3598,6 +3599,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx break; } case EVENT_KIND_USER_BREAK: { +#ifndef TARGET_WASM DebuggerTlsData *tls; tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); g_assert (tls); @@ -3605,6 +3607,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx if (tls->disable_breakpoints) return; mono_stopwatch_stop (&tls->step_time); +#endif break; } case EVENT_KIND_USER_LOG: { @@ -4316,8 +4319,8 @@ user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer user_data) /* * Called by System.Diagnostics.Debugger:Break (). */ -static void -debugger_agent_user_break (void) +void +mono_dbg_debugger_agent_user_break (void) { if (agent_config.enabled) { MonoContext ctx; @@ -8756,7 +8759,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g buffer_add_byte(buf, TRUE); mono_debug_free_method_async_debug_info (async_method); } - else + else buffer_add_byte(buf, FALSE); break; } @@ -10191,7 +10194,7 @@ mono_debugger_agent_init (void) cbs.handle_exception = debugger_agent_handle_exception; cbs.begin_exception_filter = debugger_agent_begin_exception_filter; cbs.end_exception_filter = debugger_agent_end_exception_filter; - cbs.user_break = debugger_agent_user_break; + cbs.user_break = mono_dbg_debugger_agent_user_break; cbs.debug_log = debugger_agent_debug_log; cbs.debug_log_is_enabled = debugger_agent_debug_log_is_enabled; cbs.send_crash = mono_debugger_agent_send_crash; diff --git a/src/mono/mono/mini/debugger-agent.h b/src/mono/mono/mini/debugger-agent.h index 410d0a6162002..6064ab6a5482c 100644 --- a/src/mono/mono/mini/debugger-agent.h +++ b/src/mono/mono/mini/debugger-agent.h @@ -94,6 +94,9 @@ mono_dbg_create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJ void mono_dbg_process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset); +void +mono_dbg_debugger_agent_user_break (void); + void mono_wasm_save_thread_context (void); diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 0d31b8dd58456..dd56f9b44aca1 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -489,7 +489,9 @@ mono_wasm_breakpoint_hit (void) void mono_wasm_user_break (void) { - mono_wasm_fire_bp (); + mono_wasm_save_thread_context(); + mono_dbg_debugger_agent_user_break (); + // mono_wasm_fire_bp (); } static MonoObject* diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 21f8dabdb37a6..1479759aa088e 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System.IO; namespace Microsoft.WebAssembly.Diagnostics { @@ -18,7 +19,6 @@ internal class MemberReferenceResolver private MonoProxy proxy; private ExecutionContext ctx; private PerScopeCache scopeCache; - private VarInfo[] varIds; private ILogger logger; private bool locals_fetched; @@ -31,44 +31,92 @@ public MemberReferenceResolver(MonoProxy proxy, ExecutionContext ctx, SessionId this.logger = logger; scopeCache = ctx.GetCacheForScope(scope_id); } + public async Task GetValueFromObject(JToken objRet, CancellationToken token) + { + if (objRet["value"]?.Value() != null) + return objRet["value"]?.Value(); + if (objRet["get"]?.Value() != null) + { + if (DotnetObjectId.TryParse(objRet?["get"]?["objectIdValue"]?.Value(), out DotnetObjectId objectId)) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.WriteObj(objectId); + var ret = await proxy.sdbHelper.InvokeMethod(sessionId, command_params.ToArray(), objRet["get"]["methodId"].Value(), objRet["name"].Value(), token); + return ret["value"]?.Value(); + } + } + return null; + } // Checks Locals, followed by `this` public async Task Resolve(string var_name, CancellationToken token) { - if (scopeCache.Locals.Count == 0 && !locals_fetched) + string[] parts = var_name.Split("."); + JObject rootObject = null; + foreach (string part in parts) { - Result scope_res = await proxy.GetScopeProperties(sessionId, scopeId, token); - if (scope_res.IsErr) - throw new Exception($"BUG: Unable to get properties for scope: {scopeId}. {scope_res}"); - locals_fetched = true; - } - - if (scopeCache.Locals.TryGetValue(var_name, out JObject obj)) - { - return obj["value"]?.Value(); - } + if (rootObject != null) + { + if (DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId objectId)) + { + var root_res = await proxy.RuntimeGetProperties(sessionId, objectId, null, token); + var root_res_obj = root_res.Value?["result"]; + var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == part); + if (objRet != null) + { + rootObject = await GetValueFromObject(objRet, token); + } + } + continue; + } + if (scopeCache.Locals.Count == 0 && !locals_fetched) + { + Result scope_res = await proxy.GetScopeProperties(sessionId, scopeId, token); + if (scope_res.IsErr) + throw new Exception($"BUG: Unable to get properties for scope: {scopeId}. {scope_res}"); + locals_fetched = true; + } + if (scopeCache.Locals.TryGetValue(part, out JObject obj)) + { + rootObject = obj["value"]?.Value(); + } + if (scopeCache.Locals.TryGetValue("this", out JObject objThis)) + { + if (DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value(), out DotnetObjectId objectId)) + { + var this_res = await proxy.sdbHelper.GetObjectValues(sessionId, int.Parse(objectId.Value), true, false, token); + var objRet = this_res.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == part); + if (objRet != null) + { + rootObject = await GetValueFromObject(objRet, token); + //rootObject = objRet["value"]?.Value(); + } + } + } + /* + if (scopeCache.MemberReferences.TryGetValue(var_name, out JObject ret)) + return ret; - if (scopeCache.MemberReferences.TryGetValue(var_name, out JObject ret)) - return ret; + if (varIds == null) + { + Frame scope = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId); + varIds = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); + } - if (varIds == null) - { - Frame scope = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId); - varIds = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); - } - - Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.EvaluateMemberAccess(scopeId, var_name, varIds), token); - if (res.IsOk) - { - ret = res.Value?["result"]?["value"]?["value"]?.Value(); - scopeCache.MemberReferences[var_name] = ret; + Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.EvaluateMemberAccess(scopeId, var_name, varIds), token); + if (res.IsOk) + { + ret = res.Value?["result"]?["value"]?["value"]?.Value(); + scopeCache.MemberReferences[var_name] = ret; + } + else + { + logger.LogDebug(res.Error.ToString()); + } + */ } - else - { - logger.LogDebug(res.Error.ToString()); - } - - return ret; + return rootObject; } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 86708196cffe4..27b684f7426c0 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -18,7 +18,7 @@ namespace Microsoft.WebAssembly.Diagnostics { internal class MonoProxy : DevToolsProxy { - private MonoSDBHelper sdbHelper; + internal MonoSDBHelper sdbHelper; private IList urlSymbolServerList; private static HttpClient client = new HttpClient(); private HashSet sessions = new HashSet(); @@ -577,7 +577,7 @@ private async Task OnSetVariableValue(MessageId id, int scopeId, string va return true; } - private async Task RuntimeGetProperties(MessageId id, DotnetObjectId objectId, JToken args, CancellationToken token) + internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId objectId, JToken args, CancellationToken token) { try { if (objectId.Scheme == "scope") @@ -617,7 +617,7 @@ private async Task RuntimeGetProperties(MessageId id, DotnetObjectId obj return res; } - private async Task EvaluateCondition(SessionId sessionId, ExecutionContext context, JObject mono_frame, Breakpoint bp, CancellationToken token) + private async Task EvaluateCondition(SessionId sessionId, ExecutionContext context, Frame mono_frame, Breakpoint bp, CancellationToken token) { if (string.IsNullOrEmpty(bp?.Condition) || mono_frame == null) return true; @@ -627,8 +627,7 @@ private async Task EvaluateCondition(SessionId sessionId, ExecutionContext if (bp.ConditionAlreadyEvaluatedWithError) return false; try { - var resolver = new MemberReferenceResolver(this, context, sessionId, mono_frame["frame_id"].Value(), logger); - + var resolver = new MemberReferenceResolver(this, context, sessionId, mono_frame.Id, logger); JObject retValue = await resolver.Resolve(condition, token); if (retValue == null) retValue = await EvaluateExpression.CompileAndRunTheExpression(condition, resolver, token); @@ -671,24 +670,26 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec var callFrames = new List(); var frames = new List(); for (int i = 0 ; i < number_of_events; i++) { - var event_kind = ret_debugger_cmd_reader.ReadByte(); //event kind + var event_kind = (EventKind)ret_debugger_cmd_reader.ReadByte(); //event kind var request_id = ret_debugger_cmd_reader.ReadInt32(); //request id - if ((EventKind)event_kind == EventKind.STEP) + if (event_kind == EventKind.STEP) await sdbHelper.ClearSingleStep(sessionId, request_id, token); Breakpoint bp = context.BreakpointRequests.Values.SelectMany(v => v.Locations).FirstOrDefault(b => b.RemoteId == request_id); - switch ((EventKind)event_kind) + switch (event_kind) { + case EventKind.USER_BREAK: case EventKind.STEP: case EventKind.BREAKPOINT: { int thread_id = ret_debugger_cmd_reader.ReadInt32(); - int method_id = ret_debugger_cmd_reader.ReadInt32(); + int method_id = 0; + if (event_kind != EventKind.USER_BREAK) + method_id = ret_debugger_cmd_reader.ReadInt32(); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(thread_id); command_params_writer.Write(0); command_params_writer.Write(-1); - ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, (int) CommandSet.THREAD, (int) CmdThread.GET_FRAME_INFO, command_params, token); var frame_count = ret_debugger_cmd_reader.ReadInt32(); for (int j = 0; j < frame_count; j++) { @@ -793,6 +794,11 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec data, hitBreakpoints = bp_list, }); + if (!await EvaluateCondition(sessionId, context, context.CallStack.First(), bp, token)) + { + await SendCommand(sessionId, "Debugger.resume", new JObject(), token); + return true; + } SendEvent(sessionId, "Debugger.paused", o, token); break; } @@ -1124,6 +1130,7 @@ private async Task RuntimeReady(SessionId sessionId, CancellationTok } await sdbHelper.SetProtocolVersion(sessionId, token); + await sdbHelper.EnableReceiveUserBreakRequest(sessionId, token); DebugStore store = await LoadStore(sessionId, token); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 0c5ec83431e41..59a355eb1f454 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -438,6 +438,14 @@ public override void Write(int val) Array.Reverse(bytes, 0, bytes.Length); Write(bytes); } + public void WriteObj(DotnetObjectId objectId) + { + if (objectId.Scheme == "object") + { + Write((byte)ElementType.Class); + Write(int.Parse(objectId.Value)); + } + } } internal class FieldTypeClass { @@ -507,7 +515,16 @@ public async Task SetProtocolVersion(SessionId sessionId, CancellationToke var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.SET_PROTOCOL_VERSION, command_params, token); return true; } - + public async Task EnableReceiveUserBreakRequest(SessionId sessionId, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((byte)EventKind.USER_BREAK); + command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_NONE); + command_params_writer.Write((byte)0); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + return true; + } internal async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) { Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); @@ -818,14 +835,20 @@ public async Task CreateJArrayForProperties(SessionId sessionId, int typ var getMethodId = ret_debugger_cmd_reader.ReadInt32(); ret_debugger_cmd_reader.ReadInt32(); //setmethod ret_debugger_cmd_reader.ReadInt32(); //attrs - if (await MethodIsStatic(sessionId, getMethodId, token)) + if (getMethodId == 0 || await MethodIsStatic(sessionId, getMethodId, token)) continue; JObject propRet = null; if (attributes.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any()) continue; if (isAutoExpandable) { - propRet = await InvokeMethod(sessionId, object_buffer, getMethodId, propertyNameStr, token); + try { + propRet = await InvokeMethod(sessionId, object_buffer, getMethodId, propertyNameStr, token); + } + catch (Exception) + { + continue; + } } else { @@ -836,6 +859,8 @@ public async Task CreateJArrayForProperties(SessionId sessionId, int typ objectId = $"{objectId}:method_id:{getMethodId}", className = "Function", description = "get " + propertyNameStr + " ()", + methodId = getMethodId, + objectIdValue = objectId }, name = propertyNameStr }); @@ -1288,17 +1313,18 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me command_params_writer.Write(var.Index); } - if (await IsAsyncMethod(sessionId, method.DebuggerId, token)) { ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); ret_debugger_cmd_reader.ReadByte(); //ignore type var objectId = ret_debugger_cmd_reader.ReadInt32(); var asyncLocals = await GetObjectValues(sessionId, objectId, true, false, token); - asyncLocals = new JArray(asyncLocals.Where( asyncLocal => !asyncLocal["name"].Value().Contains("<>"))); + asyncLocals = new JArray(asyncLocals.Where( asyncLocal => !asyncLocal["name"].Value().Contains("<>") || asyncLocal["name"].Value().EndsWith("__this"))); foreach (var asyncLocal in asyncLocals) { - if (asyncLocal["name"].Value().Contains("<")) + if (asyncLocal["name"].Value().EndsWith("__this")) + asyncLocal["name"] = "this"; + else if (asyncLocal["name"].Value().Contains("<")) asyncLocal["name"] = Regex.Match(asyncLocal["name"].Value(), @"\<([^)]*)\>").Groups[1].Value; } return asyncLocals; From 7186b981eb4aebd69d47b856e3c2ac6b6b89ee78 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 21 May 2021 15:36:16 -0300 Subject: [PATCH 20/48] Fixing evaluate with value type. Failed: 156, Passed: 335 --- .../MemberReferenceResolver.cs | 8 ++++---- .../BrowserDebugProxy/MonoSDBHelper.cs | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 1479759aa088e..3e3e66042bead 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -41,7 +41,7 @@ public async Task GetValueFromObject(JToken objRet, CancellationToken t { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.WriteObj(objectId); + command_params_writer.WriteObj(objectId, proxy.sdbHelper); var ret = await proxy.sdbHelper.InvokeMethod(sessionId, command_params.ToArray(), objRet["get"]["methodId"].Value(), objRet["name"].Value(), token); return ret["value"]?.Value(); } @@ -85,12 +85,12 @@ public async Task Resolve(string var_name, CancellationToken token) { if (DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value(), out DotnetObjectId objectId)) { - var this_res = await proxy.sdbHelper.GetObjectValues(sessionId, int.Parse(objectId.Value), true, false, token); - var objRet = this_res.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == part); + var root_res = await proxy.RuntimeGetProperties(sessionId, objectId, null, token); + var root_res_obj = root_res.Value?["result"]; + var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == part); if (objRet != null) { rootObject = await GetValueFromObject(objRet, token); - //rootObject = objRet["value"]?.Value(); } } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 59a355eb1f454..d7b8dafc95c69 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -438,13 +438,17 @@ public override void Write(int val) Array.Reverse(bytes, 0, bytes.Length); Write(bytes); } - public void WriteObj(DotnetObjectId objectId) + public void WriteObj(DotnetObjectId objectId, MonoSDBHelper sdbHelper) { if (objectId.Scheme == "object") { Write((byte)ElementType.Class); Write(int.Parse(objectId.Value)); } + if (objectId.Scheme == "valuetype") + { + Write(sdbHelper.valueTypes[int.Parse(objectId.Value)].valueTypeBuffer); + } } } internal class FieldTypeClass @@ -466,7 +470,8 @@ internal class ValueTypeClass public JArray valueTypeProxy; public string valueTypeVarName; public bool valueTypeAutoExpand; - public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool expand_properties) + public int Id; + public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool expand_properties, int valueTypeId) { valueTypeBuffer = buffer; valueTypeJson = json; @@ -475,6 +480,7 @@ public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool e valueTypeProxy = null; valueTypeVarName = varName; valueTypeAutoExpand = expand_properties; + Id = valueTypeId; } } internal class PointerValue @@ -492,8 +498,8 @@ public PointerValue(long address, int typeId, string varName) } internal class MonoSDBHelper { - private Dictionary valueTypes = new Dictionary(); - private Dictionary pointerValues = new Dictionary(); + internal Dictionary valueTypes = new Dictionary(); + internal Dictionary pointerValues = new Dictionary(); private static int debugger_object_id; private static int cmd_id; private static int GetId() {return cmd_id++;} @@ -885,7 +891,7 @@ public async Task GetPointerContent(SessionId sessionId, int pointerId, public async Task GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token) { var valueType = valueTypes[valueTypeId]; - var properties = await CreateJArrayForProperties(sessionId, valueType.typeId, valueType.valueTypeBuffer, valueType.valueTypeJson, valueType.valueTypeAutoExpand, $"dotnet:valuetype:{valueType.typeId}", token); + var properties = await CreateJArrayForProperties(sessionId, valueType.typeId, valueType.valueTypeBuffer, valueType.valueTypeJson, valueType.valueTypeAutoExpand, $"dotnet:valuetype:{valueType.Id}", token); return properties; } @@ -1205,7 +1211,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo byte[] valueTypeBuffer = new byte[endPos - initialPos]; ret_debugger_cmd_reader.Read(valueTypeBuffer, 0, (int)(endPos - initialPos)); ret_debugger_cmd_reader.BaseStream.Position = endPos; - valueTypes[valueTypeId] = new ValueTypeClass(name, valueTypeBuffer, valueTypeFields, typeId, AutoExpandable(className)); + valueTypes[valueTypeId] = new ValueTypeClass(name, valueTypeBuffer, valueTypeFields, typeId, AutoExpandable(className), valueTypeId); if (AutoInvokeToString(className) || isEnum == 1) { int method_id = await GetMethodIdByName(sessionId, typeId, "ToString", token); var retMethod = await InvokeMethod(sessionId, valueTypeBuffer, method_id, "methodRet", token); From 26cf8823371d4551bbf0c912ff575af8a320da37 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 21 May 2021 16:53:59 -0300 Subject: [PATCH 21/48] Trim part and add cache. Failed: 148, Passed: 343 --- .../MemberReferenceResolver.cs | 31 +++++-------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 3e3e66042bead..2645ecc3a0d18 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -54,15 +54,18 @@ public async Task Resolve(string var_name, CancellationToken token) { string[] parts = var_name.Split("."); JObject rootObject = null; + if (scopeCache.MemberReferences.TryGetValue(var_name, out JObject ret)) + return ret; foreach (string part in parts) { + string partTrimmed = part.Trim(); if (rootObject != null) { if (DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId objectId)) { var root_res = await proxy.RuntimeGetProperties(sessionId, objectId, null, token); var root_res_obj = root_res.Value?["result"]; - var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == part); + var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == partTrimmed); if (objRet != null) { rootObject = await GetValueFromObject(objRet, token); @@ -77,7 +80,7 @@ public async Task Resolve(string var_name, CancellationToken token) throw new Exception($"BUG: Unable to get properties for scope: {scopeId}. {scope_res}"); locals_fetched = true; } - if (scopeCache.Locals.TryGetValue(part, out JObject obj)) + if (scopeCache.Locals.TryGetValue(partTrimmed, out JObject obj)) { rootObject = obj["value"]?.Value(); } @@ -87,35 +90,15 @@ public async Task Resolve(string var_name, CancellationToken token) { var root_res = await proxy.RuntimeGetProperties(sessionId, objectId, null, token); var root_res_obj = root_res.Value?["result"]; - var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == part); + var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == partTrimmed); if (objRet != null) { rootObject = await GetValueFromObject(objRet, token); } } } - /* - if (scopeCache.MemberReferences.TryGetValue(var_name, out JObject ret)) - return ret; - - if (varIds == null) - { - Frame scope = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId); - varIds = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); - } - - Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.EvaluateMemberAccess(scopeId, var_name, varIds), token); - if (res.IsOk) - { - ret = res.Value?["result"]?["value"]?["value"]?.Value(); - scopeCache.MemberReferences[var_name] = ret; - } - else - { - logger.LogDebug(res.Error.ToString()); - } - */ } + scopeCache.MemberReferences[var_name] = rootObject; return rootObject; } From a8f98b54ed1945faf1b9b64dced6d4222af1e233 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 21 May 2021 18:54:11 -0300 Subject: [PATCH 22/48] Fixing evaluate expression. Failed: 99, Passed: 392 --- .../MemberReferenceResolver.cs | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 2645ecc3a0d18..99ca33136e122 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -54,13 +54,19 @@ public async Task Resolve(string var_name, CancellationToken token) { string[] parts = var_name.Split("."); JObject rootObject = null; - if (scopeCache.MemberReferences.TryGetValue(var_name, out JObject ret)) + + if (scopeCache.MemberReferences.TryGetValue(var_name, out JObject ret)) { return ret; + } foreach (string part in parts) { string partTrimmed = part.Trim(); + if (partTrimmed == "") + return null; if (rootObject != null) { + if (rootObject?["subtype"]?.Value() == "null") + return null; if (DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId objectId)) { var root_res = await proxy.RuntimeGetProperties(sessionId, objectId, null, token); @@ -70,6 +76,10 @@ public async Task Resolve(string var_name, CancellationToken token) { rootObject = await GetValueFromObject(objRet, token); } + else + { + return null; + } } continue; } @@ -84,9 +94,13 @@ public async Task Resolve(string var_name, CancellationToken token) { rootObject = obj["value"]?.Value(); } - if (scopeCache.Locals.TryGetValue("this", out JObject objThis)) + else if (scopeCache.Locals.TryGetValue("this", out JObject objThis)) { - if (DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value(), out DotnetObjectId objectId)) + if (partTrimmed == "this") + { + rootObject = objThis?["value"].Value(); + } + else if (DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value(), out DotnetObjectId objectId)) { var root_res = await proxy.RuntimeGetProperties(sessionId, objectId, null, token); var root_res_obj = root_res.Value?["result"]; @@ -95,6 +109,10 @@ public async Task Resolve(string var_name, CancellationToken token) { rootObject = await GetValueFromObject(objRet, token); } + else + { + return null; + } } } } From 4010546c4396d4a43adff38d5dd0bd53f9c31276 Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 24 May 2021 21:59:47 -0300 Subject: [PATCH 23/48] GetPropertiesTests working. Failed: 53, Passed: 438 --- src/mono/mono/mini/debugger-agent.c | 17 + src/mono/mono/mini/debugger-protocol.h | 3 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 24 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 308 ++++++++++++------ 4 files changed, 250 insertions(+), 102 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 9476040e4b5dd..a3e4725b282cc 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -8255,6 +8255,23 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint buffer_add_int (buf, value_size); break; } + case MDBGPROT_CMD_TYPE_GET_PARENTS: { + MonoClass *parent_klass = m_class_get_parent (klass); + int count = 0; + while (parent_klass != NULL) + { + count++; + parent_klass = m_class_get_parent (parent_klass); + } + buffer_add_int (buf, count); + parent_klass = m_class_get_parent (klass); + while (parent_klass != NULL) + { + buffer_add_typeid (buf, domain, parent_klass); + parent_klass = m_class_get_parent (parent_klass); + } + break; + } default: err = ERR_NOT_IMPLEMENTED; goto exit; diff --git a/src/mono/mono/mini/debugger-protocol.h b/src/mono/mono/mini/debugger-protocol.h index a12962ed1286c..e34ff51453ec6 100644 --- a/src/mono/mono/mini/debugger-protocol.h +++ b/src/mono/mono/mini/debugger-protocol.h @@ -207,7 +207,8 @@ typedef enum { MDBGPROT_CMD_TYPE_IS_INITIALIZED = 18, MDBGPROT_CMD_TYPE_CREATE_INSTANCE = 19, MDBGPROT_CMD_TYPE_GET_VALUE_SIZE = 20, - MDBGPROT_CMD_TYPE_GET_VALUES_ICORDBG = 21 + MDBGPROT_CMD_TYPE_GET_VALUES_ICORDBG = 21, + MDBGPROT_CMD_TYPE_GET_PARENTS = 22 } MdbgProtCmdType; typedef enum { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 27b684f7426c0..f859ef3ad7eb4 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -488,7 +488,7 @@ protected override async Task AcceptCommand(MessageId id, string method, J var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", token); + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, token); /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ res = Result.OkFromObject(new { result = obj["value"]}); SendResponse(id, res, token); @@ -510,7 +510,7 @@ protected override async Task AcceptCommand(MessageId id, string method, J var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", token); + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, token); res = Result.OkFromObject(new { result = obj["value"]}); SendResponse(id, res, token); return true; @@ -532,7 +532,7 @@ protected override async Task AcceptCommand(MessageId id, string method, J var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", token); + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, token); res = Result.OkFromObject(new { result = obj["value"]}); SendResponse(id, res, token); return true; @@ -579,6 +579,16 @@ private async Task OnSetVariableValue(MessageId id, int scopeId, string va internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId objectId, JToken args, CancellationToken token) { + var accessorPropertiesOnly = false; + var ownProperties = false; + if (args != null) + { + if (args["accessorPropertiesOnly"] != null) + accessorPropertiesOnly = args["accessorPropertiesOnly"].Value(); + if (args["ownProperties"] != null) + ownProperties = args["ownProperties"].Value(); + } + //Console.WriteLine($"RuntimeGetProperties - {args}"); try { if (objectId.Scheme == "scope") { @@ -586,7 +596,7 @@ internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId ob } if (objectId.Scheme == "valuetype") { - var ret = await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), token); + var ret = await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), accessorPropertiesOnly, token); Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); return res2; } @@ -598,7 +608,7 @@ internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId ob } if (objectId.Scheme == "object") { - var ret = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, false, token); + var ret = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, false, accessorPropertiesOnly, ownProperties, token); Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); return res2; } @@ -609,8 +619,8 @@ internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId ob return res2; } } - catch (Exception) { - Result res2 = Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); + catch (Exception e) { + Result res2 = Result.Err($"Unable to RuntimeGetProperties '{objectId}' - {e}"); return res2; } Result res = Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index d7b8dafc95c69..c5cecad2d6c21 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -235,7 +235,9 @@ internal enum CmdType { GET_INTERFACE_MAP = 17, IS_INITIALIZED = 18, CREATE_INSTANCE = 19, - GET_VALUE_SIZE = 20 + GET_VALUE_SIZE = 20, + GET_VALUES_ICORDBG = 21, + GET_PARENTS = 22 } internal enum CmdArray { @@ -535,7 +537,7 @@ internal async Task SendDebuggerAgentCommand(SessionId session { Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); if (res.IsErr) { - throw new Exception("SendDebuggerAgentCommand Error"); + throw new Exception($"SendDebuggerAgentCommand Error - {(CommandSet)command_set} - {command}"); } byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); @@ -639,6 +641,18 @@ public async Task MethodIsStatic(SessionId sessionId, int method_id, Cance return (flags & 0x0010) > 0; //check method is static } + public async Task GetParamCount(SessionId sessionId, int method_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(method_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_PARAM_INFO, command_params, token); + ret_debugger_cmd_reader.ReadInt32(); + int param_count = ret_debugger_cmd_reader.ReadInt32(); + return param_count; + } + public async Task SetBreakpoint(SessionId sessionId, int method_id, long il_offset, CancellationToken token) { var command_params = new MemoryStream(); @@ -711,8 +725,9 @@ public async Task> GetTypeFields(SessionId sessionId, int t for (int i = 0 ; i < nFields; i++) { int fieldId = ret_debugger_cmd_reader.ReadInt32(); //fieldId - string fieldNameStr = ret_debugger_cmd_reader.ReadString(); + ret_debugger_cmd_reader.ReadInt32(); //typeId + ret_debugger_cmd_reader.ReadInt32(); //attrs if (fieldNameStr.Contains("k__BackingField")) { fieldNameStr = fieldNameStr.Replace("k__BackingField", ""); @@ -720,8 +735,6 @@ public async Task> GetTypeFields(SessionId sessionId, int t fieldNameStr = fieldNameStr.Replace(">", ""); } ret.Add(new FieldTypeClass(fieldId, fieldNameStr)); - ret_debugger_cmd_reader.ReadInt32(); //typeId - ret_debugger_cmd_reader.ReadInt32(); //attrs } return ret; } @@ -783,21 +796,35 @@ public async Task GetArrayLength(SessionId sessionId, int object_id, Cancel length = ret_debugger_cmd_reader.ReadInt32(); return length; } - public async Task GetTypeIdFromObject(SessionId sessionId, int object_id, CancellationToken token) + public async Task> GetTypeIdFromObject(SessionId sessionId, int object_id, bool withParents, CancellationToken token) { + List ret = new List(); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(object_id); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_GET_TYPE, command_params, token); var type_id = ret_debugger_cmd_reader.ReadInt32(); - return type_id; + ret.Add(type_id); + if (withParents) + { + command_params = new MemoryStream(); + command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(type_id); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PARENTS, command_params, token); + var parentsCount = ret_debugger_cmd_reader.ReadInt32(); + for (int i = 0 ; i < parentsCount; i++) + { + ret.Add(ret_debugger_cmd_reader.ReadInt32()); + } + } + return ret; } public async Task GetClassNameFromObject(SessionId sessionId, int object_id, CancellationToken token) { - int type_id = await GetTypeIdFromObject(sessionId, object_id, token); - return await GetTypeName(sessionId, type_id, token); + var type_id = await GetTypeIdFromObject(sessionId, object_id, false, token); + return await GetTypeName(sessionId, type_id[0], token); } public async Task GetMethodIdByName(SessionId sessionId, int type_id, string method_name, CancellationToken token) @@ -822,9 +849,9 @@ public async Task InvokeMethod(SessionId sessionId, byte[] valueTypeBuf command_params_writer.Write(0); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.INVOKE_METHOD, parms, token); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, token); + return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, false, token); } - public async Task CreateJArrayForProperties(SessionId sessionId, int typeId, byte[] object_buffer, JArray attributes, bool isAutoExpandable, string objectId, CancellationToken token) + public async Task CreateJArrayForProperties(SessionId sessionId, int typeId, byte[] object_buffer, JArray attributes, bool isAutoExpandable, string objectId, bool isOwn, CancellationToken token) { JArray ret = new JArray(); var command_params = new MemoryStream(); @@ -836,12 +863,11 @@ public async Task CreateJArrayForProperties(SessionId sessionId, int typ for (int i = 0 ; i < nProperties; i++) { ret_debugger_cmd_reader.ReadInt32(); //propertyId - string propertyNameStr = ret_debugger_cmd_reader.ReadString(); var getMethodId = ret_debugger_cmd_reader.ReadInt32(); ret_debugger_cmd_reader.ReadInt32(); //setmethod - ret_debugger_cmd_reader.ReadInt32(); //attrs - if (getMethodId == 0 || await MethodIsStatic(sessionId, getMethodId, token)) + var attrs = ret_debugger_cmd_reader.ReadInt32(); //attrs + if (getMethodId == 0 || await GetParamCount(sessionId, getMethodId, token) != 0 || await MethodIsStatic(sessionId, getMethodId, token)) continue; JObject propRet = null; if (attributes.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any()) @@ -871,6 +897,8 @@ public async Task CreateJArrayForProperties(SessionId sessionId, int typ name = propertyNameStr }); } + if (isOwn) + propRet["isOwn"] = true; ret.Add(propRet); } return ret; @@ -886,13 +914,30 @@ public async Task GetPointerContent(SessionId sessionId, int pointerId, var varName = pointerValues[pointerId].varName; if (int.TryParse(varName, out _)) varName = $"[{varName}]"; - return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "*" + varName, token); + return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "*" + varName, false, token); } public async Task GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token) { + JArray ret = new JArray(); var valueType = valueTypes[valueTypeId]; - var properties = await CreateJArrayForProperties(sessionId, valueType.typeId, valueType.valueTypeBuffer, valueType.valueTypeJson, valueType.valueTypeAutoExpand, $"dotnet:valuetype:{valueType.Id}", token); - return properties; + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(valueType.typeId); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PARENTS, command_params, token); + var parentsCount = ret_debugger_cmd_reader.ReadInt32(); + List typesToGetProperties = new List(); + typesToGetProperties.Add(valueType.typeId); + for (int i = 0 ; i < parentsCount; i++) + { + typesToGetProperties.Add(ret_debugger_cmd_reader.ReadInt32()); + } + for (int i = 0 ; i < typesToGetProperties.Count; i++) + { + var properties = await CreateJArrayForProperties(sessionId, typesToGetProperties[i], valueType.valueTypeBuffer, valueType.valueTypeJson, valueType.valueTypeAutoExpand, $"dotnet:valuetype:{valueType.Id}", i == 0, token); + ret = new JArray(ret.Union(properties)); + } + + return ret; } public bool AutoExpandable(string className) { @@ -913,18 +958,20 @@ public bool AutoInvokeToString(string className) { return false; } - public async Task CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, string name, CancellationToken token) + public async Task CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, string name, bool isOwn, CancellationToken token) { long initialPos = ret_debugger_cmd_reader == null ? 0 : ret_debugger_cmd_reader.BaseStream.Position; ElementType etype = (ElementType)ret_debugger_cmd_reader.ReadByte(); JObject fieldValueType = null; + JObject ret = null; switch (etype) { case ElementType.Void: - return new JObject{{"Type", "void"}}; + ret = new JObject{{"Type", "void"}}; + break; case ElementType.Boolean: { var value = ret_debugger_cmd_reader.ReadInt32(); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "boolean", @@ -934,6 +981,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = true, name }); + break; } case ElementType.I1: { @@ -953,7 +1001,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo case ElementType.I4: { var value = ret_debugger_cmd_reader.ReadInt32(); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "number", @@ -963,11 +1011,12 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = true, name }); + break; } case ElementType.U1: { var value = ret_debugger_cmd_reader.ReadUByte(); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "number", @@ -977,11 +1026,12 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = true, name }); + break; } case ElementType.U2: { var value = ret_debugger_cmd_reader.ReadUShort(); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "number", @@ -991,11 +1041,12 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = true, name }); + break; } case ElementType.U4: { var value = ret_debugger_cmd_reader.ReadUInt32(); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "number", @@ -1005,6 +1056,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = true, name }); + break; } case ElementType.R4: { @@ -1024,7 +1076,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo { var value = ret_debugger_cmd_reader.ReadInt32(); var description = $"{value.ToString()} '{Convert.ToChar(value)}'"; - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "symbol", @@ -1034,6 +1086,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = true, name }); + break; } case ElementType.I8: { @@ -1054,7 +1107,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo ulong high = (ulong) ret_debugger_cmd_reader.ReadInt32(); ulong low = (ulong) ret_debugger_cmd_reader.ReadInt32(); var value = ((high << 32) | low); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "number", @@ -1064,13 +1117,14 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = true, name }); + break; } case ElementType.R8: { long high = (long) ret_debugger_cmd_reader.ReadInt32(); long low = (long) ret_debugger_cmd_reader.ReadInt32(); double value = BitConverter.Int64BitsToDouble(((high << 32) | low)); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "number", @@ -1080,11 +1134,13 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = true, name }); + break; } case ElementType.I: case ElementType.U: // FIXME: The client and the debuggee might have different word sizes - return new JObject{{"Type", "void"}}; + ret = new JObject{{"Type", "void"}}; + break; case ElementType.Ptr: { string type; @@ -1105,7 +1161,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo type = "symbol"; value = className + " " + valueAddress; } - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type, @@ -1118,12 +1174,13 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = false, name }); + break; } case ElementType.String: { var string_id = ret_debugger_cmd_reader.ReadInt32(); var value = await GetStringValue(sessionId, string_id, token); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "string", @@ -1133,6 +1190,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo writable = false, name }); + break; } case ElementType.SzArray: case ElementType.Array: @@ -1140,7 +1198,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo var objectId = ret_debugger_cmd_reader.ReadInt32(); var value = await GetClassNameFromObject(sessionId, objectId, token); var length = await GetArrayLength(sessionId, objectId, token); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "object", @@ -1151,13 +1209,14 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo }, name }); + break; } case ElementType.Class: case ElementType.Object: { var objectId = ret_debugger_cmd_reader.ReadInt32(); var value = await GetClassNameFromObject(sessionId, objectId, token); - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "object", @@ -1167,6 +1226,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo }, name }); + break; } case ElementType.ValueType: { @@ -1182,11 +1242,11 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo { ret_debugger_cmd_reader.ReadByte(); //ignoring the boolean type var isNull = ret_debugger_cmd_reader.ReadInt32(); - var value = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, name, token); + var value = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, name, false, token); if (isNull != 0) - return value; + ret = value; else - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "object", @@ -1197,10 +1257,11 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo }, name }); + break; } for (int i = 0; i < numFields ; i++) { - fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, token); + fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, true, token); valueTypeFields.Add(fieldValueType); } @@ -1221,10 +1282,11 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo } else if (isBoxed && numFields == 1) { fieldValueType["name"] = name; - return fieldValueType; + ret = fieldValueType; + break; } - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "object", @@ -1237,6 +1299,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo }, name }); + break; } case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL: { @@ -1270,7 +1333,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo break; } } - return JObject.FromObject(new { + ret = JObject.FromObject(new { value = new { type = "object", @@ -1280,21 +1343,27 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo }, name }); + break; } case (ElementType)ValueTypeId.VALUE_TYPE_ID_TYPE: { - return new JObject{{"Type", "void"}}; + ret = new JObject{{"Type", "void"}}; + break; } case (ElementType)ValueTypeId.VALUE_TYPE_ID_PARENT_VTYPE: { - return new JObject{{"Type", "void"}}; + ret = new JObject{{"Type", "void"}}; + break; } case (ElementType)ValueTypeId.VALUE_TYPE_ID_FIXED_ARRAY: { - return new JObject{{"Type", "void"}}; + ret = new JObject{{"Type", "void"}}; + break; } } - return null; + if (isOwn) + ret["isOwn"] = true; + return ret; } public async Task IsAsyncMethod(SessionId sessionId, int methodId, CancellationToken token) { @@ -1324,7 +1393,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); ret_debugger_cmd_reader.ReadByte(); //ignore type var objectId = ret_debugger_cmd_reader.ReadInt32(); - var asyncLocals = await GetObjectValues(sessionId, objectId, true, false, token); + var asyncLocals = await GetObjectValues(sessionId, objectId, true, false, false, false, token); asyncLocals = new JArray(asyncLocals.Where( asyncLocal => !asyncLocal["name"].Value().Contains("<>") || asyncLocal["name"].Value().EndsWith("__this"))); foreach (var asyncLocal in asyncLocals) { @@ -1340,26 +1409,29 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_VALUES, command_params, token); foreach (var var in var_ids) { - var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, var.Name, token); + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, var.Name, false, token); locals.Add(var_json); } if (!method.IsStatic()) { ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); - var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "this", token); + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "this", false, token); var_json.Add("fieldOffset", -1); locals.Add(var_json); } return locals; } - public async Task GetValueTypeValues(SessionId sessionId, int valueTypeId, CancellationToken token) + public async Task GetValueTypeValues(SessionId sessionId, int valueTypeId, bool accessorPropertiesOnly, CancellationToken token) { if (valueTypes[valueTypeId].valueTypeJsonProps == null) { valueTypes[valueTypeId].valueTypeJsonProps = await GetPropertiesValuesOfValueType(sessionId, valueTypeId, token); } - return new JArray(valueTypes[valueTypeId].valueTypeJson.Union(valueTypes[valueTypeId].valueTypeJsonProps)); + if (accessorPropertiesOnly) + return valueTypes[valueTypeId].valueTypeJsonProps; + var ret = new JArray(valueTypes[valueTypeId].valueTypeJson.Union(valueTypes[valueTypeId].valueTypeJsonProps)); + return ret; } public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId, CancellationToken token) @@ -1416,73 +1488,122 @@ public async Task GetArrayValues(SessionId sessionId, int arrayId, Cance JArray array = new JArray(); for (int i = 0 ; i < length ; i++) { - var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, i.ToString(), token); + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, i.ToString(), false, token); array.Add(var_json); } return array; } - public async Task GetObjectValues(SessionId sessionId, int objectId, bool withProperties, bool withSetter, CancellationToken token) + public async Task GetObjectValues(SessionId sessionId, int objectId, bool withProperties, bool withSetter, bool accessorPropertiesOnly, bool ownProperties, CancellationToken token) { - var typeId = await GetTypeIdFromObject(sessionId, objectId, token); - var fields = await GetTypeFields(sessionId, typeId, token); - JArray objectFields = new JArray(); - - var command_params = new MemoryStream(); - var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write(objectId); - command_params_writer.Write(fields.Count); - foreach (var field in fields) + var typeId = await GetTypeIdFromObject(sessionId, objectId, true, token); + JArray ret = new JArray(); + for (int i = 0; i < typeId.Count; i++) { - command_params_writer.Write(field.Id); - } + if (!accessorPropertiesOnly) + { + var fields = await GetTypeFields(sessionId, typeId[i], token); + JArray objectFields = new JArray(); + + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(objectId); + command_params_writer.Write(fields.Count); + foreach (var field in fields) + { + command_params_writer.Write(field.Id); + } - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_GET_VALUES, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_GET_VALUES, command_params, token); - foreach (var field in fields) + foreach (var field in fields) + { + long initialPos = ret_debugger_cmd_reader.BaseStream.Position; + int valtype = ret_debugger_cmd_reader.ReadByte(); + ret_debugger_cmd_reader.BaseStream.Position = initialPos; + var fieldValue = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, field.Name, i == 0, token); + + if (ret.Where(attribute => attribute["name"].Value().Equals(fieldValue["name"].Value())).Any()) { + continue; + } + if (withSetter) + { + var command_params_to_set = new MemoryStream(); + var command_params_writer_to_set = new MonoBinaryWriter(command_params_to_set); + command_params_writer_to_set.Write(objectId); + command_params_writer_to_set.Write(1); + command_params_writer_to_set.Write(field.Id); + + fieldValue.Add("set", JObject.FromObject(new { + commandSet = CommandSet.OBJECT_REF, + command = CmdObject.REF_SET_VALUES, + buffer = Convert.ToBase64String(command_params_to_set.ToArray()), + valtype, + length = command_params_to_set.ToArray().Length + })); + } + objectFields.Add(fieldValue); + } + ret = new JArray(ret.Union(objectFields)); + } + if (!withProperties) + return ret; + var props = await CreateJArrayForProperties(sessionId, typeId[i], Array.Empty(), ret, false, $"dotnet:object:{objectId}", i == 0, token); + ret = new JArray(ret.Union(props)); + + // ownProperties + // Note: ownProperties should mean that we return members of the klass itself, + // but we are going to ignore that here, because otherwise vscode/chrome don't + // seem to ask for inherited fields at all. + //if (ownProperties) + //break; + /*if (accessorPropertiesOnly) + break;*/ + } + if (accessorPropertiesOnly) { - long initialPos = ret_debugger_cmd_reader.BaseStream.Position; - int valtype = ret_debugger_cmd_reader.ReadByte(); - ret_debugger_cmd_reader.BaseStream.Position = initialPos; - var fieldValue = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, field.Name, token); - if (withSetter) + var retAfterRemove = new JArray(); + List> allFields = new List>(); + for (int i = 0; i < typeId.Count; i++) { - var command_params_to_set = new MemoryStream(); - var command_params_writer_to_set = new MonoBinaryWriter(command_params_to_set); - command_params_writer_to_set.Write(objectId); - command_params_writer_to_set.Write(1); - command_params_writer_to_set.Write(field.Id); - - fieldValue.Add("set", JObject.FromObject(new { - commandSet = CommandSet.OBJECT_REF, - command = CmdObject.REF_SET_VALUES, - buffer = Convert.ToBase64String(command_params_to_set.ToArray()), - valtype, - length = command_params_to_set.ToArray().Length - })); + var fields = await GetTypeFields(sessionId, typeId[i], token); + allFields.Add(fields); } - - objectFields.Add(fieldValue); + foreach (var item in ret) + { + bool foundField = false; + for (int j = 0 ; j < allFields.Count; j++) + { + foreach (var field in allFields[j]) + { + if (field.Name.Equals(item["name"].Value())) { + if (item["isOwn"] == null || (item["isOwn"].Value() && j == 0) || !item["isOwn"].Value()) + foundField = true; + break; + } + } + if (foundField) + break; + } + if (!foundField) { + retAfterRemove.Add(item); + } + } + ret = retAfterRemove; } - - if (!withProperties) - return objectFields; - - var props = await CreateJArrayForProperties(sessionId, typeId, Array.Empty(), objectFields, false, $"dotnet:object:{objectId}", token); - return new JArray(objectFields.Union(props)); + return ret; } public async Task GetObjectProxy(SessionId sessionId, int objectId, CancellationToken token) { - var ret = await GetObjectValues(sessionId, objectId, false, true, token); - var typeId = await GetTypeIdFromObject(sessionId, objectId, token); + var ret = await GetObjectValues(sessionId, objectId, false, true, false, false, token); + var typeId = await GetTypeIdFromObject(sessionId, objectId, true, token); var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write(typeId); + command_params_writer.Write(typeId[0]); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); var nProperties = ret_debugger_cmd_reader.ReadInt32(); - for (int i = 0 ; i < nProperties; i++) { ret_debugger_cmd_reader.ReadInt32(); //propertyId @@ -1532,7 +1653,6 @@ public async Task GetObjectProxy(SessionId sessionId, int objectId, Canc if (await MethodIsStatic(sessionId, getMethodId, token)) continue; } - //Console.WriteLine("GetObjectProxy - " + ret); return ret; } From fb323d0ddf5971e217d2ab99e97a4fb04f3a5c39 Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 25 May 2021 14:59:35 -0300 Subject: [PATCH 24/48] Passing delegate tests. Failed: 31, Passed: 460 --- src/mono/mono/mini/debugger-agent.c | 11 ++ src/mono/mono/mini/debugger-protocol.h | 4 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 110 +++++++++++++++++- 3 files changed, 119 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index a3e4725b282cc..356abf476ed09 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -9672,6 +9672,17 @@ object_commands (int command, guint8 *p, guint8 *end, Buffer *buf) buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type_internal (((MonoReflectionType*)obj->vtable->type)->type)); buffer_add_domainid (buf, obj->vtable->domain); break; + case MDBGPROT_CMD_OBJECT_REF_DELEGATE_GET_METHOD: + buffer_add_methodid (buf, obj->vtable->domain, ((MonoDelegate *)obj)->method); + break; + case MDBGPROT_CMD_OBJECT_IS_DELEGATE: { + MonoType *type = m_class_get_byval_arg (obj_type); + if (m_class_is_delegate (obj_type) || (type->type == MONO_TYPE_GENERICINST && m_class_is_delegate (type->data.generic_class->container_class))) + buffer_add_byte (buf, TRUE); + else + buffer_add_byte (buf, FALSE); + break; + } default: err = ERR_NOT_IMPLEMENTED; goto exit; diff --git a/src/mono/mono/mini/debugger-protocol.h b/src/mono/mono/mini/debugger-protocol.h index e34ff51453ec6..44c79c6348f59 100644 --- a/src/mono/mono/mini/debugger-protocol.h +++ b/src/mono/mono/mini/debugger-protocol.h @@ -246,7 +246,9 @@ typedef enum { MDBGPROT_CMD_OBJECT_REF_GET_DOMAIN = 5, MDBGPROT_CMD_OBJECT_REF_SET_VALUES = 6, MDBGPROT_CMD_OBJECT_REF_GET_INFO = 7, - MDBGPROT_CMD_OBJECT_REF_GET_VALUES_ICORDBG = 8 + MDBGPROT_CMD_OBJECT_REF_GET_VALUES_ICORDBG = 8, + MDBGPROT_CMD_OBJECT_REF_DELEGATE_GET_METHOD = 9, + MDBGPROT_CMD_OBJECT_IS_DELEGATE = 10 } MdbgProtCmdObject; typedef enum { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index c5cecad2d6c21..6fa2ed6e0a075 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -266,7 +266,9 @@ internal enum CmdObject { REF_GET_DOMAIN = 5, REF_SET_VALUES = 6, REF_GET_INFO = 7, - GET_VALUES_ICORDBG = 8 + GET_VALUES_ICORDBG = 8, + REF_DELEGATE_GET_METHOD = 9, + REF_IS_DELEGATE = 10 } internal enum ElementType { @@ -653,6 +655,45 @@ public async Task GetParamCount(SessionId sessionId, int method_id, Cancell return param_count; } + public async Task GetReturnType(SessionId sessionId, int method_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(method_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_PARAM_INFO, command_params, token); + ret_debugger_cmd_reader.ReadInt32(); + ret_debugger_cmd_reader.ReadInt32(); + ret_debugger_cmd_reader.ReadInt32(); + var retType = ret_debugger_cmd_reader.ReadInt32(); + var ret = await GetTypeName(sessionId, retType, token); + return ret; + } + + public async Task GetParameters(SessionId sessionId, int method_id, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(method_id); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_PARAM_INFO, command_params, token); + ret_debugger_cmd_reader.ReadInt32(); + var paramCount = ret_debugger_cmd_reader.ReadInt32(); + ret_debugger_cmd_reader.ReadInt32(); + var retType = ret_debugger_cmd_reader.ReadInt32(); + var parameters = "("; + for (int i = 0 ; i < paramCount; i++) + { + var paramType = ret_debugger_cmd_reader.ReadInt32(); + parameters += await GetTypeName(sessionId, paramType, token); + parameters = parameters.Replace("System.Func", "Func"); + if (i + 1 < paramCount) + parameters += ","; + } + parameters += ")"; + return parameters; + } + public async Task SetBreakpoint(SessionId sessionId, int method_id, long il_offset, CancellationToken token) { var command_params = new MemoryStream(); @@ -840,6 +881,43 @@ public async Task GetMethodIdByName(SessionId sessionId, int type_id, strin var nMethods = ret_debugger_cmd_reader.ReadInt32(); return ret_debugger_cmd_reader.ReadInt32(); } + + public async Task IsDelegate(SessionId sessionId, int objectId, CancellationToken token) + { + var ret = new List(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((int)objectId); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_IS_DELEGATE, command_params, token); + return ret_debugger_cmd_reader.ReadByte() == 1; + } + + public async Task GetDelegateMethod(SessionId sessionId, int objectId, CancellationToken token) + { + var ret = new List(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((int)objectId); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_DELEGATE_GET_METHOD, command_params, token); + return ret_debugger_cmd_reader.ReadInt32(); + } + + public async Task GetDelegateMethodDescription(SessionId sessionId, int objectId, CancellationToken token) + { + var methodId = await GetDelegateMethod(sessionId, objectId, token); + + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(methodId); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME, command_params, token); + var methodName = ret_debugger_cmd_reader.ReadString(); + + var returnType = await GetReturnType(sessionId, methodId, token); + var parameters = await GetParameters(sessionId, methodId, token); + + return $"{returnType} {methodName} {parameters}"; + } public async Task InvokeMethod(SessionId sessionId, byte[] valueTypeBuffer, int method_id, string varName, CancellationToken token) { MemoryStream parms = new MemoryStream(); @@ -1215,14 +1293,20 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo case ElementType.Object: { var objectId = ret_debugger_cmd_reader.ReadInt32(); - var value = await GetClassNameFromObject(sessionId, objectId, token); + var type_id = await GetTypeIdFromObject(sessionId, objectId, false, token); + var className = await GetTypeName(sessionId, type_id[0], token); + var description = className.ToString(); + if (await IsDelegate(sessionId, objectId, token)) + { + description = await GetDelegateMethodDescription(sessionId, objectId, token); + } ret = JObject.FromObject(new { value = new { type = "object", objectId = $"dotnet:object:{objectId}", //maybe pass here the typeId and avoid another call to debugger-agent when getting fields - description = value.ToString(), - className = value.ToString(), + description, + className, }, name }); @@ -1472,7 +1556,6 @@ public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId name = propertyNameStr })); } - //Console.WriteLine("GetValueTypeProxy - " + valueTypes[valueTypeId].valueTypeProxy); return valueTypes[valueTypeId].valueTypeProxy; } @@ -1497,7 +1580,24 @@ public async Task GetArrayValues(SessionId sessionId, int arrayId, Cance public async Task GetObjectValues(SessionId sessionId, int objectId, bool withProperties, bool withSetter, bool accessorPropertiesOnly, bool ownProperties, CancellationToken token) { var typeId = await GetTypeIdFromObject(sessionId, objectId, true, token); + var className = await GetTypeName(sessionId, typeId[0], token); JArray ret = new JArray(); + if (await IsDelegate(sessionId, objectId, token)) + { + var description = await GetDelegateMethodDescription(sessionId, objectId, token); + + var obj = JObject.FromObject(new { + value = new + { + type = "symbol", + value = description, + description + }, + name = "Target" + }); + ret.Add(obj); + return ret; + } for (int i = 0; i < typeId.Count; i++) { if (!accessorPropertiesOnly) From 380e6ddb1121090e2d01a2ea9a356b9bf12cc49b Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 25 May 2021 16:32:14 -0300 Subject: [PATCH 25/48] Removing unused code. --- src/mono/mono/mini/mini-wasm-debugger.c | 897 +----------------- .../BrowserDebugProxy/DevToolsHelper.cs | 8 - .../debugger/BrowserDebugProxy/MonoProxy.cs | 2 +- src/mono/wasm/runtime/library_mono.js | 382 -------- 4 files changed, 9 insertions(+), 1280 deletions(-) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index dd56f9b44aca1..5b8064f6eb827 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -32,21 +32,10 @@ enum { EXCEPTION_MODE_ALL }; -// Flags for get_*_properties -#define GPFLAG_NONE 0x0000 -#define GPFLAG_OWN_PROPERTIES 0x0001 -#define GPFLAG_ACCESSORS_ONLY 0x0002 -#define GPFLAG_EXPAND_VALUETYPES 0x0004 - //functions exported to be used by JS G_BEGIN_DECLS -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_local_vars (int scope, int* pos, int len); EMSCRIPTEN_KEEPALIVE int mono_wasm_pause_on_exceptions (int state); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_object_properties (int object_id, int gpflags); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_array_values (int object_id, int start_idx, int count, int gpflags); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_getter_on_object (int object_id, const char* name); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_getter_on_value (void *value, MonoClass *klass, const char *name); EMSCRIPTEN_KEEPALIVE void mono_wasm_set_is_debugger_attached (gboolean is_attached); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size); 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); @@ -56,13 +45,6 @@ EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command_with_parms (int id, Mdb extern void mono_wasm_fire_bp (void); extern void mono_wasm_fire_debugger_agent_message (void); extern void mono_wasm_fire_exception (int exception_obj_id, const char* message, const char* class_name, gboolean uncaught); -extern void mono_wasm_add_obj_var (const char*, const char*, guint64); -extern void mono_wasm_add_enum_var (const char*, const char*, guint64); -extern void mono_wasm_add_func_var (const char*, const char*, guint64); -extern void mono_wasm_add_properties_var (const char*, gint32); -extern void mono_wasm_add_array_item (int); -extern void mono_wasm_set_is_async_method (guint64); -extern void mono_wasm_add_typed_value (const char *type, const char *str_value, double value); extern void mono_wasm_asm_loaded (const char *asm_name, const char *assembly_data, guint32 assembly_len, const char *pdb_data, guint32 pdb_len); G_END_DECLS @@ -84,20 +66,6 @@ static int objref_id = 0; static int pause_on_exc = EXCEPTION_MODE_NONE; static MonoObject* exception_on_runtime_invoke = NULL; -static const char* -all_getters_allowed_class_names[] = { - "System.DateTime", - "System.DateTimeOffset", - "System.TimeSpan" -}; - -static const char* -to_string_as_descr_names[] = { - "System.DateTime", - "System.DateTimeOffset", - "System.Decimal", - "System.TimeSpan" -}; #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread @@ -320,18 +288,6 @@ get_this_async_id (DbgEngineStackFrame *frame) return get_object_id (obj); } -typedef struct { - gboolean is_ss; //do I need this? -} BpEvents; - -static void -no_seq_points_found (MonoMethod *method, int offset) -{ - /* - * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space. - */ - PRINT_DEBUG_MSG (1, "Unable to find seq points for method '%s', offset 0x%x.\n", mono_method_full_name (method, TRUE), offset); -} #define DBG_NOT_SUSPENDED 1 @@ -494,455 +450,6 @@ mono_wasm_user_break (void) // mono_wasm_fire_bp (); } -static MonoObject* -get_object_from_id (int objectId) -{ - ObjRef *ref = (ObjRef *)g_hash_table_lookup (objrefs, GINT_TO_POINTER (objectId)); - if (!ref) { - PRINT_DEBUG_MSG (2, "get_object_from_id !ref: %d\n", objectId); - return NULL; - } - - MonoObject *obj = mono_gchandle_get_target_internal (ref->handle); - if (!obj) - PRINT_DEBUG_MSG (2, "get_object_from_id !obj: %d\n", objectId); - - return obj; -} - -static char* -invoke_to_string (const char *class_name, MonoClass *klass, gpointer addr) -{ - MonoObject *exc; - MonoString *mstr; - char *ret_str; - ERROR_DECL (error); - MonoObject *obj; - - // TODO: this is for a specific use case right now, - // (invoke ToString() get a preview/description for *some* types) - // and we don't want to report errors for that. - if (m_class_is_valuetype (klass)) { - MonoMethod *method; - - MONO_STATIC_POINTER_INIT (MonoMethod, to_string) - to_string = mono_class_get_method_from_name_checked (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC, error); - mono_error_assert_ok (error); - MONO_STATIC_POINTER_INIT_END (MonoMethod, to_string) - - method = mono_class_get_virtual_method (klass, to_string, error); - if (!method) - return NULL; - - MonoString *mstr = (MonoString*) mono_runtime_try_invoke_internal (method, addr , NULL, &exc, error); - if (exc || !is_ok (error)) { - PRINT_DEBUG_MSG (1, "Failed to invoke ToString for %s\n", class_name); - return NULL; - } - - return mono_string_to_utf8_checked_internal (mstr, error); - } - - obj = *(MonoObject**)addr; - if (!obj) - return NULL; - - mstr = mono_object_try_to_string (obj, &exc, error); - if (exc || !is_ok (error)) - return NULL; - - ret_str = mono_string_to_utf8_checked_internal (mstr, error); - if (!is_ok (error)) - return NULL; - - return ret_str; -} - -static char* -get_to_string_description (const char* class_name, MonoClass *klass, gpointer addr) -{ - if (!class_name || !klass || !addr) - return NULL; - - if (strcmp (class_name, "System.Guid") == 0) - return mono_guid_to_string (addr); - - for (int i = 0; i < G_N_ELEMENTS (to_string_as_descr_names); i ++) { - if (strcmp (to_string_as_descr_names [i], class_name) == 0) { - return invoke_to_string (class_name, klass, addr); - } - } - - return NULL; -} - -typedef struct { - int cur_frame; - int target_frame; - int len; - int *pos; - gboolean found; -} FrameDescData; - -/* - * this returns a string formatted like - * - * :[]: - * - * .. which is consumed by `mono_wasm_add_func_var`. It is used for - * generating this for the delegate, and it's target. - */ -static char* -mono_method_to_desc_for_js (MonoMethod *method, gboolean include_namespace) -{ - MonoMethodSignature *sig = mono_method_signature_internal (method); - char *ret_desc = mono_type_full_name (sig->ret); - char *args_desc = mono_signature_get_desc (sig, include_namespace); - - char *sig_desc = g_strdup_printf ("%s:%s:%s", ret_desc, args_desc, method->name); - - g_free (ret_desc); - g_free (args_desc); - return sig_desc; -} - -static guint64 -read_enum_value (const char *mem, int type) -{ - switch (type) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_U1: - return *(guint8*)mem; - case MONO_TYPE_I1: - return *(gint8*)mem; - case MONO_TYPE_CHAR: - case MONO_TYPE_U2: - return read16 (mem); - case MONO_TYPE_I2: - return (gint16) read16 (mem); - case MONO_TYPE_U4: - case MONO_TYPE_R4: - return read32 (mem); - case MONO_TYPE_I4: - return (gint32) read32 (mem); - case MONO_TYPE_U8: - case MONO_TYPE_I8: - case MONO_TYPE_R8: - return read64 (mem); - case MONO_TYPE_U: - case MONO_TYPE_I: -#if SIZEOF_REGISTER == 8 - return read64 (mem); -#else - return read32 (mem); -#endif - default: - g_assert_not_reached (); - } - return 0; -} - -static gboolean -nullable_try_get_value (guint8 *nullable, MonoClass *klass, gpointer* out_value) -{ - mono_class_setup_fields (klass); - g_assert (m_class_is_fields_inited (klass)); - - *out_value = NULL; - MonoClassField *klass_fields = m_class_get_fields (klass); - gpointer addr_for_has_value = mono_vtype_get_field_addr (nullable, &klass_fields[0]); - if (0 == *(guint8*)addr_for_has_value) - return FALSE; - - *out_value = mono_vtype_get_field_addr (nullable, &klass_fields[1]); - return TRUE; -} - -static gboolean -describe_value(MonoType * type, gpointer addr, int gpflags) -{ - ERROR_DECL (error); - switch (type->type) { - case MONO_TYPE_BOOLEAN: - mono_wasm_add_typed_value ("bool", NULL, *(gint8*)addr); - break; - case MONO_TYPE_I1: - mono_wasm_add_typed_value ("number", NULL, *(gint8*)addr); - break; - case MONO_TYPE_U1: - mono_wasm_add_typed_value ("number", NULL, *(guint8*)addr); - break; - case MONO_TYPE_CHAR: - mono_wasm_add_typed_value ("char", NULL, *(guint16*)addr); - break; - case MONO_TYPE_U2: - mono_wasm_add_typed_value ("number", NULL, *(guint16*)addr); - break; - case MONO_TYPE_I2: - mono_wasm_add_typed_value ("number", NULL, *(gint16*)addr); - break; - case MONO_TYPE_I4: - case MONO_TYPE_I: - mono_wasm_add_typed_value ("number", NULL, *(gint32*)addr); - break; - case MONO_TYPE_U4: - case MONO_TYPE_U: - mono_wasm_add_typed_value ("number", NULL, *(guint32*)addr); - break; - case MONO_TYPE_I8: - mono_wasm_add_typed_value ("number", NULL, *(gint64*)addr); - break; - case MONO_TYPE_U8: - mono_wasm_add_typed_value ("number", NULL, *(guint64*)addr); - break; - case MONO_TYPE_R4: - mono_wasm_add_typed_value ("number", NULL, *(float*)addr); - break; - case MONO_TYPE_R8: - mono_wasm_add_typed_value ("number", NULL, *(double*)addr); - break; - case MONO_TYPE_PTR: - case MONO_TYPE_FNPTR: { - char *class_name = mono_type_full_name (type); - const void *val = *(const void **)addr; - char *descr = g_strdup_printf ("(%s) %p", class_name, val); - - EM_ASM ({ - MONO.mono_wasm_add_typed_value ('pointer', $0, { ptr_addr: $1, klass_addr: $2 }); - }, descr, val ? addr : 0, val ? mono_class_from_mono_type_internal (type) : 0); - - g_free (descr); - g_free (class_name); - break; - } - - case MONO_TYPE_STRING: { - MonoString *str_obj = *(MonoString **)addr; - if (!str_obj) { - mono_wasm_add_typed_value ("string", NULL, 0); - } else { - char *str = mono_string_to_utf8_checked_internal (str_obj, error); - mono_error_assert_ok (error); /* FIXME report error */ - mono_wasm_add_typed_value ("string", str, 0); - g_free (str); - } - break; - } - - case MONO_TYPE_OBJECT: { - MonoObject *obj = *(MonoObject**)addr; - MonoClass *klass = obj->vtable->klass; - if (!klass) { - // boxed null - mono_wasm_add_obj_var ("object", NULL, 0); - break; - } - - type = m_class_get_byval_arg (klass); - if (type->type == MONO_TYPE_OBJECT) { - mono_wasm_add_obj_var ("object", "object", get_object_id (obj)); - break; - } - - // Boxed valuetype - if (m_class_is_valuetype (klass)) - addr = mono_object_unbox_internal (obj); - - return describe_value (type, addr, gpflags); - } - - case MONO_TYPE_GENERICINST: { - MonoClass *klass = mono_class_from_mono_type_internal (type); - if (mono_class_is_nullable (klass)) { - MonoType *targ = type->data.generic_class->context.class_inst->type_argv [0]; - - gpointer nullable_value = NULL; - if (nullable_try_get_value (addr, klass, &nullable_value)) { - return describe_value (targ, nullable_value, gpflags); - } else { - char* class_name = mono_type_full_name (type); - mono_wasm_add_obj_var (class_name, NULL, 0); - g_free (class_name); - break; - } - } - - if (mono_type_generic_inst_is_valuetype (type)) - goto handle_vtype; - /* - * else fallthrough - */ - } - - case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: - case MONO_TYPE_CLASS: { - MonoObject *obj = *(MonoObject**)addr; - if (!obj) { - char *class_name = mono_type_full_name (type); - mono_wasm_add_func_var (class_name, NULL, 0); - g_free (class_name); - return TRUE; - } - MonoClass *klass = type->data.klass; - - if (m_class_is_valuetype (mono_object_class (obj))) { - addr = mono_object_unbox_internal (obj); - type = m_class_get_byval_arg (mono_object_class (obj)); - goto handle_vtype; - } - - char *class_name = mono_type_full_name (type); - int obj_id = get_object_id (obj); - - if (type-> type == MONO_TYPE_ARRAY || type->type == MONO_TYPE_SZARRAY) { - MonoArray *array = (MonoArray *)obj; - EM_ASM ({ - MONO.mono_wasm_add_typed_value ('array', $0, { objectId: $1, length: $2 }); - }, class_name, obj_id, mono_array_length_internal (array)); - } else if (m_class_is_delegate (klass) || (type->type == MONO_TYPE_GENERICINST && m_class_is_delegate (type->data.generic_class->container_class))) { - MonoMethod *method; - - if (type->type == MONO_TYPE_GENERICINST) - klass = type->data.generic_class->container_class; - - method = mono_get_delegate_invoke_internal (klass); - if (!method) { - mono_wasm_add_func_var (class_name, NULL, -1); - } else { - MonoMethod *tm = ((MonoDelegate *)obj)->method; - char *tm_desc = NULL; - if (tm) - tm_desc = mono_method_to_desc_for_js (tm, FALSE); - - mono_wasm_add_func_var (class_name, tm_desc, obj_id); - g_free (tm_desc); - } - } else { - char *to_string_val = get_to_string_description (class_name, klass, addr); - mono_wasm_add_obj_var (class_name, to_string_val, obj_id); - g_free (to_string_val); - } - g_free (class_name); - break; - } - - handle_vtype: - case MONO_TYPE_VALUETYPE: { - g_assert (addr); - MonoClass *klass = mono_class_from_mono_type_internal (type); - char *class_name = mono_type_full_name (type); - - if (m_class_is_enumtype (klass)) { - MonoClassField *field; - gpointer iter = NULL; - const char *p; - MonoTypeEnum def_type; - guint64 field_value; - guint64 value__ = 0xDEAD; - GString *enum_members = g_string_new (""); - int base_type = mono_class_enum_basetype_internal (klass)->type; - - while ((field = mono_class_get_fields_internal (klass, &iter))) { - if (strcmp ("value__", mono_field_get_name (field)) == 0) { - value__ = read_enum_value (mono_vtype_get_field_addr (addr, field), base_type); - continue; - } - - if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) - continue; - if (mono_field_is_deleted (field)) - continue; - - p = mono_class_get_field_default_value (field, &def_type); - /* this is to correctly increment `p` in the blob */ - /* len = */ mono_metadata_decode_blob_size (p, &p); - - field_value = read_enum_value (p, base_type); - - g_string_append_printf (enum_members, ",%s:%llu", mono_field_get_name (field), field_value); - } - - mono_wasm_add_enum_var (class_name, enum_members->str, value__); - g_string_free (enum_members, TRUE); - } else { - char *to_string_val = get_to_string_description (class_name, klass, addr); - - if (gpflags & GPFLAG_EXPAND_VALUETYPES) { - int32_t size = mono_class_value_size (klass, NULL); - void *value_buf = g_malloc0 (size); - mono_value_copy_internal (value_buf, addr, klass); - - EM_ASM ({ - MONO.mono_wasm_add_typed_value ($0, $1, { toString: $2, value_addr: $3, value_size: $4, klass: $5 }); - }, "begin_vt", class_name, to_string_val, value_buf, size, klass); - - g_free (value_buf); - - // FIXME: isAsyncLocalThis - describe_object_properties_for_klass (addr, klass, FALSE, gpflags); - mono_wasm_add_typed_value ("end_vt", NULL, 0); - } else { - EM_ASM ({ - MONO.mono_wasm_add_typed_value ($0, $1, { toString: $2 }); - }, "unexpanded_vt", class_name, to_string_val); - } - g_free (to_string_val); - } - g_free (class_name); - break; - } - default: { - char *type_name = mono_type_full_name (type); - char *msg = g_strdup_printf("can't handle type %s [%p, %x]", type_name, type, type->type); - mono_wasm_add_typed_value ("string", msg, 0); - g_free (msg); - g_free (type_name); - } - } - return TRUE; -} - -static gboolean -are_getters_allowed (const char *class_name) -{ - for (int i = 0; i < G_N_ELEMENTS (all_getters_allowed_class_names); i ++) { - if (strcmp (class_name, all_getters_allowed_class_names [i]) == 0) - return TRUE; - } - - return FALSE; -} - -static gboolean -invoke_and_describe_getter_value (MonoObject *obj, MonoProperty *p) -{ - ERROR_DECL (error); - MonoObject *res; - MonoObject *exc; - - MonoMethodSignature *sig = mono_method_signature_internal (p->get); - - res = mono_runtime_try_invoke_internal (p->get, obj, NULL, &exc, error); - if (!is_ok (error) && exc == NULL) - exc = (MonoObject *) mono_error_convert_to_exception (error); - if (exc) - { - const char *class_name = mono_class_full_name (mono_object_class (exc)); - ERROR_DECL (local_error); - char *str = mono_string_to_utf8_checked_internal (((MonoException*)exc)->message, local_error); - mono_error_assert_ok (local_error); /* FIXME report error */ - char *msg = g_strdup_printf("%s: %s", class_name, str); - mono_wasm_add_typed_value ("string", msg, 0); - g_free (msg); - return TRUE; - } - else if (!res || !m_class_is_valuetype (mono_object_class (res))) - return describe_value (sig->ret, &res, GPFLAG_EXPAND_VALUETYPES); - else - return describe_value (sig->ret, mono_object_unbox_internal (res), GPFLAG_EXPAND_VALUETYPES); -} - static MonoObject* mono_runtime_try_invoke_internal (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error) { exception_on_runtime_invoke = NULL; @@ -952,296 +459,6 @@ static MonoObject* mono_runtime_try_invoke_internal (MonoMethod *method, void *o exception_on_runtime_invoke = NULL; return res; } - -static void -describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAsyncLocalThis, int gpflags) -{ - MonoClassField *f; - MonoProperty *p; - MonoMethodSignature *sig; - gboolean is_valuetype; - int pnum; - char *klass_name; - gboolean auto_invoke_getters; - gboolean is_own; - gboolean only_backing_fields; - - g_assert (klass); - MonoClass *start_klass = klass; - - only_backing_fields = gpflags & GPFLAG_ACCESSORS_ONLY; - is_valuetype = m_class_is_valuetype(klass); - if (is_valuetype) - gpflags |= GPFLAG_EXPAND_VALUETYPES; - -handle_parent: - is_own = (start_klass == klass); - klass_name = mono_class_full_name (klass); - gpointer iter = NULL; - while (obj && (f = mono_class_get_fields_internal (klass, &iter))) { - if (isAsyncLocalThis && f->name[0] == '<' && f->name[1] == '>') { - if (g_str_has_suffix (f->name, "__this")) { - mono_wasm_add_properties_var ("this", f->offset); - gpointer field_value = (guint8*)obj + f->offset; - - describe_value (f->type, field_value, gpflags); - } - - continue; - } - if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) - continue; - if (mono_field_is_deleted (f)) - continue; - - if (only_backing_fields && !g_str_has_suffix(f->name, "k__BackingField")) - continue; - - EM_ASM ({ - MONO.mono_wasm_add_properties_var ($0, { field_offset: $1, is_own: $2, attr: $3, owner_class: $4 }); - }, f->name, f->offset, is_own, f->type->attrs, klass_name); - - gpointer field_addr; - if (is_valuetype) - field_addr = mono_vtype_get_field_addr (obj, f); - else - field_addr = (guint8*)obj + f->offset; - - describe_value (f->type, field_addr, gpflags); - } - - auto_invoke_getters = are_getters_allowed (klass_name); - iter = NULL; - pnum = 0; - while ((p = mono_class_get_properties (klass, &iter))) { - if (p->get->name) { //if get doesn't have name means that doesn't have a getter implemented and we don't want to show value, like VS debug - if (isAsyncLocalThis && (p->name[0] != '<' || (p->name[0] == '<' && p->name[1] == '>'))) - continue; - - sig = mono_method_signature_internal (p->get); - if (sig->param_count != 0) { - // getters with params are not shown - continue; - } - - if (p->get->flags & METHOD_ATTRIBUTE_STATIC) - continue; - - EM_ASM ({ - MONO.mono_wasm_add_properties_var ($0, { field_offset: $1, is_own: $2, attr: $3, owner_class: $4 }); - }, p->name, pnum, is_own, p->attrs, klass_name); - - gboolean vt_self_type_getter = is_valuetype && mono_class_from_mono_type_internal (sig->ret) == klass; - if (auto_invoke_getters && !vt_self_type_getter) { - invoke_and_describe_getter_value (obj, p); - } else { - // not allowed to call the getter here - char *ret_class_name = mono_class_full_name (mono_class_from_mono_type_internal (sig->ret)); - - mono_wasm_add_typed_value ("getter", ret_class_name, -1); - - g_free (ret_class_name); - continue; - } - } - pnum ++; - } - - g_free (klass_name); - - // ownProperties - // Note: ownProperties should mean that we return members of the klass itself, - // but we are going to ignore that here, because otherwise vscode/chrome don't - // seem to ask for inherited fields at all. - // if (!is_valuetype && !(gpflags & GPFLAG_OWN_PROPERTIES) && (klass = m_class_get_parent (klass))) - if (!is_valuetype && (klass = m_class_get_parent (klass))) - goto handle_parent; -} - -/* - * We return a `Target` property only for now. - * In future, we could add a `MethodInfo` too. - */ -static gboolean -describe_delegate_properties (MonoObject *obj) -{ - MonoClass *klass = mono_object_class(obj); - if (!m_class_is_delegate (klass)) - return FALSE; - - // Target, like in VS - what is this field supposed to be, anyway?? - MonoMethod *tm = ((MonoDelegate *)obj)->method; - char * sig_desc = mono_method_to_desc_for_js (tm, FALSE); - - mono_wasm_add_properties_var ("Target", -1); - mono_wasm_add_func_var (NULL, sig_desc, -1); - - g_free (sig_desc); - return TRUE; -} - -static gboolean -describe_object_properties (guint64 objectId, gboolean isAsyncLocalThis, int gpflags) -{ - PRINT_DEBUG_MSG (2, "describe_object_properties %llu, gpflags: %d\n", objectId, gpflags); - - MonoObject *obj = get_object_from_id (objectId); - if (!obj) - return FALSE; - - if (m_class_is_delegate (mono_object_class (obj))) { - // delegates get the same id format as regular objects - describe_delegate_properties (obj); - } else { - describe_object_properties_for_klass (obj, obj->vtable->klass, isAsyncLocalThis, gpflags); - } - - return TRUE; -} - -static gboolean -invoke_getter (void *obj_or_value, MonoClass *klass, const char *name) -{ - if (!obj_or_value || !klass || !name) { - PRINT_DEBUG_MSG (2, "invoke_getter: none of the arguments can be null"); - return FALSE; - } - - gpointer iter; -handle_parent: - iter = NULL; - MonoProperty *p; - while ((p = mono_class_get_properties (klass, &iter))) { - //if get doesn't have name means that doesn't have a getter implemented and we don't want to show value, like VS debug - if (!p->get->name || strcasecmp (p->name, name) != 0) - continue; - - invoke_and_describe_getter_value (obj_or_value, p); - return TRUE; - } - - if ((klass = m_class_get_parent(klass))) - goto handle_parent; - - return FALSE; -} - -static gboolean -describe_array_values (guint64 objectId, int startIdx, int count, int gpflags) -{ - if (count == 0) - return TRUE; - - int esize; - gpointer elem; - MonoArray *arr = (MonoArray*) get_object_from_id (objectId); - if (!arr) - return FALSE; - - MonoClass *klass = mono_object_class (arr); - MonoTypeEnum type = m_class_get_byval_arg (klass)->type; - if (type != MONO_TYPE_SZARRAY && type != MONO_TYPE_ARRAY) { - PRINT_DEBUG_MSG (1, "describe_array_values: object is not an array. type: 0x%x\n", type); - return FALSE; - } - - int len = arr->max_length; - if (len == 0 && startIdx == 0 && count <= 0) { - // Nothing to do - return TRUE; - } - - if (startIdx < 0 || (len > 0 && startIdx >= len)) { - PRINT_DEBUG_MSG (1, "describe_array_values: invalid startIdx (%d) for array of length %d\n", startIdx, len); - return FALSE; - } - - if (count > 0 && (startIdx + count) > len) { - PRINT_DEBUG_MSG (1, "describe_array_values: invalid count (%d) for startIdx: %d, and array of length %d\n", count, startIdx, len); - return FALSE; - } - - esize = mono_array_element_size (klass); - int endIdx = count < 0 ? len : startIdx + count; - - for (int i = startIdx; i < endIdx; i ++) { - mono_wasm_add_array_item(i); - elem = (gpointer*)((char*)arr->vector + (i * esize)); - describe_value (m_class_get_byval_arg (m_class_get_element_class (klass)), elem, gpflags); - } - return TRUE; -} - -static void -describe_async_method_locals (InterpFrame *frame, MonoMethod *method) -{ - //Async methods are special in the way that local variables can be lifted to generated class fields - gpointer addr = NULL; - if (mono_debug_lookup_method_async_debug_info (method)) { - addr = mini_get_interp_callbacks ()->frame_get_this (frame); - MonoObject *obj = *(MonoObject**)addr; - int objId = get_object_id (obj); - mono_wasm_set_is_async_method (objId); - describe_object_properties (objId, TRUE, GPFLAG_NONE); - } -} - -static void -describe_non_async_this (InterpFrame *frame, MonoMethod *method) -{ - gpointer addr = NULL; - if (mono_debug_lookup_method_async_debug_info (method)) - return; - - if (mono_method_signature_internal (method)->hasthis) { - addr = mini_get_interp_callbacks ()->frame_get_this (frame); - MonoObject *obj = *(MonoObject**)addr; - MonoClass *klass = method->klass; - MonoType *type = m_class_get_byval_arg (method->klass); - - mono_wasm_add_properties_var ("this", -1); - - if (m_class_is_valuetype (klass)) { - describe_value (type, obj, GPFLAG_EXPAND_VALUETYPES); - } else { - // this is an object, and we can retrieve the valuetypes in it later - // through the object id - describe_value (type, addr, GPFLAG_NONE); - } - } -} - -static gboolean -describe_variable (InterpFrame *frame, MonoMethod *method, MonoMethodHeader *header, int pos, int gpflags) -{ - MonoType *type = NULL; - gpointer addr = NULL; - if (pos < 0) { - MonoMethodSignature *sig = mono_method_signature_internal (method); - pos = -pos - 1; - - if (pos >= sig->param_count) { - PRINT_DEBUG_MSG(1, "BUG: describe_variable, trying to access param indexed %d, but the method (%s) has only %d params\n", pos, method->name, sig->param_count); - return FALSE; - } - - type = sig->params [pos]; - addr = mini_get_interp_callbacks ()->frame_get_arg (frame, pos); - } else { - if (pos >= header->num_locals) { - PRINT_DEBUG_MSG(1, "BUG: describe_variable, trying to access local indexed %d, but the method (%s) has only %d locals\n", pos, method->name, header->num_locals); - return FALSE; - } - - type = header->locals [pos]; - addr = mini_get_interp_callbacks ()->frame_get_local (frame, pos); - } - - PRINT_DEBUG_MSG (2, "adding val %p type [%p] %s\n", addr, type, mono_type_full_name (type)); - - return describe_value(type, addr, gpflags); -} - static gboolean write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* variableValue) { @@ -1254,7 +471,7 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia buffer_add_int (buf, 1); else if (!strcasecmp (variableValue, "False")) buffer_add_int (buf, 0); - else + else return FALSE; break; case MONO_TYPE_CHAR: @@ -1268,7 +485,7 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia return FALSE; if (val >= -128 && val <= 127) buffer_add_int (buf, val); - else + else return FALSE; break; } @@ -1278,7 +495,7 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia return FALSE; if (val >= 0 && val <= 255) buffer_add_int (buf, val); - else + else return FALSE; break; } @@ -1288,7 +505,7 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia return FALSE; if (val >= -32768 && val <= 32767) buffer_add_int (buf, val); - else + else return FALSE; break; } @@ -1298,7 +515,7 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia return FALSE; if (val >= 0 && val <= 65535) buffer_add_int (buf, val); - else + else return FALSE; break; } @@ -1308,7 +525,7 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia return FALSE; if (val >= -2147483648 && val <= 2147483647) buffer_add_int (buf, val); - else + else return FALSE; break; } @@ -1316,9 +533,9 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia intmax_t val = strtoimax (variableValue, &endptr, 10); if (errno != 0) return FALSE; - if (val >= 0 && val <= 4294967295) + if (val >= 0 && val <= 4294967295) buffer_add_int (buf, val); - else + else return FALSE; break; } @@ -1356,104 +573,6 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia return TRUE; } -static gboolean -describe_variables_on_frame (MonoStackFrameInfo *info, MonoContext *ctx, gpointer ud) -{ - ERROR_DECL (error); - FrameDescData *data = (FrameDescData*)ud; - - ++data->cur_frame; - - //skip wrappers - if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) { - return FALSE; - } - - if (data->cur_frame != data->target_frame) - return FALSE; - - data->found = TRUE; - - InterpFrame *frame = (InterpFrame*)info->interp_frame; - g_assert (frame); - MonoMethod *method = frame->imethod->method; - g_assert (method); - - MonoMethodHeader *header = mono_method_get_header_checked (method, error); - mono_error_assert_ok (error); /* FIXME report error */ - - for (int i = 0; i < data->len; i++) - { - if (!describe_variable (frame, method, header, data->pos[i], GPFLAG_EXPAND_VALUETYPES)) - mono_wasm_add_typed_value("symbol", "", 0); - } - - describe_async_method_locals (frame, method); - describe_non_async_this (frame, method); - - mono_metadata_free_mh (header); - return TRUE; -} -//FIXME this doesn't support getting the return value pseudo-var -EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_get_local_vars (int scope, int* pos, int len) -{ - if (scope < 0) - return FALSE; - - FrameDescData data; - data.target_frame = scope; - data.cur_frame = -1; - data.len = len; - data.pos = pos; - data.found = FALSE; - - mono_walk_stack_with_ctx (describe_variables_on_frame, NULL, MONO_UNWIND_NONE, &data); - - return data.found; -} - -EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_get_object_properties (int object_id, int gpflags) -{ - PRINT_DEBUG_MSG (2, "getting properties of object %d, gpflags: %d\n", object_id, gpflags); - - return describe_object_properties (object_id, FALSE, gpflags); -} - -EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_get_array_values (int object_id, int start_idx, int count, int gpflags) -{ - PRINT_DEBUG_MSG (2, "getting array values %d, startIdx: %d, count: %d, gpflags: 0x%x\n", object_id, start_idx, count, gpflags); - - return describe_array_values (object_id, start_idx, count, gpflags); -} - -EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_invoke_getter_on_object (int object_id, const char* name) -{ - MonoObject *obj = get_object_from_id (object_id); - if (!obj) - return FALSE; - - return invoke_getter (obj, mono_object_class (obj), name); -} - -EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_invoke_getter_on_value (void *value, MonoClass *klass, const char *name) -{ - PRINT_DEBUG_MSG (2, "mono_wasm_invoke_getter_on_value: v: %p klass: %p, name: %s\n", value, klass, name); - if (!klass || !value) - return FALSE; - - if (!m_class_is_valuetype (klass)) { - PRINT_DEBUG_MSG (2, "mono_wasm_invoke_getter_on_value: klass is not a valuetype. name: %s\n", mono_class_full_name (klass)); - return FALSE; - } - - return invoke_getter (value, klass, name); -} - EMSCRIPTEN_KEEPALIVE void mono_wasm_set_is_debugger_attached (gboolean is_attached) { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index f9cb8391a2804..0f35e1d6f017f 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -180,12 +180,6 @@ internal class MonoCommands public static MonoCommands GetLoadedFiles() => new MonoCommands("MONO.mono_wasm_get_loaded_files()"); - public static MonoCommands EvaluateMemberAccess(int scopeId, string expr, params VarInfo[] vars) - { - var var_ids = vars.Select(v => new { index = v.Index, name = v.Name }).ToArray(); - return new MonoCommands($"MONO.mono_wasm_eval_member_access({scopeId}, {JsonConvert.SerializeObject(var_ids)}, '', '{expr}')"); - } - public static MonoCommands SendDebuggerAgentCommand(int id, int command_set, int command, string command_parameters) { return new MonoCommands($"MONO.mono_wasm_send_dbg_command ({id}, {command_set}, {command},'{command_parameters}')"); @@ -196,8 +190,6 @@ public static MonoCommands SendDebuggerAgentCommandWithParms(int id, int command return new MonoCommands($"MONO.mono_wasm_send_dbg_command_with_parms ({id}, {command_set}, {command},'{command_parameters}', {len}, {type}, '{parm}')"); } - public static MonoCommands ReleaseObject(DotnetObjectId objectId) => new MonoCommands($"MONO.mono_wasm_release_object('{objectId}')"); - public static MonoCommands CallFunctionOn(JToken args) => new MonoCommands($"MONO.mono_wasm_call_function_on ({args.ToString()})"); public static MonoCommands Resume() => new MonoCommands($"MONO.mono_wasm_debugger_resume ()"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index f859ef3ad7eb4..41614bbe877ea 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -386,7 +386,7 @@ protected override async Task AcceptCommand(MessageId id, string method, J if (!(DotnetObjectId.TryParse(args["objectId"], out DotnetObjectId objectId) && objectId.Scheme == "cfo_res")) break; - await SendMonoCommand(id, MonoCommands.ReleaseObject(objectId), token); + //await SendMonoCommand(id, MonoCommands.ReleaseObject(objectId), token); SendResponse(id, Result.OkFromObject(new { }), token); return true; } diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 2575184c1688b..7c3d25c4049b5 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -852,45 +852,6 @@ var MonoSupportLib = { return res; }, - // @var_list: [ { index: , name: }, .. ] - mono_wasm_get_variables: function(scope, var_list) { - const numBytes = var_list.length * Int32Array.BYTES_PER_ELEMENT; - const ptr = Module._malloc(numBytes); - let heapBytes = new Int32Array(Module.HEAP32.buffer, ptr, numBytes); - for (let i=0; i ({ containerId: this._async_method_objectId, fieldOffset: v.fieldOffset })); - - for (let i in res) { - const res_name = res [i].name; - if (this._async_method_objectId != 0) { - //Async methods are special in the way that local variables can be lifted to generated class fields - //value of "this" comes here either - if (res_name !== undefined && res_name.indexOf ('>') > 0) { - // For async methods, we get the names too, so use that - // ALTHOUGH, the name wouldn't have `<>` for method args - res [i].name = res_name.substring (1, res_name.indexOf ('>')); - } - } else if (res_name === undefined && var_list [i] !== undefined) { - // For non-async methods, we just have the var id, but we have the name - // from the caller - res [i].name = var_list [i].name; - } - } - - this._post_process_details(res); - return res; - }, - // Keep in sync with the flags in mini-wasm-debugger.c _get_properties_args_to_gpflags: function (args) { let gpflags =0; @@ -909,52 +870,6 @@ var MonoSupportLib = { return gpflags; }, - /** - * @param {number} idNum - * @param {boolean} expandValueTypes - * @returns {object} - */ - _get_object_properties: function(idNum, args={}) { - let gpflags = this._get_properties_args_to_gpflags (args); - - let { res_ok, res } = this.mono_wasm_get_object_properties_info (idNum, gpflags); - if (!res_ok) - throw new Error (`Failed to get properties for ${idNum}`); - - res = MONO._filter_automatic_properties (res, args.accessorPropertiesOnly === true); - res = this._assign_vt_ids (res, v => ({ containerId: idNum, fieldOffset: v.fieldOffset })); - res = this._post_process_details (res); - - return res; - }, - - /** - * @param {WasmId} id - * @param {number} [startIdx=0] - * @param {number} [count=-1] - * @param {boolean} [expandValueTypes=false] - * @returns {object[]} - */ - _get_array_values: function (id, startIdx = 0, count = -1, expandValueTypes = false) { - if (isNaN (id.o.arrayId) || isNaN (startIdx)) - throw new Error (`Invalid array id: ${id.idStr}`); - - let gpflags = this._get_properties_args_to_gpflags({ expandValueTypes }); - let { res_ok, res } = this.mono_wasm_get_array_values_info (id.o.arrayId, startIdx, count, gpflags); - if (!res_ok) - throw new Error (`Failed to get properties for array id ${id.idStr}`); - - res = this._assign_vt_ids (res, (_, i) => ({ arrayId: id.o.arrayId, arrayIdx: Number (startIdx) + i})); - - for (let i = 0; i < res.length; i ++) { - let value = res [i].value; - if (value.objectId !== undefined && value.objectId.startsWith("dotnet:pointer")) - this._new_or_add_id_props ({ objectId: value.objectId, props: { varName: `[${i}]` } }); - } - res = this._post_process_details (res); - return res; - }, - _post_process_details: function (details) { if (details == undefined) return {}; @@ -1179,69 +1094,6 @@ var MonoSupportLib = { delete this._cache_call_function_res[objectId]; }, - /** - * @param {string} objectIdStr objectId - * @param {string} name property name - * @returns {object} return value - */ - _invoke_getter: function (objectIdStr, name) { - const id = this._parse_object_id (objectIdStr); - if (id === undefined) - throw new Error (`Invalid object id: ${objectIdStr}`); - - let getter_res; - if (id.scheme == 'object') { - if (isNaN (id.o) || id.o < 0) - throw new Error (`Invalid object id: ${objectIdStr}`); - - let { res_ok, res } = this.mono_wasm_invoke_getter_on_object_info (id.o, name); - if (!res_ok) - throw new Error (`Invoking getter on ${objectIdStr} failed`); - - getter_res = res; - } else if (id.scheme == 'valuetype') { - const id_props = this._get_id_props (objectIdStr); - if (id_props === undefined) - throw new Error (`Unknown valuetype id: ${objectIdStr}`); - - if (typeof id_props.value64 !== 'string' || isNaN (id_props.klass)) - throw new Error (`Bug: Cannot invoke getter on ${objectIdStr}, because of missing or invalid klass/value64 fields. idProps: ${JSON.stringify (id_props)}`); - - const dataPtr = Module._malloc (id_props.value64.length); - const dataHeap = new Uint8Array (Module.HEAPU8.buffer, dataPtr, id_props.value64.length); - dataHeap.set (new Uint8Array (this._base64_to_uint8 (id_props.value64))); - - let { res_ok, res } = this.mono_wasm_invoke_getter_on_value_info (dataHeap.byteOffset, id_props.klass, name); - Module._free (dataHeap.byteOffset); - - if (!res_ok) { - console.debug (`Invoking getter on valuetype ${objectIdStr}, with props: ${JSON.stringify (id_props)} failed`); - throw new Error (`Invoking getter on valuetype ${objectIdStr} failed`); - } - getter_res = res; - } else { - throw new Error (`Only object, and valuetypes supported for getters, id: ${objectIdStr}`); - } - - getter_res = MONO._post_process_details (getter_res); - return getter_res.length > 0 ? getter_res [0] : {}; - }, - - /** - * @param {string} objectIdStr objectId - * @param {string} name property name - * @returns {object} return true if it works and false if it doesn't - */ - _set_value_on_object: function (objectIdStr, name, newValue) { - let res = MONO.mono_wasm_raise_debug_event({ - eventName: 'SetValueOnObject', - objectIdStr, - name, - newValue - }); - return true; - }, - _create_proxy_from_object_id: function (objectId, details) { if (objectId.startsWith ('dotnet:array:')) { @@ -1299,34 +1151,6 @@ var MonoSupportLib = { return fn_res; } return { type: "object", className: "Object", description: "Object", objectId: objId }; - /*if (fn_res === null || (fn_res.subtype === 'null' && fn_res.value === undefined)) { - return fn_res; - }*/ - - /*// primitive type - if (Object (fn_res) !== fn_res) - return fn_res;*/ - - /* - // return .value, if it is a primitive type - if (fn_res.value !== undefined && Object (fn_res.value.value) !== fn_res.value.value) - return fn_res.value; - - if (request.returnByValue) - return {type: "object", value: fn_res};*/ - - //const fn_res_id = this._cache_call_function_res (fn_res); - /*if (Object.getPrototypeOf (fn_res) == Array.prototype) { - return { - type: "object", - subtype: "array", - className: "Array", - description: `Array(${fn_res.length})`, - objectId: fn_res_id - }; - } else { - return { type: "object", className: "Object", description: "Object", objectId: fn_res_id }; - }*/ }, _clear_per_step_state: function () { @@ -1933,71 +1757,6 @@ var MonoSupportLib = { return MONO.loaded_assets; }, - mono_wasm_add_null_var: function(className) - { - let fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); - if (!fixed_class_name) { - // Eg, when a @className is passed from js itself, like - // mono_wasm_add_null_var ("string") - fixed_class_name = className; - } - MONO.var_info.push ({value: { - type: "object", - className: fixed_class_name, - description: fixed_class_name, - subtype: "null" - }}); - }, - - _mono_wasm_add_string_var: function(var_value) { - if (var_value === 0) { - MONO.mono_wasm_add_null_var ("string"); - return; - } - - MONO.var_info.push({ - value: { - type: "string", - value: var_value, - description: var_value - } - }); - }, - - _mono_wasm_add_getter_var: function(className) { - const fixed_class_name = MONO._mono_csharp_fixup_class_name (className); - var name; - if (MONO.var_info.length > 0) - name = MONO.var_info [MONO.var_info.length - 1].name; - name = (name === undefined) ? "" : name; - - MONO.var_info.push({ - get: { - className: "Function", - description: `get ${name} () {}`, - type: "function", - } - }); - }, - - _mono_wasm_add_array_var: function(className, objectId, length) { - const fixed_class_name = MONO._mono_csharp_fixup_class_name(className); - if (objectId == 0) { - MONO.mono_wasm_add_null_var (fixed_class_name); - return; - } - - MONO.var_info.push({ - value: { - type: "object", - subtype: "array", - className: fixed_class_name, - description: `${fixed_class_name}(${length})`, - objectId: this._new_or_add_id_props ({ scheme: 'array', idArgs: { arrayId: objectId } }) - } - }); - }, - // FIXME: improve _base64_to_uint8: function (base64String) { const byteCharacters = atob (base64String); @@ -2070,147 +1829,6 @@ var MonoSupportLib = { }); }, - mono_wasm_add_properties_var: function (name, args) { - if (typeof args !== 'object') - args = { field_offset: args }; - - if (args.owner_class !== undefined && args.owner_class !== 0) - args.owner_class = Module.UTF8ToString(args.owner_class); - - let name_obj = { - name: Module.UTF8ToString (name), - fieldOffset: args.field_offset, - __args: args - }; - if (args.is_own) - name_obj.isOwn = true; - - MONO.var_info.push(name_obj); - }, - - mono_wasm_add_typed_value: function (type, str_value, value) { - let type_str = type; - if (typeof type != 'string') - type_str = Module.UTF8ToString (type); - - if (str_value !== 0) - str_value = Module.UTF8ToString (str_value); - - switch (type_str) { - case "bool": { - const v = value != 0; - MONO.var_info.push ({ - value: { - type: "boolean", - value: v, - description: v.toString () - }, - writable:true - }); - break; - } - - case "char": { - const v = `${value} '${String.fromCharCode (value)}'`; - MONO.var_info.push ({ - value: { - type: "symbol", - value: v, - description: v - }, - writable:true - }); - break; - } - - case "number": - MONO.var_info.push ({ - value: { - type: "number", - value: value, - description: '' + value - }, - writable:true - }); - break; - - case "string": - MONO._mono_wasm_add_string_var (str_value); - break; - - case "getter": - MONO._mono_wasm_add_getter_var (str_value); - break; - - case "array": - MONO._mono_wasm_add_array_var (str_value, value.objectId, value.length); - break; - - case "begin_vt": - MONO._begin_value_type_var (str_value, value); - break; - - case "end_vt": - MONO._end_value_type_var (); - break; - - case "unexpanded_vt": - MONO._add_valuetype_unexpanded_var (str_value, value); - break; - - case "pointer": { - const fixed_value_str = MONO._mono_csharp_fixup_class_name (str_value); - if (value.klass_addr == 0 || value.ptr_addr == 0 || fixed_value_str.startsWith ('(void*')) { - // null or void*, which we can't deref - MONO.var_info.push({ - value: { - type: "symbol", - value: fixed_value_str, - description: fixed_value_str - } - }); - } else { - MONO.var_info.push({ - value: { - type: "object", - className: fixed_value_str, - description: fixed_value_str, - objectId: this._new_or_add_id_props ({ scheme: 'pointer', props: value }) - } - }); - } - } - break; - - case "symbol": { - if (typeof value === 'object' && value.isClassName) - str_value = MONO._mono_csharp_fixup_class_name (str_value); - - MONO.var_info.push ({ - value: { - type: "symbol", - value: str_value, - description: str_value - } - }); - } - break; - - default: { - const msg = `'${str_value}' ${value}`; - - MONO.var_info.push ({ - value: { - type: "symbol", - value: msg, - description: msg - } - }); - break; - } - } - }, - _mono_csharp_fixup_class_name: function(className) { // Fix up generic names like Foo`2 to Foo From 0712ae11cb7e0ff2d8d8e1e516da4e43e68ff62c Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 26 May 2021 14:07:10 -0300 Subject: [PATCH 26/48] Implementing exception handler. Failed: 30, Passed: 461 --- src/mono/mono/mini/debugger-agent.c | 26 +- src/mono/mono/mini/debugger-agent.h | 3 + src/mono/mono/mini/mini-wasm-debugger.c | 26 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 274 ++++++++++-------- .../BrowserDebugProxy/MonoSDBHelper.cs | 23 ++ 5 files changed, 187 insertions(+), 165 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 356abf476ed09..b845e9d78ff8b 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -3591,6 +3591,9 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx case EVENT_KIND_EXCEPTION: { EventInfo *ei = (EventInfo *)arg; buffer_add_objid (&buf, ei->exc); +#ifdef TARGET_WASM + buffer_add_byte (&buf, ei->caught); +#endif /* * We are not yet suspending, so get_objref () will not keep this object alive. So we need to do it * later after the suspension. (#12494). @@ -4513,7 +4516,6 @@ mono_ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) g_assert (tls); if (!tls->context.valid) { - printf("Received a single step request on a thread with no managed frames.\n"); PRINT_DEBUG_MSG (1, "Received a single step request on a thread with no managed frames.\n"); return ERR_INVALID_ARGUMENT; } @@ -4754,8 +4756,8 @@ debugger_agent_unhandled_exception (MonoException *exc) process_event (EVENT_KIND_EXCEPTION, &ei, 0, NULL, events, suspend_policy); } -static void -debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, +void +mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame) { if (catch_ctx == NULL && catch_frame == NULL && mini_debug_options.suspend_on_unhandled && mono_object_class (exc) != mono_defaults.threadabortexception_class) { @@ -4763,23 +4765,17 @@ debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, while (1) ; } - int i, j, suspend_policy; GSList *events; MonoJitInfo *ji, *catch_ji; EventInfo ei; DebuggerTlsData *tls = NULL; - - if (thread_to_tls != NULL) { - MonoInternalThread *thread = mono_thread_internal_current (); - - mono_loader_lock (); - tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread); - mono_loader_unlock (); - - if (tls && tls->abort_requested) + MonoInternalThread *thread = mono_thread_internal_current (); + GET_TLS_DATA(thread); + if (tls != NULL) { + if (tls->abort_requested) return; - if (tls && tls->disable_breakpoints) + if (tls->disable_breakpoints) return; } @@ -10219,7 +10215,7 @@ mono_debugger_agent_init (void) cbs.breakpoint_from_context = debugger_agent_breakpoint_from_context; cbs.free_mem_manager = debugger_agent_free_mem_manager; cbs.unhandled_exception = debugger_agent_unhandled_exception; - cbs.handle_exception = debugger_agent_handle_exception; + cbs.handle_exception = mono_debugger_agent_handle_exception; cbs.begin_exception_filter = debugger_agent_begin_exception_filter; cbs.end_exception_filter = debugger_agent_end_exception_filter; cbs.user_break = mono_dbg_debugger_agent_user_break; diff --git a/src/mono/mono/mini/debugger-agent.h b/src/mono/mono/mini/debugger-agent.h index 6064ab6a5482c..4ba7c1477fe7e 100644 --- a/src/mono/mono/mini/debugger-agent.h +++ b/src/mono/mono/mini/debugger-agent.h @@ -106,4 +106,7 @@ mono_wasm_get_tls (void); MdbgProtErrorCode mono_do_invoke_method (DebuggerTlsData *tls, MdbgProtBuffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp); +void +mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame); + #endif diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 5b8064f6eb827..897cb6e2fc1b3 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -400,30 +400,8 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) static void handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame) { - ERROR_DECL (error); - const char *default_error_message = "Failed to get exception message."; - - PRINT_DEBUG_MSG (1, "handle exception - %d - %p - %p - %p\n", pause_on_exc, exc, throw_ctx, catch_ctx); - - //normal mono_runtime_try_invoke does not capture the exception and this is a temporary workaround. - exception_on_runtime_invoke = (MonoObject*)exc; - - if (pause_on_exc == EXCEPTION_MODE_NONE) - return; - if (pause_on_exc == EXCEPTION_MODE_UNCAUGHT && catch_ctx != NULL) - return; - - int obj_id = get_object_id ((MonoObject *)exc); - char *error_message = mono_string_to_utf8_checked_internal (exc->message, error); - - const char *class_name = mono_class_full_name (mono_object_class (exc)); - PRINT_DEBUG_MSG (2, "handle exception - calling mono_wasm_fire_exc(): %d - message - %s, class_name: %s\n", obj_id, !is_ok (error) ? error_message : default_error_message, class_name); - - mono_wasm_fire_exception (obj_id, !is_ok (error) ? error_message : default_error_message, class_name, !catch_ctx); - - if (error_message != NULL) - g_free (error_message); - PRINT_DEBUG_MSG (2, "handle exception - done\n"); + mono_wasm_save_thread_context(); + mono_debugger_agent_handle_exception (exc, throw_ctx, catch_ctx, catch_frame); } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 41614bbe877ea..39c3a2ba4d731 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -394,7 +394,8 @@ protected override async Task AcceptCommand(MessageId id, string method, J case "Debugger.setPauseOnExceptions": { string state = args["state"].Value(); - await SendMonoCommand(id, MonoCommands.SetPauseOnExceptions(state), token); + await sdbHelper.EnableExceptions(id, state, token); + //await SendMonoCommand(id, MonoCommands.SetPauseOnExceptions(state), token); // Pass this on to JS too return false; } @@ -658,15 +659,133 @@ private async Task EvaluateCondition(SessionId sessionId, ExecutionContext } return false; } + private async Task SendCallStack(SessionId sessionId, ExecutionContext context, string reason, int thread_id, Breakpoint bp, JObject data, CancellationToken token) + { + var callFrames = new List(); + var frames = new List(); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(thread_id); + command_params_writer.Write(0); + command_params_writer.Write(-1); + var ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, (int) CommandSet.THREAD, (int) CmdThread.GET_FRAME_INFO, command_params, token); + var frame_count = ret_debugger_cmd_reader.ReadInt32(); + for (int j = 0; j < frame_count; j++) { + var frame_id = ret_debugger_cmd_reader.ReadInt32(); + var method_id = ret_debugger_cmd_reader.ReadInt32(); + var il_pos = ret_debugger_cmd_reader.ReadInt32(); + var flags = ret_debugger_cmd_reader.ReadByte(); + var method_token = await sdbHelper.GetMethodToken(sessionId, method_id, token); + var assembly_id = await sdbHelper.GetAssemblyIdFromMethod(sessionId, method_id, token); + var assembly_name = await sdbHelper.GetAssemblyName(sessionId, assembly_id, token); + var method_name = await sdbHelper.GetMethodName(sessionId, method_id, token); + DebugStore store = await LoadStore(sessionId, token); + AssemblyInfo asm = store.GetAssemblyByName(assembly_name); + if (asm == null) + { + assembly_name = await sdbHelper.GetAssemblyNameFull(sessionId, assembly_id, token); //maybe is a lazy loaded assembly + asm = store.GetAssemblyByName(assembly_name); + if (asm == null) + { + Log("debug", $"Unable to find assembly: {assembly_name}"); + continue; + } + } + + MethodInfo method = asm.GetMethodByToken(method_token); + + if (method == null && !asm.HasSymbols) + { + try + { + method = await LoadSymbolsOnDemand(asm, method_token, sessionId, token); + } + catch (Exception e) + { + Log("info", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name} exception: {e}"); + continue; + } + } + + if (method == null) + { + Log("debug", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}"); + continue; + } + + method.DebuggerId = method_id; + + SourceLocation location = method?.GetLocationByIl(il_pos); + // When hitting a breakpoint on the "IncrementCount" method in the standard + // Blazor project template, one of the stack frames is inside mscorlib.dll + // and we get location==null for it. It will trigger a NullReferenceException + // if we don't skip over that stack frame. + if (location == null) + { + continue; + } + + Log("debug", $"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}"); + Log("debug", $"\tmethod {method_name} location: {location}"); + frames.Add(new Frame(method, location, frame_id)); + + callFrames.Add(new + { + functionName = method_name, + callFrameId = $"dotnet:scope:{frame_id}", + functionLocation = method.StartLocation.AsLocation(), + + location = location.AsLocation(), + + url = store.ToUrl(location), + + scopeChain = new[] + { + new + { + type = "local", + @object = new + { + @type = "object", + className = "Object", + description = "Object", + objectId = $"dotnet:scope:{frame_id}", + }, + name = method_name, + startLocation = method.StartLocation.AsLocation(), + endLocation = method.EndLocation.AsLocation(), + } + } + }); + + context.CallStack = frames; + context.ThreadId = thread_id; + } + string[] bp_list = new string[bp == null ? 0 : 1]; + if (bp != null) + bp_list[0] = bp.StackId; + var o = JObject.FromObject(new + { + callFrames, + reason, + data, + hitBreakpoints = bp_list, + }); + if (!await EvaluateCondition(sessionId, context, context.CallStack.First(), bp, token)) + { + await SendCommand(sessionId, "Debugger.resume", new JObject(), token); + return true; + } + SendEvent(sessionId, "Debugger.paused", o, token); + return true; + } private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObject args, CancellationToken token) { Result res = await SendMonoCommand(sessionId, MonoCommands.GetDebuggerAgentBufferReceived(), token); if (res.IsErr) return false; - JObject data = null; - string reason = "other";//other means breakpoint ExecutionContext context = GetContext(sessionId); if (res.IsErr) { return false; @@ -677,146 +796,49 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec ret_debugger_cmd_reader.ReadBytes(11); //skip HEADER_LEN ret_debugger_cmd_reader.ReadByte(); //suspend_policy var number_of_events = ret_debugger_cmd_reader.ReadInt32(); //number of events -> should be always one - var callFrames = new List(); - var frames = new List(); for (int i = 0 ; i < number_of_events; i++) { var event_kind = (EventKind)ret_debugger_cmd_reader.ReadByte(); //event kind var request_id = ret_debugger_cmd_reader.ReadInt32(); //request id if (event_kind == EventKind.STEP) await sdbHelper.ClearSingleStep(sessionId, request_id, token); - Breakpoint bp = context.BreakpointRequests.Values.SelectMany(v => v.Locations).FirstOrDefault(b => b.RemoteId == request_id); + int thread_id = ret_debugger_cmd_reader.ReadInt32(); switch (event_kind) { + case EventKind.EXCEPTION: + { + string reason = "exception"; + int object_id = ret_debugger_cmd_reader.ReadInt32(); + var caught = ret_debugger_cmd_reader.ReadByte(); + var exceptionObject = await sdbHelper.GetObjectValues(sessionId, object_id, true, false, false, true, token); + var exceptionObjectMessage = exceptionObject.FirstOrDefault(attr => attr["name"].Value().Equals("message")); + var data = JObject.FromObject(new + { + type = "object", + subtype = "error", + className = await sdbHelper.GetClassNameFromObject(sessionId, object_id, token), + uncaught = caught == 0, + description = exceptionObjectMessage["value"]["value"].Value(), + objectId = $"dotnet:object:{object_id}" + }); + + var ret = await SendCallStack(sessionId, context, reason, thread_id, null, data, token); + return ret; + } case EventKind.USER_BREAK: case EventKind.STEP: case EventKind.BREAKPOINT: { - int thread_id = ret_debugger_cmd_reader.ReadInt32(); + Breakpoint bp = context.BreakpointRequests.Values.SelectMany(v => v.Locations).FirstOrDefault(b => b.RemoteId == request_id); + string reason = "other";//other means breakpoint int method_id = 0; if (event_kind != EventKind.USER_BREAK) method_id = ret_debugger_cmd_reader.ReadInt32(); - var command_params = new MemoryStream(); - var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write(thread_id); - command_params_writer.Write(0); - command_params_writer.Write(-1); - ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, (int) CommandSet.THREAD, (int) CmdThread.GET_FRAME_INFO, command_params, token); - var frame_count = ret_debugger_cmd_reader.ReadInt32(); - for (int j = 0; j < frame_count; j++) { - var frame_id = ret_debugger_cmd_reader.ReadInt32(); - method_id = ret_debugger_cmd_reader.ReadInt32(); - var il_pos = ret_debugger_cmd_reader.ReadInt32(); - var flags = ret_debugger_cmd_reader.ReadByte(); - var method_token = await sdbHelper.GetMethodToken(sessionId, method_id, token); - var assembly_id = await sdbHelper.GetAssemblyIdFromMethod(sessionId, method_id, token); - var assembly_name = await sdbHelper.GetAssemblyName(sessionId, assembly_id, token); - var method_name = await sdbHelper.GetMethodName(sessionId, method_id, token); - DebugStore store = await LoadStore(sessionId, token); - AssemblyInfo asm = store.GetAssemblyByName(assembly_name); - if (asm == null) - { - assembly_name = await sdbHelper.GetAssemblyNameFull(sessionId, assembly_id, token); //maybe is a lazy loaded assembly - asm = store.GetAssemblyByName(assembly_name); - if (asm == null) - { - Log("debug", $"Unable to find assembly: {assembly_name}"); - continue; - } - } - - MethodInfo method = asm.GetMethodByToken(method_token); - - if (method == null && !asm.HasSymbols) - { - try - { - method = await LoadSymbolsOnDemand(asm, method_token, sessionId, token); - } - catch (Exception e) - { - Log("info", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name} exception: {e}"); - continue; - } - } - - if (method == null) - { - Log("debug", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}"); - continue; - } - - method.DebuggerId = method_id; - - SourceLocation location = method?.GetLocationByIl(il_pos); - - // When hitting a breakpoint on the "IncrementCount" method in the standard - // Blazor project template, one of the stack frames is inside mscorlib.dll - // and we get location==null for it. It will trigger a NullReferenceException - // if we don't skip over that stack frame. - if (location == null) - { - continue; - } - - Log("debug", $"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}"); - Log("debug", $"\tmethod {method_name} location: {location}"); - frames.Add(new Frame(method, location, frame_id)); - - callFrames.Add(new - { - functionName = method_name, - callFrameId = $"dotnet:scope:{frame_id}", - functionLocation = method.StartLocation.AsLocation(), - - location = location.AsLocation(), - - url = store.ToUrl(location), - - scopeChain = new[] - { - new - { - type = "local", - @object = new - { - @type = "object", - className = "Object", - description = "Object", - objectId = $"dotnet:scope:{frame_id}", - }, - name = method_name, - startLocation = method.StartLocation.AsLocation(), - endLocation = method.EndLocation.AsLocation(), - } - } - }); - - context.CallStack = frames; - context.ThreadId = thread_id; - } - string[] bp_list = new string[bp == null ? 0 : 1]; - if (bp != null) - bp_list[0] = bp.StackId; - var o = JObject.FromObject(new - { - callFrames, - reason, - data, - hitBreakpoints = bp_list, - }); - if (!await EvaluateCondition(sessionId, context, context.CallStack.First(), bp, token)) - { - await SendCommand(sessionId, "Debugger.resume", new JObject(), token); - return true; - } - SendEvent(sessionId, "Debugger.paused", o, token); - break; + var ret = await SendCallStack(sessionId, context, reason, thread_id, bp, null, token); + return ret; } } } - - - return true; + return false; } private async Task LoadSymbolsOnDemand(AssemblyInfo asm, int method_token, SessionId sessionId, CancellationToken token) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 6fa2ed6e0a075..be435b00eb905 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1576,7 +1576,30 @@ public async Task GetArrayValues(SessionId sessionId, int arrayId, Cance } return array; } + public async Task EnableExceptions(SessionId sessionId, string state, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write((byte)EventKind.EXCEPTION); + command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_NONE); + command_params_writer.Write((byte)1); + command_params_writer.Write((byte)ModifierKind.EXCEPTION_ONLY); + command_params_writer.Write(0); //exc_class + if (state == "all") + command_params_writer.Write((byte)1); //caught + else + command_params_writer.Write((byte)0); //caught + if (state == "uncaught" || state == "all") + command_params_writer.Write((byte)1); //uncaught + else + command_params_writer.Write((byte)0); //uncaught + command_params_writer.Write((byte)1);//subclasses + command_params_writer.Write((byte)0);//not_filtered_feature + command_params_writer.Write((byte)0);//everything_else + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + return true; + } public async Task GetObjectValues(SessionId sessionId, int objectId, bool withProperties, bool withSetter, bool accessorPropertiesOnly, bool ownProperties, CancellationToken token) { var typeId = await GetTypeIdFromObject(sessionId, objectId, true, token); From d143ecf77264f25ccaacbf4bf0c5fcac7f3fd827 Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 26 May 2021 16:20:08 -0300 Subject: [PATCH 27/48] Fixing cfo returning array. Removing more code. Removing 2 tests that tests functions which does not exist anymore. Failed: 18, Passed: 471 --- .../BrowserDebugProxy/DevToolsHelper.cs | 2 + .../debugger/BrowserDebugProxy/MonoProxy.cs | 25 ++ .../debugger/DebuggerTestSuite/MonoJsTests.cs | 79 ----- src/mono/wasm/runtime/library_mono.js | 327 +----------------- 4 files changed, 44 insertions(+), 389 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index 0f35e1d6f017f..aee0de9bf851f 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -192,6 +192,8 @@ public static MonoCommands SendDebuggerAgentCommandWithParms(int id, int command public static MonoCommands CallFunctionOn(JToken args) => new MonoCommands($"MONO.mono_wasm_call_function_on ({args.ToString()})"); + public static MonoCommands GetDetails(int objectId, JToken args = null) => new MonoCommands($"MONO.mono_wasm_get_details ({objectId}, {(args ?? "{ }")})"); + public static MonoCommands Resume() => new MonoCommands($"MONO.mono_wasm_debugger_resume ()"); public static MonoCommands SetPauseOnExceptions(string state) => new MonoCommands($"MONO.mono_wasm_set_pause_on_exceptions(\"{state}\")"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 39c3a2ba4d731..11aac1e6f8aba 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -551,6 +551,13 @@ protected override async Task AcceptCommand(MessageId id, string method, J SendResponse(id, res, token); return true; } + if (objectId.Scheme == "cfo_res") + { + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + SendResponse(id, res, token); + return true; + } return false; } } @@ -619,6 +626,24 @@ internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId ob Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); return res2; } + if (objectId.Scheme == "cfo_res") + { + Result res2 = await SendMonoCommand(id, MonoCommands.GetDetails(int.Parse(objectId.Value), args), token); + // Runtime.callFunctionOn result object + string value_json_str = res2.Value["result"]?["value"]?["__value_as_json_string__"]?.Value(); + if (value_json_str != null) + { + res2 = Result.OkFromObject(new + { + result = JArray.Parse(value_json_str) + }); + } + else + { + res2 = Result.OkFromObject(new { result = new { } }); + } + return res2; + } } catch (Exception e) { Result res2 = Result.Err($"Unable to RuntimeGetProperties '{objectId}' - {e}"); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/MonoJsTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/MonoJsTests.cs index e2b796062e308..4054c6a2cea11 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/MonoJsTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/MonoJsTests.cs @@ -13,85 +13,6 @@ namespace DebuggerTests { public class MonoJsTests : DebuggerTestBase { - [Fact] - public async Task FixupNameValueObjectsWithMissingParts() - { - var bp1_res = await SetBreakpointInMethod("debugger-test.dll", "Math", "IntAdd", 3); - - var names = new JObject[] - { - JObject.FromObject(new { name = "Abc" }), - JObject.FromObject(new { name = "Def" }), - JObject.FromObject(new { name = "Xyz" }) - }; - - var values = new JObject[] - { - JObject.FromObject(new { value = TObject("testclass") }), - JObject.FromObject(new { value = TString("test string") }), - }; - - var getters = new JObject[] - { - GetterRes("xyz"), - GetterRes("unattached") - }; - - var list = new[] { names[0], names[1], values[0], names[2], getters[0], getters[1] }; - var res = await cli.SendCommand($"Runtime.evaluate", JObject.FromObject(new { expression = $"MONO._fixup_name_value_objects({JsonConvert.SerializeObject(list)})", returnByValue = true }), token); - Assert.True(res.IsOk); - - await CheckProps(res.Value["result"]["value"], new - { - Abc = TSymbol(""), - Def = TObject("testclass"), - Xyz = TGetter("xyz") - }, "#1", num_fields: 4); - - JObject.DeepEquals(getters[1], res.Value["result"]["value"].Values().ToArray()[3]); - - static JObject GetterRes(string name) => JObject.FromObject(new - { - get = new - { - className = "Function", - description = $"get {name} () {{}}", - type = "function" - } - }); - } - - [Fact] - public async Task GetParamsAndLocalsWithInvalidIndices() - { - var bp1_res = await SetBreakpointInMethod("debugger-test.dll", "Math", "IntAdd", 3); - var pause_location = await EvaluateAndCheck( - "window.setTimeout(function() { invoke_static_method('[debugger-test] Math:IntAdd', 1, 2); })", - null, -1, -1, "IntAdd"); - - var scope_id = pause_location["callFrames"][0]["callFrameId"].Value(); - var scope = int.Parse(scope_id.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[2]); - - var var_ids = new[] - { - new { index = 0, name = "one" }, - new { index = -12, name = "bad0" }, - new { index = 1231, name = "bad1" } - }; - - var expression = $"MONO.mono_wasm_get_variables({scope}, {JsonConvert.SerializeObject(var_ids)})"; - - var res = await cli.SendCommand($"Runtime.evaluate", JObject.FromObject(new { expression, returnByValue = true }), token); - Assert.True(res.IsOk); - - await CheckProps(res.Value["result"]?["value"], new - { - one = TNumber(3), - bad0 = TSymbol(""), - bad1 = TSymbol("") - }, "results"); - } - [Fact] public async Task InvalidScopeId() { diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 7c3d25c4049b5..82c2df4b854b0 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -525,287 +525,6 @@ var MonoSupportLib = { }, }, - mono_wasm_get_exception_object: function() { - var exception_obj = MONO.active_exception; - MONO.active_exception = null; - return exception_obj ; - }, - - _fixup_name_value_objects: function (var_list) { - let out_list = []; - - var i = 0; - while (i < var_list.length) { - let o = var_list [i]; - const this_has_name = o.name !== undefined; - let next_has_value_or_get_set = false; - - if (i + 1 < var_list.length) { - const next = var_list [i+1]; - next_has_value_or_get_set = next.value !== undefined || next.get !== undefined || next.set !== undefined; - } - - if (!this_has_name) { - // insert the object as-is - // Eg. in case of locals, the names are added - // later - i ++; - } else if (next_has_value_or_get_set) { - // found a {name} followed by a {value/get} - o = Object.assign (o, var_list [i + 1]); - i += 2; - } else { - // missing value/get, so add a placeholder one - o.value = { - type: "symbol", - value: "", - description: "" - }; - i ++; - } - - out_list.push (o); - } - - return out_list; - }, - - _filter_automatic_properties: function (props, accessors_only=false) { - // Note: members in @props, have derived class members, followed by - // those from parent classes - - // Note: Auto-properties have backing fields, named with a special suffix. - // @props here will have the backing field, *and* the getter. - // - // But we want to return only one name/value pair: - // [name of the auto-property] = value of the backing field - - let getters = {}; - let all_fields_except_backing_fields = {}; - let backing_fields = {}; - - // Split props into the 3 groups - backing_fields, getters, and all_fields_except_backing_fields - props.forEach(p => { - if (p.name === undefined) { - console.debug(`Bug: Found a member with no name. Skipping it. p: ${JSON.stringify(p)}`); - return; - } - - if (p.name.endsWith('k__BackingField')) { - const auto_prop_name = p.name.replace ('k__BackingField', '') - .replace ('<', '') - .replace ('>', ''); - - // Only take the first one, as that is overriding others - if (!(auto_prop_name in backing_fields)) - backing_fields[auto_prop_name] = Object.assign(p, { name: auto_prop_name }); - - } else if (p.get !== undefined) { - // if p wasn't overridden by a getter or a field, - // from a more derived class - if (!(p.name in getters) && !(p.name in all_fields_except_backing_fields)) - getters[p.name] = p; - - } else if (!(p.name in all_fields_except_backing_fields)) { - all_fields_except_backing_fields[p.name] = p; - } - }); - - // Filter/merge backing fields, and getters - Object.values(backing_fields).forEach(backing_field => { - const auto_prop_name = backing_field.name; - const getter = getters[auto_prop_name]; - - if (getter === undefined) { - // backing field with no getter - // eg. when a field overrides/`new string foo=..` - // an autoproperty - return; - } - - if (auto_prop_name in all_fields_except_backing_fields) { - delete getters[auto_prop_name]; - } else if (getter.__args.owner_class === backing_field.__args.owner_class) { - // getter+backing_field are from the same class. - // Add the backing_field value as a field - all_fields_except_backing_fields[auto_prop_name] = backing_field; - - // .. and drop the auto-prop getter - delete getters[auto_prop_name]; - } - }); - - if (accessors_only) - return Object.values(getters); - - return Object.values(all_fields_except_backing_fields).concat(Object.values(getters)); - }, - - /** Given `dotnet:object:foo:bar`, - * returns { scheme:'object', value: 'foo:bar' } - * - * Given `dotnet:pointer:{ b: 3 }` - * returns { scheme:'object', value: '{b:3}`, o: {b:3} - * - * @param {string} idStr - * @param {boolean} [throwOnError=false] - * - * @returns {WasmId} - */ - _parse_object_id: function (idStr, throwOnError = false) { - if (idStr === undefined || idStr == "" || !idStr.startsWith ('dotnet:')) { - if (throwOnError) - throw new Error (`Invalid id: ${idStr}`); - - return undefined; - } - - const [, scheme, ...rest] = idStr.split(':'); - let res = { - scheme, - value: rest.join (':'), - idStr, - o: {} - }; - - try { - res.o = JSON.parse(res.value); - // eslint-disable-next-line no-empty - } catch (e) {} - - return res; - }, - - _resolve_member_by_name: function (base_object, base_name, expr_parts) { - if (base_object === undefined || base_object.value === undefined) - throw new Error(`Bug: base_object is undefined`); - - if (base_object.value.type === 'object' && base_object.value.subtype === 'null') - throw new ReferenceError(`Null reference: ${base_name} is null`); - - if (base_object.value.type !== 'object') - throw new ReferenceError(`'.' is only supported on non-primitive types. Failed on '${base_name}'`); - - if (expr_parts.length == 0) - throw new Error(`Invalid member access expression`);//FIXME: need the full expression here - - const root = expr_parts[0]; - const props = this.mono_wasm_get_details(base_object.value.objectId, {}); - let resObject = props.find(l => l.name == root); - if (resObject !== undefined) { - if (resObject.value === undefined && resObject.get !== undefined) - resObject = this._invoke_getter(base_object.value.objectId, root); - } - - if (resObject === undefined || expr_parts.length == 1) - return resObject; - else { - expr_parts.shift(); - return this._resolve_member_by_name(resObject, root, expr_parts); - } - }, - - mono_wasm_eval_member_access: function (scope, var_list, rootObjectId, expr) { - if (expr === undefined || expr.length == 0) - throw new Error(`expression argument required`); - - let parts = expr.split('.'); - if (parts.length == 0) - throw new Error(`Invalid member access expression: ${expr}`); - - const root = parts[0]; - - const locals = this.mono_wasm_get_variables(scope, var_list); - let rootObject = locals.find(l => l.name === root); - if (rootObject === undefined) { - // check `this` - const thisObject = locals.find(l => l.name == "this"); - if (thisObject === undefined) - throw new ReferenceError(`Could not find ${root} in locals, and no 'this' found.`); - - const thisProps = this.mono_wasm_get_details(thisObject.value.objectId, {}); - rootObject = thisProps.find(tp => tp.name == root); - if (rootObject === undefined) - throw new ReferenceError(`Could not find ${root} in locals, or in 'this'`); - - if (rootObject.value === undefined && rootObject.get !== undefined) - rootObject = this._invoke_getter(thisObject.value.objectId, root); - } - - parts.shift(); - - if (parts.length == 0) - return rootObject; - - if (rootObject === undefined || rootObject.value === undefined) - throw new Error(`Could not get a value for ${root}`); - - return this._resolve_member_by_name(rootObject, root, parts); - }, - - /** - * @param {WasmId} id - * @returns {object[]} - */ - _get_vt_properties: function (id, args={}) { - let entry = this._get_id_props (id.idStr); - - if (entry === undefined || entry.members === undefined) { - if (!isNaN (id.o.containerId)) { - // We are expanding, so get *all* the members. - // Which ones to return based on @args, can be determined - // at the time of return - this._get_object_properties (id.o.containerId, { expandValueTypes: true }); - } else if (!isNaN (id.o.arrayId)) - this._get_array_values (id, Number (id.o.arrayIdx), 1, true); - else - throw new Error (`Invalid valuetype id (${id.idStr}). Can't get properties for it.`); - } - - // Let's try again - entry = this._get_id_props (id.idStr); - - if (entry !== undefined && entry.members !== undefined) { - if (args.accessorPropertiesOnly === true) - return entry.accessors; - - return entry.members; - } - - throw new Error (`Unknown valuetype id: ${id.idStr}. Failed to get properties for it.`); - }, - - /** - * - * @callback GetIdArgsCallback - * @param {object} var - * @param {number} idx - * @returns {object} - */ - - /** - * @param {object[]} vars - * @param {GetIdArgsCallback} getIdArgs - * @returns {object} - */ - _assign_vt_ids: function (vars, getIdArgs) - { - vars.forEach ((v, i) => { - // we might not have a `.value`, like in case of getters which have a `.get` instead - const value = v.value; - if (value === undefined || !value.isValueType) - return; - - if (value.objectId !== undefined) - throw new Error (`Bug: Trying to assign valuetype id, but the var already has one: ${v}`); - - value.objectId = this._new_or_add_id_props ({ scheme: 'valuetype', idArgs: getIdArgs (v, i), props: value._props }); - delete value._props; - }); - - return vars; - }, - mono_wasm_add_dbg_command_received: function(res_ok, id, buffer, buffer_len) { const assembly_data = new Uint8Array(Module.HEAPU8.buffer, buffer, buffer_len); const base64String = MONO._base64Converter.toBase64StringImpl(assembly_data); @@ -1054,33 +773,7 @@ var MonoSupportLib = { }, mono_wasm_get_details: function (objectId, args={}) { - let id = this._parse_object_id (objectId, true); - - switch (id.scheme) { - case "object": { - if (isNaN (id.value)) - throw new Error (`Invalid objectId: ${objectId}. Expected a numeric id.`); - - args.expandValueTypes = false; - return this._get_object_properties(id.value, args); - } - - case "array": - return this._get_array_values (id); - - case "valuetype": - return this._get_vt_properties(id, args); - - case "cfo_res": - return this._get_cfo_res_details (objectId, args); - - case "pointer": { - return this._get_deref_ptr_value (objectId); - } - - default: - throw new Error(`Unknown object id format: ${objectId}`); - } + return this._get_cfo_res_details (`dotnet:cfo_res:${objectId}`, args); }, _cache_call_function_res: function (obj) { @@ -1147,9 +840,23 @@ var MonoSupportLib = { if (fn_res === undefined) return { type: "undefined" }; - if (fn_res.value !== undefined ) { - return fn_res; + if (request.returnByValue) + return {type: "object", value: fn_res}; + if (Object.getPrototypeOf (fn_res) == Array.prototype) { + + const fn_res_id = this._cache_call_function_res (fn_res); + + return { + type: "object", + subtype: "array", + className: "Array", + description: `Array(${fn_res.length})`, + objectId: fn_res_id + }; } + if (fn_res.value !== undefined ) + return fn_res; + return { type: "object", className: "Object", description: "Object", objectId: objId }; }, From 0a4c9642a3ba8d2e4ab5e1737182ec70e8ceb48e Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 26 May 2021 22:40:46 -0300 Subject: [PATCH 28/48] Fix CallFunctionOn returning primitive types and null. Failed: 9, Passed: 480 --- .../debugger/BrowserDebugProxy/MonoProxy.cs | 149 +++++++----------- src/mono/wasm/runtime/library_mono.js | 9 +- 2 files changed, 67 insertions(+), 91 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 11aac1e6f8aba..d817384809afb 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -465,106 +465,75 @@ protected override async Task AcceptCommand(MessageId id, string method, J } case "Runtime.callFunctionOn": { - - if (!DotnetObjectId.TryParse(args["objectId"], out DotnetObjectId objectId)) - return false; - - if (objectId.Scheme == "scope") - { + try { + return await CallOnFunction(id, args, token); + } + catch (Exception){ SendResponse(id, Result.Exception(new ArgumentException( - $"Runtime.callFunctionOn not supported with scope ({objectId}).")), + $"Runtime.callFunctionOn not supported with ({args["objectId"]}).")), token); return true; } - if (objectId.Scheme == "valuetype") - { - args["details"] = await sdbHelper.GetValueTypeProxy(id, int.Parse(objectId.Value), token); - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - if (res.IsErr) - return false; - if (res.Value?["result"]?["value"]?["value"] != null) - { - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); - var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); - ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, token); - /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ - res = Result.OkFromObject(new { result = obj["value"]}); - SendResponse(id, res, token); - return true; - } - res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); - SendResponse(id, res, token); - return true; - } - if (objectId.Scheme == "object") - { - args["details"] = await sdbHelper.GetObjectProxy(id, int.Parse(objectId.Value), token); - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - if (res.IsErr) - return false; - if (res.Value?["result"]?["value"]?["value"] != null) - { - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); - var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); - ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, token); - res = Result.OkFromObject(new { result = obj["value"]}); - SendResponse(id, res, token); - return true; - } - res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); - SendResponse(id, res, token); - return true; - - } - if (objectId.Scheme == "pointer") - { - args["details"] = await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token); - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - if (res.IsErr) - return false; - if (res.Value?["result"]?["value"]?["value"] != null) - { - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); - var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); - ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, token); - res = Result.OkFromObject(new { result = obj["value"]}); - SendResponse(id, res, token); - return true; - } - res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); - SendResponse(id, res, token); - return true; - - } - if (objectId.Scheme == "array") - { - args["details"] = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); - SendResponse(id, res, token); - return true; - } - if (objectId.Scheme == "cfo_res") - { - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); - SendResponse(id, res, token); - return true; - } - return false; } } return false; } - + private async Task CallOnFunction(MessageId id, JObject args, CancellationToken token) + { + if (!DotnetObjectId.TryParse(args["objectId"], out DotnetObjectId objectId)) { + return false; + } + if (objectId.Scheme == "scope") + { + SendResponse(id, + Result.Exception(new ArgumentException( + $"Runtime.callFunctionOn not supported with scope ({objectId}).")), + token); + return true; + } + if (objectId.Scheme == "object" || objectId.Scheme == "valuetype" || objectId.Scheme == "pointer" || objectId.Scheme == "array") + { + if (objectId.Scheme == "object") + args["details"] = await sdbHelper.GetObjectProxy(id, int.Parse(objectId.Value), token); + if (objectId.Scheme == "valuetype") + args["details"] = await sdbHelper.GetValueTypeProxy(id, int.Parse(objectId.Value), token); + if (objectId.Scheme == "pointer") + args["details"] = await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token); + if (objectId.Scheme == "array") + args["details"] = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + if (res.IsErr) + { + SendResponse(id, res, token); + return true; + } + if (res.Value?["result"]?["value"]?["value"] != null && objectId.Scheme != "array") + { + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadByte(); //number of objects returned. + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, token); + /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ + res = Result.OkFromObject(new { result = obj["value"]}); + SendResponse(id, res, token); + return true; + } + res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + SendResponse(id, res, token); + return true; + } + if (objectId.Scheme == "cfo_res") + { + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + SendResponse(id, res, token); + return true; + } + return false; + } private async Task OnSetVariableValue(MessageId id, int scopeId, string varName, JToken varValue, CancellationToken token) { ExecutionContext ctx = GetContext(id); diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 82c2df4b854b0..b16b844d2cb41 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -806,7 +806,7 @@ var MonoSupportLib = { } else if (prop.set !== undefined ){ Object.defineProperty (proxy, prop.name, - { get () { return prop.value.value; }, + { get () { return prop.value; }, set: function (newValue) { MONO.mono_wasm_send_dbg_command_with_parms(-1, prop.set.commandSet, prop.set.command, prop.set.buffer, prop.set.length, prop.set.valtype, newValue); return MONO.commands_received.res_ok;}} ); } else { @@ -840,6 +840,13 @@ var MonoSupportLib = { if (fn_res === undefined) return { type: "undefined" }; + if (Object (fn_res) !== fn_res) + { + if (typeof(fn_res) == "object" && fn_res == null) + return { type: typeof(fn_res), subtype: `${fn_res}`, value: null }; + return { type: typeof(fn_res), description: `${fn_res}`, value: `${fn_res}`}; + } + if (request.returnByValue) return {type: "object", value: fn_res}; if (Object.getPrototypeOf (fn_res) == Array.prototype) { From d90031b4236c842a332428e9b3528ab8b62824cd Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 27 May 2021 22:11:05 -0300 Subject: [PATCH 29/48] Failed: 7, Passed: 482 --- .../debugger/BrowserDebugProxy/MonoProxy.cs | 2 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 108 +++++++++--------- src/mono/wasm/runtime/library_mono.js | 8 +- 3 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index d817384809afb..e528c38081a21 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -509,7 +509,7 @@ private async Task CallOnFunction(MessageId id, JObject args, Cancellation SendResponse(id, res, token); return true; } - if (res.Value?["result"]?["value"]?["value"] != null && objectId.Scheme != "array") + if (res.Value?["result"]?["value"]?["type"] == null) //it means that is not a buffer returned from the debugger-agent { byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index be435b00eb905..c4bde802c3126 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1720,61 +1720,67 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, boo public async Task GetObjectProxy(SessionId sessionId, int objectId, CancellationToken token) { var ret = await GetObjectValues(sessionId, objectId, false, true, false, false, token); - var typeId = await GetTypeIdFromObject(sessionId, objectId, true, token); - var command_params = new MemoryStream(); - var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write(typeId[0]); - - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); - var nProperties = ret_debugger_cmd_reader.ReadInt32(); - for (int i = 0 ; i < nProperties; i++) + var typeIds = await GetTypeIdFromObject(sessionId, objectId, true, token); + foreach (var typeId in typeIds) { - ret_debugger_cmd_reader.ReadInt32(); //propertyId - string propertyNameStr = ret_debugger_cmd_reader.ReadString(); - var getMethodId = ret_debugger_cmd_reader.ReadInt32(); - var setMethodId = ret_debugger_cmd_reader.ReadInt32(); //setmethod - ret_debugger_cmd_reader.ReadInt32(); //attrs - if (ret.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any()) - { - var attr = ret.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).First(); - - var command_params_to_set = new MemoryStream(); - var command_params_writer_to_set = new MonoBinaryWriter(command_params_to_set); - command_params_writer_to_set.Write(setMethodId); - command_params_writer_to_set.Write((byte)ElementType.Class); - command_params_writer_to_set.Write(objectId); - command_params_writer_to_set.Write(1); + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(typeId); - attr["set"] = JObject.FromObject(new { - commandSet = CommandSet.VM, - command = CmdVM.INVOKE_METHOD, - buffer = Convert.ToBase64String(command_params_to_set.ToArray()), - valtype = attr["set"]["valtype"], - length = command_params_to_set.ToArray().Length - }); - continue; - } - else + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); + var nProperties = ret_debugger_cmd_reader.ReadInt32(); + for (int i = 0 ; i < nProperties; i++) { - var command_params_to_get = new MemoryStream(); - var command_params_writer_to_get = new MonoBinaryWriter(command_params_to_get); - command_params_writer_to_get.Write(getMethodId); - command_params_writer_to_get.Write((byte)ElementType.Class); - command_params_writer_to_get.Write(objectId); - command_params_writer_to_get.Write(0); - - ret.Add(JObject.FromObject(new { - get = JObject.FromObject(new { - commandSet = CommandSet.VM, - command = CmdVM.INVOKE_METHOD, - buffer = Convert.ToBase64String(command_params_to_get.ToArray()), - length = command_params_to_get.ToArray().Length - }), - name = propertyNameStr - })); + ret_debugger_cmd_reader.ReadInt32(); //propertyId + string propertyNameStr = ret_debugger_cmd_reader.ReadString(); + var getMethodId = ret_debugger_cmd_reader.ReadInt32(); + var setMethodId = ret_debugger_cmd_reader.ReadInt32(); //setmethod + var attrValue = ret_debugger_cmd_reader.ReadInt32(); //attrs + Console.WriteLine($"{propertyNameStr} - {attrValue}"); + if (ret.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any()) + { + var attr = ret.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).First(); + + var command_params_to_set = new MemoryStream(); + var command_params_writer_to_set = new MonoBinaryWriter(command_params_to_set); + command_params_writer_to_set.Write(setMethodId); + command_params_writer_to_set.Write((byte)ElementType.Class); + command_params_writer_to_set.Write(objectId); + command_params_writer_to_set.Write(1); + if (attr["set"] != null) + { + attr["set"] = JObject.FromObject(new { + commandSet = CommandSet.VM, + command = CmdVM.INVOKE_METHOD, + buffer = Convert.ToBase64String(command_params_to_set.ToArray()), + valtype = attr["set"]["valtype"], + length = command_params_to_set.ToArray().Length + }); + } + continue; + } + else + { + var command_params_to_get = new MemoryStream(); + var command_params_writer_to_get = new MonoBinaryWriter(command_params_to_get); + command_params_writer_to_get.Write(getMethodId); + command_params_writer_to_get.Write((byte)ElementType.Class); + command_params_writer_to_get.Write(objectId); + command_params_writer_to_get.Write(0); + + ret.Add(JObject.FromObject(new { + get = JObject.FromObject(new { + commandSet = CommandSet.VM, + command = CmdVM.INVOKE_METHOD, + buffer = Convert.ToBase64String(command_params_to_get.ToArray()), + length = command_params_to_get.ToArray().Length + }), + name = propertyNameStr + })); + } + if (await MethodIsStatic(sessionId, getMethodId, token)) + continue; } - if (await MethodIsStatic(sessionId, getMethodId, token)) - continue; } return ret; } diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index b16b844d2cb41..7f1446cd842bb 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -861,10 +861,14 @@ var MonoSupportLib = { objectId: fn_res_id }; } - if (fn_res.value !== undefined ) + if (fn_res.value !== undefined || fn_res.subtype !== undefined) { return fn_res; + } - return { type: "object", className: "Object", description: "Object", objectId: objId }; + if (fn_res == proxy) + return { type: "object", className: "Object", description: "Object", objectId: objId }; + const fn_res_id = this._cache_call_function_res (fn_res); + return { type: "object", className: "Object", description: "Object", objectId: fn_res_id }; }, _clear_per_step_state: function () { From c41ad02131b0ca586f479be253833043a33f39ce Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 28 May 2021 15:53:58 -0300 Subject: [PATCH 30/48] Fixing some tests. Failed: 2, Passed: 488 --- .../MemberReferenceResolver.cs | 14 +++- .../debugger/BrowserDebugProxy/MonoProxy.cs | 2 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 77 ++++++++++++++----- 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 99ca33136e122..50f9e2233b380 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -33,6 +33,18 @@ public MemberReferenceResolver(MonoProxy proxy, ExecutionContext ctx, SessionId } public async Task GetValueFromObject(JToken objRet, CancellationToken token) { + if (objRet["value"]?["className"]?.Value() == "System.Exception") + { + if (DotnetObjectId.TryParse(objRet?["value"]?["objectId"]?.Value(), out DotnetObjectId objectId)) + { + var exceptionObject = await proxy.sdbHelper.GetObjectValues(sessionId, int.Parse(objectId.Value), true, false, false, true, token); + var exceptionObjectMessage = exceptionObject.FirstOrDefault(attr => attr["name"].Value().Equals("_message")); + exceptionObjectMessage["value"]["value"] = objRet["value"]?["className"]?.Value() + ": " + exceptionObjectMessage["value"]?["value"]?.Value(); + return exceptionObjectMessage["value"]?.Value(); + } + return objRet["value"]?.Value(); + } + if (objRet["value"]?.Value() != null) return objRet["value"]?.Value(); if (objRet["get"]?.Value() != null) @@ -43,7 +55,7 @@ public async Task GetValueFromObject(JToken objRet, CancellationToken t var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.WriteObj(objectId, proxy.sdbHelper); var ret = await proxy.sdbHelper.InvokeMethod(sessionId, command_params.ToArray(), objRet["get"]["methodId"].Value(), objRet["name"].Value(), token); - return ret["value"]?.Value(); + return await GetValueFromObject(ret, token); } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index e528c38081a21..5fa14b63fa667 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -515,7 +515,7 @@ private async Task CallOnFunction(MessageId id, JObject args, Cancellation var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, token); + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, -1, token); /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ res = Result.OkFromObject(new { result = obj["value"]}); SendResponse(id, res, token); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index c4bde802c3126..90f815e549def 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -326,6 +326,14 @@ internal enum MonoTypeNameFormat{ MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED } + internal enum StepFilter { + None = 0, + StaticCtor = 1, + DebuggerHidden = 2, + DebuggerStepThrough = 4, + DebuggerNonUserCode = 8 + } + internal class MonoBinaryReader : BinaryReader { public MonoBinaryReader(Stream stream) : base(stream) {} @@ -391,7 +399,6 @@ public override unsafe int ReadInt32() { byte[] data = new byte[4]; Read(data, 0, 4); - int ret; fixed (byte *src = &data[0]){ PutBytesBE ((byte *) &ret, src, 4); @@ -399,6 +406,18 @@ public override unsafe int ReadInt32() return ret; } + public override unsafe double ReadDouble() + { + byte[] data = new byte[8]; + Read(data, 0, 8); + + double ret; + fixed (byte *src = &data[0]){ + PutBytesBE ((byte *) &ret, src, 8); + } + return ret; + } + public override unsafe uint ReadUInt32() { byte[] data = new byte[4]; @@ -459,10 +478,12 @@ internal class FieldTypeClass { public int Id { get; } public string Name { get; } - public FieldTypeClass(int id, string name) + public int TypeId { get; } + public FieldTypeClass(int id, string name, int typeId) { Id = id; Name = name; + TypeId = typeId; } } internal class ValueTypeClass @@ -733,6 +754,7 @@ public async Task Step(SessionId sessionId, int thread_id, StepKind kind, command_params_writer.Write(thread_id); command_params_writer.Write((int)0); command_params_writer.Write((int)kind); + command_params_writer.Write((int)StepFilter.StaticCtor); //filter var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); if (ret_debugger_cmd_reader != null) return true; @@ -767,7 +789,7 @@ public async Task> GetTypeFields(SessionId sessionId, int t { int fieldId = ret_debugger_cmd_reader.ReadInt32(); //fieldId string fieldNameStr = ret_debugger_cmd_reader.ReadString(); - ret_debugger_cmd_reader.ReadInt32(); //typeId + int typeId = ret_debugger_cmd_reader.ReadInt32(); //typeId ret_debugger_cmd_reader.ReadInt32(); //attrs if (fieldNameStr.Contains("k__BackingField")) { @@ -775,7 +797,7 @@ public async Task> GetTypeFields(SessionId sessionId, int t fieldNameStr = fieldNameStr.Replace("<", ""); fieldNameStr = fieldNameStr.Replace(">", ""); } - ret.Add(new FieldTypeClass(fieldId, fieldNameStr)); + ret.Add(new FieldTypeClass(fieldId, fieldNameStr, typeId)); } return ret; } @@ -909,7 +931,9 @@ public async Task GetDelegateMethodDescription(SessionId sessionId, int var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(methodId); - + Console.WriteLine("methodId - " + methodId); + if (methodId == 0) + return ""; var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME, command_params, token); var methodName = ret_debugger_cmd_reader.ReadString(); @@ -927,7 +951,7 @@ public async Task InvokeMethod(SessionId sessionId, byte[] valueTypeBuf command_params_writer.Write(0); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.INVOKE_METHOD, parms, token); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, false, token); + return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, false, -1, token); } public async Task CreateJArrayForProperties(SessionId sessionId, int typeId, byte[] object_buffer, JArray attributes, bool isAutoExpandable, string objectId, bool isOwn, CancellationToken token) { @@ -992,7 +1016,7 @@ public async Task GetPointerContent(SessionId sessionId, int pointerId, var varName = pointerValues[pointerId].varName; if (int.TryParse(varName, out _)) varName = $"[{varName}]"; - return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "*" + varName, false, token); + return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "*" + varName, false, -1, token); } public async Task GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token) { @@ -1036,7 +1060,7 @@ public bool AutoInvokeToString(string className) { return false; } - public async Task CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, string name, bool isOwn, CancellationToken token) + public async Task CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, string name, bool isOwn, int typeIdFromAttribute, CancellationToken token) { long initialPos = ret_debugger_cmd_reader == null ? 0 : ret_debugger_cmd_reader.BaseStream.Position; ElementType etype = (ElementType)ret_debugger_cmd_reader.ReadByte(); @@ -1199,9 +1223,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo } case ElementType.R8: { - long high = (long) ret_debugger_cmd_reader.ReadInt32(); - long low = (long) ret_debugger_cmd_reader.ReadInt32(); - double value = BitConverter.Int64BitsToDouble(((high << 32) | low)); + double value = ret_debugger_cmd_reader.ReadDouble(); ret = JObject.FromObject(new { value = new { @@ -1293,12 +1315,31 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo case ElementType.Object: { var objectId = ret_debugger_cmd_reader.ReadInt32(); + var className = ""; var type_id = await GetTypeIdFromObject(sessionId, objectId, false, token); - var className = await GetTypeName(sessionId, type_id[0], token); + className = await GetTypeName(sessionId, type_id[0], token); var description = className.ToString(); if (await IsDelegate(sessionId, objectId, token)) { + if (typeIdFromAttribute != -1) + { + className = await GetTypeName(sessionId, typeIdFromAttribute, token); + } + description = await GetDelegateMethodDescription(sessionId, objectId, token); + if (description == "") + { + ret = JObject.FromObject(new { + value = new + { + type = "symbol", + description = className.ToString(), + value = className.ToString() + }, + name + }); + break; + } } ret = JObject.FromObject(new { value = new @@ -1326,7 +1367,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo { ret_debugger_cmd_reader.ReadByte(); //ignoring the boolean type var isNull = ret_debugger_cmd_reader.ReadInt32(); - var value = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, name, false, token); + var value = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, name, false, -1, token); if (isNull != 0) ret = value; else @@ -1345,7 +1386,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo } for (int i = 0; i < numFields ; i++) { - fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, true, token); + fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, true, fields.ElementAt(i).TypeId, token); valueTypeFields.Add(fieldValueType); } @@ -1493,13 +1534,13 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_VALUES, command_params, token); foreach (var var in var_ids) { - var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, var.Name, false, token); + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, var.Name, false, -1, token); locals.Add(var_json); } if (!method.IsStatic()) { ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); - var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "this", false, token); + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "this", false, -1, token); var_json.Add("fieldOffset", -1); locals.Add(var_json); } @@ -1571,7 +1612,7 @@ public async Task GetArrayValues(SessionId sessionId, int arrayId, Cance JArray array = new JArray(); for (int i = 0 ; i < length ; i++) { - var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, i.ToString(), false, token); + var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, i.ToString(), false, -1, token); array.Add(var_json); } return array; @@ -1644,7 +1685,7 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, boo long initialPos = ret_debugger_cmd_reader.BaseStream.Position; int valtype = ret_debugger_cmd_reader.ReadByte(); ret_debugger_cmd_reader.BaseStream.Position = initialPos; - var fieldValue = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, field.Name, i == 0, token); + var fieldValue = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, field.Name, i == 0, field.TypeId, token); if (ret.Where(attribute => attribute["name"].Value().Equals(fieldValue["name"].Value())).Any()) { continue; From 2581d1da8e688d041c7fb196be909536210efb0a Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 28 May 2021 19:50:30 -0300 Subject: [PATCH 31/48] Removing a lot of code. Failed: 4, Passed: 485 --- src/mono/mono/mini/debugger-agent.c | 24 +- src/mono/mono/mini/debugger-agent.h | 3 + src/mono/mono/mini/debugger-engine.h | 8 +- src/mono/mono/mini/mini-wasm-debugger.c | 111 +----- .../BrowserDebugProxy/DevToolsHelper.cs | 4 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 4 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 2 +- src/mono/wasm/runtime/library_mono.js | 359 ------------------ 8 files changed, 31 insertions(+), 484 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index b845e9d78ff8b..465ca3cd63740 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -461,11 +461,8 @@ static MonoContext* tls_get_restore_state (void *the_tls); static gboolean try_process_suspend (void *tls, MonoContext *ctx, gboolean from_breakpoint); static gboolean begin_breakpoint_processing (void *tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal); static void begin_single_step_processing (MonoContext *ctx, gboolean from_signal); -static void ss_discard_frame_context (void *the_tls); -static void ss_calculate_framecount (void *tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes); static gboolean ensure_jit (DbgEngineStackFrame* the_frame); static int ensure_runtime_is_suspended (void); -static int get_this_async_id (DbgEngineStackFrame *frame); static int handle_multiple_ss_requests (void); static GENERATE_TRY_GET_CLASS_WITH_CACHE (fixed_buffer, "System.Runtime.CompilerServices", "FixedBufferAttribute") @@ -690,11 +687,11 @@ debugger_agent_init (void) cbs.try_process_suspend = try_process_suspend; cbs.begin_breakpoint_processing = begin_breakpoint_processing; cbs.begin_single_step_processing = begin_single_step_processing; - cbs.ss_discard_frame_context = ss_discard_frame_context; - cbs.ss_calculate_framecount = ss_calculate_framecount; + cbs.ss_discard_frame_context = mono_ss_discard_frame_context; + cbs.ss_calculate_framecount = mono_ss_calculate_framecount; cbs.ensure_jit = ensure_jit; cbs.ensure_runtime_is_suspended = ensure_runtime_is_suspended; - cbs.get_this_async_id = get_this_async_id; + cbs.get_this_async_id = mono_get_this_async_id; cbs.set_set_notification_for_wait_completion_flag = set_set_notification_for_wait_completion_flag; cbs.get_notify_debugger_of_wait_completion_method = get_notify_debugger_of_wait_completion_method; cbs.create_breakpoint_events = mono_dbg_create_breakpoint_events; @@ -4060,14 +4057,15 @@ event_requests_cleanup (void) * * Ensure DebuggerTlsData fields are filled out. */ -static void -ss_calculate_framecount (void *the_tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes) +void +mono_ss_calculate_framecount (void *the_tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes) { DebuggerTlsData *tls = (DebuggerTlsData*)the_tls; - +#ifndef TARGET_WASM if (force_use_ctx || !tls->context.valid) mono_thread_state_init_from_monoctx (&tls->context, ctx); compute_frame_info (tls->thread, tls, FALSE); +#endif if (frames) *frames = (DbgEngineStackFrame**)tls->frames; if (nframes) @@ -4079,8 +4077,8 @@ ss_calculate_framecount (void *the_tls, MonoContext *ctx, gboolean force_use_ctx * * Discard frame data and invalidate any context */ -static void -ss_discard_frame_context (void *the_tls) +void +mono_ss_discard_frame_context (void *the_tls) { DebuggerTlsData *tls = (DebuggerTlsData*)the_tls; tls->context.valid = FALSE; @@ -4125,8 +4123,8 @@ breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly) //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 (DbgEngineStackFrame *frame) +int +mono_get_this_async_id (DbgEngineStackFrame *frame) { MonoClassField *builder_field; gpointer builder; diff --git a/src/mono/mono/mini/debugger-agent.h b/src/mono/mono/mini/debugger-agent.h index 4ba7c1477fe7e..bf0a06e2056fe 100644 --- a/src/mono/mono/mini/debugger-agent.h +++ b/src/mono/mono/mini/debugger-agent.h @@ -109,4 +109,7 @@ mono_do_invoke_method (DebuggerTlsData *tls, MdbgProtBuffer *buf, InvokeData *in void mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame); +void +mono_ss_discard_frame_context (void *the_tls); + #endif diff --git a/src/mono/mono/mini/debugger-engine.h b/src/mono/mono/mini/debugger-engine.h index 0a1a1afa116b4..20fe88fedb8d7 100644 --- a/src/mono/mono/mini/debugger-engine.h +++ b/src/mono/mono/mini/debugger-engine.h @@ -549,4 +549,10 @@ int mono_ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args); void -mono_ss_args_destroy (SingleStepArgs *ss_args); \ No newline at end of file +mono_ss_args_destroy (SingleStepArgs *ss_args); + +int +mono_get_this_async_id (DbgEngineStackFrame *frame); + +void +mono_ss_calculate_framecount (void *tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes); diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 897cb6e2fc1b3..b51afbe296f35 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -26,46 +26,29 @@ static int log_level = 1; -enum { - EXCEPTION_MODE_NONE, - EXCEPTION_MODE_UNCAUGHT, - EXCEPTION_MODE_ALL -}; - //functions exported to be used by JS G_BEGIN_DECLS -EMSCRIPTEN_KEEPALIVE int mono_wasm_pause_on_exceptions (int state); EMSCRIPTEN_KEEPALIVE void mono_wasm_set_is_debugger_attached (gboolean is_attached); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size); 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); //JS functions imported that we use -extern void mono_wasm_fire_bp (void); extern void mono_wasm_fire_debugger_agent_message (void); -extern void mono_wasm_fire_exception (int exception_obj_id, const char* message, const char* class_name, gboolean uncaught); extern void mono_wasm_asm_loaded (const char *asm_name, const char *assembly_data, guint32 assembly_len, const char *pdb_data, guint32 pdb_len); G_END_DECLS -static void describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAsyncLocalThis, int gpflags); static void handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame); static gboolean receive_debugger_agent_message (void *data, int len); static void assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly); -static MonoObject* mono_runtime_try_invoke_internal (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error); //FIXME move all of those fields to the profiler object static gboolean debugger_enabled; static gboolean has_pending_lazy_loaded_assemblies; -static GHashTable *objrefs; -static GHashTable *obj_to_objref; -static int objref_id = 0; -static int pause_on_exc = EXCEPTION_MODE_NONE; -static MonoObject* exception_on_runtime_invoke = NULL; - #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread @@ -93,14 +76,6 @@ void wasm_debugger_log (int level, const gchar *format, ...) g_free (mesg); } -static void -inplace_tolower (char *c) -{ - int i; - for (i = strlen (c) - 1; i >= 0; --i) - c [i] = tolower (c [i]); -} - static void jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) { @@ -145,7 +120,7 @@ collect_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) if (!mono_find_prev_seq_point_for_native_offset (method, info->native_offset, NULL, &sp)) PRINT_DEBUG_MSG (2, "collect_frames: Failed to lookup sequence point. method: %s, native_offset: %d \n", method->name, info->native_offset); - + StackFrame *frame = g_new0 (StackFrame, 1); frame->de.ji = info->ji; frame->de.domain = mono_get_root_domain (); @@ -155,7 +130,7 @@ collect_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) 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; @@ -169,7 +144,7 @@ free_frame_state (void) for (i = 0; i < frames->len; ++i) free_frame ((DbgEngineStackFrame*)g_ptr_array_index (frames, i)); g_ptr_array_set_size (frames, 0); - } + } } static void @@ -183,7 +158,7 @@ compute_frames (void) { frames = g_ptr_array_new (); } - mono_walk_stack_with_ctx (collect_frames, NULL, MONO_UNWIND_NONE, NULL); + mono_walk_stack_with_ctx (collect_frames, NULL, MONO_UNWIND_NONE, NULL); } static MonoContext* tls_get_restore_state (void *tls) @@ -236,59 +211,6 @@ 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 *frame) -{ - 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_internal (method, builder, NULL, &ex, error); - mono_error_assert_ok (error); - - return get_object_id (obj); -} - - #define DBG_NOT_SUSPENDED 1 static int @@ -312,7 +234,7 @@ mono_wasm_debugger_init (void) .ss_calculate_framecount = ss_calculate_framecount, .ensure_jit = ensure_jit, .ensure_runtime_is_suspended = ensure_runtime_is_suspended, - .get_this_async_id = get_this_async_id, + .get_this_async_id = mono_get_this_async_id, .set_set_notification_for_wait_completion_flag = set_set_notification_for_wait_completion_flag, .get_notify_debugger_of_wait_completion_method = get_notify_debugger_of_wait_completion_method, .create_breakpoint_events = mono_dbg_create_breakpoint_events, @@ -337,9 +259,6 @@ mono_wasm_debugger_init (void) mono_profiler_set_domain_loaded_callback (prof, appdomain_load); mono_profiler_set_assembly_loaded_callback (prof, assembly_loaded); - obj_to_objref = g_hash_table_new (NULL, NULL); - objrefs = g_hash_table_new_full (NULL, NULL, NULL, mono_debugger_free_objref); - mini_get_dbg_callbacks ()->handle_exception = handle_exception; mini_get_dbg_callbacks ()->user_break = mono_wasm_user_break; @@ -360,14 +279,6 @@ mono_wasm_enable_debugging (int debug_level) log_level = debug_level; } -EMSCRIPTEN_KEEPALIVE int -mono_wasm_pause_on_exceptions (int state) -{ - pause_on_exc = state; - PRINT_DEBUG_MSG (1, "setting pause on exception: %d\n", pause_on_exc); - return 1; -} - static void assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) { @@ -417,7 +328,6 @@ mono_wasm_breakpoint_hit (void) { mono_wasm_save_thread_context(); mono_de_process_breakpoint (NULL, FALSE); - // mono_wasm_fire_bp (); } void @@ -425,18 +335,8 @@ mono_wasm_user_break (void) { mono_wasm_save_thread_context(); mono_dbg_debugger_agent_user_break (); - // mono_wasm_fire_bp (); } -static MonoObject* mono_runtime_try_invoke_internal (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error) -{ - exception_on_runtime_invoke = NULL; - MonoObject* res = mono_runtime_try_invoke (method, obj, params, exc, error); - if (exception_on_runtime_invoke != NULL) - *exc = exception_on_runtime_invoke; - exception_on_runtime_invoke = NULL; - return res; -} static gboolean write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* variableValue) { @@ -601,7 +501,6 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, } else error = mono_process_dbg_packet(id, command_set, command, &no_reply, data, data + size, &buf); - EM_ASM ({ MONO.mono_wasm_add_dbg_command_received ($0, $1, $2, $3); }, error == MDBGPROT_ERR_NONE, id, buf.buf, buf.p-buf.buf); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index aee0de9bf851f..828ac7b81efff 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -196,9 +196,9 @@ public static MonoCommands SendDebuggerAgentCommandWithParms(int id, int command public static MonoCommands Resume() => new MonoCommands($"MONO.mono_wasm_debugger_resume ()"); - public static MonoCommands SetPauseOnExceptions(string state) => new MonoCommands($"MONO.mono_wasm_set_pause_on_exceptions(\"{state}\")"); - public static MonoCommands DetachDebugger() => new MonoCommands($"MONO.mono_wasm_detach_debugger()"); + + public static MonoCommands ReleaseObject(DotnetObjectId objectId) => new MonoCommands($"MONO.mono_wasm_release_object('{objectId}')"); } internal enum MonoErrorCodes diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 5fa14b63fa667..23aadaa16612f 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -386,7 +386,7 @@ protected override async Task AcceptCommand(MessageId id, string method, J if (!(DotnetObjectId.TryParse(args["objectId"], out DotnetObjectId objectId) && objectId.Scheme == "cfo_res")) break; - //await SendMonoCommand(id, MonoCommands.ReleaseObject(objectId), token); + await SendMonoCommand(id, MonoCommands.ReleaseObject(objectId), token); SendResponse(id, Result.OkFromObject(new { }), token); return true; } @@ -395,7 +395,6 @@ protected override async Task AcceptCommand(MessageId id, string method, J { string state = args["state"].Value(); await sdbHelper.EnableExceptions(id, state, token); - //await SendMonoCommand(id, MonoCommands.SetPauseOnExceptions(state), token); // Pass this on to JS too return false; } @@ -664,6 +663,7 @@ private async Task SendCallStack(SessionId sessionId, ExecutionContext con command_params_writer.Write(-1); var ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, (int) CommandSet.THREAD, (int) CmdThread.GET_FRAME_INFO, command_params, token); var frame_count = ret_debugger_cmd_reader.ReadInt32(); + //Console.WriteLine("frame_count - " + frame_count); for (int j = 0; j < frame_count; j++) { var frame_id = ret_debugger_cmd_reader.ReadInt32(); var method_id = ret_debugger_cmd_reader.ReadInt32(); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 90f815e549def..c532c2b4278fb 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -754,7 +754,7 @@ public async Task Step(SessionId sessionId, int thread_id, StepKind kind, command_params_writer.Write(thread_id); command_params_writer.Write((int)0); command_params_writer.Write((int)kind); - command_params_writer.Write((int)StepFilter.StaticCtor); //filter + command_params_writer.Write((int)(StepFilter.StaticCtor & StepFilter.DebuggerHidden)); //filter var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); if (ret_debugger_cmd_reader != null) return true; diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 7f1446cd842bb..6fae132ef91f6 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -571,91 +571,6 @@ var MonoSupportLib = { return res; }, - // Keep in sync with the flags in mini-wasm-debugger.c - _get_properties_args_to_gpflags: function (args) { - let gpflags =0; - /* - Disabled for now. Instead, we ask debugger.c to return - ~all~ the members, and then handle the filtering in mono.js . - - if (args.ownProperties) - gpflags |= 1; - if (args.accessorPropertiesOnly) - gpflags |= 2; - */ - if (args.expandValueTypes) - gpflags |= 4; - - return gpflags; - }, - - _post_process_details: function (details) { - if (details == undefined) - return {}; - - if (details.length > 0) - this._extract_and_cache_value_types(details); - - // remove __args added by add_properties_var - details.forEach(d => delete d.__args); - return details; - }, - - /** - * Gets the next id number to use for generating ids - * - * @returns {number} - */ - _next_id: function () { - return ++this._next_id_var; - }, - - _extract_and_cache_value_types: function (var_list) { - if (var_list == undefined || !Array.isArray (var_list) || var_list.length == 0) - return var_list; - - for (let i in var_list) { - let value = var_list [i].value; - if (value === undefined) - continue; - - if (value.objectId !== undefined && value.objectId.startsWith ("dotnet:pointer:")) { - let ptr_args = this._get_id_props (value.objectId); - if (ptr_args === undefined) - throw new Error (`Bug: Expected to find an entry for pointer id: ${value.objectId}`); - - // It might have been already set in some cases, like arrays - // where the name would be `0`, but we want `[0]` for pointers, - // so the deref would look like `*[0]` - ptr_args.varName = ptr_args.varName || var_list [i].name; - } - - if (value.type != "object" || value.isValueType != true || value.expanded != true) // undefined would also give us false - continue; - - if (value.members === undefined) { - // this could happen for valuetypes that maybe - // we were not able to describe, like `ref` parameters - // So, skip that - continue; - } - - // Generate objectId for expanded valuetypes - value.objectId = value.objectId || this._new_or_add_id_props ({ scheme: 'valuetype' }); - - this._extract_and_cache_value_types (value.members); - - const accessors = value.members.filter(m => m.get !== undefined); - const new_props = Object.assign ({ members: value.members, accessors }, value.__extra_vt_props); - - this._new_or_add_id_props ({ objectId: value.objectId, props: new_props }); - delete value.members; - delete value.__extra_vt_props; - } - - return var_list; - }, - _get_cfo_res_details: function (objectId, args) { if (!(objectId in this._call_function_res_cache)) throw new Error(`Could not find any object with id ${objectId}`); @@ -714,64 +629,6 @@ var MonoSupportLib = { return { __value_as_json_string__: JSON.stringify (res_details) }; }, - /** - * Generates a new id, and a corresponding entry for associated properties - * like `dotnet:pointer:{ a: 4 }` - * The third segment of that `{a:4}` is the idArgs parameter - * - * Only `scheme` or `objectId` can be set. - * if `scheme`, then a new id is generated, and it's properties set - * if `objectId`, then it's properties are updated - * - * @param {object} args - * @param {string} [args.scheme=undefined] scheme second part of `dotnet:pointer:..` - * @param {string} [args.objectId=undefined] objectId - * @param {object} [args.idArgs={}] The third segment of the objectId - * @param {object} [args.props={}] Properties for the generated id - * - * @returns {string} generated/updated id string - */ - _new_or_add_id_props: function ({ scheme = undefined, objectId = undefined, idArgs = {}, props = {} }) { - if (scheme === undefined && objectId === undefined) - throw new Error (`Either scheme or objectId must be given`); - - if (scheme !== undefined && objectId !== undefined) - throw new Error (`Both scheme, and objectId cannot be given`); - - if (objectId !== undefined && Object.entries (idArgs).length > 0) - throw new Error (`Both objectId, and idArgs cannot be given`); - - if (Object.entries (idArgs).length == 0) { - // We want to generate a new id, only if it doesn't have other - // attributes that it can use to uniquely identify. - // Eg, we don't do this for `dotnet:valuetype:{containerId:4, fieldOffset: 24}` - idArgs.num = this._next_id (); - } - - let idStr; - if (objectId !== undefined) { - idStr = objectId; - const old_props = this._id_table [idStr]; - if (old_props === undefined) - throw new Error (`ObjectId not found in the id table: ${idStr}`); - - this._id_table [idStr] = Object.assign (old_props, props); - } else { - idStr = `dotnet:${scheme}:${JSON.stringify (idArgs)}`; - this._id_table [idStr] = props; - } - - return idStr; - }, - - /** - * @param {string} objectId - * @returns {object} - */ - _get_id_props: function (objectId) { - return this._id_table [objectId]; - }, - mono_wasm_get_details: function (objectId, args={}) { return this._get_cfo_res_details (`dotnet:cfo_res:${objectId}`, args); }, @@ -880,31 +737,12 @@ var MonoSupportLib = { this._clear_per_step_state (); }, - mono_wasm_set_pause_on_exceptions: function (state) { - if (!this.mono_wasm_pause_on_exceptions) - this.mono_wasm_pause_on_exceptions = Module.cwrap ("mono_wasm_pause_on_exceptions", 'number', [ 'number']); - var state_enum = 0; - switch (state) { - case 'uncaught': - state_enum = 1; //EXCEPTION_MODE_UNCAUGHT - break; - case 'all': - state_enum = 2; //EXCEPTION_MODE_ALL - break; - } - return this.mono_wasm_pause_on_exceptions (state_enum); - }, - mono_wasm_detach_debugger: function () { if (!this.mono_wasm_set_is_debugger_attached) this.mono_wasm_set_is_debugger_attached = Module.cwrap ('mono_wasm_set_is_debugger_attached', 'void', ['bool']); this.mono_wasm_set_is_debugger_attached(false); }, - mono_wasm_set_return_value: function (ret) { - MONO.return_value = ret; - }, - _register_c_fn: function (name, ...args) { Object.defineProperty (this._c_fn_table, name + '_wrapper', { value: Module.cwrap (name, ...args) }); }, @@ -1486,74 +1324,6 @@ var MonoSupportLib = { return new Uint8Array (byteNumbers); }, - _begin_value_type_var: function(className, args) { - if (args === undefined || (typeof args !== 'object')) { - console.debug (`_begin_value_type_var: Expected an args object`); - return; - } - - const fixed_class_name = MONO._mono_csharp_fixup_class_name(className); - const toString = args.toString; - const base64String = btoa (String.fromCharCode (...new Uint8Array (Module.HEAPU8.buffer, args.value_addr, args.value_size))); - const vt_obj = { - value: { - type : "object", - className : fixed_class_name, - description : (toString === 0 ? fixed_class_name: Module.UTF8ToString (toString)), - expanded : true, - isValueType : true, - __extra_vt_props: { klass: args.klass, value64: base64String }, - members : [] - } - }; - if (MONO._vt_stack.length == 0) - MONO._old_var_info = MONO.var_info; - - MONO.var_info = vt_obj.value.members; - MONO._vt_stack.push (vt_obj); - }, - - _end_value_type_var: function() { - let top_vt_obj_popped = MONO._vt_stack.pop (); - top_vt_obj_popped.value.members = MONO._filter_automatic_properties ( - MONO._fixup_name_value_objects (top_vt_obj_popped.value.members)); - - if (MONO._vt_stack.length == 0) { - MONO.var_info = MONO._old_var_info; - MONO.var_info.push(top_vt_obj_popped); - } else { - var top_obj = MONO._vt_stack [MONO._vt_stack.length - 1]; - top_obj.value.members.push (top_vt_obj_popped); - MONO.var_info = top_obj.value.members; - } - }, - - _add_valuetype_unexpanded_var: function(className, args) { - if (args === undefined || (typeof args !== 'object')) { - console.debug (`_add_valuetype_unexpanded_var: Expected an args object`); - return; - } - - const fixed_class_name = MONO._mono_csharp_fixup_class_name (className); - const toString = args.toString; - - MONO.var_info.push ({ - value: { - type: "object", - className: fixed_class_name, - description: (toString === 0 ? fixed_class_name : Module.UTF8ToString (toString)), - isValueType: true - } - }); - }, - - _mono_csharp_fixup_class_name: function(className) - { - // Fix up generic names like Foo`2 to Foo - // and nested class names like Foo/Bar to Foo.Bar - return className.replace(/\//g, '.').replace(/`\d+/g, ''); - }, - mono_wasm_load_data_archive: function (data, prefix) { if (data.length < 8) return false; @@ -1626,120 +1396,6 @@ var MonoSupportLib = { console.debug('mono_wasm_debug_event_raised:aef14bca-5519-4dfe-b35a-f867abc123ae', JSON.stringify(event), JSON.stringify(args)); }, }, - - mono_wasm_add_typed_value: function (type, str_value, value) { - MONO.mono_wasm_add_typed_value (type, str_value, value); - }, - - mono_wasm_add_properties_var: function(name, args) { - MONO.mono_wasm_add_properties_var (name, args); - }, - - mono_wasm_set_is_async_method: function(objectId) { - MONO._async_method_objectId = objectId; - }, - - mono_wasm_add_enum_var: function(className, members, value) { - // FIXME: flags - // - - // group0: Monday:0 - // group1: Monday - // group2: 0 - const re = new RegExp (`[,]?([^,:]+):(${value}(?=,)|${value}$)`, 'g') - const members_str = Module.UTF8ToString (members); - - const match = re.exec(members_str); - const member_name = match == null ? ('' + value) : match [1]; - - const fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); - MONO.var_info.push({ - value: { - type: "object", - className: fixed_class_name, - description: member_name, - isEnum: true - } - }); - }, - - mono_wasm_add_array_item: function(position) { - MONO.var_info.push({ - name: `${position}` - }); - }, - - mono_wasm_add_obj_var: function(className, toString, objectId) { - if (objectId == 0) { - MONO.mono_wasm_add_null_var (className); - return; - } - - const fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); - MONO.var_info.push({ - value: { - type: "object", - className: fixed_class_name, - description: (toString === 0 ? fixed_class_name : Module.UTF8ToString (toString)), - objectId: "dotnet:object:"+ objectId, - } - }); - }, - - /* - * @className, and @targetName are in the following format: - * - * :[]: - */ - mono_wasm_add_func_var: function (className, targetName, objectId) { - if (objectId == 0) { - MONO.mono_wasm_add_null_var ( - MONO._mono_csharp_fixup_class_name (Module.UTF8ToString (className))); - return; - } - - function args_to_sig (args_str) { - var parts = args_str.split (":"); - // TODO: min length = 3? - parts = parts.map (a => MONO._mono_csharp_fixup_class_name (a)); - - // method name at the end - var method_name = parts.pop (); - - // ret type at the beginning - var ret_sig = parts [0]; - var args_sig = parts.splice (1).join (', '); - return `${ret_sig} ${method_name} (${args_sig})`; - } - let tgt_sig; - if (targetName != 0) - tgt_sig = args_to_sig (Module.UTF8ToString (targetName)); - - const type_name = MONO._mono_csharp_fixup_class_name (Module.UTF8ToString (className)); - if (tgt_sig === undefined) - tgt_sig = type_name; - - if (objectId == -1 || targetName === 0) { - // Target property - MONO.var_info.push ({ - value: { - type: "symbol", - value: tgt_sig, - description: tgt_sig, - } - }); - } else { - MONO.var_info.push ({ - value: { - type: "object", - className: type_name, - description: tgt_sig, - objectId: "dotnet:object:" + objectId, - } - }); - } - }, - schedule_background_exec: function () { ++MONO.pump_count; if (typeof globalThis.setTimeout === 'function') { @@ -1763,21 +1419,6 @@ var MonoSupportLib = { } }, - mono_wasm_fire_bp: function () { - // eslint-disable-next-line no-debugger - debugger; - }, - - mono_wasm_fire_exception: function (exception_id, message, class_name, uncaught) { - MONO.active_exception = { - exception_id: exception_id, - message : Module.UTF8ToString (message), - class_name : Module.UTF8ToString (class_name), - uncaught : uncaught - }; - debugger; - }, - mono_wasm_fire_debugger_agent_message: function () { // eslint-disable-next-line no-debugger debugger; From 150aeacc12e466cfc2c663e04312b9ba7df4ecf9 Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 31 May 2021 14:53:08 -0300 Subject: [PATCH 32/48] 0 ERRORS! --- .../BrowserDebugProxy/MonoSDBHelper.cs | 6 +-- .../wasm/debugger/DebuggerTestSuite/Tests.cs | 39 +------------------ src/mono/wasm/runtime/library_mono.js | 2 +- 3 files changed, 5 insertions(+), 42 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index c532c2b4278fb..d2e89c18e72e0 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -754,7 +754,7 @@ public async Task Step(SessionId sessionId, int thread_id, StepKind kind, command_params_writer.Write(thread_id); command_params_writer.Write((int)0); command_params_writer.Write((int)kind); - command_params_writer.Write((int)(StepFilter.StaticCtor & StepFilter.DebuggerHidden)); //filter + command_params_writer.Write((int)(StepFilter.StaticCtor | StepFilter.DebuggerHidden)); //filter var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); if (ret_debugger_cmd_reader != null) return true; @@ -931,7 +931,7 @@ public async Task GetDelegateMethodDescription(SessionId sessionId, int var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(methodId); - Console.WriteLine("methodId - " + methodId); + //Console.WriteLine("methodId - " + methodId); if (methodId == 0) return ""; var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME, command_params, token); @@ -1777,7 +1777,7 @@ public async Task GetObjectProxy(SessionId sessionId, int objectId, Canc var getMethodId = ret_debugger_cmd_reader.ReadInt32(); var setMethodId = ret_debugger_cmd_reader.ReadInt32(); //setmethod var attrValue = ret_debugger_cmd_reader.ReadInt32(); //attrs - Console.WriteLine($"{propertyNameStr} - {attrValue}"); + //Console.WriteLine($"{propertyNameStr} - {attrValue}"); if (ret.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any()) { var attr = ret.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).First(); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs index a671ed2b7c181..468ca4d628d37 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs @@ -641,43 +641,6 @@ await CompareObjectPropertiesFor(frame_locals, "this", }); - [Fact] - public async Task InvalidValueTypeData() - { - await CheckInspectLocalsAtBreakpointSite( - "dotnet://debugger-test.dll/debugger-test.cs", 85, 8, - "OuterMethod", - "window.setTimeout(function() { invoke_static_method ('[debugger-test] Math:OuterMethod'); })", - wait_for_event_fn: async (pause_location) => - { - var new_id = await CreateNewId(@"MONO._new_or_add_id_props ({ scheme: 'valuetype', idArgs: { containerId: 1 }, props: { klass: 3, value64: 4 }});"); - await _invoke_getter(new_id, "NonExistant", expect_ok: false); - - new_id = await CreateNewId(@"MONO._new_or_add_id_props ({ scheme: 'valuetype', idArgs: { containerId: 1 }, props: { klass: 3 }});"); - await _invoke_getter(new_id, "NonExistant", expect_ok: false); - - new_id = await CreateNewId(@"MONO._new_or_add_id_props ({ scheme: 'valuetype', idArgs: { containerId: 1 }, props: { klass: 3, value64: 'AA' }});"); - await _invoke_getter(new_id, "NonExistant", expect_ok: false); - }); - - async Task CreateNewId(string expr) - { - var res = await cli.SendCommand("Runtime.evaluate", JObject.FromObject(new { expression = expr }), token); - Assert.True(res.IsOk, "Expected Runtime.evaluate to succeed"); - AssertEqual("string", res.Value["result"]?["type"]?.Value(), "Expected Runtime.evaluate to return a string type result"); - return res.Value["result"]?["value"]?.Value(); - } - - async Task _invoke_getter(string obj_id, string property_name, bool expect_ok) - { - var expr = $"MONO._invoke_getter ('{obj_id}', '{property_name}')"; - var res = await cli.SendCommand("Runtime.evaluate", JObject.FromObject(new { expression = expr }), token); - AssertEqual(expect_ok, res.IsOk, "Runtime.evaluate result not as expected for {expr}"); - - return res; - } - } - [Fact] public async Task MulticastDelegateTest() => await CheckInspectLocalsAtBreakpointSite( "MulticastDelegateTestClass", "Test", 5, "Test", @@ -746,7 +709,7 @@ public async Task PreviousFrameForAReflectedCall() => await CheckInspectLocalsAt await CheckProps(frame_locals, new { - mi = TObject("System.Reflection.MethodInfo"), + mi = TObject("System.Reflection.RuntimeMethodInfo"), //this is what is returned when debugging desktop apps using VS dt = TDateTime(new DateTime(4210, 3, 4, 5, 6, 7)), i = TNumber(4), strings = TArray("string[]", 1), diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 6fae132ef91f6..0fa1232118a2c 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -704,7 +704,7 @@ var MonoSupportLib = { return { type: typeof(fn_res), description: `${fn_res}`, value: `${fn_res}`}; } - if (request.returnByValue) + if (request.returnByValue && fn_res.subtype == undefined) return {type: "object", value: fn_res}; if (Object.getPrototypeOf (fn_res) == Array.prototype) { From 9155bbaa4cadf7c71fba44f128388de5ceb57724 Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 31 May 2021 23:46:53 -0300 Subject: [PATCH 33/48] Removing more code. No errors. --- src/mono/mono/mini/debugger-agent.c | 8 +- src/mono/mono/mini/mini-wasm-debugger.c | 108 ++---------------------- 2 files changed, 15 insertions(+), 101 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 465ca3cd63740..ffbc2088f778b 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -3055,7 +3055,7 @@ compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls, gboolean f tls->frames = new_frames; tls->frame_count = new_frame_count; tls->frames_up_to_date = TRUE; - +#ifndef TARGET_WASM if (CHECK_PROTOCOL_VERSION (2, 52)) { MonoJitTlsData *jit_data = thread->thread_info->jit_data; gboolean has_interp_resume_state = FALSE; @@ -3070,6 +3070,7 @@ compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls, gboolean f } } } +#endif } /* @@ -4065,7 +4066,10 @@ mono_ss_calculate_framecount (void *the_tls, MonoContext *ctx, gboolean force_us if (force_use_ctx || !tls->context.valid) mono_thread_state_init_from_monoctx (&tls->context, ctx); compute_frame_info (tls->thread, tls, FALSE); -#endif +#else + compute_frame_info (tls->thread, tls, TRUE); +#endif + if (frames) *frames = (DbgEngineStackFrame**)tls->frames; if (nframes) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index b51afbe296f35..cc2e9c9c165ad 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -88,78 +88,6 @@ appdomain_load (MonoProfiler *prof, MonoDomain *domain) mono_de_domain_add (domain); } -/* Frame state handling */ -static GPtrArray *frames; - -static void -free_frame (DbgEngineStackFrame *frame) -{ - g_free (frame); -} - -static gboolean -collect_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) -{ - SeqPoint sp; - MonoMethod *method; - - //skip wrappers - if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) - return FALSE; - - if (info->ji) - method = jinfo_get_method (info->ji); - else - method = info->method; - - if (!method) - return FALSE; - - PRINT_DEBUG_MSG (2, "collect_frames: Reporting method %s native_offset %d, wrapper_type: %d\n", method->name, info->native_offset, method->wrapper_type); - - if (!mono_find_prev_seq_point_for_native_offset (method, info->native_offset, NULL, &sp)) - PRINT_DEBUG_MSG (2, "collect_frames: Failed to lookup sequence point. method: %s, native_offset: %d \n", method->name, info->native_offset); - - - StackFrame *frame = g_new0 (StackFrame, 1); - frame->de.ji = info->ji; - frame->de.domain = mono_get_root_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; -} - -static void -free_frame_state (void) -{ - if (frames) { - int i; - for (i = 0; i < frames->len; ++i) - free_frame ((DbgEngineStackFrame*)g_ptr_array_index (frames, i)); - g_ptr_array_set_size (frames, 0); - } -} - -static void -compute_frames (void) { - if (frames) { - int i; - for (i = 0; i < frames->len; ++i) - free_frame ((DbgEngineStackFrame*)g_ptr_array_index (frames, i)); - g_ptr_array_set_size (frames, 0); - } else { - frames = g_ptr_array_new (); - } - - mono_walk_stack_with_ctx (collect_frames, NULL, MONO_UNWIND_NONE, NULL); -} static MonoContext* tls_get_restore_state (void *tls) { @@ -186,17 +114,14 @@ begin_single_step_processing (MonoContext *ctx, gboolean from_signal) static void ss_discard_frame_context (void *the_tls) { - free_frame_state (); + mono_ss_discard_frame_context (mono_wasm_get_tls()); } static void ss_calculate_framecount (void *tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***out_frames, int *nframes) { - compute_frames (); - if (out_frames) - *out_frames = (DbgEngineStackFrame **)frames->pdata; - if (nframes) - *nframes = frames->len; + mono_wasm_save_thread_context(); + mono_ss_calculate_framecount(mono_wasm_get_tls(), NULL, force_use_ctx, out_frames, nframes); } static gboolean @@ -259,8 +184,8 @@ mono_wasm_debugger_init (void) mono_profiler_set_domain_loaded_callback (prof, appdomain_load); mono_profiler_set_assembly_loaded_callback (prof, assembly_loaded); - mini_get_dbg_callbacks ()->handle_exception = handle_exception; - mini_get_dbg_callbacks ()->user_break = mono_wasm_user_break; + mini_get_dbg_callbacks ()->handle_exception = mono_debugger_agent_handle_exception; + mini_get_dbg_callbacks ()->user_break = mono_dbg_debugger_agent_user_break; //debugger-agent initialization DebuggerTransport trans; @@ -308,33 +233,17 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) } } -static void -handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame) -{ - mono_wasm_save_thread_context(); - mono_debugger_agent_handle_exception (exc, throw_ctx, catch_ctx, catch_frame); -} - void mono_wasm_single_step_hit (void) { - mono_wasm_save_thread_context(); - mono_de_process_single_step (NULL, FALSE); + mono_de_process_single_step (mono_wasm_get_tls(), FALSE); } void mono_wasm_breakpoint_hit (void) { - mono_wasm_save_thread_context(); - mono_de_process_breakpoint (NULL, FALSE); -} - -void -mono_wasm_user_break (void) -{ - mono_wasm_save_thread_context(); - mono_dbg_debugger_agent_user_break (); + mono_de_process_breakpoint (mono_wasm_get_tls(), FALSE); } static gboolean @@ -479,7 +388,7 @@ mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, i }, 0, id, 0, 0); return TRUE; } - gboolean ret = mono_wasm_send_dbg_command(id, command_set, command, bufWithParms.buf, m_dbgprot_buffer_len(&bufWithParms)); + mono_wasm_send_dbg_command(id, command_set, command, bufWithParms.buf, m_dbgprot_buffer_len(&bufWithParms)); buffer_free (&bufWithParms); return TRUE; } @@ -515,6 +424,7 @@ receive_debugger_agent_message (void *data, int len) EM_ASM ({ MONO.mono_wasm_add_dbg_command_received (1, -1, $0, $1); }, data, len); + mono_wasm_save_thread_context(); mono_wasm_fire_debugger_agent_message (); return FALSE; } From 650b40511c09b0952d550ec8a57b22b559c2ae9a Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 1 Jun 2021 14:49:15 -0300 Subject: [PATCH 34/48] Fixing added tests. --- src/mono/mono/mini/mini-wasm-debugger.c | 1 + .../wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 9 ++++++++- .../wasm/debugger/DebuggerTestSuite/AssignmentTests.cs | 2 +- src/mono/wasm/runtime/library_mono.js | 5 ----- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 17fe5d519d15a..fd19c6a846277 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -396,6 +396,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) { + ss_calculate_framecount (NULL, NULL, TRUE, NULL, NULL); MdbgProtBuffer buf; buffer_init (&buf, 128); gboolean no_reply; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index d2e89c18e72e0..b9d36359bade8 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -809,6 +809,7 @@ public string ReplaceCommonClassNames(string className) className = className.Replace("System.Int32", "int"); className = className.Replace("System.Object", "object"); className = className.Replace("System.Void", "void"); + className = className.Replace("System.Byte", "byte"); return className; } public async Task GetTypeName(SessionId sessionId, int type_id, CancellationToken token) @@ -1241,13 +1242,19 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo // FIXME: The client and the debuggee might have different word sizes ret = new JObject{{"Type", "void"}}; break; + case ElementType.FnPtr: case ElementType.Ptr: { string type; string value; long valueAddress = ret_debugger_cmd_reader.ReadLong(); var typeId = ret_debugger_cmd_reader.ReadInt32(); - var className = "(" + await GetTypeName(sessionId, typeId, token) + ")"; + var className = ""; + if (etype == ElementType.FnPtr) + className = "(*())"; //to keep the old behavior + else + className = "(" + await GetTypeName(sessionId, typeId, token) + ")"; + int pointerId = 0; if (valueAddress != 0 && className != "(void*)") { diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs index 00f917c8dc573..1afa97939d5ef 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs @@ -33,7 +33,7 @@ public class AssignmentTests : DebuggerTestBase { "MONO_TYPE_U2", TNumber(0), TNumber(1) }, { "MONO_TYPE_U4", TNumber(0), TNumber(1) }, { "MONO_TYPE_U8", TNumber(0), TNumber(1) }, - { "MONO_TYPE_R4", TNumber(0), TNumber("3.1414999961853027") }, + { "MONO_TYPE_R4", TNumber(0), TNumber("3.1415") }, //this is also the value that we see if we debug using VS { "MONO_TYPE_R8", TNumber(0), TNumber("3.1415") }, }; diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js index 0fa1232118a2c..4a69ac3ba4f49 100644 --- a/src/mono/wasm/runtime/library_mono.js +++ b/src/mono/wasm/runtime/library_mono.js @@ -788,11 +788,6 @@ var MonoSupportLib = { this._call_function_res_cache = {}; this._c_fn_table = {}; - this._register_c_var_fn ('mono_wasm_get_object_properties', 'bool', [ 'number', 'number' ]); - this._register_c_var_fn ('mono_wasm_get_array_values', 'bool', [ 'number', 'number', 'number', 'number' ]); - this._register_c_var_fn ('mono_wasm_invoke_getter_on_object', 'bool', [ 'number', 'string' ]); - this._register_c_var_fn ('mono_wasm_invoke_getter_on_value', 'bool', [ 'number', 'number', 'string' ]); - this._register_c_var_fn ('mono_wasm_get_local_vars', 'bool', [ 'number', 'number', 'number']); this._register_c_fn ('mono_wasm_send_dbg_command', 'bool', [ 'number', 'number', 'number', 'number', 'number' ]); this._register_c_fn ('mono_wasm_send_dbg_command_with_parms', 'bool', [ 'number', 'number', 'number', 'number', 'number', 'number', 'string' ]); From 62de11b4bb8b4464482f5220afef60a5b3d57aac Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 1 Jun 2021 21:04:42 -0300 Subject: [PATCH 35/48] Return javascript callstack after managed callstack. Step out from managed code return to native wasm or javascript. Adding debug info to Wasm.Browser.Sample to help testing debugger with sample. --- src/mono/mono/mini/debugger-agent.c | 16 ++++++++++ .../wasm/browser/Wasm.Browser.Sample.csproj | 4 +++ .../debugger/BrowserDebugProxy/MonoProxy.cs | 32 +++++++++++++------ .../BrowserDebugProxy/MonoSDBHelper.cs | 9 ++++-- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index adb55646689df..7fabd62911b88 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -7175,6 +7175,22 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf) g_free (req); return err; } +#ifdef TARGET_WASM + int isBPOnManagedCode = 0; + SingleStepReq *ss_req = req->info; + if (ss_req && ss_req->bps) { + GSList *l; + + for (l = ss_req->bps; l; l = l->next) { + if (((MonoBreakpoint *)l->data)->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) + isBPOnManagedCode = 1; + } + } + if (!isBPOnManagedCode) { + mono_de_cancel_all_ss (); + } + buffer_add_byte (buf, isBPOnManagedCode); +#endif } else if (req->event_kind == EVENT_KIND_METHOD_ENTRY) { req->info = mono_de_set_breakpoint (NULL, METHOD_ENTRY_IL_OFFSET, req, NULL); } else if (req->event_kind == EVENT_KIND_METHOD_EXIT) { diff --git a/src/mono/sample/wasm/browser/Wasm.Browser.Sample.csproj b/src/mono/sample/wasm/browser/Wasm.Browser.Sample.csproj index 2b05836627673..15386dece90a9 100644 --- a/src/mono/sample/wasm/browser/Wasm.Browser.Sample.csproj +++ b/src/mono/sample/wasm/browser/Wasm.Browser.Sample.csproj @@ -1,7 +1,11 @@ + Debug true runtime.js + true + embedded + 1 diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 23aadaa16612f..8878c95390449 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -134,15 +134,15 @@ protected override async Task AcceptEvent(SessionId sessionId, string meth await SendCommand(sessionId, "Debugger.resume", new JObject(), token); return true; } - case "mono_wasm_fire_bp": - case "_mono_wasm_fire_bp": - case "_mono_wasm_fire_exception": - { - return false;//await OnPause(sessionId, args, token); - } case "_mono_wasm_fire_debugger_agent_message": { - return await OnReceiveDebuggerAgentEvent(sessionId, args, token); + try { + return await OnReceiveDebuggerAgentEvent(sessionId, args, token); + } + catch (Exception) //if the page is refreshed maybe it stops here. + { + return false; + } } } break; @@ -652,7 +652,7 @@ private async Task EvaluateCondition(SessionId sessionId, ExecutionContext } return false; } - private async Task SendCallStack(SessionId sessionId, ExecutionContext context, string reason, int thread_id, Breakpoint bp, JObject data, CancellationToken token) + private async Task SendCallStack(SessionId sessionId, ExecutionContext context, string reason, int thread_id, Breakpoint bp, JObject data, IEnumerable orig_callframes, CancellationToken token) { var callFrames = new List(); var frames = new List(); @@ -759,6 +759,17 @@ private async Task SendCallStack(SessionId sessionId, ExecutionContext con string[] bp_list = new string[bp == null ? 0 : 1]; if (bp != null) bp_list[0] = bp.StackId; + + foreach (JObject frame in orig_callframes) + { + string function_name = frame["functionName"]?.Value(); + string url = frame["url"]?.Value(); + if (!(function_name.StartsWith("wasm-function", StringComparison.Ordinal) || + url.StartsWith("wasm://wasm/", StringComparison.Ordinal) || function_name == "_mono_wasm_fire_debugger_agent_message")) + { + callFrames.Add(frame); + } + } var o = JObject.FromObject(new { callFrames, @@ -772,6 +783,7 @@ private async Task SendCallStack(SessionId sessionId, ExecutionContext con return true; } SendEvent(sessionId, "Debugger.paused", o, token); + return true; } private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObject args, CancellationToken token) @@ -815,7 +827,7 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec objectId = $"dotnet:object:{object_id}" }); - var ret = await SendCallStack(sessionId, context, reason, thread_id, null, data, token); + var ret = await SendCallStack(sessionId, context, reason, thread_id, null, data, args?["callFrames"]?.Values(), token); return ret; } case EventKind.USER_BREAK: @@ -827,7 +839,7 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec int method_id = 0; if (event_kind != EventKind.USER_BREAK) method_id = ret_debugger_cmd_reader.ReadInt32(); - var ret = await SendCallStack(sessionId, context, reason, thread_id, bp, null, token); + var ret = await SendCallStack(sessionId, context, reason, thread_id, bp, null, args?["callFrames"]?.Values(), token); return ret; } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index b9d36359bade8..2b719d872f733 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -756,9 +756,12 @@ public async Task Step(SessionId sessionId, int thread_id, StepKind kind, command_params_writer.Write((int)kind); command_params_writer.Write((int)(StepFilter.StaticCtor | StepFilter.DebuggerHidden)); //filter var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); - if (ret_debugger_cmd_reader != null) - return true; - return false; + if (ret_debugger_cmd_reader == null) + return false; + var isBPOnManagedCode = ret_debugger_cmd_reader.ReadInt32(); + if (isBPOnManagedCode == 0) + return false; + return true; } public async Task ClearSingleStep(SessionId sessionId, int req_id, CancellationToken token) From da783b6b32ee6641aa0776c393e021013cb2f302 Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 2 Jun 2021 14:48:19 -0300 Subject: [PATCH 36/48] Change what Ankit suggested. Clear cache with valuetypes and pointers after resume or step. --- src/mono/mono/mini/debugger-agent.c | 8 ++------ src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs | 2 ++ src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 6 ++++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 7fabd62911b88..48617abb25584 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -370,11 +370,13 @@ static gboolean buffer_replies; #ifndef TARGET_WASM #define GET_TLS_DATA(thread) \ + DebuggerTlsData *tls; \ mono_loader_lock(); \ tls = (DebuggerTlsData*)mono_g_hash_table_lookup(thread_to_tls, thread); \ mono_loader_unlock(); #else #define GET_TLS_DATA(thread) \ + DebuggerTlsData *tls; \ tls = &debugger_wasm_thread; #endif @@ -4513,7 +4515,6 @@ mono_ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) StackFrame **frames = NULL; int nframes = 0; - DebuggerTlsData *tls; GET_TLS_DATA(ss_req->thread); g_assert (tls); @@ -4771,7 +4772,6 @@ mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx GSList *events; MonoJitInfo *ji, *catch_ji; EventInfo ei; - DebuggerTlsData *tls = NULL; MonoInternalThread *thread = mono_thread_internal_current (); GET_TLS_DATA(thread); if (tls != NULL) { @@ -7159,7 +7159,6 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf) return err; } - DebuggerTlsData* tls; GET_TLS_DATA(THREAD_TO_INTERNAL(step_thread)); g_assert (tls); @@ -8879,7 +8878,6 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) break; } case MDBGPROT_CMD_THREAD_GET_CONTEXT: { - DebuggerTlsData *tls; int start_frame; while (!is_suspended ()) { if (suspend_count) @@ -8900,7 +8898,6 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) break; } case CMD_THREAD_GET_FRAME_INFO: { - DebuggerTlsData *tls; int i, start_frame, length; // Wait for suspending if it already started @@ -9093,7 +9090,6 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) MonoThread *thread_obj; MonoInternalThread *thread; int pos, i, len, frame_idx; - DebuggerTlsData *tls; StackFrame *frame; MonoDebugMethodJitInfo *jit; MonoMethodSignature *sig; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 8878c95390449..1847c9cdb5c17 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -922,6 +922,7 @@ private async Task OnResume(MessageId msg_id, CancellationToken token) } //discard managed frames + sdbHelper.ClearCache(); GetContext(msg_id).ClearState(); } @@ -936,6 +937,7 @@ private async Task Step(MessageId msg_id, StepKind kind, CancellationToken var step = await sdbHelper.Step(msg_id, context.ThreadId, kind, token); if (step == false) { + sdbHelper.ClearCache(); context.ClearState(); await SendCommand(msg_id, "Debugger.stepOut", new JObject(), token); return false; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 2b719d872f733..85f33d97c6dec 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -536,6 +536,12 @@ public MonoSDBHelper(MonoProxy proxy) this.proxy = proxy; } + public void ClearCache() + { + valueTypes = new Dictionary(); + pointerValues = new Dictionary(); + } + public async Task SetProtocolVersion(SessionId sessionId, CancellationToken token) { var command_params = new MemoryStream(); From 8d0005fc1214266263a0e3f0d15839f780742078 Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 2 Jun 2021 15:20:21 -0300 Subject: [PATCH 37/48] Fixing suggestions. --- src/mono/mono/mini/debugger-agent.c | 46 +++++++++++-------- .../BrowserDebugProxy/MonoSDBHelper.cs | 5 +- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 48617abb25584..0ef4e4eb99fa0 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -1566,23 +1566,24 @@ static GHashTable *obj_to_objref; /* Protected by the dbg lock */ static MonoGHashTable *suspended_objs; - +#ifdef TARGET_WASM void mono_init_debugger_agent_for_wasm (int log_level_parm) { + if (mono_atomic_cas_i32 (&agent_inited, 1, 0) == 1) + return; + ids_init(); objrefs = g_hash_table_new_full (NULL, NULL, NULL, mono_debugger_free_objref); obj_to_objref = g_hash_table_new (NULL, NULL); log_level = log_level; event_requests = g_ptr_array_new (); - if (mono_atomic_cas_i32 (&agent_inited, 1, 0) == 1) - return; vm_start_event_sent = TRUE; transport = &transports [0]; memset(&debugger_wasm_thread, 0, sizeof(DebuggerTlsData)); agent_config.enabled = TRUE; } - +#endif static void @@ -6983,16 +6984,21 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) //resolve the assembly MonoImageOpenStatus status; MonoAssemblyName* aname = mono_assembly_name_new (lookup_name); + if (!aname) { + PRINT_DEBUG_MSG (1, "Could not resolve assembly %s\n", assembly_name); + buffer_add_int(buf, -1); + break; + } MonoAssemblyByNameRequest byname_req; mono_assembly_request_prepare_byname (&byname_req, MONO_ASMCTX_DEFAULT, mono_alc_get_default ()); MonoAssembly *assembly = mono_assembly_request_byname (aname, &byname_req, &status); g_free (lookup_name); + mono_assembly_name_free_internal (aname); if (!assembly) { PRINT_DEBUG_MSG (1, "Could not resolve assembly %s\n", assembly_name); buffer_add_int(buf, -1); break; } - mono_assembly_name_free_internal (aname); buffer_add_assemblyid (buf, mono_get_root_domain (), assembly); break; } @@ -10009,55 +10015,55 @@ wait_for_attach (void) } ErrorCode -mono_process_dbg_packet (int id, CommandSet command_set, int command, gboolean *no_reply, guint8 *p, guint8 *end, Buffer *buf) +mono_process_dbg_packet (int id, CommandSet command_set, int command, gboolean *no_reply, guint8 *buf, guint8 *end, Buffer *ret_buf) { ErrorCode err; /* Process the request */ switch (command_set) { case CMD_SET_VM: - err = vm_commands (command, id, p, end, buf); + err = vm_commands (command, id, buf, end, ret_buf); if (err == ERR_NONE && command == CMD_VM_INVOKE_METHOD) /* Sent after the invoke is complete */ *no_reply = TRUE; break; case CMD_SET_EVENT_REQUEST: - err = event_commands (command, p, end, buf); + err = event_commands (command, buf, end, ret_buf); break; case CMD_SET_APPDOMAIN: - err = domain_commands (command, p, end, buf); + err = domain_commands (command, buf, end, ret_buf); break; case CMD_SET_ASSEMBLY: - err = assembly_commands (command, p, end, buf); + err = assembly_commands (command, buf, end, ret_buf); break; case CMD_SET_MODULE: - err = module_commands (command, p, end, buf); + err = module_commands (command, buf, end, ret_buf); break; case CMD_SET_FIELD: - err = field_commands (command, p, end, buf); + err = field_commands (command, buf, end, ret_buf); break; case CMD_SET_TYPE: - err = type_commands (command, p, end, buf); + err = type_commands (command, buf, end, ret_buf); break; case CMD_SET_METHOD: - err = method_commands (command, p, end, buf); + err = method_commands (command, buf, end, ret_buf); break; case CMD_SET_THREAD: - err = thread_commands (command, p, end, buf); + err = thread_commands (command, buf, end, ret_buf); break; case CMD_SET_STACK_FRAME: - err = frame_commands (command, p, end, buf); + err = frame_commands (command, buf, end, ret_buf); break; case CMD_SET_ARRAY_REF: - err = array_commands (command, p, end, buf); + err = array_commands (command, buf, end, ret_buf); break; case CMD_SET_STRING_REF: - err = string_commands (command, p, end, buf); + err = string_commands (command, buf, end, ret_buf); break; case CMD_SET_POINTER: - err = pointer_commands (command, p, end, buf); + err = pointer_commands (command, buf, end, ret_buf); break; case CMD_SET_OBJECT_REF: - err = object_commands (command, p, end, buf); + err = object_commands (command, buf, end, ret_buf); break; default: err = ERR_NOT_IMPLEMENTED; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 85f33d97c6dec..b3696b6ecbc94 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1728,7 +1728,10 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, boo } if (!withProperties) return ret; - var props = await CreateJArrayForProperties(sessionId, typeId[i], Array.Empty(), ret, false, $"dotnet:object:{objectId}", i == 0, token); + var command_params_obj = new MemoryStream(); + var command_params_obj_writer = new MonoBinaryWriter(command_params_obj); + command_params_obj_writer.WriteObj(new DotnetObjectId("object", $"{objectId}"), this); + var props = await CreateJArrayForProperties(sessionId, typeId[i], command_params_obj.ToArray(), ret, false, $"dotnet:object:{objectId}", i == 0, token); ret = new JArray(ret.Union(props)); // ownProperties From 67723dc7ac02d11e98203d8a9bd6ff8c97f4f7cb Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 2 Jun 2021 16:31:52 -0300 Subject: [PATCH 38/48] Fix error on wasm build. --- src/mono/mono/mini/debugger-agent.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 0ef4e4eb99fa0..d5e4754a18169 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -4516,7 +4516,7 @@ mono_ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) StackFrame **frames = NULL; int nframes = 0; - GET_TLS_DATA(ss_req->thread); + GET_TLS_DATA (ss_req->thread); g_assert (tls); if (!tls->context.valid) { @@ -4773,8 +4773,7 @@ mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx GSList *events; MonoJitInfo *ji, *catch_ji; EventInfo ei; - MonoInternalThread *thread = mono_thread_internal_current (); - GET_TLS_DATA(thread); + GET_TLS_DATA (mono_thread_internal_current ()); if (tls != NULL) { if (tls->abort_requested) return; @@ -7165,7 +7164,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf) return err; } - GET_TLS_DATA(THREAD_TO_INTERNAL(step_thread)); + GET_TLS_DATA (THREAD_TO_INTERNAL(step_thread)); g_assert (tls); @@ -8891,7 +8890,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) } start_frame = decode_int (p, &p, end); - GET_TLS_DATA(thread); + GET_TLS_DATA (thread); if (tls == NULL) return ERR_UNLOADED; @@ -8924,7 +8923,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (start_frame != 0 || length != -1) return ERR_NOT_IMPLEMENTED; - GET_TLS_DATA(thread); + GET_TLS_DATA (thread); if (tls == NULL) return ERR_UNLOADED; @@ -9112,7 +9111,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) id = decode_id (p, &p, end); - GET_TLS_DATA(thread); + GET_TLS_DATA (thread); g_assert (tls); for (i = 0; i < tls->frame_count; ++i) { From 00a459e0f96995ccdb813c7091acf59ec920e4bc Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Fri, 11 Jun 2021 16:43:38 -0300 Subject: [PATCH 39/48] Apply suggestions from code review Co-authored-by: Larry Ewing --- src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index b3696b6ecbc94..60ca57522cc01 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1506,6 +1506,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo ret["isOwn"] = true; return ret; } + public async Task IsAsyncMethod(SessionId sessionId, int methodId, CancellationToken token) { var command_params = new MemoryStream(); @@ -1563,6 +1564,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me return locals; } + public async Task GetValueTypeValues(SessionId sessionId, int valueTypeId, bool accessorPropertiesOnly, CancellationToken token) { if (valueTypes[valueTypeId].valueTypeJsonProps == null) From d3abbf25d8642f98298ae2a68c87f19910a7df43 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 11 Jun 2021 17:01:43 -0300 Subject: [PATCH 40/48] Changing what was suggested by @lewing. --- src/mono/mono/mini/debugger-agent.c | 42 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 147 ++--- .../BrowserDebugProxy/MonoSDBHelper.cs | 583 ++++++++++-------- 3 files changed, 397 insertions(+), 375 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index d5e4754a18169..9380b1041b40b 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -369,17 +369,24 @@ static gboolean buffer_replies; #ifndef TARGET_WASM -#define GET_TLS_DATA(thread) \ +#define GET_TLS_DATA_FROM_THREAD(thread) \ DebuggerTlsData *tls; \ mono_loader_lock(); \ tls = (DebuggerTlsData*)mono_g_hash_table_lookup(thread_to_tls, thread); \ mono_loader_unlock(); +#define GET_DEBUGGER_TLS() \ + DebuggerTlsData *tls; \ + tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); #else -#define GET_TLS_DATA(thread) \ +#define GET_TLS_DATA_FROM_THREAD(thread) \ + DebuggerTlsData *tls; \ + tls = &debugger_wasm_thread; +#define GET_DEBUGGER_TLS() \ DebuggerTlsData *tls; \ tls = &debugger_wasm_thread; #endif +//mono_native_tls_get_value (debugger_tls_id); #define dbg_lock mono_de_lock #define dbg_unlock mono_de_unlock @@ -3440,15 +3447,7 @@ create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo return events; } -static void mono_stop_timer_watch (int debugger_tls_id) -{ -#ifndef TARGET_WASM - DebuggerTlsData *tls; - tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); - g_assert (tls); - mono_stopwatch_stop (&tls->step_time); -#endif -} + /* * process_event: * @@ -3570,7 +3569,9 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx break; case EVENT_KIND_BREAKPOINT: case EVENT_KIND_STEP: { - mono_stop_timer_watch (debugger_tls_id); + GET_DEBUGGER_TLS(); + g_assert (tls); + mono_stopwatch_stop (&tls->step_time); MonoMethod *method = (MonoMethod *)arg; buffer_add_methodid (&buf, domain, method); buffer_add_long (&buf, il_offset); @@ -3603,15 +3604,12 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx break; } case EVENT_KIND_USER_BREAK: { -#ifndef TARGET_WASM - DebuggerTlsData *tls; - tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); + GET_DEBUGGER_TLS(); g_assert (tls); // We are already processing a breakpoint event if (tls->disable_breakpoints) return; mono_stopwatch_stop (&tls->step_time); -#endif break; } case EVENT_KIND_USER_LOG: { @@ -4516,7 +4514,7 @@ mono_ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) StackFrame **frames = NULL; int nframes = 0; - GET_TLS_DATA (ss_req->thread); + GET_TLS_DATA_FROM_THREAD (ss_req->thread); g_assert (tls); if (!tls->context.valid) { @@ -4773,7 +4771,7 @@ mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx GSList *events; MonoJitInfo *ji, *catch_ji; EventInfo ei; - GET_TLS_DATA (mono_thread_internal_current ()); + GET_TLS_DATA_FROM_THREAD (mono_thread_internal_current ()); if (tls != NULL) { if (tls->abort_requested) return; @@ -7164,7 +7162,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf) return err; } - GET_TLS_DATA (THREAD_TO_INTERNAL(step_thread)); + GET_TLS_DATA_FROM_THREAD (THREAD_TO_INTERNAL(step_thread)); g_assert (tls); @@ -8890,7 +8888,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) } start_frame = decode_int (p, &p, end); - GET_TLS_DATA (thread); + GET_TLS_DATA_FROM_THREAD (thread); if (tls == NULL) return ERR_UNLOADED; @@ -8923,7 +8921,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (start_frame != 0 || length != -1) return ERR_NOT_IMPLEMENTED; - GET_TLS_DATA (thread); + GET_TLS_DATA_FROM_THREAD (thread); if (tls == NULL) return ERR_UNLOADED; @@ -9111,7 +9109,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) id = decode_id (p, &p, end); - GET_TLS_DATA (thread); + GET_TLS_DATA_FROM_THREAD (thread); g_assert (tls); for (i = 0; i < tls->frame_count; ++i) { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 1847c9cdb5c17..267fe724175df 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -484,55 +484,61 @@ private async Task CallOnFunction(MessageId id, JObject args, Cancellation if (!DotnetObjectId.TryParse(args["objectId"], out DotnetObjectId objectId)) { return false; } - if (objectId.Scheme == "scope") + switch (objectId.Scheme) { - SendResponse(id, - Result.Exception(new ArgumentException( - $"Runtime.callFunctionOn not supported with scope ({objectId}).")), - token); - return true; - } - if (objectId.Scheme == "object" || objectId.Scheme == "valuetype" || objectId.Scheme == "pointer" || objectId.Scheme == "array") - { - if (objectId.Scheme == "object") + case "object": args["details"] = await sdbHelper.GetObjectProxy(id, int.Parse(objectId.Value), token); - if (objectId.Scheme == "valuetype") + break; + case "valuetype": args["details"] = await sdbHelper.GetValueTypeProxy(id, int.Parse(objectId.Value), token); - if (objectId.Scheme == "pointer") + break; + case "pointer": args["details"] = await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token); - if (objectId.Scheme == "array") + break; + case "array": args["details"] = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - if (res.IsErr) + break; + case "cfo_res": { - SendResponse(id, res, token); + Result cfo_res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + cfo_res = Result.OkFromObject(new { result = cfo_res.Value?["result"]?["value"]}); + SendResponse(id, cfo_res, token); return true; } - if (res.Value?["result"]?["value"]?["type"] == null) //it means that is not a buffer returned from the debugger-agent + case "scope": { - byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); - var ret_debugger_cmd = new MemoryStream(newBytes); - var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); - ret_debugger_cmd_reader.ReadByte(); //number of objects returned. - var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, -1, token); - /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ - res = Result.OkFromObject(new { result = obj["value"]}); - SendResponse(id, res, token); + SendResponse(id, + Result.Exception(new ArgumentException( + $"Runtime.callFunctionOn not supported with scope ({objectId}).")), + token); return true; } - res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + default: + return false; + } + Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); + if (res.IsErr) + { SendResponse(id, res, token); return true; } - if (objectId.Scheme == "cfo_res") + if (res.Value?["result"]?["value"]?["type"] == null) //it means that is not a buffer returned from the debugger-agent { - Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); - res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); + var ret_debugger_cmd = new MemoryStream(newBytes); + var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); + ret_debugger_cmd_reader.ReadByte(); //number of objects returned. + var obj = await sdbHelper.CreateJObjectForVariableValue(id, ret_debugger_cmd_reader, "ret", false, -1, token); + /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/ + res = Result.OkFromObject(new { result = obj["value"]}); SendResponse(id, res, token); return true; } - return false; + res = Result.OkFromObject(new { result = res.Value?["result"]?["value"]}); + SendResponse(id, res, token); + return true; } + private async Task OnSetVariableValue(MessageId id, int scopeId, string varName, JToken varValue, CancellationToken token) { ExecutionContext ctx = GetContext(id); @@ -566,59 +572,32 @@ internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId ob } //Console.WriteLine($"RuntimeGetProperties - {args}"); try { - if (objectId.Scheme == "scope") + switch (objectId.Scheme) { - return await GetScopeProperties(id, int.Parse(objectId.Value), token); - } - if (objectId.Scheme == "valuetype") - { - var ret = await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), accessorPropertiesOnly, token); - Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); - return res2; - } - if (objectId.Scheme == "array") - { - var ret = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); - Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); - return res2; - } - if (objectId.Scheme == "object") - { - var ret = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, false, accessorPropertiesOnly, ownProperties, token); - Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); - return res2; - } - if (objectId.Scheme == "pointer") - { - var ret = new JArray(await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token)); - Result res2 = Result.Ok(JObject.FromObject(new { result = ret })); - return res2; - } - if (objectId.Scheme == "cfo_res") - { - Result res2 = await SendMonoCommand(id, MonoCommands.GetDetails(int.Parse(objectId.Value), args), token); - // Runtime.callFunctionOn result object - string value_json_str = res2.Value["result"]?["value"]?["__value_as_json_string__"]?.Value(); - if (value_json_str != null) + case "scope": + return await GetScopeProperties(id, int.Parse(objectId.Value), token); + case "valuetype": + return Result.OkFromObject(new { result = await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), accessorPropertiesOnly, token)}); + case "array": + return Result.OkFromObject(new { result = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token)}); + case "object": + return Result.OkFromObject(new { result = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, false, accessorPropertiesOnly, ownProperties, token) }); + case "pointer": + return Result.OkFromObject(new { result = await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token)}); + case "cfo_res": { - res2 = Result.OkFromObject(new - { - result = JArray.Parse(value_json_str) - }); + Result res = await SendMonoCommand(id, MonoCommands.GetDetails(int.Parse(objectId.Value), args), token); + string value_json_str = res.Value["result"]?["value"]?["__value_as_json_string__"]?.Value(); + return Result.OkFromObject(new { result = value_json_str != null ? (object) JArray.Parse(value_json_str) : new {} }); } - else - { - res2 = Result.OkFromObject(new { result = new { } }); - } - return res2; + default: + return Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); + } } catch (Exception e) { - Result res2 = Result.Err($"Unable to RuntimeGetProperties '{objectId}' - {e}"); - return res2; + return Result.Err($"Unable to RuntimeGetProperties '{objectId}' - {e}"); } - Result res = Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); - return res; } private async Task EvaluateCondition(SessionId sessionId, ExecutionContext context, Frame mono_frame, Breakpoint bp, CancellationToken token) @@ -661,7 +640,7 @@ private async Task SendCallStack(SessionId sessionId, ExecutionContext con command_params_writer.Write(thread_id); command_params_writer.Write(0); command_params_writer.Write(-1); - var ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, (int) CommandSet.THREAD, (int) CmdThread.GET_FRAME_INFO, command_params, token); + var ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, CmdThread.GetFrameInfo, command_params, token); var frame_count = ret_debugger_cmd_reader.ReadInt32(); //Console.WriteLine("frame_count - " + frame_count); for (int j = 0; j < frame_count; j++) { @@ -805,12 +784,12 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec for (int i = 0 ; i < number_of_events; i++) { var event_kind = (EventKind)ret_debugger_cmd_reader.ReadByte(); //event kind var request_id = ret_debugger_cmd_reader.ReadInt32(); //request id - if (event_kind == EventKind.STEP) + if (event_kind == EventKind.Step) await sdbHelper.ClearSingleStep(sessionId, request_id, token); int thread_id = ret_debugger_cmd_reader.ReadInt32(); switch (event_kind) { - case EventKind.EXCEPTION: + case EventKind.Exception: { string reason = "exception"; int object_id = ret_debugger_cmd_reader.ReadInt32(); @@ -830,14 +809,14 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec var ret = await SendCallStack(sessionId, context, reason, thread_id, null, data, args?["callFrames"]?.Values(), token); return ret; } - case EventKind.USER_BREAK: - case EventKind.STEP: - case EventKind.BREAKPOINT: + case EventKind.UserBreak: + case EventKind.Step: + case EventKind.Breakpoint: { Breakpoint bp = context.BreakpointRequests.Values.SelectMany(v => v.Locations).FirstOrDefault(b => b.RemoteId == request_id); string reason = "other";//other means breakpoint int method_id = 0; - if (event_kind != EventKind.USER_BREAK) + if (event_kind != EventKind.UserBreak) method_id = ret_debugger_cmd_reader.ReadInt32(); var ret = await SendCallStack(sessionId, context, reason, thread_id, bp, null, args?["callFrames"]?.Values(), token); return ret; @@ -1163,7 +1142,7 @@ private async Task RuntimeReady(SessionId sessionId, CancellationTok return await context.ready.Task; var command_params = new MemoryStream(); - var ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR_ALL_BREAKPOINTS, command_params, token); + var ret_debugger_cmd_reader = await sdbHelper.SendDebuggerAgentCommand(sessionId, CmdEventRequest.ClearAllBreakpoints, command_params, token); if (ret_debugger_cmd_reader == null) { Log("verbose", $"Failed to clear breakpoints"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 60ca57522cc01..e61157ecae2f6 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -19,256 +19,255 @@ namespace Microsoft.WebAssembly.Diagnostics { internal enum TokenType { - mdtModule = 0x00000000, // - mdtTypeRef = 0x01000000, // - mdtTypeDef = 0x02000000, // - mdtFieldDef = 0x04000000, // - mdtMethodDef = 0x06000000, // - mdtParamDef = 0x08000000, // - mdtInterfaceImpl = 0x09000000, // - mdtMemberRef = 0x0a000000, // - mdtCustomAttribute = 0x0c000000, // - mdtPermission = 0x0e000000, // - mdtSignature = 0x11000000, // - mdtEvent = 0x14000000, // - mdtProperty = 0x17000000, // - mdtModuleRef = 0x1a000000, // - mdtTypeSpec = 0x1b000000, // - mdtAssembly = 0x20000000, // - mdtAssemblyRef = 0x23000000, // - mdtFile = 0x26000000, // - mdtExportedType = 0x27000000, // - mdtManifestResource = 0x28000000, // - mdtGenericParam = 0x2a000000, // - mdtMethodSpec = 0x2b000000, // - mdtGenericParamConstraint = 0x2c000000, - - mdtString = 0x70000000, // - mdtName = 0x71000000, // - mdtBaseType = 0x72000000, // Leave this on the high end value. This does not correspond to metadata table + MdtModule = 0x00000000, // + MdtTypeRef = 0x01000000, // + MdtTypeDef = 0x02000000, // + MdtFieldDef = 0x04000000, // + MdtMethodDef = 0x06000000, // + MdtParamDef = 0x08000000, // + MdtInterfaceImpl = 0x09000000, // + MdtMemberRef = 0x0a000000, // + MdtCustomAttribute = 0x0c000000, // + MdtPermission = 0x0e000000, // + MdtSignature = 0x11000000, // + MdtEvent = 0x14000000, // + MdtProperty = 0x17000000, // + MdtModuleRef = 0x1a000000, // + MdtTypeSpec = 0x1b000000, // + MdtAssembly = 0x20000000, // + MdtAssemblyRef = 0x23000000, // + MdtFile = 0x26000000, // + MdtExportedType = 0x27000000, // + MdtManifestResource = 0x28000000, // + MdtGenericParam = 0x2a000000, // + MdtMethodSpec = 0x2b000000, // + MdtGenericParamConstraint = 0x2c000000, + MdtString = 0x70000000, // + MdtName = 0x71000000, // + MdtBaseType = 0x72000000, // Leave this on the high end value. This does not correspond to metadata table } internal enum CommandSet { - VM = 1, - OBJECT_REF = 9, - STRING_REF = 10, - THREAD = 11, - ARRAY_REF = 13, - EVENT_REQUEST = 15, - STACK_FRAME = 16, - APPDOMAIN = 20, - ASSEMBLY = 21, - METHOD = 22, - TYPE = 23, - MODULE = 24, - FIELD = 25, - EVENT = 64, - POINTER = 65 + Vm = 1, + ObjectRef = 9, + StringRef = 10, + Thread = 11, + ArrayRef = 13, + EventRequest = 15, + StackFrame = 16, + AppDomain = 20, + Assembly = 21, + Method = 22, + Type = 23, + Module = 24, + Field = 25, + Event = 64, + Pointer = 65 } internal enum EventKind { - VM_START = 0, - VM_DEATH = 1, - THREAD_START = 2, - THREAD_DEATH = 3, - APPDOMAIN_CREATE = 4, // Not in JDI - APPDOMAIN_UNLOAD = 5, // Not in JDI - METHOD_ENTRY = 6, - METHOD_EXIT = 7, - ASSEMBLY_LOAD = 8, - ASSEMBLY_UNLOAD = 9, - BREAKPOINT = 10, - STEP = 11, - TYPE_LOAD = 12, - EXCEPTION = 13, - KEEPALIVE = 14, - USER_BREAK = 15, - USER_LOG = 16, - CRASH = 17 + VmStart = 0, + VmDeath = 1, + ThreadStart = 2, + ThreadDeath = 3, + AppDomainCreate = 4, + AppDomainUnload = 5, + MethodEntry = 6, + MethodExit = 7, + AssemblyLoad = 8, + AssemblyUnload = 9, + Breakpoint = 10, + Step = 11, + TypeLoad = 12, + Exception = 13, + KeepAlive = 14, + UserBreak = 15, + UserLog = 16, + Crash = 17 } internal enum ModifierKind { - COUNT = 1, - THREAD_ONLY = 3, - LOCATION_ONLY = 7, - EXCEPTION_ONLY = 8, - STEP = 10, - ASSEMBLY_ONLY = 11, - SOURCE_FILE_ONLY = 12, - TYPE_NAME_ONLY = 13 + Count = 1, + ThreadOnly = 3, + LocationOnly = 7, + ExceptionOnly = 8, + Step = 10, + AssemblyOnly = 11, + SourceFileOnly = 12, + TypeNameOnly = 13 } internal enum SuspendPolicy { - SUSPEND_POLICY_NONE = 0, - SUSPEND_POLICY_EVENT_THREAD = 1, - SUSPEND_POLICY_ALL = 2 + None = 0, + EventThread = 1, + All = 2 } internal enum CmdVM { - VERSION = 1, - ALL_THREADS = 2, - SUSPEND = 3, - RESUME = 4, - EXIT = 5, - DISPOSE = 6, - INVOKE_METHOD = 7, - SET_PROTOCOL_VERSION = 8, - ABORT_INVOKE = 9, - SET_KEEPALIVE = 10, - GET_TYPES_FOR_SOURCE_FILE = 11, - GET_TYPES = 12, - INVOKE_METHODS = 13, - START_BUFFERING = 14, - STOP_BUFFERING = 15, - VM_READ_MEMORY = 16, - VM_WRITE_MEMORY = 17, - GET_ASSEMBLY_BY_NAME = 18 + Version = 1, + AllThreads = 2, + Suspend = 3, + Resume = 4, + Exit = 5, + Dispose = 6, + InvokeMethod = 7, + SetProtocolVersion = 8, + AbortInvoke = 9, + SetKeepAlive = 10, + GetTypesForSourceFile = 11, + GetTypes = 12, + InvokeMethods = 13, + StartBuffering = 14, + StopBuffering = 15, + VmReadMemory = 16, + VmWriteMemory = 17, + GetAssemblyByName = 18 } internal enum CmdFrame { - GET_VALUES = 1, - GET_THIS = 2, - SET_VALUES = 3, - GET_DOMAIN = 4, - SET_THIS = 5, - GET_ARGUMENT = 6, - GET_ARGUMENTS = 7 + GetValues = 1, + GetThis = 2, + SetValues = 3, + GetDomain = 4, + SetThis = 5, + GetArgument = 6, + GetArguments = 7 } internal enum CmdEvent { - COMPOSITE = 100 + Composite = 100 } internal enum CmdThread { - GET_FRAME_INFO = 1, - GET_NAME = 2, - GET_STATE = 3, - GET_INFO = 4, - /* FIXME: Merge into GET_INFO when the major protocol version is increased */ - GET_ID = 5, + GetFrameInfo = 1, + GetName = 2, + GetState = 3, + GetInfo = 4, + /* FIXME: Merge into GetInfo when the major protocol version is increased */ + GetId = 5, /* Ditto */ - GET_TID = 6, - SET_IP = 7, - GET_ELAPSED_TIME = 8 + GetTid = 6, + SetIp = 7, + GetElapsedTime = 8 } internal enum CmdEventRequest { - SET = 1, - CLEAR = 2, - CLEAR_ALL_BREAKPOINTS = 3 + Set = 1, + Clear = 2, + ClearAllBreakpoints = 3 } internal enum CmdAppDomain { - GET_ROOT_DOMAIN = 1, - GET_FRIENDLY_NAME = 2, - GET_ASSEMBLIES = 3, - GET_ENTRY_ASSEMBLY = 4, - CREATE_STRING = 5, - GET_CORLIB = 6, - CREATE_BOXED_VALUE = 7, - CREATE_BYTE_ARRAY = 8, + GetRootDomain = 1, + GetFriendlyName = 2, + GetAssemblies = 3, + GetEntryAssembly = 4, + CreateString = 5, + GetCorLib = 6, + CreateBoxedValue = 7, + CreateByteArray = 8, } internal enum CmdAssembly { - GET_LOCATION = 1, - GET_ENTRY_POINT = 2, - GET_MANIFEST_MODULE = 3, - GET_OBJECT = 4, - GET_TYPE = 5, - GET_NAME = 6, - GET_DOMAIN = 7, - GET_METADATA_BLOB = 8, - GET_IS_DYNAMIC = 9, - GET_PDB_BLOB = 10, - GET_TYPE_FROM_TOKEN = 11, - GET_METHOD_FROM_TOKEN = 12, - HAS_DEBUG_INFO = 13, + GetLocation = 1, + GetEntryPoint = 2, + GetManifestModule = 3, + GetObject = 4, + GetType = 5, + GetName = 6, + GetDomain = 7, + GetMetadataBlob = 8, + GetIsDynamic = 9, + GetPdbBlob = 10, + GetTypeFromToken = 11, + GetMethodFromToken = 12, + HasDebugInfo = 13, } internal enum CmdModule { - GET_INFO = 1, - APPLY_CHANGES = 2, + GetInfo = 1, + ApplyChanges = 2, } internal enum CmdPointer{ - GET_VALUE = 1 + GetValue = 1 } internal enum CmdMethod { - GET_NAME = 1, - GET_DECLARING_TYPE = 2, - GET_DEBUG_INFO = 3, - GET_PARAM_INFO = 4, - GET_LOCALS_INFO = 5, - GET_INFO = 6, - GET_BODY = 7, - RESOLVE_TOKEN = 8, - GET_CATTRS = 9, - MAKE_GENERIC_METHOD = 10, - TOKEN = 11, - ASSEMBLY = 12, - CLASS_TOKEN = 13, - ASYNC_DEBUG_INFO = 14, - GET_NAME_FULL = 15 + GetName = 1, + GetDeclaringType = 2, + GetDebugInfo = 3, + GetParamInfo = 4, + GetLocalsInfo = 5, + GetInfo = 6, + GetBody = 7, + ResolveToken = 8, + GetCattrs = 9, + MakeGenericMethod = 10, + Token = 11, + Assembly = 12, + ClassToken = 13, + AsyncDebugInfo = 14, + GetNameFull = 15 } internal enum CmdType { - GET_INFO = 1, - GET_METHODS = 2, - GET_FIELDS = 3, - GET_VALUES = 4, - GET_OBJECT = 5, - GET_SOURCE_FILES = 6, - SET_VALUES = 7, - IS_ASSIGNABLE_FROM = 8, - GET_PROPERTIES = 9, - GET_CATTRS = 10, - GET_FIELD_CATTRS = 11, - GET_PROPERTY_CATTRS = 12, - /* FIXME: Merge into GET_SOURCE_FILES when the major protocol version is increased */ - GET_SOURCE_FILES_2 = 13, - /* FIXME: Merge into GET_VALUES when the major protocol version is increased */ - GET_VALUES_2 = 14, - GET_METHODS_BY_NAME_FLAGS = 15, - GET_INTERFACES = 16, - GET_INTERFACE_MAP = 17, - IS_INITIALIZED = 18, - CREATE_INSTANCE = 19, - GET_VALUE_SIZE = 20, - GET_VALUES_ICORDBG = 21, - GET_PARENTS = 22 + GetInfo = 1, + GetMethods = 2, + GetFields = 3, + GetValues = 4, + GetObject = 5, + GetSourceFiles = 6, + SetValues = 7, + IsAssignableFrom = 8, + GetProperties = 9, + GetCattrs = 10, + GetFieldCattrs = 11, + GetPropertyCattrs = 12, + /* FIXME: Merge into GetSourceFiles when the major protocol version is increased */ + GetSourceFiles2 = 13, + /* FIXME: Merge into GetValues when the major protocol version is increased */ + GetValues2 = 14, + GetMethodsByNameFlags = 15, + GetInterfaces = 16, + GetInterfacesMap = 17, + IsInitialized = 18, + CreateInstance = 19, + GetValueSize = 20, + GetValuesICorDbg = 21, + GetParents = 22 } internal enum CmdArray { - GET_LENGTH = 1, - GET_VALUES = 2, - SET_VALUES = 3, - REF_GET_TYPE = 4 + GetLength = 1, + GetValues = 2, + SetValues = 3, + RefGetType = 4 } internal enum CmdField { - GET_INFO = 1 + GetInfo = 1 } internal enum CmdString { - GET_VALUE = 1, - GET_LENGTH = 2, - GET_CHARS = 3 + GetValue = 1, + GetLength = 2, + GetChars = 3 } internal enum CmdObject { - REF_GET_TYPE = 1, - REF_GET_VALUES = 2, - REF_IS_COLLECTED = 3, - REF_GET_ADDRESS = 4, - REF_GET_DOMAIN = 5, - REF_SET_VALUES = 6, - REF_GET_INFO = 7, - GET_VALUES_ICORDBG = 8, - REF_DELEGATE_GET_METHOD = 9, - REF_IS_DELEGATE = 10 + RefGetType = 1, + RefGetValues = 2, + RefIsCollected = 3, + RefGetAddress = 4, + RefGetDomain = 5, + RefSetValues = 6, + RefGetInfo = 7, + GetValuesICorDbg = 8, + RefDelegateGetMethod = 9, + RefIsDelegate = 10 } internal enum ElementType { @@ -314,16 +313,16 @@ internal enum ElementType { } internal enum ValueTypeId { - VALUE_TYPE_ID_NULL = 0xf0, - VALUE_TYPE_ID_TYPE = 0xf1, - VALUE_TYPE_ID_PARENT_VTYPE = 0xf2, - VALUE_TYPE_ID_FIXED_ARRAY = 0xf3 + Null = 0xf0, + Type = 0xf1, + VType = 0xf2, + FixedArray = 0xf3 } internal enum MonoTypeNameFormat{ - MONO_TYPE_NAME_FORMAT_IL, - MONO_TYPE_NAME_FORMAT_REFLECTION, - MONO_TYPE_NAME_FORMAT_FULL_NAME, - MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED + FormatIL, + FormatReflection, + FullName, + AssemblyQualified } internal enum StepFilter { @@ -549,20 +548,20 @@ public async Task SetProtocolVersion(SessionId sessionId, CancellationToke command_params_writer.Write(MAJOR_VERSION); command_params_writer.Write(MINOR_VERSION); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.SET_PROTOCOL_VERSION, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdVM.SetProtocolVersion, command_params, token); return true; } public async Task EnableReceiveUserBreakRequest(SessionId sessionId, CancellationToken token) { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.USER_BREAK); - command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_NONE); + command_params_writer.Write((byte)EventKind.UserBreak); + command_params_writer.Write((byte)SuspendPolicy.None); command_params_writer.Write((byte)0); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdEventRequest.Set, command_params, token); return true; } - internal async Task SendDebuggerAgentCommand(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) + internal async Task SendDebuggerAgentCommandInternal(SessionId sessionId, int command_set, int command, MemoryStream parms, CancellationToken token) { Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray())), token); if (res.IsErr) { @@ -574,7 +573,53 @@ internal async Task SendDebuggerAgentCommand(SessionId session return ret_debugger_cmd_reader; } - internal async Task SendDebuggerAgentCommandWithParms(SessionId sessionId, int command_set, int command, MemoryStream parms, int type, string extraParm, CancellationToken token) + internal Task SendDebuggerAgentCommand(SessionId sessionId, T command, MemoryStream parms, CancellationToken token) where T : Enum + { + CommandSet set = command switch { + CmdVM => CommandSet.Vm, + CmdObject => CommandSet.ObjectRef, + CmdString => CommandSet.StringRef, + CmdThread => CommandSet.Thread, + CmdArray => CommandSet.ArrayRef, + CmdEventRequest => CommandSet.EventRequest, + CmdFrame => CommandSet.StackFrame, + CmdAppDomain => CommandSet.AppDomain, + CmdAssembly => CommandSet.Assembly, + CmdMethod => CommandSet.Method, + CmdType => CommandSet.Type, + CmdModule => CommandSet.Module, + CmdField => CommandSet.Field, + CmdEvent => CommandSet.Event, + CmdPointer => CommandSet.Pointer, + _ => throw new Exception ("Unknown CommandSet") + }; + return SendDebuggerAgentCommandInternal(sessionId, (int)set, (int)(object)command, parms, token); + } + + internal Task SendDebuggerAgentCommandWithParms(SessionId sessionId, T command, MemoryStream parms, int type, string extraParm, CancellationToken token) where T : Enum + { + CommandSet set = command switch { + CmdVM => CommandSet.Vm, + CmdObject => CommandSet.ObjectRef, + CmdString => CommandSet.StringRef, + CmdThread => CommandSet.Thread, + CmdArray => CommandSet.ArrayRef, + CmdEventRequest => CommandSet.EventRequest, + CmdFrame => CommandSet.StackFrame, + CmdAppDomain => CommandSet.AppDomain, + CmdAssembly => CommandSet.Assembly, + CmdMethod => CommandSet.Method, + CmdType => CommandSet.Type, + CmdModule => CommandSet.Module, + CmdField => CommandSet.Field, + CmdEvent => CommandSet.Event, + CmdPointer => CommandSet.Pointer, + _ => throw new Exception ("Unknown CommandSet") + }; + return SendDebuggerAgentCommandWithParmsInternal(sessionId, (int)set, (int)(object)command, parms, type, extraParm, token); + } + + internal async Task SendDebuggerAgentCommandWithParmsInternal(SessionId sessionId, int command_set, int command, MemoryStream parms, int type, string extraParm, CancellationToken token) { Result res = await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommandWithParms(GetId(), command_set, command, Convert.ToBase64String(parms.ToArray()), parms.ToArray().Length, type, extraParm), token); if (res.IsErr) { @@ -592,7 +637,7 @@ public async Task GetMethodToken(SessionId sessionId, int method_id, Cancel var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(method_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.TOKEN, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.Token, command_params, token); return ret_debugger_cmd_reader.ReadInt32() & 0xffffff; //token } @@ -601,8 +646,8 @@ public async Task GetMethodIdByToken(SessionId sessionId, int assembly_id, var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(assembly_id); - command_params_writer.Write(method_token | (int)TokenType.mdtMethodDef); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_METHOD_FROM_TOKEN, command_params, token); + command_params_writer.Write(method_token | (int)TokenType.MdtMethodDef); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdAssembly.GetMethodFromToken, command_params, token); return ret_debugger_cmd_reader.ReadInt32(); } @@ -612,7 +657,7 @@ public async Task GetAssemblyIdFromMethod(SessionId sessionId, int method_i var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(method_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.ASSEMBLY, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.Assembly, command_params, token); return ret_debugger_cmd_reader.ReadInt32(); //assembly_id } @@ -622,7 +667,7 @@ public async Task GetAssemblyId(SessionId sessionId, string asm_name, Cance var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.WriteString(asm_name); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.GET_ASSEMBLY_BY_NAME, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdVM.GetAssemblyByName, command_params, token); return ret_debugger_cmd_reader.ReadInt32(); } @@ -632,7 +677,7 @@ public async Task GetAssemblyName(SessionId sessionId, int assembly_id, var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(assembly_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_LOCATION, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdAssembly.GetLocation, command_params, token); return ret_debugger_cmd_reader.ReadString(); } @@ -643,7 +688,7 @@ public async Task GetAssemblyNameFull(SessionId sessionId, int assembly_ var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(assembly_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ASSEMBLY, (int) CmdAssembly.GET_NAME, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdAssembly.GetName, command_params, token); var name = ret_debugger_cmd_reader.ReadString(); return name.Remove(name.IndexOf(",")) + ".dll"; } @@ -654,7 +699,7 @@ public async Task GetMethodName(SessionId sessionId, int method_id, Canc var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(method_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME_FULL, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.GetNameFull, command_params, token); var methodName = ret_debugger_cmd_reader.ReadString(); return methodName.Substring(methodName.IndexOf(":")+1); } @@ -665,7 +710,7 @@ public async Task MethodIsStatic(SessionId sessionId, int method_id, Cance var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(method_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_INFO, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.GetInfo, command_params, token); var flags = ret_debugger_cmd_reader.ReadInt32(); return (flags & 0x0010) > 0; //check method is static } @@ -676,7 +721,7 @@ public async Task GetParamCount(SessionId sessionId, int method_id, Cancell var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(method_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_PARAM_INFO, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.GetParamInfo, command_params, token); ret_debugger_cmd_reader.ReadInt32(); int param_count = ret_debugger_cmd_reader.ReadInt32(); return param_count; @@ -688,7 +733,7 @@ public async Task GetReturnType(SessionId sessionId, int method_id, Canc var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(method_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_PARAM_INFO, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.GetParamInfo, command_params, token); ret_debugger_cmd_reader.ReadInt32(); ret_debugger_cmd_reader.ReadInt32(); ret_debugger_cmd_reader.ReadInt32(); @@ -703,7 +748,7 @@ public async Task GetParameters(SessionId sessionId, int method_id, Canc var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(method_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_PARAM_INFO, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.GetParamInfo, command_params, token); ret_debugger_cmd_reader.ReadInt32(); var paramCount = ret_debugger_cmd_reader.ReadInt32(); ret_debugger_cmd_reader.ReadInt32(); @@ -725,13 +770,13 @@ public async Task SetBreakpoint(SessionId sessionId, int method_id, long il { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.BREAKPOINT); - command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_NONE); + command_params_writer.Write((byte)EventKind.Breakpoint); + command_params_writer.Write((byte)SuspendPolicy.None); command_params_writer.Write((byte)1); - command_params_writer.Write((byte)ModifierKind.LOCATION_ONLY); + command_params_writer.Write((byte)ModifierKind.LocationOnly); command_params_writer.Write(method_id); command_params_writer.WriteLong(il_offset); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdEventRequest.Set, command_params, token); return ret_debugger_cmd_reader.ReadInt32(); } @@ -739,10 +784,10 @@ public async Task RemoveBreakpoint(SessionId sessionId, int breakpoint_id, { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.BREAKPOINT); + command_params_writer.Write((byte)EventKind.Breakpoint); command_params_writer.Write((int) breakpoint_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdEventRequest.Clear, command_params, token); if (ret_debugger_cmd_reader != null) return true; @@ -753,15 +798,15 @@ public async Task Step(SessionId sessionId, int thread_id, StepKind kind, { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.STEP); - command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_NONE); + command_params_writer.Write((byte)EventKind.Step); + command_params_writer.Write((byte)SuspendPolicy.None); command_params_writer.Write((byte)1); - command_params_writer.Write((byte)ModifierKind.STEP); + command_params_writer.Write((byte)ModifierKind.Step); command_params_writer.Write(thread_id); command_params_writer.Write((int)0); command_params_writer.Write((int)kind); command_params_writer.Write((int)(StepFilter.StaticCtor | StepFilter.DebuggerHidden)); //filter - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdEventRequest.Set, command_params, token); if (ret_debugger_cmd_reader == null) return false; var isBPOnManagedCode = ret_debugger_cmd_reader.ReadInt32(); @@ -774,10 +819,10 @@ public async Task ClearSingleStep(SessionId sessionId, int req_id, Cancell { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.STEP); + command_params_writer.Write((byte)EventKind.Step); command_params_writer.Write((int) req_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.CLEAR, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdEventRequest.Clear, command_params, token); if (ret_debugger_cmd_reader != null) return true; @@ -791,7 +836,7 @@ public async Task> GetTypeFields(SessionId sessionId, int t var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(type_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_FIELDS, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdType.GetFields, command_params, token); var nFields = ret_debugger_cmd_reader.ReadInt32(); for (int i = 0 ; i < nFields; i++) @@ -826,8 +871,8 @@ public async Task GetTypeName(SessionId sessionId, int type_id, Cancella var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(type_id); - command_params_writer.Write((int) MonoTypeNameFormat.MONO_TYPE_NAME_FORMAT_REFLECTION); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_INFO, command_params, token); + command_params_writer.Write((int) MonoTypeNameFormat.FormatReflection); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdType.GetInfo, command_params, token); ret_debugger_cmd_reader.ReadString(); @@ -852,7 +897,7 @@ public async Task GetStringValue(SessionId sessionId, int string_id, Can var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(string_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STRING_REF, (int) CmdString.GET_VALUE, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdString.GetValue, command_params, token); var isUtf16 = ret_debugger_cmd_reader.ReadByte(); if (isUtf16 == 0) { return ret_debugger_cmd_reader.ReadString(); @@ -864,7 +909,7 @@ public async Task GetArrayLength(SessionId sessionId, int object_id, Cancel var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(object_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ARRAY_REF, (int) CmdArray.GET_LENGTH, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdArray.GetLength, command_params, token); var length = ret_debugger_cmd_reader.ReadInt32(); length = ret_debugger_cmd_reader.ReadInt32(); return length; @@ -876,7 +921,7 @@ public async Task> GetTypeIdFromObject(SessionId sessionId, int object var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(object_id); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_GET_TYPE, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdObject.RefGetType, command_params, token); var type_id = ret_debugger_cmd_reader.ReadInt32(); ret.Add(type_id); if (withParents) @@ -884,7 +929,7 @@ public async Task> GetTypeIdFromObject(SessionId sessionId, int object command_params = new MemoryStream(); command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(type_id); - ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PARENTS, command_params, token); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdType.GetParents, command_params, token); var parentsCount = ret_debugger_cmd_reader.ReadInt32(); for (int i = 0 ; i < parentsCount; i++) { @@ -909,7 +954,7 @@ public async Task GetMethodIdByName(SessionId sessionId, int type_id, strin command_params_writer.WriteString(method_name); command_params_writer.Write((int)(0x10 | 4)); //instance methods command_params_writer.Write((int)1); //case sensitive - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_METHODS_BY_NAME_FLAGS, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdType.GetMethodsByNameFlags, command_params, token); var nMethods = ret_debugger_cmd_reader.ReadInt32(); return ret_debugger_cmd_reader.ReadInt32(); } @@ -920,7 +965,7 @@ public async Task IsDelegate(SessionId sessionId, int objectId, Cancellati var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write((int)objectId); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_IS_DELEGATE, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdObject.RefIsDelegate, command_params, token); return ret_debugger_cmd_reader.ReadByte() == 1; } @@ -930,7 +975,7 @@ public async Task GetDelegateMethod(SessionId sessionId, int objectId, Canc var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write((int)objectId); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_DELEGATE_GET_METHOD, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdObject.RefDelegateGetMethod, command_params, token); return ret_debugger_cmd_reader.ReadInt32(); } @@ -944,7 +989,7 @@ public async Task GetDelegateMethodDescription(SessionId sessionId, int //Console.WriteLine("methodId - " + methodId); if (methodId == 0) return ""; - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.GET_NAME, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.GetName, command_params, token); var methodName = ret_debugger_cmd_reader.ReadString(); var returnType = await GetReturnType(sessionId, methodId, token); @@ -959,7 +1004,7 @@ public async Task InvokeMethod(SessionId sessionId, byte[] valueTypeBuf command_params_writer.Write(method_id); command_params_writer.Write(valueTypeBuffer); command_params_writer.Write(0); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.VM, (int) CmdVM.INVOKE_METHOD, parms, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdVM.InvokeMethod, parms, token); ret_debugger_cmd_reader.ReadByte(); //number of objects returned. return await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, varName, false, -1, token); } @@ -970,7 +1015,7 @@ public async Task CreateJArrayForProperties(SessionId sessionId, int typ var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(typeId); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdType.GetProperties, command_params, token); var nProperties = ret_debugger_cmd_reader.ReadInt32(); for (int i = 0 ; i < nProperties; i++) { @@ -1022,7 +1067,7 @@ public async Task GetPointerContent(SessionId sessionId, int pointerId, var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.WriteLong(pointerValues[pointerId].address); command_params_writer.Write(pointerValues[pointerId].typeId); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.POINTER, (int) CmdPointer.GET_VALUE, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdPointer.GetValue, command_params, token); var varName = pointerValues[pointerId].varName; if (int.TryParse(varName, out _)) varName = $"[{varName}]"; @@ -1035,7 +1080,7 @@ public async Task GetPropertiesValuesOfValueType(SessionId sessionId, in var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(valueType.typeId); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PARENTS, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdType.GetParents, command_params, token); var parentsCount = ret_debugger_cmd_reader.ReadInt32(); List typesToGetProperties = new List(); typesToGetProperties.Add(valueType.typeId); @@ -1442,7 +1487,7 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo }); break; } - case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL: + case (ElementType)ValueTypeId.Null: { string className = ""; ElementType variableType = (ElementType)ret_debugger_cmd_reader.ReadByte(); @@ -1486,17 +1531,17 @@ public async Task CreateJObjectForVariableValue(SessionId sessionId, Mo }); break; } - case (ElementType)ValueTypeId.VALUE_TYPE_ID_TYPE: + case (ElementType)ValueTypeId.Type: { ret = new JObject{{"Type", "void"}}; break; } - case (ElementType)ValueTypeId.VALUE_TYPE_ID_PARENT_VTYPE: + case (ElementType)ValueTypeId.VType: { ret = new JObject{{"Type", "void"}}; break; } - case (ElementType)ValueTypeId.VALUE_TYPE_ID_FIXED_ARRAY: + case (ElementType)ValueTypeId.FixedArray: { ret = new JObject{{"Type", "void"}}; break; @@ -1513,7 +1558,7 @@ public async Task IsAsyncMethod(SessionId sessionId, int methodId, Cancell var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(methodId); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.METHOD, (int) CmdMethod.ASYNC_DEBUG_INFO, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdMethod.AsyncDebugInfo, command_params, token); return ret_debugger_cmd_reader.ReadByte() == 1 ; //token } @@ -1532,7 +1577,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me if (await IsAsyncMethod(sessionId, method.DebuggerId, token)) { - ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdFrame.GetThis, command_params, token); ret_debugger_cmd_reader.ReadByte(); //ignore type var objectId = ret_debugger_cmd_reader.ReadInt32(); var asyncLocals = await GetObjectValues(sessionId, objectId, true, false, false, false, token); @@ -1548,7 +1593,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me } JArray locals = new JArray(); - ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_VALUES, command_params, token); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdFrame.GetValues, command_params, token); foreach (var var in var_ids) { var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, var.Name, false, -1, token); @@ -1556,7 +1601,7 @@ public async Task StackFrameGetValues(SessionId sessionId, MethodInfo me } if (!method.IsStatic()) { - ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_THIS, command_params, token); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdFrame.GetThis, command_params, token); var var_json = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, "this", false, -1, token); var_json.Add("fieldOffset", -1); locals.Add(var_json); @@ -1587,7 +1632,7 @@ public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(valueTypes[valueTypeId].typeId); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdType.GetProperties, command_params, token); var nProperties = ret_debugger_cmd_reader.ReadInt32(); for (int i = 0 ; i < nProperties; i++) @@ -1607,8 +1652,8 @@ public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId command_params_writer_to_proxy.Write(0); valueTypes[valueTypeId].valueTypeProxy.Add(JObject.FromObject(new { get = JObject.FromObject(new { - commandSet = CommandSet.VM, - command = CmdVM.INVOKE_METHOD, + commandSet = CommandSet.Vm, + command = CmdVM.InvokeMethod, buffer = Convert.ToBase64String(command_params_to_proxy.ToArray()), length = command_params_to_proxy.ToArray().Length }), @@ -1626,7 +1671,7 @@ public async Task GetArrayValues(SessionId sessionId, int arrayId, Cance command_params_writer.Write(arrayId); command_params_writer.Write(0); command_params_writer.Write(length); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.ARRAY_REF, (int) CmdArray.GET_VALUES, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdArray.GetValues, command_params, token); JArray array = new JArray(); for (int i = 0 ; i < length ; i++) { @@ -1640,10 +1685,10 @@ public async Task EnableExceptions(SessionId sessionId, string state, Canc var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.EXCEPTION); - command_params_writer.Write((byte)SuspendPolicy.SUSPEND_POLICY_NONE); + command_params_writer.Write((byte)EventKind.Exception); + command_params_writer.Write((byte)SuspendPolicy.None); command_params_writer.Write((byte)1); - command_params_writer.Write((byte)ModifierKind.EXCEPTION_ONLY); + command_params_writer.Write((byte)ModifierKind.ExceptionOnly); command_params_writer.Write(0); //exc_class if (state == "all") command_params_writer.Write((byte)1); //caught @@ -1656,7 +1701,7 @@ public async Task EnableExceptions(SessionId sessionId, string state, Canc command_params_writer.Write((byte)1);//subclasses command_params_writer.Write((byte)0);//not_filtered_feature command_params_writer.Write((byte)0);//everything_else - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.EVENT_REQUEST, (int) CmdEventRequest.SET, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdEventRequest.Set, command_params, token); return true; } public async Task GetObjectValues(SessionId sessionId, int objectId, bool withProperties, bool withSetter, bool accessorPropertiesOnly, bool ownProperties, CancellationToken token) @@ -1696,7 +1741,7 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, boo command_params_writer.Write(field.Id); } - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.OBJECT_REF, (int) CmdObject.REF_GET_VALUES, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdObject.RefGetValues, command_params, token); foreach (var field in fields) { @@ -1717,8 +1762,8 @@ public async Task GetObjectValues(SessionId sessionId, int objectId, boo command_params_writer_to_set.Write(field.Id); fieldValue.Add("set", JObject.FromObject(new { - commandSet = CommandSet.OBJECT_REF, - command = CmdObject.REF_SET_VALUES, + commandSet = CommandSet.ObjectRef, + command = CmdObject.RefSetValues, buffer = Convert.ToBase64String(command_params_to_set.ToArray()), valtype, length = command_params_to_set.ToArray().Length @@ -1789,7 +1834,7 @@ public async Task GetObjectProxy(SessionId sessionId, int objectId, Canc var command_params_writer = new MonoBinaryWriter(command_params); command_params_writer.Write(typeId); - var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.TYPE, (int) CmdType.GET_PROPERTIES, command_params, token); + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdType.GetProperties, command_params, token); var nProperties = ret_debugger_cmd_reader.ReadInt32(); for (int i = 0 ; i < nProperties; i++) { @@ -1812,8 +1857,8 @@ public async Task GetObjectProxy(SessionId sessionId, int objectId, Canc if (attr["set"] != null) { attr["set"] = JObject.FromObject(new { - commandSet = CommandSet.VM, - command = CmdVM.INVOKE_METHOD, + commandSet = CommandSet.Vm, + command = CmdVM.InvokeMethod, buffer = Convert.ToBase64String(command_params_to_set.ToArray()), valtype = attr["set"]["valtype"], length = command_params_to_set.ToArray().Length @@ -1832,8 +1877,8 @@ public async Task GetObjectProxy(SessionId sessionId, int objectId, Canc ret.Add(JObject.FromObject(new { get = JObject.FromObject(new { - commandSet = CommandSet.VM, - command = CmdVM.INVOKE_METHOD, + commandSet = CommandSet.Vm, + command = CmdVM.InvokeMethod, buffer = Convert.ToBase64String(command_params_to_get.ToArray()), length = command_params_to_get.ToArray().Length }), @@ -1857,11 +1902,11 @@ public async Task SetVariableValue(SessionId sessionId, int thread_id, int command_params_writer.Write(1); command_params_writer.Write(varId); JArray locals = new JArray(); - ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.GET_VALUES, command_params, token); + ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdFrame.GetValues, command_params, token); int etype = ret_debugger_cmd_reader.ReadByte(); try { - ret_debugger_cmd_reader = await SendDebuggerAgentCommandWithParms(sessionId, (int) CommandSet.STACK_FRAME, (int) CmdFrame.SET_VALUES, command_params, etype, newValue, token); + ret_debugger_cmd_reader = await SendDebuggerAgentCommandWithParms(sessionId, CmdFrame.SetValues, command_params, etype, newValue, token); } catch (Exception) { From c4c9fa3e2d02b571890ccfe62bfc23fc16a8011c Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 11 Jun 2021 17:39:46 -0300 Subject: [PATCH 41/48] Fix pointer tests. --- src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 267fe724175df..b46038934838c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -583,7 +583,7 @@ internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId ob case "object": return Result.OkFromObject(new { result = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, false, accessorPropertiesOnly, ownProperties, token) }); case "pointer": - return Result.OkFromObject(new { result = await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token)}); + return Result.OkFromObject(new { result = new JArray{await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token)}}); case "cfo_res": { Result res = await SendMonoCommand(id, MonoCommands.GetDetails(int.Parse(objectId.Value), args), token); From fc8ec749b8591fcbcdd6b92ae03ee5632ad53428 Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 14 Jun 2021 14:56:05 -0300 Subject: [PATCH 42/48] Refactoring CreateJObjectForVariableValue --- .../BrowserDebugProxy/MonoSDBHelper.cs | 560 +++++++----------- 1 file changed, 220 insertions(+), 340 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index e61157ecae2f6..4bed43bb5469a 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1115,440 +1115,320 @@ public bool AutoInvokeToString(string className) { return false; } + public JObject CreateJObject(T value, string type, string description, bool writable, string className = null, string objectId = null, string __custom_type = null, string subtype = null, bool isValueType = false, bool expanded = false, bool isEnum = false) + { + var ret = JObject.FromObject(new { + value = new + { + type, + value, + description + }, + writable + }); + if (__custom_type != null) + ret["value"]["__custom_type"] = __custom_type; + if (className != null) + ret["value"]["className"] = className; + if (objectId != null) + ret["value"]["objectId"] = objectId; + if (subtype != null) + ret["value"]["subtype"] = subtype; + if (isValueType) + ret["value"]["isValueType"] = isValueType; + if (expanded) + ret["value"]["expanded"] = expanded; + if (isEnum) + ret["value"]["isEnum"] = isEnum; + return ret; + + } + public JObject CreateJObjectForBoolean(int value) + { + return CreateJObject(value == 0 ? false : true, "boolean", value == 0 ? "false" : "true", true); + } + + public JObject CreateJObjectForNumber(T value) + { + return CreateJObject(value, "number", value.ToString(), true); + } + + public JObject CreateJObjectForChar(int value) + { + var description = $"{value.ToString()} '{Convert.ToChar(value)}'"; + return CreateJObject(description, "symbol", description, true); + } + + public async Task CreateJObjectForPtr(SessionId sessionId, ElementType etype, MonoBinaryReader ret_debugger_cmd_reader, string name, CancellationToken token) + { + string type; + string value; + long valueAddress = ret_debugger_cmd_reader.ReadLong(); + var typeId = ret_debugger_cmd_reader.ReadInt32(); + var className = ""; + if (etype == ElementType.FnPtr) + className = "(*())"; //to keep the old behavior + else + className = "(" + await GetTypeName(sessionId, typeId, token) + ")"; + + int pointerId = 0; + if (valueAddress != 0 && className != "(void*)") + { + pointerId = Interlocked.Increment(ref debugger_object_id); + type = "object"; + value = className; + pointerValues[pointerId] = new PointerValue(valueAddress, typeId, name); + } + else + { + type = "symbol"; + value = className + " " + valueAddress; + } + return CreateJObject(value, type, value, false, className, $"dotnet:pointer:{pointerId}", "pointer"); + } + + public async Task CreateJObjectForString(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, CancellationToken token) + { + var string_id = ret_debugger_cmd_reader.ReadInt32(); + var value = await GetStringValue(sessionId, string_id, token); + return CreateJObject(value, "string", value, false); + } + + public async Task CreateJObjectForArray(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, CancellationToken token) + { + var objectId = ret_debugger_cmd_reader.ReadInt32(); + var value = await GetClassNameFromObject(sessionId, objectId, token); + var length = await GetArrayLength(sessionId, objectId, token); + return CreateJObject(null, "object", $"{value.ToString()}({length})", false, value.ToString(), "dotnet:array:" + objectId, null, "array"); + } + + public async Task CreateJObjectForObject(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, int typeIdFromAttribute, CancellationToken token) + { + var objectId = ret_debugger_cmd_reader.ReadInt32(); + var className = ""; + var type_id = await GetTypeIdFromObject(sessionId, objectId, false, token); + className = await GetTypeName(sessionId, type_id[0], token); + var description = className.ToString(); + if (await IsDelegate(sessionId, objectId, token)) + { + if (typeIdFromAttribute != -1) + { + className = await GetTypeName(sessionId, typeIdFromAttribute, token); + } + + description = await GetDelegateMethodDescription(sessionId, objectId, token); + if (description == "") + { + return CreateJObject(className.ToString(), "symbol", className.ToString(), false); + } + } + return CreateJObject(null, "object", description, false, className, $"dotnet:object:{objectId}"); + } + + public async Task CreateJObjectForValueType(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, string name, long initialPos, CancellationToken token) + { + JObject fieldValueType = null; + var isEnum = ret_debugger_cmd_reader.ReadByte(); + var isBoxed = ret_debugger_cmd_reader.ReadByte() == 1; + var typeId = ret_debugger_cmd_reader.ReadInt32(); + var className = await GetTypeName(sessionId, typeId, token); + var description = className; + var numFields = ret_debugger_cmd_reader.ReadInt32(); + var fields = await GetTypeFields(sessionId, typeId, token); + JArray valueTypeFields = new JArray(); + if (className.IndexOf("System.Nullable<") == 0) //should we call something on debugger-agent to check??? + { + ret_debugger_cmd_reader.ReadByte(); //ignoring the boolean type + var isNull = ret_debugger_cmd_reader.ReadInt32(); + var value = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, name, false, -1, token); + if (isNull != 0) + return value; + else + return CreateJObject(null, "object", className, false, className, null, null, "null", true); + } + for (int i = 0; i < numFields ; i++) + { + fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, true, fields.ElementAt(i).TypeId, token); + valueTypeFields.Add(fieldValueType); + } + + long endPos = ret_debugger_cmd_reader.BaseStream.Position; + var valueTypeId = Interlocked.Increment(ref debugger_object_id); + + ret_debugger_cmd_reader.BaseStream.Position = initialPos; + byte[] valueTypeBuffer = new byte[endPos - initialPos]; + ret_debugger_cmd_reader.Read(valueTypeBuffer, 0, (int)(endPos - initialPos)); + ret_debugger_cmd_reader.BaseStream.Position = endPos; + valueTypes[valueTypeId] = new ValueTypeClass(name, valueTypeBuffer, valueTypeFields, typeId, AutoExpandable(className), valueTypeId); + if (AutoInvokeToString(className) || isEnum == 1) { + int method_id = await GetMethodIdByName(sessionId, typeId, "ToString", token); + var retMethod = await InvokeMethod(sessionId, valueTypeBuffer, method_id, "methodRet", token); + description = retMethod["value"]?["value"].Value(); + if (className.Equals("System.Guid")) + description = description.ToUpper(); //to keep the old behavior + } + else if (isBoxed && numFields == 1) { + return fieldValueType; + } + return CreateJObject(null, "object", description, false, className, $"dotnet:valuetype:{valueTypeId}", null, null, true, true, isEnum == 1); + } + + public async Task CreateJObjectForNull(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, CancellationToken token) + { + string className = ""; + ElementType variableType = (ElementType)ret_debugger_cmd_reader.ReadByte(); + switch (variableType) + { + case ElementType.String: + case ElementType.Class: + { + var type_id = ret_debugger_cmd_reader.ReadInt32(); + className = await GetTypeName(sessionId, type_id, token); + break; + + } + case ElementType.SzArray: + case ElementType.Array: + { + ElementType byte_type = (ElementType)ret_debugger_cmd_reader.ReadByte(); + var rank = ret_debugger_cmd_reader.ReadInt32(); + if (byte_type == ElementType.Class) { + var internal_type_id = ret_debugger_cmd_reader.ReadInt32(); + } + var type_id = ret_debugger_cmd_reader.ReadInt32(); + className = await GetTypeName(sessionId, type_id, token); + break; + } + default: + { + var type_id = ret_debugger_cmd_reader.ReadInt32(); + className = await GetTypeName(sessionId, type_id, token); + break; + } + } + return CreateJObject(null, "object", className, false, className, null, null, "null"); + } + public async Task CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader ret_debugger_cmd_reader, string name, bool isOwn, int typeIdFromAttribute, CancellationToken token) { long initialPos = ret_debugger_cmd_reader == null ? 0 : ret_debugger_cmd_reader.BaseStream.Position; ElementType etype = (ElementType)ret_debugger_cmd_reader.ReadByte(); - JObject fieldValueType = null; JObject ret = null; switch (etype) { + case ElementType.I: + case ElementType.U: case ElementType.Void: + case (ElementType)ValueTypeId.Type: + case (ElementType)ValueTypeId.VType: + case (ElementType)ValueTypeId.FixedArray: ret = new JObject{{"Type", "void"}}; break; case ElementType.Boolean: { var value = ret_debugger_cmd_reader.ReadInt32(); - ret = JObject.FromObject(new { - value = new - { - type = "boolean", - value = value == 0 ? false : true, - description = value == 0 ? "false" : "true" - }, - writable = true, - name - }); + ret = CreateJObjectForBoolean(value); break; } case ElementType.I1: { var value = ret_debugger_cmd_reader.ReadSByte(); - return JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); + break; } case ElementType.I2: case ElementType.I4: { var value = ret_debugger_cmd_reader.ReadInt32(); - ret = JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); break; } case ElementType.U1: { var value = ret_debugger_cmd_reader.ReadUByte(); - ret = JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); break; } case ElementType.U2: { var value = ret_debugger_cmd_reader.ReadUShort(); - ret = JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); break; } case ElementType.U4: { var value = ret_debugger_cmd_reader.ReadUInt32(); - ret = JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); break; } case ElementType.R4: { float value = BitConverter.Int32BitsToSingle(ret_debugger_cmd_reader.ReadInt32()); - return JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); + break; } case ElementType.Char: { var value = ret_debugger_cmd_reader.ReadInt32(); - var description = $"{value.ToString()} '{Convert.ToChar(value)}'"; - ret = JObject.FromObject(new { - value = new - { - type = "symbol", - value = description, - description - }, - writable = true, - name - }); + ret = CreateJObjectForChar(value); break; } case ElementType.I8: { long value = ret_debugger_cmd_reader.ReadLong(); - return JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); + break; } case ElementType.U8: { ulong high = (ulong) ret_debugger_cmd_reader.ReadInt32(); ulong low = (ulong) ret_debugger_cmd_reader.ReadInt32(); var value = ((high << 32) | low); - ret = JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); break; } case ElementType.R8: { double value = ret_debugger_cmd_reader.ReadDouble(); - ret = JObject.FromObject(new { - value = new - { - type = "number", - value, - description = value.ToString() - }, - writable = true, - name - }); + ret = CreateJObjectForNumber(value); break; } - case ElementType.I: - case ElementType.U: - // FIXME: The client and the debuggee might have different word sizes - ret = new JObject{{"Type", "void"}}; - break; case ElementType.FnPtr: case ElementType.Ptr: { - string type; - string value; - long valueAddress = ret_debugger_cmd_reader.ReadLong(); - var typeId = ret_debugger_cmd_reader.ReadInt32(); - var className = ""; - if (etype == ElementType.FnPtr) - className = "(*())"; //to keep the old behavior - else - className = "(" + await GetTypeName(sessionId, typeId, token) + ")"; - - int pointerId = 0; - if (valueAddress != 0 && className != "(void*)") - { - pointerId = Interlocked.Increment(ref debugger_object_id); - type = "object"; - value = className; - pointerValues[pointerId] = new PointerValue(valueAddress, typeId, name); - } - else - { - type = "symbol"; - value = className + " " + valueAddress; - } - ret = JObject.FromObject(new { - value = new - { - type, - __custom_type = "pointer", - value = value, - description = value, - className, - objectId = $"dotnet:pointer:{pointerId}" - }, - writable = false, - name - }); + ret = await CreateJObjectForPtr(sessionId, etype, ret_debugger_cmd_reader, name, token); break; } case ElementType.String: { - var string_id = ret_debugger_cmd_reader.ReadInt32(); - var value = await GetStringValue(sessionId, string_id, token); - ret = JObject.FromObject(new { - value = new - { - type = "string", - value, - description = value.ToString() - }, - writable = false, - name - }); + ret = await CreateJObjectForString(sessionId, ret_debugger_cmd_reader, token); break; } case ElementType.SzArray: case ElementType.Array: { - var objectId = ret_debugger_cmd_reader.ReadInt32(); - var value = await GetClassNameFromObject(sessionId, objectId, token); - var length = await GetArrayLength(sessionId, objectId, token); - ret = JObject.FromObject(new { - value = new - { - type = "object", - objectId = "dotnet:array:" + objectId, - description = $"{value.ToString()}({length})", - className = value.ToString(), - subtype = "array" - }, - name - }); + ret = await CreateJObjectForArray(sessionId, ret_debugger_cmd_reader, token); break; } case ElementType.Class: case ElementType.Object: { - var objectId = ret_debugger_cmd_reader.ReadInt32(); - var className = ""; - var type_id = await GetTypeIdFromObject(sessionId, objectId, false, token); - className = await GetTypeName(sessionId, type_id[0], token); - var description = className.ToString(); - if (await IsDelegate(sessionId, objectId, token)) - { - if (typeIdFromAttribute != -1) - { - className = await GetTypeName(sessionId, typeIdFromAttribute, token); - } - - description = await GetDelegateMethodDescription(sessionId, objectId, token); - if (description == "") - { - ret = JObject.FromObject(new { - value = new - { - type = "symbol", - description = className.ToString(), - value = className.ToString() - }, - name - }); - break; - } - } - ret = JObject.FromObject(new { - value = new - { - type = "object", - objectId = $"dotnet:object:{objectId}", //maybe pass here the typeId and avoid another call to debugger-agent when getting fields - description, - className, - }, - name - }); + ret = await CreateJObjectForObject(sessionId, ret_debugger_cmd_reader, typeIdFromAttribute, token); break; } case ElementType.ValueType: { - var isEnum = ret_debugger_cmd_reader.ReadByte(); - var isBoxed = ret_debugger_cmd_reader.ReadByte() == 1; - var typeId = ret_debugger_cmd_reader.ReadInt32(); - var className = await GetTypeName(sessionId, typeId, token); - var description = className; - var numFields = ret_debugger_cmd_reader.ReadInt32(); - var fields = await GetTypeFields(sessionId, typeId, token); - JArray valueTypeFields = new JArray(); - if (className.IndexOf("System.Nullable<") == 0) //should we call something on debugger-agent to check??? - { - ret_debugger_cmd_reader.ReadByte(); //ignoring the boolean type - var isNull = ret_debugger_cmd_reader.ReadInt32(); - var value = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, name, false, -1, token); - if (isNull != 0) - ret = value; - else - ret = JObject.FromObject(new { - value = new - { - type = "object", - subtype = "null", - isValueType = true, - className, - description = className - }, - name - }); - break; - } - for (int i = 0; i < numFields ; i++) - { - fieldValueType = await CreateJObjectForVariableValue(sessionId, ret_debugger_cmd_reader, fields.ElementAt(i).Name, true, fields.ElementAt(i).TypeId, token); - valueTypeFields.Add(fieldValueType); - } - - long endPos = ret_debugger_cmd_reader.BaseStream.Position; - var valueTypeId = Interlocked.Increment(ref debugger_object_id); - - ret_debugger_cmd_reader.BaseStream.Position = initialPos; - byte[] valueTypeBuffer = new byte[endPos - initialPos]; - ret_debugger_cmd_reader.Read(valueTypeBuffer, 0, (int)(endPos - initialPos)); - ret_debugger_cmd_reader.BaseStream.Position = endPos; - valueTypes[valueTypeId] = new ValueTypeClass(name, valueTypeBuffer, valueTypeFields, typeId, AutoExpandable(className), valueTypeId); - if (AutoInvokeToString(className) || isEnum == 1) { - int method_id = await GetMethodIdByName(sessionId, typeId, "ToString", token); - var retMethod = await InvokeMethod(sessionId, valueTypeBuffer, method_id, "methodRet", token); - description = retMethod["value"]?["value"].Value(); - if (className.Equals("System.Guid")) - description = description.ToUpper(); //to keep the old behavior - } - else if (isBoxed && numFields == 1) { - fieldValueType["name"] = name; - ret = fieldValueType; - break; - } - - ret = JObject.FromObject(new { - value = new - { - type = "object", - objectId = "dotnet:valuetype:" + valueTypeId, - description, - className, - expanded = true, - isValueType = true, - isEnum = isEnum == 1 ? true : false - }, - name - }); + ret = await CreateJObjectForValueType(sessionId, ret_debugger_cmd_reader, name, initialPos, token); break; } case (ElementType)ValueTypeId.Null: { - string className = ""; - ElementType variableType = (ElementType)ret_debugger_cmd_reader.ReadByte(); - switch (variableType) - { - case ElementType.String: - case ElementType.Class: - { - var type_id = ret_debugger_cmd_reader.ReadInt32(); - className = await GetTypeName(sessionId, type_id, token); - break; - } - case ElementType.SzArray: - case ElementType.Array: - { - ElementType byte_type = (ElementType)ret_debugger_cmd_reader.ReadByte(); - var rank = ret_debugger_cmd_reader.ReadInt32(); - if (byte_type == ElementType.Class) { - var internal_type_id = ret_debugger_cmd_reader.ReadInt32(); - } - var type_id = ret_debugger_cmd_reader.ReadInt32(); - className = await GetTypeName(sessionId, type_id, token); - break; - } - default: - { - var type_id = ret_debugger_cmd_reader.ReadInt32(); - className = await GetTypeName(sessionId, type_id, token); - break; - } - } - ret = JObject.FromObject(new { - value = new - { - type = "object", - subtype = "null", - className, - description = className - }, - name - }); - break; - } - case (ElementType)ValueTypeId.Type: - { - ret = new JObject{{"Type", "void"}}; - break; - } - case (ElementType)ValueTypeId.VType: - { - ret = new JObject{{"Type", "void"}}; - break; - } - case (ElementType)ValueTypeId.FixedArray: - { - ret = new JObject{{"Type", "void"}}; + ret = await CreateJObjectForNull(sessionId, ret_debugger_cmd_reader, token); break; } } if (isOwn) ret["isOwn"] = true; + ret["name"] = name; return ret; } From 62b15f88285b134fb5533f862cda1085362db4c6 Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 14 Jun 2021 16:07:54 -0300 Subject: [PATCH 43/48] Changing what @lewing suggested. --- .../MemberReferenceResolver.cs | 6 ++-- .../debugger/BrowserDebugProxy/MonoProxy.cs | 31 ++++++++++++------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 50f9e2233b380..70dd415e9baff 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -81,8 +81,7 @@ public async Task Resolve(string var_name, CancellationToken token) return null; if (DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId objectId)) { - var root_res = await proxy.RuntimeGetProperties(sessionId, objectId, null, token); - var root_res_obj = root_res.Value?["result"]; + var root_res_obj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == partTrimmed); if (objRet != null) { @@ -114,8 +113,7 @@ public async Task Resolve(string var_name, CancellationToken token) } else if (DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value(), out DotnetObjectId objectId)) { - var root_res = await proxy.RuntimeGetProperties(sessionId, objectId, null, token); - var root_res_obj = root_res.Value?["result"]; + var root_res_obj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == partTrimmed); if (objRet != null) { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index b46038934838c..5b61c4cd05785 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -376,8 +376,12 @@ protected override async Task AcceptCommand(MessageId id, string method, J if (!DotnetObjectId.TryParse(args?["objectId"], out DotnetObjectId objectId)) break; - Result result = await RuntimeGetProperties(id, objectId, args, token); - SendResponse(id, result, token); + var ret = await RuntimeGetPropertiesInternal(id, objectId, args, token); + if (ret == null) { + SendResponse(id, Result.Err($"Unable to RuntimeGetProperties '{objectId}'"), token); + } + else + SendResponse(id, Result.OkFromObject(new { result = ret }), token); return true; } @@ -559,7 +563,7 @@ private async Task OnSetVariableValue(MessageId id, int scopeId, string va return true; } - internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId objectId, JToken args, CancellationToken token) + internal async Task RuntimeGetPropertiesInternal(SessionId id, DotnetObjectId objectId, JToken args, CancellationToken token) { var accessorPropertiesOnly = false; var ownProperties = false; @@ -575,28 +579,31 @@ internal async Task RuntimeGetProperties(SessionId id, DotnetObjectId ob switch (objectId.Scheme) { case "scope": - return await GetScopeProperties(id, int.Parse(objectId.Value), token); + { + var res = await GetScopeProperties(id, int.Parse(objectId.Value), token); + return res.Value?["result"]; + } case "valuetype": - return Result.OkFromObject(new { result = await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), accessorPropertiesOnly, token)}); + return await sdbHelper.GetValueTypeValues(id, int.Parse(objectId.Value), accessorPropertiesOnly, token); case "array": - return Result.OkFromObject(new { result = await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token)}); + return await sdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); case "object": - return Result.OkFromObject(new { result = await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, false, accessorPropertiesOnly, ownProperties, token) }); + return await sdbHelper.GetObjectValues(id, int.Parse(objectId.Value), true, false, accessorPropertiesOnly, ownProperties, token); case "pointer": - return Result.OkFromObject(new { result = new JArray{await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token)}}); + return new JArray{await sdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token)}; case "cfo_res": { Result res = await SendMonoCommand(id, MonoCommands.GetDetails(int.Parse(objectId.Value), args), token); string value_json_str = res.Value["result"]?["value"]?["__value_as_json_string__"]?.Value(); - return Result.OkFromObject(new { result = value_json_str != null ? (object) JArray.Parse(value_json_str) : new {} }); + return value_json_str != null ? JArray.Parse(value_json_str) : null; } default: - return Result.Err($"Unable to RuntimeGetProperties '{objectId}'"); + return null; } } - catch (Exception e) { - return Result.Err($"Unable to RuntimeGetProperties '{objectId}' - {e}"); + catch (Exception) { + return null; } } From f797f9ebd3929afa04951a39a0453e3757420498 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Thu, 17 Jun 2021 00:01:02 -0300 Subject: [PATCH 44/48] Apply suggestions from code review Co-authored-by: Larry Ewing --- .../BrowserDebugProxy/MemberReferenceResolver.cs | 10 +++------- .../wasm/debugger/DebuggerTestSuite/SteppingTests.cs | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 70dd415e9baff..c4e578a0a2c92 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -83,14 +83,10 @@ public async Task Resolve(string var_name, CancellationToken token) { var root_res_obj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); var objRet = root_res_obj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == partTrimmed); - if (objRet != null) - { - rootObject = await GetValueFromObject(objRet, token); - } - else - { + if (objRet == null) return null; - } + + rootObject = await GetValueFromObject(objRet, token); } continue; } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs index 643aa5c1e46fa..eed238c6f5902 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs @@ -42,7 +42,7 @@ await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", } [Fact] - public async Task InspectLocalsDuringStepping2() + public async Task InspectLocalsDuringStepping() { var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs"; await SetBreakpoint(debugger_test_loc, 10, 8); @@ -251,7 +251,7 @@ await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", } [Fact] - public async Task InspectLocalsDuringSteppingIn2() + public async Task InspectLocalsDuringSteppingIn() { await SetBreakpoint("dotnet://debugger-test.dll/debugger-test.cs", 86, 8); From 5b2994da8d5b033a93c6e3818a8c54f880c6e18a Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Thu, 17 Jun 2021 00:01:48 -0300 Subject: [PATCH 45/48] Update src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs Co-authored-by: Larry Ewing --- src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 5b61c4cd05785..689904740d3d6 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -779,9 +779,6 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec return false; ExecutionContext context = GetContext(sessionId); - if (res.IsErr) { - return false; - } byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value()); var ret_debugger_cmd = new MemoryStream(newBytes); var ret_debugger_cmd_reader = new MonoBinaryReader(ret_debugger_cmd); From d4f1d8791b1beb30c9b2fc4e0b0c6c6b10a0d873 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Thu, 17 Jun 2021 00:02:20 -0300 Subject: [PATCH 46/48] Update src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs Co-authored-by: Larry Ewing --- .../BrowserDebugProxy/MonoSDBHelper.cs | 34 ++++--------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 4bed43bb5469a..745a653f1d867 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -573,9 +573,8 @@ internal async Task SendDebuggerAgentCommandInternal(SessionId return ret_debugger_cmd_reader; } - internal Task SendDebuggerAgentCommand(SessionId sessionId, T command, MemoryStream parms, CancellationToken token) where T : Enum - { - CommandSet set = command switch { + CommandSet GetCommandSetForCommand(T Command) => + command switch { CmdVM => CommandSet.Vm, CmdObject => CommandSet.ObjectRef, CmdString => CommandSet.StringRef, @@ -593,31 +592,12 @@ internal Task SendDebuggerAgentCommand(SessionId sessionId, CmdPointer => CommandSet.Pointer, _ => throw new Exception ("Unknown CommandSet") }; - return SendDebuggerAgentCommandInternal(sessionId, (int)set, (int)(object)command, parms, token); - } - internal Task SendDebuggerAgentCommandWithParms(SessionId sessionId, T command, MemoryStream parms, int type, string extraParm, CancellationToken token) where T : Enum - { - CommandSet set = command switch { - CmdVM => CommandSet.Vm, - CmdObject => CommandSet.ObjectRef, - CmdString => CommandSet.StringRef, - CmdThread => CommandSet.Thread, - CmdArray => CommandSet.ArrayRef, - CmdEventRequest => CommandSet.EventRequest, - CmdFrame => CommandSet.StackFrame, - CmdAppDomain => CommandSet.AppDomain, - CmdAssembly => CommandSet.Assembly, - CmdMethod => CommandSet.Method, - CmdType => CommandSet.Type, - CmdModule => CommandSet.Module, - CmdField => CommandSet.Field, - CmdEvent => CommandSet.Event, - CmdPointer => CommandSet.Pointer, - _ => throw new Exception ("Unknown CommandSet") - }; - return SendDebuggerAgentCommandWithParmsInternal(sessionId, (int)set, (int)(object)command, parms, type, extraParm, token); - } + internal Task SendDebuggerAgentCommand(SessionId sessionId, T command, MemoryStream parms, CancellationToken token) where T : Enum => + SendDebuggerAgentCommandInternal(sessionId, (int)GetCommandSetForCommand(command), (int)(object)command, parms, token); + + internal Task SendDebuggerAgentCommandWithParms(SessionId sessionId, T command, MemoryStream parms, int type, string extraParm, CancellationToken token) where T : Enum => + SendDebuggerAgentCommandWithParmsInternal(sessionId, (int)GetCommandSetForCommand(command), (int)(object)command, parms, type, extraParm, token); internal async Task SendDebuggerAgentCommandWithParmsInternal(SessionId sessionId, int command_set, int command, MemoryStream parms, int type, string extraParm, CancellationToken token) { From 6645cc5360dde5c0c3d8ad5fba401b4467f84f1d Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 17 Jun 2021 00:05:37 -0300 Subject: [PATCH 47/48] Fixing @lewing changes. --- src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 745a653f1d867..c296c8501473a 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -573,7 +573,7 @@ internal async Task SendDebuggerAgentCommandInternal(SessionId return ret_debugger_cmd_reader; } - CommandSet GetCommandSetForCommand(T Command) => + internal CommandSet GetCommandSetForCommand(T command) => command switch { CmdVM => CommandSet.Vm, CmdObject => CommandSet.ObjectRef, From a61f75e688ab53d369b145c0ab054f8f770e9ad3 Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 17 Jun 2021 12:54:16 -0300 Subject: [PATCH 48/48] Trying to fix CI. --- src/mono/mono/mini/debugger-agent.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 9380b1041b40b..33b4586f2b280 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -370,9 +370,10 @@ static gboolean buffer_replies; #ifndef TARGET_WASM #define GET_TLS_DATA_FROM_THREAD(thread) \ - DebuggerTlsData *tls; \ + DebuggerTlsData *tls = NULL; \ mono_loader_lock(); \ - tls = (DebuggerTlsData*)mono_g_hash_table_lookup(thread_to_tls, thread); \ + if (thread_to_tls != NULL) \ + tls = (DebuggerTlsData*)mono_g_hash_table_lookup(thread_to_tls, thread); \ mono_loader_unlock(); #define GET_DEBUGGER_TLS() \ DebuggerTlsData *tls; \