You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
5.9 KiB

  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using ICSharpCode.Decompiler.TypeSystem;
  19. using ICSharpCode.Decompiler.Util;
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Linq;
  23. using System.Text;
  24. using System.Threading.Tasks;
  25. namespace ICSharpCode.Decompiler.IL.ControlFlow
  26. {
  27. /// <summary>
  28. /// This exception is thrown when we find something else than we expect from the C# compiler.
  29. /// This aborts the analysis and makes the whole transform fail.
  30. /// </summary>
  31. class SymbolicAnalysisFailedException : Exception
  32. {
  33. public SymbolicAnalysisFailedException() { }
  34. public SymbolicAnalysisFailedException(string message) : base(message) { }
  35. }
  36. enum SymbolicValueType
  37. {
  38. /// <summary>
  39. /// Unknown value
  40. /// </summary>
  41. Unknown,
  42. /// <summary>
  43. /// int: Constant (result of ldc.i4)
  44. /// </summary>
  45. IntegerConstant,
  46. /// <summary>
  47. /// int: State + Constant
  48. /// </summary>
  49. State,
  50. /// <summary>
  51. /// This pointer (result of ldarg.0)
  52. /// </summary>
  53. This,
  54. /// <summary>
  55. /// bool: ValueSet.Contains(State)
  56. /// </summary>
  57. StateInSet,
  58. }
  59. struct SymbolicValue
  60. {
  61. public readonly int Constant;
  62. public readonly SymbolicValueType Type;
  63. public readonly LongSet ValueSet;
  64. public SymbolicValue(SymbolicValueType type, int constant = 0)
  65. {
  66. this.Type = type;
  67. this.Constant = constant;
  68. }
  69. public SymbolicValue(SymbolicValueType type, LongSet valueSet)
  70. {
  71. this.Type = type;
  72. this.Constant = 0;
  73. this.ValueSet = valueSet;
  74. }
  75. public SymbolicValue AsBool()
  76. {
  77. if (Type == SymbolicValueType.State) {
  78. // convert state integer to bool:
  79. // if (state + c) = if (state + c != 0) = if (state != -c)
  80. return new SymbolicValue(SymbolicValueType.StateInSet, new LongSet(unchecked(-Constant)).Invert());
  81. }
  82. return this;
  83. }
  84. public override string ToString()
  85. {
  86. return string.Format("[SymbolicValue {0}: {1}]", this.Type, this.Constant);
  87. }
  88. }
  89. class SymbolicEvaluationContext
  90. {
  91. readonly IField stateField;
  92. readonly List<ILVariable> stateVariables = new List<ILVariable>();
  93. public SymbolicEvaluationContext(IField stateField)
  94. {
  95. this.stateField = stateField;
  96. }
  97. public void AddStateVariable(ILVariable v)
  98. {
  99. if (!stateVariables.Contains(v))
  100. stateVariables.Add(v);
  101. }
  102. public IEnumerable<ILVariable> StateVariables { get => stateVariables; }
  103. static readonly SymbolicValue Failed = new SymbolicValue(SymbolicValueType.Unknown);
  104. public SymbolicValue Eval(ILInstruction inst)
  105. {
  106. if (inst is BinaryNumericInstruction bni && bni.Operator == BinaryNumericOperator.Sub && !bni.CheckForOverflow) {
  107. var left = Eval(bni.Left);
  108. var right = Eval(bni.Right);
  109. if (left.Type != SymbolicValueType.State && left.Type != SymbolicValueType.IntegerConstant)
  110. return Failed;
  111. if (right.Type != SymbolicValueType.IntegerConstant)
  112. return Failed;
  113. return new SymbolicValue(left.Type, unchecked(left.Constant - right.Constant));
  114. } else if (inst.MatchLdFld(out var target, out var field)) {
  115. if (Eval(target).Type != SymbolicValueType.This)
  116. return Failed;
  117. if (field.MemberDefinition != stateField)
  118. return Failed;
  119. return new SymbolicValue(SymbolicValueType.State);
  120. } else if (inst.MatchLdLoc(out var loadedVariable)) {
  121. if (stateVariables.Contains(loadedVariable))
  122. return new SymbolicValue(SymbolicValueType.State);
  123. else if (loadedVariable.Kind == VariableKind.Parameter && loadedVariable.Index < 0)
  124. return new SymbolicValue(SymbolicValueType.This);
  125. else
  126. return Failed;
  127. } else if (inst.MatchLdcI4(out var value)) {
  128. return new SymbolicValue(SymbolicValueType.IntegerConstant, value);
  129. } else if (inst is Comp comp) {
  130. var left = Eval(comp.Left);
  131. var right = Eval(comp.Right);
  132. if (left.Type == SymbolicValueType.State && right.Type == SymbolicValueType.IntegerConstant) {
  133. // bool: (state + left.Constant == right.Constant)
  134. LongSet trueSums = SwitchAnalysis.MakeSetWhereComparisonIsTrue(comp.Kind, right.Constant, comp.Sign);
  135. // symbolic value is true iff trueSums.Contains(state + left.Constant)
  136. LongSet trueStates = trueSums.AddOffset(unchecked(-left.Constant));
  137. // symbolic value is true iff trueStates.Contains(state)
  138. return new SymbolicValue(SymbolicValueType.StateInSet, trueStates);
  139. } else if (left.Type == SymbolicValueType.StateInSet && right.Type == SymbolicValueType.IntegerConstant) {
  140. if (comp.Kind == ComparisonKind.Equality && right.Constant == 0) {
  141. // comp((x in set) == 0) ==> x not in set
  142. return new SymbolicValue(SymbolicValueType.StateInSet, left.ValueSet.Invert());
  143. } else if (comp.Kind == ComparisonKind.Inequality && right.Constant != 0) {
  144. // comp((x in set) != 0) => x in set
  145. return new SymbolicValue(SymbolicValueType.StateInSet, left.ValueSet);
  146. } else {
  147. return Failed;
  148. }
  149. } else {
  150. return Failed;
  151. }
  152. } else {
  153. return Failed;
  154. }
  155. }
  156. }
  157. }