/*
Copyright (C) 2018-2019 de4dot@gmail.com
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if !NO_INSTR_INFO
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Iced.Intel.InstructionInfoInternal;
namespace Iced.Intel {
///
/// Contains information about an instruction, eg. read/written registers, read/written RFLAGS bits, CPUID feature bit, etc
///
public struct InstructionInfo {
internal UsedRegister[] usedRegisters;
internal UsedMemory[] usedMemoryLocations;
internal ushort usedRegistersLength;
internal ushort usedMemoryLocationsLength;
internal ushort opMaskFlags;
internal byte cpuidFeature;
internal byte flowControl;
internal byte encoding;
internal byte rflagsInfo;
internal byte flags;
[Flags]
internal enum OpMaskFlags : ushort {
OpAccessMask = 7,
Op1AccessShift = 3,
Op2AccessShift = 6,
Op3AccessShift = 9,
Op4AccessShift = 12,
}
[Flags]
internal enum Flags : byte {
SaveRestore = 0x01,
StackInstruction = 0x02,
ProtectedMode = 0x04,
Privileged = 0x08,
}
///
/// Gets a struct iterator that returns all read and written registers. There are some exceptions, this method doesn't return all used registers:
///
/// 1) If is true, or
///
/// 2) If it's a or instruction (call, sysenter, int n etc), it can read and write any register (including RFLAGS).
///
///
public readonly UsedRegisterIterator GetUsedRegisters() => new UsedRegisterIterator(usedRegisters, usedRegistersLength);
///
/// Gets a struct iterator that returns all read and written memory locations
///
///
public readonly UsedMemoryIterator GetUsedMemory() => new UsedMemoryIterator(usedMemoryLocations, usedMemoryLocationsLength);
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
public struct UsedRegisterIterator : IEnumerable, IEnumerator {
readonly UsedRegister[] usedRegisters;
readonly uint length;
int index;
internal UsedRegisterIterator(UsedRegister[] usedRegisters, uint length) {
this.usedRegisters = usedRegisters;
this.length = length;
index = -1;
}
public UsedRegisterIterator GetEnumerator() => this;
public UsedRegister Current => usedRegisters[index];
public bool MoveNext() {
index++;
return (uint)index < length;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
UsedRegister IEnumerator.Current => Current;
object IEnumerator.Current => Current;
bool IEnumerator.MoveNext() => MoveNext();
void IEnumerator.Reset() => throw new NotSupportedException();
public void Dispose() { }
}
public struct UsedMemoryIterator : IEnumerable, IEnumerator {
readonly UsedMemory[] usedMemoryLocations;
readonly uint length;
int index;
internal UsedMemoryIterator(UsedMemory[] usedMemoryLocations, uint length) {
this.usedMemoryLocations = usedMemoryLocations;
this.length = length;
index = -1;
}
public UsedMemoryIterator GetEnumerator() => this;
public UsedMemory Current => usedMemoryLocations[index];
public bool MoveNext() {
index++;
return (uint)index < length;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
UsedMemory IEnumerator.Current => Current;
object IEnumerator.Current => Current;
bool IEnumerator.MoveNext() => MoveNext();
void IEnumerator.Reset() => throw new NotSupportedException();
public void Dispose() { }
}
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
///
/// true if the instruction isn't available in real mode or virtual 8086 mode
///
[Obsolete("Use " + nameof(IsProtectedMode) + " instead", true)]
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly bool ProtectedMode => IsProtectedMode;
///
/// true if the instruction isn't available in real mode or virtual 8086 mode
///
public readonly bool IsProtectedMode => (flags & (uint)Flags.ProtectedMode) != 0;
///
/// true if this is a privileged instruction
///
[Obsolete("Use " + nameof(IsPrivileged) + " instead", true)]
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly bool Privileged => IsPrivileged;
///
/// true if this is a privileged instruction
///
public readonly bool IsPrivileged => (flags & (uint)Flags.Privileged) != 0;
///
/// true if this is an instruction that implicitly uses the stack pointer (SP/ESP/RSP), eg. call, push, pop, ret, etc.
/// See also
///
[Obsolete("Use " + nameof(IsStackInstruction) + " instead", true)]
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly bool StackInstruction => IsStackInstruction;
///
/// true if this is an instruction that implicitly uses the stack pointer (SP/ESP/RSP), eg. call, push, pop, ret, etc.
/// See also
///
public readonly bool IsStackInstruction => (flags & (uint)Flags.StackInstruction) != 0;
///
/// true if it's an instruction that saves or restores too many registers (eg. fxrstor, xsave, etc).
/// won't return all read/written registers.
///
[Obsolete("Use " + nameof(IsSaveRestoreInstruction) + " instead", true)]
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly bool SaveRestoreInstruction => IsSaveRestoreInstruction;
///
/// true if it's an instruction that saves or restores too many registers (eg. fxrstor, xsave, etc).
/// won't return all read/written registers.
///
public readonly bool IsSaveRestoreInstruction => (flags & (uint)Flags.SaveRestore) != 0;
///
/// Instruction encoding, eg. legacy, VEX, EVEX, ...
///
public readonly EncodingKind Encoding => (EncodingKind)encoding;
///
/// CPU or CPUID feature flag
///
[Obsolete("Use " + nameof(CpuidFeatures) + " instead", true)]
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly CpuidFeature CpuidFeature => CpuidFeatures[0];
///
/// Gets the CPU or CPUID feature flags
///
public readonly CpuidFeature[] CpuidFeatures => CpuidFeatureInternalData.ToCpuidFeatures[cpuidFeature];
///
/// Flow control info
///
public readonly FlowControl FlowControl => (FlowControl)flowControl;
///
/// Operand #0 access
///
public readonly OpAccess Op0Access => (OpAccess)(opMaskFlags & (uint)OpMaskFlags.OpAccessMask);
///
/// Operand #1 access
///
public readonly OpAccess Op1Access => (OpAccess)(((uint)opMaskFlags >> (int)OpMaskFlags.Op1AccessShift) & (uint)OpMaskFlags.OpAccessMask);
///
/// Operand #2 access
///
public readonly OpAccess Op2Access => (OpAccess)(((uint)opMaskFlags >> (int)OpMaskFlags.Op2AccessShift) & (uint)OpMaskFlags.OpAccessMask);
///
/// Operand #3 access
///
public readonly OpAccess Op3Access => (OpAccess)(((uint)opMaskFlags >> (int)OpMaskFlags.Op3AccessShift) & (uint)OpMaskFlags.OpAccessMask);
///
/// Operand #4 access
///
public readonly OpAccess Op4Access => (OpAccess)(((uint)opMaskFlags >> (int)OpMaskFlags.Op4AccessShift) & (uint)OpMaskFlags.OpAccessMask);
///
/// Gets operand access
///
/// Operand number, 0-4
///
public readonly OpAccess GetOpAccess(int operand) {
switch (operand) {
case 0: return Op0Access;
case 1: return Op1Access;
case 2: return Op2Access;
case 3: return Op3Access;
case 4: return Op4Access;
default:
ThrowHelper.ThrowArgumentOutOfRangeException_operand();
return 0;
}
}
///
/// All flags that are read by the CPU when executing the instruction
///
public readonly RflagsBits RflagsRead => (RflagsBits)RflagsInfoConstants.flagsRead[rflagsInfo];
///
/// All flags that are written by the CPU, except those flags that are known to be undefined, always set or always cleared. See also
///
public readonly RflagsBits RflagsWritten => (RflagsBits)RflagsInfoConstants.flagsWritten[rflagsInfo];
///
/// All flags that are always cleared by the CPU
///
public readonly RflagsBits RflagsCleared => (RflagsBits)RflagsInfoConstants.flagsCleared[rflagsInfo];
///
/// All flags that are always set by the CPU
///
public readonly RflagsBits RflagsSet => (RflagsBits)RflagsInfoConstants.flagsSet[rflagsInfo];
///
/// All flags that are undefined after executing the instruction
///
public readonly RflagsBits RflagsUndefined => (RflagsBits)RflagsInfoConstants.flagsUndefined[rflagsInfo];
///
/// All flags that are modified by the CPU. This is + + +
///
public readonly RflagsBits RflagsModified => (RflagsBits)RflagsInfoConstants.flagsModified[rflagsInfo];
}
}
#endif