async Task OnResume(MessageId msd_id, CancellationToken token) { //discard managed frames GetContext(msd_id).ClearState(); await Task.CompletedTask; }
internal async Task <JToken> TryGetVariableValue(MessageId msg_id, int scope_id, string expression, bool only_search_on_this, CancellationToken token) { JToken thisValue = null; var context = GetContext(msg_id); if (context.CallStack == null) { return(null); } if (TryFindVariableValueInCache(context, expression, only_search_on_this, out JToken obj)) { return(obj); } var scope = context.CallStack.FirstOrDefault(s => s.Id == scope_id); var vars = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); //get_this int [] var_ids = { }; var res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, var_ids), token); var values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); thisValue = values.FirstOrDefault(v => v ["name"].Value <string> () == "this"); if (!only_search_on_this) { if (thisValue != null && expression == "this") { return(thisValue); } //search in locals var var_id = vars.SingleOrDefault(v => v.Name == expression); if (var_id != null) { res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, new int [] { var_id.Index }), token); values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); return(values [0]); } } //search in scope if (thisValue != null) { var objectId = thisValue ["value"] ["objectId"].Value <string> (); var parts = objectId.Split(new char [] { ':' }); res = await SendMonoCommand(msg_id, MonoCommands.GetObjectProperties(int.Parse(parts [2]), expandValueTypes: false), token); values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); var foundValue = values.FirstOrDefault(v => v ["name"].Value <string> () == expression); if (foundValue != null) { foundValue["fromThis"] = true; context.LocalsCache[foundValue ["name"].Value <string> ()] = foundValue; return(foundValue); } } return(null); }
void OnCompileDotnetScript(MessageId msg_id, CancellationToken token) { SendResponse(msg_id, Result.OkFromObject(new { }), token); }
protected override async Task <bool> AcceptCommand(MessageId id, string method, JObject args, CancellationToken token) { // Inspector doesn't use the Target domain or sessions // so we try to init immediately if (hideWebDriver && id == SessionId.Null) { await DeleteWebDriver(id, token); } if (!contexts.TryGetValue(id, out var context)) { return(false); } switch (method) { case "Target.attachToTarget": { var resp = await SendCommand(id, method, args, token); await DeleteWebDriver(new SessionId (resp.Value ["sessionId"]?.ToString()), token); break; } case "Debugger.enable": { var resp = await SendCommand(id, method, args, token); context.DebuggerId = resp.Value ["debuggerId"]?.ToString(); if (await IsRuntimeAlreadyReadyAlready(id, token)) { await RuntimeReady(id, token); } SendResponse(id, resp, token); return(true); } case "Debugger.getScriptSource": { var script = args? ["scriptId"]?.Value <string> (); return(await OnGetScriptSource(id, script, token)); } case "Runtime.compileScript": { var exp = args? ["expression"]?.Value <string> (); if (exp.StartsWith("//dotnet:", StringComparison.Ordinal)) { OnCompileDotnetScript(id, token); return(true); } break; } case "Debugger.getPossibleBreakpoints": { var resp = await SendCommand(id, method, args, token); if (resp.IsOk && resp.Value["locations"].HasValues) { SendResponse(id, resp, token); return(true); } var start = SourceLocation.Parse(args? ["start"] as JObject); //FIXME support variant where restrictToFunction=true and end is omitted var end = SourceLocation.Parse(args? ["end"] as JObject); if (start != null && end != null && await GetPossibleBreakpoints(id, start, end, token)) { return(true); } SendResponse(id, resp, token); return(true); } case "Debugger.setBreakpoint": { break; } case "Debugger.setBreakpointByUrl": { var resp = await SendCommand(id, method, args, token); if (!resp.IsOk) { SendResponse(id, resp, token); return(true); } var bpid = resp.Value["breakpointId"]?.ToString(); var request = BreakpointRequest.Parse(bpid, args); context.BreakpointRequests[bpid] = request; if (await IsRuntimeAlreadyReadyAlready(id, token)) { var store = await RuntimeReady(id, token); Log("verbose", $"BP req {args}"); await SetBreakpoint(id, store, request, token); } SendResponse(id, Result.OkFromObject(request.AsSetBreakpointByUrlResponse()), token); return(true); } case "Debugger.removeBreakpoint": { await RemoveBreakpoint(id, args, token); break; } case "Debugger.resume": { await OnResume(id, token); break; } case "Debugger.stepInto": { return(await Step(id, StepKind.Into, token)); } case "Debugger.stepOut": { return(await Step(id, StepKind.Out, token)); } case "Debugger.stepOver": { return(await Step(id, StepKind.Over, token)); } case "Debugger.evaluateOnCallFrame": { var objId = args? ["callFrameId"]?.Value <string> (); if (objId.StartsWith("dotnet:", StringComparison.Ordinal)) { var parts = objId.Split(new char [] { ':' }); if (parts.Length < 3) { return(true); } switch (parts [1]) { case "scope": { await GetEvaluateOnCallFrame(id, int.Parse(parts [2]), args? ["expression"]?.Value <string> (), token); break; } } return(true); } return(false); } case "Runtime.getProperties": { var objId = args? ["objectId"]?.Value <string> (); if (objId.StartsWith("dotnet:", StringComparison.Ordinal)) { var parts = objId.Split(new char [] { ':' }); if (parts.Length < 3) { return(true); } switch (parts[1]) { case "scope": { await GetScopeProperties(id, int.Parse(parts[2]), token); break; } case "object": { await GetDetails(id, MonoCommands.GetObjectProperties(int.Parse(parts[2]), expandValueTypes: false), token); break; } case "array": { await GetArrayDetails(id, objId, parts, token); break; } case "valuetype": { await GetDetailsForValueType(id, objId, get_props_cmd_fn : () => { if (parts.Length < 4) { return(null); } var containerObjId = int.Parse(parts[2]); return(MonoCommands.GetObjectProperties(containerObjId, expandValueTypes: true)); }, token); break; } } return(true); } break; } // Protocol extensions case "Dotnet-test.setBreakpointByMethod": { Console.WriteLine("set-breakpoint-by-method: " + id + " " + args); var store = await RuntimeReady(id, token); string aname = args ["assemblyName"]?.Value <string> (); string typeName = args ["typeName"]?.Value <string> (); string methodName = args ["methodName"]?.Value <string> (); if (aname == null || typeName == null || methodName == null) { SendResponse(id, Result.Err("Invalid protocol message '" + args + "'."), token); return(true); } // GetAssemblyByName seems to work on file names var assembly = store.GetAssemblyByName(aname); if (assembly == null) { assembly = store.GetAssemblyByName(aname + ".exe"); } if (assembly == null) { assembly = store.GetAssemblyByName(aname + ".dll"); } if (assembly == null) { SendResponse(id, Result.Err("Assembly '" + aname + "' not found."), token); return(true); } var type = assembly.GetTypeByName(typeName); if (type == null) { SendResponse(id, Result.Err($"Type '{typeName}' not found."), token); return(true); } var methodInfo = type.Methods.FirstOrDefault(m => m.Name == methodName); if (methodInfo == null) { SendResponse(id, Result.Err($"Method '{typeName}:{methodName}' not found."), token); return(true); } bpIdGenerator++; string bpid = "by-method-" + bpIdGenerator.ToString(); var request = new BreakpointRequest(bpid, methodInfo); context.BreakpointRequests[bpid] = request; var loc = methodInfo.StartLocation; var bp = await SetMonoBreakpoint(id, bpid, loc, token); if (bp.State != BreakpointState.Active) { // FIXME: throw new NotImplementedException(); } var resolvedLocation = new { breakpointId = bpid, location = loc.AsLocation() }; SendEvent(id, "Debugger.breakpointResolved", JObject.FromObject(resolvedLocation), token); SendResponse(id, Result.OkFromObject(new { result = new { breakpointId = bpid, locations = new object [] { loc.AsLocation() } } }), token); return(true); } } return(false); }
internal void SendResponse(MessageId id, Result result, CancellationToken token) { SendResponseInternal(id, result, token); }
protected virtual Task <bool> AcceptCommand(MessageId id, string method, JObject args, CancellationToken token) { return(Task.FromResult(false)); }
async Task GetScopeProperties(MessageId msg_id, int scope_id, CancellationToken token) { try { var scope = GetContext(msg_id).CallStack.FirstOrDefault(s => s.Id == scope_id); var vars = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); var var_ids = vars.Select(v => v.Index).ToArray(); var res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, var_ids), token); //if we fail we just buble that to the IDE (and let it panic over it) if (res.IsErr) { SendResponse(msg_id, res, token); return; } var values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); if (values == null) { SendResponse(msg_id, Result.OkFromObject(new { result = Array.Empty <object> () }), token); return; } var var_list = new List <object> (); int i = 0; // Trying to inspect the stack frame for DotNetDispatcher::InvokeSynchronously // results in a "Memory access out of bounds", causing 'values' to be null, // so skip returning variable values in that case. while (i < vars.Length && i < values.Length) { var value = values [i] ["value"]; if (((string)value ["description"]) == null) { value ["description"] = value ["value"]?.ToString(); } var_list.Add(new { name = vars [i].Name, value }); i++; } //Async methods are special in the way that local variables can be lifted to generated class fields //value of "this" comes here either while (i < values.Length) { String name = values [i] ["name"].ToString(); if (name.IndexOf(">", StringComparison.Ordinal) > 0) { name = name.Substring(1, name.IndexOf(">", StringComparison.Ordinal) - 1); } var value = values [i + 1] ["value"]; if (((string)value ["description"]) == null) { value ["description"] = value ["value"]?.ToString(); } var_list.Add(new { name, value }); i = i + 2; } SendResponse(msg_id, Result.OkFromObject(new { result = var_list }), token); } catch (Exception exception) { Log("verbose", $"Error resolving scope properties {exception.Message}"); SendResponse(msg_id, Result.Exception(exception), token); } }
protected override async Task <bool> AcceptCommand(MessageId id, string method, JObject args, CancellationToken token) { if (!contexts.TryGetValue(id, out var context)) { return(false); } switch (method) { case "Debugger.enable": { var resp = await SendCommand(id, method, args, token); context.DebuggerId = resp.Value ["debuggerId"]?.ToString(); if (await IsRuntimeAlreadyReadyAlready(id, token)) { await RuntimeReady(id, token); } SendResponse(id, resp, token); return(true); } case "Debugger.getScriptSource": { var script = args? ["scriptId"]?.Value <string> (); return(await OnGetScriptSource(id, script, token)); } case "Runtime.compileScript": { var exp = args? ["expression"]?.Value <string> (); if (exp.StartsWith("//dotnet:", StringComparison.Ordinal)) { OnCompileDotnetScript(id, token); return(true); } break; } case "Debugger.getPossibleBreakpoints": { var resp = await SendCommand(id, method, args, token); if (resp.IsOk && resp.Value["locations"].HasValues) { SendResponse(id, resp, token); return(true); } var start = SourceLocation.Parse(args? ["start"] as JObject); //FIXME support variant where restrictToFunction=true and end is omitted var end = SourceLocation.Parse(args? ["end"] as JObject); if (start != null && end != null && await GetPossibleBreakpoints(id, start, end, token)) { return(true); } SendResponse(id, resp, token); return(true); } case "Debugger.setBreakpoint": { break; } case "Debugger.setBreakpointByUrl": { var resp = await SendCommand(id, method, args, token); if (!resp.IsOk) { SendResponse(id, resp, token); return(true); } var bpid = resp.Value["breakpointId"]?.ToString(); var request = BreakpointRequest.Parse(bpid, args); context.BreakpointRequests[bpid] = request; if (await IsRuntimeAlreadyReadyAlready(id, token)) { var store = await RuntimeReady(id, token); Log("verbose", $"BP req {args}"); await SetBreakpoint(id, store, request, token); } SendResponse(id, Result.OkFromObject(request.AsSetBreakpointByUrlResponse()), token); return(true); } case "Debugger.removeBreakpoint": { return(await RemoveBreakpoint(id, args, token)); } case "Debugger.resume": { await OnResume(id, token); break; } case "Debugger.stepInto": { return(await Step(id, StepKind.Into, token)); } case "Debugger.stepOut": { return(await Step(id, StepKind.Out, token)); } case "Debugger.stepOver": { return(await Step(id, StepKind.Over, token)); } case "Debugger.evaluateOnCallFrame": { var objId = args? ["callFrameId"]?.Value <string> (); if (objId.StartsWith("dotnet:", StringComparison.Ordinal)) { var parts = objId.Split(new char [] { ':' }); if (parts.Length < 3) { return(true); } switch (parts [1]) { case "scope": { await GetEvaluateOnCallFrame(id, int.Parse(parts [2]), args? ["expression"]?.Value <string> (), token); break; } } return(true); } return(false); } case "Runtime.getProperties": { var objId = args? ["objectId"]?.Value <string> (); if (objId.StartsWith("dotnet:", StringComparison.Ordinal)) { var parts = objId.Split(new char [] { ':' }); if (parts.Length < 3) { return(true); } switch (parts[1]) { case "scope": { await GetScopeProperties(id, int.Parse(parts[2]), token); break; } case "object": { await GetDetails(id, MonoCommands.GetObjectProperties(int.Parse(parts[2]), expandValueTypes: false), token); break; } case "array": { await GetArrayDetails(id, objId, parts, token); break; } case "valuetype": { await GetDetailsForValueType(id, objId, get_props_cmd_fn : () => { if (parts.Length < 4) { return(null); } var containerObjId = int.Parse(parts[2]); return(MonoCommands.GetObjectProperties(containerObjId, expandValueTypes: true)); }, token); break; } } return(true); } break; } } return(false); }
async Task OnGetScriptSource(MessageId msg_id, string script_id, CancellationToken token) { var id = new SourceId(script_id); var src_file = store.GetFileById(id); var res = new StringWriter(); //res.WriteLine ($"//{id}"); try { var uri = new Uri(src_file.Url); if (uri.IsFile && File.Exists(uri.LocalPath)) { using (var f = new StreamReader(File.Open(uri.LocalPath, FileMode.Open))) { await res.WriteAsync(await f.ReadToEndAsync()); } var o = JObject.FromObject(new { scriptSource = res.ToString() }); SendResponse(msg_id, Result.Ok(o), token); } else if (src_file.SourceUri.IsFile && File.Exists(src_file.SourceUri.LocalPath)) { using (var f = new StreamReader(File.Open(src_file.SourceUri.LocalPath, FileMode.Open))) { await res.WriteAsync(await f.ReadToEndAsync()); } var o = JObject.FromObject(new { scriptSource = res.ToString() }); SendResponse(msg_id, Result.Ok(o), token); } else if (src_file.SourceLinkUri != null) { var doc = await new WebClient().DownloadStringTaskAsync(src_file.SourceLinkUri); await res.WriteAsync(doc); var o = JObject.FromObject(new { scriptSource = res.ToString() }); SendResponse(msg_id, Result.Ok(o), token); } else { var o = JObject.FromObject(new { scriptSource = $"// Unable to find document {src_file.SourceUri}" }); SendResponse(msg_id, Result.Ok(o), token); } } catch (Exception e) { var o = JObject.FromObject(new { scriptSource = $"// Unable to read document ({e.Message})\n" + $"Local path: {src_file?.SourceUri}\n" + $"SourceLink path: {src_file?.SourceLinkUri}\n" }); SendResponse(msg_id, Result.Ok(o), token); } }
async Task GetScopeProperties(MessageId msg_id, int scope_id, CancellationToken token) { var scope = this.current_callstack.FirstOrDefault(s => s.Id == scope_id); var vars = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); var var_ids = string.Join(",", vars.Select(v => v.Index)); var o = JObject.FromObject(new { expression = string.Format(MonoCommands.GET_SCOPE_VARIABLES, scope.Id, var_ids), objectGroup = "mono_debugger", includeCommandLineAPI = false, silent = false, returnByValue = true, }); var res = await SendCommand(msg_id, "Runtime.evaluate", o, token); //if we fail we just buble that to the IDE (and let it panic over it) if (res.IsErr) { SendResponse(msg_id, res, token); return; } try { var values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); var var_list = new List <JObject> (); int i = 0; // Trying to inspect the stack frame for DotNetDispatcher::InvokeSynchronously // results in a "Memory access out of bounds", causing 'values' to be null, // so skip returning variable values in that case. while (values != null && i < vars.Length && i < values.Length) { var value = values [i] ["value"]; if (((string)value ["description"]) == null) { value ["description"] = value ["value"]?.ToString(); } var_list.Add(JObject.FromObject(new { name = vars [i].Name, value })); i++; } //Async methods are special in the way that local variables can be lifted to generated class fields //value of "this" comes here either while (i < values.Length) { String name = values [i] ["name"].ToString(); if (name.IndexOf(">", StringComparison.Ordinal) > 0) { name = name.Substring(1, name.IndexOf(">", StringComparison.Ordinal) - 1); } var value = values [i + 1] ["value"]; if (((string)value ["description"]) == null) { value ["description"] = value ["value"]?.ToString(); } var_list.Add(JObject.FromObject(new { name, value })); i = i + 2; } o = JObject.FromObject(new { result = var_list }); SendResponse(msg_id, Result.Ok(o), token); } catch (Exception exception) { Log("verbose", $"Error resolving scope properties {exception.Message}"); SendResponse(msg_id, res, token); } }
protected override async Task <bool> AcceptCommand(MessageId id, string method, JObject args, CancellationToken token) { switch (method) { case "Target.attachToTarget": { break; } case "Target.attachToBrowserTarget": { break; } case "Debugger.getScriptSource": { var script_id = args? ["scriptId"]?.Value <string> (); if (script_id.StartsWith("dotnet://", StringComparison.InvariantCultureIgnoreCase)) { await OnGetScriptSource(id, script_id, token); return(true); } break; } case "Runtime.compileScript": { var exp = args? ["expression"]?.Value <string> (); if (exp.StartsWith("//dotnet:", StringComparison.InvariantCultureIgnoreCase)) { OnCompileDotnetScript(id, token); return(true); } break; } case "Debugger.getPossibleBreakpoints": { var start = SourceLocation.Parse(args? ["start"] as JObject); //FIXME support variant where restrictToFunction=true and end is omitted var end = SourceLocation.Parse(args? ["end"] as JObject); if (start != null && end != null) { return(GetPossibleBreakpoints(id, start, end, token)); } break; } case "Debugger.setBreakpointByUrl": { Log("info", $"BP req {args}"); var bp_req = BreakPointRequest.Parse(args, store); if (bp_req != null) { await SetBreakPoint(id, bp_req, token); return(true); } break; } case "Debugger.removeBreakpoint": { return(await RemoveBreakpoint(id, args, token)); } case "Debugger.resume": { await OnResume(token); break; } case "Debugger.stepInto": { if (this.current_callstack != null) { await Step(id, StepKind.Into, token); return(true); } break; } case "Debugger.stepOut": { if (this.current_callstack != null) { await Step(id, StepKind.Out, token); return(true); } break; } case "Debugger.stepOver": { if (this.current_callstack != null) { await Step(id, StepKind.Over, token); return(true); } break; } case "Runtime.getProperties": { var objId = args? ["objectId"]?.Value <string> (); if (objId.StartsWith("dotnet:")) { var parts = objId.Split(new char [] { ':' }); if (parts.Length < 3) { return(true); } switch (parts[1]) { case "scope": { await GetScopeProperties(id, int.Parse(parts[2]), token); break; } case "object": { await GetDetails(id, int.Parse(parts[2]), token, MonoCommands.GET_OBJECT_PROPERTIES); break; } case "array": { await GetDetails(id, int.Parse(parts[2]), token, MonoCommands.GET_ARRAY_VALUES); break; } } return(true); } break; } } return(false); }
protected override async Task <bool> AcceptCommand(MessageId id, string method, JObject args, CancellationToken token) { // Inspector doesn't use the Target domain or sessions // so we try to init immediately if (hideWebDriver && id == SessionId.Null) { await DeleteWebDriver(id, token); } if (!contexts.TryGetValue(id, out var context)) { return(false); } switch (method) { case "Target.attachToTarget": { var resp = await SendCommand(id, method, args, token); await DeleteWebDriver(new SessionId (resp.Value ["sessionId"]?.ToString()), token); break; } case "Debugger.enable": { var resp = await SendCommand(id, method, args, token); context.DebuggerId = resp.Value ["debuggerId"]?.ToString(); if (await IsRuntimeAlreadyReadyAlready(id, token)) { await RuntimeReady(id, token); } SendResponse(id, resp, token); return(true); } case "Debugger.getScriptSource": { var script = args? ["scriptId"]?.Value <string> (); return(await OnGetScriptSource(id, script, token)); } case "Runtime.compileScript": { var exp = args? ["expression"]?.Value <string> (); if (exp.StartsWith("//dotnet:", StringComparison.Ordinal)) { OnCompileDotnetScript(id, token); return(true); } break; } case "Debugger.getPossibleBreakpoints": { var resp = await SendCommand(id, method, args, token); if (resp.IsOk && resp.Value["locations"].HasValues) { SendResponse(id, resp, token); return(true); } var start = SourceLocation.Parse(args? ["start"] as JObject); //FIXME support variant where restrictToFunction=true and end is omitted var end = SourceLocation.Parse(args? ["end"] as JObject); if (start != null && end != null && await GetPossibleBreakpoints(id, start, end, token)) { return(true); } SendResponse(id, resp, token); return(true); } case "Debugger.setBreakpoint": { break; } case "Debugger.setBreakpointByUrl": { var resp = await SendCommand(id, method, args, token); if (!resp.IsOk) { SendResponse(id, resp, token); return(true); } var bpid = resp.Value["breakpointId"]?.ToString(); var locations = resp.Value["locations"]?.Values <object>(); var request = BreakpointRequest.Parse(bpid, args); // is the store done loading? var loaded = context.Source.Task.IsCompleted; if (!loaded) { // Send and empty response immediately if not // and register the breakpoint for resolution context.BreakpointRequests [bpid] = request; SendResponse(id, resp, token); } if (await IsRuntimeAlreadyReadyAlready(id, token)) { var store = await RuntimeReady(id, token); Log("verbose", $"BP req {args}"); await SetBreakpoint(id, store, request, !loaded, token); } if (loaded) { // we were already loaded so we should send a response // with the locations included and register the request context.BreakpointRequests [bpid] = request; var result = Result.OkFromObject(request.AsSetBreakpointByUrlResponse(locations)); SendResponse(id, result, token); } return(true); } case "Debugger.removeBreakpoint": { await RemoveBreakpoint(id, args, token); break; } case "Debugger.resume": { await OnResume(id, token); break; } case "Debugger.stepInto": { return(await Step(id, StepKind.Into, token)); } case "Debugger.stepOut": { return(await Step(id, StepKind.Out, token)); } case "Debugger.stepOver": { return(await Step(id, StepKind.Over, token)); } case "Debugger.evaluateOnCallFrame": { if (!DotnetObjectId.TryParse(args? ["callFrameId"], out var objectId)) { return(false); } switch (objectId.Scheme) { case "scope": return(await OnEvaluateOnCallFrame(id, int.Parse(objectId.Value), args? ["expression"]?.Value <string> (), token)); default: return(false); } } case "Runtime.getProperties": { if (!DotnetObjectId.TryParse(args? ["objectId"], out var objectId)) { break; } var result = await RuntimeGetProperties(id, objectId, args, token); SendResponse(id, result, token); return(true); } case "Runtime.releaseObject": { if (!(DotnetObjectId.TryParse(args ["objectId"], out var objectId) && objectId.Scheme == "cfo_res")) { break; } await SendMonoCommand(id, MonoCommands.ReleaseObject(objectId), token); SendResponse(id, Result.OkFromObject(new{}), token); return(true); } // Protocol extensions case "DotnetDebugger.getMethodLocation": { Console.WriteLine("set-breakpoint-by-method: " + id + " " + args); var store = await RuntimeReady(id, token); string aname = args ["assemblyName"]?.Value <string> (); string typeName = args ["typeName"]?.Value <string> (); string methodName = args ["methodName"]?.Value <string> (); if (aname == null || typeName == null || methodName == null) { SendResponse(id, Result.Err("Invalid protocol message '" + args + "'."), token); return(true); } // GetAssemblyByName seems to work on file names var assembly = store.GetAssemblyByName(aname); if (assembly == null) { assembly = store.GetAssemblyByName(aname + ".exe"); } if (assembly == null) { assembly = store.GetAssemblyByName(aname + ".dll"); } if (assembly == null) { SendResponse(id, Result.Err("Assembly '" + aname + "' not found."), token); return(true); } var type = assembly.GetTypeByName(typeName); if (type == null) { SendResponse(id, Result.Err($"Type '{typeName}' not found."), token); return(true); } var methodInfo = type.Methods.FirstOrDefault(m => m.Name == methodName); if (methodInfo == null) { SendResponse(id, Result.Err($"Method '{typeName}:{methodName}' not found."), token); return(true); } var src_url = methodInfo.Assembly.Sources.Single(sf => sf.SourceId == methodInfo.SourceId).Url; SendResponse(id, Result.OkFromObject(new { result = new { line = methodInfo.StartLocation.Line, column = methodInfo.StartLocation.Column, url = src_url } }), token); return(true); } case "Runtime.callFunctionOn": { if (!DotnetObjectId.TryParse(args ["objectId"], out var objectId)) { return(false); } var silent = args ["silent"]?.Value <bool> () ?? false; if (objectId.Scheme == "scope") { var fail = silent ? Result.OkFromObject(new { result = new { } }) : Result.Exception(new ArgumentException($"Runtime.callFunctionOn not supported with scope ({objectId}).")); SendResponse(id, fail, token); return(true); } var res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(args), token); var res_value_type = res.Value? ["result"]? ["value"]?.Type; if (res.IsOk && res_value_type == JTokenType.Object || res_value_type == JTokenType.Object) { res = Result.OkFromObject(new { result = res.Value ["result"]["value"] }); } else if (res.IsErr && silent) { res = Result.OkFromObject(new { result = new { } }); } SendResponse(id, res, token); return(true); } } return(false); }
protected override async Task <bool> AcceptCommand(MessageId id, string method, JObject args, CancellationToken token) { // Inspector doesn't use the Target domain or sessions // so we try to init immediately if (hideWebDriver && id == SessionId.Null) { await DeleteWebDriver(id, token); } if (!contexts.TryGetValue(id, out var context)) { return(false); } switch (method) { case "Target.attachToTarget": { var resp = await SendCommand(id, method, args, token); await DeleteWebDriver(new SessionId (resp.Value ["sessionId"]?.ToString()), token); break; } case "Debugger.enable": { var resp = await SendCommand(id, method, args, token); context.DebuggerId = resp.Value ["debuggerId"]?.ToString(); if (await IsRuntimeAlreadyReadyAlready(id, token)) { await RuntimeReady(id, token); } SendResponse(id, resp, token); return(true); } case "Debugger.getScriptSource": { var script = args? ["scriptId"]?.Value <string> (); return(await OnGetScriptSource(id, script, token)); } case "Runtime.compileScript": { var exp = args? ["expression"]?.Value <string> (); if (exp.StartsWith("//dotnet:", StringComparison.Ordinal)) { OnCompileDotnetScript(id, token); return(true); } break; } case "Debugger.getPossibleBreakpoints": { var resp = await SendCommand(id, method, args, token); if (resp.IsOk && resp.Value["locations"].HasValues) { SendResponse(id, resp, token); return(true); } var start = SourceLocation.Parse(args? ["start"] as JObject); //FIXME support variant where restrictToFunction=true and end is omitted var end = SourceLocation.Parse(args? ["end"] as JObject); if (start != null && end != null && await GetPossibleBreakpoints(id, start, end, token)) { return(true); } SendResponse(id, resp, token); return(true); } case "Debugger.setBreakpoint": { break; } case "Debugger.setBreakpointByUrl": { var resp = await SendCommand(id, method, args, token); if (!resp.IsOk) { SendResponse(id, resp, token); return(true); } var bpid = resp.Value["breakpointId"]?.ToString(); var request = BreakpointRequest.Parse(bpid, args); context.BreakpointRequests[bpid] = request; if (await IsRuntimeAlreadyReadyAlready(id, token)) { var store = await RuntimeReady(id, token); Log("verbose", $"BP req {args}"); await SetBreakpoint(id, store, request, token); } SendResponse(id, Result.OkFromObject(request.AsSetBreakpointByUrlResponse()), token); return(true); } case "Debugger.removeBreakpoint": { await RemoveBreakpoint(id, args, token); break; } case "Debugger.resume": { await OnResume(id, token); break; } case "Debugger.stepInto": { return(await Step(id, StepKind.Into, token)); } case "Debugger.stepOut": { return(await Step(id, StepKind.Out, token)); } case "Debugger.stepOver": { return(await Step(id, StepKind.Over, token)); } case "Debugger.evaluateOnCallFrame": { if (!DotnetObjectId.TryParse(args? ["callFrameId"], out var objectId)) { return(false); } switch (objectId.Scheme) { case "scope": return(await OnEvaluateOnCallFrame(id, int.Parse(objectId.Value), args? ["expression"]?.Value <string> (), token)); default: return(false); } } case "Runtime.getProperties": { if (!DotnetObjectId.TryParse(args? ["objectId"], out var objectId)) { break; } var result = await RuntimeGetProperties(id, objectId, args, token); SendResponse(id, result, token); return(true); } case "Runtime.releaseObject": { if (!(DotnetObjectId.TryParse(args ["objectId"], out var objectId) && objectId.Scheme == "cfo_res")) { break; } await SendMonoCommand(id, new MonoCommands ($"MONO.mono_wasm_release_object('{objectId}')"), token); SendResponse(id, Result.OkFromObject(new{}), token); return(true); } // Protocol extensions case "Dotnet-test.setBreakpointByMethod": { Console.WriteLine("set-breakpoint-by-method: " + id + " " + args); var store = await RuntimeReady(id, token); string aname = args ["assemblyName"]?.Value <string> (); string typeName = args ["typeName"]?.Value <string> (); string methodName = args ["methodName"]?.Value <string> (); if (aname == null || typeName == null || methodName == null) { SendResponse(id, Result.Err("Invalid protocol message '" + args + "'."), token); return(true); } // GetAssemblyByName seems to work on file names var assembly = store.GetAssemblyByName(aname); if (assembly == null) { assembly = store.GetAssemblyByName(aname + ".exe"); } if (assembly == null) { assembly = store.GetAssemblyByName(aname + ".dll"); } if (assembly == null) { SendResponse(id, Result.Err("Assembly '" + aname + "' not found."), token); return(true); } var type = assembly.GetTypeByName(typeName); if (type == null) { SendResponse(id, Result.Err($"Type '{typeName}' not found."), token); return(true); } var methodInfo = type.Methods.FirstOrDefault(m => m.Name == methodName); if (methodInfo == null) { SendResponse(id, Result.Err($"Method '{typeName}:{methodName}' not found."), token); return(true); } bpIdGenerator++; string bpid = "by-method-" + bpIdGenerator.ToString(); var request = new BreakpointRequest(bpid, methodInfo); context.BreakpointRequests[bpid] = request; var loc = methodInfo.StartLocation; var bp = await SetMonoBreakpoint(id, bpid, loc, token); if (bp.State != BreakpointState.Active) { // FIXME: throw new NotImplementedException(); } var resolvedLocation = new { breakpointId = bpid, location = loc.AsLocation() }; SendEvent(id, "Debugger.breakpointResolved", JObject.FromObject(resolvedLocation), token); SendResponse(id, Result.OkFromObject(new { result = new { breakpointId = bpid, locations = new object [] { loc.AsLocation() } } }), token); return(true); } case "Runtime.callFunctionOn": { if (!DotnetObjectId.TryParse(args ["objectId"], out var objectId)) { return(false); } var silent = args ["silent"]?.Value <bool> () ?? false; if (objectId.Scheme == "scope") { var fail = silent ? Result.OkFromObject(new { result = new { } }) : Result.Exception(new ArgumentException($"Runtime.callFunctionOn not supported with scope ({objectId}).")); SendResponse(id, fail, token); return(true); } var returnByValue = args ["returnByValue"]?.Value <bool> () ?? false; var cmd = new MonoCommands($"MONO.mono_wasm_call_function_on ({args.ToString ()}, {(returnByValue ? "true" : "false")})"); var res = await SendMonoCommand(id, cmd, token); if (!returnByValue && DotnetObjectId.TryParse(res.Value?["result"]?["value"]?["objectId"], out var resultObjectId) && resultObjectId.Scheme == "cfo_res") { res = Result.OkFromObject(new { result = res.Value ["result"]["value"] }); } if (res.IsErr && silent) { res = Result.OkFromObject(new { result = new { } }); } SendResponse(id, res, token); return(true); } } return(false); }