//include file for __dislib.asm and maybe even for your module
//(c) 1998 Henrik Nebrin
//You may change the strucs to class objects if you like too.
//Remember not to change the order of the data and not
//use virutal functions in these structs/soon-to-be-classes.
//You may use virtual functions in any relatives, though
#ifndef __dislib_h
#define __dislib_h

#ifndef asmwords
#define asmwords
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
#endif

//dis_immoperand_t.__flags
const di_signextended = 0x01;           //set if imm is sign-extended

//an immediate operand (byte/word/dword)
struct dis_immoperand_t {
    dword immediate;                    //byte/word/dword (check ../.flags)
    byte __flags;

    int signextended (void) const {return (__flags & di_signextended);}
  };

//for dis_regoperand_t.register and more
enum __dr_registers {
  dr_eax,
  dr_ecx,
  dr_edx,
  dr_ebx,
  dr_esp,
  dr_ebp,
  dr_esi,
  dr_edi,
  dr_ax,                                //NOTE: dr_ax-dr_di and dr_eax-dr_edi
  dr_cx,                                // must be the first 10h equates.
  dr_dx,                                // Two of them must fit in a byte
  dr_bx,                                // in dis_memoperand_t.baseindex
  dr_sp,
  dr_bp,
  dr_si,
  dr_di,
  dr_al,
  dr_cl,
  dr_dl,
  dr_bl,
  dr_ah,
  dr_ch,
  dr_dh,
  dr_bh,
  dr_es,                                //not segment overrides!
  dr_cs,
  dr_ss,
  dr_ds,
  dr_fs,
  dr_gs,
  dr_X1,
  dr_X2,
  dr_cr0,
  dr_cr1,
  dr_cr2,
  dr_cr3,
  dr_cr4,
  dr_cr5,
  dr_cr6,
  dr_cr7,
  dr_dr0,
  dr_dr1,
  dr_dr2,
  dr_dr3,
  dr_dr4,
  dr_dr5,
  dr_dr6,
  dr_dr7,
  dr_tr0,
  dr_tr1,
  dr_tr2,
  dr_tr3,
  dr_tr4,
  dr_tr5,
  dr_tr6,
  dr_tr7,
  dr_mm0,
  dr_mm1,
  dr_mm2,
  dr_mm3,
  dr_mm4,
  dr_mm5,
  dr_mm6,
  dr_mm7,
  dr_st0,
  dr_st1,
  dr_st2,
  dr_st3,
  dr_st4,
  dr_st5,
  dr_st6,
  dr_st7,
  dr_st,
  dr_none=0xFF                          //Never returned in a struc
  };

//any register
struct dis_regoperand_t {
    byte _register;
  };

//dis_memoperand_t.__flags
const dm_displbyte              = 0x00; //displacement size
const dm_displword              = 0x01;
const dm_displdword             = 0x02;
const dm_displsizemask          = 0x03;
const dm_displsignextended      = 0x04; //if displacement is sign-extended
const dm_segoverride            = 0x08; //if there is a segment override
const dm_hasdispl               = 0x10; //if we have a displacement
const dm_hasbase                = 0x20; //if we have a base register
const dm_hasindex               = 0x40; //if we have an index register
const dm_hasscale               = 0x80; //if we have a scale value

//for dis_memoperand_t.segoverride
const dm_seges  = 0x00;                 //segment overrides
const dm_segcs  = 0x01;
const dm_segss  = 0x02;
const dm_segds  = 0x03;
const dm_segfs  = 0x04;
const dm_seggs  = 0x05;
const dm_segX1  = 0x06;
const dm_segX2  = 0x07;

//for dis_memoperand_t.scalesize
const dm_scale0 = 0x00;                 //index scale (bits 0-1)
const dm_scale1 = 0x01;
const dm_scale2 = 0x02;
const dm_scale3 = 0x03;

//any memory address seg:[base+index*X+displ]
struct dis_memoperand_t {
    dword displ;
    byte baseindex;                     //base=bits 0-3,index=bits 4-7
    byte scale;
    byte __flags;
    //if (__flags & dm_segoverride != 0x00):
    //current segment override = bits 0-3 (dm_segXX) (ds:[bp] = ds=current seg)
    //default segment override = bits 4-7 (dm_segXX shl 4) ([bp] = ss=def seg)
    byte segoverride;

