private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[] flags, int offset, int argIndex, out int constant) { if ((flags[offset] & OpcodeFlags.BasicBlockStart) != 0) { constant = 0; return(false); } for (int currentOffset = offset - 1; currentOffset >= 0; currentOffset--) { if ((flags[currentOffset] & OpcodeFlags.InstructionStart) == 0) { continue; } ILReader reader = new ILReader(body, currentOffset); ILOpcode opcode = reader.ReadILOpcode(); if (opcode == ILOpcode.call || opcode == ILOpcode.callvirt) { MethodDesc method = (MethodDesc)methodIL.GetObject(reader.ReadILToken()); if (argIndex == 0) { BodySubstitution substitution = GetSubstitution(method); if (substitution != null && substitution.Value is int && (opcode != ILOpcode.callvirt || !method.IsVirtual)) { constant = (int)substitution.Value; return(true); } else { constant = 0; return(false); } } argIndex--; if (method.Signature.Length > 0 || !method.Signature.IsStatic) { // We don't know how to skip over the parameters break; } } else if (opcode == ILOpcode.ldsfld) { FieldDesc field = (FieldDesc)methodIL.GetObject(reader.ReadILToken()); if (argIndex == 0) { object substitution = GetSubstitution(field); if (substitution is int) { constant = (int)substitution; return(true); } else { constant = 0; return(false); } } argIndex--; } else if (opcode >= ILOpcode.ldc_i4_0 && opcode <= ILOpcode.ldc_i4_8) { if (argIndex == 0) { constant = opcode - ILOpcode.ldc_i4_0; return(true); } argIndex--; } else if (opcode == ILOpcode.ldc_i4) { if (argIndex == 0) { constant = (int)reader.ReadILUInt32(); return(true); } argIndex--; } else if (opcode == ILOpcode.ldc_i4_s) { if (argIndex == 0) { constant = (int)(sbyte)reader.ReadILByte(); return(true); } argIndex--; } else if ((opcode == ILOpcode.ldloc || opcode == ILOpcode.ldloc_s || (opcode >= ILOpcode.ldloc_0 && opcode <= ILOpcode.ldloc_3)) && ((flags[currentOffset] & OpcodeFlags.BasicBlockStart) == 0)) { // Paired stloc/ldloc that the C# compiler generates in debug code? int locIndex = opcode switch { ILOpcode.ldloc => reader.ReadILUInt16(), ILOpcode.ldloc_s => reader.ReadILByte(), _ => opcode - ILOpcode.ldloc_0, }; for (int potentialStlocOffset = currentOffset - 1; potentialStlocOffset >= 0; potentialStlocOffset--) { if ((flags[potentialStlocOffset] & OpcodeFlags.InstructionStart) == 0) { continue; } ILReader nestedReader = new ILReader(body, potentialStlocOffset); ILOpcode otherOpcode = nestedReader.ReadILOpcode(); if ((otherOpcode == ILOpcode.stloc || otherOpcode == ILOpcode.stloc_s || (otherOpcode >= ILOpcode.stloc_0 && otherOpcode <= ILOpcode.stloc_3)) && otherOpcode switch { ILOpcode.stloc => nestedReader.ReadILUInt16(), ILOpcode.stloc_s => nestedReader.ReadILByte(), _ => otherOpcode - ILOpcode.stloc_0, } == locIndex)
public void Scan(MethodIL methodBody) { MethodDesc thisMethod = methodBody.OwningMethod; ValueBasicBlockPair[] locals = new ValueBasicBlockPair[methodBody.GetLocals().Length]; Dictionary <int, Stack <StackSlot> > knownStacks = new Dictionary <int, Stack <StackSlot> >(); Stack <StackSlot> currentStack = new Stack <StackSlot>(methodBody.MaxStack); ScanExceptionInformation(knownStacks, methodBody); BasicBlockIterator blockIterator = new BasicBlockIterator(methodBody); MethodReturnValue = null; ILReader reader = new ILReader(methodBody.GetILBytes()); while (reader.HasNext) { int curBasicBlock = blockIterator.MoveNext(reader.Offset); if (knownStacks.ContainsKey(reader.Offset)) { if (currentStack == null) { // The stack copy constructor reverses the stack currentStack = new Stack <StackSlot>(knownStacks[reader.Offset].Reverse()); } else { currentStack = MergeStack(currentStack, knownStacks[reader.Offset]); } } if (currentStack == null) { currentStack = new Stack <StackSlot>(methodBody.MaxStack); } int offset = reader.Offset; ILOpcode opcode = reader.ReadILOpcode(); switch (opcode) { case ILOpcode.add: case ILOpcode.add_ovf: case ILOpcode.add_ovf_un: case ILOpcode.and: case ILOpcode.div: case ILOpcode.div_un: case ILOpcode.mul: case ILOpcode.mul_ovf: case ILOpcode.mul_ovf_un: case ILOpcode.or: case ILOpcode.rem: case ILOpcode.rem_un: case ILOpcode.sub: case ILOpcode.sub_ovf: case ILOpcode.sub_ovf_un: case ILOpcode.xor: case ILOpcode.cgt: case ILOpcode.cgt_un: case ILOpcode.clt: case ILOpcode.clt_un: case ILOpcode.shl: case ILOpcode.shr: case ILOpcode.shr_un: case ILOpcode.ceq: PopUnknown(currentStack, 2, methodBody, offset); PushUnknown(currentStack); reader.Skip(opcode); break; case ILOpcode.dup: currentStack.Push(currentStack.Peek()); break; case ILOpcode.ldnull: currentStack.Push(new StackSlot(NullValue.Instance)); break; case ILOpcode.ldc_i4_0: case ILOpcode.ldc_i4_1: case ILOpcode.ldc_i4_2: case ILOpcode.ldc_i4_3: case ILOpcode.ldc_i4_4: case ILOpcode.ldc_i4_5: case ILOpcode.ldc_i4_6: case ILOpcode.ldc_i4_7: case ILOpcode.ldc_i4_8: { int value = opcode - ILOpcode.ldc_i4_0; ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case ILOpcode.ldc_i4_m1: { ConstIntValue civ = new ConstIntValue(-1); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case ILOpcode.ldc_i4: { int value = (int)reader.ReadILUInt32(); ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case ILOpcode.ldc_i4_s: { int value = (sbyte)reader.ReadILByte(); ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case ILOpcode.arglist: case ILOpcode.ldftn: case ILOpcode.sizeof_: case ILOpcode.ldc_i8: case ILOpcode.ldc_r4: case ILOpcode.ldc_r8: PushUnknown(currentStack); reader.Skip(opcode); break; case ILOpcode.ldarg: case ILOpcode.ldarg_0: case ILOpcode.ldarg_1: case ILOpcode.ldarg_2: case ILOpcode.ldarg_3: case ILOpcode.ldarg_s: case ILOpcode.ldarga: case ILOpcode.ldarga_s: ScanLdarg(opcode, opcode switch { ILOpcode.ldarg => reader.ReadILUInt16(), ILOpcode.ldarga => reader.ReadILUInt16(), ILOpcode.ldarg_s => reader.ReadILByte(), ILOpcode.ldarga_s => reader.ReadILByte(), _ => opcode - ILOpcode.ldarg_0 }, currentStack, thisMethod); break;