/*++

Copyright (c) 2012 Minoca Corp.

    This file is licensed under the terms of the GNU General Public License
    version 3. Alternative licensing terms are available. Contact
    info@minocacorp.com for details. See the LICENSE file at the root of this
    project for complete licensing information.

Module Name:

    x86dis.c

Abstract:

    This module contains routines for disassembling x86 binary code.

Author:

    Evan Green 21-Jun-2012

Environment:

    Debugging client

--*/

//
// ------------------------------------------------------------------- Includes
//

#include <minoca/lib/types.h>
#include "disasm.h"

#include <stdio.h>
#include <string.h>
#include <assert.h>

//
// --------------------------------------------------------------------- Macros
//

//
// Define macros to get at the pieces of the ModRM byte. This also adds the
// extra bit extended by the REX byte, which if not present is a no-op, as it
// will be zero.
//

#define X86_MODRM_MOD(_ModRm) (((_ModRm) & X86_MOD_MASK) >> X86_MOD_SHIFT)
#define X86_MODRM_REG(_Instruction, _ModRm) \
    ((((_ModRm) & X86_REG_MASK) >> X86_REG_SHIFT) | \
     (((_Instruction)->Rex & X64_REX_R) << 1))

#define X86_MODRM_RM(_Instruction, _ModRm) \
    ((((_ModRm) & X86_RM_MASK) >> X86_RM_SHIFT) | \
     (((_Instruction)->Rex & X64_REX_B) << 3))

//
// Define macros to get the fields of the Scale-Index-Base byte, extending
// index and base with the REX bits.
//

#define X86_SIB_BASE(_Instruction) \
    ((((_Instruction)->Sib & X86_BASE_MASK) >> X86_BASE_SHIFT) | \
     (((_Instruction)->Rex & X64_REX_B) << 3))

#define X86_SIB_INDEX(_Instruction) \
    ((((_Instruction)->Sib & X86_INDEX_MASK) >> X86_INDEX_SHIFT) | \
     (((_Instruction)->Rex & X64_REX_X) << 2))

#define X86_SIB_SCALE(_Instruction) \
    (1 << (((_Instruction)->Sib & X86_SCALE_MASK) >> X86_SCALE_SHIFT))

//
// This macro un-extends a register, just getting the 3-bit value.
//

#define X86_BASIC_REG(_Reg) ((_Reg) & 0x7)

//
// This macro creates a fake REX prefix from a VEX byte.
//

#define X64_VEX_TO_REX(_Vex, _VexMap) \
    (X64_REX_VALUE | ((~(_Vex) >> 5) & 0x7) | (((_VexMap) >> 4) & X64_REX_W))

//
// This macro gets the V register out of the VEX byte.
//

#define X64_VEX_V(_Vex) ((~(_Vex) >> 3) & 0x0F)

//
// ---------------------------------------------------------------- Definitions
//

//
// Define the meanings of some of size characters used in the encoding table.
//

#define X86_WIDTH_BYTE 'b'
#define X86_WIDTH_WORD 'w'
#define X86_WIDTH_LONG 'l'
#define X86_WIDTH_LONGLONG 'q'
#define X86_WIDTH_OWORD 'o'
#define X86_WIDTH_YWORD 'y'
#define X86_WIDTH_ZWORD 'z'
#define X86_FLOATING_POINT_REGISTER 'f'
#define X86_CONTROL_REGISTER 'C'
#define X86_DEBUG_REGISTER 'D'
#define X86_SEGMENT_REGISTER 'S'

//
// Define the internal bitfields of the ModR/M and SIB byte.
//

#define X86_MOD_MASK 0xC0
#define X86_REG_MASK 0x38
#define X86_RM_MASK 0x07
#define X86_MOD_SHIFT 6
#define X86_REG_SHIFT 3
#define X86_RM_SHIFT 0
#define X86_SCALE_MASK 0xC0
#define X86_INDEX_MASK 0x38
#define X86_BASE_MASK 0x07
#define X86_SCALE_SHIFT 6
#define X86_INDEX_SHIFT 3
#define X86_BASE_SHIFT 0

//
// Define the X64 REX bits.
//

//
// This bit indicates a 64-bit operand size.
//

#define X64_REX_W 0x08

//
// This bit is an extension to the ModRM reg field.
//

#define X64_REX_R 0x04

//
// This bit is an extension to the SIB index field.
//

#define X64_REX_X 0x02

//
// This bit is an extension to the ModRM rm field, or SIB base field.
//

#define X64_REX_B 0x01

//
// This bit is set to indicate 256 bit registers are in use.
//

#define X64_VEX_L 0x04

//
// This bit is called W/E, and is often the equivalent of the REX W bit.
//

#define X64_VEX_W 0x80

//
// Define some of the prefixes that can come at the beginning of an instruction.
//

#define X86_MAX_PREFIXES 5
#define X86_OPERAND_OVERRIDE 0x66
#define X86_ADDRESS_OVERRIDE 0x67
#define X86_ESCAPE_OPCODE 0x0F
#define X86_PREFIX_LOCK 0xF0
#define X86_PREFIX_REPN 0xF2
#define X86_PREFIX_REP 0xF3
#define X86_PREFIX_CS 0x2E
#define X86_PREFIX_DS 0x3E
#define X86_PREFIX_ES 0x26
#define X86_PREFIX_FS 0x64
#define X86_PREFIX_GS 0x65
#define X86_PREFIX_SS 0x36

#define X64_REX_MASK 0xF0
#define X64_REX_VALUE 0x40

#define X64_XOP 0x8F
#define X64_VEX3 0xC4
#define X64_VEX2 0xC5

#define X64_VEX2_MAP_SELECT 0x61

#define X86_INVALID_GROUP 99

//
// Define the sizes of the register name arrays.
//

#define X86_REGISTER_NAME_COUNT 16

//
// Define the size of the working buffers.
//

#define X86_WORKING_BUFFER_SIZE 100

//
// Define some x87 floating point support definitions, constants used in
// decoding an x87 coprocessor instruction.
//

#define X87_ESCAPE_OFFSET 0xD8
#define X87_FCOM_MASK 0xF8
#define X87_FCOM_OPCODE 0xD0
#define X87_D9_E0_OFFSET 0xE0
#define X87_DA_C0_MASK 0x38
#define X87_DA_CO_SHIFT 3
#define X87_FUCOMPP_OPCODE 0xE9
#define X87_DB_C0_MASK 0x38
#define X87_DB_C0_SHIFT 3
#define X87_DB_E0_INDEX 4
#define X87_DB_E0_MASK 0x7
#define X87_DF_C0_MASK 0x38
#define X87_DF_C0_SHIFT 3
#define X87_DF_E0_INDEX 4
#define X87_DF_E0_MASK 0x07
#define X87_DF_E0_COUNT 3

#define X87_REGISTER_TARGET "Rf"
#define X87_ST0_TARGET "!est"
#define X87_FLD_MNEMONIC "fld"
#define X87_FXCH_MNEMONIC "fxch"
#define X87_NOP_MNEMONIC "fnop"
#define X87_FSTP1_MNEMONIC "fstp1"
#define X87_FUCOMPP_MNEMONIC "fucompp"
#define X87_DF_E0_TARGET "!eax"

//
// ------------------------------------------------------ Data Type Definitions
//

/*++

Structure Description:

    This structure provides basic information about an instruction, including
    its mnemonic name, operand encodings, and additional parsing information.

Members:

    Mnemonic - Stores a pointer to the string containing the opcode's mnemonic.

    Target - Stores a pointer to a string describing the destination operand's
        encoding.

    Source - Stores a pointer to a string describing the source operand's
        encoding.

    Third - Stores a pointer to a string describing the third operand.

    Group - Stores the opcode group number. Some instructions require furthur
        decoding, the group number indicates that.

--*/

typedef struct _X86_INSTRUCTION_DEFINITION {
    PSTR Mnemonic;
    PSTR Target;
    PSTR Source;
    PSTR Third;
    INT Group;
} X86_INSTRUCTION_DEFINITION, *PX86_INSTRUCTION_DEFINITION;

/*++

Structure Description:

    This structure provides the mnemonic switch for an opcode group.

Members:

    Group - Stores the group number.

    Mnemonics - Stores the mnemonics for each opcode in the group.

--*/

typedef struct _X86_OPCODE_GROUP {
    INT Group;
    PSTR Mnemonics[8];
} X86_OPCODE_GROUP, *PX86_OPCODE_GROUP;

/*++

Structure Description:

    This structure stores information about an instructions mnemonics and
    encoding when an array index is wasteful for describing the actual opcode
    number.

Members:

    Prefix - Stores the specfic prefix value for which this instruction is
        valid.

    Opcode - Stores the opcode this definition defines.

    Instruction - Stores an array describing the mnemonics and encoding of the
        instruction.

--*/

typedef struct _X86_SPARSE_INSTRUCTION_DEFINITION {
    BYTE Prefix;
    BYTE Opcode;
    X86_INSTRUCTION_DEFINITION Instruction;
} X86_SPARSE_INSTRUCTION_DEFINITION, *PX86_SPARSE_INSTRUCTION_DEFINITION;

/*++

Structure Description:

    This structure stores all binary information about a decoded instruction.

Members:

    Language - Stores the machine language type being decoded. Valid values are
        x86 and x64.

    InstructionPointer - Stores the current instruction pointer, used for
        computing the operand address of RIP-relative addresses.

    Prefix - Stores up to 4 prefix bytes, which is the maximum number of
        allowed prefixes in x86 instructions.

    Opcode - Stores the first (and many times only) opcode byte.

    Opcode2 - Stores the second opcode byte, if necessary (as determined by the
        first opcode byte).

    ModRm - Stores the ModR/M byte of the instruction, if one exists. Bits 6-7
        describe the Mod part of the instruction, which can describe what sort
        of addressing/displacement is encoded in the instruction. Bits 5-3 hold
        the Reg data, which stores either a register number or additional
        decoding information for instruction groups. Bits 2-0 store the R/M
        byte, which either stores another register value or describes how the
        memory information is encoded.

    Sib - Stores the Scale/Index/Base byte of the opcode, if one exists.
        Addressing with an sib byte usually looks like (Base + index * 2^Scale),
        where Base and Index are both general registers. Bits 6-7 describe the
        scale, which is raised to the power of two (and can therefore describe a
        scale of 1, 2, 4, or 8). Bits 5-3 describe the index register, and bits
        2-0 describe the base register, both of which are encoded like the Reg
        field for general registers.

    Rex - Stores the REX byte for 64-bit register extension.

    Vex - Stores the VEX byte (the last byte of the VEX prefix) if there is one.

    VexMap - Stores the second to last byte of the VEX prefix, which includes
        the map select and ~RXB bits. For a two-byte VEX prefix, a specific
        value is inferred, which is set here.

    Displacement - Stores the displacement of the instruction operand.

    Immediate - Stores the immediate value that may or may not be encoded in the
        instruction.

    Length - Stores the total size of this instruction encoding in bytes.

    DisplacementSize - Stores the size in bytes of the displacement value. Once
        the Displacement field is populated, this field is not too useful.

    ImmediateSize - Stores the size in bytes of the immediate value. Once the
        Immediate field is populated, this field is not too useful.

    OperandOverride - Stores a flag indicating whether or not the operand
        override prefix was on this instruction.

    AddressOverrride - Stores a flag indicating whether or not the address
        override prefix was specified on this instruction.

    Definition - Stores a the instruction decoding information,
        including the instruction mnemonic.

    Lock - Stores a lock string or an empty string, depending on whether or not
        the lock prefix was supplied.

    Rep - Stores a rep string or an empty string depending on whether or not
        the rep prefix was supplied.

    SegmentPrefix - Stores the segment prefix string, or an empty string if
        there is no segment prefix.

--*/

typedef struct _X86_INSTRUCTION {
    MACHINE_LANGUAGE Language;
    ULONGLONG InstructionPointer;
    BYTE Prefix[X86_MAX_PREFIXES];
    BYTE Opcode;
    BYTE Opcode2;
    BYTE ModRm;
    BYTE Sib;
    BYTE Rex;
    BYTE Vex;
    BYTE VexMap;
    ULONGLONG Displacement;
    ULONGLONG Immediate;
    ULONG Length;
    ULONG DisplacementSize;
    ULONG ImmediateSize;
    BOOL OperandOverride;
    BOOL AddressOverride;
    X86_INSTRUCTION_DEFINITION Definition;
    PCSTR Lock;
    PCSTR Rep;
    PCSTR SegmentPrefix;
} X86_INSTRUCTION, *PX86_INSTRUCTION;

typedef enum _X86_REGISTER_VALUE {
    X86RegisterValueAx,
    X86RegisterValueCx,
    X86RegisterValueDx,
    X86RegisterValueBx,
    X86RegisterValueSp,
    X86RegisterValueBp,
    X86RegisterValueSi,
    X86RegisterValueDi,
    X86RegisterValueR8,
    X86RegisterValueR9,
    X86RegisterValueR10,
    X86RegisterValueR11,
    X86RegisterValueR12,
    X86RegisterValueR13,
    X86RegisterValueR14,
    X86RegisterValueR15,
    X86RegisterValueScaleIndexBase,
    X86RegisterValueDisplacement32,
    X86RegisterValueRipRelative
} X86_REGISTER_VALUE, *PX86_REGISTER_VALUE;

typedef enum _X86_MOD_VALUE {
    X86ModValueNoDisplacement,
    X86ModValueDisplacement8,
    X86ModValueDisplacement32,
    X86ModValueRegister
} X86_MOD_VALUE, *PX86_MOD_VALUE;

//
// -------------------------------------------------------------------- Globals
//

//
// Define the x86 instruction encodings. A 6 after the width character of the
// opcode format indicates that the default operand size is 64 bits in long
// mode.
//