    int currentsegoverride (void) const {return (segoverride & 0x0F);}
    int defaultsegoverride (void) const {return (segoverride >> 4);}
    int getsegoverride (void) const {return (__flags & dm_segoverride != 0
                          ? currentsegoverride () : defaultsegoverride ());}
    int base (void) const {return (baseindex & 0x0F);}
    int index (void) const {return (baseindex >> 4);}
    int displacementsize (void) const {return (__flags & dm_displsizemask);}
    int hassegoverride (void) const {return (__flags & dm_segoverride);}
    int hasdisplacement (void) const {return (__flags & dm_hasdispl);}
    int hasbase (void) const {return (__flags & dm_hasbase);}
    int hasindex (void) const {return (__flags & dm_hasindex);}
    int hasscale (void) const {return (__flags & dm_hasscale);}
  };

//for dis_nearoperand_t.__flags
const dn_short  = 0x01;                 //jmp short X, loop X, etc X

//call/jmp near/short ptr XXXX
struct dis_nearoperand_t {
    dword ofs;                          //word/dword (check ../.size)
    byte __flags;
    int isshort (void) const {return (__flags & dn_short);}
  };

//call/jmp far ptr XXXX:XXXX
struct dis_faroperand_t {
    dword ofs;                          //word/dword (check ../.size)
    word seg;
  };

union dis_operands_t {
    dis_immoperand_t imm;
    dis_regoperand_t reg;
    dis_memoperand_t mem;
    dis_nearoperand_t nearptr;
    dis_faroperand_t farptr;
  };

//for dis_operand_t.flags
const dop_mem           = 0x00;         //a memory,
const dop_imm           = 0x01;         // immediate,
const dop_reg           = 0x02;         // register,
const dop_nearofs       = 0x03;         // near ptr and
const dop_farofs        = 0x04;         // far ptr operand
const dop_typemask      = 0x07;
const dop_small         = 0x08;         //print small (not set if large is)
const dop_large         = 0x10;         //print large (not set if small is)

//for dis_operand_t.size (not just memory operands)
const dop_sizebyte              = 0x00; //mov al,[1234h]
const dop_sizeword              = 0x01; //mov ax,[1234h]
const dop_sizedword             = 0x02; //mov eax,[1234h]
const dop_sizepword             = 0x03; //sgdt pword ptr [1234h]
const dop_sizeqword             = 0x04; //fistp qword ptr [1234h]
const dop_sizetbyte             = 0x05; //fbld tbyte ptr [1234h]
const dop_sizewordofs           = 0x06; //jmp/call word ptr ds:[1234h] (16-bit)
const dop_sizedwordsegofs       = 0x07; //jmp/call dword ptr ds:[1234h] (16-bit)
const dop_sizedwordofs          = 0x08; //jmp/call dword ptr ds:[1234h] (32-bit)
const dop_sizefwordsegofs       = 0x09; //jmp/call fword ptr ds:[1234h] (32-bit)
const dop_sizetwowords          = 0x0A; //two words in memory (bound)
const dop_sizetwodwords         = 0x0B; //two dwords in memory (bound)

struct dis_operand_t {
    dis_operands_t ops;
    dword flags;
    byte size;
    byte res[3];

    int ismem (void) const {return ((flags & dop_typemask) == dop_mem);}
    int isimm (void) const {return ((flags & dop_typemask) == dop_imm);}
    int isreg (void) const {return ((flags & dop_typemask) == dop_reg);}
    int isnearptr (void) const {return ((flags & dop_typemask) == dop_nearofs);}
    int isfarptr (void) const {return ((flags & dop_typemask) == dop_farofs);}
    int usesmall (void) const {return (flags & dop_small);}
    int uselarge (void) const {return (flags & dop_large);}
  };

#if sizeof (dis_operand_t) != 0x10
  #err
#endif

//for dis_opcode_t.flags
const do_hasmodrm       = 0x0001;       //if the instruction has a modR/M byte
const do_hassib         = 0x0002;       // and/or a sib byte
const do_showmemsize    = 0x0004;       //you should print the memory size
const do_dontshowmemsize= 0x0008;       //you shouldn't print the memory size
const do_dontprintops   = 0x0010;       //don't print the opcodes (string instr.)
const do_hasreg         = 0x0020;       //one or more of the operands is a reg
const do_hassegreg      = 0x0040;       //one operand has a segment register

