/// <summary> /// (This method allocates and is slower than using an <see cref="InstructionInfoFactory"/>.) /// /// Gets instruction info such as which register is read and written etc. /// </summary> /// <param name="options">Options</param> /// <returns></returns> public InstructionInfo GetInfo(InstructionInfoOptions options) { var usedRegisters = InstructionInfoInternal.SimpleList <UsedRegister> .Empty; var usedMemoryLocations = InstructionInfoInternal.SimpleList <UsedMemory> .Empty; return(InstructionInfoFactory.Create(ref this, ref usedRegisters, ref usedMemoryLocations, options)); }
/// <summary> /// (This method allocates and is slower than using an <see cref="InstructionInfoFactory"/>.) /// /// Gets a struct iterator that returns all read and written memory locations /// </summary> /// <returns></returns> public InstructionInfo.UsedMemoryIterator GetUsedMemory() { var usedRegisters = InstructionInfoInternal.SimpleList <UsedRegister> .Empty; var usedMemoryLocations = InstructionInfoInternal.SimpleList <UsedMemory> .Empty; return(InstructionInfoFactory.Create(ref this, ref usedRegisters, ref usedMemoryLocations, InstructionInfoOptions.NoRegisterUsage).GetUsedMemory()); }
private void DecorateDebugInfo(Instruction instr, DebugInfoHelper debugRecords, ulong baseInstrIP) { if (debugRecords != null) { InstructionInfoFactory factory = new InstructionInfoFactory(); InstructionInfo info = factory.GetInfo(instr); ulong codeOffset = instr.IP - baseInstrIP; debugRecords.Update(codeOffset); Variable variable = null; foreach (UsedMemory usedMemInfo in info.GetUsedMemory()) { string baseRegister = usedMemInfo.Base.ToString(); int displacement; unchecked { displacement = (int)usedMemInfo.Displacement; } Dictionary <int, Variable> offsetToVariableMap; if (debugRecords.registerRelativeVariables.TryGetValue(usedMemInfo.Base.ToString(), out offsetToVariableMap)) { if (offsetToVariableMap.TryGetValue(displacement, out variable)) { output.Write($"; [{usedMemInfo.Base.ToString().ToLower()}{(displacement < 0 ? '-' : '+')}{Math.Abs(displacement):X}h] = {variable.Type} {variable.Index}"); } } } foreach (UsedRegister usedMemInfo in info.GetUsedRegisters()) { if (debugRecords.registerVariables.TryGetValue(usedMemInfo.Register.ToString(), out variable)) { output.Write($"; {usedMemInfo.Register.ToString().ToLower()} = {variable.Type} {variable.Index}"); } } } }
/// <summary> /// (This method allocates and is slower than using an <see cref="InstructionInfoFactory"/>.) /// /// Gets instruction info such as which register is read and written etc. /// </summary> /// <returns></returns> public readonly InstructionInfo GetInfo() { var usedRegisters = InstructionInfoInternal.SimpleList <UsedRegister> .Empty; var usedMemoryLocations = InstructionInfoInternal.SimpleList <UsedMemory> .Empty; return(InstructionInfoFactory.Create(this, ref usedRegisters, ref usedMemoryLocations, InstructionInfoOptions.None)); }
void InstructionInfo_GetOpAccess_throws_if_invalid_input() { Instruction instr = default; instr.Code = Code.Nopd; var info = new InstructionInfoFactory().GetInfo(instr); Assert.Throws <ArgumentOutOfRangeException>(() => info.GetOpAccess(-1)); Assert.Throws <ArgumentOutOfRangeException>(() => info.GetOpAccess(IcedConstants.MaxOpCount)); }
void VATests(VirtualAddressTestCase tc) { var decoder = Decoder.Create(tc.Bitness, new ByteArrayCodeReader(tc.HexBytes), tc.DecoderOptions); decoder.IP = tc.Bitness switch { 16 => DecoderConstants.DEFAULT_IP16, 32 => DecoderConstants.DEFAULT_IP32, 64 => DecoderConstants.DEFAULT_IP64, _ => throw new InvalidOperationException(), }; var instruction = decoder.Decode(); var getRegValue = new VARegisterValueProviderImpl(tc.RegisterValues); var getRegValueFail = new VARegisterValueProviderImpl(Array.Empty <(Register register, int elementIndex, int elementSize, ulong value)>()); var factory = new InstructionInfoFactory(); var info = factory.GetInfo(instruction); var usedMem = info.GetUsedMemory().Skip(tc.UsedMemIndex).First(); bool b1 = usedMem.TryGetVirtualAddress(tc.ElementIndex, getRegValue, out ulong value1); Assert.True(b1); Assert.Equal(tc.ExpectedValue, value1); bool b2 = usedMem.TryGetVirtualAddress(tc.ElementIndex, out ulong value2, (Register register, int elementIndex, int elementSize, out ulong value) => getRegValue.TryGetRegisterValue(register, elementIndex, elementSize, out value)); Assert.True(b2); Assert.Equal(tc.ExpectedValue, value2); ulong value3 = usedMem.GetVirtualAddress(tc.ElementIndex, getRegValue); Assert.Equal(tc.ExpectedValue, value3); ulong value4 = usedMem.GetVirtualAddress(tc.ElementIndex, (register, elementIndex2, elementSize) => getRegValue.GetRegisterValue(register, elementIndex2, elementSize)); Assert.Equal(tc.ExpectedValue, value4); Assert.False(usedMem.TryGetVirtualAddress(tc.ElementIndex, out ulong value5, (Register register, int elementIndex, int elementSize, out ulong value) => { value = 0; return(false); })); Assert.Equal(0UL, value5); Assert.False(usedMem.TryGetVirtualAddress(tc.ElementIndex, getRegValueFail, out ulong value6)); Assert.Equal(0UL, value6); }
private void DecorateDebugInfo(Instruction instr, DebugInfoHelper debugRecords, ulong baseInstrIP) { if (debugRecords != null) { HashSet <Variable> variables; InstructionInfoFactory factory = new InstructionInfoFactory(); InstructionInfo info = factory.GetInfo(instr); ulong codeOffset = instr.IP - baseInstrIP; debugRecords.Update(codeOffset); foreach (UsedMemory usedMemInfo in info.GetUsedMemory()) { string baseRegister = usedMemInfo.Base.ToString(); int displacement; unchecked { displacement = (int)usedMemInfo.Displacement; } Dictionary <int, HashSet <Variable> > offsetToVariableMap; if (debugRecords.registerRelativeVariables.TryGetValue(usedMemInfo.Base.ToString(), out offsetToVariableMap)) { if (offsetToVariableMap.TryGetValue(displacement, out variables)) { output.Write($";"); foreach (Variable variable in variables) { output.Write($" [{usedMemInfo.Base.ToString().ToLower()}{(displacement < 0 ? '-' : '+')}{Math.Abs(displacement):X}h] = {variable.Type} {variable.Index}"); } } } } foreach (UsedRegister usedMemInfo in info.GetUsedRegisters()) { // TODO, if the code is accessing EAX but the debug info maps to RAX, then this match is going to fail. if (debugRecords.registerVariables.TryGetValue(usedMemInfo.Register.ToString(), out variables)) { output.Write($";"); foreach (Variable variable in variables) { output.Write($" {usedMemInfo.Register.ToString().ToLower()} = {variable.Type} {variable.Index}"); } } } } }
protected void TestInstructionInfo(int bitness, string hexBytes, Code code, int lineNo, InstructionInfoTestCase testCase) { var decoder = CreateDecoder(bitness, hexBytes); var instr = decoder.Decode(); Assert.Equal(code, instr.Code); Assert.Equal(testCase.StackPointerIncrement, instr.StackPointerIncrement); var info = instr.GetInfo(); Assert.Equal(testCase.Encoding, info.Encoding); Assert.Equal(testCase.CpuidFeature, info.CpuidFeature); 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.Privileged, info.Privileged); Assert.Equal(testCase.ProtectedMode, info.ProtectedMode); Assert.Equal(testCase.StackInstruction, info.StackInstruction); Assert.Equal(testCase.SaveRestoreInstruction, info.SaveRestoreInstruction); 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( 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)); Assert.Equal(info.GetUsedMemory(), instr.GetUsedMemory(), UsedMemoryEqualityComparer.Instance); Assert.Equal(info.GetUsedRegisters(), instr.GetUsedRegisters(), UsedRegisterEqualityComparer.Instance); const int MAX_OP_COUNT = 4; Debug.Assert(instr.OpCount <= MAX_OP_COUNT); for (int i = 0; i < instr.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; default: throw new InvalidOperationException(); } } for (int i = instr.OpCount; i < MAX_OP_COUNT; 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(ref instr); CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: true); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoMemoryUsage); CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: false); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoRegisterUsage); CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: true); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoRegisterUsage | InstructionInfoOptions.NoMemoryUsage); CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: false); Assert.Equal(info.Encoding, instr.Code.Encoding()); var cf = instr.Code.CpuidFeature(); if (cf == CpuidFeature.AVX && instr.Op1Kind == OpKind.Register && (code == Code.VEX_Vbroadcastss_VX_WX || code == Code.VEX_Vbroadcastss_VY_WX || code == Code.VEX_Vbroadcastsd_VY_WX)) { cf = CpuidFeature.AVX2; } Assert.Equal(info.CpuidFeature, cf); Assert.Equal(info.FlowControl, instr.Code.FlowControl()); Assert.Equal(info.ProtectedMode, instr.Code.ProtectedMode()); Assert.Equal(info.Privileged, instr.Code.Privileged()); Assert.Equal(info.StackInstruction, instr.Code.StackInstruction()); Assert.Equal(info.SaveRestoreInstruction, instr.Code.SaveRestoreInstruction()); Assert.Equal(info.Encoding, instr.Encoding); Assert.Equal(info.CpuidFeature, instr.CpuidFeature); Assert.Equal(info.FlowControl, instr.FlowControl); Assert.Equal(info.ProtectedMode, instr.ProtectedMode); Assert.Equal(info.Privileged, instr.Privileged); Assert.Equal(info.StackInstruction, instr.StackInstruction); Assert.Equal(info.SaveRestoreInstruction, instr.SaveRestoreInstruction); Assert.Equal(info.RflagsRead, instr.RflagsRead); Assert.Equal(info.RflagsWritten, instr.RflagsWritten); Assert.Equal(info.RflagsCleared, instr.RflagsCleared); Assert.Equal(info.RflagsSet, instr.RflagsSet); Assert.Equal(info.RflagsUndefined, instr.RflagsUndefined); Assert.Equal(info.RflagsModified, instr.RflagsModified); }
protected void TestInstructionInfo(int bitness, string hexBytes, Code code, DecoderOptions options, int lineNo, InstructionInfoTestCase testCase) { var codeBytes = HexUtils.ToByteArray(hexBytes); Instruction instr; if (bitness == 16 && code == Code.Popw_CS && hexBytes == "0F") { instr = default; instr.Code = Code.Popw_CS; instr.Op0Kind = OpKind.Register; instr.Op0Register = Register.CS; instr.CodeSize = CodeSize.Code16; instr.ByteLength = 1; } else if (code >= Code.DeclareByte) { instr = default; instr.Code = code; instr.DeclareDataCount = 1; Assert.Equal(64, bitness); instr.CodeSize = CodeSize.Code64; switch (code) { case Code.DeclareByte: Assert.Equal("66", hexBytes); instr.SetDeclareByteValue(0, 0x66); break; case Code.DeclareWord: Assert.Equal("6644", hexBytes); instr.SetDeclareWordValue(0, 0x4466); break; case Code.DeclareDword: Assert.Equal("664422EE", hexBytes); instr.SetDeclareDwordValue(0, 0xEE224466); break; case Code.DeclareQword: Assert.Equal("664422EE12345678", hexBytes); instr.SetDeclareQwordValue(0, 0x78563412EE224466); break; default: throw new InvalidOperationException(); } } else { var decoder = CreateDecoder(bitness, codeBytes, options); instr = decoder.Decode(); if (codeBytes.Length != 1 && codeBytes[0] == 0x9B && instr.ByteLength == 1) { instr = decoder.Decode(); switch (instr.Code) { case Code.Fnstenv_m14byte: instr.Code = Code.Fstenv_m14byte; break; case Code.Fnstenv_m28byte: instr.Code = Code.Fstenv_m28byte; break; case Code.Fnstcw_m16: instr.Code = Code.Fstcw_m16; break; case Code.Fneni: instr.Code = Code.Feni; break; case Code.Fndisi: instr.Code = Code.Fdisi; break; case Code.Fnclex: instr.Code = Code.Fclex; break; case Code.Fninit: instr.Code = Code.Finit; break; case Code.Fnsetpm: instr.Code = Code.Fsetpm; break; case Code.Fnsave_m94byte: instr.Code = Code.Fsave_m94byte; break; case Code.Fnsave_m108byte: instr.Code = Code.Fsave_m108byte; break; case Code.Fnstsw_m16: instr.Code = Code.Fstsw_m16; break; case Code.Fnstsw_AX: instr.Code = Code.Fstsw_AX; break; default: Assert.False(true, $"Invalid FPU instr Code value: {instr.Code}"); break; } } } Assert.Equal(code, instr.Code); Assert.Equal(testCase.StackPointerIncrement, instr.StackPointerIncrement); var info = instr.GetInfo(); 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)); Assert.Equal(info.GetUsedMemory(), instr.GetUsedMemory(), UsedMemoryEqualityComparer.Instance); Assert.Equal(info.GetUsedRegisters(), instr.GetUsedRegisters(), UsedRegisterEqualityComparer.Instance); Debug.Assert(Iced.Intel.DecoderConstants.MaxOpCount == 5); Debug.Assert(instr.OpCount <= Iced.Intel.DecoderConstants.MaxOpCount); for (int i = 0; i < instr.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 = instr.OpCount; i < Iced.Intel.DecoderConstants.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(ref instr); CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: true); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoMemoryUsage); CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: false); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoRegisterUsage); CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: true); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoRegisterUsage | InstructionInfoOptions.NoMemoryUsage); CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: false); Assert.Equal(info.Encoding, instr.Code.Encoding()); var cf = instr.Code.CpuidFeatures(); if (cf.Length == 1 && cf[0] == CpuidFeature.AVX && instr.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, instr.Code.FlowControl()); Assert.Equal(info.IsProtectedMode, instr.Code.IsProtectedMode()); Assert.Equal(info.IsPrivileged, instr.Code.IsPrivileged()); Assert.Equal(info.IsStackInstruction, instr.Code.IsStackInstruction()); Assert.Equal(info.IsSaveRestoreInstruction, instr.Code.IsSaveRestoreInstruction()); Assert.Equal(info.Encoding, instr.Encoding); Assert.Equal(info.CpuidFeatures, instr.CpuidFeatures); Assert.Equal(info.FlowControl, instr.FlowControl); Assert.Equal(info.IsProtectedMode, instr.IsProtectedMode); Assert.Equal(info.IsPrivileged, instr.IsPrivileged); Assert.Equal(info.IsStackInstruction, instr.IsStackInstruction); Assert.Equal(info.IsSaveRestoreInstruction, instr.IsSaveRestoreInstruction); Assert.Equal(info.RflagsRead, instr.RflagsRead); Assert.Equal(info.RflagsWritten, instr.RflagsWritten); Assert.Equal(info.RflagsCleared, instr.RflagsCleared); Assert.Equal(info.RflagsSet, instr.RflagsSet); Assert.Equal(info.RflagsUndefined, instr.RflagsUndefined); Assert.Equal(info.RflagsModified, instr.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 <= Register.YMM0 + InstructionInfoConstants.VMM_count - 1) { index = reg - Register.YMM0; if (hash.Contains(Register.ZMM0 + index)) { continue; } } else if (Register.XMM0 <= reg && reg <= Register.XMM0 + InstructionInfoConstants.VMM_count - 1) { 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); }
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); }
protected void TestInstructionInfo(int bitness, string hexBytes, Code code, DecoderOptions options, int lineNo, InstructionInfoTestCase testCase) { var codeBytes = HexUtils.ToByteArray(hexBytes); Instruction instr; if (bitness == 16 && code == Code.Popw_CS && hexBytes == "0F") { instr = default; instr.Code = Code.Popw_CS; instr.Op0Kind = OpKind.Register; instr.Op0Register = Register.CS; instr.CodeSize = CodeSize.Code16; instr.ByteLength = 1; } else { var decoder = CreateDecoder(bitness, codeBytes, options); instr = decoder.Decode(); if (codeBytes.Length != 1 && codeBytes[0] == 0x9B && instr.ByteLength == 1) { instr = decoder.Decode(); switch (instr.Code) { case Code.Fnstenv_m14byte: instr.Code = Code.Fstenv_m14byte; break; case Code.Fnstenv_m28byte: instr.Code = Code.Fstenv_m28byte; break; case Code.Fnstcw_m16: instr.Code = Code.Fstcw_m16; break; case Code.Fneni: instr.Code = Code.Feni; break; case Code.Fndisi: instr.Code = Code.Fdisi; break; case Code.Fnclex: instr.Code = Code.Fclex; break; case Code.Fninit: instr.Code = Code.Finit; break; case Code.Fnsetpm: instr.Code = Code.Fsetpm; break; case Code.Fnsave_m94byte: instr.Code = Code.Fsave_m94byte; break; case Code.Fnsave_m108byte: instr.Code = Code.Fsave_m108byte; break; case Code.Fnstsw_m16: instr.Code = Code.Fstsw_m16; break; case Code.Fnstsw_AX: instr.Code = Code.Fstsw_AX; break; default: Assert.False(true, $"Invalid FPU instr Code value: {instr.Code}"); break; } } } Assert.Equal(code, instr.Code); Assert.Equal(testCase.StackPointerIncrement, instr.StackPointerIncrement); var info = instr.GetInfo(); Assert.Equal(testCase.Encoding, info.Encoding); Assert.Equal(testCase.CpuidFeature, info.CpuidFeature); 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.Privileged, info.Privileged); Assert.Equal(testCase.ProtectedMode, info.ProtectedMode); Assert.Equal(testCase.StackInstruction, info.StackInstruction); Assert.Equal(testCase.SaveRestoreInstruction, info.SaveRestoreInstruction); 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)); Assert.Equal(info.GetUsedMemory(), instr.GetUsedMemory(), UsedMemoryEqualityComparer.Instance); Assert.Equal(info.GetUsedRegisters(), instr.GetUsedRegisters(), UsedRegisterEqualityComparer.Instance); Debug.Assert(Iced.Intel.DecoderConstants.MaxOpCount == 5); Debug.Assert(instr.OpCount <= Iced.Intel.DecoderConstants.MaxOpCount); for (int i = 0; i < instr.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 = instr.OpCount; i < Iced.Intel.DecoderConstants.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(ref instr); CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: true); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoMemoryUsage); CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: false); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoRegisterUsage); CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: true); info2 = new InstructionInfoFactory().GetInfo(ref instr, InstructionInfoOptions.NoRegisterUsage | InstructionInfoOptions.NoMemoryUsage); CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: false); Assert.Equal(info.Encoding, instr.Code.Encoding()); var cf = instr.Code.CpuidFeature(); if (cf == CpuidFeature.AVX && instr.Op1Kind == OpKind.Register && (code == Code.VEX_Vbroadcastss_xmm_xmmm32 || code == Code.VEX_Vbroadcastss_ymm_xmmm32 || code == Code.VEX_Vbroadcastsd_ymm_xmmm64)) { cf = CpuidFeature.AVX2; } Assert.Equal(info.CpuidFeature, cf); Assert.Equal(info.FlowControl, instr.Code.FlowControl()); Assert.Equal(info.ProtectedMode, instr.Code.ProtectedMode()); Assert.Equal(info.Privileged, instr.Code.Privileged()); Assert.Equal(info.StackInstruction, instr.Code.StackInstruction()); Assert.Equal(info.SaveRestoreInstruction, instr.Code.SaveRestoreInstruction()); Assert.Equal(info.Encoding, instr.Encoding); Assert.Equal(info.CpuidFeature, instr.CpuidFeature); Assert.Equal(info.FlowControl, instr.FlowControl); Assert.Equal(info.ProtectedMode, instr.ProtectedMode); Assert.Equal(info.Privileged, instr.Privileged); Assert.Equal(info.StackInstruction, instr.StackInstruction); Assert.Equal(info.SaveRestoreInstruction, instr.SaveRestoreInstruction); Assert.Equal(info.RflagsRead, instr.RflagsRead); Assert.Equal(info.RflagsWritten, instr.RflagsWritten); Assert.Equal(info.RflagsCleared, instr.RflagsCleared); Assert.Equal(info.RflagsSet, instr.RflagsSet); Assert.Equal(info.RflagsUndefined, instr.RflagsUndefined); Assert.Equal(info.RflagsModified, instr.RflagsModified); }