Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm] debug with modularized runtime(s) #61848

Merged
merged 7 commits into from
Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 10 additions & 23 deletions src/mono/mono/component/mini-wasm-debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ static gboolean has_pending_lazy_loaded_assemblies;

#define THREAD_TO_INTERNAL(thread) (thread)->internal_thread

extern void mono_wasm_debugger_log (int level, char *message);

void wasm_debugger_log (int level, const gchar *format, ...)
{
va_list args;
Expand All @@ -62,19 +64,7 @@ void wasm_debugger_log (int level, const gchar *format, ...)
va_start (args, format);
mesg = g_strdup_vprintf (format, args);
va_end (args);

EM_ASM ({
var level = $0;
var message = Module.UTF8ToString ($1);
var namespace = "Debugger.Debug";

if (INTERNAL["logging"] && INTERNAL.logging["debugger"]) {
INTERNAL.logging.debugger (level, message);
return;
}

console.debug("%s: %s", namespace, message);
}, level, mesg);
mono_wasm_debugger_log(level, mesg);
g_free (mesg);
}

Expand Down Expand Up @@ -367,16 +357,16 @@ mono_wasm_set_is_debugger_attached (gboolean is_attached)
}
}

extern void mono_wasm_add_dbg_command_received(mono_bool res_ok, int id, void* buffer, int buffer_len);

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size, int valtype, char* newvalue)
{
MdbgProtBuffer bufWithParms;
buffer_init (&bufWithParms, 128);
m_dbgprot_buffer_add_data (&bufWithParms, data, size);
if (!write_value_to_buffer(&bufWithParms, valtype, newvalue)) {
EM_ASM ({
INTERNAL.mono_wasm_add_dbg_command_received ($0, $1, $2, $3);
}, 0, id, 0, 0);
mono_wasm_add_dbg_command_received(0, id, 0, 0);
return TRUE;
}
mono_wasm_send_dbg_command(id, command_set, command, bufWithParms.buf, m_dbgprot_buffer_len(&bufWithParms));
Expand All @@ -402,20 +392,17 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command,
}
else
error = mono_process_dbg_packet (id, command_set, command, &no_reply, data, data + size, &buf);
EM_ASM ({
INTERNAL.mono_wasm_add_dbg_command_received ($0, $1, $2, $3);
}, error == MDBGPROT_ERR_NONE, id, buf.buf, buf.p-buf.buf);


mono_wasm_add_dbg_command_received(error == MDBGPROT_ERR_NONE, id, buf.buf, buf.p-buf.buf);

buffer_free (&buf);
return TRUE;
}

static gboolean
receive_debugger_agent_message (void *data, int len)
{
EM_ASM ({
INTERNAL.mono_wasm_add_dbg_command_received (1, -1, $0, $1);
}, data, len);
mono_wasm_add_dbg_command_received(1, -1, data, len);
mono_wasm_save_thread_context();
mono_wasm_fire_debugger_agent_message ();
return FALSE;
Expand Down
8 changes: 7 additions & 1 deletion src/mono/wasm/debugger/BrowserDebugHost/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ async Task ConnectProxy(HttpContext context)
}

var endpoint = new Uri($"ws://{devToolsHost.Authority}{context.Request.Path}");
int runtimeId = 0;
if (context.Request.Query.TryGetValue("RuntimeId", out var runtimeIdValue))
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved
{
int.TryParse(runtimeIdValue.First(), out runtimeId);
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved
}

try
{
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
Expand All @@ -159,7 +165,7 @@ async Task ConnectProxy(HttpContext context)
);

context.Request.Query.TryGetValue("urlSymbolServer", out StringValues urlSymbolServerList);
var proxy = new DebuggerProxy(loggerFactory, urlSymbolServerList.ToList());
var proxy = new DebuggerProxy(loggerFactory, urlSymbolServerList.ToList(), runtimeId);

System.Net.WebSockets.WebSocket ideSocket = await context.WebSockets.AcceptWebSocketAsync();

