public async Task <JObject> GetValueFromObject(JToken objRet, CancellationToken token) { if (objRet["value"]?["className"]?.Value <string>() == "System.Exception") { if (DotnetObjectId.TryParse(objRet?["value"]?["objectId"]?.Value <string>(), out DotnetObjectId objectId)) { var exceptionObject = await context.SdbAgent.GetObjectValues(objectId.Value, GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.OwnProperties, token); var exceptionObjectMessage = exceptionObject.FirstOrDefault(attr => attr["name"].Value <string>().Equals("_message")); exceptionObjectMessage["value"]["value"] = objRet["value"]?["className"]?.Value <string>() + ": " + exceptionObjectMessage["value"]?["value"]?.Value <string>(); return(exceptionObjectMessage["value"]?.Value <JObject>()); } return(objRet["value"]?.Value <JObject>()); } if (objRet["value"]?.Value <JObject>() != null) { return(objRet["value"]?.Value <JObject>()); } if (objRet["get"]?.Value <JObject>() != null) { if (DotnetObjectId.TryParse(objRet?["get"]?["objectIdValue"]?.Value <string>(), out DotnetObjectId objectId)) { using var commandParamsWriter = new MonoBinaryWriter(); commandParamsWriter.WriteObj(objectId, context.SdbAgent); var ret = await context.SdbAgent.InvokeMethod(commandParamsWriter.GetParameterBuffer(), objRet["get"]["methodId"].Value <int>(), objRet["name"].Value <string>(), token); return(await GetValueFromObject(ret, token)); } } return(null); }
public async Task <JObject> GetValueFromObject(JToken objRet, CancellationToken token) { if (objRet["value"]?["className"]?.Value <string>() == "System.Exception") { if (DotnetObjectId.TryParse(objRet?["value"]?["objectId"]?.Value <string>(), out DotnetObjectId objectId)) { var exceptionObject = await proxy.SdbHelper.GetObjectValues(sessionId, int.Parse(objectId.Value), true, false, false, true, token); var exceptionObjectMessage = exceptionObject.FirstOrDefault(attr => attr["name"].Value <string>().Equals("_message")); exceptionObjectMessage["value"]["value"] = objRet["value"]?["className"]?.Value <string>() + ": " + exceptionObjectMessage["value"]?["value"]?.Value <string>(); return(exceptionObjectMessage["value"]?.Value <JObject>()); } return(objRet["value"]?.Value <JObject>()); } if (objRet["value"]?.Value <JObject>() != null) { return(objRet["value"]?.Value <JObject>()); } if (objRet["get"]?.Value <JObject>() != null) { if (DotnetObjectId.TryParse(objRet?["get"]?["objectIdValue"]?.Value <string>(), out DotnetObjectId objectId)) { var commandParams = new MemoryStream(); var commandParamsWriter = new MonoBinaryWriter(commandParams); commandParamsWriter.WriteObj(objectId, proxy.SdbHelper); var ret = await proxy.SdbHelper.InvokeMethod(sessionId, commandParams.ToArray(), objRet["get"]["methodId"].Value <int>(), objRet["name"].Value <string>(), token); return(await GetValueFromObject(ret, token)); } } return(null); }
public async Task <JObject> GetValueFromObject(JToken objRet, CancellationToken token) { if (objRet["value"]?["className"]?.Value <string>() == "System.Exception") { if (DotnetObjectId.TryParse(objRet?["value"]?["objectId"]?.Value <string>(), out DotnetObjectId objectId)) { GetMembersResult exceptionObject = await MemberObjectsExplorer.GetTypeMemberValues(context.SdbAgent, objectId, GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.OwnProperties, token); var exceptionObjectMessage = exceptionObject.FirstOrDefault(attr => attr["name"].Value <string>().Equals("_message")); exceptionObjectMessage["value"]["value"] = objRet["value"]?["className"]?.Value <string>() + ": " + exceptionObjectMessage["value"]?["value"]?.Value <string>(); return(exceptionObjectMessage["value"]?.Value <JObject>()); } return(objRet["value"]?.Value <JObject>()); } if (objRet["value"]?.Value <JObject>() != null) { return(objRet["value"]?.Value <JObject>()); } if (objRet["get"]?.Value <JObject>() != null && DotnetObjectId.TryParse(objRet?["get"]?["objectId"]?.Value <string>(), out DotnetObjectId getterObjectId)) { var ret = await context.SdbAgent.InvokeMethod(getterObjectId, token); return(await GetValueFromObject(ret, token)); } return(null); }
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 live_vars = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); //get_this var res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, live_vars), token); var scope_values = res.Value?["result"]?["value"]?.Values <JObject>()?.ToArray(); thisValue = scope_values?.FirstOrDefault(v => v["name"]?.Value <string>() == "this"); if (!only_search_on_this) { if (thisValue != null && expression == "this") { return(thisValue); } var value = scope_values.SingleOrDefault(sv => sv["name"]?.Value <string>() == expression); if (value != null) { return(value); } } //search in scope if (thisValue != null) { if (!DotnetObjectId.TryParse(thisValue["value"]["objectId"], out var objectId)) { return(null); } res = await SendMonoCommand(msg_id, MonoCommands.GetDetails(objectId), token); scope_values = res.Value?["result"]?["value"]?.Values <JObject>().ToArray(); var foundValue = scope_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); }
private static string ConvertJSToCSharpLocalVariableAssignment(string idName, JToken variable) { string typeRet; object valueRet; JToken value = variable["value"]; string type = variable["type"].Value <string>(); string subType = variable["subtype"]?.Value <string>(); switch (type) { case "string": { var str = value?.Value <string>(); str = str.Replace("\"", "\\\""); valueRet = $"\"{str}\""; typeRet = "string"; break; } case "symbol": { valueRet = $"'{value?.Value<char>()}'"; typeRet = "char"; break; } case "number": //casting to double and back to string would loose precision; so casting straight to string valueRet = value?.Value <string>(); typeRet = "double"; break; case "boolean": valueRet = value?.Value <string>().ToLowerInvariant(); typeRet = "bool"; break; case "object": if (variable["subtype"]?.Value <string>() == "null") { (valueRet, typeRet) = GetNullObject(variable["className"]?.Value <string>()); } else { if (!DotnetObjectId.TryParse(variable["objectId"], out DotnetObjectId objectId)) { throw new Exception($"Internal error: Cannot parse objectId for var {idName}, with value: {variable}"); } switch (objectId?.Scheme) { case "valuetype" when variable["isEnum"]?.Value <bool>() == true: typeRet = variable["className"]?.Value <string>(); valueRet = $"({typeRet}) {value["value"].Value<double>()}"; break;
public static bool TryParse(string id, out DotnetObjectId objectId) { objectId = null; try { if (id == null) { return(false); } if (!id.StartsWith("dotnet:")) { return(false); } string[] parts = id.Split(":"); if (parts.Length < 3) { return(false); } objectId = new DotnetObjectId(parts[1], int.Parse(parts[2])); switch (objectId.Scheme) { case "methodId": { parts = id.Split(":"); if (parts.Length > 3) { objectId.SubValue = int.Parse(parts[3]); } break; } } return(true); } catch (Exception) { return(false); } }
async Task <Result> RuntimeGetProperties(MessageId id, DotnetObjectId objectId, JToken args, CancellationToken token) { if (objectId.Scheme == "scope") { return(await GetScopeProperties(id, int.Parse(objectId.Value), token)); } var res = await SendMonoCommand(id, MonoCommands.GetDetails(objectId, args), token); if (res.IsErr) { return(res); } if (objectId.Scheme == "cfo_res") { // Runtime.callFunctionOn result object var value_json_str = res.Value["result"]?["value"]?["__value_as_json_string__"]?.Value <string>(); if (value_json_str != null) { res = Result.OkFromObject(new { result = JArray.Parse(value_json_str) }); } else { res = Result.OkFromObject(new { result = new { } }); } } else { res = Result.Ok(JObject.FromObject(new { result = res.Value["result"]["value"] })); } return(res); }
public static bool TryParse(string id, out DotnetObjectId objectId) { objectId = null; if (id == null) { return(false); } if (!id.StartsWith("dotnet:")) { return(false); } string[] parts = id.Split(":", 3); if (parts.Length < 3) { return(false); } objectId = new DotnetObjectId(parts[1], parts[2]); return(true); }
public static bool TryParse(JToken jToken, out DotnetObjectId objectId) => TryParse(jToken?.Value <string>(), out objectId);
// Checks Locals, followed by `this` public async Task <JObject> Resolve(string varName, CancellationToken token) { //has method calls if (varName.Contains('(')) { return(null); } string[] parts = varName.Split("."); JObject rootObject = null; if (scopeCache.MemberReferences.TryGetValue(varName, out JObject ret)) { return(ret); } if (scopeCache.ObjectFields.TryGetValue(varName, out JObject valueRet)) { return(await GetValueFromObject(valueRet, token)); } foreach (string part in parts) { string partTrimmed = part.Trim(); if (partTrimmed == "") { return(null); } if (rootObject != null) { if (rootObject?["subtype"]?.Value <string>() == "null") { return(null); } if (DotnetObjectId.TryParse(rootObject?["objectId"]?.Value <string>(), out DotnetObjectId objectId)) { var rootResObj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); var objRet = rootResObj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value <string>() == partTrimmed); if (objRet == null) { return(null); } rootObject = await GetValueFromObject(objRet, token); } continue; } if (scopeCache.Locals.Count == 0 && !localsFetched) { Result scope_res = await proxy.GetScopeProperties(sessionId, scopeId, token); if (scope_res.IsErr) { throw new Exception($"BUG: Unable to get properties for scope: {scopeId}. {scope_res}"); } localsFetched = true; } if (scopeCache.Locals.TryGetValue(partTrimmed, out JObject obj)) { rootObject = obj["value"]?.Value <JObject>(); } else if (scopeCache.Locals.TryGetValue("this", out JObject objThis)) { if (partTrimmed == "this") { rootObject = objThis?["value"].Value <JObject>(); } else if (DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value <string>(), out DotnetObjectId objectId)) { var rootResObj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); var objRet = rootResObj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value <string>() == partTrimmed); if (objRet != null) { rootObject = await GetValueFromObject(objRet, token); } else { return(null); } } } } scopeCache.MemberReferences[varName] = rootObject; return(rootObject); }
public async Task <JObject> Resolve(InvocationExpressionSyntax method, Dictionary <string, JObject> memberAccessValues, CancellationToken token) { var methodName = ""; try { JObject rootObject = null; var expr = method.Expression; if (expr is MemberAccessExpressionSyntax) { var memberAccessExpressionSyntax = expr as MemberAccessExpressionSyntax; rootObject = await Resolve(memberAccessExpressionSyntax.Expression.ToString(), token); methodName = memberAccessExpressionSyntax.Name.ToString(); } else if (expr is IdentifierNameSyntax) { if (scopeCache.ObjectFields.TryGetValue("this", out JObject valueRet)) { rootObject = await GetValueFromObject(valueRet, token); methodName = expr.ToString(); } } if (rootObject != null) { DotnetObjectId.TryParse(rootObject?["objectId"]?.Value <string>(), out DotnetObjectId objectId); var typeId = await proxy.SdbHelper.GetTypeIdFromObject(sessionId, int.Parse(objectId.Value), true, token); int methodId = await proxy.SdbHelper.GetMethodIdByName(sessionId, typeId[0], methodName, token); if (methodId == 0) { var typeName = await proxy.SdbHelper.GetTypeName(sessionId, typeId[0], token); throw new Exception($"Method '{methodName}' not found in type '{typeName}'"); } var command_params_obj = new MemoryStream(); var commandParamsObjWriter = new MonoBinaryWriter(command_params_obj); commandParamsObjWriter.WriteObj(objectId, proxy.SdbHelper); if (method.ArgumentList != null) { commandParamsObjWriter.Write((int)method.ArgumentList.Arguments.Count); foreach (var arg in method.ArgumentList.Arguments) { if (arg.Expression is LiteralExpressionSyntax) { if (!await commandParamsObjWriter.WriteConst(sessionId, arg.Expression as LiteralExpressionSyntax, proxy.SdbHelper, token)) { return(null); } } if (arg.Expression is IdentifierNameSyntax) { var argParm = arg.Expression as IdentifierNameSyntax; if (!await commandParamsObjWriter.WriteJsonValue(sessionId, memberAccessValues[argParm.Identifier.Text], proxy.SdbHelper, token)) { return(null); } } } var retMethod = await proxy.SdbHelper.InvokeMethod(sessionId, command_params_obj.ToArray(), methodId, "methodRet", token); return(await GetValueFromObject(retMethod, token)); } } return(null); } catch (Exception) { throw new Exception($"Unable to evaluate method '{methodName}'"); } }
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>(); var the_mono_frames = res.Value?["result"]?["value"]?["frames"]?.Values <JObject>(); foreach (var mono_frame in the_mono_frames) { int frame_id = mono_frame["frame_id"].Value <int>(); 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 && !asm.Image.HasSymbols) { try { method = await LoadSymbolsOnDemand(asm, method_token, sessionId, token); } catch (Exception e) { Log("info", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name} exception: {e.ToString()}"); continue; } } 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)); callFrames.Add(new { functionName = method_name, callFrameId = $"dotnet:scope:{frame_id}", 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}", }, 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); }
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); } SendResponse(id, Result.OkFromObject(new { }), token); 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); }
public async Task <JObject> Resolve(InvocationExpressionSyntax method, Dictionary <string, JObject> memberAccessValues, CancellationToken token) { var methodName = ""; int isTryingLinq = 0; try { JObject rootObject = null; var expr = method.Expression; if (expr is MemberAccessExpressionSyntax) { var memberAccessExpressionSyntax = expr as MemberAccessExpressionSyntax; rootObject = await Resolve(memberAccessExpressionSyntax.Expression.ToString(), token); methodName = memberAccessExpressionSyntax.Name.ToString(); } else if (expr is IdentifierNameSyntax) { if (scopeCache.ObjectFields.TryGetValue("this", out JObject valueRet)) { rootObject = await GetValueFromObject(valueRet, token); methodName = expr.ToString(); } } if (rootObject != null) { DotnetObjectId.TryParse(rootObject?["objectId"]?.Value <string>(), out DotnetObjectId objectId); var typeIds = await sdbHelper.GetTypeIdFromObject(sessionId, int.Parse(objectId.Value), true, token); int methodId = await sdbHelper.GetMethodIdByName(sessionId, typeIds[0], methodName, token); var className = await sdbHelper.GetTypeNameOriginal(sessionId, typeIds[0], token); if (methodId == 0) //try to search on System.Linq.Enumerable { if (linqTypeId == -1) { linqTypeId = await sdbHelper.GetTypeByName(sessionId, "System.Linq.Enumerable", token); } methodId = await sdbHelper.GetMethodIdByName(sessionId, linqTypeId, methodName, token); if (methodId != 0) { foreach (var typeId in typeIds) { var genericTypeArgs = await sdbHelper.GetTypeParamsOrArgsForGenericType(sessionId, typeId, token); if (genericTypeArgs.Count > 0) { isTryingLinq = 1; methodId = await sdbHelper.MakeGenericMethod(sessionId, methodId, genericTypeArgs, token); break; } } } } if (methodId == 0) { var typeName = await sdbHelper.GetTypeName(sessionId, typeIds[0], token); throw new Exception($"Method '{methodName}' not found in type '{typeName}'"); } var commandParamsObj = new MemoryStream(); var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj); if (isTryingLinq == 0) { commandParamsObjWriter.WriteObj(objectId, sdbHelper); } if (method.ArgumentList != null) { commandParamsObjWriter.Write((int)method.ArgumentList.Arguments.Count + isTryingLinq); if (isTryingLinq == 1) { commandParamsObjWriter.WriteObj(objectId, sdbHelper); } foreach (var arg in method.ArgumentList.Arguments) { if (arg.Expression is LiteralExpressionSyntax) { if (!await commandParamsObjWriter.WriteConst(sessionId, arg.Expression as LiteralExpressionSyntax, sdbHelper, token)) { return(null); } } if (arg.Expression is IdentifierNameSyntax) { var argParm = arg.Expression as IdentifierNameSyntax; if (!await commandParamsObjWriter.WriteJsonValue(sessionId, memberAccessValues[argParm.Identifier.Text], sdbHelper, token)) { return(null); } } } var retMethod = await sdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, "methodRet", token); return(await GetValueFromObject(retMethod, token)); } } return(null); } catch (Exception) { throw new Exception($"Unable to evaluate method '{methodName}'"); } }
public async Task <JObject> Resolve(ElementAccessExpressionSyntax elementAccess, Dictionary <string, JObject> memberAccessValues, JObject indexObject, CancellationToken token) { try { JObject rootObject = null; string elementAccessStrExpression = elementAccess.Expression.ToString(); rootObject = await Resolve(elementAccessStrExpression, token); if (rootObject == null) { rootObject = indexObject; indexObject = null; } if (rootObject != null) { string elementIdxStr; int elementIdx = 0; // x[1] or x[a] or x[a.b] if (indexObject == null) { if (elementAccess.ArgumentList != null) { var commandParamsObj = new MemoryStream(); var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj); foreach (var arg in elementAccess.ArgumentList.Arguments) { // e.g. x[1] if (arg.Expression is LiteralExpressionSyntax) { var argParm = arg.Expression as LiteralExpressionSyntax; elementIdxStr = argParm.ToString(); int.TryParse(elementIdxStr, out elementIdx); } // e.g. x[a] or x[a.b] if (arg.Expression is IdentifierNameSyntax) { var argParm = arg.Expression as IdentifierNameSyntax; // x[a.b] memberAccessValues.TryGetValue(argParm.Identifier.Text, out indexObject); // x[a] if (indexObject == null) { indexObject = await Resolve(argParm.Identifier.Text, token); } elementIdxStr = indexObject["value"].ToString(); int.TryParse(elementIdxStr, out elementIdx); } } } } // e.g. x[a[0]], x[a[b[1]]] etc. else { elementIdxStr = indexObject["value"].ToString(); int.TryParse(elementIdxStr, out elementIdx); } if (elementIdx >= 0) { DotnetObjectId.TryParse(rootObject?["objectId"]?.Value <string>(), out DotnetObjectId objectId); switch (objectId.Scheme) { case "array": rootObject["value"] = await sdbHelper.GetArrayValues(sessionId, int.Parse(objectId.Value), token); return((JObject)rootObject["value"][elementIdx]["value"]); case "object": var typeIds = await sdbHelper.GetTypeIdFromObject(sessionId, int.Parse(objectId.Value), true, token); int methodId = await sdbHelper.GetMethodIdByName(sessionId, typeIds[0], "ToArray", token); var commandParamsObj = new MemoryStream(); var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj); commandParamsObjWriter.WriteObj(objectId, sdbHelper); var toArrayRetMethod = await sdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, elementAccess.Expression.ToString(), token); rootObject = await GetValueFromObject(toArrayRetMethod, token); DotnetObjectId.TryParse(rootObject?["objectId"]?.Value <string>(), out DotnetObjectId arrayObjectId); rootObject["value"] = await sdbHelper.GetArrayValues(sessionId, int.Parse(arrayObjectId.Value), token); return((JObject)rootObject["value"][elementIdx]["value"]); default: throw new InvalidOperationException($"Cannot apply indexing with [] to an expression of type '{objectId.Scheme}'"); } } } return(null); } catch (Exception ex) { var e = ex; throw new Exception($"Unable to evaluate method '{elementAccess}'"); } }