X86_INSTRUCTION_DEFINITION DbgX86Instructions[256] = {
    {"add", "Eb", "Gb", "", 0},                 /* 00 */
    {"add", "Ev", "Gv", "", 0},                 /* 01 */
    {"add", "Gb", "Eb", "", 0},                 /* 02 */
    {"add", "Gv", "Ev", "", 0},                 /* 03 */
    {"add", "!bal", "Ib", "", 0},               /* 04 */
    {"add", "!r0", "Iz", "", 0},                /* 05 */
    {"push", "!wes", "", "", 0},                /* 06 */
    {"pop", "!wes", "", "", 0},                 /* 07 */
    {"or", "Eb", "Gb", "", 0},                  /* 08 */
    {"or", "Ev", "Gv", "", 0},                  /* 09 */
    {"or", "Gb", "Eb", "", 0},                  /* 0A */
    {"or", "Gv", "Ev", "", 0},                  /* 0B */
    {"or", "!bal", "Ib", "", 0},                /* 0C */
    {"or", "!r0", "Iz", "", 0},                 /* 0D */
    {"push", "!wcs", "", "", 0},                /* 0E */
    {"2BYTE", "", "", "", X86_INVALID_GROUP},   /* 0F */ /* Two Byte Opcodes */
    {"adc", "Eb", "Gb", "", 0},                 /* 10 */
    {"adc", "Ev", "Gv", "", 0},                 /* 11 */
    {"adc", "Gb", "Eb", "", 0},                 /* 12 */
    {"adc", "Gv", "Ev", "", 0},                 /* 13 */
    {"adc", "!bal", "Ib", "", 0},               /* 14 */
    {"adc", "!r0", "Iz", "", 0},                /* 15 */
    {"push", "!wss", "", "", 0},                /* 16 */
    {"pop", "!wss", "", "", 0},                 /* 17 */
    {"sbb", "Eb", "Gb", "", 0},                 /* 18 */
    {"sbb", "Ev", "Gv", "", 0},                 /* 19 */
    {"sbb", "Gb", "Eb", "", 0},                 /* 1A */
    {"sbb", "Gv", "Ev", "", 0},                 /* 1B */
    {"sbb", "!bal", "Ib", "", 0},               /* 1C */
    {"sbb", "!r0", "Iz", "", 0},                /* 1D */
    {"push", "!wds", "", "", 0},                /* 1E */
    {"pop", "!wds", "", "", 0},                 /* 1F */
    {"and", "Eb", "Gb", "", 0},                 /* 20 */
    {"and", "Ev", "Gv", "", 0},                 /* 21 */
    {"and", "Gb", "Eb", "", 0},                 /* 22 */
    {"and", "Gv", "Ev", "", 0},                 /* 23 */
    {"and", "!bal", "Ib", "", 0},               /* 24 */
    {"and", "!r0", "Iz", "", 0},                /* 25 */
    {"ES:", "", "", "", X86_INVALID_GROUP},     /* 26 */ /* ES prefix */
    {"daa", "", "", "", 0},                     /* 27 */
    {"sub", "Eb", "Gb", "", 0},                 /* 28 */
    {"sub", "Ev", "Gv", "", 0},                 /* 29 */
    {"sub", "Gb", "Eb", "", 0},                 /* 2A */
    {"sub", "Gv", "Ev", "", 0},                 /* 2B */
    {"sub", "!bal", "Ib", "", 0},               /* 2C */
    {"sub", "!r0", "Iz", "", 0},                /* 2D */
    {"CS:", "", "", "", X86_INVALID_GROUP},     /* 2E */ /* CS prefix */
    {"das", "", "", "", 0},                     /* 2F */
    {"xor", "Eb", "Gb", "", 0},                 /* 30 */
    {"xor", "Ev", "Gv", "", 0},                 /* 31 */
    {"xor", "Gb", "Eb", "", 0},                 /* 32 */
    {"xor", "Gv", "Ev", "", 0},                 /* 33 */
    {"xor", "!bal", "Ib", "", 0},               /* 34 */
    {"xor", "!r0", "Iz", "", 0},                /* 35 */
    {"SS:", "", "", "", X86_INVALID_GROUP},     /* 36 */ /* SS prefix */
    {"aaa", "", "", "", 0},                     /* 37 */
    {"cmp", "Eb", "Gb", "", 0},                 /* 38 */
    {"cmp", "Ev", "Gv", "", 0},                 /* 39 */
    {"cmp", "Gb", "Eb", "", 0},                 /* 3A */
    {"cmp", "Gv", "Ev", "", 0},                 /* 3B */
    {"cmp", "!bal", "Ib", "", 0},               /* 3C */
    {"cmp", "!r0", "Iz", "", 0},                /* 3D */
    {"DS:", "", "", "", X86_INVALID_GROUP},     /* 3E */ /* DS prefix */
    {"aas", "", "", "", 0},                     /* 3F */
    {"inc", "!r0", "", "", 0},                  /* 40 */
    {"inc", "!r1", "", "", 0},                  /* 41 */
    {"inc", "!r2", "", "", 0},                  /* 42 */
    {"inc", "!r3", "", "", 0},                  /* 43 */
    {"inc", "!r4", "", "", 0},                  /* 44 */
    {"inc", "!r5", "", "", 0},                  /* 45 */
    {"inc", "!r6", "", "", 0},                  /* 46 */
    {"inc", "!r7", "", "", 0},                  /* 47 */
    {"dec", "!r0", "", "", 0},                  /* 48 */
    {"dec", "!r1", "", "", 0},                  /* 49 */
    {"dec", "!r2", "", "", 0},                  /* 4A */
    {"dec", "!r3", "", "", 0},                  /* 4B */
    {"dec", "!r4", "", "", 0},                  /* 4C */
    {"dec", "!r5", "", "", 0},                  /* 4D */
    {"dec", "!r6", "", "", 0},                  /* 4E */
    {"dec", "!r7", "", "", 0},                  /* 4F */
    {"push", "!r06", "", "", 0},                /* 50 */
    {"push", "!r16", "", "", 0},                /* 51 */
    {"push", "!r26", "", "", 0},                /* 52 */
    {"push", "!r36", "", "", 0},                /* 53 */
    {"push", "!r46", "", "", 0},                /* 54 */
    {"push", "!r56", "", "", 0},                /* 55 */
    {"push", "!r66", "", "", 0},                /* 56 */
    {"push", "!r76", "", "", 0},                /* 57 */
    {"pop", "!r06", "", "", 0},                 /* 58 */
    {"pop", "!r16", "", "", 0},                 /* 59 */
    {"pop", "!r26", "", "", 0},                 /* 5A */
    {"pop", "!r36", "", "", 0},                 /* 5B */
    {"pop", "!r46", "", "", 0},                 /* 5C */
    {"pop", "!r56", "", "", 0},                 /* 5D */
    {"pop", "!r66", "", "", 0},                 /* 5E */
    {"pop", "!r76", "", "", 0},                 /* 5F */
    {"pushad", "", "", "", 0},                  /* 60 */
    {"popad", "", "", "", 0},                   /* 61 */
    {"bound", "Gv", "Ma", "", 0},               /* 62 */
    {"movsxd", "Gv", "Ed", "", 0},              /* 63 */ /* Was arpl in 286+ */
    {"FS:", "", "", "", X86_INVALID_GROUP},     /* 64 */ /* FS prefix */
    {"GS:", "", "", "", X86_INVALID_GROUP},     /* 65 */ /* GS prefix */
    {"OPSIZE:", "", "", "", X86_INVALID_GROUP}, /* 66 */ /* Operand override */
    {"ADSIZE:", "", "", "", X86_INVALID_GROUP}, /* 67 */ /* Address override */
    {"push", "Iz", "", "", 0},                  /* 68 */
    {"imul", "Gv", "Ev", "Iz", 0},              /* 69 */
    {"push", "Ib", "", "", 0},                  /* 6A */
    {"imul", "Gv", "Ev", "Ib", 0},              /* 6B */
    {"ins", "Yb", "!wdx", "", 0},               /* 6C */
    {"ins", "Yz", "!wdx", "", 0},               /* 6D */
    {"outs", "!wdx", "Xb", "", 0},              /* 6E */
    {"outs", "!wdx", "Xz", "", 0},              /* 6F */
    {"jo ", "Jb", "", "", 0},                   /* 70 */
    {"jno", "Jb", "", "", 0},                   /* 71 */
    {"jb ", "Jb", "", "", 0},                   /* 72 */
    {"jnb", "Jb", "", "", 0},                   /* 73 */
    {"jz ", "Jb", "", "", 0},                   /* 74 */
    {"jnz", "Jb", "", "", 0},                   /* 75 */
    {"jbe", "Jb", "", "", 0},                   /* 76 */
    {"jnbe", "Jb", "", "", 0},                  /* 77 */
    {"js ", "Jb", "", "", 0},                   /* 78 */
    {"jns", "Jb", "", "", 0},                   /* 79 */
    {"jp ", "Jb", "", "", 0},                   /* 7A */
    {"jnp", "Jb", "", "", 0},                   /* 7B */
    {"jl ", "Jb", "", "", 0},                   /* 7C */
    {"jnl", "Jb", "", "", 0},                   /* 7D */
    {"jle", "Jb", "", "", 0},                   /* 7E */
    {"jnle", "Jb", "", "", 0},                  /* 7F */
    {"GRP1", "Eb", "Ib", "", 1},                /* 80 */ /* Group 1 opcodes. */
    {"GRP1", "Ev", "Iz", "", 1},                /* 81 */ /* Reg of ModR/M */
    {"GRP1", "Eb", "Ib", "", 1},                /* 82 */ /* extends opcode.*/
    {"GRP1", "Ev", "Ib", "", 1},                /* 83 */
    {"test", "Eb", "Gb", "", 0},                /* 84 */
    {"test", "Ev", "Gv", "", 0},                /* 85 */
    {"xchg", "Eb", "Eb", "", 0},                /* 86 */
    {"xchg", "Ev", "Gv", "", 0},                /* 87 */
    {"mov", "Eb", "Gb", "", 0},                 /* 88 */
    {"mov", "Ev", "Gv", "", 0},                 /* 89 */
    {"mov", "Gb", "Eb", "", 0},                 /* 8A */
    {"mov", "Gv", "Ev", "", 0},                 /* 8B */
    {"mov", "Ev", "Sw", "", 0},                 /* 8C */
    {"lea", "Gv", "M", "", 0},                  /* 8D */
    {"mov", "Sw", "Ev", "", 0},                 /* 8E */
    {"pop", "Ev6", "", "", 0},                  /* 8F */
    {"nop", "", "", "", 0},                     /* 90 */
    {"xchg", "!r1", "!r0", "", 0},              /* 91 */
    {"xchg", "!r2", "!r0", "", 0},              /* 92 */
    {"xchg", "!r3", "!r0", "", 0},              /* 93 */
    {"xchg", "!r4", "!r0", "", 0},              /* 94 */
    {"xchg", "!r5", "!r0", "", 0},              /* 95 */
    {"xchg", "!r6", "!r0", "", 0},              /* 96 */
    {"xchg", "!r7", "!r0", "", 0},              /* 97 */
    {"cwde", "", "", "", 0},                    /* 98 */
    {"cdq", "", "", "", 0},                     /* 99 */
    {"call", "Ap", "", "", 0},                  /* 9A */
    {"fwait", "", "", "", 0},                   /* 9B */
    {"pushf", "", "", "", 0},                   /* 9C */ /* arg1 = Fv */
    {"popf", "", "", "", 0},                    /* 9D */ /* arg1 = Fv */
    {"sahf", "", "", "", 0},                    /* 9E */
    {"lafh", "", "", "", 0},                    /* 9F */
    {"mov", "!bal", "Ob", "", 0},               /* A0 */
    {"mov", "!r0", "Ov", "", 0},                /* A1 */
    {"mov", "Ob", "!bal", "", 0},               /* A2 */
    {"mov", "Ov", "!r0", "", 0},                /* A3 */
    {"movs", "Yb", "Xb", "", 0},                /* A4 */
    {"movs", "Yv", "Xv", "", 0},                /* A5 */
    {"cmps", "Yb", "Xb", "", 0},                /* A6 */
    {"cmps", "Yv", "Xv", "", 0},                /* A7 */
    {"test", "!bal", "Ib", "", 0},              /* A8 */
    {"test", "!r0", "Iz", "", 0},               /* A9 */
    {"stos", "Yb", "!bal", "", 0},              /* AA */
    {"stos", "Yv", "!r0", "", 0},               /* AB */
    {"lods", "!bal", "Xb", "", 0},              /* AC */
    {"lods", "!r0", "Xv", "", 0},               /* AD */
    {"scas", "Yb", "!bal", "", 0},              /* AE */
    {"scas", "Yv", "!r0", "", 0},               /* AF */
    {"mov", "!b0", "Ib", "", 0},                /* B0 */
    {"mov", "!b1", "Ib", "", 0},                /* B1 */
    {"mov", "!b2", "Ib", "", 0},                /* B2 */
    {"mov", "!b3", "Ib", "", 0},                /* B3 */
    {"mov", "!b4", "Ib", "", 0},                /* B4 */
    {"mov", "!b5", "Ib", "", 0},                /* B5 */
    {"mov", "!b6", "Ib", "", 0},                /* B6 */
    {"mov", "!b7", "Ib", "", 0},                /* B7 */
    {"mov", "!r0", "Iv", "", 0},                /* B8 */
    {"mov", "!r1", "Iv", "", 0},                /* B9 */
    {"mov", "!r2", "Iv", "", 0},                /* BA */
    {"mov", "!r3", "Iv", "", 0},                /* BB */
    {"mov", "!r4", "Iv", "", 0},                /* BC */
    {"mov", "!r5", "Iv", "", 0},                /* BD */
    {"mov", "!r6", "Iv", "", 0},                /* BE */
    {"mov", "!r7", "Iv", "", 0},                /* BF */
    {"GRP2", "Eb", "Ib", "", 2},                /* C0 */ /* Group 2 */
    {"GRP2", "Ev", "Ib", "", 2},                /* C1 */ /* Group 2 */
    {"ret", "Iw", "", "", 0},                   /* C2 */
    {"ret", "", "", "", 0},                     /* C3 */
    {"les", "Gz", "Mp", "", 0},                 /* C4 */
    {"lds", "Gz", "Mp", "", 0},                 /* C5 */
    {"mov", "Eb", "Ib", "", 11},                /* C6 */ /* Group 11 */
    {"mov", "Ev", "Iz", "", 11},                /* C7 */ /* Group 11 */
    {"enter", "Iw", "Ib", "", 0},               /* C8 */
    {"leave", "", "", "", 0},                   /* C9 */
    {"retf", "Iw", "", "", 0},                  /* CA */
    {"retf", "", "", "", 0},                    /* CB */
    {"int", "!e3", "", "", 0},                  /* CC */
    {"int", "Ib", "", "", 0},                   /* CD */
    {"into", "", "", "", 0},                    /* CE */
    {"iret", "", "", "", 0},                    /* CF */
    {"GRP2", "Eb", "!e1", "", 2},               /* D0 */ /* Group 2, arg2 = 1 */
    {"GRP2", "Ev", "!e1", "", 2},               /* D1 */ /* Group 2, arg2 = 1 */
    {"GRP2", "Eb", "!bcl", "", 2},              /* D2 */ /* Group 2 */
    {"GRP2", "Ev", "!bcl", "", 2},              /* D3 */ /* Group 2 */
    {"aam", "Ib", "", "", 0},                   /* D4 */
    {"aad", "Ib", "", "", 0},                   /* D5 */
    {"setalc", "", "", "", 0},                  /* D6 */
    {"xlat", "", "", "", 0},                    /* D7 */
    {"ESC0", "Ev", "", "", 0x87},               /* D8 */ /* x87 Floating Pt */
    {"ESC1", "Ev", "", "", 0x87},               /* D9 */
    {"ESC2", "Ev", "", "", 0x87},               /* DA */
    {"ESC3", "Ev", "", "", 0x87},               /* DB */
    {"ESC4", "Ev", "", "", 0x87},               /* DC */
    {"ESC5", "Ev", "", "", 0x87},               /* DD */
    {"ESC6", "Ev", "", "", 0x87},               /* DE */
    {"ESC7", "Ev", "", "", 0x87},               /* DF */
    {"loopnz", "Jb", "", "", 0},                /* E0 */
    {"loopz", "Jb", "", "", 0},                 /* E1 */
    {"loop", "Jb", "", "", 0},                  /* E2 */
    {"jcxz", "Jb", "", "", 0},                  /* E3 */
    {"in ", "!bal", "Ib", "", 0},               /* E4 */
    {"in ", "!eeax", "Iv", "", 0},              /* E5 */
    {"out", "Ib", "!bal", "", 0},               /* E6 */
    {"out", "Ib", "!eeax", "", 0},              /* E7 */
    {"call", "Jz6", "", "", 0},                 /* E8 */
    {"jmp", "Jz6", "", "", 0},                  /* E9 */
    {"jmp", "Ap", "", "", 0},                   /* EA */
    {"jmp", "Jb", "", "", 0},                   /* EB */
    {"in ", "!bal", "!wdx", "", 0},             /* EC */
    {"in ", "!eeax", "!wdx", "", 0},            /* ED */
    {"out", "!wdx", "!bal", "", 0},             /* EE */
    {"out", "!wdx", "!eeax", "", 0},            /* EF */
    {"LOCK:", "", "", "", 0},                   /* F0 */ /* Lock prefix */
    {"int", "!e1", "", "", 0},                  /* F1 */ /* Int 1 */
    {"REPNE:", "", "", "", 0},                  /* F2 */ /* Repne prefix */
    {"REP:", "", "", "", 0},                    /* F3 */ /* Rep prefix */
    {"hlt", "", "", "", 0},                     /* F4 */
    {"cmc", "", "", "", 0},                     /* F5 */
    {"GRP3", "Eb", "", "", 3},                  /* F6 */ /* Group 3 */
    {"GRP3", "Ev", "", "", 3},                  /* F7 */ /* Group 3 */
    {"clc", "", "", "", 0},                     /* F8 */
    {"stc", "", "", "", 0},                     /* F9 */
    {"cli", "", "", "", 0},                     /* FA */
    {"sti", "", "", "", 0},                     /* FB */
    {"cld", "", "", "", 0},                     /* FC */
    {"std", "", "", "", 0},                     /* FD */
    {"GRP4", "Eb", "", "", 4},                  /* FE */ /* Group 4 */
    {"GRP5", "Ev", "", "", 5},                  /* FF */ /* Group 5 */
};

