示例#1
0
        protected override async Task <bool> AcceptEvent(SessionId sessionId, string method, JObject args, CancellationToken token)
        {
            switch (method)
            {
            case "Runtime.consoleAPICalled":
            {
                var type = args["type"]?.ToString();
                if (type == "debug")
                {
                    var a = args["args"];
                    if (a?[0]?["value"]?.ToString() == MonoConstants.RUNTIME_IS_READY &&
                        a?[1]?["value"]?.ToString() == "fe00e07a-5519-4dfe-b35a-f867dbaf2e28")
                    {
                        if (a.Count() > 2)
                        {
                            try
                            {
                                // The optional 3rd argument is the stringified assembly
                                // list so that we don't have to make more round trips
                                var context = GetContext(sessionId);
                                var loaded  = a?[2]?["value"]?.ToString();
                                if (loaded != null)
                                {
                                    context.LoadedFiles = JToken.Parse(loaded).ToObject <string[]>();
                                }
                            }
                            catch (InvalidCastException ice)
                            {
                                Log("verbose", ice.ToString());
                            }
                        }
                        await RuntimeReady(sessionId, token);
                    }
                }
                break;
            }

            case "Runtime.executionContextCreated":
            {
                SendEvent(sessionId, method, args, token);
                var ctx      = args?["context"];
                var aux_data = ctx?["auxData"] as JObject;
                var id       = ctx["id"].Value <int>();
                if (aux_data != null)
                {
                    var is_default = aux_data["isDefault"]?.Value <bool>();
                    if (is_default == true)
                    {
                        await OnDefaultContext(sessionId, new ExecutionContext { Id = id, AuxData = aux_data }, token);
                    }
                }
                return(true);
            }

            case "Debugger.paused":
            {
                //TODO figure out how to stich out more frames and, in particular what happens when real wasm is on the stack
                var top_func = args?["callFrames"]?[0]?["functionName"]?.Value <string>();

                if (top_func == "mono_wasm_fire_bp" || top_func == "_mono_wasm_fire_bp" || top_func == "_mono_wasm_fire_exception")
                {
                    return(await OnPause(sessionId, args, token));
                }
                break;
            }

            case "Debugger.breakpointResolved":
            {
                break;
            }

            case "Debugger.scriptParsed":
            {
                var url = args?["url"]?.Value <string>() ?? "";

                switch (url)
                {
                case var _ when url == "":
                case var _ when url.StartsWith("wasm://", StringComparison.Ordinal):
                {
                    Log("verbose", $"ignoring wasm: Debugger.scriptParsed {url}");
                    return(true);
                }
                }
                Log("verbose", $"proxying Debugger.scriptParsed ({sessionId.sessionId}) {url} {args}");
                break;
            }

            case "Target.attachedToTarget":
            {
                if (args["targetInfo"]["type"]?.ToString() == "page")
                {
                    await DeleteWebDriver(new SessionId(args["sessionId"]?.ToString()), token);
                }
                break;
            }
            }

            return(false);
        }