Expand Down
4 changes: 2 additions & 2 deletions src/mono/wasm/debugger/BrowserDebugProxy/DebuggerProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public class DebuggerProxy
{
private readonly MonoProxy proxy;

public DebuggerProxy(ILoggerFactory loggerFactory, IList<string> urlSymbolServerList)
public DebuggerProxy(ILoggerFactory loggerFactory, IList<string> urlSymbolServerList, int runtimeId = 0)
{
proxy = new MonoProxy(loggerFactory, urlSymbolServerList);
proxy = new MonoProxy(loggerFactory, urlSymbolServerList, runtimeId);
}

public Task Run(Uri browserUri, WebSocket ideSocket)
Expand Down
24 changes: 12 additions & 12 deletions src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,31 +172,31 @@ internal class MonoCommands

public MonoCommands(string expression) => this.expression = expression;

public static MonoCommands GetDebuggerAgentBufferReceived() => new MonoCommands("INTERNAL.mono_wasm_get_dbg_command_info()");
public static MonoCommands GetDebuggerAgentBufferReceived(int runtimeId) => new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_get_dbg_command_info()");

public static MonoCommands IsRuntimeReady() => new MonoCommands("INTERNAL.mono_wasm_runtime_is_ready");
public static MonoCommands IsRuntimeReady(int runtimeId) => new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_runtime_is_ready");

public static MonoCommands GetLoadedFiles() => new MonoCommands("INTERNAL.mono_wasm_get_loaded_files()");
public static MonoCommands GetLoadedFiles(int runtimeId) => new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_get_loaded_files()");

public static MonoCommands SendDebuggerAgentCommand(int id, int command_set, int command, string command_parameters)
public static MonoCommands SendDebuggerAgentCommand(int runtimeId, int id, int command_set, int command, string command_parameters)
{
return new MonoCommands($"INTERNAL.mono_wasm_send_dbg_command ({id}, {command_set}, {command},'{command_parameters}')");
return new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_send_dbg_command ({id}, {command_set}, {command},'{command_parameters}')");
}

public static MonoCommands SendDebuggerAgentCommandWithParms(int id, int command_set, int command, string command_parameters, int len, int type, string parm)
public static MonoCommands SendDebuggerAgentCommandWithParms(int runtimeId, int id, int command_set, int command, string command_parameters, int len, int type, string parm)
{
return new MonoCommands($"INTERNAL.mono_wasm_send_dbg_command_with_parms ({id}, {command_set}, {command},'{command_parameters}', {len}, {type}, '{parm}')");
return new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_send_dbg_command_with_parms ({id}, {command_set}, {command},'{command_parameters}', {len}, {type}, '{parm}')");
}

public static MonoCommands CallFunctionOn(JToken args) => new MonoCommands($"INTERNAL.mono_wasm_call_function_on ({args})");
public static MonoCommands CallFunctionOn(int runtimeId, JToken args) => new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_call_function_on ({args})");

public static MonoCommands GetDetails(int objectId, JToken args = null) => new MonoCommands($"INTERNAL.mono_wasm_get_details ({objectId}, {(args ?? "{ }")})");
public static MonoCommands GetDetails(int runtimeId, int objectId, JToken args = null) => new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_get_details ({objectId}, {(args ?? "{ }")})");

public static MonoCommands Resume() => new MonoCommands($"INTERNAL.mono_wasm_debugger_resume ()");
public static MonoCommands Resume(int runtimeId) => new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_debugger_resume ()");

public static MonoCommands DetachDebugger() => new MonoCommands($"INTERNAL.mono_wasm_detach_debugger()");
public static MonoCommands DetachDebugger(int runtimeId) => new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_detach_debugger()");

public static MonoCommands ReleaseObject(DotnetObjectId objectId) => new MonoCommands($"INTERNAL.mono_wasm_release_object('{objectId}')");
public static MonoCommands ReleaseObject(int runtimeId, DotnetObjectId objectId) => new MonoCommands($"getDotnetRuntime({runtimeId}).INTERNAL.mono_wasm_release_object('{objectId}')");
}

internal enum MonoErrorCodes
Expand Down
27 changes: 15 additions & 12 deletions src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ internal class MonoProxy : DevToolsProxy
private Dictionary<SessionId, ExecutionContext> contexts = new Dictionary<SessionId, ExecutionContext>();
private const string sPauseOnUncaught = "pause_on_uncaught";
private const string sPauseOnCaught = "pause_on_caught";
// index of the runtime in a same JS page/process
public int RuntimeId { get; private set; }
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved

public MonoProxy(ILoggerFactory loggerFactory, IList<string> urlSymbolServerList) : base(loggerFactory)
public MonoProxy(ILoggerFactory loggerFactory, IList<string> urlSymbolServerList, int runtimeId = 0) : base(loggerFactory)
{
this.urlSymbolServerList = urlSymbolServerList ?? new List<string>();
RuntimeId = runtimeId;
}

