public bool ShouldInclude(Code code, bool?isMemOp) { if (ExcludeCpuid.Count != 0) { if (CodeUtils.IsSpecialAvxAvx2(code)) { // AVX (reg,mem) or AVX2 (reg,reg). if (isMemOp is null) { // Remove the instruction if both AVX and AVX2 should be excluded. if (ExcludeCpuid.Contains(CpuidFeature.AVX) && ExcludeCpuid.Contains(CpuidFeature.AVX2)) { return(false); } } else if (isMemOp.GetValueOrDefault()) { if (ExcludeCpuid.Contains(CpuidFeature.AVX)) { return(false); } } else { if (ExcludeCpuid.Contains(CpuidFeature.AVX2)) { return(false); } } } else { foreach (var cpuid in code.CpuidFeatures()) { if (ExcludeCpuid.Contains(cpuid)) { return(false); } } } } if (IncludeCpuid.Count != 0) { bool include = false; foreach (var cpuid in code.CpuidFeatures()) { if (IncludeCpuid.Contains(cpuid)) { include = true; break; } } if (!include) { return(false); } } if (IncludeCode.Count != 0 && !IncludeCode.Contains(code)) { return(false); } if (ExcludeCode.Contains(code)) { return(false); } return(true); }
FuzzerInstruction(Code code, FuzzerInstructionFlags flags, uint w, uint l, MandatoryPrefix mandatoryPrefix, FuzzerOpCodeTable table, OpCode opCode, int groupIndex, int rmGroupIndex, bool isModrmMemory, int operandSize, int addressSize) { // Should be a 2-byte opcode instead (groupIndex = modrm.reg and rmGroupIndex = modrm.rm bits) Assert.True(groupIndex < 0 || rmGroupIndex < 0); Assert.True(groupIndex >= -1 && groupIndex <= 7); Assert.True(rmGroupIndex >= -1 && rmGroupIndex <= 7); var opc = code.ToOpCode(); Assert.True(opc.IsInstruction || code == Code.INVALID); if (isModrmMemory) { if (opc.CanBroadcast) { flags |= FuzzerInstructionFlags.CanBroadcast; } if (opc.CanUseLockPrefix) { flags |= FuzzerInstructionFlags.CanUseLockPrefix; } } else { if (opc.CanUseRoundingControl) { flags |= FuzzerInstructionFlags.CanUseRoundingControl; } if (opc.CanSuppressAllExceptions) { flags |= FuzzerInstructionFlags.CanSuppressAllExceptions; } } if (opc.RequireNonZeroOpMaskRegister) { flags |= FuzzerInstructionFlags.RequireNonZeroOpMaskRegister; } if (opc.CanUseZeroingMasking) { flags |= FuzzerInstructionFlags.CanUseZeroingMasking; } if (opc.CanUseOpMaskRegister) { flags |= FuzzerInstructionFlags.CanUseOpMaskRegister; } switch (code) { case Code.Xchg_r16_AX: case Code.Xchg_r32_EAX: case Code.Xchg_r64_RAX: flags |= FuzzerInstructionFlags.IsXchgRegAcc; break; case Code.Nopw: case Code.Nopd: case Code.Nopq: flags |= FuzzerInstructionFlags.IsNop; break; case Code.Rdrand_r16: case Code.Rdrand_r32: case Code.Rdrand_r64: case Code.Rdseed_r16: case Code.Rdseed_r32: case Code.Rdseed_r64: case Code.Movbe_r16_m16: case Code.Movbe_r32_m32: case Code.Movbe_r64_m64: case Code.Movbe_m16_r16: case Code.Movbe_m32_r32: case Code.Movbe_m64_r64: Assert.True(mandatoryPrefix == MandatoryPrefix.None); mandatoryPrefix = MandatoryPrefix.PNP; flags |= FuzzerInstructionFlags.IsNFx; break; } Code = code; Flags = flags; W = w; L = l; MandatoryPrefix = mandatoryPrefix; Table = table; OpCode = opCode; GroupIndex = groupIndex; RmGroupIndex = rmGroupIndex; IsModrmMemory = isModrmMemory; OperandSize = operandSize; AddressSize = addressSize; if (MandatoryPrefix == MandatoryPrefix.P66 && operandSize != 64 && CodeUtils.IsReservedNop(Code)) { MandatoryPrefix = MandatoryPrefix.None; } FuzzerOperand[]? operands = null; // Special support for reserved nop instructions since we may have transformed them to // a 2-byte opcode (no ops) or a reg or rm group (one operand). if (CodeUtils.IsReservedNop(code)) { // Verify our assumptions Assert.True(opc.OpCount == 2); const int RM_INDEX = 0; const int REG_INDEX = 1; switch (opc.GetOpKind(RM_INDEX)) { case OpCodeOperandKind.r16_or_mem: case OpCodeOperandKind.r32_or_mem: case OpCodeOperandKind.r64_or_mem: break; default: throw ThrowHelpers.Unreachable; } switch (opc.GetOpKind(REG_INDEX)) { case OpCodeOperandKind.r16_reg: case OpCodeOperandKind.r32_reg: case OpCodeOperandKind.r64_reg: break; default: throw ThrowHelpers.Unreachable; } if (OpCode.IsTwobyte) { Assert.True(groupIndex < 0 && rmGroupIndex < 0); operands = Array.Empty <FuzzerOperand>(); } else if (groupIndex >= 0) { Assert.True(rmGroupIndex < 0); // reg bits are hard coded, rm bits can be used operands = new FuzzerOperand[1] { FuzzerOperands.GetOperand(opc.GetOpKind(RM_INDEX), isModrmMemory) }; } else if (rmGroupIndex >= 0) { // rm bits are hard coded, reg bits can be used operands = new FuzzerOperand[1] { FuzzerOperands.GetOperand(opc.GetOpKind(REG_INDEX), isModrmMemory) }; } } if (operands is null) { int opCount = opc.OpCount + (opc.CanUseOpMaskRegister ? 1 : 0); operands = opCount == 0 ? Array.Empty <FuzzerOperand>() : new FuzzerOperand[opCount]; int i; for (i = 0; i < opc.OpCount; i++) { operands[i] = FuzzerOperands.GetOperand(opc.GetOpKind(i), isModrmMemory); } if (opc.CanUseOpMaskRegister) { operands[i++] = FuzzerOperands.OpMaskRegister; } Assert.True(i == operands.Length); } operands = operands.Where(a => a.Kind != FuzzerOperandKind.None).ToArray(); Operands = operands; Assert.True(!opc.CanUseOpMaskRegister || (operands.Length > 0 && operands[operands.Length - 1] == FuzzerOperands.OpMaskRegister)); ImmediateOperands = operands.OfType <ImmediateFuzzerOperand>().ToArray(); MemOffsOperands = operands.Where(a => a.Kind == FuzzerOperandKind.MemOffs).ToArray(); ImpliedMemOperands = operands.Where(a => a.Kind == FuzzerOperandKind.ImpliedMem).ToArray(); ModrmMemoryOperands = operands.OfType <ModrmMemoryFuzzerOperand>().ToArray(); RegisterOperands = operands.OfType <RegisterFuzzerOperand>().ToArray(); // There are fuzzers that test only some of these op kinds, so if there's a new op kind, a new fuzzer would need // to be added, see eg AllMemOffsFuzzerGen Assert.True(Operands.Length == ImmediateOperands.Length + MemOffsOperands.Length + ImpliedMemOperands.Length + ModrmMemoryOperands.Length + RegisterOperands.Length); foreach (var memOp in ModrmMemoryOperands) { if (memOp.IsVSIB) { Flags |= FuzzerInstructionFlags.IsVsib; break; } } }