示例#2
0
        //static int frame_id=0;
        async Task <bool> OnPause(SessionId sessionId, JObject args, CancellationToken token)
        {
            //FIXME we should send release objects every now and then? Or intercept those we inject and deal in the runtime
            var res = await SendMonoCommand(sessionId, MonoCommands.GetCallStack(), token);

            var     orig_callframes = args?["callFrames"]?.Values <JObject>();
            var     context         = GetContext(sessionId);
            JObject data            = null;
            var     reason          = "other";//other means breakpoint

            if (res.IsErr)
            {
                //Give up and send the original call stack
                return(false);
            }

            //step one, figure out where did we hit
            var res_value = res.Value?["result"]?["value"];

            if (res_value == null || res_value is JValue)
            {
                //Give up and send the original call stack
                return(false);
            }

            Log("verbose", $"call stack (err is {res.Error} value is:\n{res.Value}");
            var bp_id = res_value?["breakpoint_id"]?.Value <int>();

            Log("verbose", $"We just hit bp {bp_id}");
            if (!bp_id.HasValue)
            {
                //Give up and send the original call stack
                return(false);
            }

            var bp = context.BreakpointRequests.Values.SelectMany(v => v.Locations).FirstOrDefault(b => b.RemoteId == bp_id.Value);

            var callFrames = new List <object>();

            foreach (var frame in orig_callframes)
            {
                var function_name = frame["functionName"]?.Value <string>();
                var url           = frame["url"]?.Value <string>();
                if ("mono_wasm_fire_bp" == function_name || "_mono_wasm_fire_bp" == function_name ||
                    "_mono_wasm_fire_exception" == function_name)
                {
                    if ("_mono_wasm_fire_exception" == function_name)
                    {
                        var exception_obj_id = await SendMonoCommand(sessionId, MonoCommands.GetExceptionObject(), token);

                        var res_val = exception_obj_id.Value?["result"]?["value"];
                        var exception_dotnet_obj_id = new DotnetObjectId("object", res_val?["exception_id"]?.Value <string>());
                        data = JObject.FromObject(new
                        {
                            type        = "object",
                            subtype     = "error",
                            className   = res_val?["class_name"]?.Value <string>(),
                            uncaught    = res_val?["uncaught"]?.Value <bool>(),
                            description = res_val?["message"]?.Value <string>() + "\n",
                            objectId    = exception_dotnet_obj_id.ToString()
                        });
                        reason = "exception";
                    }

                    var frames          = new List <Frame>();
                    int frame_id        = 0;
                    var the_mono_frames = res.Value?["result"]?["value"]?["frames"]?.Values <JObject>();

                    foreach (var mono_frame in the_mono_frames)
                    {
                        ++frame_id;
                        var il_pos        = mono_frame["il_pos"].Value <int>();
                        var method_token  = mono_frame["method_token"].Value <uint>();
                        var assembly_name = mono_frame["assembly_name"].Value <string>();

                        // This can be different than `method.Name`, like in case of generic methods
                        var method_name = mono_frame["method_name"]?.Value <string>();

                        var store = await LoadStore(sessionId, token);

                        var asm = store.GetAssemblyByName(assembly_name);
                        if (asm == null)
                        {
                            Log("info", $"Unable to find assembly: {assembly_name}");
                            continue;
                        }

                        var method = asm.GetMethodByToken(method_token);

                        if (method == null)
                        {
                            Log("info", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}");
                            continue;
                        }

                        var location = method?.GetLocationByIl(il_pos);

                        // When hitting a breakpoint on the "IncrementCount" method in the standard
                        // Blazor project template, one of the stack frames is inside mscorlib.dll
                        // and we get location==null for it. It will trigger a NullReferenceException
                        // if we don't skip over that stack frame.
                        if (location == null)
                        {
                            continue;
                        }

                        Log("info", $"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}");
                        Log("info", $"\tmethod {method_name} location: {location}");
                        frames.Add(new Frame(method, location, frame_id - 1));

                        callFrames.Add(new
                        {
                            functionName     = method_name,
                            callFrameId      = $"dotnet:scope:{frame_id - 1}",
                            functionLocation = method.StartLocation.AsLocation(),

                            location = location.AsLocation(),

                            url = store.ToUrl(location),

                            scopeChain = new[]
                            {
                                new
                                {
                                    type    = "local",
                                    @object = new
                                    {
                                        @type       = "object",
                                        className   = "Object",
                                        description = "Object",
                                        objectId    = $"dotnet:scope:{frame_id-1}",
                                    },
                                    name          = method_name,
                                    startLocation = method.StartLocation.AsLocation(),
                                    endLocation   = method.EndLocation.AsLocation(),
                                }
                            }
                        });

                        context.CallStack = frames;
                    }
                }
                else if (!(function_name.StartsWith("wasm-function", StringComparison.Ordinal) ||
                           url.StartsWith("wasm://wasm/", StringComparison.Ordinal)))
                {
                    callFrames.Add(frame);
                }
            }

            var bp_list = new string[bp == null ? 0 : 1];

            if (bp != null)
            {
                bp_list[0] = bp.StackId;
            }

            var o = JObject.FromObject(new
            {
                callFrames,
                reason,
                data,
                hitBreakpoints = bp_list,
            });

            SendEvent(sessionId, "Debugger.paused", o, token);
            return(true);
        }
示例#3
0
 internal Task <Result> SendMonoCommand(SessionId id, MonoCommands cmd, CancellationToken token) => SendCommand(id, "Runtime.evaluate", JObject.FromObject(cmd), token);
示例#4
0
 protected virtual Task <bool> AcceptEvent(SessionId sessionId, string method, JObject args, CancellationToken token)
 {
     return(Task.FromResult(false));
 }
示例#5
0
 public void SendEvent(SessionId sessionId, string method, JObject args, CancellationToken token)
 {
     //Log ("verbose", $"sending event {method}: {args}");
     SendEventInternal(sessionId, method, args, token);
 }
示例#6
0
 internal async Task <Result> SendCommand(SessionId id, string method, JObject args, CancellationToken token)
 {
     //Log ("verbose", $"sending command {method}: {args}");
     return(await SendCommandInternal(id, method, args, token));
 }
示例#7
0
 public virtual Task SendEvent(SessionId sessionId, string method, JObject args, CancellationToken token)
 {
     // logger.LogTrace($"sending event {method}: {args}");
     return(SendEventInternal(sessionId, method, args, token));
 }