internal ExecutionContext GetContext(SessionId sessionId)
Expand Down Expand Up @@ -223,7 +226,7 @@ protected override async Task<bool> AcceptEvent(SessionId sessionId, string meth

case "Target.targetDestroyed":
{
await SendMonoCommand(sessionId, MonoCommands.DetachDebugger(), token);
await SendMonoCommand(sessionId, MonoCommands.DetachDebugger(RuntimeId), token);
break;
}
}
Expand All @@ -236,7 +239,7 @@ private async Task<bool> IsRuntimeAlreadyReadyAlready(SessionId sessionId, Cance
if (contexts.TryGetValue(sessionId, out ExecutionContext context) && context.IsRuntimeReady)
return true;

Result res = await SendMonoCommand(sessionId, MonoCommands.IsRuntimeReady(), token);
Result res = await SendMonoCommand(sessionId, MonoCommands.IsRuntimeReady(RuntimeId), token);
return res.Value?["result"]?["value"]?.Value<bool>() ?? false;
}

Expand Down Expand Up @@ -434,7 +437,7 @@ protected override async Task<bool> AcceptCommand(MessageId id, string method, J
if (!(DotnetObjectId.TryParse(args["objectId"], out DotnetObjectId objectId) && objectId.Scheme == "cfo_res"))
break;

await SendMonoCommand(id, MonoCommands.ReleaseObject(objectId), token);
await SendMonoCommand(id, MonoCommands.ReleaseObject(RuntimeId, objectId), token);
SendResponse(id, Result.OkFromObject(new { }), token);
return true;
}
Expand Down Expand Up @@ -558,7 +561,7 @@ private async Task<bool> CallOnFunction(MessageId id, JObject args, Cancellation
break;
case "cfo_res":
{
Result cfo_res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token);
Result cfo_res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(RuntimeId, args), token);
cfo_res = Result.OkFromObject(new { result = cfo_res.Value?["result"]?["value"]});
SendResponse(id, cfo_res, token);
return true;
Expand All @@ -574,7 +577,7 @@ private async Task<bool> CallOnFunction(MessageId id, JObject args, Cancellation
default:
return false;
}
Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token);
Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(RuntimeId, args), token);
if (res.IsErr)
{
SendResponse(id, res, token);
Expand Down Expand Up @@ -652,7 +655,7 @@ internal async Task<JToken> RuntimeGetPropertiesInternal(SessionId id, DotnetObj
return new JArray{await context.SdbAgent.GetPointerContent(int.Parse(objectId.Value), token)};
case "cfo_res":
{
Result res = await SendMonoCommand(id, MonoCommands.GetDetails(int.Parse(objectId.Value), args), token);
Result res = await SendMonoCommand(id, MonoCommands.GetDetails(RuntimeId, int.Parse(objectId.Value), args), token);
string value_json_str = res.Value["result"]?["value"]?["__value_as_json_string__"]?.Value<string>();
return value_json_str != null ? JArray.Parse(value_json_str) : null;
}
Expand Down Expand Up @@ -831,7 +834,7 @@ private async Task<bool> SendCallStack(SessionId sessionId, ExecutionContext con
}
private async Task<bool> OnReceiveDebuggerAgentEvent(SessionId sessionId, JObject args, CancellationToken token)
{
Result res = await SendMonoCommand(sessionId, MonoCommands.GetDebuggerAgentBufferReceived(), token);
Result res = await SendMonoCommand(sessionId, MonoCommands.GetDebuggerAgentBufferReceived(RuntimeId), token);
if (res.IsErr)
return false;

Expand Down Expand Up @@ -966,11 +969,11 @@ private async Task OnDefaultContext(SessionId sessionId, ExecutionContext contex

private async Task OnResume(MessageId msg_id, CancellationToken token)
{
ExecutionContext ctx = GetContext(msg_id);
if (ctx.CallStack != null)
ExecutionContext context = GetContext(msg_id);
if (context.CallStack != null)
{
// Stopped on managed code
await SendMonoCommand(msg_id, MonoCommands.Resume(), token);
await SendMonoCommand(msg_id, MonoCommands.Resume(RuntimeId), token);
}

//discard managed frames
Expand Down Expand Up @@ -1187,7 +1190,7 @@ internal async Task<DebugStore> LoadStore(SessionId sessionId, CancellationToken

if (loaded_files == null)
{
Result loaded = await SendMonoCommand(sessionId, MonoCommands.GetLoadedFiles(), token);
Result loaded = await SendMonoCommand(sessionId, MonoCommands.GetLoadedFiles(RuntimeId), token);
loaded_files = loaded.Value?["result"]?["value"]?.ToObject<string[]>();
}

Expand Down
4 changes: 2 additions & 2 deletions src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ public async Task<bool> EnableReceiveRequests(EventKind eventKind, CancellationT
}

internal async Task<MonoBinaryReader> SendDebuggerAgentCommand<T>(T command, MonoBinaryWriter arguments, CancellationToken token) =>
MonoBinaryReader.From (await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(GetId(), (int)GetCommandSetForCommand(command), (int)(object)command, arguments?.ToBase64().data ?? string.Empty), token));
MonoBinaryReader.From (await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommand(proxy.RuntimeId, GetId(), (int)GetCommandSetForCommand(command), (int)(object)command, arguments?.ToBase64().data ?? string.Empty), token));

internal CommandSet GetCommandSetForCommand<T>(T command) =>
command switch {
Expand All @@ -882,7 +882,7 @@ internal CommandSet GetCommandSetForCommand<T>(T command) =>
};

internal async Task<MonoBinaryReader> SendDebuggerAgentCommandWithParms<T>(T command, (string data, int length) encoded, int type, string extraParm, CancellationToken token) =>
MonoBinaryReader.From(await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommandWithParms(GetId(), (int)GetCommandSetForCommand(command), (int)(object)command, encoded.data, encoded.length, type, extraParm), token));
MonoBinaryReader.From(await proxy.SendMonoCommand(sessionId, MonoCommands.SendDebuggerAgentCommandWithParms(proxy.RuntimeId, GetId(), (int)GetCommandSetForCommand(command), (int)(object)command, encoded.data, encoded.length, type, extraParm), token));

public async Task<int> CreateString(string value, CancellationToken token)
{
Expand Down
14 changes: 7 additions & 7 deletions src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async Task CreateJSBreakpoint()
{
// Test that js breakpoints get set correctly
// 13 24
// 13 33
// 13 53
var bp1_res = await SetBreakpoint("/debugger-driver.html", 13, 24);

Assert.EndsWith("debugger-driver.html", bp1_res.Value["breakpointId"].ToString());
Expand All @@ -48,7 +48,7 @@ public async Task CreateJSBreakpoint()
Assert.Equal(13, (int)loc["lineNumber"]);
Assert.Equal(24, (int)loc["columnNumber"]);

var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 33);
var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 53);

Assert.EndsWith("debugger-driver.html", bp2_res.Value["breakpointId"].ToString());
Assert.Equal(1, bp2_res.Value["locations"]?.Value<JArray>()?.Count);
Expand All @@ -57,14 +57,14 @@ public async Task CreateJSBreakpoint()

Assert.NotNull(loc2["scriptId"]);
Assert.Equal(13, (int)loc2["lineNumber"]);
Assert.Equal(33, (int)loc2["columnNumber"]);
Assert.Equal(53, (int)loc2["columnNumber"]);
}

[Fact]
public async Task CreateJS0Breakpoint()
{
// 13 24
// 13 33
// 13 53
var bp1_res = await SetBreakpoint("/debugger-driver.html", 13, 0);

Assert.EndsWith("debugger-driver.html", bp1_res.Value["breakpointId"].ToString());
Expand All @@ -74,9 +74,9 @@ public async Task CreateJS0Breakpoint()

Assert.NotNull(loc["scriptId"]);
Assert.Equal(13, (int)loc["lineNumber"]);
Assert.Equal(24, (int)loc["columnNumber"]);
Assert.Equal(4, (int)loc["columnNumber"]);
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved

var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 33);
var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 53);

Assert.EndsWith("debugger-driver.html", bp2_res.Value["breakpointId"].ToString());
Assert.Equal(1, bp2_res.Value["locations"]?.Value<JArray>()?.Count);
Expand All @@ -85,7 +85,7 @@ public async Task CreateJS0Breakpoint()

Assert.NotNull(loc2["scriptId"]);
Assert.Equal(13, (int)loc2["lineNumber"]);
Assert.Equal(33, (int)loc2["columnNumber"]);
Assert.Equal(53, (int)loc2["columnNumber"]);
}

[Theory]
Expand Down
Loading