namespace X86Disassembler.X86;
using Handlers;
///
/// Decodes x86 instructions from a byte buffer
///
public class InstructionDecoder
{
// The buffer containing the code to decode
private readonly byte[] _codeBuffer;
// The length of the buffer
private readonly int _length;
// The current position in the buffer
private int _position;
// The instruction handler factory
private readonly InstructionHandlerFactory _handlerFactory;
// Specialized decoders
private readonly PrefixDecoder _prefixDecoder;
private readonly ModRMDecoder _modRMDecoder;
///
/// Initializes a new instance of the InstructionDecoder class
///
/// The buffer containing the code to decode
/// The length of the buffer
public InstructionDecoder(byte[] codeBuffer, int length)
{
_codeBuffer = codeBuffer;
_length = length;
_position = 0;
// Create specialized decoders
_prefixDecoder = new PrefixDecoder();
_modRMDecoder = new ModRMDecoder(codeBuffer, this, length);
// Create the instruction handler factory
_handlerFactory = new InstructionHandlerFactory(_codeBuffer, this, _length);
}
///
/// Decodes an instruction at the current position
///
/// The decoded instruction, or null if the decoding failed
public Instruction? DecodeInstruction()
{
if (_position >= _length)
{
return null;
}
// Reset prefix flags
_prefixDecoder.Reset();
// Save the start position of the instruction
int startPosition = _position;
// Create a new instruction
Instruction instruction = new Instruction
{
Address = (uint)startPosition,
};
// Handle prefixes
while (_position < _length)
{
byte prefix = _codeBuffer[_position];
if (_prefixDecoder.DecodePrefix(prefix))
{
_position++;
}
else
{
break;
}
}
if (_position >= _length)
{
// If we reached the end of the buffer while processing prefixes,
// create an instruction with just the prefix information
if (_prefixDecoder.HasSegmentOverridePrefix())
{
instruction.Mnemonic = _prefixDecoder.GetSegmentOverride();
instruction.Operands = "";
// Set the raw bytes
int length = _position - startPosition;
instruction.RawBytes = new byte[length];
Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, length);
return instruction;
}
return null;
}
// Read the opcode
byte opcode = _codeBuffer[_position++];
// Get a handler for the opcode
var handler = _handlerFactory.GetHandler(opcode);
bool handlerSuccess = false;
// Try to decode with a handler first
if (handler != null)
{
// Store the current segment override state
bool hasSegmentOverride = _prefixDecoder.HasSegmentOverridePrefix();
string segmentOverride = _prefixDecoder.GetSegmentOverride();
// Decode the instruction
handlerSuccess = handler.Decode(opcode, instruction);
// Apply segment override prefix to the operands if needed
if (handlerSuccess && hasSegmentOverride)
{
instruction.Operands = _prefixDecoder.ApplySegmentOverride(instruction.Operands);
}
}
// If no handler is found or decoding fails, create a default instruction
if (!handlerSuccess)
{
instruction.Mnemonic = OpcodeMap.GetMnemonic(opcode);
instruction.Operands = "??";
}
// Apply REP/REPNE prefix to the mnemonic if needed
instruction.Mnemonic = _prefixDecoder.ApplyRepPrefix(instruction.Mnemonic);
// Set the raw bytes
int bytesLength = _position - startPosition;
instruction.RawBytes = new byte[bytesLength];
Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, bytesLength);
return instruction;
}
///
/// Gets the current position in the buffer
///
/// The current position
public int GetPosition()
{
return _position;
}
///
/// Sets the current position in the buffer
///
/// The new position
public void SetPosition(int position)
{
_position = position;
}
///
/// Checks if the operand size prefix is present
///
/// True if the operand size prefix is present
public bool HasOperandSizePrefix()
{
return _prefixDecoder.HasOperandSizePrefix();
}
///
/// Checks if the address size prefix is present
///
/// True if the address size prefix is present
public bool HasAddressSizePrefix()
{
return _prefixDecoder.HasAddressSizePrefix();
}
///
/// Checks if a segment override prefix is present
///
/// True if a segment override prefix is present
public bool HasSegmentOverridePrefix()
{
return _prefixDecoder.HasSegmentOverridePrefix();
}
///
/// Gets the segment override prefix
///
/// The segment override prefix, or an empty string if none is present
public string GetSegmentOverride()
{
return _prefixDecoder.GetSegmentOverride();
}
///
/// Checks if the LOCK prefix is present
///
/// True if the LOCK prefix is present
public bool HasLockPrefix()
{
return _prefixDecoder.HasLockPrefix();
}
///
/// Checks if the REP/REPNE prefix is present
///
/// True if the REP/REPNE prefix is present
public bool HasRepPrefix()
{
return _prefixDecoder.HasRepPrefix();
}
///
/// Checks if the instruction has an operand size override prefix (0x66)
///
/// True if the instruction has an operand size override prefix
public bool HasOperandSizeOverridePrefix()
{
return _prefixDecoder.HasOperandSizePrefix();
}
///
/// Reads a byte from the buffer and advances the position
///
/// The byte read
public byte ReadByte()
{
if (_position >= _length)
{
return 0;
}
return _codeBuffer[_position++];
}
///
/// Reads a 16-bit value from the buffer and advances the position
///
/// The 16-bit value read
public ushort ReadUInt16()
{
if (_position + 1 >= _length)
{
return 0;
}
ushort value = (ushort)(_codeBuffer[_position] | (_codeBuffer[_position + 1] << 8));
_position += 2;
return value;
}
///
/// Reads a 32-bit value from the buffer and advances the position
///
/// The 32-bit value read
public uint ReadUInt32()
{
if (_position + 3 >= _length)
{
return 0;
}
uint value = (uint)(_codeBuffer[_position] |
(_codeBuffer[_position + 1] << 8) |
(_codeBuffer[_position + 2] << 16) |
(_codeBuffer[_position + 3] << 24));
_position += 4;
return value;
}
}