public bool TryResolve(DebugStore store) { if (request == null || store == null) { return(false); } return(store.AllSources().FirstOrDefault(source => TryResolve(source)) != null); }
async Task LoadStore(SessionId sessionId, CancellationToken token) { var loaded_pdbs = await SendMonoCommand(sessionId, MonoCommands.GetLoadedFiles(), token); var the_value = loaded_pdbs.Value? ["result"]? ["value"]; var the_pdbs = the_value?.ToObject <string[]> (); store = new DebugStore(); await store.Load(sessionId, the_pdbs, token); }
public static BreakPointRequest Parse(JObject args, DebugStore store) { // Events can potentially come out of order, so DebugStore may not be initialized // The BP being set in these cases are JS ones, which we can safely ignore if (args == null || store == null) { return(null); } var url = args? ["url"]?.Value <string> (); if (url == null) { var urlRegex = args?["urlRegex"].Value <string>(); var sourceFile = store?.GetFileByUrlRegex(urlRegex); url = sourceFile?.DotNetUrl; } if (url != null && !url.StartsWith("dotnet://", StringComparison.InvariantCulture)) { var sourceFile = store.GetFileByUrl(url); url = sourceFile?.DotNetUrl; } if (url == null) { return(null); } var parts = ParseDocumentUrl(url); if (parts.Assembly == null) { return(null); } var line = args? ["lineNumber"]?.Value <int> (); var column = args? ["columnNumber"]?.Value <int> (); if (line == null || column == null) { return(null); } return(new BreakPointRequest() { Assembly = parts.Assembly, File = parts.DocumentPath, Line = line.Value, Column = column.Value }); }
async Task SetBreakpoint(SessionId sessionId, DebugStore store, BreakpointRequest req, bool sendResolvedEvent, CancellationToken token) { var context = GetContext(sessionId); if (req.Locations.Any()) { Log("debug", $"locations already loaded for {req.Id}"); return; } var comparer = new SourceLocation.LocationComparer(); // if column is specified the frontend wants the exact matches // and will clear the bp if it isn't close enoug var locations = store.FindBreakpointLocations(req) .Distinct(comparer) .Where(l => l.Line == req.Line && (req.Column == 0 || l.Column == req.Column)) .OrderBy(l => l.Column) .GroupBy(l => l.Id); logger.LogDebug("BP request for '{req}' runtime ready {context.RuntimeReady}", req, GetContext(sessionId).IsRuntimeReady); var breakpoints = new List <Breakpoint>(); foreach (var sourceId in locations) { var loc = sourceId.First(); var bp = await SetMonoBreakpoint(sessionId, req.Id, loc, token); // If we didn't successfully enable the breakpoint // don't add it to the list of locations for this id if (bp.State != BreakpointState.Active) { continue; } breakpoints.Add(bp); var resolvedLocation = new { breakpointId = req.Id, location = loc.AsLocation() }; if (sendResolvedEvent) { SendEvent(sessionId, "Debugger.breakpointResolved", JObject.FromObject(resolvedLocation), token); } } req.Locations.AddRange(breakpoints); return; }
public static BreakPointRequest Parse(JObject args, DebugStore store) { if (args == null) { return(null); } var url = args? ["url"]?.Value <string> (); if (url == null) { var urlRegex = args?["urlRegex"].Value <string>(); var sourceFile = store.GetFileByUrlRegex(urlRegex); url = sourceFile?.DotNetUrl; } if (url != null && !url.StartsWith("dotnet://", StringComparison.InvariantCulture)) { var sourceFile = store.GetFileByUrl(url); url = sourceFile?.DotNetUrl; } if (url == null) { return(null); } var parts = ParseDocumentUrl(url); if (parts.Assembly == null) { return(null); } var line = args? ["lineNumber"]?.Value <int> (); var column = args? ["columnNumber"]?.Value <int> (); if (line == null || column == null) { return(null); } return(new BreakPointRequest() { Assembly = parts.Assembly, File = parts.DocumentPath, Line = line.Value, Column = column.Value }); }
async Task LoadStore(SessionId sessionId, CancellationToken token) { var o = JObject.FromObject(new { expression = MonoCommands.GET_LOADED_FILES, objectGroup = "mono_debugger", includeCommandLineAPI = false, silent = false, returnByValue = true, }); var loaded_pdbs = await SendCommand(sessionId, "Runtime.evaluate", o, token); var the_value = loaded_pdbs.Value? ["result"]? ["value"]; var the_pdbs = the_value?.ToObject <string[]> (); store = new DebugStore(); await store.Load(sessionId, the_pdbs, token); }
async Task SetBreakpoint(SessionId sessionId, DebugStore store, BreakpointRequest req, CancellationToken token) { var context = GetContext(sessionId); if (req.Locations.Any()) { Log("debug", $"locations already loaded for {req.Id}"); return; } var locations = store.FindBreakpointLocations(req).ToList(); logger.LogDebug("BP request for '{req}' runtime ready {context.RuntimeReady}", req, GetContext(sessionId).IsRuntimeReady); var breakpoints = new List <Breakpoint> (); foreach (var loc in locations) { var bp = await SetMonoBreakpoint(sessionId, req, loc, token); // If we didn't successfully enable the breakpoint // don't add it to the list of locations for this id if (bp.State != BreakpointState.Active) { continue; } breakpoints.Add(bp); var resolvedLocation = new { breakpointId = req.Id, location = loc.AsLocation() }; SendEvent(sessionId, "Debugger.breakpointResolved", JObject.FromObject(resolvedLocation), token); } req.Locations.AddRange(breakpoints); return; }
async Task RuntimeReady(CancellationToken token) { var o = JObject.FromObject(new { expression = MonoCommands.GET_LOADED_FILES, objectGroup = "mono_debugger", includeCommandLineAPI = false, silent = false, returnByValue = true, }); var loaded_pdbs = await SendCommand("Runtime.evaluate", o, token); var the_value = loaded_pdbs.Value? ["result"]? ["value"]; var the_pdbs = the_value?.ToObject <string[]> (); this.store = new DebugStore(the_pdbs); foreach (var s in store.AllSources()) { var ok = JObject.FromObject(new { scriptId = s.SourceId.ToString(), url = s.Url, executionContextId = this.ctx_id, hash = s.DocHashCode, executionContextAuxData = this.aux_ctx_data, dotNetUrl = s.DotNetUrl }); //Debug ($"\tsending {s.Url}"); SendEvent("Debugger.scriptParsed", ok, token); } o = JObject.FromObject(new { expression = MonoCommands.CLEAR_ALL_BREAKPOINTS, objectGroup = "mono_debugger", includeCommandLineAPI = false, silent = false, returnByValue = true, }); var clear_result = await SendCommand("Runtime.evaluate", o, token); if (clear_result.IsErr) { Debug($"Failed to clear breakpoints due to {clear_result}"); } runtime_ready = true; foreach (var bp in breakpoints) { if (bp.State != BreakPointState.Pending) { continue; } var res = await EnableBreakPoint(bp, token); var ret_code = res.Value? ["result"]? ["value"]?.Value <int> (); //if we fail we just buble that to the IDE (and let it panic over it) if (!ret_code.HasValue) { //FIXME figure out how to inform the IDE of that. Info($"FAILED TO ENABLE BP {bp.LocalId}"); bp.State = BreakPointState.Disabled; } } }
//from ide protected override async Task <bool> AcceptCommand(MessageId sessionId, JObject args, CancellationToken token) { if (args["type"] == null) { return(false); } switch (args["type"].Value <string>()) { case "resume": { if (!contexts.TryGetValue(sessionId, out ExecutionContext context)) { return(false); } context.PausedOnWasm = false; if (context.CallStack == null) { return(false); } if (args["resumeLimit"] == null || args["resumeLimit"].Type == JTokenType.Null) { await OnResume(sessionId, token); return(false); } switch (args["resumeLimit"]["type"].Value <string>()) { case "next": await context.SdbAgent.Step(context.ThreadId, StepKind.Over, token); break; case "finish": await context.SdbAgent.Step(context.ThreadId, StepKind.Out, token); break; case "step": await context.SdbAgent.Step(context.ThreadId, StepKind.Into, token); break; } await SendResume(sessionId, token); return(true); } case "isAttached": case "attach": { var ctx = GetContextFixefox(sessionId); ctx.ThreadName = args["to"].Value <string>(); break; } case "source": { return(await OnGetScriptSource(sessionId, args["to"].Value <string>(), token)); } case "getBreakableLines": { return(await OnGetBreakableLines(sessionId, args["to"].Value <string>(), token)); } case "getBreakpointPositionsCompressed": { //{"positions":{"39":[20,28]},"from":"server1.conn2.child10/source27"} if (args["to"].Value <string>().StartsWith("dotnet://")) { var line = new JObject(); var offsets = new JArray(); offsets.Add(0); line.Add(args["query"]["start"]["line"].Value <string>(), offsets); var o = JObject.FromObject(new { positions = line, from = args["to"].Value <string>() }); await SendEventInternal(sessionId, "", o, token); return(true); } break; } case "setBreakpoint": { if (!contexts.TryGetValue(sessionId, out ExecutionContext context)) { return(false); } var req = JObject.FromObject(new { url = args["location"]["sourceUrl"].Value <string>(), lineNumber = args["location"]["line"].Value <int>() - 1, columnNumber = args["location"]["column"].Value <int>() }); var bp = context.BreakpointRequests.Where(request => request.Value.CompareRequest(req)).FirstOrDefault(); if (bp.Value != null) { bp.Value.UpdateCondition(args["options"]?["condition"]?.Value <string>()); await SendCommand(sessionId, "", args, token); return(true); } string bpid = Interlocked.Increment(ref context.breakpointId).ToString(); if (args["options"]?["condition"]?.Value <string>() != null) { req["condition"] = args["options"]?["condition"]?.Value <string>(); } var request = BreakpointRequest.Parse(bpid, req); bool loaded = context.Source.Task.IsCompleted; context.BreakpointRequests[bpid] = request; if (await IsRuntimeAlreadyReadyAlready(sessionId, token)) { DebugStore store = await RuntimeReady(sessionId, token); Log("verbose", $"BP req {args}"); await SetBreakpoint(sessionId, store, request, !loaded, false, token); } await SendCommand(sessionId, "", args, token); return(true); } case "removeBreakpoint": { if (!contexts.TryGetValue(sessionId, out ExecutionContext context)) { return(false); } Result resp = await SendCommand(sessionId, "", args, token); var reqToRemove = JObject.FromObject(new { url = args["location"]["sourceUrl"].Value <string>(), lineNumber = args["location"]["line"].Value <int>() - 1, columnNumber = args["location"]["column"].Value <int>() }); foreach (var req in context.BreakpointRequests.Values) { if (req.CompareRequest(reqToRemove)) { foreach (var bp in req.Locations) { var breakpoint_removed = await context.SdbAgent.RemoveBreakpoint(bp.RemoteId, token); if (breakpoint_removed) { bp.RemoteId = -1; bp.State = BreakpointState.Disabled; } } } } return(true); } case "prototypeAndProperties": case "slice": { var to = args?["to"].Value <string>().Replace("propertyIterator", ""); if (!DotnetObjectId.TryParse(to, out DotnetObjectId objectId)) { return(false); } var res = await RuntimeGetObjectMembers(sessionId, objectId, args, token); var variables = ConvertToFirefoxContent(res); var o = JObject.FromObject(new { ownProperties = variables, from = args["to"].Value <string>() }); if (args["type"].Value <string>() == "prototypeAndProperties") { o.Add("prototype", GetPrototype(objectId, args)); } await SendEvent(sessionId, "", o, token); return(true); } case "prototype": { if (!DotnetObjectId.TryParse(args?["to"], out DotnetObjectId objectId)) { return(false); } var o = JObject.FromObject(new { prototype = GetPrototype(objectId, args), from = args["to"].Value <string>() }); await SendEvent(sessionId, "", o, token); return(true); } case "enumSymbols": { if (!DotnetObjectId.TryParse(args?["to"], out DotnetObjectId objectId)) { return(false); } var o = JObject.FromObject(new { type = "symbolIterator", count = 0, actor = args["to"].Value <string>() + "symbolIterator" }); var iterator = JObject.FromObject(new { iterator = o, from = args["to"].Value <string>() }); await SendEvent(sessionId, "", iterator, token); return(true); } case "enumProperties": { //{"iterator":{"type":"propertyIterator","actor":"server1.conn19.child63/propertyIterator73","count":3},"from":"server1.conn19.child63/obj71"} if (!DotnetObjectId.TryParse(args?["to"], out DotnetObjectId objectId)) { return(false); } var res = await RuntimeGetObjectMembers(sessionId, objectId, args, token); var variables = ConvertToFirefoxContent(res); var o = JObject.FromObject(new { type = "propertyIterator", count = variables.Count, actor = args["to"].Value <string>() + "propertyIterator" }); var iterator = JObject.FromObject(new { iterator = o, from = args["to"].Value <string>() }); await SendEvent(sessionId, "", iterator, token); return(true); } case "getEnvironment": { if (!DotnetObjectId.TryParse(args?["to"], out DotnetObjectId objectId)) { return(false); } var ctx = GetContextFixefox(sessionId); if (ctx.CallStack == null) { return(false); } Frame scope = ctx.CallStack.FirstOrDefault(s => s.Id == objectId.Value); var res = await RuntimeGetObjectMembers(sessionId, objectId, args, token); var variables = ConvertToFirefoxContent(res); var o = JObject.FromObject(new { actor = args["to"].Value <string>() + "_0", type = "function", scopeKind = "function", function = new { displayName = scope.Method.Name }, bindings = new { arguments = new JArray(), variables }, from = args["to"].Value <string>() }); await SendEvent(sessionId, "", o, token); return(true); } case "frames": { ExecutionContext ctx = GetContextFixefox(sessionId); if (ctx.PausedOnWasm) { try { await GetFrames(sessionId, ctx, args, token); return(true); } catch (Exception) //if the page is refreshed maybe it stops here. { await SendResume(sessionId, token); return(true); } } //var ret = await SendCommand(sessionId, "frames", args, token); //await SendEvent(sessionId, "", ret.Value["result"]["fullContent"] as JObject, token); return(false); } case "evaluateJSAsync": { var context = GetContextFixefox(sessionId); if (context.CallStack != null) { var resultID = $"runtimeResult-{context.GetResultID()}"; var o = JObject.FromObject(new { resultID, from = args["to"].Value <string>() }); await SendEvent(sessionId, "", o, token); Frame scope = context.CallStack.First <Frame>(); var resolver = new MemberReferenceResolver(this, context, sessionId, scope.Id, logger); JObject retValue = await resolver.Resolve(args?["text"]?.Value <string>(), token); if (retValue == null) { retValue = await ExpressionEvaluator.CompileAndRunTheExpression(args?["text"]?.Value <string>(), resolver, logger, token); } var osend = JObject.FromObject(new { type = "evaluationResult", resultID, hasException = false, input = args?["text"], from = args["to"].Value <string>() }); if (retValue["type"].Value <string>() == "object") { osend["result"] = JObject.FromObject(new { type = retValue["type"], @class = retValue["className"], description = retValue["description"], actor = retValue["objectId"], }); } else { osend["result"] = retValue["value"]; osend["resultType"] = retValue["type"]; osend["resultDescription"] = retValue["description"]; } await SendEvent(sessionId, "", osend, token); } else { var ret = await SendCommand(sessionId, "evaluateJSAsync", args, token); var o = JObject.FromObject(new { resultID = ret.FullContent["resultID"], from = args["to"].Value <string>() }); await SendEvent(sessionId, "", o, token); await SendEvent(sessionId, "", ret.FullContent, token); } return(true); } case "DotnetDebugger.getMethodLocation": { var ret = await GetMethodLocation(sessionId, args, token); ret.Value["from"] = "internal"; await SendEvent(sessionId, "", ret.Value, token); return(true); } default: return(false); } return(false); }