From 56e58d304a8e8e770e4abda13d3031c9feae5709 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Tue, 14 Jun 2022 15:55:13 -0300 Subject: [PATCH] [wasm][debugger] Implement get bytes from loaded_files using debugger protocol. (#69072) * Implement get bytes from loaded_files using debugger protocol. * fix pdb size == nul * Adressing @radical comments. * Fix build. * fix compilation * Addressing @radical comments. Co-authored-by: Ankit Jain --- src/mono/mono/component/debugger-protocol.h | 5 +- src/mono/mono/component/mini-wasm-debugger.c | 18 +++++ src/mono/mono/metadata/mono-debug.c | 13 ++++ src/mono/mono/mini/mini-wasm.h | 2 + .../debugger/BrowserDebugProxy/DebugStore.cs | 74 +++++++++++++------ .../debugger/BrowserDebugProxy/MonoProxy.cs | 7 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 38 +++++++++- src/mono/wasm/runtime/driver.c | 18 +++++ .../metadata/details/assembly-functions.h | 1 + 9 files changed, 150 insertions(+), 26 deletions(-) diff --git a/src/mono/mono/component/debugger-protocol.h b/src/mono/mono/component/debugger-protocol.h index af28674c42d52f..70753b7ec70111 100644 --- a/src/mono/mono/component/debugger-protocol.h +++ b/src/mono/mono/component/debugger-protocol.h @@ -11,7 +11,7 @@ */ #define MAJOR_VERSION 2 -#define MINOR_VERSION 60 +#define MINOR_VERSION 61 typedef enum { MDBGPROT_CMD_COMPOSITE = 100 @@ -36,7 +36,8 @@ typedef enum { MDBGPROT_CMD_VM_READ_MEMORY = 16, MDBGPROT_CMD_VM_WRITE_MEMORY = 17, MDBGPROT_CMD_GET_ASSEMBLY_BY_NAME = 18, - MDBGPROT_CMD_GET_MODULE_BY_GUID = 19 + MDBGPROT_CMD_GET_MODULE_BY_GUID = 19, + MDBGPROT_CMD_GET_ASSEMBLY_BYTES = 20, //wasm specific } MdbgProtCmdVM; typedef enum { diff --git a/src/mono/mono/component/mini-wasm-debugger.c b/src/mono/mono/component/mini-wasm-debugger.c index f719b1806d1159..a13e273ebb9eba 100644 --- a/src/mono/mono/component/mini-wasm-debugger.c +++ b/src/mono/mono/component/mini-wasm-debugger.c @@ -418,6 +418,24 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, invoke_data.endp = data + size; error = mono_do_invoke_method (tls, &buf, &invoke_data, data, &data); } + else if (command_set == MDBGPROT_CMD_SET_VM && (command == MDBGPROT_CMD_GET_ASSEMBLY_BYTES)) + { + char* assembly_name = m_dbgprot_decode_string (data, &data, data + size); + if (assembly_name == NULL) + { + m_dbgprot_buffer_add_int (&buf, 0); + m_dbgprot_buffer_add_int (&buf, 0); + } + else + { + unsigned int assembly_size = 0; + int symfile_size = 0; + const unsigned char* assembly_bytes = mono_wasm_get_assembly_bytes (assembly_name, &assembly_size); + const unsigned char* pdb_bytes = mono_get_symfile_bytes_from_bundle (assembly_name, &symfile_size); + m_dbgprot_buffer_add_byte_array (&buf, (uint8_t *) assembly_bytes, assembly_size); + m_dbgprot_buffer_add_byte_array (&buf, (uint8_t *) pdb_bytes, symfile_size); + } + } else error = mono_process_dbg_packet (id, command_set, command, &no_reply, data, data + size, &buf); diff --git a/src/mono/mono/metadata/mono-debug.c b/src/mono/mono/metadata/mono-debug.c index 5fbe40b0f55b72..37a98e7e43df38 100644 --- a/src/mono/mono/metadata/mono-debug.c +++ b/src/mono/mono/metadata/mono-debug.c @@ -1112,6 +1112,19 @@ open_symfile_from_bundle (MonoImage *image) return NULL; } +const mono_byte * +mono_get_symfile_bytes_from_bundle (const char *assembly_name, int *size) +{ + BundledSymfile *bsymfile; + for (bsymfile = bundled_symfiles; bsymfile; bsymfile = bsymfile->next) { + if (strcmp (bsymfile->aname, assembly_name)) + continue; + *size = bsymfile->size; + return bsymfile->raw_contents; + } + return NULL; +} + void mono_debugger_lock (void) { diff --git a/src/mono/mono/mini/mini-wasm.h b/src/mono/mono/mini/mini-wasm.h index d307077de1c337..e83a1baefb1933 100644 --- a/src/mono/mono/mini/mini-wasm.h +++ b/src/mono/mono/mini/mini-wasm.h @@ -103,6 +103,8 @@ G_EXTERN_C void mono_wasm_enable_debugging (int log_level); void mono_wasm_set_timeout (int timeout); int mono_wasm_assembly_already_added (const char *assembly_name); +const unsigned char *mono_wasm_get_assembly_bytes (const char *name, unsigned int *size); + void mono_wasm_print_stack_trace (void); gboolean diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 9fb4b8f04fe9e8..2baa2f2e02873f 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -1366,36 +1366,61 @@ public IEnumerable Add(SessionId id, string name, byte[] assembly_da } } - public async IAsyncEnumerable Load(SessionId id, string[] loaded_files, [EnumeratorCancellation] CancellationToken token) + public async IAsyncEnumerable Load(SessionId id, string[] loaded_files, ExecutionContext context, bool useDebuggerProtocol, [EnumeratorCancellation] CancellationToken token) { var asm_files = new List(); - var pdb_files = new List(); - foreach (string file_name in loaded_files) - { - if (file_name.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase)) - pdb_files.Add(file_name); - else - asm_files.Add(file_name); - } - List steps = new List(); - foreach (string url in asm_files) + + if (!useDebuggerProtocol) { - try + var pdb_files = new List(); + foreach (string file_name in loaded_files) { - string candidate_pdb = Path.ChangeExtension(url, "pdb"); - string pdb = pdb_files.FirstOrDefault(n => n == candidate_pdb); + if (file_name.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase)) + pdb_files.Add(file_name); + else + asm_files.Add(file_name); + } - steps.Add( - new DebugItem - { - Url = url, - Data = Task.WhenAll(MonoProxy.HttpClient.GetByteArrayAsync(url, token), pdb != null ? MonoProxy.HttpClient.GetByteArrayAsync(pdb, token) : Task.FromResult(null)) - }); + foreach (string url in asm_files) + { + try + { + string candidate_pdb = Path.ChangeExtension(url, "pdb"); + string pdb = pdb_files.FirstOrDefault(n => n == candidate_pdb); + + steps.Add( + new DebugItem + { + Url = url, + Data = Task.WhenAll(MonoProxy.HttpClient.GetByteArrayAsync(url, token), pdb != null ? MonoProxy.HttpClient.GetByteArrayAsync(pdb, token) : Task.FromResult(null)) + }); + } + catch (Exception e) + { + logger.LogDebug($"Failed to read {url} ({e.Message})"); + } } - catch (Exception e) + } + else + { + foreach (string file_name in loaded_files) { - logger.LogDebug($"Failed to read {url} ({e.Message})"); + if (file_name.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase)) + continue; + try + { + steps.Add( + new DebugItem + { + Url = file_name, + Data = context.SdbAgent.GetBytesFromAssemblyAndPdb(Path.GetFileName(file_name), token) + }); + } + catch (Exception e) + { + logger.LogDebug($"Failed to read {file_name} ({e.Message})"); + } } } @@ -1405,6 +1430,11 @@ public async IAsyncEnumerable Load(SessionId id, string[] loaded_fil try { byte[][] bytes = await step.Data.ConfigureAwait(false); + if (bytes[0] == null) + { + logger.LogDebug($"Bytes from assembly {step.Url} is NULL"); + continue; + } assembly = new AssemblyInfo(monoProxy, id, step.Url, bytes[0], bytes[1], logger, token); } catch (Exception e) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index d81bb825b467b5..4ddddec96cb8db 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -1509,7 +1509,12 @@ internal async Task LoadStore(SessionId sessionId, CancellationToken } else { - await foreach (SourceFile source in context.store.Load(sessionId, loaded_files, token).WithCancellation(token)) + var useDebuggerProtocol = false; + (int MajorVersion, int MinorVersion) = await context.SdbAgent.GetVMVersion(token); + if (MajorVersion == 2 && MinorVersion >= 61) + useDebuggerProtocol = true; + + await foreach (SourceFile source in context.store.Load(sessionId, loaded_files, context, useDebuggerProtocol, token)) { await OnSourceFileAdded(sessionId, source, context, token); } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index a95715a4ef19a0..1ee180fadb73e1 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -140,7 +140,8 @@ internal enum CmdVM { VmReadMemory = 16, VmWriteMemory = 17, GetAssemblyByName = 18, - GetModuleByGUID = 19 + GetModuleByGUID = 19, + GetAssemblyAndPdbBytes = 20 } internal enum CmdFrame { @@ -750,6 +751,9 @@ internal sealed class MonoSDBHelper private static int MINOR_VERSION = 61; private static int MAJOR_VERSION = 2; + private int VmMinorVersion { get; set; } + private int VmMajorVersion { get; set; } + private Dictionary methods; private Dictionary assemblies; private Dictionary types; @@ -770,6 +774,8 @@ public MonoSDBHelper(MonoProxy proxy, ILogger logger, SessionId sessionId) this.proxy = proxy; this.logger = logger; this.sessionId = sessionId; + this.VmMajorVersion = -1; + this.VmMinorVersion = -1; ValueCreator = new(this, logger); ResetStore(null); } @@ -883,6 +889,18 @@ public async Task GetTypeInfo(int typeId, Cancella public void ClearCache() => ValueCreator.ClearCache(); + public async Task<(int, int)> GetVMVersion(CancellationToken token) + { + if (VmMajorVersion != -1) + return (VmMajorVersion, VmMinorVersion); + using var commandParamsWriter = new MonoBinaryWriter(); + using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdVM.Version, commandParamsWriter, token); + retDebuggerCmdReader.ReadString(); //vm version + VmMajorVersion = retDebuggerCmdReader.ReadInt32(); + VmMinorVersion = retDebuggerCmdReader.ReadInt32(); + return (VmMajorVersion, VmMinorVersion); + } + public async Task SetProtocolVersion(CancellationToken token) { using var commandParamsWriter = new MonoBinaryWriter(); @@ -2128,6 +2146,24 @@ public async Task ApplyUpdates(int moduleId, string dmeta, string dil, str return true; } + public async Task GetBytesFromAssemblyAndPdb(string assemblyName, CancellationToken token) + { + using var commandParamsWriter = new MonoBinaryWriter(); + byte[] assembly_buf = null; + byte[] pdb_buf = null; + commandParamsWriter.Write(assemblyName); + var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdVM.GetAssemblyAndPdbBytes, commandParamsWriter, token); + int assembly_size = retDebuggerCmdReader.ReadInt32(); + if (assembly_size > 0) + assembly_buf = retDebuggerCmdReader.ReadBytes(assembly_size); + int pdb_size = retDebuggerCmdReader.ReadInt32(); + if (pdb_size > 0) + pdb_buf = retDebuggerCmdReader.ReadBytes(pdb_size); + byte[][] ret = new byte[2][]; + ret[0] = assembly_buf; + ret[1] = pdb_buf; + return ret; + } private static readonly string[] s_primitiveTypeNames = new[] { "bool", diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 2a30682885e7cd..fb0b15101fdd33 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -238,6 +238,24 @@ mono_wasm_assembly_already_added (const char *assembly_name) return 0; } +const unsigned char * +mono_wasm_get_assembly_bytes (const char *assembly_name, unsigned int *size) +{ + if (assembly_count == 0) + return 0; + + WasmAssembly *entry = assemblies; + while (entry != NULL) { + if (strcmp (entry->assembly.name, assembly_name) == 0) + { + *size = entry->assembly.size; + return entry->assembly.data; + } + entry = entry->next; + } + return NULL; +} + typedef struct WasmSatelliteAssembly_ WasmSatelliteAssembly; struct WasmSatelliteAssembly_ { diff --git a/src/native/public/mono/metadata/details/assembly-functions.h b/src/native/public/mono/metadata/details/assembly-functions.h index 4634ba4046a0f5..df752b66956193 100644 --- a/src/native/public/mono/metadata/details/assembly-functions.h +++ b/src/native/public/mono/metadata/details/assembly-functions.h @@ -64,6 +64,7 @@ MONO_API_FUNCTION(MONO_RT_EXTERNAL_ONLY void, mono_assembly_name_free, (MonoAsse MONO_API_FUNCTION(void, mono_register_bundled_assemblies, (const MonoBundledAssembly **assemblies)) MONO_API_FUNCTION(void, mono_register_symfile_for_assembly, (const char* assembly_name, const mono_byte *raw_contents, int size)) +MONO_API_FUNCTION(const mono_byte *, mono_get_symfile_bytes_from_bundle, (const char* assembly_name, int *size)) MONO_API_FUNCTION(void, mono_set_assemblies_path, (const char* path))