//for dis_opcode_t.prefixes (will probably be changed if intel decides
//to add 2 more segment overrides)
const __dis_esprefix    = 0x01;         //You shouldn't care about these
const __dis_csprefix    = 0x02;         // segment overrides since __dis
const __dis_ssprefix    = 0x03;         // will save them in the right
const __dis_dsprefix    = 0x04;         // memory operand (if there is a
const __dis_fsprefix    = 0x05;         // memory operand, that is!!!)
const __dis_gsprefix    = 0x06;
const __dis_repprefix   = 0x08;         //both __dis_repprefix and
const __dis_repnzprefix = 0x10;         // __dis_repnzprefix are never set
const __dis_lockprefix  = 0x20;
const __dis_opprefix    = 0x40;         //66h (op) or 67h (adr) prefix. Will
const __dis_adrprefix   = 0x80;         // not be printed as an operand even
                                        // if __df_prefixinstructions is set!!!
                                        // If a 66h or 67h prefix is before
                                        // any other prefixes, __dis will not
                                        // print any of those prefixes as an
                                        // instruction

//for dis_opcode_t.opcodeid (the HIGH byte). The LOW byte is opcode AND FFh
//for opid_opnames1 and opid_opnames2.
const opid_opnames1     = 0x0000;       //opcodes 0000h -> 00FFh
const opid_opnames2     = 0x0100;       //opcodes 0F00h -> 0FFFh
const opid_grp1EbIbA    = 0x0200;       //0080h
const opid_grp1EvIv     = 0x0300;       //0081h
const opid_grp1EbIbB    = 0x0400;       //0082h
const opid_grp1EvIb     = 0x0500;       //0083h
const opid_grp2EbIb     = 0x0600;       //00C0h
const opid_grp2EvIb     = 0x0700;       //00C1h
const opid_grp2Eb1      = 0x0800;       //00D0h
const opid_grp2Ev1      = 0x0900;       //00D1h
const opid_grp2EbCL     = 0x0A00;       //00D2h
const opid_grp2EvCL     = 0x0B00;       //00D3h
const opid_grp3Eb       = 0x0C00;       //00F6h
const opid_grp3Ev       = 0x0D00;       //00F7h
const opid_grp4         = 0x0E00;       //00FEh
const opid_grp5         = 0x0F00;       //00FFh
const opid_grp6         = 0x1000;       //0F00h
const opid_grp7         = 0x1100;       //0F01h
const opid_grp8         = 0x1200;       //0FBAh
const opid_grp9         = 0x1300;       //0FC7h
const opid_grpA0F71     = 0x1400;       //0F71h
const opid_grpA0F72     = 0x1500;       //0F72h
const opid_grpA0F73     = 0x1600;       //0F73h
const opid_grpB         = 0x1700;       //0FAEh
const opid_special      = 0x1800;
const opid_floatD8reg   = 0x1900;       //00D8h with modR/M < C0h (00h-07h)
const opid_floatD9reg   = 0x1A00;
const opid_floatDAreg   = 0x1B00;
const opid_floatDBreg   = 0x1C00;
const opid_floatDCreg   = 0x1D00;
const opid_floatDDreg   = 0x1E00;
const opid_floatDEreg   = 0x1F00;
const opid_floatDFreg   = 0x2000;
const opid_floatD8      = 0x2100;       //00D8h with modR/M >= C0h
const opid_floatD9      = 0x2200;       // (the lsb in opcode.opcodeid
const opid_floatDA      = 0x2300;       // is modR/M-C0h, 00h-3Fh)
const opid_floatDB      = 0x2400;
const opid_floatDC      = 0x2500;
const opid_floatDD      = 0x2600;
const opid_floatDE      = 0x2700;
const opid_floatDF      = 0x2800;
//NOTE: If it's a K3D opcode (opid_amdk3d only), opcode.opcodeword
//is 0F00h + last_byte_in_instruction (=K3D opcode), since opcodeword
//is a word. Check high byte of opcodeid if you want to know it's
//a K3D instruction.
const opid_amdk3d       = 0x2900;     //0F0FXX opcodes
const opid_amdk3dspecial= 0x2A00;     //K3D instructions in normal intel tables
const opid_amdspecial   = 0x2B00;     //0FXX or XX opcodes
const opid_cyrixspecial = 0x2C00;     //Cyrix ops in normal intel table

