Example #1
0
 protected virtual Task <bool> AcceptCommand(MessageId id, JObject args, CancellationToken token)
 {
     return(Task.FromResult(false));
 }
Example #2
0
 public virtual void SendResponse(MessageId id, Result result, CancellationToken token)
 {
     SendResponseInternal(id, result, token);
 }
Example #3
0
        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);
            }

            case "Debugger.setPauseOnExceptions":
            {
                string state = args["state"].Value <string>();
                await SendMonoCommand(id, MonoCommands.SetPauseOnExceptions(state), token);

                // Pass this on to JS too
                return(false);
            }

            // Protocol extensions
            case "DotnetDebugger.addSymbolServerUrl":
            {
                string url = args["url"]?.Value <string>();
                if (!String.IsNullOrEmpty(url) && !urlSymbolServerList.Contains(url))
                {
                    urlSymbolServerList.Add(url);
                }
                return(true);
            }

            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)
                {
                    // Maybe this is an async method, in which case the debug info is attached
                    // to the async method implementation, in class named:
                    //      `{type_name}/<method_name>::MoveNext`
                    methodInfo = assembly.TypesByName.Values.SingleOrDefault(t => t.FullName.StartsWith($"{typeName}/<{methodName}>"))?
                                 .Methods.FirstOrDefault(mi => mi.Name == "MoveNext");
                }

                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);
                }

                if (objectId.Scheme == "scope")
                {
                    SendResponse(id,
                                 Result.Exception(new ArgumentException(
                                                      $"Runtime.callFunctionOn not supported with scope ({objectId}).")),
                                 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"] });
                }

                SendResponse(id, res, token);
                return(true);
            }
            }

            return(false);
        }
Example #4
0
 void OnCompileDotnetScript(MessageId msg_id, CancellationToken token)
 {
     SendResponse(msg_id, Result.OkFromObject(new { }), token);
 }
Example #5
0
            public async Task <SyntaxTree> ReplaceVars(SyntaxTree syntaxTree, MonoProxy proxy, MessageId msg_id, int scope_id, CancellationToken token)
            {
                CompilationUnitSyntax root = syntaxTree.GetCompilationUnitRoot();

                foreach (var var in variables)
                {
                    ClassDeclarationSyntax  classDeclaration = root.Members.ElementAt(0) as ClassDeclarationSyntax;
                    MethodDeclarationSyntax method           = classDeclaration.Members.ElementAt(0) as MethodDeclarationSyntax;

                    JToken value = await proxy.TryGetVariableValue(msg_id, scope_id, var.Identifier.Text, false, token);

                    if (value == null)
                    {
                        throw new Exception($"The name {var.Identifier.Text} does not exist in the current context");
                    }

                    values.Add(ConvertJSToCSharpType(value["value"]));

                    var updatedMethod = method.AddParameterListParameters(
                        SyntaxFactory.Parameter(
                            SyntaxFactory.Identifier(var.Identifier.Text))
                        .WithType(SyntaxFactory.ParseTypeName(GetTypeFullName(value["value"]))));
                    root = root.ReplaceNode(method, updatedMethod);
                }
                syntaxTree = syntaxTree.WithRootAndOptions(root, syntaxTree.Options);
                return(syntaxTree);
            }
Example #6
0
        internal static async Task <string> CompileAndRunTheExpression(MonoProxy proxy, MessageId msg_id, int scope_id, string expression, CancellationToken token)
        {
            FindVariableNMethodCall findVarNMethodCall = new FindVariableNMethodCall();
            string     retString;
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
				using System;
				public class CompileAndRunTheExpression
				{
					public string Evaluate()
					{
						return ("                         + expression + @").ToString(); 
					}
				}"                );

            FindThisExpression findThisExpression = new FindThisExpression(syntaxTree);
            var expressionTree = GetExpressionFromSyntaxTree(syntaxTree);

            findThisExpression.Visit(expressionTree);
            await findThisExpression.CheckIfIsProperty(proxy, msg_id, scope_id, token);

            syntaxTree = findThisExpression.syntaxTree;

            expressionTree = GetExpressionFromSyntaxTree(syntaxTree);
            findVarNMethodCall.Visit(expressionTree);

            syntaxTree = await findVarNMethodCall.ReplaceVars(syntaxTree, proxy, msg_id, scope_id, token);

            MetadataReference[] references = new MetadataReference[]
            {
                MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
            };

            CSharpCompilation compilation = CSharpCompilation.Create(
                "compileAndRunTheExpression",
                syntaxTrees: new[] { syntaxTree },
                references: references,
                options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            using (var ms = new MemoryStream())
            {
                EmitResult result = compilation.Emit(ms);
                ms.Seek(0, SeekOrigin.Begin);
                Assembly assembly = Assembly.Load(ms.ToArray());
                Type     type     = assembly.GetType("CompileAndRunTheExpression");
                object   obj      = Activator.CreateInstance(type);
                var      ret      = type.InvokeMember("Evaluate",
                                                      BindingFlags.Default | BindingFlags.InvokeMethod,
                                                      null,
                                                      obj,
                                                      findVarNMethodCall.values.ToArray());
                retString = ret.ToString();
            }
            return(retString);
        }