private bool AdvanceTo(InstructionDecodingState newState, byte substate = 0) { Contract.Requires(newState > State); this.state = newState; this.substate = substate; return newState != InstructionDecodingState.Completed && newState != InstructionDecodingState.Error; }
public bool Feed(byte @byte) { switch (State) { case InstructionDecodingState.Initial: case InstructionDecodingState.ExpectPrefixOrOpcode: { state = InstructionDecodingState.ExpectPrefixOrOpcode; // Check if we have a legacy prefix var legacyPrefix = LegacyPrefixEnum.TryFromEncodingByte(@byte); if (legacyPrefix.HasValue) { if (builder.LegacyPrefixes.ContainsFromGroup(legacyPrefix.Value.GetGroup())) return AdvanceToError(InstructionDecodingError.DuplicateLegacyPrefixGroup); builder.LegacyPrefixes = ImmutableLegacyPrefixList.Add(builder.LegacyPrefixes, legacyPrefix.Value); return true; } var xexType = XexEnums.GetTypeFromByte(@byte); if (context == CodeContext.SixtyFourBit && xexType == XexType.RexAndEscapes) { builder.Xex = new Xex((Rex)@byte); return AdvanceTo(InstructionDecodingState.ExpectOpcode); } if (xexType >= XexType.Vex2) { if (context.IsRealOrVirtual8086()) return AdvanceToError(InstructionDecodingError.VexIn8086Mode); int remainingBytes = xexType.GetMinSizeInBytes() - 1; // Hack: We accumulate the xex bytes, but make sure we end up with the type in the most significant byte accumulator = @byte | ((uint)xexType << (24 - remainingBytes * 8)); return AdvanceTo(InstructionDecodingState.ExpectXexByte, substate: (byte)remainingBytes); } goto case InstructionDecodingState.ExpectOpcode; } case InstructionDecodingState.ExpectXexByte: { if ((accumulator >> 24) == (uint)Vex3Xop.FirstByte_Xop && (@byte & 0x04) == 0) { // What we just read was not a XOP, but a POP reg/mem builder.Xex = default(Xex); builder.OpcodeByte = (byte)Vex3Xop.FirstByte_Xop; builder.ModRM = (ModRM)@byte; state = InstructionDecodingState.ExpectModRM; return AdvanceToSibOrFurther(); } // Accumulate xex bytes accumulator = (accumulator << 8) | @byte; --substate; if (substate > 0) return true; // More bytes to read // Thanks to our hack, we always have the type in the most significant byte now var xexType = (XexType)(accumulator >> 24); switch (xexType) { case XexType.Vex2: builder.Xex = new Xex((Vex2)accumulator); break; case XexType.Vex3: case XexType.Xop: builder.Xex = new Xex((Vex3Xop)accumulator); break; case XexType.EVex: builder.Xex = new Xex((EVex)accumulator); break; default: throw new UnreachableException(); } accumulator = 0; return AdvanceTo(InstructionDecodingState.ExpectOpcode); } case InstructionDecodingState.ExpectOpcode: { if (builder.Xex.Type.AllowsEscapes()) { if (builder.Xex.OpcodeMap == OpcodeMap.Default && @byte == 0x0F) { builder.Xex = builder.Xex.WithOpcodeMap(OpcodeMap.Escape0F); return true; } if (builder.Xex.OpcodeMap == OpcodeMap.Escape0F) { switch (@byte) { case 0x38: builder.Xex = builder.Xex.WithOpcodeMap(OpcodeMap.Escape0F38); return true; case 0x3A: builder.Xex = builder.Xex.WithOpcodeMap(OpcodeMap.Escape0F3A); return true; default: break; } } } builder.OpcodeByte = @byte; bool hasModRM; int immediateSizeInBytes; tag = lookup.TryLookup(context, builder.LegacyPrefixes, builder.Xex, builder.OpcodeByte, out hasModRM, out immediateSizeInBytes); if (tag == null) return AdvanceToError(InstructionDecodingError.UnknownOpcode); builder.ImmediateSizeInBytes = immediateSizeInBytes; return hasModRM ? AdvanceTo(InstructionDecodingState.ExpectModRM) : AdvanceToImmediateOrEnd(); } case InstructionDecodingState.ExpectModRM: { builder.ModRM = (ModRM)@byte; return AdvanceToSibOrFurther(); } case InstructionDecodingState.ExpectSib: { builder.Sib = (Sib)@byte; return AdvanceToDisplacementOrFurther(); } case InstructionDecodingState.ExpectDisplacement: { accumulator |= (uint)@byte << (substate * 8); substate++; var displacementSize = builder.ModRM.Value.GetDisplacementSize( builder.Sib.GetValueOrDefault(), GetEffectiveAddressSize()); if (substate < displacementSize.InBytes()) return true; // More bytes to come // Sign-extend if (displacementSize == DisplacementSize._8) builder.Displacement = unchecked((sbyte)accumulator); else if (displacementSize == DisplacementSize._16) builder.Displacement = unchecked((short)accumulator); else if (displacementSize == DisplacementSize._32) builder.Displacement = unchecked((int)accumulator); return AdvanceToImmediateOrEnd(); } case InstructionDecodingState.ExpectImmediate: { builder.Immediate |= (ulong)@byte << (substate * 8); substate++; if (substate < builder.ImmediateSizeInBytes) return true; // More bytes to come return AdvanceTo(InstructionDecodingState.Completed); } default: throw new InvalidOperationException("Invalid decoding state."); } }
/// <summary> /// Resets this <see cref="InstructionDecoder"/> to the <see cref="InstructionDecodingState.Initial"/> state. /// </summary> public void Reset() { if (state == InstructionDecodingState.Initial) return; state = InstructionDecodingState.Initial; substate = 0; accumulator = 0; builder.Clear(); builder.DefaultAddressSize = context.GetDefaultAddressSize(); tag = null; }