/*++ Copyright (c) 2012 Minoca Corp. All Rights Reserved 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 #include "disasm.h" #include #include #include // // ---------------------------------------------------------------- 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_FLOATING_POINT_REGISTER 'f' // // 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 some of the prefixes that can come at the beginning of an instruction. // #define X86_MAX_PREFIXES 4 #define X86_OPERAND_OVERRIDE 0x66 #define X86_ADDRESS_OVERRIDE 0x67 #define X86_ESCAPE_OPCODE 0x0F #define X86_PREFIX_LOCK 0xF0 #define X86_PREFIX_REP1 0xF2 #define X86_PREFIX_REP2 0xF3 #define X86_PREFIX_CS 0x2E #define X86_PREFIX_DS 0x3E #define X86_PREFIX_ES 0x26 #define X86_PREFIX_SS 0x36 // // This mask/value combination covers the FS prefix, GS prefix, Operand // override, and Address override. // #define X86_PREFIX_FS_GS_OVERRIDE_MASK 0xFC #define X86_PREFIX_FS_GS_OVERRIDE_VALUE 0x64 // // For opcode groups with fewer than the maximum number of possible opcodes, // define how many opcodes each group does have. // #define X86_GROUP_4_INSTRUCTION_COUNT 2 #define X86_GROUP_5_INSTRUCTION_COUNT 7 #define X86_GROUP_6_INSTRUCTION_COUNT 6 #define X86_GROUP_8_FIRST_INSTRUCTION 4 #define X86_GROUP_9_ONLY_VALID_INSTRUCTION 1 #define X86_INVALID_GROUP 99 // // Define the sizes of the register name arrays. // #define X86_DEBUG_REGISTER_COUNT 8 #define X86_SEGMENT_REGISTER_COUNT 6 #define X86_REGISTER_NAME_COUNT 8 // // Define the size of the working buffers. // #define X86_WORKING_BUFFER_SIZE 100 // // Define the multiplication and shift opcodes that have 3 operands. // #define X86_OPCODE1_IMUL1 0x69 #define X86_OPCODE1_IMUL2 0x6B #define X86_OPCODE2_SHLD1 0xA4 #define X86_OPCODE2_SHLD2 0xA5 #define X86_OPCODE2_SHRD1 0xAC #define X86_OPCODE2_SHRD2 0xAD // // 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 "! st" #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 "! ax" // // ------------------------------------------------------ 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. 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; INT Group; } X86_INSTRUCTION_DEFINITION, *PX86_INSTRUCTION_DEFINITION; /*++ 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: 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. 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. --*/ typedef struct _X86_INSTRUCTION { BYTE Prefix[X86_MAX_PREFIXES]; BYTE Opcode; BYTE Opcode2; BYTE ModRm; BYTE Sib; ULONG Displacement; ULONG Immediate; ULONG Length; ULONG DisplacementSize; ULONG ImmediateSize; BOOL OperandOverride; BOOL AddressOverride; X86_INSTRUCTION_DEFINITION Definition; } X86_INSTRUCTION, *PX86_INSTRUCTION; typedef enum _X86_REGISTER_VALUE { X86RegisterValueEax, X86RegisterValueEcx, X86RegisterValueEdx, X86RegisterValueEbx, X86RegisterValueEsp, X86RegisterValueEbp, X86RegisterValueEsi, X86RegisterValueEdi, X86RegisterValueScaleIndexBase, X86RegisterValueDisplacement32, } X86_REGISTER_VALUE, *PX86_REGISTER_VALUE; typedef enum _X86_MOD_VALUE { X86ModValueNoDisplacement, X86ModValueDisplacement8, X86ModValueDisplacement32, X86ModValueRegister } X86_MOD_VALUE, *PX86_MOD_VALUE; // // -------------------------------------------------------------------- Globals // // // Define working buffers. Note that this makes the disassembly code not thread // safe. // CHAR DbgX86DisassemblyBuffer[X86_WORKING_BUFFER_SIZE]; CHAR DbgX86OperandBuffer[X86_WORKING_BUFFER_SIZE]; // // Define the x86 instruction encodings. // 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", "!rax", "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", "!rax", "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", "!rax", "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", "!rax", "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", "!rax", "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", "!rax", "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", "!rax", "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", "!rax", "Iz", 0}, /* 3D */ {"DS:", "", "", X86_INVALID_GROUP}, /* 3E */ /* DS prefix */ {"aas", "", "", 0}, /* 3F */ {"inc", "!eax", "", 0}, /* 40 */ {"inc", "!ecx", "", 0}, /* 41 */ {"inc", "!edx", "", 0}, /* 42 */ {"inc", "!ebx", "", 0}, /* 43 */ {"inc", "!esp", "", 0}, /* 44 */ {"inc", "!ebp", "", 0}, /* 45 */ {"inc", "!esi", "", 0}, /* 46 */ {"inc", "!edi", "", 0}, /* 47 */ {"dec", "!eax", "", 0}, /* 48 */ {"dec", "!ecx", "", 0}, /* 49 */ {"dec", "!edx", "", 0}, /* 4A */ {"dec", "!ebx", "", 0}, /* 4B */ {"dec", "!esp", "", 0}, /* 4C */ {"dec", "!ebp", "", 0}, /* 4D */ {"dec", "!esi", "", 0}, /* 4E */ {"dec", "!edi", "", 0}, /* 4F */ {"push", "!rax", "", 0}, /* 50 */ {"push", "!rcx", "", 0}, /* 51 */ {"push", "!rdx", "", 0}, /* 52 */ {"push", "!rbx", "", 0}, /* 53 */ {"push", "!rsp", "", 0}, /* 54 */ {"push", "!rbp", "", 0}, /* 55 */ {"push", "!rsi", "", 0}, /* 56 */ {"push", "!rdi", "", 0}, /* 57 */ {"pop", "!rax", "", 0}, /* 58 */ {"pop", "!rcx", "", 0}, /* 59 */ {"pop", "!rdx", "", 0}, /* 5A */ {"pop", "!rbx", "", 0}, /* 5B */ {"pop", "!rsp", "", 0}, /* 5C */ {"pop", "!rbp", "", 0}, /* 5D */ {"pop", "!rsi", "", 0}, /* 5E */ {"pop", "!rdi", "", 0}, /* 5F */ {"pushad", "", "", 0}, /* 60 */ {"popad", "", "", 0}, /* 61 */ {"bound", "Gv", "Ma", 0}, /* 62 */ {"arpl", "Ew", "Gw", 0}, /* 63 */ {"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", 0}, /* 69 */ /* Also has Iz */ {"push", "Ib", "", 0}, /* 6A */ {"imul", "Gv", "Ev", 0}, /* 6B */ /* Also has Ib */ {"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", "Ml", 0}, /* 8D */ {"mov", "Sw", "Ev", 0}, /* 8E */ {"pop", "Ev", "", 10}, /* 8F */ /* Group 10 */ {"nop", "", "", 0}, /* 90 */ /* nop */ {"xchg", "!rcx", "!rax", 0}, /* 91 */ {"xchg", "!rdx", "!rax", 0}, /* 92 */ {"xchg", "!rbx", "!rax", 0}, /* 93 */ {"xchg", "!rsp", "!rax", 0}, /* 94 */ {"xchg", "!rbp", "!rax", 0}, /* 95 */ {"xchg", "!rsi", "!rax", 0}, /* 96 */ {"xchg", "!rdi", "!rax", 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", "!rax", "Ov", 0}, /* A1 */ {"mov", "Ob", "!bal", 0}, /* A2 */ {"mov", "Ov", "!rax", 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", "!rax", "Iz", 0}, /* A9 */ {"stos", "Yb", "!bal", 0}, /* AA */ {"stos", "Yv", "!rax", 0}, /* AB */ {"lods", "!bal", "Xb", 0}, /* AC */ {"lods", "!rax", "Xv", 0}, /* AD */ {"scas", "Yb", "!bal", 0}, /* AE */ {"scas", "Yv", "!rax", 0}, /* AF */ {"mov", "!bal", "Ib", 0}, /* B0 */ {"mov", "!bcl", "Ib", 0}, /* B1 */ {"mov", "!bdl", "Ib", 0}, /* B2 */ {"mov", "!bbl", "Ib", 0}, /* B3 */ {"mov", "!bah", "Ib", 0}, /* B4 */ {"mov", "!bch", "Ib", 0}, /* B5 */ {"mov", "!bdh", "Ib", 0}, /* B6 */ {"mov", "!bbh", "Ib", 0}, /* B7 */ {"mov", "!rax", "Iv", 0}, /* B8 */ {"mov", "!rcx", "Iv", 0}, /* B9 */ {"mov", "!rdx", "Iv", 0}, /* BA */ {"mov", "!rbx", "Iv", 0}, /* BB */ {"mov", "!rsp", "Iv", 0}, /* BC */ {"mov", "!rbp", "Iv", 0}, /* BD */ {"mov", "!rsi", "Iv", 0}, /* BE */ {"mov", "!rdi", "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", 12}, /* C6 */ /* Group 12 */ {"mov", "Ev", "Iz", 12}, /* C7 */ /* Group 12 */ {"enter", "Iw", "Ib", 0}, /* C8 */ {"leave", "", "", 0}, /* C9 */ {"retf", "Iw", "", 0}, /* CA */ {"retf", "", "", 0}, /* CB */ {"int", "!b3", "", 0}, /* CC */ /* Int 3 */ {"int", "Ib", "", 0}, /* CD */ {"into", "", "", 0}, /* CE */ {"iret", "", "", 0}, /* CF */ {"GRP2", "Eb", "!b1", 2}, /* D0 */ /* Group 2, arg2 = 1 */ {"GRP2", "Ev", "!b1", 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 */ {"jecx", "Jb", "", 0}, /* E3 */ {"in ", "!bal", "Ib", 0}, /* E4 */ {"in ", "!eax", "Iv", 0}, /* E5 */ {"out", "Ib", "!bal", 0}, /* E6 */ {"out", "Ib", "!eax", 0}, /* E7 */ {"call", "Jz", "", 0}, /* E8 */ {"jmp", "Jz", "", 0}, /* E9 */ {"jmp", "Ap", "", 0}, /* EA */ {"jmp", "Jb", "", 0}, /* EB */ {"in ", "!bal", "!wdx", 0}, /* EC */ {"in ", "!eax", "!wdx", 0}, /* ED */ {"out", "!wdx", "!bal", 0}, /* EE */ {"out", "!wdx", "!eax", 0}, /* EF */ {"LOCK:", "", "", 0}, /* F0 */ /* Lock prefix */ {"int", "!b1", "", 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", "", 0x3A}, /* F7 */ /* Group 3A */ {"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", "", "", 6}}, /* 00 */ /* Group 6 */ {0, 0x1, {"GRP7", "", "", 7}}, /* 01 */ /* Group 7 */ {0, 0x2, {"lar", "Gv", "Ew", 0}}, /* 02 */ {0, 0x3, {"lsl", "Gv", "Ew", 0}}, /* 03 */ {0, 0x5, {"loadall/syscall", "", "", 0}}, /* 05 */ {0, 0x6, {"clts", "", "", 0}}, /* 06 */ {0, 0x7, {"loadall/sysret", "", "", 0}}, /* 07 */ {0, 0x8, {"invd", "", "", 0}}, /* 08 */ {0, 0x9, {"wbinvd", "", "", 0}}, /* 09 */ {0, 0xB, {"ud1", "", "", 0}}, /* 0B */ {0, 0x10, {"umov", "Eb", "Gb", 0}}, /* 10 */ {0, 0x11, {"umov", "Ev", "Gv", 0}}, /* 11 */ {0, 0x12, {"umov", "Gb", "Eb", 0}}, /* 12 */ {0, 0x13, {"umov", "Gv", "Ev", 0}}, /* 13 */ {0, 0x20, {"mov", "Rd", "Cd", 0}}, /* 20 */ {0, 0x21, {"mov", "Rd", "Dd", 0}}, /* 21 */ {0, 0x22, {"mov", "Cd", "Rd", 0}}, /* 22 */ {0, 0x23, {"mov", "Dd", "Rd", 0}}, /* 23 */ {0, 0x30, {"wrmsr", "", "", 0}}, /* 30 */ {0, 0x31, {"rdtsc", "", "", 0}}, /* 31 */ {0, 0x32, {"rdmsr", "", "", 0}}, /* 32 */ {0, 0x33, {"rdpmc", "", "", 0}}, /* 33 */ {0, 0x34, {"sysenter", "", "", 0}}, /* 34 */ {0, 0x35, {"sysexit", "", "", 0}}, /* 35 */ {0, 0x37, {"getsec", "", "", 0}}, /* 37 */ {0, 0x40, {"cmovo", "Gv", "Ev", 0}}, /* 40 */ {0, 0x41, {"cmovno", "Gv", "Ev", 0}}, /* 41 */ {0, 0x42, {"cmovb", "Gv", "Ev", 0}}, /* 42 */ {0, 0x43, {"cmovnb", "Gv", "Ev", 0}}, /* 43 */ {0, 0x44, {"cmovz", "Gv", "Ev", 0}}, /* 44 */ {0, 0x45, {"cmovnz", "Gv", "Ev", 0}}, /* 45 */ {0, 0x46, {"cmovbe", "Gv", "Ev", 0}}, /* 46 */ {0, 0x47, {"cmovnbe", "Gv", "Ev", 0}}, /* 47 */ {0, 0x48, {"cmovs", "Gv", "Ev", 0}}, /* 48 */ {0, 0x49, {"cmovns", "Gv", "Ev", 0}}, /* 49 */ {0, 0x4A, {"cmovp", "Gv", "Ev", 0}}, /* 4A */ {0, 0x4B, {"cmovnp", "Gv", "Ev", 0}}, /* 4B */ {0, 0x4C, {"cmovl", "Gv", "Ev", 0}}, /* 4C */ {0, 0x4D, {"cmovnl", "Gv", "Ev", 0}}, /* 4D */ {0, 0x4E, {"cmovle", "Gv", "Ev", 0}}, /* 4E */ {0, 0x4F, {"cmovnle", "Gv", "Ev", 0}}, /* 4F */ {0, 0x80, {"jo ", "Jz", "", 0}}, /* 80 */ {0, 0x81, {"jno", "Jz", "", 0}}, /* 81 */ {0, 0x82, {"jb ", "Jz", "", 0}}, /* 82 */ {0, 0x83, {"jnb", "Jz", "", 0}}, /* 83 */ {0, 0x84, {"jz ", "Jz", "", 0}}, /* 84 */ {0, 0x85, {"jnz", "Jz", "", 0}}, /* 85 */ {0, 0x86, {"jbe", "Jz", "", 0}}, /* 86 */ {0, 0x87, {"jnbe", "Jz", "", 0}}, /* 87 */ {0, 0x88, {"js ", "Jz", "", 0}}, /* 88 */ {0, 0x89, {"jns", "Jz", "", 0}}, /* 89 */ {0, 0x8A, {"jp", "Jz", "", 0}}, /* 8A */ {0, 0x8B, {"jnp", "Jz", "", 0}}, /* 8B */ {0, 0x8C, {"jl ", "Jz", "", 0}}, /* 8C */ {0, 0x8D, {"jnl", "Jz", "", 0}}, /* 8D */ {0, 0x8E, {"jle", "Jz", "", 0}}, /* 8E */ {0, 0x8F, {"jnle", "Jz", "", 0}}, /* 8F */ {0, 0x90, {"seto", "Eb", "", 0}}, /* 90 */ {0, 0x91, {"setno", "Eb", "", 0}}, /* 91 */ {0, 0x92, {"setb", "Eb", "", 0}}, /* 92 */ {0, 0x93, {"setnb", "Eb", "", 0}}, /* 93 */ {0, 0x94, {"setz", "Eb", "", 0}}, /* 94 */ {0, 0x95, {"setnz", "Eb", "", 0}}, /* 95 */ {0, 0x96, {"setbe", "Eb", "", 0}}, /* 96 */ {0, 0x97, {"setnbe", "Eb", "", 0}}, /* 97 */ {0, 0x98, {"sets", "Eb", "", 0}}, /* 98 */ {0, 0x99, {"setns", "Eb", "", 0}}, /* 99 */ {0, 0x9A, {"setp", "Eb", "", 0}}, /* 9A */ {0, 0x9B, {"setnp", "Eb", "", 0}}, /* 9B */ {0, 0x9C, {"setl", "Eb", "", 0}}, /* 9C */ {0, 0x9D, {"setnl", "Eb", "", 0}}, /* 9D */ {0, 0x9E, {"setle", "Eb", "", 0}}, /* 9E */ {0, 0x9F, {"setnle", "Eb", "", 0}}, /* 9F */ {0, 0xA0, {"push", "!wfs", "", 0}}, /* A0 */ {0, 0xA1, {"pop", "!wfs", "", 0}}, /* A1 */ {0, 0xA2, {"cpuid", "", "", 0}}, /* A2 */ {0, 0xA3, {"bt ", "Ev", "Gv", 0}}, /* A3 */ {0, 0xA4, {"shld", "Ev", "Gv", 0}}, /* A4 */ /* also has Ib */ {0, 0xA5, {"shld", "Ev", "Gv", 0}}, /* A5 */ /* also has !bcl */ {0, 0xA6, {"cmpxchg", "", "", 0}}, /* A6 */ {0, 0xA7, {"cmpxchg", "", "", 0}}, /* A7 */ {0, 0xA8, {"push", "!wgs", "", 0}}, /* A8 */ {0, 0xA9, {"pop", "!gs", "", 0}}, /* A9 */ {0, 0xAA, {"rsm", "", "", 0}}, /* AA */ {0, 0xAB, {"bts", "Ev", "Gv", 0}}, /* AB */ {0, 0xAC, {"shrd", "Ev", "Gv", 0}}, /* AC */ /* Also has Ib */ {0, 0xAD, {"shrd", "Ev", "Gv", 0}}, /* AD */ /* Also has !bcl */ {0, 0xAE, {"GRP15", "", "", 15}}, /* AE */ /* Group 15 */ {0, 0xAF, {"imul", "Gv", "Ev", 0}}, /* AF */ {0, 0xB0, {"cmpxchg", "Eb", "Gb", 0}}, /* B0 */ {0, 0xB1, {"cmpxchg", "Ev", "Gv", 0}}, /* B1 */ {0, 0xB2, {"lss", "Gz", "Mp", 0}}, /* B2 */ {0, 0xB3, {"btr", "Ev", "Gv", 0}}, /* B3 */ {0, 0xB4, {"lfs", "Gz", "Mp", 0}}, /* B4 */ {0, 0xB5, {"lgs", "Gz", "Mp", 0}}, /* B5 */ {0, 0xB6, {"movzx", "Gv", "Eb", 0}}, /* B6 */ {0, 0xB7, {"movxz", "Gv", "Ew", 0}}, /* B7 */ {0, 0xB8, {"jmpe", "Jz", "", 0}}, /* B8 */ {0, 0xB9, {"ud2", "", "", 11}}, /* B9 */ /* Group 11 */ {0, 0xBA, {"GRP8", "Ev", "Ib", 8}}, /* BA */ /* Group 8 */ {0, 0xBB, {"btc", "Ev", "Gv", 0}}, /* BB */ {0, 0xBC, {"bsf", "Gv", "Ev", 0}}, /* BC */ {0, 0xBD, {"bsr", "Gv", "Ev", 0}}, /* BD */ {0, 0xBE, {"movsx", "Gv", "Eb", 0}}, /* BE */ {0, 0xBF, {"movsx", "Gv", "Ew", 0}}, /* BF */ {0xF3, 0xB8, {"popcnt", "Gv", "Ev", 0}}, /* B8 */ {0xF3, 0xBD, {"lzcnt", "Gv", "Ev", 0}}, /* BD */ {0, 0xC0, {"xadd", "Eb", "Gb", 0}}, /* C0 */ {0, 0xC1, {"xadd", "Ev", "Gv", 0}}, /* C1 */ {0, 0xC7, {"GRP9", "", "", 9}}, /* C7 */ /* Group 9 */ {0, 0xC8, {"bswap", "!leax", "", 0}}, /* C8 */ {0, 0xC9, {"bswap", "!lecx", "", 0}}, /* C9 */ {0, 0xCA, {"bswap", "!ledx", "", 0}}, /* CA */ {0, 0xCB, {"bswap", "!lebx", "", 0}}, /* CB */ {0, 0xCC, {"bswap", "!lesp", "", 0}}, /* CC */ {0, 0xCD, {"bswap", "!lebp", "", 0}}, /* CD */ {0, 0xCE, {"bswap", "!lesi", "", 0}}, /* CE */ {0, 0xCF, {"bswap", "!ledi", "", 0}}, /* CF */ {0, 0xFF, {"ud", "", "", 0}}, /* FF */ {0x66, 0xFF, {"ud", "", "", 0}}, /* FF */ {0, 0x0, {"", "", "", 0}}, /* 00 */ {0, 0x0, {"", "", "", 0}}, /* 00 */ {0, 0x0, {"", "", "", 0}}, /* 00 */ {0, 0x0, {"", "", "", 0}}, /* 00 */ {0, 0x0, {"", "", "", 0}}, /* 00 */ {0, 0x0, {"", "", "", 0}}, /* 00 */ {0, 0x0, {"", "", "", 0}}, /* 00 */ {0, 0x0, {"", "", "", 0}}, /* 00 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group1Instructions[8] = { {"add", "", "", 0}, /* 00 */ {"or ", "", "", 0}, /* 01 */ {"adc", "", "", 0}, /* 02 */ {"sbb", "", "", 0}, /* 03 */ {"and", "", "", 0}, /* 04 */ {"sub", "", "", 0}, /* 05 */ {"xor", "", "", 0}, /* 06 */ {"cmp", "", "", 0}, /* 07 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group2Instructions[8] = { {"rol", "", "", 0}, /* 00 */ {"ror", "", "", 0}, /* 01 */ {"rcl", "", "", 0}, /* 02 */ {"rcr", "", "", 0}, /* 03 */ {"shl", "", "", 0}, /* 04 */ {"shr", "", "", 0}, /* 05 */ {"sal", "", "", 0}, /* 06 */ {"sar", "", "", 0}, /* 07 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group3Instructions[8] = { {"test", "Ev", "Ib", 0}, /* 00 */ {"test", "Ev", "Ib", 0}, /* 01 */ {"not", "", "", 0}, /* 02 */ {"neg", "", "", 0}, /* 03 */ {"mul", "", "!rax", 0}, /* 04 */ {"mul", "", "!rax", 0}, /* 05 */ {"div", "", "!rax", 0}, /* 06 */ {"div", "", "!rax", 0}, /* 07 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group3AInstructions[8] = { {"test", "Ev", "Iz", 0}, /* 00 */ {"test", "Ev", "Iz", 0}, /* 01 */ {"not", "", "", 0}, /* 02 */ {"neg", "", "", 0}, /* 03 */ {"mul", "", "!rax", 0}, /* 04 */ {"mul", "", "!rax", 0}, /* 05 */ {"div", "", "!rax", 0}, /* 06 */ {"div", "", "!rax", 0}, /* 07 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group4Instructions[X86_GROUP_4_INSTRUCTION_COUNT] = { {"inc", "Eb", "", 0}, /* 00 */ {"dec", "Eb", "", 0}, /* 01 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group5Instructions[X86_GROUP_5_INSTRUCTION_COUNT] = { {"inc", "Ev", "", 0}, /* 00 */ {"dec", "Ev", "", 0}, /* 01 */ {"call", "Ev", "", 0}, /* 02 */ {"call", "Mp", "", 0}, /* 03 */ {"jmp", "Ev", "", 0}, /* 04 */ {"jmp", "Mp", "", 0}, /* 05 */ {"push", "Ev", "", 0}, /* 06 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group6Instructions[X86_GROUP_6_INSTRUCTION_COUNT] = { {"sldt", "Ev", "", 0}, /* 00 */ {"str", "Ev", "", 0}, /* 01 */ {"lldt", "Ev", "", 0}, /* 02 */ {"ltr", "Ev", "", 0}, /* 03 */ {"verr", "Ev", "", 0}, /* 04 */ {"verw", "Ev", 0}, /* 05 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group7Instructions[8] = { {"sgdt", "Ms", "", 0}, /* 00 */ {"sidt", "Ms", "", 0}, /* 01 */ {"lgdt", "Ms", "", 0}, /* 02 */ {"lidt", "Ms", "", 0}, /* 03 */ {"smsw", "Mw", "", 0}, /* 04 */ {"", "", "", X86_INVALID_GROUP}, /* 05 */ {"lmsw", "Mw", "", 0}, /* 06 */ {"invlpg", "Ml", "", 0}, /* 07 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group8Instructions[8] = { {"", "", "", X86_INVALID_GROUP}, /* 00 */ {"", "", "", X86_INVALID_GROUP}, /* 01 */ {"", "", "", X86_INVALID_GROUP}, /* 02 */ {"", "", "", X86_INVALID_GROUP}, /* 03 */ {"bt ", "", "", 0}, /* 04 */ {"bts", "", 0}, /* 05 */ {"btr", "", "", 0}, /* 06 */ {"btc", "", "", 0}, /* 07 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group9Instructions[8] = { {"", "", "", X86_INVALID_GROUP}, /* 00 */ {"cmpxchg", "Mq", "", 0}, /* 01 */ }; X86_INSTRUCTION_DEFINITION DbgX86Group15Instructions[8] = { {"fxsave", "M", "", 0}, /* 00 */ {"fxrstor", "M", "", 0}, /* 01 */ {"vldmxcsr", "Md", "", 0}, /* 02 */ {"vstmxcsr", "Md", "", 0}, /* 03 */ {"xsave", "M", "", 0}, /* 04 */ {"xrstor", "M", "", 0}, /* 05 */ {"xsaveopt", "M", "", 0}, /* 06 */ {"clflush", "M", "", 0}, /* 07 */ }; 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 DbgX86DebugRegisterNames[X86_DEBUG_REGISTER_COUNT] = { "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7" }; PSTR DbgX86SegmentRegisterNames[X86_SEGMENT_REGISTER_COUNT] = { "es", "cs", "ss", "ds", "fs", "gs" }; PSTR DbgX86RegisterNames8Bit[X86_REGISTER_NAME_COUNT] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", }; PSTR DbgX86RegisterNames16Bit[X86_REGISTER_NAME_COUNT] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; PSTR DbgX86RegisterNames32Bit[X86_REGISTER_NAME_COUNT] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; PSTR DbgX87RegisterNames[X86_REGISTER_NAME_COUNT] = { "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", }; // // ----------------------------------------------- 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 DbgpX86GetControlRegister ( BYTE ModRm ); PSTR DbgpX86GetDebugRegister ( BYTE ModRm ); PSTR DbgpX86GetSegmentRegister ( BYTE ModRm ); PSTR DbgpX86GetGenericRegister ( X86_REGISTER_VALUE RegisterNumber, CHAR Type ); VOID DbgpX86GetDisplacement ( PX86_INSTRUCTION Instruction, PSTR Buffer, 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 ) /*++ 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. Return Value: TRUE on success. FALSE if the instruction was unknown. --*/ { ULONGLONG Address; BOOL AddressValid; X86_INSTRUCTION Instruction; PSTR Mnemonic; BOOL Result; PSTR ThirdOperandFormat; if ((Disassembly == NULL) || (Buffer == NULL)) { return FALSE; } memset(Buffer, 0, BufferLength); memset(Disassembly, 0, sizeof(DISASSEMBLED_INSTRUCTION)); // // 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. // Disassembly->Mnemonic = Buffer; strcpy(Disassembly->Mnemonic, Mnemonic); Buffer += strlen(Mnemonic) + 1; BufferLength -= (strlen(Mnemonic) + 1); // // Get the destination operand. // Result = DbgpX86PrintOperand(InstructionPointer, &Instruction, Instruction.Definition.Target, DbgX86DisassemblyBuffer, X86_WORKING_BUFFER_SIZE, &Address, &AddressValid); if ((Result == FALSE) || (strlen(DbgX86DisassemblyBuffer) >= 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; strcpy(Disassembly->DestinationOperand, DbgX86DisassemblyBuffer); Buffer += strlen(DbgX86DisassemblyBuffer) + 1; BufferLength -= (strlen(DbgX86DisassemblyBuffer) + 1); // // Get the source operand. // Result = DbgpX86PrintOperand(InstructionPointer, &Instruction, Instruction.Definition.Source, DbgX86DisassemblyBuffer, X86_WORKING_BUFFER_SIZE, &Address, &AddressValid); if ((Result == FALSE) || (strlen(DbgX86DisassemblyBuffer) >= 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 (strlen(DbgX86DisassemblyBuffer) > 0) { Disassembly->SourceOperand = Buffer; strcpy(Disassembly->SourceOperand, DbgX86DisassemblyBuffer); Buffer += strlen(DbgX86DisassemblyBuffer) + 1; BufferLength -= (strlen(DbgX86DisassemblyBuffer) - 1); } // // Handle the MUL, SHLD, and SHRD instructions, which have 3 operands. // ThirdOperandFormat = NULL; if (Instruction.Opcode == X86_OPCODE1_IMUL1) { ThirdOperandFormat = "Iz"; } else if (Instruction.Opcode == X86_OPCODE1_IMUL2) { ThirdOperandFormat = "Ib"; } else if ((Instruction.Opcode == X86_ESCAPE_OPCODE) && ((Instruction.Opcode2 == X86_OPCODE2_SHLD1) || (Instruction.Opcode2 == X86_OPCODE2_SHRD1))) { ThirdOperandFormat = "Ib"; } else if ((Instruction.Opcode == X86_ESCAPE_OPCODE) && ((Instruction.Opcode2 == X86_OPCODE2_SHLD2) || (Instruction.Opcode2 == X86_OPCODE2_SHRD2))) { ThirdOperandFormat = "!bcl"; } if (ThirdOperandFormat != NULL) { Result = DbgpX86PrintOperand(InstructionPointer, &Instruction, ThirdOperandFormat, DbgX86DisassemblyBuffer, X86_WORKING_BUFFER_SIZE, &Address, &AddressValid); if ((Result == FALSE) || (strlen(DbgX86DisassemblyBuffer) > BufferLength)) { Result = FALSE; goto DisassembleEnd; } Disassembly->ThirdOperand = Buffer; strcpy(Disassembly->ThirdOperand, DbgX86DisassemblyBuffer); } 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; X86_MOD_VALUE Mod; X86_REGISTER_VALUE Register; PSTR RegisterString; X86_REGISTER_VALUE 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; } strcpy(Operand, ""); strcpy(DbgX86OperandBuffer, ""); *Address = 0ULL; *AddressValid = FALSE; if (strlen(OperandFormat) < 2) { return TRUE; } Type = OperandFormat[0]; Width = OperandFormat[1]; // // 'd' means dword, which gets translated to long here for simplicity. // if (Width == 'd') { Width = X86_WIDTH_LONG; } // // If the width is variable, it is probably a dword unless an override is // specified. // if ((Width == 'v') || (Width == 'z')) { Width = X86_WIDTH_LONG; if ((Instruction->OperandOverride == TRUE) || (Instruction->AddressOverride == TRUE)) { Width = X86_WIDTH_WORD; } } switch (Type) { // // The ! encoding indicates that a register is hardcoded. Unless an override // is set, append an e to the beginning of the hardcoded register (to make // ax into eax). // case '!': if ((Width == 'r') || (Width == 'e')) { if ((Instruction->ImmediateSize == 0) && (Instruction->OperandOverride == FALSE)) { strcat(Operand, "e"); } else if (Instruction->ImmediateSize == 4) { strcat(Operand, "e"); } } strcat(Operand, OperandFormat + 2); 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': sprintf(DbgX86OperandBuffer, "[0x%x]", Instruction->Immediate); strcat(Operand, DbgX86OperandBuffer); *Address = Instruction->Immediate; *AddressValid = TRUE; break; // // C - Reg field of mod R/M byte selects a control register. // case 'C': sprintf(DbgX86OperandBuffer, "%s", DbgpX86GetControlRegister(Instruction->ModRm)); strcat(Operand, DbgX86OperandBuffer); break; // // D - Reg field of mod R/M byte selects a debug register. // case 'D': sprintf(DbgX86OperandBuffer, "%s", DbgpX86GetDebugRegister(Instruction->ModRm)); strcat(Operand, DbgX86OperandBuffer); 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. // case 'E': case 'M': Mod = (Instruction->ModRm & X86_MOD_MASK) >> X86_MOD_SHIFT; Rm = (Instruction->ModRm & X86_RM_MASK) >> X86_RM_SHIFT; if (Mod == X86ModValueRegister) { if (Type == 'M') { return FALSE; } RegisterString = DbgpX86GetGenericRegister(Rm, Width); } else { // // An R/M value of 4 actually indicates an SIB byte is present, not // ESP. // if (Rm == X86RegisterValueEsp) { Rm = X86RegisterValueScaleIndexBase; BaseValue = (Instruction->Sib & X86_BASE_MASK) >> X86_BASE_SHIFT; IndexValue = (Instruction->Sib & X86_INDEX_MASK) >> X86_INDEX_SHIFT; Base = DbgpX86GetGenericRegister(BaseValue, X86_WIDTH_LONG); Index = DbgpX86GetGenericRegister(IndexValue, X86_WIDTH_LONG); // // 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 (BaseValue == X86RegisterValueEbp) { Base = ""; sprintf(DbgX86OperandBuffer, "0x%x", Instruction->Displacement); strcat(Operand, DbgX86OperandBuffer); } // // Raise the scale to 2^(Scale). // Scale = (Instruction->Sib & X86_SCALE_MASK) >> X86_SCALE_SHIFT; if (Scale == 0) { Scale = 1; } else if (Scale == 1) { Scale = 2; } else if (Scale == 2) { Scale = 4; } else if (Scale == 3) { Scale = 8; } } else if ((Mod == X86ModValueNoDisplacement) && (Rm == X86RegisterValueEbp)) { Rm = X86RegisterValueDisplacement32; } else { RegisterString = DbgpX86GetGenericRegister(Rm, X86_WIDTH_LONG); } } // // The operand is simply a register. // if (Mod == X86ModValueRegister) { strcat(Operand, RegisterString); // // The operand is an address with a scale/index/base. // } else if (Rm == X86RegisterValueScaleIndexBase) { sprintf(DbgX86OperandBuffer, "[%s", Base); strcat(Operand, DbgX86OperandBuffer); // // An index of 4 indicates that the index and scale fields are not // used. // if (IndexValue != 4) { if (strlen(Base) != 0) { strcat(Operand, "+"); } sprintf(DbgX86OperandBuffer, "%s*%d", Index, Scale); strcat(Operand, DbgX86OperandBuffer); } DbgpX86GetDisplacement(Instruction, DbgX86OperandBuffer, NULL); strcat(Operand, DbgX86OperandBuffer); strcat(Operand, "]"); // // The operand is a 32-bit address. // } else if (Rm == X86RegisterValueDisplacement32) { sprintf(DbgX86OperandBuffer, "[0x%x]", Instruction->Displacement); strcat(Operand, DbgX86OperandBuffer); *Address = Instruction->Displacement; *AddressValid = TRUE; // // The operand is an address in a register, possibly with some // additional displacement. // } else { sprintf(DbgX86OperandBuffer, "[%s", RegisterString); strcat(Operand, DbgX86OperandBuffer); DbgpX86GetDisplacement(Instruction, DbgX86OperandBuffer, NULL); strcat(Operand, DbgX86OperandBuffer); strcat(Operand, "]"); } break; // // F - EFLAGS register. // case 'F': strcat(Operand, "eflags"); break; // // G - Reg field of Mod R/M byte selects a general register. // case 'G': Register = (Instruction->ModRm & X86_REG_MASK) >> X86_REG_SHIFT; strcat(Operand, DbgpX86GetGenericRegister(Register, Width)); 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': sprintf(DbgX86OperandBuffer, "0x%x", Instruction->Immediate); strcat(Operand, DbgX86OperandBuffer); break; // // J - Instruction contains a relative offset to be added to the instruction // pointer. // case 'J': DbgpX86GetDisplacement(Instruction, DbgX86OperandBuffer, (PLONGLONG)Address); *Address += (InstructionPointer + Instruction->Length); sprintf(DbgX86OperandBuffer, "[0x%x]", *Address); strcat(Operand, DbgX86OperandBuffer); *AddressValid = TRUE; break; // // R - R/M field of modR/M byte selects a general register. Mod field should // be set to 11. // case 'R': Mod = (Instruction->ModRm & X86_MOD_MASK) >> X86_MOD_SHIFT; Rm = (Instruction->ModRm & X86_RM_MASK) >> X86_RM_SHIFT; if (Mod != X86ModValueRegister) { return FALSE; } strcat(Operand, DbgpX86GetGenericRegister(Rm, Width)); break; // // S - Reg field of ModR/M byte selects a segment register. // case 'S': strcat(Operand, DbgpX86GetSegmentRegister(Instruction->ModRm)); break; // // X - Memory addressed by DS:SI register pair (eg. MOVS CMPS, OUTS, LODS). // case 'X': strcat(Operand, "DS:[esi]"); break; // // Y - Memory addressed by ES:DI register pair (eg. MOVS INS, STOS, SCAS). // case 'Y': strcat(Operand, "ES:[edi]"); 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. --*/ { BYTE RegByte; if (Instruction == NULL) { return NULL; } if (Instruction->Definition.Group == 0) { return Instruction->Definition.Mnemonic; } RegByte = (Instruction->ModRm & X86_REG_MASK) >> X86_REG_SHIFT; switch (Instruction->Definition.Group) { case 1: return DbgX86Group1Instructions[RegByte].Mnemonic; case 2: return DbgX86Group2Instructions[RegByte].Mnemonic; case 3: return DbgX86Group3Instructions[RegByte].Mnemonic; case 0x3A: return DbgX86Group3AInstructions[RegByte].Mnemonic; case 4: if (RegByte >= X86_GROUP_4_INSTRUCTION_COUNT) { return NULL; } return DbgX86Group4Instructions[RegByte].Mnemonic; case 5: if (RegByte >= X86_GROUP_5_INSTRUCTION_COUNT) { return "(bad)"; } return DbgX86Group5Instructions[RegByte].Mnemonic; case 10: case 12: if (RegByte != 0) { return "(bad)"; } return Instruction->Definition.Mnemonic; case 15: return DbgX86Group15Instructions[RegByte].Mnemonic; } 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; PBYTE CurrentPrefix; ULONG DisplacementSize; ULONG Group; ULONG ImmediateSize; ULONG Mod; BOOL ModRmExists; UCHAR Opcode3; BYTE RegByte; BOOL Result; BOOL SibExists; PX86_INSTRUCTION_DEFINITION TopLevelDefinition; PX86_INSTRUCTION_DEFINITION TwoByteInstruction; if (Instruction == NULL) { return FALSE; } CurrentPrefix = &(Instruction->Prefix[0]); Beginning = InstructionStream; Result = TRUE; memset(Instruction, 0, sizeof(X86_INSTRUCTION)); // // 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)). // while ((*InstructionStream == X86_PREFIX_LOCK) || (*InstructionStream == X86_PREFIX_REP1) || (*InstructionStream == X86_PREFIX_REP2) || ((*InstructionStream & X86_PREFIX_FS_GS_OVERRIDE_MASK) == X86_PREFIX_FS_GS_OVERRIDE_VALUE) || (*InstructionStream == X86_PREFIX_CS) || (*InstructionStream == X86_PREFIX_DS) || (*InstructionStream == X86_PREFIX_ES) || (*InstructionStream == X86_PREFIX_SS)) { if (*InstructionStream == X86_OPERAND_OVERRIDE) { Instruction->OperandOverride = TRUE; } else if (*InstructionStream == X86_ADDRESS_OVERRIDE) { Instruction->AddressOverride = TRUE; } *CurrentPrefix = *InstructionStream; CurrentPrefix += 1; InstructionStream += 1; Instruction->Length += 1; // // No more than 4 prefixes are allowed in one instruction. // if (Instruction->Length == X86_MAX_PREFIXES) { break; } } 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 (Instruction->Definition.Group) { case 1: case 2: break; case 3: Instruction->Definition.Source = DbgX86Group3Instructions[RegByte].Source; break; case 0x3A: Instruction->Definition.Source = DbgX86Group3AInstructions[RegByte].Source; break; case 4: case 5: break; case 6: if (RegByte >= X86_GROUP_6_INSTRUCTION_COUNT) { Result = FALSE; goto GetInstructionComponentsEnd; } Instruction->Definition = DbgX86Group6Instructions[RegByte]; break; case 7: Instruction->Definition = DbgX86Group7Instructions[RegByte]; // // 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; case 8: if (RegByte < X86_GROUP_8_FIRST_INSTRUCTION) { Result = FALSE; goto GetInstructionComponentsEnd; } Instruction->Definition = DbgX86Group8Instructions[RegByte]; break; case 9: if (RegByte != X86_GROUP_9_ONLY_VALID_INSTRUCTION) { Result = FALSE; goto GetInstructionComponentsEnd; } Instruction->Definition = DbgX86Group9Instructions[RegByte]; break; case 10: case 12: case 0x87: break; case 15: Instruction->Definition = DbgX86Group15Instructions[RegByte]; break; default: assert(FALSE); 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 = (Instruction->ModRm & X86_MOD_MASK) >> X86_MOD_SHIFT; if (Base == X86RegisterValueEbp) { 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. // case 'E': case 'M': case 'R': *ModRmExists = TRUE; ModRm = *InstructionStream; Mod = (ModRm & X86_MOD_MASK) >> X86_MOD_SHIFT; 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 == X86RegisterValueEsp) { 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 == X86RegisterValueEbp)) { 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. // X - Memory addressed by DS:SI pair. // Y - Memory addressed by ES:DI pair. // ! - Hardcoded register. // case 'F': 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': *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->AddressOverride == TRUE) { *DisplacementSize = 2; } break; } break; default: return FALSE; } // // Now that the target has been processed, loop again to process the // source. // ParseCount += 1; if (Instruction->Definition.Source[0] == '\0') { break; } Type = Instruction->Definition.Source[0]; Width = Instruction->Definition.Source[1]; } while (ParseCount < 2); // // Handle the special instructions that actually have three operands. // if (Instruction->Opcode == X86_OPCODE1_IMUL1) { *ImmediateSize = 4; if (Instruction->OperandOverride == TRUE) { *ImmediateSize = 2; } } if (Instruction->Opcode == X86_OPCODE1_IMUL2) { *ImmediateSize = 1; } if ((Instruction->Opcode == X86_ESCAPE_OPCODE) && ((Instruction->Opcode2 == X86_OPCODE2_SHLD1) || (Instruction->Opcode2 == X86_OPCODE2_SHRD1))) { *ImmediateSize = 1; } return TRUE; } PSTR DbgpX86GetControlRegister ( BYTE ModRm ) /*++ Routine Description: This routine reads the REG bits of a ModR/M byte and returns a string representing the control register in those bits. Arguments: ModRm - Supplies the ModR/M byte of the instruction. Only bits 5:3 are used. Return Value: The control register specifed, in string form. --*/ { BYTE RegisterNumber; RegisterNumber = (ModRm & X86_REG_MASK) >> X86_REG_SHIFT; switch (RegisterNumber) { case 0: return "cr0"; break; case 2: return "cr2"; break; case 3: return "cr3"; break; case 4: return "cr4"; break; } return "ERR"; } PSTR DbgpX86GetDebugRegister ( BYTE ModRm ) /*++ Routine Description: This routine reads the REG bits of a ModR/M byte and returns a string representing the debug register in those bits. Arguments: ModRm - Supplies the ModR/M byte of the instruction. Only bits 5:3 are used. Return Value: The debug register specifed, in string form. --*/ { BYTE RegisterNumber; RegisterNumber = (ModRm & X86_REG_MASK) >> X86_REG_SHIFT; if (RegisterNumber >= X86_DEBUG_REGISTER_COUNT) { return "ERR"; } return DbgX86DebugRegisterNames[RegisterNumber]; } PSTR DbgpX86GetSegmentRegister ( BYTE ModRm ) /*++ Routine Description: This routine reads the REG bits of a ModR/M byte and returns a string representing the segment register in those bits. Arguments: ModRm - Supplies the ModR/M byte of the instruction. Only bits 5:3 are used. Return Value: The segment register specifed, in string form. --*/ { BYTE RegisterNumber; RegisterNumber = (ModRm & X86_REG_MASK) >> X86_REG_SHIFT; if (RegisterNumber >= X86_SEGMENT_REGISTER_COUNT) { return "ER"; } return DbgX86SegmentRegisterNames[RegisterNumber]; } PSTR DbgpX86GetGenericRegister ( 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: 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. --*/ { if (RegisterNumber >= X86_REGISTER_NAME_COUNT) { return "ERR"; } switch (Type) { case X86_WIDTH_BYTE: return DbgX86RegisterNames8Bit[RegisterNumber]; case X86_WIDTH_WORD: return DbgX86RegisterNames16Bit[RegisterNumber]; case X86_WIDTH_LONG: return DbgX86RegisterNames32Bit[RegisterNumber]; case X86_FLOATING_POINT_REGISTER: return DbgX87RegisterNames[RegisterNumber]; default: assert(FALSE); return "ERR"; } } VOID DbgpX86GetDisplacement ( PX86_INSTRUCTION Instruction, PSTR Buffer, 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. DisplacementValue - Supplies a pointer to the variable that will receive the numerical displacement value. This can be NULL. Return Value: The instruction displacement field, in string form. --*/ { LONG Displacement; if ((Buffer == NULL) || (Instruction == NULL)) { return; } strcpy(Buffer, ""); if (Instruction->Displacement == 0) { return; } switch (Instruction->DisplacementSize) { case 1: Displacement = (CHAR)Instruction->Displacement; break; case 2: Displacement = (SHORT)Instruction->Displacement; break; case 4: Displacement = (LONG)Instruction->Displacement; break; default: return; } if (Displacement < 0) { sprintf(Buffer, "-0x%x", -Displacement); } else { sprintf(Buffer, "+0x%x", Displacement); } if (DisplacementValue != NULL) { *DisplacementValue = Displacement; } } 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; 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; while (InstructionIndex < InstructionLength) { if ((DbgX86TwoByteInstructions[InstructionIndex].Prefix == Instruction->Prefix[PrefixIndex]) && (DbgX86TwoByteInstructions[InstructionIndex].Opcode == Instruction->Opcode2)) { Definition = &(DbgX86TwoByteInstructions[InstructionIndex].Instruction); 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 = (ModRm & X86_MOD_MASK) >> X86_MOD_SHIFT; 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; }