enum __opid_amdspecial {
  opid_amdsyscall       = opid_amdspecial,//0Fh 05h
  opid_amdsysret,                       //0Fh, 07h
  opid_amdud,                           //0Fh, FFh
  };

enum __opid_amdk3dspecial {
  opid_amdprefetch      = opid_amdk3dspecial, //0Fh, 0Dh, xx000xxx
  opid_amdprefetchw,                    //0Fh, 0Dh, xx001xxx
  opid_amdprefetch2,                    //not used by amd yet
  opid_amdprefetch3,                    //
  opid_amdprefetch4,                    //
  opid_amdprefetch5,                    //
  opid_amdprefetch6,                    //
  opid_amdprefetch7,                    //
  opid_amdfemms                         //0Fh, 0Eh
  };

enum __opid_cyrixspecial {
  opid_cyrixsvdc,                       //0Fh, 78h
  opid_cyrixrsdc,                       //0Fh, 79h
  opid_cyrixsvldt,                      //0Fh, 7Ah
  opid_cyrixrsldt,                      //0Fh, 7Bh
  opid_cyrixsvts,                       //0Fh, 7Ch
  opid_cyrixrsts,                       //0Fh, 7Dh
                                        //0Fh, 7Eh moved to 0Fh, 38h
  opid_cyrixrdshr,                      //0Fh, 36h
  opid_cyrixwrshr,                      //0Fh, 37h
  opid_cyrixsmint,                      //0Fh, 38h
  opid_cyrixpaveb,                      //0Fh, 50h
  opid_cyrixpaddsiw,                    //0Fh, 51h
  opid_cyrixpmagw,                      //0Fh, 52h
  opid_cyrixpdistib,                    //0Fh, 54h
  opid_cyrixpsubsiw,                    //0Fh, 55h
  opid_cyrixpmvzb,                      //0Fh, 58h
  opid_cyrixpmulhrw,                    //0Fh, 59h
  opid_cyrixpmvnzb,                     //0Fh, 5Ah
  opid_cyrixpmvlzb,                     //0Fh, 5Bh
  opid_cyrixpmvgezb,                    //0Fh, 5Ch
  opid_cyrixpmulhriw,                   //0Fh, 5Dh
  opid_cyrixpmachriw,                   //0Fh, 5Eh
  };

enum __opid_special {
    opid_db       = opid_special,
    opid_enterd,
    opid_enterw,
    opid_enter,
    opid_sgdtd,
    opid_sgdtw,
    opid_sgdt,
    opid_sidtd,
    opid_sidtw,
    opid_sidt,
    opid_lgdtd,
    opid_lgdtw,
    opid_lgdt,
    opid_lidtd,
    opid_lidtw,
    opid_lidt,
    opid_loopdne,
    opid_loopwne,
    opid_loopne,
    opid_loopde,
    opid_loopwe,
    opid_loope,
    opid_loopd,
    opid_loopw,
    opid_loop,
    opid_jcxz,
    opid_jecxz,
    opid_cbw,
    opid_cwde,
    opid_cwd,
    opid_cdq,
    opid_pushad,
    opid_pushaw,
    opid_pusha,
    opid_popad,
    opid_popaw,
    opid_popa,
    opid_pushfd,
    opid_pushfw,
    opid_pushf,
    opid_popfd,
    opid_popfw,
    opid_popf,
    opid_leaved,
    opid_leavew,
    opid_leave,
    opid_iretd,
    opid_iretw,
    opid_iret,
    opid_retnd,
    opid_retnw,
    opid_retn,
    opid_retfd,
    opid_retfw,
    opid_retf,
    opid_xlat,
    opid_xlatb,
    opid_ins,
    opid_insb,
    opid_insw,
    opid_insd,
    opid_outs,
    opid_outsb,
    opid_outsw,
    opid_outsd,
    opid_scas,
    opid_scasb,
    opid_scasw,
    opid_scasd,
    opid_stos,
    opid_stosb,
    opid_stosw,
    opid_stosd,
    opid_lods,
    opid_lodsb,
    opid_lodsw,
    opid_lodsd,
    opid_cmps,
    opid_cmpsb,
    opid_cmpsw,
    opid_cmpsd,
    opid_movs,
    opid_movsb,
    opid_movsw,
    opid_movsd,
    opid_esc
  };

