Exemple #1
0
        void Register_is_not_too_big()
        {
            const int maxValue = IcedConstants.RegisterEnumCount - 1 + Registers.ExtraRegisters;

            Static.Assert(maxValue < (1 << InstrOpInfo.TEST_RegisterBits) ? 0 : -1);
            Static.Assert(maxValue >= (1 << (InstrOpInfo.TEST_RegisterBits - 1)) ? 0 : -1);
        }
        static (string hexBytes, Code code, DecoderOptions options, InstructionInfoTestCase testCase) ParseLine(string line, int bitness, Dictionary <string, Register> toRegister)
        {
            Static.Assert(MiscInstrInfoTestConstants.InstrInfoElemsPerLine == 5 ? 0 : -1);
            var elems = line.Split(commaSeparator, MiscInstrInfoTestConstants.InstrInfoElemsPerLine);

            if (elems.Length != MiscInstrInfoTestConstants.InstrInfoElemsPerLine)
            {
                throw new Exception($"Expected {MiscInstrInfoTestConstants.InstrInfoElemsPerLine - 1} commas");
            }

            var testCase = new InstructionInfoTestCase();

            testCase.IP = bitness switch {
                16 => DecoderConstants.DEFAULT_IP16,
                32 => DecoderConstants.DEFAULT_IP32,
                64 => DecoderConstants.DEFAULT_IP64,
                _ => throw new InvalidOperationException(),
            };

            var hexBytes = ToHexBytes(elems[0].Trim());
            var codeStr  = elems[1].Trim();

            if (CodeUtils.IsIgnored(codeStr))
            {
                return(default);
Exemple #3
0
        /// <summary>
        /// Negates the condition code, eg. <c>JE</c> -> <c>JNE</c>. Can be used if it's <c>Jcc</c>, <c>SETcc</c>, <c>CMOVcc</c>, <c>LOOPcc</c>
        /// and returns the original value if it's none of those instructions.
        /// </summary>
        /// <param name="code">Code value</param>
        /// <returns></returns>
        public static Code NegateConditionCode(this Code code)
        {
            uint t;

            if ((t = (uint)(code - Code.Jo_rel16)) <= (uint)(Code.Jg_rel32_64 - Code.Jo_rel16) ||
                (t = (uint)(code - Code.Jo_rel8_16)) <= (uint)(Code.Jg_rel8_64 - Code.Jo_rel8_16) ||
                (t = (uint)(code - Code.Cmovo_r16_rm16)) <= (uint)(Code.Cmovg_r64_rm64 - Code.Cmovo_r16_rm16))
            {
                // They're ordered, eg. je_16, je_32, je_64, jne_16, jne_32, jne_64
                // if low 3, add 3, else if high 3, subtract 3.
                //return (((int)((t / 3) << 31) >> 31) | 1) * 3 + code;
                if (((t / 3) & 1) != 0)
                {
                    return(code - 3);
                }
                return(code + 3);
            }

            t = (uint)(code - Code.Seto_rm8);
            if (t <= (uint)(Code.Setg_rm8 - Code.Seto_rm8))
            {
                return((int)(t ^ 1) + Code.Seto_rm8);
            }

            Static.Assert(Code.Loopne_rel8_16_CX + 7 == Code.Loope_rel8_16_CX ? 0 : -1);
            t = (uint)(code - Code.Loopne_rel8_16_CX);
            if (t <= (uint)(Code.Loope_rel8_64_RCX - Code.Loopne_rel8_16_CX))
            {
                return(Code.Loopne_rel8_16_CX + (int)((t + 7) % 14));
            }

            return(code);
        }
Exemple #4
0
        public override void Decode(Decoder decoder, ref Instruction instruction)
        {
            Debug.Assert(decoder.state.Encoding == EncodingKind.MVEX);
            if (decoder.invalidCheckMask != 0 && ((decoder.state.vvvv_invalidCheck & 0xF) != 0 || decoder.state.aaa == 0))
            {
                decoder.SetInvalidInstruction();
            }
            instruction.InternalSetCodeNoCheck(code);

            Static.Assert(OpKind.Register == 0 ? 0 : -1);
            //instruction.Op1Kind = OpKind.Register;
            instruction.Op1Register = (int)(decoder.state.reg + decoder.state.zs.extraRegisterBase + decoder.state.extraRegisterBaseEVEX) + Register.ZMM0;
            var mvex = new MvexInfo(code);
            var sss  = decoder.state.Sss;

            if (decoder.state.mod == 3)
            {
                decoder.SetInvalidInstruction();
            }
            else
            {
                instruction.Op0Kind = OpKind.Memory;
                if ((decoder.state.zs.flags & StateFlags.MvexEH) != 0)
                {
                    instruction.InternalSetIsMvexEvictionHint();
                }
                if ((mvex.InvalidConvFns & (1U << sss) & decoder.invalidCheckMask) != 0)
                {
                    decoder.SetInvalidInstruction();
                }
                instruction.InternalSetMvexRegMemConv(MvexRegMemConv.MemConvNone + sss);
                decoder.ReadOpMem_VSIB(ref instruction, Register.ZMM0, mvex.GetTupleType(sss));
            }
        }
        static MemorySizeInfoTestCase ParseLine(string line, int lineNo)
        {
            Static.Assert(MiscInstrInfoTestConstants.MemorySizeElemsPerLine == 6 ? 0 : -1);
            var elems = line.Split(commaSeparator, MiscInstrInfoTestConstants.MemorySizeElemsPerLine);

            if (elems.Length != MiscInstrInfoTestConstants.MemorySizeElemsPerLine)
            {
                throw new Exception($"Expected {MiscInstrInfoTestConstants.MemorySizeElemsPerLine - 1} commas");
            }

            var tc = new MemorySizeInfoTestCase();

            tc.LineNumber   = lineNo;
            tc.MemorySize   = ToEnumConverter.GetMemorySize(elems[0].Trim());
            tc.Size         = NumberConverter.ToInt32(elems[1].Trim());
            tc.ElementSize  = NumberConverter.ToInt32(elems[2].Trim());
            tc.ElementType  = ToEnumConverter.GetMemorySize(elems[3].Trim());
            tc.ElementCount = NumberConverter.ToInt32(elems[4].Trim());
            foreach (var value in elems[5].Split(spaceSeparator, StringSplitOptions.RemoveEmptyEntries))
            {
                if (!InstructionInfoDicts.MemorySizeFlagsTable.TryGetValue(value, out var flags))
                {
                    throw new InvalidOperationException($"Invalid flags value: {value}");
                }
                tc.Flags |= flags;
            }
            return(tc);
        }
Exemple #6
0
		public static bool IsNotrackPrefixBranch(Code code) {
			Static.Assert(Code.Jmp_rm16 + 1 == Code.Jmp_rm32 ? 0 : -1);
			Static.Assert(Code.Jmp_rm16 + 2 == Code.Jmp_rm64 ? 0 : -1);
			Static.Assert(Code.Call_rm16 + 1 == Code.Call_rm32 ? 0 : -1);
			Static.Assert(Code.Call_rm16 + 2 == Code.Call_rm64 ? 0 : -1);
			return (uint)code - (uint)Code.Jmp_rm16 <= 2 || (uint)code - (uint)Code.Call_rm16 <= 2;
		}
        public override void Decode(Decoder decoder, ref Instruction instruction)
        {
            Debug.Assert(decoder.state.Encoding == EncodingKind.Legacy);
            Static.Assert(OpKind.Register == 0 ? 0 : -1);
            //instruction.Op0Kind = OpKind.Register;
            instruction.Op0Register = (int)decoder.state.reg + Register.MM0;
            if (decoder.state.mod == 3)
            {
                Static.Assert(OpKind.Register == 0 ? 0 : -1);
                //instruction.Op1Kind = OpKind.Register;
                instruction.Op1Register = (int)decoder.state.rm + Register.MM0;
            }
            else
            {
                instruction.Op1Kind = OpKind.Memory;
                decoder.ReadOpMem(ref instruction);
            }
            var code = codeValues[(int)decoder.ReadByte()];

            switch (code)
            {
            case Code.D3NOW_Pfrcpv_mm_mmm64:
            case Code.D3NOW_Pfrsqrtv_mm_mmm64:
                if ((decoder.options & DecoderOptions.Cyrix) == 0 || decoder.Bitness == 64)
                {
                    code = Code.INVALID;
                }
                break;
            }
            instruction.InternalSetCodeNoCheck(code);
            if (code == Code.INVALID)
            {
                decoder.SetInvalidInstruction();
            }
        }
        void INVALID_Code_value_is_zero()
        {
            // A 'default' Instruction should be an invalid instruction
            Static.Assert((int)Code.INVALID == 0 ? 0 : -1);
            Instruction instruction1 = default;

            Assert.Equal(Code.INVALID, instruction1.Code);
            var instruction2 = new Instruction();

            Assert.Equal(Code.INVALID, instruction2.Code);
            Assert.True(Instruction.EqualsAllBits(instruction1, instruction2));
        }
Exemple #9
0
 public OpCodeHandler_MandatoryPrefix2_NoModRM(OpCodeHandler handler, OpCodeHandler handler66, OpCodeHandler handlerF3, OpCodeHandler handlerF2)
 {
     Static.Assert((int)MandatoryPrefixByte.None == 0 ? 0 : -1);
     Static.Assert((int)MandatoryPrefixByte.P66 == 1 ? 0 : -1);
     Static.Assert((int)MandatoryPrefixByte.PF3 == 2 ? 0 : -1);
     Static.Assert((int)MandatoryPrefixByte.PF2 == 3 ? 0 : -1);
     handlers = new OpCodeHandler[4] {
         handler ?? throw new ArgumentNullException(nameof(handler)),
               handler66 ?? throw new ArgumentNullException(nameof(handler66)),
                     handlerF3 ?? throw new ArgumentNullException(nameof(handlerF3)),
                           handlerF2 ?? throw new ArgumentNullException(nameof(handlerF2)),
     };
     Debug.Assert(handler.HasModRM == HasModRM);
     Debug.Assert(handler66.HasModRM == HasModRM);
     Debug.Assert(handlerF3.HasModRM == HasModRM);
     Debug.Assert(handlerF2.HasModRM == HasModRM);
 }
Exemple #10
0
 void Verify_ConditionCode_values_are_in_correct_order()
 {
     Static.Assert((int)ConditionCode.None == 0 ? 0 : -1);
     Static.Assert((int)ConditionCode.o == 1 ? 0 : -1);
     Static.Assert((int)ConditionCode.no == 2 ? 0 : -1);
     Static.Assert((int)ConditionCode.b == 3 ? 0 : -1);
     Static.Assert((int)ConditionCode.ae == 4 ? 0 : -1);
     Static.Assert((int)ConditionCode.e == 5 ? 0 : -1);
     Static.Assert((int)ConditionCode.ne == 6 ? 0 : -1);
     Static.Assert((int)ConditionCode.be == 7 ? 0 : -1);
     Static.Assert((int)ConditionCode.a == 8 ? 0 : -1);
     Static.Assert((int)ConditionCode.s == 9 ? 0 : -1);
     Static.Assert((int)ConditionCode.ns == 10 ? 0 : -1);
     Static.Assert((int)ConditionCode.p == 11 ? 0 : -1);
     Static.Assert((int)ConditionCode.np == 12 ? 0 : -1);
     Static.Assert((int)ConditionCode.l == 13 ? 0 : -1);
     Static.Assert((int)ConditionCode.ge == 14 ? 0 : -1);
     Static.Assert((int)ConditionCode.le == 15 ? 0 : -1);
     Static.Assert((int)ConditionCode.g == 16 ? 0 : -1);
 }
Exemple #11
0
        static Code[] CreateCodeValues()
        {
            var result = new Code[0x100];

            Static.Assert(Code.INVALID == 0 ? 0 : -1);
            // GENERATOR-BEGIN: D3nowCodeValues
            // ⚠️This was generated by GENERATOR!🦹‍♂️
            result[0xBF] = Code.D3NOW_Pavgusb_mm_mmm64;
            result[0xBB] = Code.D3NOW_Pswapd_mm_mmm64;
            result[0xB7] = Code.D3NOW_Pmulhrw_mm_mmm64;
            result[0xB6] = Code.D3NOW_Pfrcpit2_mm_mmm64;
            result[0xB4] = Code.D3NOW_Pfmul_mm_mmm64;
            result[0xB0] = Code.D3NOW_Pfcmpeq_mm_mmm64;
            result[0xAE] = Code.D3NOW_Pfacc_mm_mmm64;
            result[0xAA] = Code.D3NOW_Pfsubr_mm_mmm64;
            result[0xA7] = Code.D3NOW_Pfrsqit1_mm_mmm64;
            result[0xA6] = Code.D3NOW_Pfrcpit1_mm_mmm64;
            result[0xA4] = Code.D3NOW_Pfmax_mm_mmm64;
            result[0xA0] = Code.D3NOW_Pfcmpgt_mm_mmm64;
            result[0x9E] = Code.D3NOW_Pfadd_mm_mmm64;
            result[0x9A] = Code.D3NOW_Pfsub_mm_mmm64;
            result[0x97] = Code.D3NOW_Pfrsqrt_mm_mmm64;
            result[0x96] = Code.D3NOW_Pfrcp_mm_mmm64;
            result[0x94] = Code.D3NOW_Pfmin_mm_mmm64;
            result[0x90] = Code.D3NOW_Pfcmpge_mm_mmm64;
            result[0x8E] = Code.D3NOW_Pfpnacc_mm_mmm64;
            result[0x8A] = Code.D3NOW_Pfnacc_mm_mmm64;
            result[0x87] = Code.D3NOW_Pfrsqrtv_mm_mmm64;
            result[0x86] = Code.D3NOW_Pfrcpv_mm_mmm64;
            result[0x1D] = Code.D3NOW_Pf2id_mm_mmm64;
            result[0x1C] = Code.D3NOW_Pf2iw_mm_mmm64;
            result[0x0D] = Code.D3NOW_Pi2fd_mm_mmm64;
            result[0x0C] = Code.D3NOW_Pi2fw_mm_mmm64;
            // GENERATOR-END: D3nowCodeValues
            return(result);
        }
Exemple #12
0
        static (string hexBytes, Code code, DecoderOptions options, InstructionInfoTestCase testCase) ParseLine(string line, int bitness, Dictionary <string, Register> toRegister)
        {
            Static.Assert(MiscInstrInfoTestConstants.InstrInfoElemsPerLine == 5 ? 0 : -1);
            var elems = line.Split(commaSeparator, MiscInstrInfoTestConstants.InstrInfoElemsPerLine);

            if (elems.Length != MiscInstrInfoTestConstants.InstrInfoElemsPerLine)
            {
                throw new Exception($"Expected {MiscInstrInfoTestConstants.InstrInfoElemsPerLine - 1} commas");
            }

            var testCase = new InstructionInfoTestCase();

            var hexBytes = ToHexBytes(elems[0].Trim());
            var code     = ToEnumConverter.GetCode(elems[1].Trim());

            testCase.Encoding = ToEnumConverter.GetEncodingKind(elems[2].Trim());
            var cpuidFeatureStrings = elems[3].Trim().Split(new[] { ';' });

            var cpuidFeatures = new CpuidFeature[cpuidFeatureStrings.Length];

            testCase.CpuidFeatures = cpuidFeatures;
            for (int i = 0; i < cpuidFeatures.Length; i++)
            {
                cpuidFeatures[i] = ToEnumConverter.GetCpuidFeature(cpuidFeatureStrings[i]);
            }

            var options = DecoderOptions.None;

            foreach (var keyValue in elems[4].Split(spaceSeparator, StringSplitOptions.RemoveEmptyEntries))
            {
                string key, value;
                int    index = keyValue.IndexOf('=');
                if (index >= 0)
                {
                    key   = keyValue.Substring(0, index);
                    value = keyValue.Substring(index + 1);
                }
                else
                {
                    key   = keyValue;
                    value = string.Empty;
                }

                switch (key)
                {
                case InstructionInfoKeys.IsProtectedMode:
                    if (value != string.Empty)
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    testCase.IsProtectedMode = true;
                    break;

                case InstructionInfoKeys.IsPrivileged:
                    if (value != string.Empty)
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    testCase.IsPrivileged = true;
                    break;

                case InstructionInfoKeys.IsSaveRestoreInstruction:
                    if (value != string.Empty)
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    testCase.IsSaveRestoreInstruction = true;
                    break;

                case InstructionInfoKeys.IsStackInstruction:
                    if (!int.TryParse(value, out testCase.StackPointerIncrement))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    testCase.IsStackInstruction = true;
                    break;

                case InstructionInfoKeys.IsSpecial:
                    if (value != string.Empty)
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    testCase.IsSpecial = true;
                    break;

                case InstructionInfoKeys.RflagsRead:
                    if (!ParseRflags(value, ref testCase.RflagsRead))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.RflagsUndefined:
                    if (!ParseRflags(value, ref testCase.RflagsUndefined))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.RflagsWritten:
                    if (!ParseRflags(value, ref testCase.RflagsWritten))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.RflagsCleared:
                    if (!ParseRflags(value, ref testCase.RflagsCleared))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.RflagsSet:
                    if (!ParseRflags(value, ref testCase.RflagsSet))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.FlowControl:
                    if (!ToEnumConverter.TryFlowControl(value, out testCase.FlowControl))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.Op0Access:
                    if (!InstructionInfoDicts.ToAccess.TryGetValue(value, out testCase.Op0Access))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.Op1Access:
                    if (!InstructionInfoDicts.ToAccess.TryGetValue(value, out testCase.Op1Access))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.Op2Access:
                    if (!InstructionInfoDicts.ToAccess.TryGetValue(value, out testCase.Op2Access))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.Op3Access:
                    if (!InstructionInfoDicts.ToAccess.TryGetValue(value, out testCase.Op3Access))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.Op4Access:
                    if (!InstructionInfoDicts.ToAccess.TryGetValue(value, out testCase.Op4Access))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.ReadRegister:
                    if (!AddRegisters(toRegister, value, OpAccess.Read, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.CondReadRegister:
                    if (!AddRegisters(toRegister, value, OpAccess.CondRead, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.WriteRegister:
                    if (!AddRegisters(toRegister, value, OpAccess.Write, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.CondWriteRegister:
                    if (!AddRegisters(toRegister, value, OpAccess.CondWrite, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.ReadWriteRegister:
                    if (!AddRegisters(toRegister, value, OpAccess.ReadWrite, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.ReadCondWriteRegister:
                    if (!AddRegisters(toRegister, value, OpAccess.ReadCondWrite, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.ReadMemory:
                    if (!AddMemory(bitness, toRegister, value, OpAccess.Read, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.CondReadMemory:
                    if (!AddMemory(bitness, toRegister, value, OpAccess.CondRead, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.ReadWriteMemory:
                    if (!AddMemory(bitness, toRegister, value, OpAccess.ReadWrite, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.ReadCondWriteMemory:
                    if (!AddMemory(bitness, toRegister, value, OpAccess.ReadCondWrite, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.WriteMemory:
                    if (!AddMemory(bitness, toRegister, value, OpAccess.Write, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.CondWriteMemory:
                    if (!AddMemory(bitness, toRegister, value, OpAccess.CondWrite, testCase))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                case InstructionInfoKeys.DecoderOptions:
                    if (!TryParseDecoderOptions(value.Split(semicolonSeparator), ref options))
                    {
                        throw new Exception($"Invalid key-value value, '{keyValue}'");
                    }
                    break;

                default:
                    throw new Exception($"Invalid key-value value, '{keyValue}'");
                }
            }

            return(hexBytes, code, options, testCase);
        }
        static OpCodeInfoTestCase ReadTestCase(string line, int lineNo)
        {
            var parts = line.Split(seps);

            if (parts.Length != 8)
            {
                throw new InvalidOperationException($"Invalid number of commas ({parts.Length - 1} commas)");
            }

            var tc = new OpCodeInfoTestCase();

            tc.LineNumber    = lineNo;
            tc.IsInstruction = true;
            tc.GroupIndex    = -1;

            var code = parts[0].Trim();

            if (CodeUtils.IsIgnored(code))
            {
                return(null);
            }
            tc.Code              = ToCode(code);
            tc.Encoding          = ToEncoding(parts[1].Trim());
            tc.MandatoryPrefix   = ToMandatoryPrefix(parts[2].Trim());
            tc.Table             = ToTable(parts[3].Trim());
            tc.OpCode            = ToOpCode(parts[4].Trim(), out tc.OpCodeLength);
            tc.OpCodeString      = parts[5].Trim();
            tc.InstructionString = parts[6].Trim().Replace('|', ',');

            bool gotVectorLength = false;
            bool gotW            = false;

            foreach (var part in parts[7].Split(optsseps))
            {
                var key = part.Trim();
                if (key.Length == 0)
                {
                    continue;
                }
                int index = key.IndexOf('=');
                if (index >= 0)
                {
                    var value = key.Substring(index + 1);
                    key = key.Substring(0, index);
                    switch (key)
                    {
                    case OpCodeInfoKeys.GroupIndex:
                        if (!uint.TryParse(value, out uint groupIndex) || groupIndex > 7)
                        {
                            throw new InvalidOperationException($"Invalid group index: {value}");
                        }
                        tc.GroupIndex = (int)groupIndex;
                        tc.IsGroup    = true;
                        break;

                    case OpCodeInfoKeys.RmGroupIndex:
                        if (!uint.TryParse(value, out uint rmGroupIndex) || rmGroupIndex > 7)
                        {
                            throw new InvalidOperationException($"Invalid group index: {value}");
                        }
                        tc.RmGroupIndex = (int)rmGroupIndex;
                        tc.IsRmGroup    = true;
                        break;

                    case OpCodeInfoKeys.OpCodeOperandKind:
                        var opParts = value.Split(opseps);
                        tc.OpCount = opParts.Length;
                        if (opParts.Length >= 1)
                        {
                            tc.Op0Kind = ToOpCodeOperandKind(opParts[0]);
                        }
                        if (opParts.Length >= 2)
                        {
                            tc.Op1Kind = ToOpCodeOperandKind(opParts[1]);
                        }
                        if (opParts.Length >= 3)
                        {
                            tc.Op2Kind = ToOpCodeOperandKind(opParts[2]);
                        }
                        if (opParts.Length >= 4)
                        {
                            tc.Op3Kind = ToOpCodeOperandKind(opParts[3]);
                        }
                        if (opParts.Length >= 5)
                        {
                            tc.Op4Kind = ToOpCodeOperandKind(opParts[4]);
                        }
                        Static.Assert(IcedConstants.MaxOpCount == 5 ? 0 : -1);
                        if (opParts.Length >= 6)
                        {
                            throw new InvalidOperationException($"Invalid number of operands: '{value}'");
                        }
                        break;

                    case OpCodeInfoKeys.TupleType:
                        tc.TupleType = ToTupleType(value.Trim());
                        break;

                    case OpCodeInfoKeys.DecoderOption:
                        tc.DecoderOption = ToDecoderOptions(value.Trim());
                        break;

                    default:
                        throw new InvalidOperationException($"Invalid key: '{key}'");
                    }
                }
                else
                {
                    switch (key)
                    {
                    case OpCodeInfoFlags.NoInstruction:
                        tc.IsInstruction = false;
                        break;

                    case OpCodeInfoFlags.Bit16:
                        tc.Mode16 = true;
                        break;

                    case OpCodeInfoFlags.Bit32:
                        tc.Mode32 = true;
                        break;

                    case OpCodeInfoFlags.Bit64:
                        tc.Mode64 = true;
                        break;

                    case OpCodeInfoFlags.Fwait:
                        tc.Fwait = true;
                        break;

                    case OpCodeInfoFlags.OperandSize16:
                        tc.OperandSize = 16;
                        break;

                    case OpCodeInfoFlags.OperandSize32:
                        tc.OperandSize = 32;
                        break;

                    case OpCodeInfoFlags.OperandSize64:
                        tc.OperandSize = 64;
                        break;

                    case OpCodeInfoFlags.AddressSize16:
                        tc.AddressSize = 16;
                        break;

                    case OpCodeInfoFlags.AddressSize32:
                        tc.AddressSize = 32;
                        break;

                    case OpCodeInfoFlags.AddressSize64:
                        tc.AddressSize = 64;
                        break;

                    case OpCodeInfoFlags.LIG:
                        tc.IsLIG        = true;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L0:
                        tc.L            = 0;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L1:
                        tc.L            = 1;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L128:
                        tc.L            = 0;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L256:
                        tc.L            = 1;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L512:
                        tc.L            = 2;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.WIG:
                        tc.IsWIG = true;
                        gotW     = true;
                        break;

                    case OpCodeInfoFlags.WIG32:
                        tc.W       = 0;
                        tc.IsWIG32 = true;
                        gotW       = true;
                        break;

                    case OpCodeInfoFlags.W0:
                        tc.W = 0;
                        gotW = true;
                        break;

                    case OpCodeInfoFlags.W1:
                        tc.W = 1;
                        gotW = true;
                        break;

                    case OpCodeInfoFlags.Broadcast:
                        tc.CanBroadcast = true;
                        break;

                    case OpCodeInfoFlags.RoundingControl:
                        tc.CanUseRoundingControl = true;
                        break;

                    case OpCodeInfoFlags.SuppressAllExceptions:
                        tc.CanSuppressAllExceptions = true;
                        break;

                    case OpCodeInfoFlags.OpMaskRegister:
                        tc.CanUseOpMaskRegister = true;
                        break;

                    case OpCodeInfoFlags.RequireOpMaskRegister:
                        tc.CanUseOpMaskRegister  = true;
                        tc.RequireOpMaskRegister = true;
                        break;

                    case OpCodeInfoFlags.ZeroingMasking:
                        tc.CanUseZeroingMasking = true;
                        break;

                    case OpCodeInfoFlags.Lock:
                        tc.CanUseLockPrefix = true;
                        break;

                    case OpCodeInfoFlags.Xacquire:
                        tc.CanUseXacquirePrefix = true;
                        break;

                    case OpCodeInfoFlags.Xrelease:
                        tc.CanUseXreleasePrefix = true;
                        break;

                    case OpCodeInfoFlags.Rep:
                    case OpCodeInfoFlags.Repe:
                        tc.CanUseRepPrefix = true;
                        break;

                    case OpCodeInfoFlags.Repne:
                        tc.CanUseRepnePrefix = true;
                        break;

                    case OpCodeInfoFlags.Bnd:
                        tc.CanUseBndPrefix = true;
                        break;

                    case OpCodeInfoFlags.HintTaken:
                        tc.CanUseHintTakenPrefix = true;
                        break;

                    case OpCodeInfoFlags.Notrack:
                        tc.CanUseNotrackPrefix = true;
                        break;

                    case OpCodeInfoFlags.IgnoresRoundingControl:
                        tc.IgnoresRoundingControl = true;
                        break;

                    case OpCodeInfoFlags.AmdLockRegBit:
                        tc.AmdLockRegBit = true;
                        break;

                    case OpCodeInfoFlags.DefaultOpSize64:
                        tc.DefaultOpSize64 = true;
                        break;

                    case OpCodeInfoFlags.ForceOpSize64:
                        tc.ForceOpSize64 = true;
                        break;

                    case OpCodeInfoFlags.IntelForceOpSize64:
                        tc.IntelForceOpSize64 = true;
                        break;

                    case OpCodeInfoFlags.Cpl0:
                        tc.Cpl0 = true;
                        break;

                    case OpCodeInfoFlags.Cpl1:
                        tc.Cpl1 = true;
                        break;

                    case OpCodeInfoFlags.Cpl2:
                        tc.Cpl2 = true;
                        break;

                    case OpCodeInfoFlags.Cpl3:
                        tc.Cpl3 = true;
                        break;

                    case OpCodeInfoFlags.InputOutput:
                        tc.IsInputOutput = true;
                        break;

                    case OpCodeInfoFlags.Nop:
                        tc.IsNop = true;
                        break;

                    case OpCodeInfoFlags.ReservedNop:
                        tc.IsReservedNop = true;
                        break;

                    case OpCodeInfoFlags.SerializingIntel:
                        tc.IsSerializingIntel = true;
                        break;

                    case OpCodeInfoFlags.SerializingAmd:
                        tc.IsSerializingAmd = true;
                        break;

                    case OpCodeInfoFlags.MayRequireCpl0:
                        tc.MayRequireCpl0 = true;
                        break;

                    case OpCodeInfoFlags.CetTracked:
                        tc.IsCetTracked = true;
                        break;

                    case OpCodeInfoFlags.NonTemporal:
                        tc.IsNonTemporal = true;
                        break;

                    case OpCodeInfoFlags.FpuNoWait:
                        tc.IsFpuNoWait = true;
                        break;

                    case OpCodeInfoFlags.IgnoresModBits:
                        tc.IgnoresModBits = true;
                        break;

                    case OpCodeInfoFlags.No66:
                        tc.No66 = true;
                        break;

                    case OpCodeInfoFlags.NFx:
                        tc.NFx = true;
                        break;

                    case OpCodeInfoFlags.RequiresUniqueRegNums:
                        tc.RequiresUniqueRegNums = true;
                        break;

                    case OpCodeInfoFlags.Privileged:
                        tc.IsPrivileged = true;
                        break;

                    case OpCodeInfoFlags.SaveRestore:
                        tc.IsSaveRestore = true;
                        break;

                    case OpCodeInfoFlags.StackInstruction:
                        tc.IsStackInstruction = true;
                        break;

                    case OpCodeInfoFlags.IgnoresSegment:
                        tc.IgnoresSegment = true;
                        break;

                    case OpCodeInfoFlags.OpMaskReadWrite:
                        tc.IsOpMaskReadWrite = true;
                        break;

                    case OpCodeInfoFlags.RealMode:
                        tc.RealMode = true;
                        break;

                    case OpCodeInfoFlags.ProtectedMode:
                        tc.ProtectedMode = true;
                        break;

                    case OpCodeInfoFlags.Virtual8086Mode:
                        tc.Virtual8086Mode = true;
                        break;

                    case OpCodeInfoFlags.CompatibilityMode:
                        tc.CompatibilityMode = true;
                        break;

                    case OpCodeInfoFlags.LongMode:
                        tc.LongMode = true;
                        break;

                    case OpCodeInfoFlags.UseOutsideSmm:
                        tc.UseOutsideSmm = true;
                        break;

                    case OpCodeInfoFlags.UseInSmm:
                        tc.UseInSmm = true;
                        break;

                    case OpCodeInfoFlags.UseOutsideEnclaveSgx:
                        tc.UseOutsideEnclaveSgx = true;
                        break;

                    case OpCodeInfoFlags.UseInEnclaveSgx1:
                        tc.UseInEnclaveSgx1 = true;
                        break;

                    case OpCodeInfoFlags.UseInEnclaveSgx2:
                        tc.UseInEnclaveSgx2 = true;
                        break;

                    case OpCodeInfoFlags.UseOutsideVmxOp:
                        tc.UseOutsideVmxOp = true;
                        break;

                    case OpCodeInfoFlags.UseInVmxRootOp:
                        tc.UseInVmxRootOp = true;
                        break;

                    case OpCodeInfoFlags.UseInVmxNonRootOp:
                        tc.UseInVmxNonRootOp = true;
                        break;

                    case OpCodeInfoFlags.UseOutsideSeam:
                        tc.UseOutsideSeam = true;
                        break;

                    case OpCodeInfoFlags.UseInSeam:
                        tc.UseInSeam = true;
                        break;

                    case OpCodeInfoFlags.TdxNonRootGenUd:
                        tc.TdxNonRootGenUd = true;
                        break;

                    case OpCodeInfoFlags.TdxNonRootGenVe:
                        tc.TdxNonRootGenVe = true;
                        break;

                    case OpCodeInfoFlags.TdxNonRootMayGenEx:
                        tc.TdxNonRootMayGenEx = true;
                        break;

                    case OpCodeInfoFlags.IntelVmExit:
                        tc.IntelVmExit = true;
                        break;

                    case OpCodeInfoFlags.IntelMayVmExit:
                        tc.IntelMayVmExit = true;
                        break;

                    case OpCodeInfoFlags.IntelSmmVmExit:
                        tc.IntelSmmVmExit = true;
                        break;

                    case OpCodeInfoFlags.AmdVmExit:
                        tc.AmdVmExit = true;
                        break;

                    case OpCodeInfoFlags.AmdMayVmExit:
                        tc.AmdMayVmExit = true;
                        break;

                    case OpCodeInfoFlags.TsxAbort:
                        tc.TsxAbort = true;
                        break;

                    case OpCodeInfoFlags.TsxImplAbort:
                        tc.TsxImplAbort = true;
                        break;

                    case OpCodeInfoFlags.TsxMayAbort:
                        tc.TsxMayAbort = true;
                        break;

                    case OpCodeInfoFlags.IntelDecoder16:
                        tc.IntelDecoder16 = true;
                        break;

                    case OpCodeInfoFlags.IntelDecoder32:
                        tc.IntelDecoder32 = true;
                        break;

                    case OpCodeInfoFlags.IntelDecoder64:
                        tc.IntelDecoder64 = true;
                        break;

                    case OpCodeInfoFlags.AmdDecoder16:
                        tc.AmdDecoder16 = true;
                        break;

                    case OpCodeInfoFlags.AmdDecoder32:
                        tc.AmdDecoder32 = true;
                        break;

                    case OpCodeInfoFlags.AmdDecoder64:
                        tc.AmdDecoder64 = true;
                        break;

                    default:
                        throw new InvalidOperationException($"Invalid key: '{key}'");
                    }
                }
            }
            switch (tc.Encoding)
            {
            case EncodingKind.Legacy:
            case EncodingKind.D3NOW:
                break;

            case EncodingKind.VEX:
            case EncodingKind.EVEX:
            case EncodingKind.XOP:
                if (!gotVectorLength)
                {
                    throw new InvalidOperationException("Missing vector length: L0/L1/L128/L256/L512/LIG");
                }
                if (!gotW)
                {
                    throw new InvalidOperationException("Missing W bit: W0/W1/WIG/WIG32");
                }
                break;

            default:
                throw new InvalidOperationException();
            }

            return(tc);
        }
Exemple #14
0
        protected void TestInstructionInfo(int bitness, string hexBytes, Code code, DecoderOptions options, int lineNo, InstructionInfoTestCase testCase)
        {
            var         codeBytes = HexUtils.ToByteArray(hexBytes);
            Instruction instruction;

            if (testCase.IsSpecial)
            {
                if (bitness == 16 && code == Code.Popw_CS && hexBytes == "0F")
                {
                    instruction             = default;
                    instruction.Code        = Code.Popw_CS;
                    instruction.Op0Kind     = OpKind.Register;
                    instruction.Op0Register = Register.CS;
                    instruction.CodeSize    = CodeSize.Code16;
                    instruction.Length      = 1;
                }
                else if (code <= Code.DeclareQword)
                {
                    instruction                  = default;
                    instruction.Code             = code;
                    instruction.DeclareDataCount = 1;
                    Assert.Equal(64, bitness);
                    instruction.CodeSize = CodeSize.Code64;
                    switch (code)
                    {
                    case Code.DeclareByte:
                        Assert.Equal("66", hexBytes);
                        instruction.SetDeclareByteValue(0, 0x66);
                        break;

                    case Code.DeclareWord:
                        Assert.Equal("6644", hexBytes);
                        instruction.SetDeclareWordValue(0, 0x4466);
                        break;

                    case Code.DeclareDword:
                        Assert.Equal("664422EE", hexBytes);
                        instruction.SetDeclareDwordValue(0, 0xEE224466);
                        break;

                    case Code.DeclareQword:
                        Assert.Equal("664422EE12345678", hexBytes);
                        instruction.SetDeclareQwordValue(0, 0x78563412EE224466);
                        break;

                    default: throw new InvalidOperationException();
                    }
                }
                else
                {
                    var decoder = CreateDecoder(bitness, codeBytes, options);
                    instruction = decoder.Decode();
                    if (codeBytes.Length > 1 && codeBytes[0] == 0x9B && instruction.Length == 1)
                    {
                        instruction      = decoder.Decode();
                        instruction.Code = instruction.Code switch {
                            Code.Fnstenv_m14byte => Code.Fstenv_m14byte,
                            Code.Fnstenv_m28byte => Code.Fstenv_m28byte,
                            Code.Fnstcw_m2byte => Code.Fstcw_m2byte,
                            Code.Fneni => Code.Feni,
                            Code.Fndisi => Code.Fdisi,
                            Code.Fnclex => Code.Fclex,
                            Code.Fninit => Code.Finit,
                            Code.Fnsetpm => Code.Fsetpm,
                            Code.Fnsave_m94byte => Code.Fsave_m94byte,
                            Code.Fnsave_m108byte => Code.Fsave_m108byte,
                            Code.Fnstsw_m2byte => Code.Fstsw_m2byte,
                            Code.Fnstsw_AX => Code.Fstsw_AX,
                            Code.Fnstdw_AX => Code.Fstdw_AX,
                            Code.Fnstsg_AX => Code.Fstsg_AX,
                            _ => throw new InvalidOperationException(),
                        };
                    }
                    else
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
            else
            {
                var decoder = CreateDecoder(bitness, codeBytes, options);
                instruction = decoder.Decode();
            }
            Assert.Equal(code, instruction.Code);

            Assert.Equal(testCase.StackPointerIncrement, instruction.StackPointerIncrement);

            var info = new InstructionInfoFactory().GetInfo(instruction);

            Assert.Equal(testCase.Encoding, info.Encoding);
            Assert.Equal(testCase.CpuidFeatures, info.CpuidFeatures);
            Assert.Equal(testCase.RflagsRead, info.RflagsRead);
            Assert.Equal(testCase.RflagsUndefined, info.RflagsUndefined);
            Assert.Equal(testCase.RflagsWritten, info.RflagsWritten);
            Assert.Equal(testCase.RflagsCleared, info.RflagsCleared);
            Assert.Equal(testCase.RflagsSet, info.RflagsSet);
            Assert.Equal(testCase.IsPrivileged, info.IsPrivileged);
            Assert.Equal(testCase.IsStackInstruction, info.IsStackInstruction);
            Assert.Equal(testCase.IsSaveRestoreInstruction, info.IsSaveRestoreInstruction);
            Assert.Equal(testCase.FlowControl, info.FlowControl);
            Assert.Equal(testCase.Op0Access, info.Op0Access);
            Assert.Equal(testCase.Op1Access, info.Op1Access);
            Assert.Equal(testCase.Op2Access, info.Op2Access);
            Assert.Equal(testCase.Op3Access, info.Op3Access);
            Assert.Equal(testCase.Op4Access, info.Op4Access);
            Assert.Equal(
                new HashSet <UsedMemory>(testCase.UsedMemory, UsedMemoryEqualityComparer.Instance),
                new HashSet <UsedMemory>(info.GetUsedMemory(), UsedMemoryEqualityComparer.Instance));
            Assert.Equal(
                new HashSet <UsedRegister>(GetUsedRegisters(testCase.UsedRegisters), UsedRegisterEqualityComparer.Instance),
                new HashSet <UsedRegister>(GetUsedRegisters(info.GetUsedRegisters()), UsedRegisterEqualityComparer.Instance));

            Static.Assert(IcedConstants.MaxOpCount == 5 ? 0 : -1);
            Debug.Assert(instruction.OpCount <= IcedConstants.MaxOpCount);
            for (int i = 0; i < instruction.OpCount; i++)
            {
                switch (i)
                {
                case 0:
                    Assert.Equal(testCase.Op0Access, info.GetOpAccess(i));
                    break;

                case 1:
                    Assert.Equal(testCase.Op1Access, info.GetOpAccess(i));
                    break;

                case 2:
                    Assert.Equal(testCase.Op2Access, info.GetOpAccess(i));
                    break;

                case 3:
                    Assert.Equal(testCase.Op3Access, info.GetOpAccess(i));
                    break;

                case 4:
                    Assert.Equal(testCase.Op4Access, info.GetOpAccess(i));
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }
            for (int i = instruction.OpCount; i < IcedConstants.MaxOpCount; i++)
            {
                Assert.Equal(OpAccess.None, info.GetOpAccess(i));
            }

            Assert.Equal(RflagsBits.None, info.RflagsWritten & (info.RflagsCleared | info.RflagsSet | info.RflagsUndefined));
            Assert.Equal(RflagsBits.None, info.RflagsCleared & (info.RflagsWritten | info.RflagsSet | info.RflagsUndefined));
            Assert.Equal(RflagsBits.None, info.RflagsSet & (info.RflagsWritten | info.RflagsCleared | info.RflagsUndefined));
            Assert.Equal(RflagsBits.None, info.RflagsUndefined & (info.RflagsWritten | info.RflagsCleared | info.RflagsSet));
            Assert.Equal(info.RflagsWritten | info.RflagsCleared | info.RflagsSet | info.RflagsUndefined, info.RflagsModified);

            var info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.None);

            CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: true);
            info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoMemoryUsage);
            CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: false);
            info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoRegisterUsage);
            CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: true);
            info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoRegisterUsage | InstructionInfoOptions.NoMemoryUsage);
            CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: false);

            Assert.Equal(info.Encoding, instruction.Code.Encoding());
#if ENCODER && OPCODE_INFO
            Assert.Equal(code.ToOpCode().Encoding, instruction.Code.Encoding());
#endif
            Assert.Equal(info.CpuidFeatures, instruction.Code.CpuidFeatures());
            Assert.Equal(info.FlowControl, instruction.Code.FlowControl());
            Assert.Equal(info.IsPrivileged, instruction.Code.IsPrivileged());
            Assert.Equal(info.IsStackInstruction, instruction.Code.IsStackInstruction());
            Assert.Equal(info.IsSaveRestoreInstruction, instruction.Code.IsSaveRestoreInstruction());

            Assert.Equal(info.Encoding, instruction.Encoding);
            Assert.Equal(info.CpuidFeatures, instruction.CpuidFeatures);
            Assert.Equal(info.FlowControl, instruction.FlowControl);
            Assert.Equal(info.IsPrivileged, instruction.IsPrivileged);
            Assert.Equal(info.IsStackInstruction, instruction.IsStackInstruction);
            Assert.Equal(info.IsSaveRestoreInstruction, instruction.IsSaveRestoreInstruction);
            Assert.Equal(info.RflagsRead, instruction.RflagsRead);
            Assert.Equal(info.RflagsWritten, instruction.RflagsWritten);
            Assert.Equal(info.RflagsCleared, instruction.RflagsCleared);
            Assert.Equal(info.RflagsSet, instruction.RflagsSet);
            Assert.Equal(info.RflagsUndefined, instruction.RflagsUndefined);
            Assert.Equal(info.RflagsModified, instruction.RflagsModified);
        }
Exemple #15
0
        public override void Decode(Decoder decoder, ref Instruction instruction)
        {
            Debug.Assert(decoder.state.Encoding == EncodingKind.MVEX);
            instruction.InternalSetCodeNoCheck(code);

            Static.Assert(OpKind.Register == 0 ? 0 : -1);
            //instruction.Op0Kind = OpKind.Register;
            instruction.Op0Register = (int)decoder.state.reg + Register.K0;
            Static.Assert(OpKind.Register == 0 ? 0 : -1);
            //instruction.Op1Kind = OpKind.Register;
            instruction.Op1Register = (int)decoder.state.vvvv + Register.ZMM0;
            var mvex = new MvexInfo(code);
            var sss  = decoder.state.Sss;

            if (decoder.state.mod == 3)
            {
                Static.Assert(OpKind.Register == 0 ? 0 : -1);
                //instruction.Op2Kind = OpKind.Register;
                instruction.Op2Register = (int)(decoder.state.rm + decoder.state.extraBaseRegisterBaseEVEX) + Register.ZMM0;
                if ((decoder.state.zs.flags & StateFlags.MvexEH) != 0)
                {
                    if (mvex.CanUseSuppressAllExceptions)
                    {
                        if ((sss & 4) != 0)
                        {
                            instruction.InternalSetSuppressAllExceptions();
                        }
                        if (mvex.CanUseRoundingControl)
                        {
                            Static.Assert((int)RoundingControl.None == 0 ? 0 : -1);
                            Static.Assert((int)RoundingControl.RoundToNearest == 1 ? 0 : -1);
                            Static.Assert((int)RoundingControl.RoundDown == 2 ? 0 : -1);
                            Static.Assert((int)RoundingControl.RoundUp == 3 ? 0 : -1);
                            Static.Assert((int)RoundingControl.RoundTowardZero == 4 ? 0 : -1);
                            instruction.InternalRoundingControl = ((uint)sss & 3) + (uint)RoundingControl.RoundToNearest;
                        }
                    }
                    else if (mvex.NoSaeRc && ((uint)sss & decoder.invalidCheckMask) != 0)
                    {
                        decoder.SetInvalidInstruction();
                    }
                }
                else
                {
                    if ((mvex.InvalidSwizzleFns & (1U << sss) & decoder.invalidCheckMask) != 0)
                    {
                        decoder.SetInvalidInstruction();
                    }
                    Debug.Assert((uint)sss <= 7);
                    instruction.InternalSetMvexRegMemConv(MvexRegMemConv.RegSwizzleNone + sss);
                }
            }
            else
            {
                instruction.Op2Kind = OpKind.Memory;
                if ((decoder.state.zs.flags & StateFlags.MvexEH) != 0)
                {
                    instruction.InternalSetIsMvexEvictionHint();
                }
                if ((mvex.InvalidConvFns & (1U << sss) & decoder.invalidCheckMask) != 0)
                {
                    decoder.SetInvalidInstruction();
                }
                instruction.InternalSetMvexRegMemConv(MvexRegMemConv.MemConvNone + sss);
                decoder.ReadOpMem(ref instruction, mvex.GetTupleType(sss));
            }
            if (((decoder.state.zs.extraRegisterBase | decoder.state.extraRegisterBaseEVEX) & decoder.invalidCheckMask) != 0)
            {
                decoder.SetInvalidInstruction();
            }
            instruction.Op3Kind    = OpKind.Immediate8;
            instruction.Immediate8 = (byte)decoder.ReadByte();
        }
        static OpCodeInfoTestCase ReadTestCase(string line, int lineNo)
        {
            var parts = line.Split(seps);

            if (parts.Length != 8)
            {
                throw new InvalidOperationException($"Invalid number of commas ({parts.Length - 1} commas)");
            }

            var tc = new OpCodeInfoTestCase();

            tc.LineNumber    = lineNo;
            tc.IsInstruction = true;
            tc.GroupIndex    = -1;

            tc.Code              = ToCode(parts[0].Trim());
            tc.Encoding          = ToEncoding(parts[1].Trim());
            tc.MandatoryPrefix   = ToMandatoryPrefix(parts[2].Trim());
            tc.Table             = ToTable(parts[3].Trim());
            tc.OpCode            = ToOpCode(parts[4].Trim());
            tc.OpCodeString      = parts[5].Trim();
            tc.InstructionString = parts[6].Trim().Replace('|', ',');

            bool gotVectorLength = false;
            bool gotW            = false;

            foreach (var part in parts[7].Split(optsseps))
            {
                var key = part.Trim();
                if (key.Length == 0)
                {
                    continue;
                }
                int index = key.IndexOf('=');
                if (index >= 0)
                {
                    var value = key.Substring(index + 1);
                    key = key.Substring(0, index);
                    switch (key)
                    {
                    case OpCodeInfoKeys.GroupIndex:
                        if (!uint.TryParse(value, out uint groupIndex) || groupIndex > 7)
                        {
                            throw new InvalidOperationException($"Invalid group index: {value}");
                        }
                        tc.GroupIndex = (int)groupIndex;
                        tc.IsGroup    = true;
                        break;

                    case OpCodeInfoKeys.OpCodeOperandKind:
                        var opParts = value.Split(opseps);
                        tc.OpCount = opParts.Length;
                        if (opParts.Length >= 1)
                        {
                            tc.Op0Kind = ToOpCodeOperandKind(opParts[0]);
                        }
                        if (opParts.Length >= 2)
                        {
                            tc.Op1Kind = ToOpCodeOperandKind(opParts[1]);
                        }
                        if (opParts.Length >= 3)
                        {
                            tc.Op2Kind = ToOpCodeOperandKind(opParts[2]);
                        }
                        if (opParts.Length >= 4)
                        {
                            tc.Op3Kind = ToOpCodeOperandKind(opParts[3]);
                        }
                        if (opParts.Length >= 5)
                        {
                            tc.Op4Kind = ToOpCodeOperandKind(opParts[4]);
                        }
                        Static.Assert(IcedConstants.MaxOpCount == 5 ? 0 : -1);
                        if (opParts.Length >= 6)
                        {
                            throw new InvalidOperationException($"Invalid number of operands: '{value}'");
                        }
                        break;

                    case OpCodeInfoKeys.TupleType:
                        tc.TupleType = ToTupleType(value.Trim());
                        break;

                    default:
                        throw new InvalidOperationException($"Invalid key: '{key}'");
                    }
                }
                else
                {
                    switch (key)
                    {
                    case OpCodeInfoFlags.NotInstruction:
                        tc.IsInstruction = false;
                        break;

                    case OpCodeInfoFlags.Bit16:
                        tc.Mode16 = true;
                        break;

                    case OpCodeInfoFlags.Bit32:
                        tc.Mode32 = true;
                        break;

                    case OpCodeInfoFlags.Bit64:
                        tc.Mode64 = true;
                        break;

                    case OpCodeInfoFlags.Fwait:
                        tc.Fwait = true;
                        break;

                    case OpCodeInfoFlags.OperandSize16:
                        tc.OperandSize = 16;
                        break;

                    case OpCodeInfoFlags.OperandSize32:
                        tc.OperandSize = 32;
                        break;

                    case OpCodeInfoFlags.OperandSize64:
                        tc.OperandSize = 64;
                        break;

                    case OpCodeInfoFlags.AddressSize16:
                        tc.AddressSize = 16;
                        break;

                    case OpCodeInfoFlags.AddressSize32:
                        tc.AddressSize = 32;
                        break;

                    case OpCodeInfoFlags.AddressSize64:
                        tc.AddressSize = 64;
                        break;

                    case OpCodeInfoFlags.LIG:
                        tc.IsLIG        = true;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L0:
                        tc.L            = 0;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L1:
                        tc.L            = 1;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L128:
                        tc.L            = 0;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L256:
                        tc.L            = 1;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.L512:
                        tc.L            = 2;
                        gotVectorLength = true;
                        break;

                    case OpCodeInfoFlags.WIG:
                        tc.IsWIG = true;
                        gotW     = true;
                        break;

                    case OpCodeInfoFlags.WIG32:
                        tc.W       = 0;
                        tc.IsWIG32 = true;
                        gotW       = true;
                        break;

                    case OpCodeInfoFlags.W0:
                        tc.W = 0;
                        gotW = true;
                        break;

                    case OpCodeInfoFlags.W1:
                        tc.W = 1;
                        gotW = true;
                        break;

                    case OpCodeInfoFlags.Broadcast:
                        tc.CanBroadcast = true;
                        break;

                    case OpCodeInfoFlags.RoundingControl:
                        tc.CanUseRoundingControl = true;
                        break;

                    case OpCodeInfoFlags.SuppressAllExceptions:
                        tc.CanSuppressAllExceptions = true;
                        break;

                    case OpCodeInfoFlags.OpMaskRegister:
                        tc.CanUseOpMaskRegister = true;
                        break;

                    case OpCodeInfoFlags.RequireNonZeroOpMaskRegister:
                        tc.CanUseOpMaskRegister         = true;
                        tc.RequireNonZeroOpMaskRegister = true;
                        break;

                    case OpCodeInfoFlags.ZeroingMasking:
                        tc.CanUseZeroingMasking = true;
                        break;

                    case OpCodeInfoFlags.LockPrefix:
                        tc.CanUseLockPrefix = true;
                        break;

                    case OpCodeInfoFlags.XacquirePrefix:
                        tc.CanUseXacquirePrefix = true;
                        break;

                    case OpCodeInfoFlags.XreleasePrefix:
                        tc.CanUseXreleasePrefix = true;
                        break;

                    case OpCodeInfoFlags.RepPrefix:
                    case OpCodeInfoFlags.RepePrefix:
                        tc.CanUseRepPrefix = true;
                        break;

                    case OpCodeInfoFlags.RepnePrefix:
                        tc.CanUseRepnePrefix = true;
                        break;

                    case OpCodeInfoFlags.BndPrefix:
                        tc.CanUseBndPrefix = true;
                        break;

                    case OpCodeInfoFlags.HintTakenPrefix:
                        tc.CanUseHintTakenPrefix = true;
                        break;

                    case OpCodeInfoFlags.NotrackPrefix:
                        tc.CanUseNotrackPrefix = true;
                        break;

                    default:
                        throw new InvalidOperationException($"Invalid key: '{key}'");
                    }
                }
            }
            switch (tc.Encoding)
            {
            case EncodingKind.Legacy:
            case EncodingKind.D3NOW:
                break;

            case EncodingKind.VEX:
            case EncodingKind.EVEX:
            case EncodingKind.XOP:
                if (!gotVectorLength)
                {
                    throw new InvalidOperationException("Missing vector length: L0/L1/L128/L256/L512/LIG");
                }
                if (!gotW)
                {
                    throw new InvalidOperationException("Missing W bit: W0/W1/WIG/WIG32");
                }
                break;

            default:
                throw new InvalidOperationException();
            }

            return(tc);
        }
Exemple #17
0
#pragma warning disable xUnit1026 // Theory methods should use all of their parameters
        void Test_all_OpCodeInfos(int lineNo, Code code, string opCodeString, string instructionString, OpCodeInfoTestCase tc)
        {
#pragma warning restore xUnit1026 // Theory methods should use all of their parameters
            var info = tc.Code.ToOpCode();
            Assert.Equal(tc.Code, info.Code);
#pragma warning disable xUnit2006 // Do not use invalid string equality check
            // Show the full string without ellipses by using Equal<string>() instead of Equal()
            Assert.Equal <string>(tc.OpCodeString, info.ToOpCodeString());
            Assert.Equal <string>(tc.InstructionString, info.ToInstructionString());
#pragma warning restore xUnit2006 // Do not use invalid string equality check
            Assert.True((object)info.ToInstructionString() == info.ToString());
            Assert.Equal(tc.Mnemonic, info.Mnemonic);
            Assert.Equal(tc.Encoding, info.Encoding);
            Assert.Equal(tc.IsInstruction, info.IsInstruction);
            Assert.Equal(tc.Mode16, info.Mode16);
            Assert.Equal(tc.Mode16, info.IsAvailableInMode(16));
            Assert.Equal(tc.Mode32, info.Mode32);
            Assert.Equal(tc.Mode32, info.IsAvailableInMode(32));
            Assert.Equal(tc.Mode64, info.Mode64);
            Assert.Equal(tc.Mode64, info.IsAvailableInMode(64));
            Assert.Equal(tc.Fwait, info.Fwait);
            Assert.Equal(tc.OperandSize, info.OperandSize);
            Assert.Equal(tc.AddressSize, info.AddressSize);
            Assert.Equal(tc.L, info.L);
            Assert.Equal(tc.W, info.W);
            Assert.Equal(tc.IsLIG, info.IsLIG);
            Assert.Equal(tc.IsWIG, info.IsWIG);
            Assert.Equal(tc.IsWIG32, info.IsWIG32);
            Assert.Equal(tc.TupleType, info.TupleType);
            Assert.Equal(tc.MemorySize, info.MemorySize);
            Assert.Equal(tc.BroadcastMemorySize, info.BroadcastMemorySize);
            Assert.Equal(tc.DecoderOption, info.DecoderOption);
            Assert.Equal(tc.CanBroadcast, info.CanBroadcast);
            Assert.Equal(tc.CanUseRoundingControl, info.CanUseRoundingControl);
            Assert.Equal(tc.CanSuppressAllExceptions, info.CanSuppressAllExceptions);
            Assert.Equal(tc.CanUseOpMaskRegister, info.CanUseOpMaskRegister);
            Assert.Equal(tc.RequireOpMaskRegister, info.RequireOpMaskRegister);
            if (tc.RequireOpMaskRegister)
            {
                Assert.True(info.CanUseOpMaskRegister);
                Assert.False(info.CanUseZeroingMasking);
            }
            Assert.Equal(tc.CanUseZeroingMasking, info.CanUseZeroingMasking);
            Assert.Equal(tc.CanUseLockPrefix, info.CanUseLockPrefix);
            Assert.Equal(tc.CanUseXacquirePrefix, info.CanUseXacquirePrefix);
            Assert.Equal(tc.CanUseXreleasePrefix, info.CanUseXreleasePrefix);
            Assert.Equal(tc.CanUseRepPrefix, info.CanUseRepPrefix);
            Assert.Equal(tc.CanUseRepnePrefix, info.CanUseRepnePrefix);
            Assert.Equal(tc.CanUseBndPrefix, info.CanUseBndPrefix);
            Assert.Equal(tc.CanUseHintTakenPrefix, info.CanUseHintTakenPrefix);
            Assert.Equal(tc.CanUseNotrackPrefix, info.CanUseNotrackPrefix);
            Assert.Equal(tc.IgnoresRoundingControl, info.IgnoresRoundingControl);
            Assert.Equal(tc.AmdLockRegBit, info.AmdLockRegBit);
            Assert.Equal(tc.DefaultOpSize64, info.DefaultOpSize64);
            Assert.Equal(tc.ForceOpSize64, info.ForceOpSize64);
            Assert.Equal(tc.IntelForceOpSize64, info.IntelForceOpSize64);
            Assert.Equal(tc.Cpl0 && !tc.Cpl1 && !tc.Cpl2 && !tc.Cpl3, info.MustBeCpl0);
            Assert.Equal(tc.Cpl0, info.Cpl0);
            Assert.Equal(tc.Cpl1, info.Cpl1);
            Assert.Equal(tc.Cpl2, info.Cpl2);
            Assert.Equal(tc.Cpl3, info.Cpl3);
            Assert.Equal(tc.IsInputOutput, info.IsInputOutput);
            Assert.Equal(tc.IsNop, info.IsNop);
            Assert.Equal(tc.IsReservedNop, info.IsReservedNop);
            Assert.Equal(tc.IsSerializingIntel, info.IsSerializingIntel);
            Assert.Equal(tc.IsSerializingAmd, info.IsSerializingAmd);
            Assert.Equal(tc.MayRequireCpl0, info.MayRequireCpl0);
            Assert.Equal(tc.IsCetTracked, info.IsCetTracked);
            Assert.Equal(tc.IsNonTemporal, info.IsNonTemporal);
            Assert.Equal(tc.IsFpuNoWait, info.IsFpuNoWait);
            Assert.Equal(tc.IgnoresModBits, info.IgnoresModBits);
            Assert.Equal(tc.No66, info.No66);
            Assert.Equal(tc.NFx, info.NFx);
            Assert.Equal(tc.RequiresUniqueRegNums, info.RequiresUniqueRegNums);
            Assert.Equal(tc.RequiresUniqueDestRegNum, info.RequiresUniqueDestRegNum);
            Assert.Equal(tc.IsPrivileged, info.IsPrivileged);
            Assert.Equal(tc.IsSaveRestore, info.IsSaveRestore);
            Assert.Equal(tc.IsStackInstruction, info.IsStackInstruction);
            Assert.Equal(tc.IgnoresSegment, info.IgnoresSegment);
            Assert.Equal(tc.IsOpMaskReadWrite, info.IsOpMaskReadWrite);
            Assert.Equal(tc.RealMode, info.RealMode);
            Assert.Equal(tc.ProtectedMode, info.ProtectedMode);
            Assert.Equal(tc.Virtual8086Mode, info.Virtual8086Mode);
            Assert.Equal(tc.CompatibilityMode, info.CompatibilityMode);
            Assert.Equal(tc.LongMode, info.LongMode);
            Assert.Equal(tc.UseOutsideSmm, info.UseOutsideSmm);
            Assert.Equal(tc.UseInSmm, info.UseInSmm);
            Assert.Equal(tc.UseOutsideEnclaveSgx, info.UseOutsideEnclaveSgx);
            Assert.Equal(tc.UseInEnclaveSgx1, info.UseInEnclaveSgx1);
            Assert.Equal(tc.UseInEnclaveSgx2, info.UseInEnclaveSgx2);
            Assert.Equal(tc.UseOutsideVmxOp, info.UseOutsideVmxOp);
            Assert.Equal(tc.UseInVmxRootOp, info.UseInVmxRootOp);
            Assert.Equal(tc.UseInVmxNonRootOp, info.UseInVmxNonRootOp);
            Assert.Equal(tc.UseOutsideSeam, info.UseOutsideSeam);
            Assert.Equal(tc.UseInSeam, info.UseInSeam);
            Assert.Equal(tc.TdxNonRootGenUd, info.TdxNonRootGenUd);
            Assert.Equal(tc.TdxNonRootGenVe, info.TdxNonRootGenVe);
            Assert.Equal(tc.TdxNonRootMayGenEx, info.TdxNonRootMayGenEx);
            Assert.Equal(tc.IntelVmExit, info.IntelVmExit);
            Assert.Equal(tc.IntelMayVmExit, info.IntelMayVmExit);
            Assert.Equal(tc.IntelSmmVmExit, info.IntelSmmVmExit);
            Assert.Equal(tc.AmdVmExit, info.AmdVmExit);
            Assert.Equal(tc.AmdMayVmExit, info.AmdMayVmExit);
            Assert.Equal(tc.TsxAbort, info.TsxAbort);
            Assert.Equal(tc.TsxImplAbort, info.TsxImplAbort);
            Assert.Equal(tc.TsxMayAbort, info.TsxMayAbort);
            Assert.Equal(tc.IntelDecoder16, info.IntelDecoder16);
            Assert.Equal(tc.IntelDecoder32, info.IntelDecoder32);
            Assert.Equal(tc.IntelDecoder64, info.IntelDecoder64);
            Assert.Equal(tc.AmdDecoder16, info.AmdDecoder16);
            Assert.Equal(tc.AmdDecoder32, info.AmdDecoder32);
            Assert.Equal(tc.AmdDecoder64, info.AmdDecoder64);
            Assert.Equal(tc.Table, info.Table);
            Assert.Equal(tc.MandatoryPrefix, info.MandatoryPrefix);
            Assert.Equal(tc.OpCode, info.OpCode);
            Assert.Equal(tc.OpCodeLength, info.OpCodeLength);
            Assert.Equal(tc.IsGroup, info.IsGroup);
            Assert.Equal(tc.GroupIndex, info.GroupIndex);
            Assert.Equal(tc.IsRmGroup, info.IsRmGroup);
            Assert.Equal(tc.RmGroupIndex, info.RmGroupIndex);
            Assert.Equal(tc.OpCount, info.OpCount);
            Assert.Equal(tc.Op0Kind, info.Op0Kind);
            Assert.Equal(tc.Op1Kind, info.Op1Kind);
            Assert.Equal(tc.Op2Kind, info.Op2Kind);
            Assert.Equal(tc.Op3Kind, info.Op3Kind);
            Assert.Equal(tc.Op4Kind, info.Op4Kind);
            Assert.Equal(tc.Op0Kind, info.GetOpKind(0));
            Assert.Equal(tc.Op1Kind, info.GetOpKind(1));
            Assert.Equal(tc.Op2Kind, info.GetOpKind(2));
            Assert.Equal(tc.Op3Kind, info.GetOpKind(3));
            Assert.Equal(tc.Op4Kind, info.GetOpKind(4));
            Static.Assert(IcedConstants.MaxOpCount == 5 ? 0 : -1);
            for (int i = tc.OpCount; i < IcedConstants.MaxOpCount; i++)
            {
                Assert.Equal(OpCodeOperandKind.None, info.GetOpKind(i));
            }
        }
Exemple #18
0
        void Write_all_properties()
        {
            Instruction instruction = default;

            instruction.IP   = 0x8A6BD04A9B683A92;
            instruction.IP16 = ushort.MinValue;
            Assert.Equal(ushort.MinValue, instruction.IP16);
            Assert.Equal(ushort.MinValue, instruction.IP32);
            Assert.Equal(ushort.MinValue, instruction.IP);
            instruction.IP   = 0x8A6BD04A9B683A92;
            instruction.IP16 = ushort.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.IP16);
            Assert.Equal(ushort.MaxValue, instruction.IP32);
            Assert.Equal(ushort.MaxValue, instruction.IP);

            instruction.IP   = 0x8A6BD04A9B683A92;
            instruction.IP32 = uint.MinValue;
            Assert.Equal(ushort.MinValue, instruction.IP16);
            Assert.Equal(uint.MinValue, instruction.IP32);
            Assert.Equal(uint.MinValue, instruction.IP);
            instruction.IP   = 0x8A6BD04A9B683A92;
            instruction.IP32 = uint.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.IP16);
            Assert.Equal(uint.MaxValue, instruction.IP32);
            Assert.Equal(uint.MaxValue, instruction.IP);

            instruction.IP = ulong.MinValue;
            Assert.Equal(ushort.MinValue, instruction.IP16);
            Assert.Equal(uint.MinValue, instruction.IP32);
            Assert.Equal(ulong.MinValue, instruction.IP);
            instruction.IP = ulong.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.IP16);
            Assert.Equal(uint.MaxValue, instruction.IP32);
            Assert.Equal(ulong.MaxValue, instruction.IP);

            instruction.NextIP   = 0x8A6BD04A9B683A92;
            instruction.NextIP16 = ushort.MinValue;
            Assert.Equal(ushort.MinValue, instruction.NextIP16);
            Assert.Equal(ushort.MinValue, instruction.NextIP32);
            Assert.Equal(ushort.MinValue, instruction.NextIP);
            instruction.NextIP   = 0x8A6BD04A9B683A92;
            instruction.NextIP16 = ushort.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.NextIP16);
            Assert.Equal(ushort.MaxValue, instruction.NextIP32);
            Assert.Equal(ushort.MaxValue, instruction.NextIP);

            instruction.NextIP   = 0x8A6BD04A9B683A92;
            instruction.NextIP32 = uint.MinValue;
            Assert.Equal(ushort.MinValue, instruction.NextIP16);
            Assert.Equal(uint.MinValue, instruction.NextIP32);
            Assert.Equal(uint.MinValue, instruction.NextIP);
            instruction.NextIP   = 0x8A6BD04A9B683A92;
            instruction.NextIP32 = uint.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.NextIP16);
            Assert.Equal(uint.MaxValue, instruction.NextIP32);
            Assert.Equal(uint.MaxValue, instruction.NextIP);

            instruction.NextIP = ulong.MinValue;
            Assert.Equal(ushort.MinValue, instruction.NextIP16);
            Assert.Equal(uint.MinValue, instruction.NextIP32);
            Assert.Equal(ulong.MinValue, instruction.NextIP);
            instruction.NextIP = ulong.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.NextIP16);
            Assert.Equal(uint.MaxValue, instruction.NextIP32);
            Assert.Equal(ulong.MaxValue, instruction.NextIP);

            instruction.MemoryDisplacement32 = uint.MinValue;
            Assert.Equal(uint.MinValue, instruction.MemoryDisplacement32);
            Assert.Equal(uint.MinValue, instruction.MemoryDisplacement64);
            instruction.MemoryDisplacement32 = uint.MaxValue;
            Assert.Equal(uint.MaxValue, instruction.MemoryDisplacement32);
            Assert.Equal(uint.MaxValue, instruction.MemoryDisplacement64);

            instruction.MemoryDisplacement64 = ulong.MinValue;
            Assert.Equal(uint.MinValue, instruction.MemoryDisplacement32);
            Assert.Equal(ulong.MinValue, instruction.MemoryDisplacement64);
            instruction.MemoryDisplacement64 = ulong.MaxValue;
            Assert.Equal(uint.MaxValue, instruction.MemoryDisplacement32);
            Assert.Equal(ulong.MaxValue, instruction.MemoryDisplacement64);

            instruction.MemoryDisplacement64 = 0x1234_5678_9ABC_DEF1;
            instruction.MemoryDisplacement32 = 0x5AA5_4321;
            Assert.Equal(0x5AA5_4321U, instruction.MemoryDisplacement32);
            Assert.Equal(0x5AA5_4321U, instruction.MemoryDisplacement64);

            instruction.Immediate8 = byte.MinValue;
            Assert.Equal(byte.MinValue, instruction.Immediate8);
            instruction.Immediate8 = byte.MaxValue;
            Assert.Equal(byte.MaxValue, instruction.Immediate8);

            instruction.Immediate8_2nd = byte.MinValue;
            Assert.Equal(byte.MinValue, instruction.Immediate8_2nd);
            instruction.Immediate8_2nd = byte.MaxValue;
            Assert.Equal(byte.MaxValue, instruction.Immediate8_2nd);

            instruction.Immediate16 = ushort.MinValue;
            Assert.Equal(ushort.MinValue, instruction.Immediate16);
            instruction.Immediate16 = ushort.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.Immediate16);

            instruction.Immediate32 = uint.MinValue;
            Assert.Equal(uint.MinValue, instruction.Immediate32);
            instruction.Immediate32 = uint.MaxValue;
            Assert.Equal(uint.MaxValue, instruction.Immediate32);

            instruction.Immediate64 = ulong.MinValue;
            Assert.Equal(ulong.MinValue, instruction.Immediate64);
            instruction.Immediate64 = ulong.MaxValue;
            Assert.Equal(ulong.MaxValue, instruction.Immediate64);

            instruction.Immediate8to16 = sbyte.MinValue;
            Assert.Equal(sbyte.MinValue, instruction.Immediate8to16);
            instruction.Immediate8to16 = sbyte.MaxValue;
            Assert.Equal(sbyte.MaxValue, instruction.Immediate8to16);

            instruction.Immediate8to32 = sbyte.MinValue;
            Assert.Equal(sbyte.MinValue, instruction.Immediate8to32);
            instruction.Immediate8to32 = sbyte.MaxValue;
            Assert.Equal(sbyte.MaxValue, instruction.Immediate8to32);

            instruction.Immediate8to64 = sbyte.MinValue;
            Assert.Equal(sbyte.MinValue, instruction.Immediate8to64);
            instruction.Immediate8to64 = sbyte.MaxValue;
            Assert.Equal(sbyte.MaxValue, instruction.Immediate8to64);

            instruction.Immediate32to64 = int.MinValue;
            Assert.Equal(int.MinValue, instruction.Immediate32to64);
            instruction.Immediate32to64 = int.MaxValue;
            Assert.Equal(int.MaxValue, instruction.Immediate32to64);

            instruction.Op0Kind      = OpKind.NearBranch16;
            instruction.NearBranch16 = ushort.MinValue;
            Assert.Equal(ushort.MinValue, instruction.NearBranch16);
            Assert.Equal(ushort.MinValue, instruction.NearBranchTarget);
            instruction.NearBranch16 = ushort.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.NearBranch16);
            Assert.Equal(ushort.MaxValue, instruction.NearBranchTarget);

            instruction.Op0Kind      = OpKind.NearBranch32;
            instruction.NearBranch32 = uint.MinValue;
            Assert.Equal(uint.MinValue, instruction.NearBranch32);
            Assert.Equal(uint.MinValue, instruction.NearBranchTarget);
            instruction.NearBranch32 = uint.MaxValue;
            Assert.Equal(uint.MaxValue, instruction.NearBranch32);
            Assert.Equal(uint.MaxValue, instruction.NearBranchTarget);

            instruction.Op0Kind      = OpKind.NearBranch64;
            instruction.NearBranch64 = ulong.MinValue;
            Assert.Equal(ulong.MinValue, instruction.NearBranch64);
            Assert.Equal(ulong.MinValue, instruction.NearBranchTarget);
            instruction.NearBranch64 = ulong.MaxValue;
            Assert.Equal(ulong.MaxValue, instruction.NearBranch64);
            Assert.Equal(ulong.MaxValue, instruction.NearBranchTarget);

            instruction.FarBranch16 = ushort.MinValue;
            Assert.Equal(ushort.MinValue, instruction.FarBranch16);
            instruction.FarBranch16 = ushort.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.FarBranch16);

            instruction.FarBranch32 = uint.MinValue;
            Assert.Equal(uint.MinValue, instruction.FarBranch32);
            instruction.FarBranch32 = uint.MaxValue;
            Assert.Equal(uint.MaxValue, instruction.FarBranch32);

            instruction.FarBranchSelector = ushort.MinValue;
            Assert.Equal(ushort.MinValue, instruction.FarBranchSelector);
            instruction.FarBranchSelector = ushort.MaxValue;
            Assert.Equal(ushort.MaxValue, instruction.FarBranchSelector);

            instruction.HasXacquirePrefix = false;
            Assert.False(instruction.HasXacquirePrefix);
            instruction.HasXacquirePrefix = true;
            Assert.True(instruction.HasXacquirePrefix);

            instruction.HasXreleasePrefix = false;
            Assert.False(instruction.HasXreleasePrefix);
            instruction.HasXreleasePrefix = true;
            Assert.True(instruction.HasXreleasePrefix);

            instruction.HasRepPrefix = false;
            Assert.False(instruction.HasRepPrefix);
            Assert.False(instruction.HasRepePrefix);
            instruction.HasRepPrefix = true;
            Assert.True(instruction.HasRepPrefix);
            Assert.True(instruction.HasRepePrefix);

            instruction.HasRepePrefix = false;
            Assert.False(instruction.HasRepPrefix);
            Assert.False(instruction.HasRepePrefix);
            instruction.HasRepePrefix = true;
            Assert.True(instruction.HasRepPrefix);
            Assert.True(instruction.HasRepePrefix);

            instruction.HasRepnePrefix = false;
            Assert.False(instruction.HasRepnePrefix);
            instruction.HasRepnePrefix = true;
            Assert.True(instruction.HasRepnePrefix);

            instruction.HasLockPrefix = false;
            Assert.False(instruction.HasLockPrefix);
            instruction.HasLockPrefix = true;
            Assert.True(instruction.HasLockPrefix);

            instruction.IsBroadcast = false;
            Assert.False(instruction.IsBroadcast);
            instruction.IsBroadcast = true;
            Assert.True(instruction.IsBroadcast);

            instruction.SuppressAllExceptions = false;
            Assert.False(instruction.SuppressAllExceptions);
            instruction.SuppressAllExceptions = true;
            Assert.True(instruction.SuppressAllExceptions);

            for (int i = 0; i <= IcedConstants.MaxInstructionLength; i++)
            {
                instruction.Length = i;
                Assert.Equal(i, instruction.Length);
            }

            foreach (var codeSize in GetCodeSizeValues())
            {
                instruction.CodeSize = codeSize;
                Assert.Equal(codeSize, instruction.CodeSize);
            }

            foreach (var code in GetCodeValues())
            {
                instruction.Code = code;
                Assert.Equal(code, instruction.Code);
            }
            foreach (var code in GetCodeValues())
            {
                instruction.InternalSetCodeNoCheck(code);
                Assert.Equal(code, instruction.Code);
            }
            Assert.Throws <ArgumentOutOfRangeException>(() => instruction.Code = (Code)(-1));
            Assert.Throws <ArgumentOutOfRangeException>(() => instruction.Code = (Code)IcedConstants.CodeEnumCount);

            Static.Assert(IcedConstants.MaxOpCount == 5 ? 0 : -1);
            foreach (var opKind in GetOpKindValues())
            {
                instruction.Op0Kind = opKind;
                Assert.Equal(opKind, instruction.Op0Kind);
            }

            foreach (var opKind in GetOpKindValues())
            {
                instruction.Op1Kind = opKind;
                Assert.Equal(opKind, instruction.Op1Kind);
            }

            foreach (var opKind in GetOpKindValues())
            {
                instruction.Op2Kind = opKind;
                Assert.Equal(opKind, instruction.Op2Kind);
            }

            foreach (var opKind in GetOpKindValues())
            {
                instruction.Op3Kind = opKind;
                Assert.Equal(opKind, instruction.Op3Kind);
            }

            foreach (var opKind in GetOpKindValues())
            {
                if (opKind == OpKind.Immediate8)
                {
                    instruction.Op4Kind = opKind;
                    Assert.Equal(opKind, instruction.Op4Kind);
                }
                else
                {
                    Assert.Throws <ArgumentOutOfRangeException>(() => instruction.Op4Kind = opKind);
                }
            }

            foreach (var opKind in GetOpKindValues())
            {
                instruction.SetOpKind(0, opKind);
                Assert.Equal(opKind, instruction.Op0Kind);
                Assert.Equal(opKind, instruction.GetOpKind(0));
            }

            foreach (var opKind in GetOpKindValues())
            {
                instruction.SetOpKind(1, opKind);
                Assert.Equal(opKind, instruction.Op1Kind);
                Assert.Equal(opKind, instruction.GetOpKind(1));
            }

            foreach (var opKind in GetOpKindValues())
            {
                instruction.SetOpKind(2, opKind);
                Assert.Equal(opKind, instruction.Op2Kind);
                Assert.Equal(opKind, instruction.GetOpKind(2));
            }

            foreach (var opKind in GetOpKindValues())
            {
                instruction.SetOpKind(3, opKind);
                Assert.Equal(opKind, instruction.Op3Kind);
                Assert.Equal(opKind, instruction.GetOpKind(3));
            }

            foreach (var opKind in GetOpKindValues())
            {
                if (opKind == OpKind.Immediate8)
                {
                    instruction.SetOpKind(4, opKind);
                    Assert.Equal(opKind, instruction.Op4Kind);
                    Assert.Equal(opKind, instruction.GetOpKind(4));
                }
                else
                {
                    Assert.Throws <ArgumentOutOfRangeException>(() => instruction.SetOpKind(4, opKind));
                }
            }

            var segValues = new Register[] {
                Register.ES,
                Register.CS,
                Register.SS,
                Register.DS,
                Register.FS,
                Register.GS,
                Register.None,
            };

            foreach (var seg in segValues)
            {
                instruction.SegmentPrefix = seg;
                Assert.Equal(seg, instruction.SegmentPrefix);
                if (instruction.SegmentPrefix == Register.None)
                {
                    Assert.False(instruction.HasSegmentPrefix);
                }
                else
                {
                    Assert.True(instruction.HasSegmentPrefix);
                }
            }

            var displSizes = new int[] { 8, 4, 2, 1, 0 };

            foreach (var displSize in displSizes)
            {
                instruction.MemoryDisplSize = displSize;
                Assert.Equal(displSize, instruction.MemoryDisplSize);
            }

            var scaleValues = new int[] { 8, 4, 2, 1 };

            foreach (var scaleValue in scaleValues)
            {
                instruction.MemoryIndexScale = scaleValue;
                Assert.Equal(scaleValue, instruction.MemoryIndexScale);
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.MemoryBase = reg;
                Assert.Equal(reg, instruction.MemoryBase);
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.MemoryIndex = reg;
                Assert.Equal(reg, instruction.MemoryIndex);
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.Op0Register = reg;
                Assert.Equal(reg, instruction.Op0Register);
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.Op1Register = reg;
                Assert.Equal(reg, instruction.Op1Register);
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.Op2Register = reg;
                Assert.Equal(reg, instruction.Op2Register);
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.Op3Register = reg;
                Assert.Equal(reg, instruction.Op3Register);
            }

            foreach (var reg in GetRegisterValues())
            {
                if (reg == Register.None)
                {
                    instruction.Op4Register = reg;
                    Assert.Equal(reg, instruction.Op4Register);
                }
                else
                {
                    Assert.Throws <ArgumentOutOfRangeException>(() => instruction.Op4Register = reg);
                }
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.SetOpRegister(0, reg);
                Assert.Equal(reg, instruction.Op0Register);
                Assert.Equal(reg, instruction.GetOpRegister(0));
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.SetOpRegister(1, reg);
                Assert.Equal(reg, instruction.Op1Register);
                Assert.Equal(reg, instruction.GetOpRegister(1));
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.SetOpRegister(2, reg);
                Assert.Equal(reg, instruction.Op2Register);
                Assert.Equal(reg, instruction.GetOpRegister(2));
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.SetOpRegister(3, reg);
                Assert.Equal(reg, instruction.Op3Register);
                Assert.Equal(reg, instruction.GetOpRegister(3));
            }

            foreach (var reg in GetRegisterValues())
            {
                if (reg == Register.None)
                {
                    instruction.SetOpRegister(4, reg);
                    Assert.Equal(reg, instruction.Op4Register);
                    Assert.Equal(reg, instruction.GetOpRegister(4));
                }
                else
                {
                    Assert.Throws <ArgumentOutOfRangeException>(() => instruction.SetOpRegister(4, reg));
                }
            }

            var opMasks = new Register[] {
                Register.K1,
                Register.K2,
                Register.K3,
                Register.K4,
                Register.K5,
                Register.K6,
                Register.K7,
                Register.None,
            };

            foreach (var opMask in opMasks)
            {
                instruction.OpMask = opMask;
                Assert.Equal(opMask, instruction.OpMask);
                Assert.Equal(opMask != Register.None, instruction.HasOpMask);
            }

            instruction.ZeroingMasking = false;
            Assert.False(instruction.ZeroingMasking);
            Assert.True(instruction.MergingMasking);
            instruction.ZeroingMasking = true;
            Assert.True(instruction.ZeroingMasking);
            Assert.False(instruction.MergingMasking);
            instruction.MergingMasking = false;
            Assert.False(instruction.MergingMasking);
            Assert.True(instruction.ZeroingMasking);
            instruction.MergingMasking = true;
            Assert.True(instruction.MergingMasking);
            Assert.False(instruction.ZeroingMasking);

            foreach (var rc in GetRoundingControlValues())
            {
                instruction.RoundingControl = rc;
                Assert.Equal(rc, instruction.RoundingControl);
            }

            foreach (var reg in GetRegisterValues())
            {
                instruction.MemoryBase = reg;
                Assert.Equal(reg == Register.RIP || reg == Register.EIP, instruction.IsIPRelativeMemoryOperand);
            }

            instruction.MemoryBase           = Register.EIP;
            instruction.NextIP               = 0x123456709EDCBA98;
            instruction.MemoryDisplacement64 = 0x876543219ABCDEF5;
            Assert.True(instruction.IsIPRelativeMemoryOperand);
            Assert.Equal(0x9ABCDEF5UL, instruction.IPRelativeMemoryAddress);

            instruction.MemoryBase           = Register.RIP;
            instruction.NextIP               = 0x123456709EDCBA98;
            instruction.MemoryDisplacement64 = 0x876543219ABCDEF5;
            Assert.True(instruction.IsIPRelativeMemoryOperand);
            Assert.Equal(0x876543219ABCDEF5UL, instruction.IPRelativeMemoryAddress);

            instruction.DeclareDataCount = 1;
            Assert.Equal(1, instruction.DeclareDataCount);
            instruction.DeclareDataCount = 15;
            Assert.Equal(15, instruction.DeclareDataCount);
            instruction.DeclareDataCount = 16;
            Assert.Equal(16, instruction.DeclareDataCount);
        }
Exemple #19
0
#pragma warning disable xUnit1026 // Theory methods should use all of their parameters
        void Test_all_OpCodeInfos(int lineNo, Code code, string opCodeString, string instructionString, OpCodeInfoTestCase tc)
        {
#pragma warning restore xUnit1026 // Theory methods should use all of their parameters
            var info = tc.Code.ToOpCode();
            Assert.Equal(tc.Code, info.Code);
#pragma warning disable xUnit2006 // Do not use invalid string equality check
            // Show the full string without ellipses by using Equal<string>() instead of Equal()
            Assert.Equal <string>(tc.OpCodeString, info.ToOpCodeString());
            Assert.Equal <string>(tc.InstructionString, info.ToInstructionString());
#pragma warning restore xUnit2006 // Do not use invalid string equality check
            Assert.True((object)info.ToInstructionString() == info.ToString());
            Assert.Equal(tc.Encoding, info.Encoding);
            Assert.Equal(tc.IsInstruction, info.IsInstruction);
            Assert.Equal(tc.Mode16, info.Mode16);
            Assert.Equal(tc.Mode16, info.IsAvailableInMode(16));
            Assert.Equal(tc.Mode32, info.Mode32);
            Assert.Equal(tc.Mode32, info.IsAvailableInMode(32));
            Assert.Equal(tc.Mode64, info.Mode64);
            Assert.Equal(tc.Mode64, info.IsAvailableInMode(64));
            Assert.Equal(tc.Fwait, info.Fwait);
            Assert.Equal(tc.OperandSize, info.OperandSize);
            Assert.Equal(tc.AddressSize, info.AddressSize);
            Assert.Equal(tc.L, info.L);
            Assert.Equal(tc.W, info.W);
            Assert.Equal(tc.IsLIG, info.IsLIG);
            Assert.Equal(tc.IsWIG, info.IsWIG);
            Assert.Equal(tc.IsWIG32, info.IsWIG32);
            Assert.Equal(tc.TupleType, info.TupleType);
            Assert.Equal(tc.CanBroadcast, info.CanBroadcast);
            Assert.Equal(tc.CanUseRoundingControl, info.CanUseRoundingControl);
            Assert.Equal(tc.CanSuppressAllExceptions, info.CanSuppressAllExceptions);
            Assert.Equal(tc.CanUseOpMaskRegister, info.CanUseOpMaskRegister);
            Assert.Equal(tc.RequireNonZeroOpMaskRegister, info.RequireNonZeroOpMaskRegister);
            if (tc.RequireNonZeroOpMaskRegister)
            {
                Assert.True(info.CanUseOpMaskRegister);
                Assert.False(info.CanUseZeroingMasking);
            }
            Assert.Equal(tc.CanUseZeroingMasking, info.CanUseZeroingMasking);
            Assert.Equal(tc.CanUseLockPrefix, info.CanUseLockPrefix);
            Assert.Equal(tc.CanUseXacquirePrefix, info.CanUseXacquirePrefix);
            Assert.Equal(tc.CanUseXreleasePrefix, info.CanUseXreleasePrefix);
            Assert.Equal(tc.CanUseRepPrefix, info.CanUseRepPrefix);
            Assert.Equal(tc.CanUseRepnePrefix, info.CanUseRepnePrefix);
            Assert.Equal(tc.CanUseBndPrefix, info.CanUseBndPrefix);
            Assert.Equal(tc.CanUseHintTakenPrefix, info.CanUseHintTakenPrefix);
            Assert.Equal(tc.CanUseNotrackPrefix, info.CanUseNotrackPrefix);
            Assert.Equal(tc.Table, info.Table);
            Assert.Equal(tc.MandatoryPrefix, info.MandatoryPrefix);
            Assert.Equal(tc.OpCode, info.OpCode);
            Assert.Equal(tc.IsGroup, info.IsGroup);
            Assert.Equal(tc.GroupIndex, info.GroupIndex);
            Assert.Equal(tc.OpCount, info.OpCount);
            Assert.Equal(tc.Op0Kind, info.Op0Kind);
            Assert.Equal(tc.Op1Kind, info.Op1Kind);
            Assert.Equal(tc.Op2Kind, info.Op2Kind);
            Assert.Equal(tc.Op3Kind, info.Op3Kind);
            Assert.Equal(tc.Op4Kind, info.Op4Kind);
            Assert.Equal(tc.Op0Kind, info.GetOpKind(0));
            Assert.Equal(tc.Op1Kind, info.GetOpKind(1));
            Assert.Equal(tc.Op2Kind, info.GetOpKind(2));
            Assert.Equal(tc.Op3Kind, info.GetOpKind(3));
            Assert.Equal(tc.Op4Kind, info.GetOpKind(4));
            Static.Assert(IcedConstants.MaxOpCount == 5 ? 0 : -1);
            for (int i = tc.OpCount; i < IcedConstants.MaxOpCount; i++)
            {
                Assert.Equal(OpCodeOperandKind.None, info.GetOpKind(i));
            }
        }
Exemple #20
0
        protected void TestInstructionInfo(int bitness, string hexBytes, Code code, DecoderOptions options, int lineNo, InstructionInfoTestCase testCase)
        {
            var         codeBytes = HexUtils.ToByteArray(hexBytes);
            Instruction instruction;

            if (testCase.IsSpecial)
            {
                if (bitness == 16 && code == Code.Popw_CS && hexBytes == "0F")
                {
                    instruction             = default;
                    instruction.Code        = Code.Popw_CS;
                    instruction.Op0Kind     = OpKind.Register;
                    instruction.Op0Register = Register.CS;
                    instruction.CodeSize    = CodeSize.Code16;
                    instruction.Length      = 1;
                }
                else if (code <= Code.DeclareQword)
                {
                    instruction                  = default;
                    instruction.Code             = code;
                    instruction.DeclareDataCount = 1;
                    Assert.Equal(64, bitness);
                    instruction.CodeSize = CodeSize.Code64;
                    switch (code)
                    {
                    case Code.DeclareByte:
                        Assert.Equal("66", hexBytes);
                        instruction.SetDeclareByteValue(0, 0x66);
                        break;

                    case Code.DeclareWord:
                        Assert.Equal("6644", hexBytes);
                        instruction.SetDeclareWordValue(0, 0x4466);
                        break;

                    case Code.DeclareDword:
                        Assert.Equal("664422EE", hexBytes);
                        instruction.SetDeclareDwordValue(0, 0xEE224466);
                        break;

                    case Code.DeclareQword:
                        Assert.Equal("664422EE12345678", hexBytes);
                        instruction.SetDeclareQwordValue(0, 0x78563412EE224466);
                        break;

                    default: throw new InvalidOperationException();
                    }
                }
                else
                {
                    var decoder = CreateDecoder(bitness, codeBytes, options);
                    instruction = decoder.Decode();
                    if (codeBytes.Length > 1 && codeBytes[0] == 0x9B && instruction.Length == 1)
                    {
                        instruction      = decoder.Decode();
                        instruction.Code = instruction.Code switch {
                            Code.Fnstenv_m14byte => Code.Fstenv_m14byte,
                            Code.Fnstenv_m28byte => Code.Fstenv_m28byte,
                            Code.Fnstcw_m2byte => Code.Fstcw_m2byte,
                            Code.Fneni => Code.Feni,
                            Code.Fndisi => Code.Fdisi,
                            Code.Fnclex => Code.Fclex,
                            Code.Fninit => Code.Finit,
                            Code.Fnsetpm => Code.Fsetpm,
                            Code.Fnsave_m94byte => Code.Fsave_m94byte,
                            Code.Fnsave_m108byte => Code.Fsave_m108byte,
                            Code.Fnstsw_m2byte => Code.Fstsw_m2byte,
                            Code.Fnstsw_AX => Code.Fstsw_AX,
                            _ => throw new InvalidOperationException(),
                        };
                    }
                    else
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
            else
            {
                var decoder = CreateDecoder(bitness, codeBytes, options);
                instruction = decoder.Decode();
            }
            Assert.Equal(code, instruction.Code);

            Assert.Equal(testCase.StackPointerIncrement, instruction.StackPointerIncrement);

            var info = new InstructionInfoFactory().GetInfo(instruction);

            Assert.Equal(testCase.Encoding, info.Encoding);
            Assert.Equal(testCase.CpuidFeatures, info.CpuidFeatures);
            Assert.Equal(testCase.RflagsRead, info.RflagsRead);
            Assert.Equal(testCase.RflagsUndefined, info.RflagsUndefined);
            Assert.Equal(testCase.RflagsWritten, info.RflagsWritten);
            Assert.Equal(testCase.RflagsCleared, info.RflagsCleared);
            Assert.Equal(testCase.RflagsSet, info.RflagsSet);
            Assert.Equal(testCase.IsPrivileged, info.IsPrivileged);
            Assert.Equal(testCase.IsProtectedMode, info.IsProtectedMode);
            Assert.Equal(testCase.IsStackInstruction, info.IsStackInstruction);
            Assert.Equal(testCase.IsSaveRestoreInstruction, info.IsSaveRestoreInstruction);
            Assert.Equal(testCase.FlowControl, info.FlowControl);
            Assert.Equal(testCase.Op0Access, info.Op0Access);
            Assert.Equal(testCase.Op1Access, info.Op1Access);
            Assert.Equal(testCase.Op2Access, info.Op2Access);
            Assert.Equal(testCase.Op3Access, info.Op3Access);
            Assert.Equal(testCase.Op4Access, info.Op4Access);
            Assert.Equal(
                new HashSet <UsedMemory>(testCase.UsedMemory, UsedMemoryEqualityComparer.Instance),
                new HashSet <UsedMemory>(info.GetUsedMemory(), UsedMemoryEqualityComparer.Instance));
            Assert.Equal(
                new HashSet <UsedRegister>(GetUsedRegisters(testCase.UsedRegisters), UsedRegisterEqualityComparer.Instance),
                new HashSet <UsedRegister>(GetUsedRegisters(info.GetUsedRegisters()), UsedRegisterEqualityComparer.Instance));

            Static.Assert(IcedConstants.MaxOpCount == 5 ? 0 : -1);
            Debug.Assert(instruction.OpCount <= IcedConstants.MaxOpCount);
            for (int i = 0; i < instruction.OpCount; i++)
            {
                switch (i)
                {
                case 0:
                    Assert.Equal(testCase.Op0Access, info.GetOpAccess(i));
                    break;

                case 1:
                    Assert.Equal(testCase.Op1Access, info.GetOpAccess(i));
                    break;

                case 2:
                    Assert.Equal(testCase.Op2Access, info.GetOpAccess(i));
                    break;

                case 3:
                    Assert.Equal(testCase.Op3Access, info.GetOpAccess(i));
                    break;

                case 4:
                    Assert.Equal(testCase.Op4Access, info.GetOpAccess(i));
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }
            for (int i = instruction.OpCount; i < IcedConstants.MaxOpCount; i++)
            {
                Assert.Equal(OpAccess.None, info.GetOpAccess(i));
            }

            Assert.Equal(RflagsBits.None, info.RflagsWritten & (info.RflagsCleared | info.RflagsSet | info.RflagsUndefined));
            Assert.Equal(RflagsBits.None, info.RflagsCleared & (info.RflagsWritten | info.RflagsSet | info.RflagsUndefined));
            Assert.Equal(RflagsBits.None, info.RflagsSet & (info.RflagsWritten | info.RflagsCleared | info.RflagsUndefined));
            Assert.Equal(RflagsBits.None, info.RflagsUndefined & (info.RflagsWritten | info.RflagsCleared | info.RflagsSet));
            Assert.Equal(info.RflagsWritten | info.RflagsCleared | info.RflagsSet | info.RflagsUndefined, info.RflagsModified);

            var info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.None);

            CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: true);
            info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoMemoryUsage);
            CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: false);
            info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoRegisterUsage);
            CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: true);
            info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoRegisterUsage | InstructionInfoOptions.NoMemoryUsage);
            CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: false);

            Assert.Equal(info.Encoding, instruction.Code.Encoding());
#if ENCODER && OPCODE_INFO
            Assert.Equal(code.ToOpCode().Encoding, instruction.Code.Encoding());
#endif
            var cf = instruction.Code.CpuidFeatures();
            if (cf.Length == 1 && cf[0] == CpuidFeature.AVX && instruction.Op1Kind == OpKind.Register && (code == Code.VEX_Vbroadcastss_xmm_xmmm32 || code == Code.VEX_Vbroadcastss_ymm_xmmm32 || code == Code.VEX_Vbroadcastsd_ymm_xmmm64))
            {
                cf = new[] { CpuidFeature.AVX2 }
            }
            ;
            Assert.Equal(info.CpuidFeatures, cf);
            Assert.Equal(info.FlowControl, instruction.Code.FlowControl());
            Assert.Equal(info.IsProtectedMode, instruction.Code.IsProtectedMode());
            Assert.Equal(info.IsPrivileged, instruction.Code.IsPrivileged());
            Assert.Equal(info.IsStackInstruction, instruction.Code.IsStackInstruction());
            Assert.Equal(info.IsSaveRestoreInstruction, instruction.Code.IsSaveRestoreInstruction());

            Assert.Equal(info.Encoding, instruction.Encoding);
            Assert.Equal(info.CpuidFeatures, instruction.CpuidFeatures);
            Assert.Equal(info.FlowControl, instruction.FlowControl);
            Assert.Equal(info.IsProtectedMode, instruction.IsProtectedMode);
            Assert.Equal(info.IsPrivileged, instruction.IsPrivileged);
            Assert.Equal(info.IsStackInstruction, instruction.IsStackInstruction);
            Assert.Equal(info.IsSaveRestoreInstruction, instruction.IsSaveRestoreInstruction);
            Assert.Equal(info.RflagsRead, instruction.RflagsRead);
            Assert.Equal(info.RflagsWritten, instruction.RflagsWritten);
            Assert.Equal(info.RflagsCleared, instruction.RflagsCleared);
            Assert.Equal(info.RflagsSet, instruction.RflagsSet);
            Assert.Equal(info.RflagsUndefined, instruction.RflagsUndefined);
            Assert.Equal(info.RflagsModified, instruction.RflagsModified);
        }

        void CheckEqual(ref InstructionInfo info1, ref InstructionInfo info2, bool hasRegs2, bool hasMem2)
        {
            if (hasRegs2)
            {
                Assert.Equal(info1.GetUsedRegisters(), info2.GetUsedRegisters(), UsedRegisterEqualityComparer.Instance);
            }
            else
            {
                Assert.Empty(info2.GetUsedRegisters());
            }
            if (hasMem2)
            {
                Assert.Equal(info1.GetUsedMemory(), info2.GetUsedMemory(), UsedMemoryEqualityComparer.Instance);
            }
            else
            {
                Assert.Empty(info2.GetUsedMemory());
            }
            Assert.Equal(info1.IsProtectedMode, info2.IsProtectedMode);
            Assert.Equal(info1.IsPrivileged, info2.IsPrivileged);
            Assert.Equal(info1.IsStackInstruction, info2.IsStackInstruction);
            Assert.Equal(info1.IsSaveRestoreInstruction, info2.IsSaveRestoreInstruction);
            Assert.Equal(info1.Encoding, info2.Encoding);
            Assert.Equal(info1.CpuidFeatures, info2.CpuidFeatures);
            Assert.Equal(info1.FlowControl, info2.FlowControl);
            Assert.Equal(info1.Op0Access, info2.Op0Access);
            Assert.Equal(info1.Op1Access, info2.Op1Access);
            Assert.Equal(info1.Op2Access, info2.Op2Access);
            Assert.Equal(info1.Op3Access, info2.Op3Access);
            Assert.Equal(info1.Op4Access, info2.Op4Access);
            Assert.Equal(info1.RflagsRead, info2.RflagsRead);
            Assert.Equal(info1.RflagsWritten, info2.RflagsWritten);
            Assert.Equal(info1.RflagsCleared, info2.RflagsCleared);
            Assert.Equal(info1.RflagsSet, info2.RflagsSet);
            Assert.Equal(info1.RflagsUndefined, info2.RflagsUndefined);
            Assert.Equal(info1.RflagsModified, info2.RflagsModified);
        }

        IEnumerable <UsedRegister> GetUsedRegisters(IEnumerable <UsedRegister> usedRegisterIterator)
        {
            var read      = new List <Register>();
            var write     = new List <Register>();
            var condRead  = new List <Register>();
            var condWrite = new List <Register>();

            foreach (var info in usedRegisterIterator)
            {
                switch (info.Access)
                {
                case OpAccess.Read:
                    read.Add(info.Register);
                    break;

                case OpAccess.CondRead:
                    condRead.Add(info.Register);
                    break;

                case OpAccess.Write:
                    write.Add(info.Register);
                    break;

                case OpAccess.CondWrite:
                    condWrite.Add(info.Register);
                    break;

                case OpAccess.ReadWrite:
                    read.Add(info.Register);
                    write.Add(info.Register);
                    break;

                case OpAccess.ReadCondWrite:
                    read.Add(info.Register);
                    condWrite.Add(info.Register);
                    break;

                case OpAccess.None:
                case OpAccess.NoMemAccess:
                default:
                    throw new InvalidOperationException();
                }
            }

            foreach (var reg in GetRegisters(read))
            {
                yield return(new UsedRegister(reg, OpAccess.Read));
            }
            foreach (var reg in GetRegisters(write))
            {
                yield return(new UsedRegister(reg, OpAccess.Write));
            }
            foreach (var reg in GetRegisters(condRead))
            {
                yield return(new UsedRegister(reg, OpAccess.CondRead));
            }
            foreach (var reg in GetRegisters(condWrite))
            {
                yield return(new UsedRegister(reg, OpAccess.CondWrite));
            }
        }

        IEnumerable <Register> GetRegisters(List <Register> regs)
        {
            if (regs.Count <= 1)
            {
                return(regs);
            }

            regs.Sort(RegisterSorter);

            var hash = new HashSet <Register>();
            int index;

            foreach (var reg in regs)
            {
                if (Register.EAX <= reg && reg <= Register.R15D)
                {
                    index = reg - Register.EAX;
                    if (hash.Contains(Register.RAX + index))
                    {
                        continue;
                    }
                }
                else if (Register.AX <= reg && reg <= Register.R15W)
                {
                    index = reg - Register.AX;
                    if (hash.Contains(Register.RAX + index))
                    {
                        continue;
                    }
                    if (hash.Contains(Register.EAX + index))
                    {
                        continue;
                    }
                }
                else if (Register.AL <= reg && reg <= Register.R15L)
                {
                    index = reg - Register.AL;
                    if (Register.AH <= reg && reg <= Register.BH)
                    {
                        index -= 4;
                    }
                    if (hash.Contains(Register.RAX + index))
                    {
                        continue;
                    }
                    if (hash.Contains(Register.EAX + index))
                    {
                        continue;
                    }
                    if (hash.Contains(Register.AX + index))
                    {
                        continue;
                    }
                }
                else if (Register.YMM0 <= reg && reg <= IcedConstants.YMM_last)
                {
                    index = reg - Register.YMM0;
                    if (hash.Contains(Register.ZMM0 + index))
                    {
                        continue;
                    }
                }
                else if (Register.XMM0 <= reg && reg <= IcedConstants.XMM_last)
                {
                    index = reg - Register.XMM0;
                    if (hash.Contains(Register.ZMM0 + index))
                    {
                        continue;
                    }
                    if (hash.Contains(Register.YMM0 + index))
                    {
                        continue;
                    }
                }
                hash.Add(reg);
            }

            foreach (var info in lowRegs)
            {
                if (hash.Contains(info.rl) && hash.Contains(info.rh))
                {
                    hash.Remove(info.rl);
                    hash.Remove(info.rh);
                    hash.Add(info.rx);
                }
            }

            return(hash);
        }