Skip to content

Commit

Permalink
[wasm][debugger] Implement get bytes from loaded_files using debugger…
Browse files Browse the repository at this point in the history
… 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 <[email protected]>
  • Loading branch information
thaystg and radical authored Jun 14, 2022
1 parent 261574b commit 56e58d3
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 26 deletions.
5 changes: 3 additions & 2 deletions src/mono/mono/component/debugger-protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

#define MAJOR_VERSION 2
#define MINOR_VERSION 60
#define MINOR_VERSION 61

typedef enum {
MDBGPROT_CMD_COMPOSITE = 100
Expand All @@ -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 {
Expand Down
18 changes: 18 additions & 0 deletions src/mono/mono/component/mini-wasm-debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
13 changes: 13 additions & 0 deletions src/mono/mono/metadata/mono-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/mini/mini-wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
74 changes: 52 additions & 22 deletions src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1366,36 +1366,61 @@ public IEnumerable<SourceFile> Add(SessionId id, string name, byte[] assembly_da
}
}

public async IAsyncEnumerable<SourceFile> Load(SessionId id, string[] loaded_files, [EnumeratorCancellation] CancellationToken token)
public async IAsyncEnumerable<SourceFile> Load(SessionId id, string[] loaded_files, ExecutionContext context, bool useDebuggerProtocol, [EnumeratorCancellation] CancellationToken token)
{
var asm_files = new List<string>();
var pdb_files = new List<string>();
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<DebugItem> steps = new List<DebugItem>();
foreach (string url in asm_files)

if (!useDebuggerProtocol)
{
try
var pdb_files = new List<string>();
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<byte[]>(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<byte[]>(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})");
}
}
}

Expand All @@ -1405,6 +1430,11 @@ public async IAsyncEnumerable<SourceFile> 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)
Expand Down
7 changes: 6 additions & 1 deletion src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1509,7 +1509,12 @@ internal async Task<DebugStore> 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);
}
Expand Down
38 changes: 37 additions & 1 deletion src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ internal enum CmdVM {
VmReadMemory = 16,
VmWriteMemory = 17,
GetAssemblyByName = 18,
GetModuleByGUID = 19
GetModuleByGUID = 19,
GetAssemblyAndPdbBytes = 20
}

internal enum CmdFrame {
Expand Down Expand Up @@ -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<int, MethodInfoWithDebugInformation> methods;
private Dictionary<int, AssemblyInfo> assemblies;
private Dictionary<int, TypeInfoWithDebugInformation> types;
Expand All @@ -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);
}
Expand Down Expand Up @@ -883,6 +889,18 @@ public async Task<TypeInfoWithDebugInformation> 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<bool> SetProtocolVersion(CancellationToken token)
{
using var commandParamsWriter = new MonoBinaryWriter();
Expand Down Expand Up @@ -2128,6 +2146,24 @@ public async Task<bool> ApplyUpdates(int moduleId, string dmeta, string dil, str
return true;
}

public async Task<byte[][]> 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",
Expand Down
18 changes: 18 additions & 0 deletions src/mono/wasm/runtime/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_ {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down

0 comments on commit 56e58d3

Please sign in to comment.