//for dis_opcode.optype
const optype_dunno      = 0x00;
const optype_far        = 0x01;         //call/jmp far
const optype_near       = 0x02;         //call/jmp near
const optype_short      = 0x03;         //call/jmp/loop/etc short

//everything in this struct can and will be changed when you call __dis ()
struct dis_opcode_t {
    dis_operand_t op[3];                //the three operands
    word flags;
    word opcodeword;                    //00XXh or 0FXXh
    word opcodeid;                      //see opid_XXX equates (name of instr.)
    byte opsize;                        //operand size (16 or 32)
    byte adrsize;                       //address size (16 or 32)
    byte rm;                            //the rm field in modR/M
    byte modrm;                         //the modR/M byte (if any)
    byte reg;                           //the reg field in modR/M
    byte mod;                           //the mod field in modR/M
    byte sib;                           //the sib byte (if any)
    byte noperands;                     //# of operands. CHECK THIS FIRST
    byte prefixes;                      // BEFORE USING ANY OTHER DATA IN
                                        // THIS STRUCT!!!
    byte optype;                        //Type of opcode (optype_xxx)

    int hasmodrm (void) const {return (flags & do_hasmodrm);}
    int hassib (void) const {return (flags & do_hassib);}
    int showmemsize (void) const {return (flags & do_showmemsize);}
    int dontshowmemsize (void) const {return (flags & do_dontshowmemsize);}
    int dontprintops (void) const {return (flags & do_dontprintops);}
    int hasreg (void) const {return (flags & do_hasreg);}
    int hassegreg (void) const {return (flags & do_hassegreg);}
    int segprefix (void) const {return ((prefixes & 0x07) - 1);}
    int hasrepprefix (void) const {return (prefixes & __dis_repprefix);}
    int hasrepnzprefix (void) const {return (prefixes & __dis_repnzprefix);}
    int haslockprefix (void) const {return (prefixes & __dis_lockprefix);}
    int hasopprefix (void) const {return (prefixes & __dis_opprefix);}
    int hasadrprefix (void) const {return (prefixes & __dis_adrprefix);}
    int isstringinstruction (void) const {return (opcodeid >= opid_ins && opcodeid <= opid_movsd);}
  };

#if sizeof (dis_opcode_t) & 3
  #err
#endif

//for __dis_input_t.flags
const __df_prefixinstructions   = 0x00000001; //print a prefix as an operand
const __df_showsizeop           = 0x00000002; //mov al,[0] -> mov al,small [0] (etc)
const __df_stringoperands       = 0x00000004; //expand string instructions + xlat
const __df_floatasesc           = 0x00000008; //print float as esc opcodes

//for __dis_input.cputype
const __discpu_intel    = 0x00;         //intel 8088+ opcodes
const __discpu_amd      = 0x01;         //intel 8088+, AMD and K3D opcodes
const __discpu_cyrix    = 0x02;         //intel 8088+ and Cyrix opcodes

struct __dis_input_t;
typedef __cdecl int (*getbyte_t)(__dis_input_t &);

struct __dis_input_t {
    dis_opcode_t opcode;                //will be changed in __dis ()
    dword eip;
    dword flags;
#if sizeof (int) == 4
  #if sizeof (void (*)(void)) == 6
    //
    //   Get the next instruction byte
    //
    //   returns <= 0xFF if no error. returns > 0xFF if error
    //
    getbyte_t _getbyte [1];
    byte __res[2];
  #elseif sizeof (void (*)(void)) == 4
    getbyte_t _getbyte [2];
  #elseif sizeof (void (*)(void)) == 8
    getbyte_t _getbyte [1];
  #else
    getbyte_t _getbyte [2];
//    #err
#endif
#else
  #if sizeof (void (*)(void)) == 4
    //
    //   Get the next instruction byte
    //
    //   returns <= 0xFF if no error. returns > 0xFF if error
    //
    getbyte_t _getbyte [1];
  #else
    getbyte_t _getbyte [2];
  #endif
#endif
    byte codesize;                      //16 or 32-bit code (not changed by me)
    byte cputype;
    byte res[2];

    __cdecl int getbyte (__dis_input_t &di) {return (_getbyte[0](di));}
  };

#if sizeof (__dis_input_t) & 3
  #err
#endif

//decode one instruction (but not print it in a string)
//returns 0=not ok,!0=ok (.getbyte returned > 0x00FF)
extern "C" __cdecl unsigned int __dis (__dis_input_t &);

#endif
