/// <summary> /// Finds the length of an array or a primitive value for use in loop bounds /// </summary> /// <returns>The array length or primitive.</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="src">The expression to examine.</param> protected virtual DataElement ResolveArrayLengthOrPrimitive(NetworkState network, ProcessState proc, MethodState method, ICSharpCode.Decompiler.CSharp.Syntax.Expression src) { if (src is ICSharpCode.Decompiler.CSharp.Syntax.PrimitiveExpression) { try { return(new Constant { Source = src, DefaultValue = Convert.ToInt32((src as ICSharpCode.Decompiler.CSharp.Syntax.PrimitiveExpression).Value), CecilType = LoadType(typeof(int)), Parent = method }); } catch (Exception ex) { throw new Exception(string.Format("Unable to resolve as a constant value: {0}", src), ex); } } DataElement member; var ex_left = src as ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression; if (ex_left != null) { if (ex_left.MemberName != "Length") { throw new Exception(string.Format("Only plain style for loops supported: {0}", src)); } member = LocateDataElement(network, proc, method, null, ex_left.Target); } else { var ex_id = src as ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression; if (ex_id == null) { throw new ArgumentException(string.Format("Unable to resolve loop limit: {0}", src)); } return(LocateDataElement(network, proc, method, null, ex_id)); } if (member.CecilType.IsFixedArrayType()) { if (member.Source is IMemberDefinition) { return(new Constant { Source = member, DefaultValue = ((IMemberDefinition)member.Source).GetFixedArrayLength(), CecilType = LoadType(typeof(int)) }); } else if (member.Source is System.Reflection.MemberInfo) { return(new Constant { Source = member, DefaultValue = ((System.Reflection.MemberInfo)member.Source).GetFixedArrayLength(), CecilType = LoadType(typeof(int)) }); } } var value = member.DefaultValue; if (value is AST.ArrayCreateExpression) { var ce = (value as ArrayCreateExpression); var target = ce.ElementExpressions.Length; return(new Constant() { DefaultValue = target, Source = ce, CecilType = LoadType(typeof(int)) }); } else if (value is AST.EmptyArrayCreateExpression) { var ce = (value as EmptyArrayCreateExpression); var target = ce.SizeExpression.GetTarget(); if (target == null) { return(new Constant() { DefaultValue = ((PrimitiveExpression)ce.SizeExpression).Value, Source = ce, CecilType = LoadType(typeof(int)) }); } else { return(new Constant() { DefaultValue = target.DefaultValue, Source = target.Source, CecilType = LoadType(typeof(int)) }); } } if (value is ICSharpCode.Decompiler.CSharp.Syntax.ArrayCreateExpression) { return new Constant() { Source = value, DefaultValue = (value as ICSharpCode.Decompiler.CSharp.Syntax.ArrayCreateExpression).Initializer.Children.Count(), CecilType = LoadType(typeof(int)), Parent = method } } ; if (value is Array) { return new Constant() { DefaultValue = ((Array)value).Length, Source = value, CecilType = LoadType(typeof(int)) } } ; if (value is IMemberDefinition) { try { var mr = value as IMemberDefinition; if (mr is FieldDefinition && network.ConstantLookup.ContainsKey(mr as FieldDefinition)) { return(ResolveArrayLengthOrPrimitive(network, proc, method, new ICSharpCode.Decompiler.CSharp.Syntax.PrimitiveExpression(network.ConstantLookup[mr as FieldDefinition]))); } } catch (Exception ex) { throw new Exception(string.Format("Unable to resolve as a constant value: {0}", src), ex); } } try { return(new Constant() { Source = value, DefaultValue = Convert.ToInt32(value), CecilType = LoadType(typeof(int)), Parent = method }); } catch (Exception ex) { throw new Exception(string.Format("Unable to resolve as a constant value: {0}", src), ex); } }
/// <summary> /// Decompile the specified expression, given the network, process, method, and statement /// </summary> /// <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 decompile</param> protected Expression Decompile(NetworkState network, ProcessState proc, MethodState method, Statement statement, ICSharpCode.Decompiler.CSharp.Syntax.Expression expression) { if (expression is ICSharpCode.Decompiler.CSharp.Syntax.AssignmentExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.AssignmentExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.IdentifierExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression) { var mr = expression as ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression; if (mr.ToString() == "base.ShouldContinue") { return new PrimitiveExpression(true, method.SourceMethod.Module.ImportReference(typeof(bool))) { SourceExpression = mr, Parent = statement, } } ; return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.MemberReferenceExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.PrimitiveExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.PrimitiveExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.IndexerExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.IndexerExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.CastExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.CastExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.ConditionalExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.ConditionalExpression)); } 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; if (mt.ToString() == "base.PrintDebug" || mt.ToString() == "base.SimulationOnly") { return new EmptyExpression() { SourceExpression = si, Parent = statement } } ; if (mt.ToString() == "Console.WriteLine" || mt.ToString() == "Console.Write") { return new EmptyExpression() { SourceExpression = si, Parent = statement } } ; // 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(Decompile(network, proc, method, statement, new ICSharpCode.Decompiler.CSharp.Syntax.CastExpression(AstType.Create(mtm.SourceResultType.FullName), si.Arguments.First().Clone()))); } else if (mt.MemberName == "op_Increment") { return(Decompile(network, proc, method, statement, new ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorExpression(UnaryOperatorType.Increment, si.Arguments.First().Clone()))); } else if (mt.MemberName == "op_Decrement") { return(Decompile(network, proc, method, statement, new ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorExpression(UnaryOperatorType.Decrement, si.Arguments.First().Clone()))); } } return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.InvocationExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.ParenthesizedExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.ParenthesizedExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.NullReferenceExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.NullReferenceExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.ArrayCreateExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.ArrayCreateExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.CheckedExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.CheckedExpression)); } else if (expression is ICSharpCode.Decompiler.CSharp.Syntax.UncheckedExpression) { return(Decompile(network, proc, method, statement, expression as ICSharpCode.Decompiler.CSharp.Syntax.UncheckedExpression)); } else if (expression == ICSharpCode.Decompiler.CSharp.Syntax.Expression.Null) { return new EmptyExpression() { SourceExpression = expression } } ; else { throw new Exception(string.Format("Unsupported expression: {0} ({1})", expression, expression.GetType().FullName)); } }