X86_SPARSE_INSTRUCTION_DEFINITION DbgX86TwoByteInstructions[] = {
    {0, 0x0, {"GRP6", "Ev", "", "", 6}},        /* Group 6 */
    {0, 0x1, {"GRP7", "Ev", "", "", 7}},        /* Group 7 */
    {0, 0x2, {"lar", "Gv", "Ew", "", 0}},
    {0, 0x3, {"lsl", "Gv", "Ew", "", 0}},
    {0, 0x5, {"syscall", "", "", "", 0}},
    {0, 0x6, {"clts", "", "", "", 0}},
    {0, 0x7, {"sysret", "", "", "", 0}},
    {0, 0x8, {"invd", "", "", "", 0}},
    {0, 0x9, {"wbinvd", "", "", "", 0}},
    {0, 0xA, {"cl1invmb", "", "", "", 0}},
    {0, 0xB, {"ud1", "", "", "", 0}},

    {0, 0x10, {"movups", "Vx", "Wx", "", 0}},
    {0, 0x11, {"movups", "Wx", "Vx", "", 0}},
    {0, 0x12, {"movlps", "Vo", "Ho", "Mo.q", 0}},
    {0, 0x13, {"movlps", "Mo.q", "Vo", "", 0}},
    {0, 0x14, {"unpcklps", "Vx", "Hx", "Wx", 0}},
    {0, 0x15, {"unpckhps", "Vx", "Hx", "Wx", 0}},
    {0, 0x16, {"movhps", "Vo", "Ho", "Uo", 0}},
    {0, 0x17, {"movhps", "Mo.q", "Vo", "", 0}},
    {0, 0x18, {"GRP16", "M", "", "", 16}},      /* Group 16 */
    {0, 0x19, {"GRP16", "M", "", "", 16}},
    {0, 0x1A, {"GRP16", "M", "", "", 16}},
    {0, 0x1B, {"GRP16", "M", "", "", 16}},
    {0, 0x1C, {"GRP16", "M", "", "", 16}},
    {0, 0x1D, {"GRP16", "M", "", "", 16}},
    {0, 0x1E, {"GRP16", "M", "", "", 16}},
    {0, 0x1F, {"GRP16", "M", "", "", 16}},

    {0x66, 0x10, {"movupd", "Vx", "Wx", "", 0}},
    {0x66, 0x11, {"movupd", "Wx", "Vx", "", 0}},
    {0x66, 0x12, {"movlpd", "Vo", "Ho", "Mo.q", 0}},
    {0x66, 0x13, {"movlpd", "Mo.q", "Vo", "", 0}},
    {0x66, 0x14, {"unpcklpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x15, {"unpckhpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x16, {"movhpd", "Vo", "Ho", "Mo.q", 0}},
    {0x66, 0x17, {"movhpd", "Mo.q", "Vo", "", 0}},
    {0x66, 0x18, {"GRP16", "M", "", "", 16}},
    {0x66, 0x19, {"GRP16", "M", "", "", 16}},
    {0x66, 0x1A, {"GRP16", "M", "", "", 16}},
    {0x66, 0x1B, {"GRP16", "M", "", "", 16}},
    {0x66, 0x1C, {"GRP16", "M", "", "", 16}},
    {0x66, 0x1D, {"GRP16", "M", "", "", 16}},
    {0x66, 0x1E, {"GRP16", "M", "", "", 16}},
    {0x66, 0x1F, {"GRP16", "M", "", "", 16}},

    {0xF3, 0x10, {"movss", "Vo", "Mo.d", "", 0}},
    {0xF3, 0x11, {"movss", "Mo.d", "Vo", "", 0}},
    {0xF3, 0x12, {"movsldup", "Vx", "Wx", "", 0}},
    {0xF3, 0x16, {"movshdup", "Vx", "Wx", "", 0}},
    {0xF3, 0x18, {"GRP16", "M", "", "", 16}},
    {0xF3, 0x19, {"GRP16", "M", "", "", 16}},
    {0xF3, 0x1A, {"GRP16", "M", "", "", 16}},
    {0xF3, 0x1B, {"GRP16", "M", "", "", 16}},
    {0xF3, 0x1C, {"GRP16", "M", "", "", 16}},
    {0xF3, 0x1D, {"GRP16", "M", "", "", 16}},
    {0xF3, 0x1E, {"GRP16", "M", "", "", 16}},
    {0xF3, 0x1F, {"GRP16", "M", "", "", 16}},

    {0xF2, 0x10, {"movsd", "Vo", "Mo.d", "", 0}},
    {0xF2, 0x11, {"movsd", "Mo.d", "Vo", "", 0}},
    {0xF2, 0x12, {"movddup", "Vx", "Wx", "", 0}},
    {0xF2, 0x18, {"GRP16", "M", "", "", 16}},
    {0xF2, 0x19, {"GRP16", "M", "", "", 16}},
    {0xF2, 0x1A, {"GRP16", "M", "", "", 16}},
    {0xF2, 0x1B, {"GRP16", "M", "", "", 16}},
    {0xF2, 0x1C, {"GRP16", "M", "", "", 16}},
    {0xF2, 0x1D, {"GRP16", "M", "", "", 16}},
    {0xF2, 0x1E, {"GRP16", "M", "", "", 16}},
    {0xF2, 0x1F, {"GRP16", "M", "", "", 16}},

    {0, 0x20, {"mov", "Ry6", "Cy", "", 0}},
    {0, 0x21, {"mov", "Ry6", "Dy", "", 0}},
    {0, 0x22, {"mov", "Cy", "Ry6", "", 0}},
    {0, 0x23, {"mov", "Dy", "Ry6", "", 0}},
    {0, 0x24, {"mov", "Ry6", "Ty", "", 0}},
    {0, 0x26, {"mov", "Ty", "Ry6", "", 0}},
    {0, 0x28, {"movaps", "Vx", "Wx", "", 0}},
    {0, 0x29, {"movaps", "Wx", "Vx", "", 0}},
    {0, 0x2A, {"cvtpi2ps", "Vo", "Mq", "", 0}},
    {0, 0x2B, {"movntps", "Mx", "Vx", "", 0}},
    {0, 0x2C, {"cvttps2pi", "Pq", "Wo.q", "", 0}},
    {0, 0x2D, {"cvtps2pi", "Pq", "Wo.q", "", 0}},
    {0, 0x2E, {"ucomiss", "Vo", "Wo.d", "", 0}},
    {0, 0x2F, {"comiss", "Vo", "Wo.d", "", 0}},

    {0xF0, 0x20, {"mov", "Rd", "!ecr8", "", 0}},
    {0xF0, 0x22, {"mov", "!ecr8", "Rd", "", 0}},

    {0x66, 0x28, {"movapd", "Vx", "Wx", "", 0}},
    {0x66, 0x29, {"movapd", "Wx", "Vx", "", 0}},
    {0x66, 0x2A, {"cvtpi2pd", "Vo", "Mq", "", 0}},
    {0x66, 0x2B, {"movntpd", "Mx", "Vx", "", 0}},
    {0x66, 0x2C, {"cvttpd2pi", "Pq", "Wo", "", 0}},
    {0x66, 0x2D, {"cvtpd2pi", "Pq", "Wo", "", 0}},
    {0x66, 0x2E, {"ucomisd", "Vo", "Wo.q", "", 0}},
    {0x66, 0x2F, {"comisd", "Vo", "Wo.q", "", 0}},

    {0xF3, 0x2A, {"cvtsi2ss", "Vo", "Ho", "Ey", 0}},
    {0xF3, 0x2B, {"movntss", "Md", "Vo", "", 0}},
    {0xF3, 0x2C, {"cvttss2si", "Gy", "Wo.d", "", 0}},
    {0xF3, 0x2D, {"cvtss2si", "Gy", "Wo.d", "", 0}},

    {0xF2, 0x2A, {"cvtsi2sd", "Vo", "Ho", "Ey", 0}},
    {0xF2, 0x2B, {"movntsd", "Md", "Vo", "", 0}},
    {0xF2, 0x2C, {"cvttsd2si", "Gy", "Wo.q", "", 0}},
    {0xF2, 0x2D, {"cvtsd2si", "Gy", "Wo.q", "", 0}},

    {0, 0x30, {"wrmsr", "", "", "", 0}},
    {0, 0x31, {"rdtsc", "", "", "", 0}},
    {0, 0x32, {"rdmsr", "", "", "", 0}},
    {0, 0x33, {"rdpmc", "", "", "", 0}},
    {0, 0x34, {"sysenter", "", "", "", 0}},
    {0, 0x35, {"sysexit", "", "", "", 0}},
    {0, 0x37, {"getsec", "", "", "", 0}},

    {0, 0x40, {"cmovo", "Gv", "Ev", "", 0}},
    {0, 0x41, {"cmovno", "Gv", "Ev", "", 0}},
    {0, 0x42, {"cmovb", "Gv", "Ev", "", 0}},
    {0, 0x43, {"cmovnb", "Gv", "Ev", "", 0}},
    {0, 0x44, {"cmovz", "Gv", "Ev", "", 0}},
    {0, 0x45, {"cmovnz", "Gv", "Ev", "", 0}},
    {0, 0x46, {"cmovbe", "Gv", "Ev", "", 0}},
    {0, 0x47, {"cmovnbe", "Gv", "Ev", "", 0}},
    {0, 0x48, {"cmovs", "Gv", "Ev", "", 0}},
    {0, 0x49, {"cmovns", "Gv", "Ev", "", 0}},
    {0, 0x4A, {"cmovp", "Gv", "Ev", "", 0}},
    {0, 0x4B, {"cmovnp", "Gv", "Ev", "", 0}},
    {0, 0x4C, {"cmovl", "Gv", "Ev", "", 0}},
    {0, 0x4D, {"cmovnl", "Gv", "Ev", "", 0}},
    {0, 0x4E, {"cmovle", "Gv", "Ev", "", 0}},
    {0, 0x4F, {"cmovnle", "Gv", "Ev", "", 0}},

    {0, 0x50, {"movmskps", "Gy", "Ux", "", 0}},
    {0, 0x51, {"sqrtps", "Vx", "Wx", "", 0}},
    {0, 0x52, {"rsqrtps", "Vx", "Wx", "", 0}},
    {0, 0x53, {"rcpps", "Vx", "Wx", "", 0}},
    {0, 0x54, {"andps", "Vx", "Hx", "Wx", 0}},
    {0, 0x55, {"andnps", "Vx", "Hx", "Wx", 0}},
    {0, 0x56, {"orps", "Vx", "Hx", "Wx", 0}},
    {0, 0x57, {"xorps", "Vx", "Hx", "Wx", 0}},
    {0, 0x58, {"addps", "Vx", "Hx", "Wx", 0}},
    {0, 0x59, {"mulps", "Vx", "Hx", "Wx", 0}},
    {0, 0x5A, {"cvtps2pd", "Vo", "Wo.q", "", 0}},
    {0, 0x5B, {"cvtdq2ps", "Vx", "Wx", "", 0}},
    {0, 0x5C, {"subps", "Vx", "Hx", "Wx", 0}},
    {0, 0x5D, {"minps", "Vx", "Hx", "Wx", 0}},
    {0, 0x5E, {"divps", "Vx", "Hx", "Wx", 0}},
    {0, 0x5F, {"maxps", "Vx", "Hx", "Wx", 0}},

    {0x66, 0x50, {"movmskpd", "Gy", "Ux", "", 0}},
    {0x66, 0x51, {"sqrtpd", "Vx", "Wx", "", 0}},
    {0x66, 0x54, {"andpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x55, {"andnpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x56, {"orpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x57, {"xorpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x58, {"addpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x59, {"mulpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x5A, {"cvtpd2ps", "Vo", "Wo", "", 0}},
    {0x66, 0x5B, {"cvtps2dq", "Vx", "Wx", "", 0}},
    {0x66, 0x5C, {"subpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x5D, {"minpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x5E, {"divpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x5F, {"maxpd", "Vx", "Hx", "Wx", 0}},

    {0xF3, 0x51, {"sqrtss", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x52, {"rsqrtss", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x53, {"rcpss", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x58, {"addss", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x59, {"mulss", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x5A, {"cvtss2sd", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x5B, {"cvttps2dq", "Vx", "Wx", "", 0}},
    {0xF3, 0x5C, {"subss", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x5D, {"minss", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x5E, {"divss", "Vo", "Ho", "Wo.d", 0}},
    {0xF3, 0x5F, {"maxss", "Vo", "Ho", "Wo.d", 0}},

    {0xF2, 0x51, {"sqrtsd", "Vo", "Ho", "Wo.q", 0}},
    {0xF2, 0x58, {"addsd", "Vo", "Ho", "Wo.q", 0}},
    {0xF2, 0x59, {"mulsd", "Vo", "Ho", "Wo.q", 0}},
    {0xF2, 0x5A, {"cvtsd2ss", "Vo", "Ho", "Wo.q", 0}},
    {0xF2, 0x5C, {"subsd", "Vo", "Ho", "Wo.q", 0}},
    {0xF2, 0x5D, {"minsd", "Vo", "Ho", "Wo.q", 0}},
    {0xF2, 0x5E, {"divsd", "Vo", "Ho", "Wo.q", 0}},
    {0xF2, 0x5F, {"maxsd", "Vo", "Ho", "Wo.q", 0}},

    {0, 0x60, {"punpcklbw", "Pq", "Qd", "", 0}},
    {0, 0x61, {"punpcklwd", "Pq", "Qd", "", 0}},
    {0, 0x62, {"punpckldq", "Pq", "Qd", "", 0}},
    {0, 0x63, {"packsswb", "Pq", "Qq", "", 0}},
    {0, 0x64, {"pcmpgtb", "Pq", "Qq", "", 0}},
    {0, 0x65, {"pcmpgtw", "Pq", "Qq", "", 0}},
    {0, 0x66, {"pcmpgtd", "Pq", "Qq", "", 0}},
    {0, 0x67, {"packuswb", "Pq", "Qq", "", 0}},
    {0, 0x68, {"punpckhbw", "Pq", "Qq", "", 0}},
    {0, 0x69, {"punpckhwd", "Pq", "Qq", "", 0}},
    {0, 0x6A, {"punpckhdq", "Pq", "Qq", "", 0}},
    {0, 0x6B, {"packssdw", "Pq", "Qq", "", 0}},
    {0, 0x6E, {"movd", "Pq", "Ey", "", 0}},
    {0, 0x6F, {"movq", "Pq", "Qq", "", 0}},

    {0x66, 0x60, {"unpcklbw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x61, {"punpcklwd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x62, {"punpckldq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x63, {"packsswb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x64, {"pcmpgtb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x65, {"pcmpgtw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x66, {"pcmpgtd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x67, {"packuswb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x68, {"punpckhbw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x69, {"punpckhwd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x6A, {"punpckhdq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x6B, {"packssdw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x6C, {"punpckl-qdq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x6D, {"punpckh-qdq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x6E, {"movd", "Vo", "Ey", "", 0}},
    {0x66, 0x6F, {"movdqa", "Vx", "Wx", "", 0}},

    {0xF3, 0x6F, {"movdqu", "Vx", "Wx", "", 0}},

    {0, 0x70, {"pshufw", "Pq", "Qq", "Ib", 0}},
    {0, 0x71, {"GRP12", "Nb", "Iq", "", 12}},
    {0, 0x72, {"GRP13", "Nb", "Iq", "", 13}},
    {0, 0x73, {"GRP14", "Nb", "Iq", "", 14}},
    {0, 0x74, {"pcmpeqb", "Pq", "Qq", "", 0}},
    {0, 0x75, {"pcmpeqw", "Pq", "Qq", "", 0}},
    {0, 0x76, {"pcmpeqd", "Pq", "Qq", "", 0}},
    {0, 0x77, {"emms", "", "", "", 0}},
    {0, 0x78, {"vmread", "Ey", "Gy", "", 0}},
    {0, 0x79, {"vmwrite", "Gy", "Ey", "", 0}},
    {0, 0x7E, {"movd", "Ey", "Pq", "", 0}},
    {0, 0x7F, {"movq", "Qq", "Pq", "", 0}},

    {0x66, 0x70, {"pshufd", "Vx", "Wx", "Ib", 0}},
    {0x66, 0x71, {"GRP12", "Nb", "Iq", "", 12}},
    {0x66, 0x72, {"GRP13", "Nb", "Iq", "", 13}},
    {0x66, 0x73, {"GRP14", "Nb", "Iq", "", 14}},
    {0x66, 0x74, {"pcmpeqb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x75, {"pcmpeqw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x76, {"pcmpeqd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x7C, {"haddpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x7D, {"hsubpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0x7E, {"movd", "Ey", "Vo", "", 0}},
    {0x66, 0x7F, {"movdqa", "Wx", "Vx", "", 0}},

    {0xF3, 0x70, {"pshufhw", "Vx", "Wx", "Ib", 0}},
    {0xF3, 0x71, {"GRP12", "Nb", "Iq", "", 12}},
    {0xF3, 0x72, {"GRP13", "Nb", "Iq", "", 13}},
    {0xF3, 0x73, {"GRP14", "Nb", "Iq", "", 14}},
    {0xF3, 0x7E, {"movq", "Vo", "Wo.q", "", 0}},
    {0xF3, 0x7F, {"movdqu", "Wx", "Vx", "", 0}},

    {0xF2, 0x70, {"pshuflw", "Vx", "Wx", "Ib", 0}},
    {0xF2, 0x71, {"GRP12", "Nb", "Iq", "", 12}},
    {0xF2, 0x72, {"GRP13", "Nb", "Iq", "", 13}},
    {0xF2, 0x73, {"GRP14", "Nb", "Iq", "", 14}},
    {0xF2, 0x7C, {"haddps", "Vx", "Hx", "Wx", 0}},
    {0xF2, 0x7D, {"hsubps", "Vx", "Hx", "Wx", 0}},

    {0, 0x80, {"jo ", "Jz", "", "", 0}},
    {0, 0x81, {"jno", "Jz", "", "", 0}},
    {0, 0x82, {"jb ", "Jz", "", "", 0}},
    {0, 0x83, {"jnb", "Jz", "", "", 0}},
    {0, 0x84, {"jz ", "Jz", "", "", 0}},
    {0, 0x85, {"jnz", "Jz", "", "", 0}},
    {0, 0x86, {"jbe", "Jz", "", "", 0}},
    {0, 0x87, {"jnbe", "Jz", "", "", 0}},
    {0, 0x88, {"js ", "Jz", "", "", 0}},
    {0, 0x89, {"jns", "Jz", "", "", 0}},
    {0, 0x8A, {"jp", "Jz", "", "", 0}},
    {0, 0x8B, {"jnp", "Jz", "", "", 0}},
    {0, 0x8C, {"jl ", "Jz", "", "", 0}},
    {0, 0x8D, {"jnl", "Jz", "", "", 0}},
    {0, 0x8E, {"jle", "Jz", "", "", 0}},
    {0, 0x8F, {"jnle", "Jz", "", "", 0}},

    {0, 0x90, {"seto", "Eb", "", "", 0}},
    {0, 0x91, {"setno", "Eb", "", "", 0}},
    {0, 0x92, {"setb", "Eb", "", "", 0}},
    {0, 0x93, {"setnb", "Eb", "", "", 0}},
    {0, 0x94, {"setz", "Eb", "", "", 0}},
    {0, 0x95, {"setnz", "Eb", "", "", 0}},
    {0, 0x96, {"setbe", "Eb", "", "", 0}},
    {0, 0x97, {"setnbe", "Eb", "", "", 0}},
    {0, 0x98, {"sets", "Eb", "", "", 0}},
    {0, 0x99, {"setns", "Eb", "", "", 0}},
    {0, 0x9A, {"setp", "Eb", "", "", 0}},
    {0, 0x9B, {"setnp", "Eb", "", "", 0}},
    {0, 0x9C, {"setl", "Eb", "", "", 0}},
    {0, 0x9D, {"setnl", "Eb", "", "", 0}},
    {0, 0x9E, {"setle", "Eb", "", "", 0}},
    {0, 0x9F, {"setnle", "Eb", "", "", 0}},

    {0, 0xA0, {"push", "!wfs", "", "", 0}},
    {0, 0xA1, {"pop", "!wfs", "", "", 0}},
    {0, 0xA2, {"cpuid", "", "", "", 0}},
    {0, 0xA3, {"bt ", "Ev", "Gv", "", 0}},
    {0, 0xA4, {"shld", "Ev", "Gv", "Ib", 0}},
    {0, 0xA5, {"shld", "Ev", "Gv", "!b1", 0}},
    {0, 0xA6, {"cmpxchg", "", "", "", 0}},
    {0, 0xA7, {"cmpxchg", "", "", "", 0}},
    {0, 0xA8, {"push", "!wgs", "", "", 0}},
    {0, 0xA9, {"pop", "!gs", "", "", 0}},
    {0, 0xAA, {"rsm", "", "", "", 0}},
    {0, 0xAB, {"bts", "Ev", "Gv", "", 0}},
    {0, 0xAC, {"shrd", "Ev", "Gv", "Ib", 0}},
    {0, 0xAD, {"shrd", "Ev", "Gv", "!b1", 0}},
    {0, 0xAE, {"GRP15", "M", "", "", 15}},       /* Group 15 */
    {0, 0xAF, {"imul", "Gv", "Ev", "", 0}},

    {0xF3, 0xAE, {"GRP15A", "Ry", "", "", 0x15A}},  /* Group 15A */

    {0, 0xB0, {"cmpxchg", "Eb", "Gb", "", 0}},
    {0, 0xB1, {"cmpxchg", "Ev", "Gv", "", 0}},
    {0, 0xB2, {"lss", "Gz", "Mp", "", 0}},
    {0, 0xB3, {"btr", "Ev", "Gv", "", 0}},
    {0, 0xB4, {"lfs", "Gz", "Mp", "", 0}},
    {0, 0xB5, {"lgs", "Gz", "Mp", "", 0}},
    {0, 0xB6, {"movzx", "Gv", "Eb", "", 0}},
    {0, 0xB7, {"movxz", "Gv", "Ew", "", 0}},
    {0, 0xB8, {"jmpe", "Jz", "", "", 0}},
    {0, 0xB9, {"ud2", "", "", "", 0}},          /* Group 10 */
    {0, 0xBA, {"GRP8", "Ev", "Ib", "", 8}},     /* Group 8 */
    {0, 0xBB, {"btc", "Ev", "Gv", "", 0}},
    {0, 0xBC, {"bsf", "Gv", "Ev", "", 0}},
    {0, 0xBD, {"bsr", "Gv", "Ev", "", 0}},
    {0, 0xBE, {"movsx", "Gv", "Eb", "", 0}},
    {0, 0xBF, {"movsx", "Gv", "Ew", "", 0}},

    {0xF3, 0xB8, {"popcnt", "Gv", "Ev", "", 0}},
    {0xF3, 0xBD, {"lzcnt", "Gv", "Ev", "", 0}},

    {0, 0xC0, {"xadd", "Eb", "Gb", "", 0}},
    {0, 0xC1, {"xadd", "Ev", "Gv", "", 0}},
    {0, 0xC2, {"cmpccps", "Vx", "Hx", "Wx", 0}},/* Also has Ib */
    {0, 0xC3, {"movnti", "My", "Gy", "", 0}},
    {0, 0xC4, {"pinsrw", "Pq", "Mw", "Ib", 0}},
    {0, 0xC5, {"pextrw", "Gy", "Nq", "Ib", 0}},
    {0, 0xC6, {"shufps", "Vx", "Hx", "Wx", 0}}, /* Also has Ib */
    {0, 0xC7, {"GRP9", "M", "", "", 9}},        /* Group 9 */
    {0, 0xC8, {"bswap", "!r0", "", "", 0}},
    {0, 0xC9, {"bswap", "!r1", "", "", 0}},
    {0, 0xCA, {"bswap", "!r2", "", "", 0}},
    {0, 0xCB, {"bswap", "!r3", "", "", 0}},
    {0, 0xCC, {"bswap", "!r4", "", "", 0}},
    {0, 0xCD, {"bswap", "!r5", "", "", 0}},
    {0, 0xCE, {"bswap", "!r6", "", "", 0}},
    {0, 0xCF, {"bswap", "!r7", "", "", 0}},

    {0x66, 0xC0, {"xadd", "Eb", "Gb", "", 0}},
    {0x66, 0xC1, {"xadd", "Ev", "Gv", "", 0}},
    {0x66, 0xC2, {"cmpccpd", "Vx", "Hx", "Wx", 0}},    /* Also has Ib */
    {0x66, 0xC4, {"pinsrw", "Vo", "Ho", "Mw", 0}},     /* Also has Ib */
    {0x66, 0xC5, {"pextrw", "Gy", "Uo", "Ib", 0}},
    {0x66, 0xC6, {"shufpd", "Vx", "Hx", "Wx", 0}},     /* Also has Ib */
    {0x66, 0xC7, {"GRP9", "M", "", "", 9}},      /* Group 9 */

    {0xF3, 0xC0, {"xadd", "Eb", "Gb", "", 0}},
    {0xF3, 0xC1, {"xadd", "Ev", "Gv", "", 0}},
    {0xF3, 0xC2, {"cmpccss", "Vo", "Ho", "Wo.d", 0}},  /* Also has Ib */
    {0xF3, 0xC7, {"GRP9", "M", "", "", 9}},      /* Group 9 */

    {0xF2, 0xC0, {"xadd", "Eb", "Gb", "", 0}},
    {0xF2, 0xC1, {"xadd", "Ev", "Gv", "", 0}},
    {0xF2, 0xC2, {"cmpccss", "Vo", "Ho", "Wo.d", 0}},  /* Also has Ib */
    {0xF2, 0xC7, {"GRP9", "M", "", "", 9}},      /* Group 9 */

    {0, 0xD1, {"psrlw", "Pq", "Qq", "", 0}},
    {0, 0xD2, {"psrld", "Pq", "Qq", "", 0}},
    {0, 0xD3, {"psrlq", "Pq", "Qq", "", 0}},
    {0, 0xD4, {"paddq", "Pq", "Qq", "", 0}},
    {0, 0xD5, {"pmullw", "Pq", "Qq", "", 0}},
    {0, 0xD7, {"pmovmskb", "Gy", "Nq", "", 0}},
    {0, 0xD8, {"psubusb", "Pq", "Qq", "", 0}},
    {0, 0xD9, {"psubusw", "Pq", "Qq", "", 0}},
    {0, 0xDA, {"pminub", "Pq", "Qq", "", 0}},
    {0, 0xDB, {"pand", "Pq", "Qq", "", 0}},
    {0, 0xDC, {"paddusb", "Pq", "Qq", "", 0}},
    {0, 0xDD, {"paddusw", "Pq", "Qq", "", 0}},
    {0, 0xDE, {"pmaxub", "Pq", "Qq", "", 0}},
    {0, 0xDF, {"pandn", "Pq", "Qq", "", 0}},

    {0x66, 0xD0, {"addsubpd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xD1, {"psrlw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xD2, {"psrld", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xD3, {"psrlq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xD4, {"paddq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xD5, {"pmullw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xD6, {"pmovq", "Wo.q", "Vo", "", 0}},
    {0x66, 0xD7, {"pmovmskb", "Gy", "Ux", "", 0}},
    {0x66, 0xD8, {"psubusb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xD9, {"psubusw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xDA, {"pminub", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xDB, {"pand", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xDC, {"paddusb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xDD, {"paddusw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xDE, {"pmaxub", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xDF, {"pandn", "Vx", "Hx", "Wx", 0}},

    {0xF3, 0xD6, {"movq2dq", "Vo", "Nq", "", 0}},

    {0xF2, 0xD0, {"addsubps", "Vx", "Hx", "Wx", 0}},
    {0xF2, 0xD6, {"movdq2q", "Pq", "Uq", "", 0}},

    {0, 0xE0, {"pavgb", "Pq", "Qq", "", 0}},
    {0, 0xE1, {"psraw", "Pq", "Qq", "", 0}},
    {0, 0xE2, {"psrad", "Pq", "Qq", "", 0}},
    {0, 0xE3, {"pavgw", "Pq", "Qq", "", 0}},
    {0, 0xE4, {"pmulhuw", "Pq", "Qq", "", 0}},
    {0, 0xE5, {"pmulhw", "Pq", "Qq", "", 0}},
    {0, 0xE7, {"movntq", "Mq", "Pq", "", 0}},
    {0, 0xE8, {"psubsb", "Pq", "Qq", "", 0}},
    {0, 0xE9, {"psubsw", "Pq", "Qq", "", 0}},
    {0, 0xEA, {"pminsw", "Pq", "Qq", "", 0}},
    {0, 0xEB, {"por", "Pq", "Qq", "", 0}},
    {0, 0xEC, {"paddsb", "Pq", "Qq", "", 0}},
    {0, 0xED, {"paddsw", "Pq", "Qq", "", 0}},
    {0, 0xEE, {"pmaxsw", "Mq", "Pq", "", 0}},
    {0, 0xEF, {"pxor", "Mq", "Pq", "", 0}},

    {0x66, 0xE0, {"pavgb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xE1, {"psraw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xE2, {"psrad", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xE3, {"pavgw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xE4, {"pmulhuw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xE5, {"pmulhw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xE6, {"cvttpd2dq", "Vo", "Wx", "", 0}},
    {0x66, 0xE7, {"movntdq", "Mx", "Vx", "", 0}},
    {0x66, 0xE8, {"psubsb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xE9, {"psubsw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xEA, {"pminsw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xEB, {"por", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xEC, {"paddsb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xED, {"paddsw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xEE, {"pmaxsw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xEF, {"pxor", "Vx", "Hx", "Wx", 0}},

    {0xF3, 0xE6, {"cvtdq2pd", "Vo", "Wo.q", "", 0}},

    {0xF2, 0xE6, {"cvtpd2dq", "Vo", "Wx", "", 0}},

    {0, 0xF1, {"psllw", "Pq", "Qq", "", 0}},
    {0, 0xF2, {"pslld", "Pq", "Qq", "", 0}},
    {0, 0xF3, {"psllq", "Pq", "Qq", "", 0}},
    {0, 0xF4, {"pmuludq", "Pq", "Qq", "", 0}},
    {0, 0xF5, {"pmaddwd", "Pq", "Qq", "", 0}},
    {0, 0xF6, {"psadbw", "Pq", "Qq", "", 0}},
    {0, 0xF7, {"maskmovq", "Pq", "Nq", "", 0}},
    {0, 0xF8, {"psubb", "Pq", "Qq", "", 0}},
    {0, 0xF9, {"psubw", "Pq", "Qq", "", 0}},
    {0, 0xFA, {"psubd", "Pq", "Qq", "", 0}},
    {0, 0xFB, {"psubq", "Pq", "Qq", "", 0}},
    {0, 0xFC, {"paddb", "Pq", "Qq", "", 0}},
    {0, 0xFD, {"paddw", "Pq", "Qq", "", 0}},
    {0, 0xFE, {"paddd", "Pq", "Qq", "", 0}},
    {0, 0xFF, {"ud", "", "", "", 0}},

    {0x66, 0xF1, {"psllw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xF2, {"pslld", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xF3, {"psllq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xF4, {"pmuludq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xF5, {"pmaddwd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xF6, {"psadbw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xF7, {"maskmovdqq", "Vo", "Uo", "", 0}},
    {0x66, 0xF8, {"psubb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xF9, {"psubw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xFA, {"psubd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xFB, {"psubq", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xFC, {"paddb", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xFD, {"paddw", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xFE, {"paddd", "Vx", "Hx", "Wx", 0}},
    {0x66, 0xFF, {"ud", "", "", "", 0}},

    {0xF2, 0xF0, {"lddqu", "Vx", "Mx", "", 0}},

    {0, 0x0, {"", "", "", "", 0}},
};

//
// Define the opcode groups, terminated by group zero.
//

X86_OPCODE_GROUP DbgX86OpcodeGroups[] = {
    {1, {"add", "or ", "adc", "sbb", "and", "sub", "xor", "cmp"}},
    {2, {"rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar"}},
    {3, {"test", "test", "not", "neg", "mul", "imul", "div", "idiv"}},
    {4, {"inc", "dec", "(bad)", "(bad)", "(bad)", "(bad)", "(bad)", "(bad)"}},
    {5, {"inc", "dec", "call", "call", "jmp", "jmp", "push", "(bad)"}},
    {6, {"sldt", "str", "lldt", "ltr", "verr", "verw", "jmpe", "(bad)"}},
    {7, {"sgdt", "sidt", "lgdt", "lidt", "smsw", "rstorssp", "lmsw", "invlpg"}},
    {8, {"(bad)", "(bad)", "(bad)", "(bad)", "bt", "bts", "btr", "btc"}},
    {9, {"(bad)", "cmpxchg8b", "xrstors", "xsavec",
         "xsaves", "(bad)", "vmptrld", "vmptrst"}},

    {10, {"ud2", "ud2", "ud2", "ud2", "ud2", "ud2", "ud2", "ud2"}},
    {11, {"mov", "(bad)", "(bad)", "(bad)",
          "(bad)", "(bad)", "(bad)", "xabort"}},

    {12, {"(bad)", "(bad)", "psrlw", "(bad)",
          "psraw", "(bad)", "psllw", "(bad)"}},

    {13, {"(bad)", "(bad)", "psrld", "(bad)",
          "psrad", "(bad)", "pslld", "(bad)"}},

    {14, {"(bad)", "(bad)", "psrlq", "psrldq",
          "(bad)", "(bad)", "psllq", "pslldq"}},

    {15, {"fxsave", "fxrstor", "ldmxcsr", "stmxcsr",
          "xsave", "xrstor", "xsaveopt", "clflush"}},

    {0x15A, {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase",
             "ptwrite", "(bad)", "(bad)", "(bad)"}},

    {16, {"prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2",
          "hint", "hint", "hint", "hint"}},

    {17, {"(bad)", "blsr", "blsmsk", "blsi",
          "(bad)", "(bad)", "(bad)", "(bad)"}},

    {0}
};

X86_SPARSE_INSTRUCTION_DEFINITION DbgX860F01Alternates[] = {
    {0, 0xC1, {"vmcall", "", "", "", 0}},
    {0, 0xC2, {"vmlaunch", "", "", "", 0}},
    {0, 0xC3, {"vmresume", "", "", "", 0}},
    {0, 0xC4, {"vmxoff", "", "", "", 0}},
    {0, 0xC8, {"monitor", "", "", "", 0}},
    {0, 0xC9, {"mwait", "", "", "", 0}},
    {0, 0xCA, {"clac", "", "", "", 0}},
    {0, 0xCB, {"stac", "", "", "", 0}},
    {0, 0xCF, {"encls", "", "", "", 0}},
    {0, 0xD0, {"xgetbv", "", "", "", 0}},
    {0, 0xD1, {"xsetbv", "", "", "", 0}},
    {0, 0xD4, {"vmfunc", "", "", "", 0}},
    {0, 0xD5, {"xend", "", "", "", 0}},
    {0, 0xD6, {"xtest", "", "", "", 0}},
    {0, 0xD7, {"enclu", "", "", "", 0}},
    {0, 0xD8, {"vmrun", "", "", "", 0}},
    {0, 0xD9, {"vmmcall", "", "", "", 0}},
    {0, 0xDA, {"vmload", "", "", "", 0}},
    {0, 0xDB, {"vmsave", "", "", "", 0}},
    {0, 0xDC, {"stgi", "", "", "", 0}},
    {0, 0xDD, {"clgi", "", "", "", 0}},
    {0, 0xDE, {"skinit", "", "", "", 0}},
    {0, 0xDF, {"invlpga", "", "", "", 0}},
    {0, 0xEE, {"rdpkru", "", "", "", 0}},
    {0, 0xEF, {"wrpkru", "", "", "", 0}},
    {0, 0xF8, {"swapgs", "", "", "", 0}},
    {0, 0xF9, {"rdtscp", "", "", "", 0}},
    {0, 0xFA, {"monitorx", "", "", "", 0}},
    {0, 0xFB, {"mwaitx", "", "", "", 0}},
    {0, 0xFC, {"clzero", "", "", "", 0}},
};

//
// Define the various x87 floating point mnemonics. The first index is the
// first opcode (offset from 0xD8), and the second index is the reg2 portion
// of the ModR/M byte. These are only valid if the mod portion of ModR/M
// does not specify a register. If it specifies a register, then there are
// different arrays used for decoding.
//

PSTR DbgX87Instructions[8][8] = {
    {
        "fadd",
        "fmul",
        "fcom",
        "fcomp",
        "fsub",
        "fsubr",
        "fdiv",
        "fdivr"
    },

    {
        "fld",
        NULL,
        "fst",
        "fstp",
        "fldenv",
        "fldcw",
        "fstenv",
        "fstcw"
    },

    {
        "fiadd",
        "fimul",
        "ficom",
        "ficomp",
        "fisub",
        "fisubr",
        "fidiv",
        "fidivr"
    },

    {
        "fild",
        "fisttp",
        "fist",
        "fistp",
        NULL,
        "fld",
        NULL,
        "fstp"
    },

    {
        "fadd",
        "fmul",
        "fcom",
        "fcomp",
        "fsub",
        "fsubr",
        "fdiv",
        "fdivr"
    },

    {
        "fld",
        "fisttp",
        "fst",
        "fstp",
        "frstor",
        NULL,
        "fsave",
        "fstsw"
    },

    {
        "fiadd",
        "fimul",
        "ficom",
        "ficomp",
        "fisub",
        "fisubr",
        "fidiv",
        "fidivr"
    },

    {
        "fild",
        "fisttp",
        "fist",
        "fistp",
        "fbld",
        "fild",
        "fbstp",
        "fistp"
    }
};

PSTR DbgX87D9E0Instructions[32] = {
    "fchs",
    "fabs",
    NULL,
    NULL,
    "ftst",
    "fxam",
    "ftstp",
    NULL,
    "fld1",
    "fldl2t",
    "fldl2e",
    "fldpi",
    "fldlg2",
    "fldln2",
    "fldz",
    NULL,
    "f2xm1",
    "fyl2x",
    "fptan",
    "fpatan",
    "fxtract",
    "fprem1",
    "fdecstp",
    "fincstp",
    "fprem",
    "fyl2xp1",
    "fsqrt",
    "fsincos",
    "frndint",
    "fscale",
    "fsin",
    "fcos",
};

PSTR DbgX87DAC0Instructions[8] = {
    "fcmovb",
    "fcmove",
    "fcmovbe",
    "fcmovu",
    NULL,
    NULL,
    NULL,
    NULL
};

PSTR DbgX87DBC0Instructions[8] = {
    "fcmovnb",
    "fcmovne",
    "fcmovnbe",
    "fcmovnu",
    NULL,
    "fucomi",
    "fcomi",
    NULL
};

PSTR DbgX87DBE0Instructions[8] = {
    "feni",
    "fdisi",
    "fclex",
    "finit",
    "fsetpm",
    "frstpm",
    NULL,
    NULL
};

PSTR DbgX87DCC0Instructions[8] = {
    "fadd",
    "fmul",
    "fcom",
    "fcomp",
    "fsubr",
    "fsub",
    "fdivr",
    "fdiv",
};

PSTR DbgX87DDC0Instructions[8] = {
    "ffree",
    "fxch",
    "fst",
    "fstp",
    "fucom",
    "fucomp",
    NULL,
    NULL,
};

PSTR DbgX87DEC0Instructions[8] = {
    "faddp",
    "fmulp",
    "fcomp",
    NULL,
    "fsubrp",
    "fsubp",
    "fdivrp",
    "fdivp",
};

PSTR DbgX87DFC0Instructions[8] = {
    "freep",
    "fxch",
    "fstp",
    "fstp",
    NULL,
    "fucomip",
    "fcomip",
    NULL,
};

PSTR DbgX87DFE0Instructions[X87_DF_E0_COUNT] = {
    "fstsw",
    "fstdw",
    "fstsg",
};

//
// Define the register name constants.
//

PSTR DbgX86ControlRegisterNames[X86_REGISTER_NAME_COUNT] = {
    "cr0",
    "cr1",
    "cr2",
    "cr3",
    "cr4",
    "cr5",
    "cr6",
    "cr7",
    "cr8",
    "cr9",
    "cr10",
    "cr11",
    "cr12",
    "cr13",
    "cr14",
    "cr15"
};

PSTR DbgX86DebugRegisterNames[X86_REGISTER_NAME_COUNT] = {
    "dr0",
    "dr1",
    "dr2",
    "dr3",
    "dr4",
    "dr5",
    "dr6",
    "dr7",
    "dr8",
    "dr9",
    "dr10",
    "dr11",
    "dr12",
    "dr13",
    "dr14",
    "dr15"
};

PSTR DbgX86SegmentRegisterNames[X86_REGISTER_NAME_COUNT] = {
    "es",
    "cs",
    "ss",
    "ds",
    "fs",
    "gs",
    "ERR",
    "ERR",
    "es",
    "cs",
    "ss",
    "ds",
    "fs",
    "gs",
    "ERR",
    "ERR"
};

//
// The 8 bit registers have different names in long mode. The first array here
// is for 32-bit mode, the second is for long mode.
//

PSTR DbgX86RegisterNames8Bit[2][X86_REGISTER_NAME_COUNT] = {
    {
        "al",
        "cl",
        "dl",
        "bl",
        "ah",
        "ch",
        "dh",
        "bh",
        "r8b",
        "r9b",
        "r10b",
        "r11b",
        "r12b",
        "r13b",
        "r14b",
        "r15b"
    },
    {
        "al",
        "cl",
        "dl",
        "bl",
        "spl",
        "bpl",
        "sil",
        "dil",
        "r8b",
        "r9b",
        "r10b",
        "r11b",
        "r12b",
        "r13b",
        "r14b",
        "r15b"
    }
};

PSTR DbgX86RegisterNames16Bit[X86_REGISTER_NAME_COUNT] = {
    "ax",
    "cx",
    "dx",
    "bx",
    "sp",
    "bp",
    "si",
    "di",
    "r8w",
    "r9w",
    "r10w",
    "r11w",
    "r12w",
    "r13w",
    "r14w",
    "r15w"
};

PSTR DbgX86RegisterNames32Bit[X86_REGISTER_NAME_COUNT] = {
    "eax",
    "ecx",
    "edx",
    "ebx",
    "esp",
    "ebp",
    "esi",
    "edi",
    "r8d",
    "r9d",
    "r10d",
    "r11d",
    "r12d",
    "r13d",
    "r14d",
    "r15d"
};

PSTR DbgX86RegisterNames64Bit[X86_REGISTER_NAME_COUNT] = {
    "rax",
    "rcx",
    "rdx",
    "rbx",
    "rsp",
    "rbp",
    "rsi",
    "rdi",
    "r8",
    "r9",
    "r10",
    "r11",
    "r12",
    "r13",
    "r14",
    "r15"
};

PSTR DbgX87RegisterNames[X86_REGISTER_NAME_COUNT] = {
    "st(0)",
    "st(1)",
    "st(2)",
    "st(3)",
    "st(4)",
    "st(5)",
    "st(6)",
    "st(7)",
    "ERR",
    "ERR",
    "ERR",
    "ERR",
    "ERR",
    "ERR",
    "ERR",
    "ERR"
};

PSTR DbgX86MmxRegisterNames[X86_REGISTER_NAME_COUNT] = {
    "mmx0",
    "mmx1",
    "mmx2",
    "mmx3",
    "mmx4",
    "mmx5",
    "mmx6",
    "mmx7",
    "mmx8",
    "mmx9",
    "mmx10",
    "mmx11",
    "mmx12",
    "mmx13",
    "mmx14",
    "mmx15"
};

PSTR DbgX86XmmRegisterNames[X86_REGISTER_NAME_COUNT] = {
    "xmm0",
    "xmm1",
    "xmm2",
    "xmm3",
    "xmm4",
    "xmm5",
    "xmm6",
    "xmm7",
    "xmm8",
    "xmm9",
    "xmm10",
    "xmm11",
    "xmm12",
    "xmm13",
    "xmm14",
    "xmm15"
};

PSTR DbgX86YmmRegisterNames[X86_REGISTER_NAME_COUNT] = {
    "ymm0",
    "ymm1",
    "ymm2",
    "ymm3",
    "ymm4",
    "ymm5",
    "ymm6",
    "ymm7",
    "ymm8",
    "ymm9",
    "ymm10",
    "ymm11",
    "ymm12",
    "ymm13",
    "ymm14",
    "ymm15"
};

//
// ----------------------------------------------- Internal Function Prototypes
//

BOOL
DbgpX86PrintOperand (
    ULONGLONG InstructionPointer,
    PX86_INSTRUCTION Instruction,
    PSTR OperandFormat,
    PSTR Operand,
    ULONG BufferLength,
    PULONGLONG Address,
    PBOOL AddressValid
    );

PSTR
DbgpX86PrintMnemonic (
    PX86_INSTRUCTION Instruction
    );

BOOL
DbgpX86GetInstructionComponents (
    PBYTE InstructionStream,
    PX86_INSTRUCTION Instruction
    );

BOOL
DbgpX86GetInstructionParameters (
    PBYTE InstructionStream,
    PX86_INSTRUCTION Instruction,
    PBOOL ModRmExists,
    PBOOL SibExists,
    PULONG DisplacementSize,
    PULONG ImmediateSize
    );

PSTR
DbgpX86RegisterName (
    PX86_INSTRUCTION Instruction,
    X86_REGISTER_VALUE RegisterNumber,
    CHAR Type
    );

INT
DbgpX86GetDisplacement (
    PX86_INSTRUCTION Instruction,
    PSTR Buffer,
    ULONG BufferLength,
    PLONGLONG DisplacementValue
    );

PX86_INSTRUCTION_DEFINITION
DbgpX86GetTwoByteInstruction (
    PX86_INSTRUCTION Instruction
    );

BOOL
DbgpX86DecodeFloatingPointInstruction (
    PX86_INSTRUCTION Instruction
    );

//
// ------------------------------------------------------------------ Functions
//

BOOL
DbgpX86Disassemble (
    ULONGLONG InstructionPointer,
    PBYTE InstructionStream,
    PSTR Buffer,
    ULONG BufferLength,
    PDISASSEMBLED_INSTRUCTION Disassembly,
    MACHINE_LANGUAGE Language
    )

/*++

Routine Description:

    This routine decodes one instruction from an IA-32 binary instruction
    stream into a human readable form.

Arguments:

    InstructionPointer - Supplies the instruction pointer for the start of the
        instruction stream.

    InstructionStream - Supplies a pointer to the binary instruction stream.

    Buffer - Supplies a pointer to the buffer where the human
        readable strings will be printed. This buffer must be allocated by the
        caller.

    BufferLength - Supplies the length of the supplied buffer.

    Disassembly - Supplies a pointer to the structure that will receive
        information about the instruction.

    Language - Supplies the type of machine langage being decoded.

Return Value:

    TRUE on success.

    FALSE if the instruction was unknown.

--*/

{

    ULONGLONG Address;
    BOOL AddressValid;
    X86_INSTRUCTION Instruction;
    INT Length;
    PSTR Mnemonic;
    BOOL Result;
    PSTR ThirdOperandFormat;
    CHAR WorkingBuffer[X86_WORKING_BUFFER_SIZE];

    if ((Disassembly == NULL) || (Buffer == NULL)) {
        return FALSE;
    }

    memset(Buffer, 0, BufferLength);
    memset(Disassembly, 0, sizeof(DISASSEMBLED_INSTRUCTION));
    memset(&Instruction, 0, sizeof(X86_INSTRUCTION));
    Instruction.Language = Language;
    Instruction.InstructionPointer = InstructionPointer;

    //
    // Dissect the instruction into more managable components.
    //

    Result = DbgpX86GetInstructionComponents(InstructionStream, &Instruction);
    if (Result == FALSE) {
        goto DisassembleEnd;
    }

    Disassembly->BinaryLength = Instruction.Length;

    //
    // Print the mnemonic.
    //

    Mnemonic = DbgpX86PrintMnemonic(&Instruction);
    if ((Mnemonic == NULL) || (strlen(Mnemonic) >= BufferLength)) {
        Result = FALSE;
        goto DisassembleEnd;
    }

    //
    // Copy the mnemonic into the buffer, and advance the buffer to the next
    // free spot.
    //

    Length = snprintf(Buffer,
                      BufferLength,
                      "%s%s%s",
                      Instruction.Lock,
                      Instruction.Rep,
                      Mnemonic);

    if (Length < 0) {
        Result = FALSE;
        goto DisassembleEnd;
    }

    Disassembly->Mnemonic = Buffer;
    Buffer += Length + 1;
    BufferLength -= Length + 1;

    //
    // Get the destination operand.
    //

    WorkingBuffer[0] = '\0';
    Result = DbgpX86PrintOperand(InstructionPointer,
                                 &Instruction,
                                 Instruction.Definition.Target,
                                 WorkingBuffer,
                                 sizeof(WorkingBuffer),
                                 &Address,
                                 &AddressValid);

    if ((Result == FALSE) ||
        (strlen(WorkingBuffer) >= BufferLength)) {

        Result = FALSE;
        goto DisassembleEnd;
    }

    //
    // If an address came out of that, plug it into the result.
    //

    if (AddressValid != FALSE) {
        Disassembly->OperandAddress = Address;
        Disassembly->AddressIsValid = TRUE;
        Disassembly->AddressIsDestination = TRUE;
    }

    //
    // Copy the operand into the buffer, and advance the buffer.
    //

    Disassembly->DestinationOperand = Buffer;
    strncpy(Disassembly->DestinationOperand, WorkingBuffer, BufferLength);
    Buffer += strlen(WorkingBuffer) + 1;
    BufferLength -= strlen(WorkingBuffer) + 1;

    //
    // Get the source operand.
    //

    WorkingBuffer[0] = '\0';
    Result = DbgpX86PrintOperand(InstructionPointer,
                                 &Instruction,
                                 Instruction.Definition.Source,
                                 WorkingBuffer,
                                 sizeof(WorkingBuffer),
                                 &Address,
                                 &AddressValid);

    if ((Result == FALSE) || (strlen(WorkingBuffer) >= BufferLength)) {
        Result = FALSE;
        goto DisassembleEnd;
    }

    //
    // If an address came out of the operand, plug it into the result.
    //

    if (AddressValid != FALSE) {
         Disassembly->OperandAddress = Address;
         Disassembly->AddressIsValid = TRUE;
         Disassembly->AddressIsDestination = FALSE;
    }

    //
    // Copy the operand into the buffer, and advance the buffer.
    //

    if (WorkingBuffer[0] != '\0') {
        Disassembly->SourceOperand = Buffer;
        strncpy(Disassembly->SourceOperand, WorkingBuffer, BufferLength);
        Buffer += strlen(WorkingBuffer) + 1;
        BufferLength -= strlen(WorkingBuffer) + 1;
    }

    //
    // Handle the third operand.
    //

    ThirdOperandFormat = Instruction.Definition.Third;
    if ((ThirdOperandFormat != NULL) && (*ThirdOperandFormat != '\0')) {
        WorkingBuffer[0] = '\0';
        Result = DbgpX86PrintOperand(InstructionPointer,
                                     &Instruction,
                                     ThirdOperandFormat,
                                     WorkingBuffer,
                                     sizeof(WorkingBuffer),
                                     &Address,
                                     &AddressValid);

        if ((Result == FALSE) || (strlen(WorkingBuffer) > BufferLength)) {
            Result = FALSE;
            goto DisassembleEnd;
        }

        //
        // If the second operand is empty, take over its slot.
        //

        if (Disassembly->SourceOperand == NULL) {
            Disassembly->SourceOperand = Buffer;

        } else {
            Disassembly->ThirdOperand = Buffer;
        }

        strncpy(Buffer, WorkingBuffer, BufferLength);
    }

DisassembleEnd:
    return Result;
}

//
// --------------------------------------------------------- Internal Functions
//

BOOL
DbgpX86PrintOperand (
    ULONGLONG InstructionPointer,
    PX86_INSTRUCTION Instruction,
    PSTR OperandFormat,
    PSTR Operand,
    ULONG BufferLength,
    PULONGLONG Address,
    PBOOL AddressValid
    )

/*++

Routine Description:

    This routine prints an operand in an IA instruction stream depending on the
    supplied format.

Arguments:

    InstructionPointer - Supplies the instruction pointer for the instruction
        being disassembled.

    Instruction - Supplies a pointer to the instruction structure.

    OperandFormat - Supplies the format of the operand in two or more
        characters. These are largely compatible with the Intel Opcode
        Encodings, except for the ! prefix, which indicates an absolute
        register name.

    Operand - Supplies a pointer to the string that will receive the human
        readable operand.

    BufferLength - Supplies the length of the supplied buffer.

    Address - Supplies a pointer that receives the memory address encoded in the
        operand.

    AddressValid - Supplies a pointer that receives whether or not the value
        store in the Address parameter is valid.

Return Value:

    TRUE on success.

    FALSE on failure.

--*/

{

    PSTR Base;
    BYTE BaseValue;
    PSTR Index;
    BYTE IndexValue;
    INT Length;
    X86_MOD_VALUE Mod;
    PSTR RegisterString;
    UCHAR Rm;
    ULONG Scale;
    CHAR Type;
    CHAR Width;

    Base = NULL;
    Index = NULL;
    IndexValue = 0xFF;
    Scale = 0;
    RegisterString = NULL;

    //
    // Start by doing some parameter checking.
    //

    if ((Operand == NULL) || (BufferLength == 0)) {
        return FALSE;
    }

    Operand[0] = '\0';
    *Address = 0ULL;
    *AddressValid = FALSE;
    if (*OperandFormat == '\0') {
        return TRUE;
    }

    Type = OperandFormat[0];
    Width = OperandFormat[1];

    //
    // 'd' means dword, which gets translated to long here for simplicity.
    //

    switch (Width) {
    case 'd':
        Width = X86_WIDTH_LONG;
        break;

    case '\0':
    case 's':
    case 'p':
        Width = X86_WIDTH_LONG;
        if (Instruction->Language == MachineLanguageX64) {
            Width = X86_WIDTH_LONGLONG;
        }

        break;

    case 'y':
        Width = X86_WIDTH_LONG;
        if ((Instruction->Rex & X64_REX_W) != 0) {
            Width = X86_WIDTH_LONGLONG;
        }

        break;

    //
    // If the width is variable, it is probably a dword unless an override is
    // specified.
    //

    case 'v':
    case 'z':

        //
        // A few instructions default to 64-bits in long mode.
        //

        if ((Instruction->Language == MachineLanguageX64) &&
            (OperandFormat[2] == '6')) {

            Width = X86_WIDTH_LONGLONG;
            if (Instruction->OperandOverride != FALSE) {
                Width = X86_WIDTH_WORD;
            }

        } else if ((Instruction->Rex & X64_REX_W) != 0) {
            if (Width == 'v') {
                Width = X86_WIDTH_LONGLONG;

            } else {
                Width = X86_WIDTH_LONG;
            }

        } else {
            Width = X86_WIDTH_LONG;
            if ((Instruction->OperandOverride == TRUE) ||
                (Instruction->AddressOverride == TRUE)) {

                Width = X86_WIDTH_WORD;
            }
        }

        break;

    case 'u':
        Width = X86_WIDTH_YWORD;
        if (Instruction->OperandOverride != FALSE) {
            Width = X86_WIDTH_ZWORD;
        }

        break;

    case 'x':
        Width = X86_WIDTH_OWORD;
        if ((Instruction->Vex & X64_VEX_L) != 0) {
            Width = X86_WIDTH_YWORD;
        }

        break;

    //
    // An unknown width specifier.
    //

    default:
        break;
    }

    switch (Type) {

    //
    // The ! encoding indicates that a register is hardcoded.
    //

    case '!':

        //
        // If the width is 'e', then it's a hardcoded string.
        //

        if (Width == 'e') {
            strncpy(Operand, OperandFormat + 2, BufferLength);

        //
        // An r indicates a register corresponding to the current mode. These
        // encode a register number as an ASCII number.
        //

        } else if ((OperandFormat[2] >= '0') && (OperandFormat[2] <= '7')) {
            if (Width == 'r') {
                if (Instruction->OperandOverride != FALSE) {
                    Width = X86_WIDTH_WORD;

                } else if ((Instruction->Language == MachineLanguageX64) &&
                           (OperandFormat[3] == '6')) {

                    Width = X86_WIDTH_LONGLONG;

                } else {
                    Width = X86_WIDTH_LONG;
                    if ((Instruction->Rex & X64_REX_W) != 0) {
                        Width = X86_WIDTH_LONGLONG;
                    }
                }
            }

            Rm = OperandFormat[2] - '0';
            Rm = X86_MODRM_RM(Instruction, Rm);
            strncpy(Operand,
                    DbgpX86RegisterName(Instruction, Rm, Width),
                    BufferLength);

        //
        // Otherwise it's something like wcs or bal, with a width and register.
        //

        } else {
            strncpy(Operand, OperandFormat + 2, BufferLength);
        }

        break;

    //
    // A - Direct address, no mod R/M byte; address of operand is encoded in
    // instruction. No base, index, or scaling can be applied.
    //

    case 'A':
        snprintf(Operand,
                 BufferLength,
                 "%s[0x%llx]",
                 Instruction->SegmentPrefix,
                 Instruction->Immediate);

        *Address = Instruction->Immediate;
        *AddressValid = TRUE;
        break;

    //
    // C - Reg field of mod R/M byte selects a control register.
    // D - Reg field of mod R/M byte selects a debug register.
    // S - Reg field of ModR/M byte selects a segment register.
    //

    case 'C':
    case 'D':
    case 'S':
        RegisterString = DbgpX86RegisterName(
                                Instruction,
                                X86_MODRM_REG(Instruction, Instruction->ModRm),
                                Type);

        strncpy(Operand, RegisterString, BufferLength);
        break;

    //
    // V - XMM/YMM register specified by ModRM.reg.
    //

    case 'V':
        RegisterString = DbgpX86RegisterName(
                                Instruction,
                                X86_MODRM_REG(Instruction, Instruction->ModRm),
                                Width);

        strncpy(Operand, RegisterString, BufferLength);
        break;

    //
    // H - XMM/YMM register specified by VEX/VOP.vvvv field, if one is present.
    //

    case 'H':
        if (Instruction->VexMap != 0) {
            Rm = X64_VEX_V(Instruction->Vex);
            RegisterString = DbgpX86RegisterName(Instruction, Rm, Width);
            strncpy(Operand, RegisterString, BufferLength);
        }

        break;

    //
    // E - Mod R/M bytes follows opcode and specifies operand. Operand is either
    // a general register or a memory address. If it is a memory address, the
    // address is computed from a segment register and any of the following
    // values: a base register, an index register, a scaling factor, and a
    // displacement.
    // M - Mod R/M byte may only refer to memory.
    // W - XMM/YMM register or memory operand.
    //

    case 'E':
    case 'M':
    case 'W':
        Mod = X86_MODRM_MOD(Instruction->ModRm);
        Rm = X86_MODRM_RM(Instruction, Instruction->ModRm);
        if (Mod == X86ModValueRegister) {
            if (Type == 'M') {
                return FALSE;
            }

            RegisterString = DbgpX86RegisterName(Instruction, Rm, Width);

        } else {

            //
            // Memory accesses only happen via general registers. Convert larger
            // memory references into native ones.
            //

            if ((Width == X86_WIDTH_OWORD) || (Width == X86_WIDTH_YWORD) ||
                (Width == X86_WIDTH_ZWORD)) {

                Width = X86_WIDTH_LONG;
                if (Instruction->Language == MachineLanguageX64) {
                    Width = X86_WIDTH_LONGLONG;
                }
            }

            //
            // An R/M value of 4 actually indicates an SIB byte is present, not
            // ESP. The REX extension bit doesn't matter here.
            //

            if (X86_BASIC_REG(Rm) == X86RegisterValueSp) {
                Rm = X86RegisterValueScaleIndexBase;
                BaseValue = X86_SIB_BASE(Instruction);
                IndexValue = X86_SIB_INDEX(Instruction);
                Scale = X86_SIB_SCALE(Instruction);
                Base = DbgpX86RegisterName(Instruction, BaseValue, Width);
                Index = DbgpX86RegisterName(Instruction, IndexValue, Width);

                //
                // A base value of 5 (ebp) indicates that the base field is not
                // used, and a displacement is present. The Mod field then
                // specifies the size of the displacement.
                //

                if (X86_BASIC_REG(BaseValue) == X86RegisterValueBp) {
                    Base = "";
                    Length = snprintf(Operand,
                                      BufferLength,
                                      "0x%llx",
                                      Instruction->Displacement);

                    if (Length <= 0) {
                        return FALSE;
                    }

                    Operand += Length;
                    BufferLength -= Length;
                }

            } else if ((Mod == X86ModValueNoDisplacement) &&
                       (X86_BASIC_REG(Rm) == X86RegisterValueBp)) {

                Rm = X86RegisterValueDisplacement32;
                if (Instruction->Language == MachineLanguageX64) {
                    Rm = X86RegisterValueRipRelative;
                }

            } else {
                RegisterString = DbgpX86RegisterName(Instruction, Rm, Width);
            }
        }

        //
        // The operand is simply a register.
        //

        if (Mod == X86ModValueRegister) {
            strncpy(Operand, RegisterString, BufferLength);

        //
        // The operand is an address with a scale/index/base.
        //

        } else if (Rm == X86RegisterValueScaleIndexBase) {
            Length = snprintf(Operand,
                              BufferLength,
                              "%s[%s",
                              Instruction->SegmentPrefix,
                              Base);

            if ((Length <= 0) || (BufferLength - Length <= 3)) {
                return FALSE;
            }

            Operand += Length;
            BufferLength -= Length;

            //
            // An index of 4 indicates that the index and scale fields are not
            // used.
            //

            if (IndexValue != 4) {
                if (*Base != '\0') {
                    *Operand = '+';
                    Operand += 1;
                    BufferLength -= 1;
                }

                Length = snprintf(Operand, BufferLength, "%s*%d", Index, Scale);
                if (Length <= 0) {
                    return FALSE;
                }

                Operand += Length;
                BufferLength -= Length;
            }

            Length = DbgpX86GetDisplacement(Instruction,
                                            Operand,
                                            BufferLength,
                                            NULL);

            if ((Length < 0) || (BufferLength - Length <= 2)) {
                return FALSE;
            }

            Operand[Length] = ']';
            Operand += Length + 1;
            BufferLength -= Length + 1;
            *Operand = '\0';

        //
        // The operand is a 32-bit address.
        //

        } else if (Rm == X86RegisterValueDisplacement32) {
            Length = snprintf(Operand,
                              BufferLength,
                              "%s[0x%llx]",
                              Instruction->SegmentPrefix,
                              Instruction->Displacement);

            if (Length <= 0) {
                return FALSE;
            }

            *Address = Instruction->Displacement;
            *AddressValid = TRUE;

        //
        // The operand is an address in a register, possibly with some
        // additional displacement.
        //

        } else {

            //
            // The register could be RIP in the long-mode-only RIP-relative
            // addressing.
            //

            if (Rm == X86RegisterValueRipRelative) {
                RegisterString = "rip";
                if (Instruction->AddressOverride != FALSE) {
                    RegisterString = "eip";
                }

                *Address = Instruction->InstructionPointer +
                           Instruction->Length +
                           (LONG)(Instruction->Displacement);

                *AddressValid = TRUE;
            }

            Length = snprintf(Operand,
                              BufferLength,
                              "%s[%s",
                              Instruction->SegmentPrefix,
                              RegisterString);

            if (Length <= 0) {
                return FALSE;
            }

            Operand += Length;
            BufferLength -= Length;
            Length = DbgpX86GetDisplacement(Instruction,
                                            Operand,
                                            BufferLength,
                                            NULL);

            if ((Length < 0) || (BufferLength - Length <= 2)) {
                return FALSE;
            }

            Operand[Length] = ']';
            Operand += Length + 1;
            BufferLength -= Length + 1;
            *Operand = '\0';
        }

    break;

    //
    // G - Reg field of Mod R/M byte selects a general register.
    //

    case 'G':
        Rm = X86_MODRM_REG(Instruction, Instruction->ModRm);
        strncpy(Operand,
                DbgpX86RegisterName(Instruction, Rm, Width),
                BufferLength);

        break;

    //
    // I - Immediate data: value of operand is encoded in Immediate field.
    // O - Direct offset: no ModR/M byte. Offset of operand is encoded in
    // instruction. No Base/Index/Scale can be applied.
    //

    case 'I':
    case 'O':
        snprintf(Operand, BufferLength, "0x%llx", Instruction->Immediate);
        break;

    //
    // J - Instruction contains a relative offset to be added to the instruction
    // pointer.
    //

    case 'J':
        DbgpX86GetDisplacement(Instruction,
                               Operand,
                               BufferLength,
                               (PLONGLONG)Address);

        *Address += (InstructionPointer + Instruction->Length);
        snprintf(Operand,
                 BufferLength,
                 "%s[0x%llx]",
                 Instruction->SegmentPrefix,
                 *Address);

        *AddressValid = TRUE;
        break;

    //
    // R - R/M field of modR/M byte selects a general register. Mod field should
    // be set to 11.
    // U - XMM/YMM register specified by ModRM.rm with mod set to 11.
    //

    case 'R':
    case 'U':
        Mod = X86_MODRM_MOD(Instruction->ModRm);
        Rm = X86_MODRM_RM(Instruction, Instruction->ModRm);
        if (Mod != X86ModValueRegister) {
            return FALSE;
        }

        strncpy(Operand,
                DbgpX86RegisterName(Instruction, Rm, Width),
                BufferLength);

        break;

    //
    // X - Memory addressed by DS:SI register pair (eg. MOVS CMPS, OUTS, LODS).
    //

    case 'X':
        RegisterString = DbgpX86RegisterName(Instruction,
                                             X86RegisterValueSi,
                                             X86_WIDTH_LONG);

        snprintf(Operand, BufferLength, "ds:[%s]", RegisterString);
        break;

    //
    // Y - Memory addressed by ES:DI register pair (eg. MOVS INS, STOS, SCAS).
    //

    case 'Y':
        RegisterString = DbgpX86RegisterName(Instruction,
                                             X86RegisterValueDi,
                                             X86_WIDTH_LONG);

        snprintf(Operand, BufferLength, "ds:[%s]", RegisterString);
        break;

    default:
        return FALSE;
    }

    return TRUE;
}

PSTR
DbgpX86PrintMnemonic (
    PX86_INSTRUCTION Instruction
    )

/*++

Routine Description:

    This routine prints an instruction mnemonic.

Arguments:

    Instruction - Supplies a pointer to the instruction structure.

Return Value:

    A pointer to the mnemonic on success.

    NULL on failure.

--*/

{

    PX86_OPCODE_GROUP OpcodeGroup;
    BYTE RegByte;

    if (Instruction == NULL) {
        return NULL;
    }

    if (Instruction->Definition.Group == 0) {
        return Instruction->Definition.Mnemonic;
    }

    assert(Instruction->Definition.Group != X86_INVALID_GROUP);

    RegByte = (Instruction->ModRm & X86_REG_MASK) >> X86_REG_SHIFT;
    OpcodeGroup = &(DbgX86OpcodeGroups[0]);
    while (OpcodeGroup->Group != 0) {
        if (OpcodeGroup->Group == Instruction->Definition.Group) {
            return OpcodeGroup->Mnemonics[RegByte];
        }

        OpcodeGroup += 1;
    }

    assert(FALSE);

    return NULL;
}

BOOL
DbgpX86GetInstructionComponents (
    PBYTE InstructionStream,
    PX86_INSTRUCTION Instruction
    )

/*++

Routine Description:

    This routine reads an instruction stream and decomposes it into its
    respective components.

Arguments:

    InstructionStream - Supplies a pointer to the raw binary instruction stream.

    Instruction - Supplies a pointer to the structure that will accept the
        instruction decomposition.

Return Value:

    TRUE on success.

    FALSE otherwise.

--*/

{

    ULONG AlternateCount;
    ULONG AlternateIndex;
    ULONG Base;
    PBYTE Beginning;
    ULONG DisplacementSize;
    ULONG Group;
    ULONG ImmediateSize;
    ULONG Mod;
    BOOL ModRmExists;
    UCHAR Opcode3;
    INT PrefixIndex;
    BYTE RegByte;
    BOOL Result;
    BOOL SibExists;
    PX86_INSTRUCTION_DEFINITION TopLevelDefinition;
    PX86_INSTRUCTION_DEFINITION TwoByteInstruction;

    if (Instruction == NULL) {
        return FALSE;
    }

    Beginning = InstructionStream;
    Result = TRUE;

    //
    // Begin by handling any prefixes. The prefixes are: F0 (LOCK), F2 (REP),
    // F3 (REP), 2E (CS), 36 (SS), 3E (DS), 26 (ES), 64 (FS), 65 (GS),
    // 66 (Operand-size override), 67 (Address-size override)).
    //

    Instruction->Lock = "";
    Instruction->Rep = "";
    Instruction->SegmentPrefix = "";
    for (PrefixIndex = 0; PrefixIndex < X86_MAX_PREFIXES; PrefixIndex += 1) {
        switch (*InstructionStream) {
        case X86_PREFIX_LOCK:
            Instruction->Lock = "lock ";
            break;

        case X86_PREFIX_REPN:
            Instruction->Rep = "repne ";
            break;

        case X86_PREFIX_REP:
            Instruction->Rep = "rep ";
            break;

        case X86_PREFIX_CS:
            if (Instruction->Language != MachineLanguageX64) {
                Instruction->SegmentPrefix = "cs:";
            }

            break;

        case X86_PREFIX_DS:
            if (Instruction->Language != MachineLanguageX64) {
                Instruction->SegmentPrefix = "ds:";
            }

            break;

        case X86_PREFIX_ES:
            Instruction->SegmentPrefix = "es:";
            break;

        case X86_PREFIX_FS:
            Instruction->SegmentPrefix = "fs:";
            break;

        case X86_PREFIX_GS:
            Instruction->SegmentPrefix = "gs:";
            break;

        case X86_PREFIX_SS:
            Instruction->SegmentPrefix = "ss:";
            break;

        case X86_OPERAND_OVERRIDE:
            Instruction->OperandOverride = TRUE;
            break;

        case X86_ADDRESS_OVERRIDE:
            Instruction->AddressOverride = TRUE;
            break;

        default:
            PrefixIndex = X86_MAX_PREFIXES;
            break;
        }

        if (PrefixIndex == X86_MAX_PREFIXES) {
            break;
        }

        Instruction->Prefix[PrefixIndex] = *InstructionStream;
        InstructionStream += 1;
        Instruction->Length += 1;
    }

    //
    // Grab the REX prefix for x64, which has to go right before the
    // instruction opcode.
    //

    if (Instruction->Language == MachineLanguageX64) {
        if ((*InstructionStream & X64_REX_MASK) == X64_REX_VALUE) {
            Instruction->Rex = *InstructionStream;
            InstructionStream += 1;
            Instruction->Length += 1;

        //
        // Look for the 2-byte VEX prefix. Convert it to a 3 byte prefix.
        //

        } else if (*InstructionStream == X64_VEX2) {
            InstructionStream += 1;
            Instruction->Length += 1;
            Instruction->Vex = *InstructionStream;
            Instruction->VexMap = X64_VEX2_MAP_SELECT |
                                  (Instruction->Vex & 0x80);

            Instruction->Vex &= 0x7F;
            InstructionStream += 1;
            Instruction->Length += 1;
            Instruction->Rex = X64_VEX_TO_REX(Instruction->Vex,
                                              Instruction->VexMap);

        //
        // Look for the 3 byte VEX/XOP prefix.
        //

        } else if ((*InstructionStream == X64_VEX3) ||
                   (*InstructionStream == X64_XOP)) {

            InstructionStream += 1;
            Instruction->Length += 1;
            Instruction->VexMap = *InstructionStream;
            InstructionStream += 1;
            Instruction->Length += 1;
            Instruction->Vex = *InstructionStream;
            InstructionStream += 1;
            Instruction->Length += 1;
            Instruction->Rex = X64_VEX_TO_REX(Instruction->Vex,
                                              Instruction->VexMap);
        }
    }

    Instruction->Opcode = *InstructionStream;
    Instruction->Length += 1;
    InstructionStream += 1;

    //
    // Check for a two byte opcode.
    //

    if (Instruction->Opcode == X86_ESCAPE_OPCODE) {
        Instruction->Opcode2 = *InstructionStream;
        Instruction->Length += 1;
        InstructionStream += 1;
        TwoByteInstruction = DbgpX86GetTwoByteInstruction(Instruction);
        if (TwoByteInstruction == NULL) {
            Result = FALSE;
            goto GetInstructionComponentsEnd;
        }

        TopLevelDefinition = TwoByteInstruction;

    } else {
        TopLevelDefinition = &(DbgX86Instructions[Instruction->Opcode]);
    }

    //
    // Modify the instruction definition for groups. If the opcode is in a
    // group, then it must have a modR/M byte, so cheat a little and get it.
    //

    Instruction->Definition = *TopLevelDefinition;
    Group = Instruction->Definition.Group;
    if ((Group != 0) && (Group != X86_INVALID_GROUP)) {
        RegByte = (*InstructionStream & X86_REG_MASK) >> X86_REG_SHIFT;
        switch (Group) {
        case 3:
            if (RegByte <= 1) {
                if (Instruction->Opcode == 0xF6) {
                    Instruction->Definition.Source = "Ib";

                } else {

                    assert(Instruction->Opcode == 0xF7);

                    Instruction->Definition.Source = "Iz";
                }
            }

            break;

        case 7:

            //
            // There are a bunch of alternate encoding instructions hidden
            // behind 0F 01, go look for them.
            //

            if (RegByte == 1) {
                Opcode3 = *InstructionStream;
                AlternateCount = sizeof(DbgX860F01Alternates) /
                                 sizeof(DbgX860F01Alternates[0]);

                for (AlternateIndex = 0;
                     AlternateIndex < AlternateCount;
                     AlternateIndex += 1) {

                    if (DbgX860F01Alternates[AlternateIndex].Opcode ==
                        Opcode3) {

                        Instruction->Definition =
                              DbgX860F01Alternates[AlternateIndex].Instruction;

                        break;
                    }
                }
            }

            break;

        default:
            break;
        }
    }

    //
    // Get the structure of the instruction.
    //

    Result = DbgpX86GetInstructionParameters(InstructionStream,
                                             Instruction,
                                             &ModRmExists,
                                             &SibExists,
                                             &DisplacementSize,
                                             &ImmediateSize);

    if (Result == FALSE) {
        goto GetInstructionComponentsEnd;
    }

    if (Group != 0) {
        ModRmExists = TRUE;
    }

    //
    // Populate the various pieces of the instruction.
    //

    Instruction->DisplacementSize = DisplacementSize;
    Instruction->ImmediateSize = ImmediateSize;
    if (ModRmExists == TRUE) {
        Instruction->ModRm = *InstructionStream;
        InstructionStream += 1;
    }

    if (SibExists == TRUE) {
        Instruction->Sib = *InstructionStream;
        InstructionStream += 1;

        //
        // Check to see if the SIB byte requires a displacement. EBP is not a
        // valid base, since that can be specified in the Mod bits.
        //

        Base = (Instruction->Sib & X86_BASE_MASK) >> X86_BASE_SHIFT;
        Mod = X86_MODRM_MOD(Instruction->ModRm);
        if (Base == X86RegisterValueBp) {
            if (Mod == X86ModValueDisplacement8) {
                DisplacementSize = 1;

            } else {
                DisplacementSize = 4;
            }
        }
    }

    //
    // Grab the displacement and immediates from the instruction stream if
    // they're there.
    //

    if (DisplacementSize != 0) {
        memcpy(&(Instruction->Displacement),
               InstructionStream,
               DisplacementSize);

        InstructionStream += DisplacementSize;
    }

    if (ImmediateSize != 0) {
        memcpy(&(Instruction->Immediate), InstructionStream, ImmediateSize);
        InstructionStream += ImmediateSize;
    }

    Instruction->Length = InstructionStream - Beginning;

    //
    // If it's an x87 floating point instruction, decode it now that the
    // ModR/M byte was grabbed.
    //

    if (Group == 0x87) {
        Result = DbgpX86DecodeFloatingPointInstruction(Instruction);
        if (Result == FALSE) {
            goto GetInstructionComponentsEnd;
        }
    }

GetInstructionComponentsEnd:
    return Result;
}

BOOL
DbgpX86GetInstructionParameters (
    PBYTE InstructionStream,
    PX86_INSTRUCTION Instruction,
    PBOOL ModRmExists,
    PBOOL SibExists,
    PULONG DisplacementSize,
    PULONG ImmediateSize
    )

/*++

Routine Description:

    This routine determines the format of the rest of the instruction based on
    the opcode, any prefixes, and possibly the ModRM byte.

Arguments:

    InstructionStream - Supplies a pointer to the binary instruction stream,
        after the prefixes and opcode.

    Instruction - Supplies a pointer to an instruction. The Prefixes, Opcode,
        and Definition must be filled out.

    ModRmExists - Supplies a pointer where a boolean will be returned
        indicating whether or not a ModRM byte is present.

    SibExists - Supplies a pointer where a boolean will be returned indicating
        whether or not a Scale/Index/Base byte is present in the instruction
        stream.

    DisplacementSize - Supplies a pointer where the size of the Displacement
        value will be returned. 0 indicates there is no displacement in the
        instruction.

    ImmediateSize - Supplies a pointer where  the size of the Immediate field
        in the instruction will be returned. 0 indicates there is no Immediate
        field in the instruction.

Return Value:

    TRUE on success.

    FALSE otherwise.

--*/

{

    X86_MOD_VALUE Mod;
    BYTE ModRm;
    ULONG ParseCount;
    BYTE RmValue;
    CHAR Type;
    CHAR Width;

    *ModRmExists = FALSE;
    *SibExists = FALSE;
    *DisplacementSize = 0;
    *ImmediateSize = 0;
    if (Instruction->Definition.Target[0] == '\0') {
        return TRUE;
    }

    Type = Instruction->Definition.Target[0];
    Width = Instruction->Definition.Target[1];
    ParseCount = 0;
    do {
        switch (Type) {

        //
        // A - Direct address. No Mod/RM, Immediate specifies address. No SIB.
        //

        case 'A':
            *ImmediateSize = 4;
            break;

        //
        // C - Control register in ModR/M.
        // D - Debug register in ModR/M.
        // S - Segment register in Reg field of ModR/M.
        // T - Test register in ModR/M.
        // V - SIMD floating point register in ModR/M.
        //

        case 'C':
        case 'D':
        case 'S':
        case 'T':
        case 'V':
            *ModRmExists = TRUE;
            break;

       //
       // E - Mod R/M bytes follows opcode and specifies operand. Operand is
       // either a general register or a memory address. If it is a memory
       // address, the address is computed from a segment register and any of
       // the following values: a base register, an index register, a scaling
       // factor, and a displacement.
       // M - Mod R/M byte may only refer to memory.
       // R - Mod R/M byte may only refer to a general register.
       // W - XMM/YMM register or memory operand.
       // U - XMM/YMM register specified by ModRM.rm with mod set to 11.
       //

        case 'E':
        case 'M':
        case 'R':
        case 'U':
        case 'W':
            *ModRmExists = TRUE;
            ModRm = *InstructionStream;
            Mod = X86_MODRM_MOD(ModRm);
            RmValue = (ModRm & X86_RM_MASK) >> X86_RM_SHIFT;
            if (Mod != X86ModValueRegister) {

                //
                // An R/M value of 4 actually indicates an SIB byte is present,
                // not ESP.
                //

                if (RmValue == X86RegisterValueSp) {
                    RmValue = X86RegisterValueScaleIndexBase;
                    *SibExists = TRUE;
                }

                //
                // An R/M value of 5 when Mod is 0 means that the address is
                // actually just a 32bit displacment.
                //

                if ((Mod == X86ModValueNoDisplacement) &&
                    (RmValue == X86RegisterValueBp)) {

                    RmValue = X86RegisterValueDisplacement32;
                    *DisplacementSize = 4;
                }
            }

            //
            // Get any displacements as specified by the MOD bits.
            //

            if (Mod == X86ModValueDisplacement8) {
                *DisplacementSize = 1;

            } else if (Mod == X86ModValueDisplacement32) {
                *DisplacementSize = 4;
            }

            break;

        //
        // F - Flags register. No additional bytes.
        // H - XMM or YMM register encoded in VEX/VOP.vvvv.
        // X - Memory addressed by DS:SI pair.
        // Y - Memory addressed by ES:DI pair.
        // ! - Hardcoded register.
        //

        case 'F':
        case 'H':
        case 'X':
        case 'Y':
        case '!':
            break;

        //
        // G - General register specified in Reg field of ModR/M byte.
        //

        case 'G':
            *ModRmExists = TRUE;
            break;

        //
        // I - Immediate data is encoded in subsequent bytes.
        //

        case 'I':
            switch (Width) {
            case X86_WIDTH_BYTE:
                *ImmediateSize = 1;
                break;

            case X86_WIDTH_WORD:
                *ImmediateSize = 2;
                break;

            case X86_WIDTH_LONG:
                *ImmediateSize = 4;
                break;

            case 'v':
            case 'z':
                if ((Instruction->Rex & X64_REX_W) != 0) {
                    if (Width == 'v') {
                        *ImmediateSize = 8;

                    } else {
                        *ImmediateSize = 4;
                    }

                } else {
                    *ImmediateSize = 4;
                    if (Instruction->OperandOverride == TRUE) {
                        *ImmediateSize = 2;
                    }
                }

                break;
            }

            break;

        //
        // O - Direct Offset. No ModR/M byte, offset of operand is encoded in
        // instruction. No SIB.
        //

        case 'O':
            *ImmediateSize = 4;
            if (Instruction->AddressOverride != FALSE) {
                *ImmediateSize = 2;
            }

            break;

        //
        // J - Instruction contains relative offset.
        //

        case 'J':
            switch (Width) {
            case X86_WIDTH_BYTE:
                *DisplacementSize = 1;
                break;

            case X86_WIDTH_WORD:
                *DisplacementSize = 2;
                break;

            case X86_WIDTH_LONG:
                *DisplacementSize = 4;
                break;

            case 'v':
            case 'z':
                *DisplacementSize = 4;
                if ((Instruction->Rex & X64_REX_W) != 0) {
                    if (Width == 'v') {
                        *DisplacementSize = 8;
                    }

                } else {
                    if (Instruction->AddressOverride == TRUE) {
                        *DisplacementSize = 2;
                    }
                }

                break;
            }

            break;

        default:

            assert(FALSE);

            return FALSE;
        }

        //
        // Now that the target has been processed, loop again to process the
        // source.
        //

        ParseCount += 1;
        if (ParseCount == 1) {
            if (Instruction->Definition.Source[0] == '\0') {
                break;
            }

            Type = Instruction->Definition.Source[0];
            Width = Instruction->Definition.Source[1];

        } else {
            if (Instruction->Definition.Third[0] == '\0') {
                break;
            }

            Type = Instruction->Definition.Third[0];
            Width = Instruction->Definition.Third[1];
        }

    } while (ParseCount < 3);

    //
    // Handle the cmpcc instructions that actually have an extra immediate on
    // them.
    //

    if (strncmp(Instruction->Definition.Mnemonic, "cmpcc", 5) == 0) {
        *ImmediateSize = 1;
    }

    return TRUE;
}

PSTR
DbgpX86RegisterName (
    PX86_INSTRUCTION Instruction,
    X86_REGISTER_VALUE RegisterNumber,
    CHAR Type
    )

/*++

Routine Description:

    This routine reads a register number and a width and returns a string
    representing that register. The register number should be in the same format
    as specified in the REG bits of the ModR/M byte.

Arguments:

    Instruction - Supplies the remaining register context.

    RegisterNumber - Supplies which register to print out, as specified by the
        REG bits of the ModR/M byte.

    Type - Supplies a width or special register format.

Return Value:

    The register specifed, in string form.

--*/

{

    BOOL LongNames;

    switch (Type) {
    case X86_WIDTH_BYTE:
        LongNames = Instruction->Rex != 0;
        return DbgX86RegisterNames8Bit[LongNames][RegisterNumber];

    case X86_WIDTH_WORD:
        return DbgX86RegisterNames16Bit[RegisterNumber];

    case X86_WIDTH_LONG:
        return DbgX86RegisterNames32Bit[RegisterNumber];

    case X86_WIDTH_LONGLONG:
        return DbgX86RegisterNames64Bit[RegisterNumber];

    case X86_WIDTH_OWORD:
        return DbgX86XmmRegisterNames[RegisterNumber];

    case X86_WIDTH_YWORD:
        return DbgX86YmmRegisterNames[RegisterNumber];

    case X86_FLOATING_POINT_REGISTER:
        return DbgX87RegisterNames[RegisterNumber];

    case X86_CONTROL_REGISTER:
        return DbgX86ControlRegisterNames[RegisterNumber];

    case X86_DEBUG_REGISTER:
        return DbgX86DebugRegisterNames[RegisterNumber];

    case X86_SEGMENT_REGISTER:
        return DbgX86SegmentRegisterNames[RegisterNumber];

    default:
        break;
    }

    assert(FALSE);

    return "ERR";
}

INT
DbgpX86GetDisplacement (
    PX86_INSTRUCTION Instruction,
    PSTR Buffer,
    ULONG BufferLength,
    PLONGLONG DisplacementValue
    )

/*++

Routine Description:

    This routine prints an address displacement value.

Arguments:

    Instruction - Supplies a pointer to the instruction containing the
        displacement.

    Buffer - Supplies a pointer to the output buffer the displacement will be
        printed to.

    BufferLength - Supplies the length of the buffer in bytes.

    DisplacementValue - Supplies a pointer to the variable that will receive the
        numerical displacement value. This can be NULL.

Return Value:

    Returns the length of the buffer consumed, not including the null
    terminator.

--*/

{

    LONGLONG Displacement;
    INT Length;

    if ((BufferLength < 1) || (Instruction == NULL)) {
        return 0;
    }

    Buffer[0] = '\0';
    if (Instruction->Displacement == 0) {
        return 0;
    }

    switch (Instruction->DisplacementSize) {
    case 1:
        Displacement = (SCHAR)Instruction->Displacement;
        break;

    case 2:
        Displacement = (SHORT)Instruction->Displacement;
        break;

    case 4:
        Displacement = (LONG)Instruction->Displacement;
        break;

    case 8:
        Displacement = (LONGLONG)Instruction->Displacement;
        break;

    default:
        return 0;
    }

    if (Displacement < 0) {
        Length = snprintf(Buffer, BufferLength, "-0x%llx", -Displacement);

    } else {
        Length = snprintf(Buffer, BufferLength, "+0x%llx", Displacement);
    }

    if (DisplacementValue != NULL) {
        *DisplacementValue = Displacement;
    }

    return Length;
}

PX86_INSTRUCTION_DEFINITION
DbgpX86GetTwoByteInstruction (
    PX86_INSTRUCTION Instruction
    )

/*++

Routine Description:

    This routine finds a two-byte instruction definition corresponding to the
    instruction opcode and prefixes.

Arguments:

    Instruction - Supplies a pointer to the instruction containing the
        two byte opcode and any prefixes.

Return Value:

    Returns a pointer to the instruction definition, or NULL if one could not
    be found.

--*/

{

    PX86_INSTRUCTION_DEFINITION Definition;
    ULONG InstructionIndex;
    ULONG InstructionLength;
    UCHAR Prefix;
    ULONG PrefixIndex;

    PrefixIndex = 0;
    InstructionLength = sizeof(DbgX86TwoByteInstructions) /
                        sizeof(DbgX86TwoByteInstructions[0]);

    //
    // First search through the array looking for a version with the first
    // corresponding prefix.
    //

    while (Instruction->Prefix[PrefixIndex] != 0) {
        InstructionIndex = 0;
        Prefix = Instruction->Prefix[PrefixIndex];
        while (InstructionIndex < InstructionLength) {
            if ((DbgX86TwoByteInstructions[InstructionIndex].Prefix ==
                 Prefix) &&
                (DbgX86TwoByteInstructions[InstructionIndex].Opcode ==
                 Instruction->Opcode2)) {

                Definition =
                    &(DbgX86TwoByteInstructions[InstructionIndex].Instruction);

                switch (Prefix) {
                case X86_PREFIX_REP:
                case X86_PREFIX_REPN:
                    Instruction->Rep = "";
                    break;

                case X86_PREFIX_LOCK:
                    Instruction->Lock = "";
                    break;

                default:
                    break;
                }

                return Definition;
            }

            InstructionIndex += 1;
        }

        PrefixIndex += 1;
    }

    //
    // The search for the specific prefix instruction was not successful, or
    // no prefixes were present. Search for the opcode with a prefix of zero,
    // indicating that the prefix field is not applicable.
    //

    InstructionIndex = 0;
    while (InstructionIndex < InstructionLength) {
        if ((DbgX86TwoByteInstructions[InstructionIndex].Opcode ==
             Instruction->Opcode2) &&
             (DbgX86TwoByteInstructions[InstructionIndex].Prefix == 0)) {

            return &(DbgX86TwoByteInstructions[InstructionIndex].Instruction);
        }

        InstructionIndex += 1;
    }

    //
    // The search yielded no results. Return NULL.
    //

    return NULL;
}

BOOL
DbgpX86DecodeFloatingPointInstruction (
    PX86_INSTRUCTION Instruction
    )

/*++

Routine Description:

    This routine decodes the given x87 floating point instruction by
    manipulating the instruction definition.

Arguments:

    Instruction - Supplies a pointer to the instruction.

Return Value:

    TRUE on success.

    FALSE if the instruction is invalid. Well, let's be more PC and say that no
    instruction is "invalid", only "executionally challenged".

--*/

{

    BYTE Index;
    BYTE Mod;
    BYTE ModRm;
    BYTE Opcode;
    BYTE Opcode2;

    ModRm = Instruction->ModRm;
    Mod = X86_MODRM_MOD(Instruction->ModRm);
    Opcode = Instruction->Opcode - X87_ESCAPE_OFFSET;
    Opcode2 = (ModRm & X86_REG_MASK) >> X86_REG_SHIFT;

    //
    // Reset the group to 0 so that after this routine tweaks everything it
    // gets treated like a normal instruction.
    //

    Instruction->Definition.Group = 0;
    Instruction->Definition.Mnemonic = NULL;

    //
    // If the ModR/M byte does not specify a register, then use the big
    // table to figure out the mnemonic.
    //

    if (Mod != X86ModValueRegister) {
        Instruction->Definition.Mnemonic = DbgX87Instructions[Opcode][Opcode2];
        if (Instruction->Definition.Mnemonic == NULL) {
            return FALSE;
        }

        return TRUE;
    }

    switch (Opcode) {

    //
    // Handle D8 instructions.
    //

    case 0:
        Instruction->Definition.Mnemonic = DbgX87Instructions[0][Opcode2];

        //
        // The fcom and fcomp instructions take only ST(i). Everything else
        // has two operands, st, and st(i).
        //

        if ((ModRm & X87_FCOM_MASK) == X87_FCOM_OPCODE) {
            Instruction->Definition.Target = X87_REGISTER_TARGET;

        } else {
            Instruction->Definition.Target = X87_ST0_TARGET;
            Instruction->Definition.Source = X87_REGISTER_TARGET;
        }

        break;

    //
    // Handle D9 instructions.
    //

    case 1:
        switch (Opcode2) {

        //
        // C0-C7 is FLD ST(i).
        //

        case 0:
            Instruction->Definition.Mnemonic = X87_FLD_MNEMONIC;
            Instruction->Definition.Target = X87_REGISTER_TARGET;
            break;

        //
        // C8-CF is FXCH ST(i).
        //

        case 1:
            Instruction->Definition.Mnemonic = X87_FXCH_MNEMONIC;
            Instruction->Definition.Target = X87_REGISTER_TARGET;
            break;

        //
        // D0-D7 is just a NOP (really only at D0, but let it slide).
        //

        case 2:
            Instruction->Definition.Mnemonic = X87_NOP_MNEMONIC;
            Instruction->Definition.Target = "";
            break;

        //
        // D8-DF is FSTP1 ST(i).
        //

        case 3:
            Instruction->Definition.Mnemonic = X87_FSTP1_MNEMONIC;
            Instruction->Definition.Target = X87_REGISTER_TARGET;
            break;

        //
        // E0-FF is a grab bag of instructions with no operands.
        //

        default:
            Instruction->Definition.Mnemonic =
                        DbgX87D9E0Instructions[ModRm - X87_D9_E0_OFFSET];

            Instruction->Definition.Target = "";
            break;
        }

        break;

    //
    // Handle DA instructions.
    //

    case 2:

        //
        // The fucompp instruction lives off by itself in a wasteland.
        //

        if (ModRm == X87_FUCOMPP_OPCODE) {
            Instruction->Definition.Mnemonic = X87_FUCOMPP_MNEMONIC;
            Instruction->Definition.Target = "";

        } else {

            //
            // There are 8 instructions (4 valid), each of which take the form
            // xxx ST, ST(i). So each instruction takes up 8 bytes.
            //

            Index = (ModRm & X87_DA_C0_MASK) >> X87_DA_CO_SHIFT;
            Instruction->Definition.Mnemonic = DbgX87DAC0Instructions[Index];
            Instruction->Definition.Target = X87_ST0_TARGET;
            Instruction->Definition.Source = X87_REGISTER_TARGET;
        }

        break;

    //
    // Handle DB instructions.
    //

    case 3:
        Index = (ModRm & X87_DB_C0_MASK) >> X87_DB_C0_SHIFT;

        //
        // There's a small rash of inidividual instructions in the E0-E7
        // range.
        //

        if (Index == X87_DB_E0_INDEX) {
            Index = ModRm & X87_DB_E0_MASK;
            Instruction->Definition.Mnemonic = DbgX87DBE0Instructions[Index];
            Instruction->Definition.Target = "";

        //
        // Otherwise there are swaths of instructions that take up 8 bytes
        // each as they take the form xxx ST, ST(i).
        //

        } else {
            Instruction->Definition.Mnemonic = DbgX87DBC0Instructions[Index];
            Instruction->Definition.Target = X87_ST0_TARGET;
            Instruction->Definition.Source = X87_REGISTER_TARGET;
        }

        break;

    //
    // DC is the same as D8, except it handles doubles instead of singles
    // (floats). There's one other annoying detail which is that the FSUB and
    // FSUBR are switched above 0xC0. The same goes for FDIV and FDIVR.
    //

    case 4:
        Instruction->Definition.Mnemonic = DbgX87DCC0Instructions[Opcode2];

        //
        // The fcom and fcomp instructions take only ST(i). Everything else
        // has two operands, st, and st(i).
        //

        if ((ModRm & X87_FCOM_MASK) == X87_FCOM_OPCODE) {
            Instruction->Definition.Target = X87_REGISTER_TARGET;

        } else {
            Instruction->Definition.Target = X87_ST0_TARGET;
            Instruction->Definition.Source = X87_REGISTER_TARGET;
        }

        break;

    //
    // Handle DD instructions.
    //

    case 5:
        Instruction->Definition.Mnemonic = DbgX87DDC0Instructions[Opcode2];
        Instruction->Definition.Target = X87_REGISTER_TARGET;
        break;

    //
    // Handle DE instructions.
    //

    case 6:
        Instruction->Definition.Mnemonic = DbgX87DEC0Instructions[Opcode2];
        Instruction->Definition.Target = X87_REGISTER_TARGET;
        Instruction->Definition.Source = X87_ST0_TARGET;
        break;

    //
    // Handle DF instructions.
    //

    case 7:
        Index = (ModRm & X87_DF_C0_MASK) >> X87_DF_C0_SHIFT;

        //
        // There's a small rash of individual instructions in the E0-E7
        // range. They're pretty old school.
        //

        if (Index == X87_DF_E0_INDEX) {
            Index = ModRm & X87_DF_E0_MASK;
            if (Index < X87_DF_E0_COUNT) {
                Instruction->Definition.Mnemonic =
                                                 DbgX87DFE0Instructions[Index];

                Instruction->Definition.Target = X87_DF_E0_TARGET;
            }

        } else {
            Instruction->Definition.Mnemonic = DbgX87DFC0Instructions[Opcode2];
            Instruction->Definition.Target = X87_REGISTER_TARGET;
            Instruction->Definition.Source = X87_ST0_TARGET;
        }

        break;

    //
    // This function was inappropriately called.
    //

    default:

        assert(FALSE);

        break;
    }

    if (Instruction->Definition.Mnemonic == NULL) {
        return FALSE;
    }

    return TRUE;
}

