/// <summary> /// Locates a bus by reference /// </summary> /// <returns>The bus.</returns> /// <param name="network">The top-level network.</param> /// <param name="proc">The process where the method is located.</param> /// <param name="method">The method the expression is found.</param> /// <param name="expression">The expression used to initialize the bus.</param> protected virtual Bus LocateBus(NetworkState network, ProcessState proc, MethodState method, ICSharpCode.Decompiler.CSharp.Syntax.Expression expression) { var de = TryLocateElement(network, proc, method, null, expression); if (de is AST.Bus) { return(de as AST.Bus); } throw new Exception("Need to walk the tree?"); }
/// <summary> /// Locates the target for an expression. /// </summary> /// <returns>The data element.</returns> /// <param name="network">The top-level network.</param> /// <param name="proc">The process where the method is located.</param> /// <param name="method">The method where the statement is found.</param> /// <param name="statement">The statement where the expression is found.</param> /// <param name="expression">The expression to examine.</param> protected ASTItem TryLocateElement(NetworkState network, ProcessState proc, MethodState method, Statement statement, ICSharpCode.Decompiler.CSharp.Syntax.Expression expression) { if (expression is ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression; var target = e.Target; return(LocateDataElement(network, proc, method, statement, target)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.IndexerExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.IndexerExpression; var target = e.Target; return(LocateDataElement(network, proc, method, statement, target)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression; var name = e.Identifier; Variable variable; if (method != null && method.TryGetVariable(name, out variable)) { return(variable); } if (method != null) { var p = method.Parameters.FirstOrDefault(x => x.Name == name); if (p != null) { return(p); } } if (proc.Variables.TryGetValue(name, out variable)) { return(variable); } Signal signal; if (proc != null && proc.Signals.TryGetValue(name, out signal)) { return(signal); } return(null); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression; ASTItem current = null; var parts = new List <string>(); ICSharpCode.Decompiler.CSharp.Syntax.Expression ec = e; while (ec != null) { if (ec is ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression) { parts.Add(((ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression)ec).MemberName); ec = ((ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression)ec).Target; } else if (ec is ICSharpCode.Decompiler.CSharp.Syntax.ThisReferenceExpression) { //parts.Add("this"); ec = null; break; } else if (ec is ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression) { parts.Add(((ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression)ec).Identifier); ec = null; break; } else if (ec is ICSharpCode.Decompiler.CSharp.Syntax.TypeReferenceExpression) { TypeDefinition dc = null; if (method != null) { dc = method.SourceMethod.DeclaringType; } else if (proc != null) { dc = proc.CecilType.Resolve(); } var ecs = ec.ToString(); if (dc != null) { if (ecs == dc.FullName || ecs == dc.Name) { ec = null; //parts.Add("this"); break; } var targetproc = network.Processes.FirstOrDefault(x => x.CecilType.Name == ecs || x.CecilType.FullName == ecs); if (targetproc != null) { // This is a static reference current = null; //targetproc; break; } var bt = LoadTypeByName(ecs, dc.Module); if (bt == null) { bt = LoadTypeByName(dc.FullName + "." + ecs, method.SourceMethod.Module); } if (bt == null) { bt = LoadTypeByName(dc.Namespace + "." + ecs, method.SourceMethod.Module); } // In some cases dc.Namespace is empty ... if (bt == null && proc != null && proc.SourceType != null) { bt = LoadTypeByName(proc.SourceType.Namespace + "." + ecs, method.SourceMethod.Module); } if (bt != null && parts.Count == 1) { var br = bt.Resolve(); var px = br.Fields.FirstOrDefault(x => x.Name == parts[0]); // Enum flags are encoded as constants if (br.IsEnum) { if (px == null) { throw new Exception($"Unable to find enum value {parts[0]} in {br.FullName}"); } return(new Constant() { CecilType = bt, DefaultValue = px, Source = expression }); } else { // This is a constant of sorts var pe = network.ConstantLookup.Keys.FirstOrDefault(x => x.Name == parts[0]); if (pe != null) { return(network.ConstantLookup[pe]); } return(network.ConstantLookup[px] = new Constant() { CecilType = px.FieldType, Name = parts[0], Source = px, Parent = network }); } //parts.AddRange(bt.FullName.Split('.').Reverse()); } break; } // Likely a static reference, which is stored as a global constant ec = null; } else { throw new Exception($"Unexpected element in reference chain: {ec.GetType().FullName}"); } } parts.Reverse(); var fullname = string.Join(".", parts); if (parts.First() == "this") { parts.RemoveAt(0); if (proc == null) { throw new Exception("Attempting to do a resolve of \this\" but no process context is provided"); } current = proc; } var first = true; foreach (var el in parts) { var isIsFirst = first; first = false; if (current == null) { var pe = network.ConstantLookup.Keys.FirstOrDefault(x => x.Name == el); if (pe != null) { current = network.ConstantLookup[pe]; continue; } } if (current is MethodState || (isIsFirst && current == null)) { //if (method.LocalRenames.ContainsKey(el)) // el = method.LocalRenames[el]; var mt = current as MethodState ?? method; if (mt != null) { Variable temp; if (mt.TryGetVariable(el, out temp)) { current = temp; continue; } var p = mt.Parameters.FirstOrDefault(x => x.Name == el); if (p != null) { current = p; continue; } if (mt.ReturnVariable != null && !string.IsNullOrWhiteSpace(mt.ReturnVariable.Name) && el == mt.ReturnVariable.Name) { current = mt.ReturnVariable; continue; } } } if (current is ProcessState || (isIsFirst && current == null)) { var pr = current as ProcessState ?? proc; if (pr != null) { if (pr.BusInstances.ContainsKey(el)) { current = pr.BusInstances[el]; continue; } if (pr.Signals.ContainsKey(el)) { current = pr.Signals[el]; continue; } if (pr.Variables.ContainsKey(el)) { current = pr.Variables[el]; continue; } if (pr.Methods != null) { var p = pr.Methods.FirstOrDefault(x => x.Name == el); if (p != null) { current = p; continue; } } } } if (current is Bus) { current = ((Bus)current).Signals.FirstOrDefault(x => x.Name == el); if (current != null) { continue; } } if (current is Variable) { var fi = ((Variable)current).CecilType.Resolve().Fields.FirstOrDefault(x => x.Name == el); if (fi != null) { current = new Variable() { Name = el, Parent = current, Source = fi, CecilType = fi.FieldType, DefaultValue = null }; continue; } var pi = ((Variable)current).CecilType.Resolve().Properties.FirstOrDefault(x => x.Name == el); if (pi != null) { current = new Variable() { Name = el, Parent = current, Source = fi, CecilType = fi.FieldType, DefaultValue = null }; continue; } } if (el == "Length" && (current is DataElement) && ((DataElement)current).CecilType.IsArrayType()) { return(new Constant() { ArrayLengthSource = current as DataElement, CecilType = LoadType(typeof(int)), DefaultValue = null, Source = (current as DataElement).Source }); } throw new Exception($"Failed lookup at {el} in {fullname}"); } if (current == null) { throw new Exception($"Failed to fully resolve {fullname}"); } return(current); } else { throw new Exception($"Unable to find a data element for an expression of type {expression.GetType().FullName}"); } }
/// <summary> /// Locates the target for an expression, and throws an exception if not found. /// </summary> /// <returns>The data element.</returns> /// <param name="network">The top-level network.</param> /// <param name="proc">The process where the method is located.</param> /// <param name="method">The method where the statement is found.</param> /// <param name="statement">The statement where the expression is found.</param> /// <param name="expression">The expression to examine.</param> protected virtual DataElement LocateDataElement(NetworkState network, ProcessState proc, MethodState method, Statement statement, ICSharpCode.Decompiler.CSharp.Syntax.Expression expression) { var res = TryLocateDataElement(network, proc, method, statement, expression); if (res == null) { throw new Exception($"Unable to locate item for {expression}"); } return(res); }
/// <summary> /// Locates the target for an expression. /// </summary> /// <returns>The data element.</returns> /// <param name="network">The top-level network.</param> /// <param name="proc">The process where the method is located.</param> /// <param name="method">The method where the statement is found.</param> /// <param name="statement">The statement where the expression is found.</param> /// <param name="expression">The expression to examine.</param> protected DataElement TryLocateDataElement(NetworkState network, ProcessState proc, MethodState method, Statement statement, ICSharpCode.Decompiler.CSharp.Syntax.Expression expression) { var el = TryLocateElement(network, proc, method, statement, expression); if (el == null) { return(null); } if (!(el is DataElement)) { throw new Exception($"Failed to fully resolve {expression.ToString()}, got a result of type {el.GetType().FullName}"); } return((DataElement)el); }
/// <summary> /// Examines the given expression and returns the resulting output type from the expression /// </summary> /// <returns>The expression type.</returns> /// <param name="network">The top-level network.</param> /// <param name="proc">The process where the method is located.</param> /// <param name="method">The method where the statement is found.</param> /// <param name="statement">The statement where the expression is found.</param> /// <param name="expression">The expression to examine.</param> protected TypeReference ResolveExpressionType(NetworkState network, ProcessState proc, MethodState method, Statement statement, ICSharpCode.Decompiler.CSharp.Syntax.Expression expression) { if (expression is ICSharpCode.Decompiler.CSharp.Syntax.AssignmentExpression) { return(ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.AssignmentExpression).Left)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression) { return(LocateDataElement(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression).CecilType); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression) { var el = TryLocateElement(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression); if (el == null) { throw new Exception($"Location failed for expression {expression}"); } else if (el is DataElement) { return(((DataElement)el).CecilType); } else if (el is Method) { var rv = ((Method)el).ReturnVariable; if (rv == null) { return(null); } return(rv.CecilType); } else { throw new Exception($"Unexpected result for {expression} {el.GetType().FullName}"); } } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.PrimitiveExpression) { return(LoadType((expression as ICSharpCode.Decompiler.CSharp.Syntax.PrimitiveExpression).Value.GetType())); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorExpression) { var e = expression as ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorExpression; var op = e.Operator; if (op.IsCompareOperator() || op.IsLogicalOperator()) { return(LoadType(typeof(bool))); } var lefttype = ResolveExpressionType(network, proc, method, statement, e.Left); //var righttype = ResolveExpressionType(network, proc, method, statement, e.Right); if (op.IsArithmeticOperator() || op.IsBitwiseOperator()) { var righttype = ResolveExpressionType(network, proc, method, statement, e.Right); // Custom resolve of the resulting type as dictated by the .Net rules if (righttype.IsSameTypeReference <double>() || lefttype.IsSameTypeReference <double>()) { return(lefttype.LoadType(typeof(double))); } if (righttype.IsSameTypeReference <float>() || lefttype.IsSameTypeReference <float>()) { return(lefttype.LoadType(typeof(float))); } if (righttype.IsSameTypeReference <ulong>() || lefttype.IsSameTypeReference <ulong>()) { return(lefttype.LoadType(typeof(ulong))); } if (righttype.IsSameTypeReference <long>() || lefttype.IsSameTypeReference <long>()) { return(lefttype.LoadType(typeof(long))); } if (righttype.IsSameTypeReference <uint>() || lefttype.IsSameTypeReference <uint>()) { if (lefttype.IsSameTypeReference <sbyte>() || lefttype.IsSameTypeReference <short>() || righttype.IsSameTypeReference <sbyte>() || righttype.IsSameTypeReference <short>()) { return(lefttype.LoadType(typeof(long))); } else { return(lefttype.LoadType(typeof(uint))); } } if (righttype.IsSameTypeReference <int>() || lefttype.IsSameTypeReference <int>()) { if (righttype.IsSameTypeReference <uint>() || lefttype.IsSameTypeReference <uint>()) { return(lefttype.LoadType(typeof(uint))); } else { return(lefttype.LoadType(typeof(int))); } } if (righttype.IsSameTypeReference <ushort>() || lefttype.IsSameTypeReference <ushort>()) { return(lefttype.LoadType(typeof(int))); } if (righttype.IsSameTypeReference <short>() || lefttype.IsSameTypeReference <short>()) { return(lefttype.LoadType(typeof(int))); } if (righttype.IsSameTypeReference <sbyte>() || lefttype.IsSameTypeReference <sbyte>()) { return(lefttype.LoadType(typeof(int))); } if (righttype.IsSameTypeReference <byte>() || lefttype.IsSameTypeReference <byte>()) { return(lefttype.LoadType(typeof(int))); } Console.WriteLine("Warning: unable to determine result type for operation {0} on types {1} and {2}", op, lefttype, righttype); //TODO: Return a larger type, double the bits? return(lefttype); } else { // TODO: Find the largest type? return(lefttype); } } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorExpression) { return(ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorExpression).Expression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.IndexerExpression) { var arraytype = ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.IndexerExpression).Target); return(arraytype.GetArrayElementType()); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.CastExpression) { return(LoadType((expression as ICSharpCode.Decompiler.CSharp.Syntax.CastExpression).Type, method)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.ConditionalExpression) { return(ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.ConditionalExpression).TrueExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression) { var si = expression as ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression; var mt = si.Target as ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression; // Catch common translations if (mt != null && (expression as ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression).Arguments.Count == 1) { if (mt.MemberName == "op_Implicit" || mt.MemberName == "op_Explicit") { var mtm = Decompile(network, proc, method, statement, mt); return(ResolveExpressionType(network, proc, method, statement, new ICSharpCode.Decompiler.CSharp.Syntax.CastExpression(ICSharpCode.Decompiler.CSharp.Syntax.AstType.Create(mtm.SourceResultType.FullName), si.Arguments.First().Clone()))); } else if (mt.MemberName == "op_Increment") { return(ResolveExpressionType(network, proc, method, statement, new ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorExpression(ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.Increment, si.Arguments.First().Clone()))); } else if (mt.MemberName == "op_Decrement") { return(ResolveExpressionType(network, proc, method, statement, new ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorExpression(ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.Decrement, si.Arguments.First().Clone()))); } } var m = proc.CecilType.Resolve().GetMethods().FirstOrDefault(x => x.Name == mt.MemberName); if (m != null) { return(m.ReturnType); } return(ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression).Target)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.ParenthesizedExpression) { return(ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.ParenthesizedExpression).Expression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.NullReferenceExpression) { return(null); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.ArrayCreateExpression) { return(ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.ArrayCreateExpression).Initializer.FirstChild as ICSharpCode.Decompiler.CSharp.Syntax.Expression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.CheckedExpression) { return(ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.CheckedExpression).Expression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.UncheckedExpression) { return(ResolveExpressionType(network, proc, method, statement, (expression as ICSharpCode.Decompiler.CSharp.Syntax.UncheckedExpression).Expression)); } else if (expression == ICSharpCode.Decompiler.CSharp.Syntax.Expression.Null) { return(null); } else { throw new Exception(string.Format("Unsupported expression: {0} ({1})", expression, expression.GetType().FullName)); } }