From 45aa2063a43edb476a4e35433a714eb1802c0468 Mon Sep 17 00:00:00 2001 From: Thays Date: Thu, 1 Jul 2021 17:58:42 -0300 Subject: [PATCH 01/11] Add test case for debug after hot reload. --- .../DebuggerTestSuite/BreakpointTests.cs | 18 +++++ .../DebuggerTestSuite/DebuggerTestBase.cs | 49 ++++++++++++ .../ApplyUpdateReferencedAssembly.csproj | 31 ++++++++ .../MethodBody1.cs | 18 +++++ .../MethodBody1_v1.cs | 18 +++++ .../MethodBody1_v2.cs | 17 +++++ .../deltascript.json | 7 ++ .../tests/debugger-test/debugger-test.cs | 75 +++++++++++++++++++ .../tests/debugger-test/debugger-test.csproj | 25 +++++++ .../tests/debugger-test/runtime-debugger.js | 6 +- 10 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/ApplyUpdateReferencedAssembly.csproj create mode 100644 src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs create mode 100644 src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs create mode 100644 src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs create mode 100644 src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/deltascript.json diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs index a4f53aac02b31..b2ba925ebf633 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs @@ -287,5 +287,23 @@ await LoadAssemblyDynamically( CheckNumber(locals, "b", 10); } + [Fact] + public async Task DebugLazyLoadedAssemblyWithHotReload() + { + var pause_location = await LoadAssemblyAndTestHotReload( + Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"), + Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"), + Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll")); + /*var source_location = "dotnet://lazy-debugger-test-embedded.dll/lazy-debugger-test-embedded.cs"; + Assert.Contains(source_location, scripts.Values);*/ + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + //Console.WriteLine(pause_location); + CheckNumber(locals, "a", 10); + Console.WriteLine(pause_location["callFrames"][0]); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", null, 0, 0, null); + Console.WriteLine(pause_location["callFrames"][0]); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", null, 0, 0, null); + Console.WriteLine(pause_location["callFrames"][0]); + } } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index a6af28d8e4592..371dde8b7abf0 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -1040,6 +1040,55 @@ internal async Task LoadAssemblyDynamicallyALCAndRunMethod(string asm_f await cli.SendCommand("Runtime.evaluate", run_method, token); return await insp.WaitFor(Inspector.PAUSE); } + + internal async Task LoadAssemblyAndTestHotReload(string asm_file, string pdb_file, string asm_file_hot_reload) + { + // Simulate loading an assembly into the framework + byte[] bytes = File.ReadAllBytes(asm_file); + string asm_base64 = Convert.ToBase64String(bytes); + bytes = File.ReadAllBytes(pdb_file); + string pdb_base64 = Convert.ToBase64String(bytes); + + bytes = File.ReadAllBytes($"{asm_file_hot_reload}.1.dmeta"); + string dmeta1 = Convert.ToBase64String(bytes); + + bytes = File.ReadAllBytes($"{asm_file_hot_reload}.1.dil"); + string dil1 = Convert.ToBase64String(bytes); + + bytes = File.ReadAllBytes($"{asm_file_hot_reload}.1.dpdb"); + string dpdb1 = Convert.ToBase64String(bytes); + + + bytes = File.ReadAllBytes($"{asm_file_hot_reload}.2.dmeta"); + string dmeta2 = Convert.ToBase64String(bytes); + + bytes = File.ReadAllBytes($"{asm_file_hot_reload}.2.dil"); + string dil2 = Convert.ToBase64String(bytes); + + bytes = File.ReadAllBytes($"{asm_file_hot_reload}.2.dpdb"); + string dpdb2 = Convert.ToBase64String(bytes); + + string expression = $"let asm_b64 = '{asm_base64}'; let pdb_b64 = '{pdb_base64}';"; + expression = $"{expression} let dmeta1 = '{dmeta1}'; let dil1 = '{dil1}'; let dpdb1 = '{dpdb1}';"; + expression = $"{expression} let dmeta2 = '{dmeta2}'; let dil2 = '{dil2}'; let dpdb2 = '{dpdb2}';"; + expression = $"{{ {expression} invoke_static_method('[debugger-test] TestHotReload:LoadLazyHotReload', asm_b64, pdb_b64, dmeta1, dil1, dpdb1, dmeta2, dil2, dpdb2); }}"; + var load_assemblies = JObject.FromObject(new + { + expression + }); + + Result load_assemblies_res = await cli.SendCommand("Runtime.evaluate", load_assemblies, token); + + Assert.True(load_assemblies_res.IsOk); + Thread.Sleep(1000); + var run_method = JObject.FromObject(new + { + expression = "window.setTimeout(function() { invoke_static_method('[debugger-test] TestHotReload:RunMethod'); }, 1);" + }); + + await cli.SendCommand("Runtime.evaluate", run_method, token); + return await insp.WaitFor(Inspector.PAUSE); + } } class DotnetObjectId diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/ApplyUpdateReferencedAssembly.csproj b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/ApplyUpdateReferencedAssembly.csproj new file mode 100644 index 0000000000000..550971c8b6f31 --- /dev/null +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/ApplyUpdateReferencedAssembly.csproj @@ -0,0 +1,31 @@ + + + true + deltascript.json + library + false + true + + false + true + + false + false + false + + + + + + + + + + + diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs new file mode 100644 index 0000000000000..5ae994a8e716c --- /dev/null +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System; + +namespace ApplyUpdateReferencedAssembly +{ + public class MethodBody1 { + public static string StaticMethod1 () { + Console.WriteLine("original"); + int a = 10; + Debugger.Break(); + Console.WriteLine("passei do break"); + return "OLD STRING"; + } + } +} diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs new file mode 100644 index 0000000000000..8c02261b6f7f7 --- /dev/null +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System; + +namespace ApplyUpdateReferencedAssembly +{ + public class MethodBody1 { + public static string StaticMethod1 () { + Console.WriteLine("v1"); + double b = 15; + Debugger.Break(); + Console.WriteLine("passei v1"); + return "NEW STRING"; + } + } +} diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs new file mode 100644 index 0000000000000..d2e8b59374832 --- /dev/null +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; +using System; + +namespace ApplyUpdateReferencedAssembly +{ + public class MethodBody1 { + public static string StaticMethod1 () { + Console.WriteLine("v2"); + bool c = true; + Debugger.Break(); + Console.WriteLine("passei v2"); + return "NEWEST STRING"; + } + } +} diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/deltascript.json b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/deltascript.json new file mode 100644 index 0000000000000..8e738364bc747 --- /dev/null +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/deltascript.json @@ -0,0 +1,7 @@ +{ + "changes": [ + {"document": "MethodBody1.cs", "update": "MethodBody1_v1.cs"}, + {"document": "MethodBody1.cs", "update": "MethodBody1_v2.cs"}, + ] +} + diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 32177bbc0c5b0..e362d3582e62f 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -578,3 +578,78 @@ public static void RunMethodInALC(string type_name, string method_name) } } + public class TestHotReload { + static System.Reflection.Assembly loadedAssembly; + static byte[] dmeta_data1_bytes; + static byte[] dil_data1_bytes; + static byte[] dpdb_data1_bytes; + static byte[] dmeta_data2_bytes; + static byte[] dil_data2_bytes; + static byte[] dpdb_data2_bytes; + public static void LoadLazyHotReload(string asm_base64, string pdb_base64, string dmeta_data1, string dil_data1, string dpdb_data1, string dmeta_data2, string dil_data2, string dpdb_data2) + { + byte[] asm_bytes = Convert.FromBase64String(asm_base64); + byte[] pdb_bytes = Convert.FromBase64String(pdb_base64); + + dmeta_data1_bytes = Convert.FromBase64String(dmeta_data1); + dil_data1_bytes = Convert.FromBase64String(dil_data1); + dpdb_data1_bytes = Convert.FromBase64String(dpdb_data1); + + dmeta_data2_bytes = Convert.FromBase64String(dmeta_data2); + dil_data2_bytes = Convert.FromBase64String(dil_data2); + dpdb_data2_bytes = Convert.FromBase64String(dpdb_data2); + + + loadedAssembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(new System.IO.MemoryStream(asm_bytes), new System.IO.MemoryStream(pdb_bytes)); + Console.WriteLine($"Loaded - {loadedAssembly}"); + + } + public static void RunMethod() + { + var ty = typeof(System.Reflection.Metadata.AssemblyExtensions); + var mi = ty.GetMethod("GetApplyUpdateCapabilities", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static, Array.Empty()); + + if (mi == null) + return; + + var caps = mi.Invoke(null, null) as string; + + if (String.IsNullOrEmpty(caps)) + return; + + var myType = loadedAssembly.GetType("ApplyUpdateReferencedAssembly.MethodBody1"); + var myMethod = myType.GetMethod("StaticMethod1"); + myMethod.Invoke(null, null); + + ApplyUpdate(loadedAssembly, 1); + + myType = loadedAssembly.GetType("ApplyUpdateReferencedAssembly.MethodBody1"); + myMethod = myType.GetMethod("StaticMethod1"); + myMethod.Invoke(null, null); + + ApplyUpdate(loadedAssembly, 2); + + myType = loadedAssembly.GetType("ApplyUpdateReferencedAssembly.MethodBody1"); + myMethod = myType.GetMethod("StaticMethod1"); + myMethod.Invoke(null, null); + } + + internal static void ApplyUpdate (System.Reflection.Assembly assm, int version) + { + string basename = assm.Location; + if (basename == "") + basename = assm.GetName().Name + ".dll"; + Console.Error.WriteLine($"Apply Delta Update for {basename}, revision {version}"); + + if (version == 1) + { + System.Reflection.Metadata.AssemblyExtensions.ApplyUpdate(assm, dmeta_data1_bytes, dil_data1_bytes, dpdb_data1_bytes); + } + else if (version == 2) + { + System.Reflection.Metadata.AssemblyExtensions.ApplyUpdate(assm, dmeta_data2_bytes, dil_data2_bytes, dpdb_data2_bytes); + } + + } + } + diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj index 648dbcc64fc6d..ab5781f45f85d 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj @@ -18,6 +18,7 @@ + @@ -38,6 +39,30 @@ + + + + + + + + + + + + + + + diff --git a/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js b/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js index 8fb1e86211afe..191504d235f51 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js +++ b/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -var Module = { +var Module = { config: null, preInit: async function() { @@ -27,6 +27,10 @@ var Module = { MONO.mono_wasm_setenv ("MONO_LOG_LEVEL", "debug"); MONO.mono_wasm_setenv ("MONO_LOG_MASK", "all"); */ + + Module.config.environment_variables = { + "DOTNET_MODIFIABLE_ASSEMBLIES": "debug" + }; MONO.mono_load_runtime_and_bcl_args (Module.config) }, }; From 51649990e3a5468e03193ad5bfc60869498f8501 Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 6 Jul 2021 14:22:27 -0300 Subject: [PATCH 02/11] Implementing debug after hot reload, on runtime side, and on client side for wasm. --- src/mono/mono/component/debugger-agent.c | 59 +++++++++- src/mono/mono/component/debugger-agent.h | 2 +- src/mono/mono/component/debugger-protocol.h | 4 +- src/mono/mono/component/debugger-stub.c | 13 ++- src/mono/mono/component/debugger.h | 3 + src/mono/mono/component/hot_reload-stub.c | 14 ++- src/mono/mono/component/hot_reload.c | 109 +++++++++++++++-- src/mono/mono/component/hot_reload.h | 3 +- src/mono/mono/component/mini-wasm-debugger.c | 9 +- src/mono/mono/metadata/debug-mono-ppdb.c | 60 ++++++++++ src/mono/mono/metadata/debug-mono-ppdb.h | 3 + src/mono/mono/metadata/icall.c | 3 +- src/mono/mono/metadata/metadata-internals.h | 2 +- src/mono/mono/metadata/metadata-update.c | 13 ++- src/mono/mono/metadata/metadata-update.h | 3 + src/mono/mono/metadata/mono-debug.c | 8 +- src/mono/mono/mini/interp/transform.c | 3 +- .../debugger/BrowserDebugProxy/DebugStore.cs | 110 +++++++++++++++--- .../debugger/BrowserDebugProxy/MonoProxy.cs | 90 +++++++++++++- .../BrowserDebugProxy/MonoSDBHelper.cs | 21 +++- .../DebuggerTestSuite/BreakpointTests.cs | 60 ++++++++-- .../DebuggerTestSuite/DebuggerTestBase.cs | 4 +- .../MethodBody1.cs | 18 ++- .../MethodBody1_v1.cs | 22 +++- .../MethodBody1_v2.cs | 21 +++- .../tests/debugger-test/debugger-test.cs | 14 +-- .../tests/debugger-test/debugger-test.csproj | 3 +- 27 files changed, 595 insertions(+), 79 deletions(-) diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index f72c95392e974..e372d6ec29b85 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -307,6 +307,15 @@ typedef struct { MonoStackHash *hashes; } EventInfo; +typedef struct { + /* For EVENT_KIND_EXCEPTION */ + MonoImage *image; + gconstpointer meta_bytes; + int meta_len; + gconstpointer pdb_bytes; + int pdb_len; +} EnCInfo; + #ifdef HOST_WIN32 #define get_last_sock_error() WSAGetLastError() #define MONO_EWOULDBLOCK WSAEWOULDBLOCK @@ -1604,7 +1613,7 @@ static MonoGHashTable *suspended_objs; #ifdef TARGET_WASM void -mono_init_debugger_agent_for_wasm (int log_level_parm) +mono_init_debugger_agent_for_wasm (int log_level_parm, MonoProfilerHandle *prof) { if (mono_atomic_cas_i32 (&agent_inited, 1, 0) == 1) return; @@ -1615,6 +1624,7 @@ 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); + pending_assembly_loads = g_ptr_array_new (); log_level = log_level_parm; event_requests = g_ptr_array_new (); @@ -1622,6 +1632,8 @@ mono_init_debugger_agent_for_wasm (int log_level_parm) transport = &transports [0]; memset(&debugger_wasm_thread, 0, sizeof(DebuggerTlsData)); agent_config.enabled = TRUE; + + mono_profiler_set_jit_done_callback (*prof, jit_done); } #endif @@ -3600,6 +3612,9 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx case EVENT_KIND_TYPE_LOAD: buffer_add_typeid (&buf, domain, (MonoClass *)arg); break; + case MDBGPROT_EVENT_KIND_METHOD_UPDATE: + buffer_add_methodid (&buf, domain, (MonoMethod *)arg); + break; case EVENT_KIND_BREAKPOINT: case EVENT_KIND_STEP: { GET_DEBUGGER_TLS(); @@ -3655,6 +3670,15 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx case EVENT_KIND_KEEPALIVE: suspend_policy = SUSPEND_POLICY_NONE; break; + + case MDBGPROT_EVENT_KIND_ENC_UPDATE: { + EnCInfo *ei = (EnCInfo *)arg; + buffer_add_moduleid (&buf, mono_domain_get (), ei->image); + m_dbgprot_buffer_add_byte_array (&buf, (uint8_t *) ei->meta_bytes, ei->meta_len); + m_dbgprot_buffer_add_byte_array (&buf, (uint8_t *) ei->pdb_bytes, ei->pdb_len); + break; + } + default: g_assert_not_reached (); } @@ -4060,6 +4084,9 @@ jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) send_type_load (method->klass); + if (m_class_get_image(method->klass)->has_updates) { + process_profiler_event (MDBGPROT_EVENT_KIND_METHOD_UPDATE, method); + } if (jinfo) mono_de_add_pending_breakpoints (method, jinfo); } @@ -6517,6 +6544,28 @@ get_types_for_source_file (gpointer key, gpointer value, gpointer user_data) } } +static void +send_enc_delta (MonoImage *image, gconstpointer dmeta_bytes, int32_t dmeta_len, gconstpointer dpdb_bytes, int32_t dpdb_len) +{ + //TODO: if it came from debugger we don't need to pass the parameters back, they are already on debugger client side. + if (agent_config.enabled) { + int suspend_policy; + GSList *events; + mono_loader_lock (); + events = create_event_list (MDBGPROT_EVENT_KIND_ENC_UPDATE, NULL, NULL, NULL, &suspend_policy); + mono_loader_unlock (); + + EnCInfo info; + info.image = image; + info.meta_bytes = dpdb_bytes; + info.meta_len = dpdb_len; + info.pdb_bytes = dpdb_bytes; + info.pdb_len = dpdb_len; + + process_event (MDBGPROT_EVENT_KIND_ENC_UPDATE, &info, 0, NULL, events, suspend_policy); + } +} + static gboolean module_apply_changes (MonoImage *image, MonoArray *dmeta, MonoArray *dil, MonoArray *dpdb, MonoError *error) { @@ -6525,9 +6574,9 @@ module_apply_changes (MonoImage *image, MonoArray *dmeta, MonoArray *dil, MonoAr int32_t dmeta_len = mono_array_length_internal (dmeta); gpointer dil_bytes = (gpointer)mono_array_addr_internal (dil, char, 0); int32_t dil_len = mono_array_length_internal (dil); - gpointer dpdb_bytes G_GNUC_UNUSED = !dpdb ? NULL : (gpointer)mono_array_addr_internal (dpdb, char, 0); - int32_t dpdb_len G_GNUC_UNUSED = !dpdb ? 0 : mono_array_length_internal (dpdb); - mono_image_load_enc_delta (image, dmeta_bytes, dmeta_len, dil_bytes, dil_len, error); + gpointer dpdb_bytes = !dpdb ? NULL : (gpointer)mono_array_addr_internal (dpdb, char, 0); + int32_t dpdb_len = !dpdb ? 0 : mono_array_length_internal (dpdb); + mono_image_load_enc_delta (image, dmeta_bytes, dmeta_len, dil_bytes, dil_len, dpdb_bytes, dpdb_len, error); return is_ok (error); } @@ -7239,6 +7288,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf) req->info = mono_de_set_breakpoint (NULL, METHOD_EXIT_IL_OFFSET, req, NULL); } else if (req->event_kind == EVENT_KIND_EXCEPTION) { } else if (req->event_kind == EVENT_KIND_TYPE_LOAD) { + } else if (req->event_kind == MDBGPROT_EVENT_KIND_METHOD_UPDATE) { } else { if (req->nmodifiers) { g_free (req); @@ -10278,6 +10328,7 @@ debugger_agent_add_function_pointers(MonoComponentDebugger* fn_table) fn_table->debug_log_is_enabled = debugger_agent_debug_log_is_enabled; fn_table->send_crash = mono_debugger_agent_send_crash; fn_table->transport_handshake = debugger_agent_transport_handshake; + fn_table->send_enc_delta = send_enc_delta; } diff --git a/src/mono/mono/component/debugger-agent.h b/src/mono/mono/component/debugger-agent.h index 60f4244820247..ad5a0cb1d0b1d 100644 --- a/src/mono/mono/component/debugger-agent.h +++ b/src/mono/mono/component/debugger-agent.h @@ -23,7 +23,7 @@ DebuggerTlsData* mono_wasm_get_tls (void); void -mono_init_debugger_agent_for_wasm (int log_level); +mono_init_debugger_agent_for_wasm (int log_level, MonoProfilerHandle *prof); void mono_wasm_save_thread_context (void); diff --git a/src/mono/mono/component/debugger-protocol.h b/src/mono/mono/component/debugger-protocol.h index 24e8a2e42c27e..292b723cc351b 100644 --- a/src/mono/mono/component/debugger-protocol.h +++ b/src/mono/mono/component/debugger-protocol.h @@ -294,7 +294,9 @@ typedef enum { MDBGPROT_EVENT_KIND_KEEPALIVE = 14, MDBGPROT_EVENT_KIND_USER_BREAK = 15, MDBGPROT_EVENT_KIND_USER_LOG = 16, - MDBGPROT_EVENT_KIND_CRASH = 17 + MDBGPROT_EVENT_KIND_CRASH = 17, + MDBGPROT_EVENT_KIND_ENC_UPDATE = 18, + MDBGPROT_EVENT_KIND_METHOD_UPDATE = 19, } MdbgProtEventKind; typedef enum { diff --git a/src/mono/mono/component/debugger-stub.c b/src/mono/mono/component/debugger-stub.c index 1c5467adadddd..3628c0fbc532a 100644 --- a/src/mono/mono/component/debugger-stub.c +++ b/src/mono/mono/component/debugger-stub.c @@ -66,6 +66,9 @@ stub_mono_wasm_breakpoint_hit (void); static void stub_mono_wasm_single_step_hit (void); +static void +stub_send_enc_delta (MonoImage *image, gconstpointer dmeta_bytes, int32_t dmeta_len, gconstpointer dpdb_bytes, int32_t dpdb_len); + static MonoComponentDebugger fn_table = { { MONO_COMPONENT_ITF_VERSION, &debugger_avaliable }, &stub_debugger_init, @@ -87,7 +90,10 @@ static MonoComponentDebugger fn_table = { //wasm &stub_mono_wasm_breakpoint_hit, - &stub_mono_wasm_single_step_hit + &stub_mono_wasm_single_step_hit, + + //HotReload + &stub_send_enc_delta, }; static bool @@ -201,3 +207,8 @@ static void stub_mono_wasm_single_step_hit (void) { } + +static void +stub_send_enc_delta (MonoImage *image, gconstpointer dmeta_bytes, int32_t dmeta_len, gconstpointer dpdb_bytes, int32_t dpdb_len) +{ +} diff --git a/src/mono/mono/component/debugger.h b/src/mono/mono/component/debugger.h index de50c5641137a..81ef259f3ebe1 100644 --- a/src/mono/mono/component/debugger.h +++ b/src/mono/mono/component/debugger.h @@ -194,6 +194,9 @@ typedef struct MonoComponentDebugger { void (*mono_wasm_breakpoint_hit) (void); void (*mono_wasm_single_step_hit) (void); + //HotReload + void (*send_enc_delta) (MonoImage *image, gconstpointer dmeta_bytes, int32_t dmeta_len, gconstpointer dpdb_bytes, int32_t dpdb_len); + } MonoComponentDebugger; diff --git a/src/mono/mono/component/hot_reload-stub.c b/src/mono/mono/component/hot_reload-stub.c index 718ce3e453a10..56dae5071b3e0 100644 --- a/src/mono/mono/component/hot_reload-stub.c +++ b/src/mono/mono/component/hot_reload-stub.c @@ -15,7 +15,7 @@ static bool hot_reload_stub_available (void); static void -hot_reload_stub_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error); +hot_reload_stub_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, gconstpointer dpdb_bytes_orig, uint32_t dpdb_length, MonoError *error); static MonoComponentHotReload * component_hot_reload_stub_init (void); @@ -59,6 +59,9 @@ hot_reload_stub_table_bounds_check (MonoImage *base_image, int table_index, int static gboolean hot_reload_stub_delta_heap_lookup (MonoImage *base_image, MetadataHeapGetterFunc get_heap, uint32_t orig_index, MonoImage **image_out, uint32_t *index_out); +static gpointer +hot_reload_stub_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx); + static MonoComponentHotReload fn_table = { { MONO_COMPONENT_ITF_VERSION, &hot_reload_stub_available }, &hot_reload_stub_set_fastpath_data, @@ -75,6 +78,7 @@ static MonoComponentHotReload fn_table = { &hot_reload_stub_get_updated_method_rva, &hot_reload_stub_table_bounds_check, &hot_reload_stub_delta_heap_lookup, + &hot_reload_stub_get_updated_method_ppdb }; static bool @@ -139,7 +143,7 @@ hot_reload_stub_relative_delta_index (MonoImage *image_dmeta, int token) } void -hot_reload_stub_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error) +hot_reload_stub_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, gconstpointer dpdb_bytes_orig, uint32_t dpdb_length, MonoError *error) { mono_error_set_not_supported (error, "Hot reload not supported in this runtime."); } @@ -172,6 +176,12 @@ hot_reload_stub_delta_heap_lookup (MonoImage *base_image, MetadataHeapGetterFunc g_assert_not_reached (); } +static gpointer +hot_reload_stub_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx) +{ + g_assert_not_reached (); +} + MONO_COMPONENT_EXPORT_ENTRYPOINT MonoComponentHotReload * mono_component_hot_reload_init (void) diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 0997e8f859c23..a0b6c14143aa2 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -53,7 +53,7 @@ static void hot_reload_effective_table_slow (const MonoTableInfo **t, int *idx); static void -hot_reload_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error); +hot_reload_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, gconstpointer dpdb_bytes_orig, uint32_t dpdb_length, MonoError *error); static int hot_reload_relative_delta_index (MonoImage *image_dmeta, int token); @@ -73,6 +73,9 @@ hot_reload_table_bounds_check (MonoImage *base_image, int table_index, int token static gboolean hot_reload_delta_heap_lookup (MonoImage *base_image, MetadataHeapGetterFunc get_heap, uint32_t orig_index, MonoImage **image_out, uint32_t *index_out); +static gpointer +hot_reload_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx); + static MonoComponentHotReload fn_table = { { MONO_COMPONENT_ITF_VERSION, &hot_reload_available }, &hot_reload_set_fastpath_data, @@ -89,6 +92,7 @@ static MonoComponentHotReload fn_table = { &hot_reload_get_updated_method_rva, &hot_reload_table_bounds_check, &hot_reload_delta_heap_lookup, + &hot_reload_get_updated_method_ppdb, }; MonoComponentHotReload * @@ -146,6 +150,9 @@ typedef struct _DeltaInfo { /* Maps MethodDef token indices to a pointer into the RVA of the delta IL */ GHashTable *method_table_update; + /* Maps MethodDef token indices to a pointer into the RVA of the delta PPDB */ + GHashTable *method_ppdb_table_update; + // for each table, the row in the EncMap table that has the first token for remapping it? uint32_t enc_recs [MONO_TABLE_NUM]; delta_row_count count [MONO_TABLE_NUM]; @@ -312,6 +319,8 @@ delta_info_destroy (DeltaInfo *dinfo) { if (dinfo->method_table_update) g_hash_table_destroy (dinfo->method_table_update); + if (dinfo->method_ppdb_table_update) + g_hash_table_destroy (dinfo->method_ppdb_table_update); g_free (dinfo); } @@ -1103,17 +1112,47 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, gconstpointer } static void -set_update_method (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, MonoImage *image_dmeta, DeltaInfo *delta_info, uint32_t token_index, const char* il_address) +set_update_method (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, MonoImage *image_dmeta, DeltaInfo *delta_info, uint32_t token_index, const char* il_address, const char* pdb_address) { mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "setting method 0x%08x in g=%d IL=%p", token_index, generation, (void*)il_address); /* FIXME: this is a race if other threads are doing a lookup. */ g_hash_table_insert (base_info->method_table_update, GUINT_TO_POINTER (token_index), GUINT_TO_POINTER (generation)); g_hash_table_insert (delta_info->method_table_update, GUINT_TO_POINTER (token_index), (gpointer) il_address); + g_hash_table_insert (delta_info->method_ppdb_table_update, GUINT_TO_POINTER (token_index), (gpointer) pdb_address); +} + +static const char * +hot_reload_get_method_debug_information (MonoImage *image_dppdb, int idx) +{ + MonoTableInfo *table_encmap = &image_dppdb->tables [MONO_TABLE_ENCMAP]; + int rows = table_info_get_rows (table_encmap); + for (int i = 0; i < rows ; ++i) { + guint32 cols [MONO_ENCMAP_SIZE]; + mono_metadata_decode_row (table_encmap, i, cols, MONO_ENCMAP_SIZE); + int map_token = cols [MONO_ENCMAP_TOKEN]; + int token_table = mono_metadata_token_table (map_token); + if (token_table != MONO_TABLE_METHODBODY) + continue; + int token_index = mono_metadata_token_index (map_token); + if (token_index == idx) + { + guint32 cols [MONO_METHODBODY_SIZE]; + MonoTableInfo *methodbody_table = &image_dppdb->tables [MONO_TABLE_METHODBODY]; + mono_metadata_decode_row (methodbody_table, i, cols, MONO_METHODBODY_SIZE); + if (!cols [MONO_METHODBODY_SEQ_POINTS]) + return NULL; + + const char *ptr = mono_metadata_blob_heap (image_dppdb, cols [MONO_METHODBODY_SEQ_POINTS]); + return ptr; + } + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb encmap i=%d: token=0x%08x (table=%s): %d", i, map_token, mono_meta_table_name (token_table)); + } + return NULL; } /* do actuall enclog application */ static gboolean -apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, MonoImage *image_dmeta, DeltaInfo *delta_info, gconstpointer dil_data, uint32_t dil_length, MonoError *error) +apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, MonoImage *image_dmeta, MonoImage *image_dppdb, DeltaInfo *delta_info, gconstpointer dil_data, uint32_t dil_length, MonoError *error) { MonoTableInfo *table_enclog = &image_dmeta->tables [MONO_TABLE_ENCLOG]; int rows = table_info_get_rows (table_enclog); @@ -1184,12 +1223,16 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen base_info->method_table_update = g_hash_table_new (g_direct_hash, g_direct_equal); if (!delta_info->method_table_update) delta_info->method_table_update = g_hash_table_new (g_direct_hash, g_direct_equal); + if (!delta_info->method_ppdb_table_update) + + delta_info->method_ppdb_table_update = g_hash_table_new (g_direct_hash, g_direct_equal); int mapped_token = hot_reload_relative_delta_index (image_dmeta, mono_metadata_make_token (token_table, token_index)); int rva = mono_metadata_decode_row_col (&image_dmeta->tables [MONO_TABLE_METHOD], mapped_token - 1, MONO_METHOD_RVA); if (rva < dil_length) { char *il_address = ((char *) dil_data) + rva; - set_update_method (image_base, base_info, generation, image_dmeta, delta_info, token_index, il_address); + const char *method_debug_information = hot_reload_get_method_debug_information (image_dppdb, token_index); + set_update_method (image_base, base_info, generation, image_dmeta, delta_info, token_index, il_address, method_debug_information); } else { /* rva points probably into image_base IL stream. can this ever happen? */ g_print ("TODO: this case is still a bit contrived. token=0x%08x with rva=0x%04x\n", log_token, rva); @@ -1226,7 +1269,7 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen * LOCKING: Takes the publish_lock */ void -hot_reload_apply_changes (MonoImage *image_base, gconstpointer dmeta_bytes, uint32_t dmeta_length, gconstpointer dil_bytes_orig, uint32_t dil_length, MonoError *error) +hot_reload_apply_changes (MonoImage *image_base, gconstpointer dmeta_bytes, uint32_t dmeta_length, gconstpointer dil_bytes_orig, uint32_t dil_length, gconstpointer dpdb_bytes_orig, uint32_t dpdb_length, MonoError *error) { if (!assembly_update_supported (image_base->assembly)) { mono_error_set_invalid_operation (error, "The assembly can not be edited or changed."); @@ -1261,7 +1304,12 @@ hot_reload_apply_changes (MonoImage *image_base, gconstpointer dmeta_bytes, uint /* makes a copy of dil_bytes_orig */ gpointer dil_bytes = open_dil_data (image_base, dil_bytes_orig, dil_length); - /* TODO: make a copy of the dpdb bytes, once we consume them */ + + MonoImage *image_dpdb = image_open_dmeta_from_data (image_base, generation, dpdb_bytes_orig, dpdb_length); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image string size: 0x%08x", image_dpdb->heap_strings.size); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image user string size: 0x%08x", image_dpdb->heap_us.size); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image blob heap addr: %p", image_dpdb->heap_blob.data); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image blob heap size: 0x%08x", image_dpdb->heap_blob.size); BaselineInfo *base_info = baseline_info_lookup_or_add (image_base); @@ -1317,7 +1365,7 @@ hot_reload_apply_changes (MonoImage *image_base, gconstpointer dmeta_bytes, uint if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE)) dump_update_summary (image_base, image_dmeta); - if (!apply_enclog_pass2 (image_base, base_info, generation, image_dmeta, delta_info, dil_bytes, dil_length, error)) { + if (!apply_enclog_pass2 (image_base, base_info, generation, image_dmeta, image_dpdb, delta_info, dil_bytes, dil_length, error)) { mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "Error applying delta image to base=%s, due to: %s", basename, mono_error_get_message (error)); hot_reload_update_cancel (generation); return; @@ -1359,6 +1407,36 @@ metadata_update_count_updates (MonoImage *base) return metadata_update_local_generation (base, base_info, (MonoImage*)base_info->delta_image_last->data); } +static gpointer +get_method_ppdb_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint32_t idx) +{ + gpointer loc = NULL; + uint32_t cur = hot_reload_get_thread_generation (); + int generation = -1; + + /* Go through all the updates that the current thread can see and see + * if they updated the method. Keep the latest visible update */ + for (GList *ptr = base_info->delta_image; ptr != NULL; ptr = ptr->next) { + MonoImage *image_delta = (MonoImage*) ptr->data; + DeltaInfo *delta_info = delta_info_lookup (image_delta); + g_assert (delta_info); + if (delta_info->generation > cur) + break; + if (delta_info->method_ppdb_table_update) { + gpointer result = g_hash_table_lookup (delta_info->method_ppdb_table_update, GUINT_TO_POINTER (idx)); + /* if it's not in the table of a later generation, the + * later generation didn't modify the method + */ + if (result != NULL) { + loc = result; + generation = delta_info->generation; + } + } + } + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "method lookup idx=0x%08x returned gen=%d ppdb=%p", idx, generation, loc); + return loc; +} + static gpointer get_method_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint32_t idx) { @@ -1389,6 +1467,23 @@ get_method_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint32_t return loc; } +gpointer +hot_reload_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx) +{ + BaselineInfo *info = baseline_info_lookup (base_image); + if (!info) + return NULL; + gpointer loc = NULL; + /* EnC case */ + if (G_UNLIKELY (info->method_table_update)) { + uint32_t gen = GPOINTER_TO_UINT (g_hash_table_lookup (info->method_table_update, GUINT_TO_POINTER (idx))); + if (G_UNLIKELY (gen > 0)) { + loc = get_method_ppdb_update_rva (base_image, info, idx); + } + } + return loc; +} + gpointer hot_reload_get_updated_method_rva (MonoImage *base_image, uint32_t idx) { diff --git a/src/mono/mono/component/hot_reload.h b/src/mono/mono/component/hot_reload.h index 4994664103cc2..ad43badfc2f6a 100644 --- a/src/mono/mono/component/hot_reload.h +++ b/src/mono/mono/component/hot_reload.h @@ -23,12 +23,13 @@ typedef struct _MonoComponentHotReload { void (*cleanup_on_close) (MonoImage *image); void (*effective_table_slow) (const MonoTableInfo **t, int *idx); int (*relative_delta_index) (MonoImage *image_dmeta, int token); - void (*apply_changes) (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error); + void (*apply_changes) (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, gconstpointer dpdb_bytes_orig, uint32_t dpdb_length, MonoError *error); void (*image_close_except_pools_all) (MonoImage *base_image); void (*image_close_all) (MonoImage *base_image); gpointer (*get_updated_method_rva) (MonoImage *base_image, uint32_t idx); gboolean (*table_bounds_check) (MonoImage *base_image, int table_index, int token_index); gboolean (*delta_heap_lookup) (MonoImage *base_image, MetadataHeapGetterFunc get_heap, uint32_t orig_index, MonoImage **image_out, uint32_t *index_out); + gpointer (*get_updated_method_ppdb) (MonoImage *base_image, uint32_t idx); } MonoComponentHotReload; MONO_COMPONENT_EXPORT_ENTRYPOINT diff --git a/src/mono/mono/component/mini-wasm-debugger.c b/src/mono/mono/component/mini-wasm-debugger.c index 4df2172841efe..ef9d33c0df9cb 100644 --- a/src/mono/mono/component/mini-wasm-debugger.c +++ b/src/mono/mono/component/mini-wasm-debugger.c @@ -78,12 +78,6 @@ void wasm_debugger_log (int level, const gchar *format, ...) g_free (mesg); } -static void -jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) -{ - mono_de_add_pending_breakpoints (method, jinfo); -} - static void appdomain_load (MonoProfiler *prof, MonoDomain *domain) { @@ -186,7 +180,6 @@ mono_wasm_debugger_init (MonoDefaults *mono_defaults) get_mini_debug_options ()->load_aot_jit_info_eagerly = TRUE; MonoProfilerHandle prof = mono_profiler_create (NULL); - mono_profiler_set_jit_done_callback (prof, jit_done); //FIXME support multiple appdomains mono_profiler_set_domain_loaded_callback (prof, appdomain_load); mono_profiler_set_assembly_loaded_callback (prof, assembly_loaded); @@ -197,7 +190,7 @@ mono_wasm_debugger_init (MonoDefaults *mono_defaults) trans.send = receive_debugger_agent_message; mono_debugger_agent_register_transport (&trans); - mono_init_debugger_agent_for_wasm (log_level); + mono_init_debugger_agent_for_wasm (log_level, &prof); } static void diff --git a/src/mono/mono/metadata/debug-mono-ppdb.c b/src/mono/mono/metadata/debug-mono-ppdb.c index 070f9b8b0cf28..640ef200cccdd 100644 --- a/src/mono/mono/metadata/debug-mono-ppdb.c +++ b/src/mono/mono/metadata/debug-mono-ppdb.c @@ -456,6 +456,66 @@ mono_ppdb_is_embedded (MonoPPDBFile *ppdb) return ppdb->is_embedded; } +void +mono_ppdb_get_seq_points_enc (const char* ptr, MonoSymSeqPoint **seq_points, int *n_seq_points) +{ + GArray *sps; + MonoSymSeqPoint sp; + int iloffset = 0; + int start_line = 0; + int start_col = 0; + int delta_cols = 0; + gboolean first_non_hidden = TRUE; + int adv_line, adv_col; + int size = mono_metadata_decode_blob_size (ptr, &ptr); + const char* end = ptr + size; + sps = g_array_new (FALSE, TRUE, sizeof (MonoSymSeqPoint)); + mono_metadata_decode_value (ptr, &ptr); + while (ptr < end) { + int delta_il = mono_metadata_decode_value (ptr, &ptr); + iloffset += delta_il; + + int delta_lines = mono_metadata_decode_value (ptr, &ptr); + if (delta_lines == 0) + delta_cols = mono_metadata_decode_value (ptr, &ptr); + else + delta_cols = mono_metadata_decode_signed_value (ptr, &ptr); + + if (delta_lines == 0 && delta_cols == 0) { + /* Hidden sequence point */ + continue; + } + + if (first_non_hidden) { + start_line = mono_metadata_decode_value (ptr, &ptr); + start_col = mono_metadata_decode_value (ptr, &ptr); + } else { + adv_line = mono_metadata_decode_signed_value (ptr, &ptr); + adv_col = mono_metadata_decode_signed_value (ptr, &ptr); + start_line += adv_line; + start_col += adv_col; + } + first_non_hidden = FALSE; + + memset (&sp, 0, sizeof (sp)); + sp.il_offset = iloffset; + sp.line = start_line; + sp.column = start_col; + sp.end_line = start_line + delta_lines; + sp.end_column = start_col + delta_cols; + + g_array_append_val (sps, sp); + } + + if (n_seq_points) { + *n_seq_points = sps->len; + g_assert (seq_points); + *seq_points = g_new (MonoSymSeqPoint, sps->len); + memcpy (*seq_points, sps->data, sps->len * sizeof (MonoSymSeqPoint)); + } + + g_array_free (sps, TRUE); +} void mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points) { diff --git a/src/mono/mono/metadata/debug-mono-ppdb.h b/src/mono/mono/metadata/debug-mono-ppdb.h index c27a97069c97e..e16317f9fc728 100644 --- a/src/mono/mono/metadata/debug-mono-ppdb.h +++ b/src/mono/mono/metadata/debug-mono-ppdb.h @@ -32,6 +32,9 @@ mono_ppdb_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset); void mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points); +void +mono_ppdb_get_seq_points_enc (const char* ptr, MonoSymSeqPoint **seq_points, int *n_seq_points); + MonoDebugLocalsInfo* mono_ppdb_lookup_locals (MonoDebugMethodInfo *minfo); diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 84fc4df27c1b2..7f88f6932c6e9 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -5778,7 +5778,8 @@ ves_icall_AssemblyExtensions_ApplyUpdate (MonoAssembly *assm, g_assert (image_base); // TODO: use dpdb_bytes - mono_image_load_enc_delta (image_base, dmeta_bytes, dmeta_len, dil_bytes, dil_len, error); + mono_image_load_enc_delta (image_base, dmeta_bytes, dmeta_len, dil_bytes, dil_len, dpdb_bytes, dpdb_len, error); + mono_error_set_pending_exception (error); } diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h index 545693ef12a58..213cba0d7aba9 100644 --- a/src/mono/mono/metadata/metadata-internals.h +++ b/src/mono/mono/metadata/metadata-internals.h @@ -819,7 +819,7 @@ int mono_image_relative_delta_index (MonoImage *image_dmeta, int token); MONO_COMPONENT_API void -mono_image_load_enc_delta (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error); +mono_image_load_enc_delta (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, gconstpointer dpdb, uint32_t dpdb_len, MonoError *error); gboolean mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo); diff --git a/src/mono/mono/metadata/metadata-update.c b/src/mono/mono/metadata/metadata-update.c index d1d646c49ba25..89a791f83dbf7 100644 --- a/src/mono/mono/metadata/metadata-update.c +++ b/src/mono/mono/metadata/metadata-update.c @@ -73,9 +73,12 @@ mono_image_relative_delta_index (MonoImage *image_dmeta, int token) } void -mono_image_load_enc_delta (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error) +mono_image_load_enc_delta (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, gconstpointer dpdb, uint32_t dpdb_len, MonoError *error) { - mono_component_hot_reload ()->apply_changes (base_image, dmeta, dmeta_len, dil, dil_len, error); + mono_component_hot_reload ()->apply_changes (base_image, dmeta, dmeta_len, dil, dil_len, dpdb, dpdb_len, error); + if (is_ok (error)) { + mono_component_debugger ()->send_enc_delta (base_image, dmeta, dmeta_len, dpdb, dpdb_len); + } } static void @@ -108,6 +111,12 @@ mono_metadata_update_get_updated_method_rva (MonoImage *base_image, uint32_t idx return mono_component_hot_reload ()->get_updated_method_rva (base_image, idx); } +gpointer +mono_metadata_update_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx) +{ + return mono_component_hot_reload ()->get_updated_method_ppdb (base_image, idx); +} + gboolean mono_metadata_update_table_bounds_check (MonoImage *base_image, int table_index, int token_index) { diff --git a/src/mono/mono/metadata/metadata-update.h b/src/mono/mono/metadata/metadata-update.h index 52bfa701e57f8..15d0d51e10f4a 100644 --- a/src/mono/mono/metadata/metadata-update.h +++ b/src/mono/mono/metadata/metadata-update.h @@ -48,6 +48,9 @@ mono_metadata_update_image_close_all (MonoImage *base_image); gpointer mono_metadata_update_get_updated_method_rva (MonoImage *base_image, uint32_t idx); +gpointer +mono_metadata_update_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx); + gboolean mono_metadata_update_table_bounds_check (MonoImage *base_image, int table_index, int token_index); diff --git a/src/mono/mono/metadata/mono-debug.c b/src/mono/mono/metadata/mono-debug.c index bdef02c84f020..58ecee24d4590 100644 --- a/src/mono/mono/metadata/mono-debug.c +++ b/src/mono/mono/metadata/mono-debug.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #if NO_UNALIGNED_ACCESS @@ -1115,7 +1116,12 @@ mono_debug_enabled (void) void mono_debug_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points) { - if (minfo->handle->ppdb) + MonoImage* img = m_class_get_image (minfo->method->klass); + if (img->has_updates) { + int idx = mono_metadata_token_index (minfo->method->token); + gpointer ptr = mono_metadata_update_get_updated_method_ppdb (img, idx); + mono_ppdb_get_seq_points_enc (ptr, seq_points, n_seq_points); + } else if (minfo->handle->ppdb) mono_ppdb_get_seq_points (minfo, source_file, source_file_list, source_files, seq_points, n_seq_points); else mono_debug_symfile_get_seq_points (minfo, source_file, source_file_list, source_files, seq_points, n_seq_points); diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 4a17c9410b724..dcea17fe92188 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -9775,8 +9775,7 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, Mon MonoJitMemoryManager *jit_mm = get_default_jit_mm (); jit_mm_lock (jit_mm); - if (!g_hash_table_lookup (jit_mm->seq_points, imethod->method)) - g_hash_table_insert (jit_mm->seq_points, imethod->method, imethod->jinfo->seq_points); + g_hash_table_replace (jit_mm->seq_points, imethod->method, imethod->jinfo->seq_points); jit_mm_unlock (jit_mm); // FIXME: Add a different callback ? diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 81c419e4c5850..eb44b8f7969ee 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -62,12 +62,12 @@ internal class BreakpointRequest public int Line { get; private set; } public int Column { get; private set; } public string Condition { get; private set; } - public MethodInfo Method { get; private set; } + public MethodInfo Method { get; set; } private JObject request; public bool IsResolved => Assembly != null; - public List Locations { get; } = new List(); + public List Locations { get; set; } = new List(); public override string ToString() => $"BreakpointRequest Assembly: {Assembly} File: {File} Line: {Line} Column: {Column}"; @@ -241,6 +241,13 @@ public override int GetHashCode(SourceLocation loc) lineNumber = line, columnNumber = column }; + + internal bool IsEnCMethod() + { + if (CliLocation != null) + return CliLocation.Method.IsEnCMethod; + return false; + } } internal class SourceId @@ -321,21 +328,26 @@ internal class MethodInfo public string Name { get; } public MethodDebugInformation DebugInformation; public MethodDefinitionHandle methodDefHandle; + private MetadataReader pdbMetadataReader; - public SourceLocation StartLocation { get; } - public SourceLocation EndLocation { get; } + public SourceLocation StartLocation { get; set;} + public SourceLocation EndLocation { get; set;} public AssemblyInfo Assembly { get; } public int Token { get; } + internal bool IsEnCMethod; + internal LocalScopeHandleCollection localScopes; public bool IsStatic() => (methodDef.Attributes & MethodAttributes.Static) != 0; - public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type) + public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type, MetadataReader asmMetadataReader, MetadataReader pdbMetadataReader) { this.Assembly = assembly; - this.methodDef = Assembly.asmMetadataReader.GetMethodDefinition(methodDefHandle); - this.DebugInformation = Assembly.pdbMetadataReader.GetMethodDebugInformation(methodDefHandle.ToDebugInformationHandle()); + this.methodDef = asmMetadataReader.GetMethodDefinition(methodDefHandle); + this.DebugInformation = pdbMetadataReader.GetMethodDebugInformation(methodDefHandle.ToDebugInformationHandle()); this.source = source; this.Token = token; this.methodDefHandle = methodDefHandle; - this.Name = Assembly.asmMetadataReader.GetString(methodDef.Name); + this.Name = asmMetadataReader.GetString(methodDef.Name); + this.pdbMetadataReader = pdbMetadataReader; + this.IsEnCMethod = false; if (!DebugInformation.SequencePointsBlob.IsNil) { var sps = DebugInformation.GetSequencePoints(); @@ -358,6 +370,37 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, StartLocation = new SourceLocation(this, start); EndLocation = new SourceLocation(this, end); } + localScopes = pdbMetadataReader.GetLocalScopes(methodDefHandle); + } + + public void UpdateEnC(MetadataReader asmMetadataReader, MetadataReader pdbMetadataReaderParm, int method_idx) + { + this.DebugInformation = pdbMetadataReaderParm.GetMethodDebugInformation(MetadataTokens.MethodDebugInformationHandle(method_idx)); + this.pdbMetadataReader = pdbMetadataReaderParm; + this.IsEnCMethod = true; + if (!DebugInformation.SequencePointsBlob.IsNil) + { + var sps = DebugInformation.GetSequencePoints(); + SequencePoint start = sps.First(); + SequencePoint end = sps.First(); + + foreach (SequencePoint sp in sps) + { + if (sp.StartLine < start.StartLine) + start = sp; + else if (sp.StartLine == start.StartLine && sp.StartColumn < start.StartColumn) + start = sp; + + if (sp.EndLine > end.EndLine) + end = sp; + else if (sp.EndLine == end.EndLine && sp.EndColumn > end.EndColumn) + end = sp; + } + + StartLocation = new SourceLocation(this, start); + EndLocation = new SourceLocation(this, end); + } + localScopes = pdbMetadataReader.GetLocalScopes(MetadataTokens.MethodDefinitionHandle(method_idx)); } public SourceLocation GetLocationByIl(int pos) @@ -394,18 +437,18 @@ public VarInfo[] GetLiveVarsAt(int offset) res.Add(new VarInfo(parameter, Assembly.asmMetadataReader)); } - var localScopes = Assembly.pdbMetadataReader.GetLocalScopes(methodDefHandle); + foreach (var localScopeHandle in localScopes) { - var localScope = Assembly.pdbMetadataReader.GetLocalScope(localScopeHandle); + var localScope = pdbMetadataReader.GetLocalScope(localScopeHandle); if (localScope.StartOffset <= offset && localScope.EndOffset > offset) { var localVariables = localScope.GetLocalVariables(); foreach (var localVariableHandle in localVariables) { - var localVariable = Assembly.pdbMetadataReader.GetLocalVariable(localVariableHandle); + var localVariable = pdbMetadataReader.GetLocalVariable(localVariableHandle); if (localVariable.Attributes != LocalVariableAttributes.DebuggerHidden) - res.Add(new VarInfo(localVariable, Assembly.pdbMetadataReader)); + res.Add(new VarInfo(localVariable, pdbMetadataReader)); } } } @@ -465,6 +508,8 @@ internal class AssemblyInfo internal string Url { get; } internal MetadataReader asmMetadataReader { get; } internal MetadataReader pdbMetadataReader { get; set; } + internal List enCMemoryStream = new List(); + internal List enCMetadataReader = new List(); internal PEReader peReader; internal MemoryStream asmStream; internal MemoryStream pdbStream; @@ -496,11 +541,39 @@ public unsafe AssemblyInfo(string url, byte[] assembly, byte[] pdb) Populate(); } + public bool EnCUpdate(byte[] meta, byte[] pdb) + { + var asmStream = new MemoryStream(meta); + MetadataReader asmMetadataReader = MetadataReaderProvider.FromMetadataStream(asmStream).GetMetadataReader(); + var pdbStream = new MemoryStream(pdb); + MetadataReader pdbMetadataReader = MetadataReaderProvider.FromPortablePdbStream(pdbStream).GetMetadataReader(); + enCMemoryStream.Add(asmStream); + enCMemoryStream.Add(pdbStream); + enCMetadataReader.Add(asmMetadataReader); + enCMetadataReader.Add(pdbMetadataReader); + PopulateEnC(asmMetadataReader, pdbMetadataReader); + return true; + } + public AssemblyInfo(ILogger logger) { this.logger = logger; } + private void PopulateEnC(MetadataReader asmMetadataReaderParm, MetadataReader pdbMetadataReaderParm) + { + int i = 1; + foreach (EntityHandle encMapHandle in asmMetadataReaderParm.GetEditAndContinueMapEntries()) + { + if (encMapHandle.Kind == HandleKind.MethodDebugInformation) + { + var method = methods[asmMetadataReader.GetRowNumber(encMapHandle)]; + method.UpdateEnC(asmMetadataReaderParm, pdbMetadataReaderParm, i); + i++; + } + } + } + private void Populate() { var d2s = new Dictionary(); @@ -543,7 +616,7 @@ SourceFile FindSource(DocumentHandle doc, int rowid, string documentName) var document = pdbMetadataReader.GetDocument(methodDebugInformation.Document); var documentName = pdbMetadataReader.GetString(document.Name); SourceFile source = FindSource(methodDebugInformation.Document, asmMetadataReader.GetRowNumber(methodDebugInformation.Document), documentName); - var methodInfo = new MethodInfo(this, method, asmMetadataReader.GetRowNumber(method), source, typeInfo); + var methodInfo = new MethodInfo(this, method, asmMetadataReader.GetRowNumber(method), source, typeInfo, asmMetadataReader, pdbMetadataReader); methods[asmMetadataReader.GetRowNumber(method)] = methodInfo; if (source != null) @@ -605,6 +678,7 @@ private Uri GetSourceLinkUrl(string document) } public IEnumerable Sources => this.sources; + public Dictionary Methods => this.methods; public Dictionary TypesByName => this.typesByName; public int Id => id; @@ -828,6 +902,16 @@ private class DebugItem public Task Data { get; set; } } + public IEnumerable EnCUpdate(SessionId sessionId, AssemblyInfo asm, byte[] meta_data, byte[] pdb_data) + { + asm.EnCUpdate(meta_data, pdb_data); + foreach (var method in asm.Methods) + { + if (method.Value.IsEnCMethod) + yield return method.Value; + } + } + public IEnumerable Add(SessionId sessionId, byte[] assembly_data, byte[] pdb_data) { AssemblyInfo assembly = null; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index f45d31ca1c874..4c2b6fbd74c3c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -349,7 +349,7 @@ protected override async Task AcceptCommand(MessageId id, string method, J case "Debugger.removeBreakpoint": { - await RemoveBreakpoint(id, args, token); + await RemoveBreakpoint(id, args, false, token); break; } @@ -844,6 +844,63 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec int thread_id = ret_debugger_cmd_reader.ReadInt32(); switch (event_kind) { + case EventKind.MethodUpdate: + { + var method_id = ret_debugger_cmd_reader.ReadInt32(); + 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); + asm = store.GetAssemblyByName(assembly_name); + if (asm == null) + { + await SendCommand(sessionId, "Debugger.resume", new JObject(), token); + return true; + } + } + MethodInfo method = asm.GetMethodByToken(method_token); + if (method == null) + { + await SendCommand(sessionId, "Debugger.resume", new JObject(), token); + return true; + } + foreach (var req in context.BreakpointRequests.Values) + { + if (req.Method != null && req.Method.Assembly.Id == method.Assembly.Id && req.Method.Token == method.Token) + { + await SetBreakpoint(sessionId, context.store, req, true, token); + } + } + await SendCommand(sessionId, "Debugger.resume", new JObject(), token); + return true; + } + case EventKind.EnCUpdate: + { + int moduleId = ret_debugger_cmd_reader.ReadInt32(); + int meta_size = ret_debugger_cmd_reader.ReadInt32(); + byte[] meta_buf = ret_debugger_cmd_reader.ReadBytes(meta_size); + int pdb_size = ret_debugger_cmd_reader.ReadInt32(); + byte[] pdb_buf = ret_debugger_cmd_reader.ReadBytes(pdb_size); + + var assembly_name = await sdbHelper.GetAssemblyNameFromModule(sessionId, moduleId, token); + DebugStore store = await LoadStore(sessionId, token); + AssemblyInfo asm = store.GetAssemblyByName(assembly_name); + try { + foreach (var method in store.EnCUpdate(sessionId, asm, meta_buf, pdb_buf)) + await ResetBreakpoint(sessionId, method, token); + } + catch (Exception e) + { + Console.WriteLine(e); + } + await SendCommand(sessionId, "Debugger.resume", new JObject(), token); + return true; + } case EventKind.Exception: { string reason = "exception"; @@ -1209,7 +1266,9 @@ private async Task RuntimeReady(SessionId sessionId, CancellationTok await sdbHelper.EnableExceptions(sessionId, "uncaught", token); await sdbHelper.SetProtocolVersion(sessionId, token); - await sdbHelper.EnableReceiveUserBreakRequest(sessionId, token); + await sdbHelper.EnableReceiveRequests(sessionId, EventKind.UserBreak, token); + await sdbHelper.EnableReceiveRequests(sessionId, EventKind.EnCUpdate, token); + await sdbHelper.EnableReceiveRequests(sessionId, EventKind.MethodUpdate, token); DebugStore store = await LoadStore(sessionId, token); @@ -1218,7 +1277,21 @@ private async Task RuntimeReady(SessionId sessionId, CancellationTok return store; } - private async Task RemoveBreakpoint(MessageId msg_id, JObject args, CancellationToken token) + private async Task ResetBreakpoint(SessionId msg_id, MethodInfo method, CancellationToken token) + { + ExecutionContext context = GetContext(msg_id); + foreach (var req in context.BreakpointRequests.Values) + { + if (req.Method != null) + { + if (req.Method.Assembly.Id == method.Assembly.Id && req.Method.Token == method.Token) { + await RemoveBreakpoint(msg_id, JObject.FromObject(new {breakpointId = req.Id}), true, token); + } + } + } + } + + private async Task RemoveBreakpoint(SessionId msg_id, JObject args, bool isEnCReset, CancellationToken token) { string bpid = args?["breakpointId"]?.Value(); @@ -1232,10 +1305,16 @@ private async Task RemoveBreakpoint(MessageId msg_id, JObject args, Cancellation if (breakpoint_removed) { bp.RemoteId = -1; - bp.State = BreakpointState.Disabled; + if (isEnCReset) + bp.State = BreakpointState.Pending; + else + bp.State = BreakpointState.Disabled; } } - context.BreakpointRequests.Remove(bpid); + if (!isEnCReset) + context.BreakpointRequests.Remove(bpid); + else + breakpointRequest.Locations = new List(); } private async Task SetBreakpoint(SessionId sessionId, DebugStore store, BreakpointRequest req, bool sendResolvedEvent, CancellationToken token) @@ -1263,6 +1342,7 @@ private async Task SetBreakpoint(SessionId sessionId, DebugStore store, Breakpoi foreach (IGrouping sourceId in locations) { SourceLocation loc = sourceId.First(); + req.Method = loc.CliLocation.Method; Breakpoint bp = await SetMonoBreakpoint(sessionId, req.Id, loc, req.Condition, token); // If we didn't successfully enable the breakpoint diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 48ed3a9992bb9..f9d97eb601953 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -83,7 +83,9 @@ internal enum EventKind { KeepAlive = 14, UserBreak = 15, UserLog = 16, - Crash = 17 + Crash = 17, + EnCUpdate = 18, + MethodUpdate = 19 } internal enum ModifierKind { @@ -552,16 +554,18 @@ public async Task SetProtocolVersion(SessionId sessionId, CancellationToke var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdVM.SetProtocolVersion, command_params, token); return true; } - public async Task EnableReceiveUserBreakRequest(SessionId sessionId, CancellationToken token) + + public async Task EnableReceiveRequests(SessionId sessionId, EventKind event_kind, CancellationToken token) { var command_params = new MemoryStream(); var command_params_writer = new MonoBinaryWriter(command_params); - command_params_writer.Write((byte)EventKind.UserBreak); + command_params_writer.Write((byte)event_kind); command_params_writer.Write((byte)SuspendPolicy.None); command_params_writer.Write((byte)0); var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdEventRequest.Set, command_params, token); return true; } + 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); @@ -652,6 +656,17 @@ public async Task GetAssemblyId(SessionId sessionId, string asm_name, Cance return ret_debugger_cmd_reader.ReadInt32(); } + public async Task GetAssemblyNameFromModule(SessionId sessionId, int moduleId, CancellationToken token) + { + var command_params = new MemoryStream(); + var command_params_writer = new MonoBinaryWriter(command_params); + command_params_writer.Write(moduleId); + + var ret_debugger_cmd_reader = await SendDebuggerAgentCommand(sessionId, CmdModule.GetInfo, command_params, token); + ret_debugger_cmd_reader.ReadString(); + return ret_debugger_cmd_reader.ReadString(); + } + public async Task GetAssemblyName(SessionId sessionId, int assembly_id, CancellationToken token) { var command_params = new MemoryStream(); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs index b2ba925ebf633..379e17928375b 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs @@ -288,22 +288,62 @@ await LoadAssemblyDynamically( } [Fact] - public async Task DebugLazyLoadedAssemblyWithHotReload() + public async Task DebugHotReloadMethodChangedUserBreak() { var pause_location = await LoadAssemblyAndTestHotReload( Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"), Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"), - Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll")); - /*var source_location = "dotnet://lazy-debugger-test-embedded.dll/lazy-debugger-test-embedded.cs"; - Assert.Contains(source_location, scripts.Values);*/ + Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll"), + "MethodBody1", "StaticMethod1"); var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); - //Console.WriteLine(pause_location); CheckNumber(locals, "a", 10); - Console.WriteLine(pause_location["callFrames"][0]); - pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", null, 0, 0, null); - Console.WriteLine(pause_location["callFrames"][0]); - pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", null, 0, 0, null); - Console.WriteLine(pause_location["callFrames"][0]); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 14, 8, "StaticMethod1"); + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "b", 15); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 14, 8, "StaticMethod1"); + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckBool(locals, "c", true); } + + [Fact] + public async Task DebugHotReloadMethodUnchanged() + { + var pause_location = await LoadAssemblyAndTestHotReload( + Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"), + Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"), + Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll"), + "MethodBody2", "StaticMethod1"); + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "a", 10); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 23, 8, "StaticMethod1"); + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "a", 10); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 23, 8, "StaticMethod1"); + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "a", 10); + } + + [Fact] + public async Task DebugHotReloadMethodAddBreakpoint() + { + int line = 30; + await SetBreakpoint(".*/MethodBody1.cs$", line, 0, use_regex: true); + var pause_location = await LoadAssemblyAndTestHotReload( + Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"), + Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"), + Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll"), + "MethodBody3", "StaticMethod3"); + + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "a", 10); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 30, 12, "StaticMethod3"); + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "b", 15); + + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 30, 4, "StaticMethod3"); + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckBool(locals, "c", true); + } + } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index 371dde8b7abf0..b26624807150f 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -1041,7 +1041,7 @@ internal async Task LoadAssemblyDynamicallyALCAndRunMethod(string asm_f return await insp.WaitFor(Inspector.PAUSE); } - internal async Task LoadAssemblyAndTestHotReload(string asm_file, string pdb_file, string asm_file_hot_reload) + internal async Task LoadAssemblyAndTestHotReload(string asm_file, string pdb_file, string asm_file_hot_reload, string class_name, string method_name) { // Simulate loading an assembly into the framework byte[] bytes = File.ReadAllBytes(asm_file); @@ -1083,7 +1083,7 @@ internal async Task LoadAssemblyAndTestHotReload(string asm_file, strin Thread.Sleep(1000); var run_method = JObject.FromObject(new { - expression = "window.setTimeout(function() { invoke_static_method('[debugger-test] TestHotReload:RunMethod'); }, 1);" + expression = "window.setTimeout(function() { invoke_static_method('[debugger-test] TestHotReload:RunMethod', '" + class_name + "', '" + method_name + "'); }, 1);" }); await cli.SendCommand("Runtime.evaluate", run_method, token); diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs index 5ae994a8e716c..b2b8f4d364c08 100644 --- a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs @@ -11,7 +11,23 @@ public static string StaticMethod1 () { Console.WriteLine("original"); int a = 10; Debugger.Break(); - Console.WriteLine("passei do break"); + return "OLD STRING"; + } + } + + public class MethodBody2 { + public static string StaticMethod1 () { + Console.WriteLine("original"); + int a = 10; + Debugger.Break(); + return "OLD STRING"; + } + } + + public class MethodBody3 { + public static string StaticMethod3 () { + int a = 10; + Console.WriteLine("original"); return "OLD STRING"; } } diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs index 8c02261b6f7f7..03a4d33b0646b 100644 --- a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs @@ -8,10 +8,26 @@ namespace ApplyUpdateReferencedAssembly { public class MethodBody1 { public static string StaticMethod1 () { - Console.WriteLine("v1"); - double b = 15; + Console.WriteLine("v1"); + double b = 15; + Debugger.Break(); + return "NEW STRING"; + } + } + + public class MethodBody2 { + public static string StaticMethod1 () { + Console.WriteLine("original"); + int a = 10; Debugger.Break(); - Console.WriteLine("passei v1"); + return "OLD STRING"; + } + } + + public class MethodBody3 { + public static string StaticMethod3 () { + float b = 15; + Console.WriteLine("v1"); return "NEW STRING"; } } diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs index d2e8b59374832..e38d43cbcac6b 100644 --- a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs @@ -6,12 +6,29 @@ namespace ApplyUpdateReferencedAssembly { public class MethodBody1 { - public static string StaticMethod1 () { + public static string StaticMethod1 () + { Console.WriteLine("v2"); bool c = true; Debugger.Break(); - Console.WriteLine("passei v2"); return "NEWEST STRING"; } } + + public class MethodBody2 { + public static string StaticMethod1 () { + Console.WriteLine("original"); + int a = 10; + Debugger.Break(); + return "OLD STRING"; + } + } + + public class MethodBody3 { + public static string StaticMethod3 () { + bool c = true; + Console.WriteLine("v2"); + return "NEWEST STRING"; + } + } } diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index e362d3582e62f..228d9d1ff62e5 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -604,7 +604,7 @@ public static void LoadLazyHotReload(string asm_base64, string pdb_base64, strin Console.WriteLine($"Loaded - {loadedAssembly}"); } - public static void RunMethod() + public static void RunMethod(string className, string methodName) { var ty = typeof(System.Reflection.Metadata.AssemblyExtensions); var mi = ty.GetMethod("GetApplyUpdateCapabilities", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static, Array.Empty()); @@ -617,20 +617,20 @@ public static void RunMethod() if (String.IsNullOrEmpty(caps)) return; - var myType = loadedAssembly.GetType("ApplyUpdateReferencedAssembly.MethodBody1"); - var myMethod = myType.GetMethod("StaticMethod1"); + var myType = loadedAssembly.GetType($"ApplyUpdateReferencedAssembly.{className}"); + var myMethod = myType.GetMethod(methodName); myMethod.Invoke(null, null); ApplyUpdate(loadedAssembly, 1); - myType = loadedAssembly.GetType("ApplyUpdateReferencedAssembly.MethodBody1"); - myMethod = myType.GetMethod("StaticMethod1"); + myType = loadedAssembly.GetType($"ApplyUpdateReferencedAssembly.{className}"); + myMethod = myType.GetMethod(methodName); myMethod.Invoke(null, null); ApplyUpdate(loadedAssembly, 2); - myType = loadedAssembly.GetType("ApplyUpdateReferencedAssembly.MethodBody1"); - myMethod = myType.GetMethod("StaticMethod1"); + myType = loadedAssembly.GetType($"ApplyUpdateReferencedAssembly.{className}"); + myMethod = myType.GetMethod(methodName); myMethod.Invoke(null, null); } diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj index ab5781f45f85d..797fa16751648 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj @@ -25,7 +25,8 @@ $(AppDir) $(MonoProjectRoot)wasm\runtime-test.js - 1 + + -1 true From e8bbbfc3c97768c5ce0aa136b7ca656a2f51136f Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 6 Jul 2021 14:53:49 -0300 Subject: [PATCH 03/11] Reuse some code. --- src/mono/mono/metadata/debug-mono-ppdb.c | 136 +++++++++-------------- 1 file changed, 50 insertions(+), 86 deletions(-) diff --git a/src/mono/mono/metadata/debug-mono-ppdb.c b/src/mono/mono/metadata/debug-mono-ppdb.c index 640ef200cccdd..4586bbc19dc68 100644 --- a/src/mono/mono/metadata/debug-mono-ppdb.c +++ b/src/mono/mono/metadata/debug-mono-ppdb.c @@ -456,8 +456,8 @@ mono_ppdb_is_embedded (MonoPPDBFile *ppdb) return ppdb->is_embedded; } -void -mono_ppdb_get_seq_points_enc (const char* ptr, MonoSymSeqPoint **seq_points, int *n_seq_points) +static int +mono_ppdb_get_seq_points_internal (const char* ptr, MonoSymSeqPoint **seq_points, int *n_seq_points, int docidx, MonoImage *image, MonoPPDBFile *ppdb, GPtrArray **sfiles, char **source_file, int **source_files, GPtrArray **sindexes, gboolean read_doc_value) { GArray *sps; MonoSymSeqPoint sp; @@ -469,11 +469,42 @@ mono_ppdb_get_seq_points_enc (const char* ptr, MonoSymSeqPoint **seq_points, int int adv_line, adv_col; int size = mono_metadata_decode_blob_size (ptr, &ptr); const char* end = ptr + size; + MonoDebugSourceInfo *docinfo; + gboolean first = TRUE; + sps = g_array_new (FALSE, TRUE, sizeof (MonoSymSeqPoint)); + + /* Header */ + /* LocalSignature */ mono_metadata_decode_value (ptr, &ptr); + if (docidx == 0 && read_doc_value) + docidx = mono_metadata_decode_value (ptr, &ptr); + if (sfiles && *sfiles) + { + docinfo = get_docinfo (ppdb, image, docidx); + g_ptr_array_add (*sfiles, docinfo); + } + + if (source_file && *source_file) + *source_file = g_strdup (docinfo->source_file); + + iloffset = 0; + start_line = 0; + start_col = 0; while (ptr < end) { int delta_il = mono_metadata_decode_value (ptr, &ptr); + if (!first && delta_il == 0 && read_doc_value) { + /* subsequent-document-record */ + docidx = mono_metadata_decode_value (ptr, &ptr); + docinfo = get_docinfo (ppdb, image, docidx); + if (sfiles && *sfiles) + { + g_ptr_array_add (*sfiles, docinfo); + } + continue; + } iloffset += delta_il; + first = FALSE; int delta_lines = mono_metadata_decode_value (ptr, &ptr); if (delta_lines == 0) @@ -505,6 +536,9 @@ mono_ppdb_get_seq_points_enc (const char* ptr, MonoSymSeqPoint **seq_points, int sp.end_column = start_col + delta_cols; g_array_append_val (sps, sp); + if (sfiles && *sfiles) { + g_ptr_array_add (*sindexes, GUINT_TO_POINTER ((*sfiles)->len - 1)); + } } if (n_seq_points) { @@ -513,9 +547,17 @@ mono_ppdb_get_seq_points_enc (const char* ptr, MonoSymSeqPoint **seq_points, int *seq_points = g_new (MonoSymSeqPoint, sps->len); memcpy (*seq_points, sps->data, sps->len * sizeof (MonoSymSeqPoint)); } - + int sps_len = sps->len; g_array_free (sps, TRUE); + return sps_len; +} + +void +mono_ppdb_get_seq_points_enc (const char* ptr, MonoSymSeqPoint **seq_points, int *n_seq_points) +{ + mono_ppdb_get_seq_points_internal (ptr, seq_points, n_seq_points, 0, NULL, NULL, NULL, NULL, NULL, NULL, FALSE); } + void mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points) { @@ -525,12 +567,7 @@ mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrAr MonoTableInfo *tables = image->tables; guint32 cols [MONO_METHODBODY_SIZE]; const char *ptr; - const char *end; - MonoDebugSourceInfo *docinfo; - int i, method_idx, size, docidx, iloffset, delta_il, delta_lines, delta_cols, start_line, start_col, adv_line, adv_col; - gboolean first = TRUE, first_non_hidden = TRUE; - GArray *sps; - MonoSymSeqPoint sp; + int i, method_idx, docidx; GPtrArray *sfiles = NULL; GPtrArray *sindexes = NULL; @@ -570,89 +607,16 @@ mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrAr return; ptr = mono_metadata_blob_heap (image, cols [MONO_METHODBODY_SEQ_POINTS]); - size = mono_metadata_decode_blob_size (ptr, &ptr); - end = ptr + size; - - sps = g_array_new (FALSE, TRUE, sizeof (MonoSymSeqPoint)); - - /* Header */ - /* LocalSignature */ - mono_metadata_decode_value (ptr, &ptr); - if (docidx == 0) - docidx = mono_metadata_decode_value (ptr, &ptr); - docinfo = get_docinfo (ppdb, image, docidx); - - if (sfiles) - g_ptr_array_add (sfiles, docinfo); - - if (source_file) - *source_file = g_strdup (docinfo->source_file); - - iloffset = 0; - start_line = 0; - start_col = 0; - while (ptr < end) { - delta_il = mono_metadata_decode_value (ptr, &ptr); - if (!first && delta_il == 0) { - /* subsequent-document-record */ - docidx = mono_metadata_decode_value (ptr, &ptr); - docinfo = get_docinfo (ppdb, image, docidx); - if (sfiles) - g_ptr_array_add (sfiles, docinfo); - continue; - } - iloffset += delta_il; - first = FALSE; - - delta_lines = mono_metadata_decode_value (ptr, &ptr); - if (delta_lines == 0) - delta_cols = mono_metadata_decode_value (ptr, &ptr); - else - delta_cols = mono_metadata_decode_signed_value (ptr, &ptr); - - if (delta_lines == 0 && delta_cols == 0) { - /* Hidden sequence point */ - continue; - } - - if (first_non_hidden) { - start_line = mono_metadata_decode_value (ptr, &ptr); - start_col = mono_metadata_decode_value (ptr, &ptr); - } else { - adv_line = mono_metadata_decode_signed_value (ptr, &ptr); - adv_col = mono_metadata_decode_signed_value (ptr, &ptr); - start_line += adv_line; - start_col += adv_col; - } - first_non_hidden = FALSE; - - memset (&sp, 0, sizeof (sp)); - sp.il_offset = iloffset; - sp.line = start_line; - sp.column = start_col; - sp.end_line = start_line + delta_lines; - sp.end_column = start_col + delta_cols; - - g_array_append_val (sps, sp); - if (source_files) - g_ptr_array_add (sindexes, GUINT_TO_POINTER (sfiles->len - 1)); - } - - if (n_seq_points) { - *n_seq_points = sps->len; - g_assert (seq_points); - *seq_points = g_new (MonoSymSeqPoint, sps->len); - memcpy (*seq_points, sps->data, sps->len * sizeof (MonoSymSeqPoint)); - } + + int sps_len = mono_ppdb_get_seq_points_internal (ptr, seq_points, n_seq_points, docidx, image, ppdb, &sfiles, source_file, source_files, &sindexes, TRUE); if (source_files) { - *source_files = g_new (int, sps->len); - for (i = 0; i < sps->len; ++i) + *source_files = g_new (int, sps_len); + for (i = 0; i < sps_len; ++i) (*source_files)[i] = GPOINTER_TO_INT (g_ptr_array_index (sindexes, i)); g_ptr_array_free (sindexes, TRUE); } - g_array_free (sps, TRUE); } MonoDebugLocalsInfo* From 79e00bf150d53615afdae4638a00e192f257a7a9 Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 6 Jul 2021 14:56:49 -0300 Subject: [PATCH 04/11] Remove unrelated comment. --- src/mono/mono/component/debugger-agent.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index e372d6ec29b85..bec98edb3c2f3 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -308,7 +308,6 @@ typedef struct { } EventInfo; typedef struct { - /* For EVENT_KIND_EXCEPTION */ MonoImage *image; gconstpointer meta_bytes; int meta_len; From 84de82a523e6f657511ad18aff8df79ac3f61aa6 Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 6 Jul 2021 15:02:54 -0300 Subject: [PATCH 05/11] Reuse code. --- src/mono/mono/component/hot_reload.c | 45 +++++++--------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index a0b6c14143aa2..68f2ad03dda88 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -1408,7 +1408,7 @@ metadata_update_count_updates (MonoImage *base) } static gpointer -get_method_ppdb_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint32_t idx) +get_method_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint32_t idx, gboolean is_pdb) { gpointer loc = NULL; uint32_t cur = hot_reload_get_thread_generation (); @@ -1422,38 +1422,13 @@ get_method_ppdb_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint g_assert (delta_info); if (delta_info->generation > cur) break; - if (delta_info->method_ppdb_table_update) { - gpointer result = g_hash_table_lookup (delta_info->method_ppdb_table_update, GUINT_TO_POINTER (idx)); - /* if it's not in the table of a later generation, the - * later generation didn't modify the method - */ - if (result != NULL) { - loc = result; - generation = delta_info->generation; - } - } - } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "method lookup idx=0x%08x returned gen=%d ppdb=%p", idx, generation, loc); - return loc; -} - -static gpointer -get_method_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint32_t idx) -{ - gpointer loc = NULL; - uint32_t cur = hot_reload_get_thread_generation (); - int generation = -1; - - /* Go through all the updates that the current thread can see and see - * if they updated the method. Keep the latest visible update */ - for (GList *ptr = base_info->delta_image; ptr != NULL; ptr = ptr->next) { - MonoImage *image_delta = (MonoImage*) ptr->data; - DeltaInfo *delta_info = delta_info_lookup (image_delta); - g_assert (delta_info); - if (delta_info->generation > cur) - break; - if (delta_info->method_table_update) { - gpointer result = g_hash_table_lookup (delta_info->method_table_update, GUINT_TO_POINTER (idx)); + GHashTable *table = NULL; + if (is_pdb) + table = delta_info->method_ppdb_table_update; + else + table = delta_info->method_table_update; + if (table) { + gpointer result = g_hash_table_lookup (table, GUINT_TO_POINTER (idx)); /* if it's not in the table of a later generation, the * later generation didn't modify the method */ @@ -1478,7 +1453,7 @@ hot_reload_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx) if (G_UNLIKELY (info->method_table_update)) { uint32_t gen = GPOINTER_TO_UINT (g_hash_table_lookup (info->method_table_update, GUINT_TO_POINTER (idx))); if (G_UNLIKELY (gen > 0)) { - loc = get_method_ppdb_update_rva (base_image, info, idx); + loc = get_method_update_rva (base_image, info, idx, TRUE); } } return loc; @@ -1495,7 +1470,7 @@ hot_reload_get_updated_method_rva (MonoImage *base_image, uint32_t idx) if (G_UNLIKELY (info->method_table_update)) { uint32_t gen = GPOINTER_TO_UINT (g_hash_table_lookup (info->method_table_update, GUINT_TO_POINTER (idx))); if (G_UNLIKELY (gen > 0)) { - loc = get_method_update_rva (base_image, info, idx); + loc = get_method_update_rva (base_image, info, idx, FALSE); } } return loc; From 38712add9dc7c612eb410856f4d785588b4b2318 Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 6 Jul 2021 15:15:41 -0300 Subject: [PATCH 06/11] Refactor new code. --- .../debugger/BrowserDebugProxy/DebugStore.cs | 13 +-- .../debugger/BrowserDebugProxy/MonoProxy.cs | 107 +++++++++--------- .../BrowserDebugProxy/MonoSDBHelper.cs | 2 +- 3 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index eb44b8f7969ee..c1e8ce60bda6c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -241,13 +241,6 @@ public override int GetHashCode(SourceLocation loc) lineNumber = line, columnNumber = column }; - - internal bool IsEnCMethod() - { - if (CliLocation != null) - return CliLocation.Method.IsEnCMethod; - return false; - } } internal class SourceId @@ -541,7 +534,7 @@ public unsafe AssemblyInfo(string url, byte[] assembly, byte[] pdb) Populate(); } - public bool EnCUpdate(byte[] meta, byte[] pdb) + public bool EnC(byte[] meta, byte[] pdb) { var asmStream = new MemoryStream(meta); MetadataReader asmMetadataReader = MetadataReaderProvider.FromMetadataStream(asmStream).GetMetadataReader(); @@ -902,9 +895,9 @@ private class DebugItem public Task Data { get; set; } } - public IEnumerable EnCUpdate(SessionId sessionId, AssemblyInfo asm, byte[] meta_data, byte[] pdb_data) + public IEnumerable EnC(SessionId sessionId, AssemblyInfo asm, byte[] meta_data, byte[] pdb_data) { - asm.EnCUpdate(meta_data, pdb_data); + asm.EnC(meta_data, pdb_data); foreach (var method in asm.Methods) { if (method.Value.IsEnCMethod) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 4c2b6fbd74c3c..f14bc1e16a99b 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -689,6 +689,56 @@ private async Task EvaluateCondition(SessionId sessionId, ExecutionContext } return false; } + + private async Task ProcessEnC(SessionId sessionId, ExecutionContext context, MonoBinaryReader ret_debugger_cmd_reader, CancellationToken token) + { + int moduleId = ret_debugger_cmd_reader.ReadInt32(); + int meta_size = ret_debugger_cmd_reader.ReadInt32(); + byte[] meta_buf = ret_debugger_cmd_reader.ReadBytes(meta_size); + int pdb_size = ret_debugger_cmd_reader.ReadInt32(); + byte[] pdb_buf = ret_debugger_cmd_reader.ReadBytes(pdb_size); + + var assembly_name = await sdbHelper.GetAssemblyNameFromModule(sessionId, moduleId, token); + DebugStore store = await LoadStore(sessionId, token); + AssemblyInfo asm = store.GetAssemblyByName(assembly_name); + foreach (var method in store.EnC(sessionId, asm, meta_buf, pdb_buf)) + await ResetBreakpoint(sessionId, method, token); + return true; + } + + private async Task SendBreakpointsOfMethodUpdated(SessionId sessionId, ExecutionContext context, MonoBinaryReader ret_debugger_cmd_reader, CancellationToken token) + { + var method_id = ret_debugger_cmd_reader.ReadInt32(); + 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); + asm = store.GetAssemblyByName(assembly_name); + if (asm == null) + { + return true; + } + } + MethodInfo method = asm.GetMethodByToken(method_token); + if (method == null) + { + return true; + } + foreach (var req in context.BreakpointRequests.Values) + { + if (req.Method != null && req.Method.Assembly.Id == method.Assembly.Id && req.Method.Token == method.Token) + { + await SetBreakpoint(sessionId, context.store, req, true, token); + } + } + return true; + } + 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(); @@ -846,60 +896,15 @@ private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObjec { case EventKind.MethodUpdate: { - var method_id = ret_debugger_cmd_reader.ReadInt32(); - 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); - asm = store.GetAssemblyByName(assembly_name); - if (asm == null) - { - await SendCommand(sessionId, "Debugger.resume", new JObject(), token); - return true; - } - } - MethodInfo method = asm.GetMethodByToken(method_token); - if (method == null) - { - await SendCommand(sessionId, "Debugger.resume", new JObject(), token); - return true; - } - foreach (var req in context.BreakpointRequests.Values) - { - if (req.Method != null && req.Method.Assembly.Id == method.Assembly.Id && req.Method.Token == method.Token) - { - await SetBreakpoint(sessionId, context.store, req, true, token); - } - } + var ret = await SendBreakpointsOfMethodUpdated(sessionId, context, ret_debugger_cmd_reader, token); await SendCommand(sessionId, "Debugger.resume", new JObject(), token); - return true; + return ret; } - case EventKind.EnCUpdate: + case EventKind.EnC: { - int moduleId = ret_debugger_cmd_reader.ReadInt32(); - int meta_size = ret_debugger_cmd_reader.ReadInt32(); - byte[] meta_buf = ret_debugger_cmd_reader.ReadBytes(meta_size); - int pdb_size = ret_debugger_cmd_reader.ReadInt32(); - byte[] pdb_buf = ret_debugger_cmd_reader.ReadBytes(pdb_size); - - var assembly_name = await sdbHelper.GetAssemblyNameFromModule(sessionId, moduleId, token); - DebugStore store = await LoadStore(sessionId, token); - AssemblyInfo asm = store.GetAssemblyByName(assembly_name); - try { - foreach (var method in store.EnCUpdate(sessionId, asm, meta_buf, pdb_buf)) - await ResetBreakpoint(sessionId, method, token); - } - catch (Exception e) - { - Console.WriteLine(e); - } + var ret = await ProcessEnC(sessionId, context, ret_debugger_cmd_reader, token); await SendCommand(sessionId, "Debugger.resume", new JObject(), token); - return true; + return ret; } case EventKind.Exception: { @@ -1267,7 +1272,7 @@ private async Task RuntimeReady(SessionId sessionId, CancellationTok await sdbHelper.SetProtocolVersion(sessionId, token); await sdbHelper.EnableReceiveRequests(sessionId, EventKind.UserBreak, token); - await sdbHelper.EnableReceiveRequests(sessionId, EventKind.EnCUpdate, token); + await sdbHelper.EnableReceiveRequests(sessionId, EventKind.EnC, token); await sdbHelper.EnableReceiveRequests(sessionId, EventKind.MethodUpdate, 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 f9d97eb601953..42ad54e6e2c61 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -84,7 +84,7 @@ internal enum EventKind { UserBreak = 15, UserLog = 16, Crash = 17, - EnCUpdate = 18, + EnC = 18, MethodUpdate = 19 } From f13a500bbdeabcab767bf3c508e4be8ea14771b6 Mon Sep 17 00:00:00 2001 From: Thays Date: Tue, 6 Jul 2021 15:32:24 -0300 Subject: [PATCH 07/11] Fix log. --- src/mono/mono/component/hot_reload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 68f2ad03dda88..7fa01eefa643d 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -1145,7 +1145,7 @@ hot_reload_get_method_debug_information (MonoImage *image_dppdb, int idx) const char *ptr = mono_metadata_blob_heap (image_dppdb, cols [MONO_METHODBODY_SEQ_POINTS]); return ptr; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb encmap i=%d: token=0x%08x (table=%s): %d", i, map_token, mono_meta_table_name (token_table)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb encmap i=%d: token=0x%08x (table=%s)", i, map_token, mono_meta_table_name (token_table)); } return NULL; } From 781969b6a23a993ee726b40f3e8d1ef2675d7d31 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Tue, 6 Jul 2021 22:35:59 -0300 Subject: [PATCH 08/11] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aleksey Kliger (λgeek) --- src/mono/mono/metadata/icall.c | 1 - .../tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 7f88f6932c6e9..7cf93109bdd0b 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -5776,7 +5776,6 @@ ves_icall_AssemblyExtensions_ApplyUpdate (MonoAssembly *assm, g_assert (dmeta_len >= 0); MonoImage *image_base = assm->image; g_assert (image_base); - // TODO: use dpdb_bytes mono_image_load_enc_delta (image_base, dmeta_bytes, dmeta_len, dil_bytes, dil_len, dpdb_bytes, dpdb_len, error); diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs index e38d43cbcac6b..4cd88d660a3f1 100644 --- a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs +++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs @@ -26,9 +26,9 @@ public static string StaticMethod1 () { public class MethodBody3 { public static string StaticMethod3 () { - bool c = true; - Console.WriteLine("v2"); - return "NEWEST STRING"; + bool c = true; + Console.WriteLine("v2"); + return "NEWEST STRING"; } } } From e337da565fa6b0750640111a3f2bad0023e8328a Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 7 Jul 2021 13:01:05 -0300 Subject: [PATCH 09/11] Fixing hot reload without debug information. --- src/mono/mono/component/hot_reload.c | 17 ++++++++++++----- src/mono/mono/component/mini-wasm-debugger.c | 2 +- .../DebuggerTestSuite/BreakpointTests.cs | 6 +++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 7fa01eefa643d..7b5d7d9d6212d 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -1124,6 +1124,9 @@ set_update_method (MonoImage *image_base, BaselineInfo *base_info, uint32_t gene static const char * hot_reload_get_method_debug_information (MonoImage *image_dppdb, int idx) { + if (!image_dppdb) + return NULL; + MonoTableInfo *table_encmap = &image_dppdb->tables [MONO_TABLE_ENCMAP]; int rows = table_info_get_rows (table_encmap); for (int i = 0; i < rows ; ++i) { @@ -1305,11 +1308,15 @@ hot_reload_apply_changes (MonoImage *image_base, gconstpointer dmeta_bytes, uint /* makes a copy of dil_bytes_orig */ gpointer dil_bytes = open_dil_data (image_base, dil_bytes_orig, dil_length); - MonoImage *image_dpdb = image_open_dmeta_from_data (image_base, generation, dpdb_bytes_orig, dpdb_length); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image string size: 0x%08x", image_dpdb->heap_strings.size); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image user string size: 0x%08x", image_dpdb->heap_us.size); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image blob heap addr: %p", image_dpdb->heap_blob.data); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image blob heap size: 0x%08x", image_dpdb->heap_blob.size); + MonoImage *image_dpdb = NULL; + if (dpdb_length > 0) + { + MonoImage *image_dpdb = image_open_dmeta_from_data (image_base, generation, dpdb_bytes_orig, dpdb_length); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image string size: 0x%08x", image_dpdb->heap_strings.size); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image user string size: 0x%08x", image_dpdb->heap_us.size); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image blob heap addr: %p", image_dpdb->heap_blob.data); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "pdb image blob heap size: 0x%08x", image_dpdb->heap_blob.size); + } BaselineInfo *base_info = baseline_info_lookup_or_add (image_base); diff --git a/src/mono/mono/component/mini-wasm-debugger.c b/src/mono/mono/component/mini-wasm-debugger.c index ef9d33c0df9cb..5dd9d8ce1d402 100644 --- a/src/mono/mono/component/mini-wasm-debugger.c +++ b/src/mono/mono/component/mini-wasm-debugger.c @@ -143,9 +143,9 @@ handle_multiple_ss_requests (void) { static void mono_wasm_enable_debugging_internal (int debug_level) { + log_level = debug_level; PRINT_DEBUG_MSG (1, "DEBUGGING ENABLED\n"); debugger_enabled = TRUE; - log_level = debug_level; } static void diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs index 379e17928375b..77a8cb6c12e16 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs @@ -327,7 +327,7 @@ public async Task DebugHotReloadMethodUnchanged() public async Task DebugHotReloadMethodAddBreakpoint() { int line = 30; - await SetBreakpoint(".*/MethodBody1.cs$", line, 0, use_regex: true); + await SetBreakpoint(".*/MethodBody1.cs$", line, 12, use_regex: true); var pause_location = await LoadAssemblyAndTestHotReload( Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"), Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"), @@ -336,11 +336,11 @@ public async Task DebugHotReloadMethodAddBreakpoint() var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); CheckNumber(locals, "a", 10); - pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 30, 12, "StaticMethod3"); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 29, 12, "StaticMethod3"); locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); CheckNumber(locals, "b", 15); - pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 30, 4, "StaticMethod3"); + pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 29, 12, "StaticMethod3"); locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); CheckBool(locals, "c", true); } From 48d285da30aabd02e24c0456fdc791e7ceafd8a8 Mon Sep 17 00:00:00 2001 From: Thays Date: Wed, 7 Jul 2021 13:05:45 -0300 Subject: [PATCH 10/11] replacing spaces with tabs. --- .../wasm/debugger/tests/debugger-test/runtime-debugger.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js b/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js index 191504d235f51..2c24917f62033 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js +++ b/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js @@ -29,8 +29,8 @@ var Module = { */ Module.config.environment_variables = { - "DOTNET_MODIFIABLE_ASSEMBLIES": "debug" - }; + "DOTNET_MODIFIABLE_ASSEMBLIES": "debug" + }; MONO.mono_load_runtime_and_bcl_args (Module.config) }, }; From fb9a4f17e56de2bce0a7f0d7f2f2a0df5ff9ecb6 Mon Sep 17 00:00:00 2001 From: Thays Date: Mon, 12 Jul 2021 09:30:54 -0300 Subject: [PATCH 11/11] Fixing CI. --- src/mono/mono/metadata/debug-mono-ppdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/metadata/debug-mono-ppdb.c b/src/mono/mono/metadata/debug-mono-ppdb.c index 4586bbc19dc68..67bd4715d33bd 100644 --- a/src/mono/mono/metadata/debug-mono-ppdb.c +++ b/src/mono/mono/metadata/debug-mono-ppdb.c @@ -536,7 +536,7 @@ mono_ppdb_get_seq_points_internal (const char* ptr, MonoSymSeqPoint **seq_points sp.end_column = start_col + delta_cols; g_array_append_val (sps, sp); - if (sfiles && *sfiles) { + if (sindexes && *sindexes) { g_ptr_array_add (*sindexes, GUINT_TO_POINTER ((*sfiles)->len - 1)); } }