/* This file is in the public domain. */ #include #include "fnprintf.h" #include "machine.h" #include #include /* text ~ escapes: ~?...~|...~. conditional : o true if 16-bit osize, else 32-bit osize a true if 16-bit asize, else 32-bit asize O true if 32-bit osize, else 16-bit osize A true if 32-bit asize, else 16-bit asize may be nested, up to about 30 deep ~W same as ~?oW~|D~. ~E same as ~?OE~. ~F causes the disassembly to fail ~p pad to 16-char boundary, always at least two spaces ~c condition code name ~rx operand: r/m, x is size char ~mx operand: mem, x is size char ~Rx operand: reg, x is size char ~ix operand: imm, x is size char ~jx operand: jump displacement, x is size char ~!x mark place, x is single digit ~<...~>x process text, insert it at place marked x (cannot be nested) size char: '?': unspecified (valid only for ~m) '1': 8 '2': 16 '4': 32 '8': 64 'a': 80 'O': osize 'A': asize 'S': valid only for ~R, indicates a segment register 'C': valid only for ~R, indicates a control register 'D': valid only for ~R, indicates a debug register 'T': valid only for ~R, indicates a test register 'F': valid only for ~R, indicates an FPU register 'M': valid only for ~R, indicates an MMX register */ #define F_REPE 0x00000001 /* 0xf3 is REPE, not REP */ typedef struct onebyte ONEBYTE; typedef struct oneb_digit ONEB_DIGIT; typedef struct twobyte TWOBYTE; typedef struct twob_digit TWOB_DIGIT; struct onebyte { unsigned char byte; const char *text; unsigned int flags; } ; struct oneb_digit { unsigned char byte; const char *texts[8]; } ; struct twobyte { unsigned char byte1; unsigned char byte2; const char *text; } ; struct twob_digit { unsigned char byte1; unsigned char byte2; const char *texts[8]; } ; static const char *regs_8[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" }; static const char *regs_16[] = { "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI" }; static const char *regs_32[] = { "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI" }; static const char *regs_mmx[] = { "MM0", "MM1", "MM2", "MM3", "MM4", "MM5", "MM6", "MM7" }; static const char *regs_seg[] = { "ES", "CS", "SS", "DS", "FS", "GS", 0, 0 }; static const char *regs_ctl[] = { "CR0", 0, "CR2", "CR3", "CR4", 0, 0, 0 }; static const char *regs_dbg[] = { "DR0", "DR1", "DR2", "DR3", 0, 0, 0, 0 }; static const char *regs_test[] = { 0, 0, 0, "TR3", "TR4", "TR5", "TR6", "TR7" }; static const char *cc_name[] = { "O", "NO", "C", "NC", "Z", "NZ", "BE", "A", "S", "NS", "PE", "PO", "L", "GE", "LE", "G" }; static const char *regs_fp[] = { "ST0", "ST1", "ST2", "ST3", "ST4", "ST5", "ST6", "ST7" }; /* One constant byte, nothing more */ static const ONEBYTE onebyte[] = { { 0x06, "PUSH~pES" }, { 0x07, "POP~pES" }, { 0x0e, "PUSH~pCS" }, { 0x16, "PUSH~pSS" }, { 0x17, "POP~pSS" }, { 0x1e, "PUSH~pDS" }, { 0x1f, "POP~pDS" }, { 0x27, "DAA" }, { 0x2f, "DAS" }, { 0x37, "AAA" }, { 0x3f, "AAS" }, { 0x40, "INC~p~EAX" }, { 0x41, "INC~p~ECX" }, { 0x42, "INC~p~EDX" }, { 0x43, "INC~p~EBX" }, { 0x44, "INC~p~ESP" }, { 0x45, "INC~p~EBP" }, { 0x46, "INC~p~ESI" }, { 0x47, "INC~p~EDI" }, { 0x48, "DEC~p~EAX" }, { 0x49, "DEC~p~ECX" }, { 0x4a, "DEC~p~EDX" }, { 0x4b, "DEC~p~EBX" }, { 0x4c, "DEC~p~ESP" }, { 0x4d, "DEC~p~EBP" }, { 0x4e, "DEC~p~ESI" }, { 0x4f, "DEC~p~EDI" }, { 0x50, "PUSH~p~EAX" }, { 0x51, "PUSH~p~ECX" }, { 0x52, "PUSH~p~EDX" }, { 0x53, "PUSH~p~EBX" }, { 0x54, "PUSH~p~ESP" }, { 0x55, "PUSH~p~EBP" }, { 0x56, "PUSH~p~ESI" }, { 0x57, "PUSH~p~EDI" }, { 0x58, "POP~p~EAX" }, { 0x59, "POP~p~ECX" }, { 0x5a, "POP~p~EDX" }, { 0x5b, "POP~p~EBX" }, { 0x5c, "POP~p~ESP" }, { 0x5d, "POP~p~EBP" }, { 0x5e, "POP~p~ESI" }, { 0x5f, "POP~p~EDI" }, { 0x60, "PUSHA~W" }, { 0x61, "POPA~W" }, { 0x6c, "INSB" }, { 0x6d, "INS~W" }, { 0x6e, "OUTSB" }, { 0x6f, "OUTS~W" }, { 0x90, "NOP" }, { 0x91, "XCHG~p~EAX, ~ECX" }, { 0x92, "XCHG~p~EAX, ~EDX" }, { 0x93, "XCHG~p~EAX, ~EBX" }, { 0x94, "XCHG~p~EAX, ~ESP" }, { 0x95, "XCHG~p~EAX, ~EBP" }, { 0x96, "XCHG~p~EAX, ~ESI" }, { 0x97, "XCHG~p~EAX, ~EDI" }, { 0x98, "~?oCBW~|CWDE~." }, { 0x99, "~?oCDQ~|CWD~." }, { 0x9b, "WAIT" }, { 0x9c, "PUSHF~W" }, { 0x9d, "POPF~W" }, { 0x9e, "SAHF" }, { 0x9f, "LAHF" }, { 0xa4, "MOVSB" }, { 0xa5, "MOVS~W" }, { 0xa6, "CMPSB", F_REPE }, { 0xa7, "CMPS~W", F_REPE }, { 0xaa, "STOSB" }, { 0xab, "STOS~W" }, { 0xac, "LODSB" }, { 0xad, "LODS~W" }, { 0xae, "SCASB", F_REPE }, { 0xaf, "SCAS~W", F_REPE }, { 0xc3, "RETN" }, { 0xc9, "LEAVE" }, { 0xcb, "RETF" }, { 0xcc, "INT3" }, { 0xce, "INTO" }, { 0xcf, "IRET~W" }, { 0xd6, "SALC" }, { 0xd7, "XLATB" }, { 0xec, "IN~pAL, DX" }, { 0xed, "IN~p~EAX, DX" }, { 0xee, "OUT~pDX, AL" }, { 0xef, "OUT~pDX, ~EAX" }, { 0xf1, "INT1" }, { 0xf4, "HLT" }, { 0xf5, "CMC" }, { 0xf8, "CLC" }, { 0xf9, "STC" }, { 0xfa, "CLI" }, { 0xfb, "STI" }, { 0xfc, "CLD" }, { 0xfd, "STD" } }; static const int onebyte_n = sizeof(onebyte) / sizeof(onebyte[0]); /* One constant byte plus a /digit operand */ static const ONEB_DIGIT oneb_digit[] = { { 0x8f, { "POP~p~rO", 0, 0, 0, 0, 0, 0, 0 } }, { 0xd0, { "ROL~p~r1, 1", "ROR~p~r1, 1", "RCL~p~r1, 1", "RCR~p~r1, 1", "SHL~p~r1, 1", "SHR~p~r1, 1", 0, "SAR~p~r1, 1" } }, { 0xd1, { "ROL~p~rO, 1", "ROR~p~rO, 1", "RCL~p~rO, 1", "RCR~p~rO, 1", "SHL~p~rO, 1", "SHR~p~rO, 1", 0, "SAR~p~rO, 1" } }, { 0xd2, { "ROL~p~r1, CL", "ROR~p~r1, CL", "RCL~p~r1, CL", "RCR~p~r1, CL", "SHL~p~r1, CL", "SHR~p~r1, CL", 0, "SAR~p~r1, CL" } }, { 0xd3, { "ROL~p~rO, CL", "ROR~p~rO, CL", "RCL~p~rO, CL", "RCR~p~rO, CL", "SHL~p~rO, CL", "SHR~p~rO, CL", 0, "SAR~p~rO, CL" } }, { 0xd8, { "FADD~p~m4", "FMUL~p~m4", "FCOM~p~m4", "FCOMP~p~m4", "FSUB~p~m4", "FSUBR~p~m4", "FDIV~p~m4", "FDIVR~p~m4" } }, { 0xd9, { "FLD~p~m4", 0, "FST~p~m4", "FSTP~p~m4", "FLDENV~p~m?", "FLDCW~p~m2", "FNSTENV~p~m?", "FNSTCW~p~m2" } }, { 0xda, { "FIADD~p~m4", "FIMUL~p~m4", "FICOM~p~m4", "FICOMP~p~m4", "FISUB~p~m4", "FISUBR~p~m4", "FIDIV~p~m4", "FIDIVR~p~m4" } }, { 0xdb, { "FILD~p~m4", 0, "FIST~p~m4", "FISTP~p~m4", 0, "FLD~p~ma", 0, "FSTP~p~ma" } }, { 0xdc, { "FADD~p~m8", "FMUL~p~m8", "FCOM~p~m8", "FCOMP~p~m8", "FSUB~p~m8", "FSUBR~p~m8", "FDIV~p~m8", "FDIVR~p~m8" } }, { 0xdd, { "FLD~p~m8", 0, "FST~p~m8", "FSTP~p~m8", "FRSTOR~p~m?", 0, "FNSAVE~p~m?", "FNSTSW~p~m2" } }, { 0xde, { "FIADD~p~m2", "FIMUL~p~m2", "FICOM~p~m2", "FICOMP~p~m2", "FISUB~p~m2", "FISUBR~p~m2", "FIDIV~p~m2", "FIDIVR~p~m2" } }, { 0xdf, { "FILD~p~m2", 0, "FIST~p~m2", "FISTP~p~m2", "FBLD~p~ma", "FILD~p~m8", "FBSTP~p~ma", "FISTP~p~m8" } }, { 0xf6, { 0, 0, "NOT~p~r1", "NEG~p~r1", "MUL~p~r1", "IMUL~p~r1", "DIV~p~r1", "IDIV~p~r1" } }, { 0xf7, { 0, 0, "NOT~p~rO", "NEG~p~rO", "MUL~p~rO", "IMUL~p~rO", "DIV~p~rO", "IDIV~p~rO" } }, { 0xfe, { "INC~p~r1", "DEC~p~r1", 0, 0, 0, 0, 0, 0 } }, { 0xff, { "INC~p~rO", "DEC~p~rO", "CALL~p~rO", "CALL~pFAR ~mO", "JMP~pNEAR ~rO", "JMP~pFAR ~m?", "PUSH~p~rO", 0 } } }; static const int oneb_digit_n = sizeof(oneb_digit) / sizeof(oneb_digit[0]); /* Single constant byte followed by /r */ static const ONEBYTE oneb_r[] = { { 0x00, "ADD~p~r1, ~R1" }, { 0x01, "ADD~p~rO, ~RO" }, { 0x02, "ADD~p~R1, ~r1" }, { 0x03, "ADD~p~RO, ~rO" }, { 0x08, "OR~p~r1, ~R1" }, { 0x09, "OR~p~rO, ~RO" }, { 0x0a, "OR~p~R1, ~r1" }, { 0x0b, "OR~p~RO, ~rO" }, { 0x10, "ADC~p~r1, ~R1" }, { 0x11, "ADC~p~rO, ~RO" }, { 0x12, "ADC~p~R1, ~r1" }, { 0x13, "ADC~p~RO, ~rO" }, { 0x18, "SBB~p~r1, ~R1" }, { 0x19, "SBB~p~rO, ~RO" }, { 0x1a, "SBB~p~R1, ~r1" }, { 0x1b, "SBB~p~RO, ~rO" }, { 0x20, "AND~p~r1, ~R1" }, { 0x21, "AND~p~rO, ~RO" }, { 0x22, "AND~p~R1, ~r1" }, { 0x23, "AND~p~RO, ~rO" }, { 0x28, "SUB~p~r1, ~R1" }, { 0x29, "SUB~p~rO, ~RO" }, { 0x2a, "SUB~p~R1, ~r1" }, { 0x2b, "SUB~p~RO, ~rO" }, { 0x30, "XOR~p~r1, ~R1" }, { 0x31, "XOR~p~rO, ~RO" }, { 0x32, "XOR~p~R1, ~r1" }, { 0x33, "XOR~p~RO, ~rO" }, { 0x38, "CMP~p~r1, ~R1" }, { 0x39, "CMP~p~rO, ~RO" }, { 0x3a, "CMP~p~R1, ~r1" }, { 0x3b, "CMP~p~RO, ~rO" }, { 0x62, "BOUND~p~RO, ~m?" }, { 0x63, "ARPL~p~r2, ~R2" }, { 0x84, "TEST~p~r1, ~R1" }, { 0x85, "TEST~p~rO, ~RO" }, { 0x86, "XCHG~p~R1, ~r1" }, { 0x87, "XCHG~p~RO, ~rO" }, { 0x88, "MOV~p~r1, ~R1" }, { 0x89, "MOV~p~rO, ~RO" }, { 0x8a, "MOV~p~R1, ~r1" }, { 0x8b, "MOV~p~RO, ~rO" }, { 0x8c, "MOV~p~rO, ~RS" }, { 0x8d, "LEA~p~RO, ~m?" }, { 0x8e, "MOV~p~RS, ~rO" }, { 0xc4, "LES~p~RO, ~m?" }, { 0xc5, "LDS~p~RO, ~m?" } }; static const int oneb_r_n = sizeof(oneb_r) / sizeof(oneb_r[0]); /* Single constant byte followed by immediate */ static const ONEBYTE oneb_i[] = { { 0x04, "ADD~pAL, ~i1" }, { 0x05, "ADD~p~EAX, ~iO" }, { 0x0c, "OR~pAL, ~i1" }, { 0x0d, "OR~p~EAX, ~iO" }, { 0x14, "ADC~pAL, ~i1" }, { 0x15, "ADC~p~EAX, ~iO" }, { 0x1c, "SBB~pAL, ~i1" }, { 0x1d, "SBB~p~EAX, ~iO" }, { 0x24, "AND~pAL, ~i1" }, { 0x25, "AND~p~EAX, ~iO" }, { 0x2c, "SUB~pAL, ~i1" }, { 0x2d, "SUB~p~EAX, ~iO" }, { 0x34, "XOR~pAL, ~i1" }, { 0x35, "XOR~p~EAX, ~iO" }, { 0x3c, "CMP~pAL, ~i1" }, { 0x3d, "CMP~p~EAX, ~iO" }, { 0x68, "PUSH~p~iO" }, { 0x6a, "PUSH~p~i1" }, { 0xa8, "TEST~pAL, ~i1" }, { 0xa9, "TEST~p~EAX, ~iO" }, { 0xcd, "INT~p~i1" }, { 0xd4, "AAM~p~i1" }, { 0xd5, "AAD~p~i1" }, { 0xe0, "LOOPNE~p~j1, ~?AE~.CX" }, { 0xe1, "LOOPE~p~j1, ~?AE~.CX" }, { 0xe2, "LOOP~p~j1, ~?AE~.CX" }, { 0xe3, "J~ECXZ~p~j1" }, { 0xe4, "IN~pAL, ~i1" }, { 0xe5, "IN~p~EAX, ~i1" }, { 0xe6, "OUT~p~i1, AL" }, { 0xe7, "OUT~p~i1, ~EAX" }, { 0xe8, "CALL~p~jO" }, { 0xe9, "JMP~p~jO" }, { 0xeb, "JMP~pSHORT ~j1" } }; static const int oneb_i_n = sizeof(oneb_i) / sizeof(oneb_i[0]); /* Two constant bytes */ static const TWOBYTE twobyte[] = { { 0x0f, 0x05, "LOADALL286" }, { 0x0f, 0x06, "CLTS" }, { 0x0f, 0x07, "LOADALL" }, { 0x0f, 0x08, "INVD" }, { 0x0f, 0x09, "WBINVD" }, { 0x0f, 0x0b, "UD2A" }, { 0x0f, 0x30, "WRMSR" }, { 0x0f, 0x31, "RDTSC" }, { 0x0f, 0x32, "RDMSR" }, { 0x0f, 0x33, "RDPMC" }, #if 0 /* 40 */ { "cmovo", Gv,Ev }, { "cmovno", Gv,Ev }, { "cmovb", Gv,Ev }, { "cmovae", Gv,Ev }, { "cmove", Gv,Ev }, { "cmovne", Gv,Ev }, { "cmovbe", Gv,Ev }, { "cmova", Gv,Ev }, /* 48 */ { "cmovs", Gv,Ev }, { "cmovns", Gv,Ev }, { "cmovp", Gv,Ev }, { "cmovnp", Gv,Ev }, { "cmovl", Gv,Ev }, { "cmovge", Gv,Ev }, { "cmovle", Gv,Ev }, { "cmovg", Gv,Ev }, { GRP10 }, /* 71 */ { GRP11 }, /* 72 */ { GRP12 }, /* 73 */ /* 80 */ { "jo", Jv }, { "jno", Jv }, { "jb", Jv }, { "jae", Jv }, { "je", Jv }, { "jne", Jv }, { "jbe", Jv }, { "ja", Jv }, /* 88 */ { "js", Jv }, { "jns", Jv }, { "jp", Jv }, { "jnp", Jv }, { "jl", Jv }, { "jge", Jv }, { "jle", Jv }, { "jg", Jv }, /* 90 */ { "seto", Eb }, { "setno", Eb }, { "setb", Eb }, { "setae", Eb }, { "sete", Eb }, { "setne", Eb }, { "setbe", Eb }, { "seta", Eb }, /* 98 */ { "sets", Eb }, { "setns", Eb }, { "setp", Eb }, { "setnp", Eb }, { "setl", Eb }, { "setge", Eb }, { "setle", Eb }, { "setg", Eb }, { "shldS", Ev, Gv, Ib }, /* a4 */ { "shrdS", Ev, Gv, Ib }, /* ac */ { GRP8 }, /* ba */ { GRP9 }, /* c7 */ /* c8 */ { "bswap", eAX }, { "bswap", eCX }, { "bswap", eDX }, { "bswap", eBX }, { "bswap", eSP }, { "bswap", eBP }, { "bswap", eSI }, { "bswap", eDI }, #endif { 0x0f, 0x77, "EMMS" }, { 0x0f, 0xa0, "PUSH~pFS" }, { 0x0f, 0xa1, "POP~pFS" }, { 0x0f, 0xa2, "CPUID" }, { 0x0f, 0xa8, "PUSH~pGS" }, { 0x0f, 0xa9, "POP~pGS" }, { 0x0f, 0xaa, "RSM" }, { 0x0f, 0xb8, "UD2B" }, { 0xd0, 0xe4, "FTST" }, { 0xd9, 0xd0, "FNOP" }, { 0xd9, 0xe0, "FCHS" }, { 0xd9, 0xe1, "FABS" }, { 0xd9, 0xe5, "FXAM" }, { 0xd9, 0xe8, "FLD1" }, { 0xd9, 0xe9, "FLDL2T" }, { 0xd9, 0xea, "FLDL2E" }, { 0xd9, 0xeb, "FLDPI" }, { 0xd9, 0xec, "FLDLG2" }, { 0xd9, 0xed, "FLDLN2" }, { 0xd9, 0xee, "FLDZ" }, { 0xd9, 0xf0, "F2XM1" }, { 0xd9, 0xf1, "FYL2X" }, { 0xd9, 0xf2, "FPTAN" }, { 0xd9, 0xf3, "FPATAN" }, { 0xd9, 0xf4, "FXTRACT" }, { 0xd9, 0xf5, "FPREM1" }, { 0xd9, 0xf6, "FDECSTP" }, { 0xd9, 0xf7, "FINCSTP" }, { 0xd9, 0xf8, "FPREM" }, { 0xd9, 0xf9, "FYL2XP1" }, { 0xd9, 0xfa, "FSQRT" }, { 0xd9, 0xfb, "FSINCOS" }, { 0xd9, 0xfc, "FRNDINT" }, { 0xd9, 0xfd, "FSCALE" }, { 0xd9, 0xfe, "FSIN" }, { 0xd9, 0xff, "FCOS" }, { 0xda, 0xe9, "FUCOMPP" }, { 0xdb, 0xe0, "FNENI" }, { 0xdb, 0xe1, "FNDISI" }, { 0xdb, 0xe2, "FNCLEX" }, { 0xdb, 0xe3, "FNINIT" }, { 0xdb, 0xe4, "FSETPM" }, { 0xde, 0xd9, "FCOMPP" }, { 0xdf, 0xe0, "FNSTSW~pAX" } }; static const int twobyte_n = sizeof(twobyte) / sizeof(twobyte[0]); /* Two constant bytes plus /digit */ static const TWOB_DIGIT twob_digit[] = { { 0x0f, 0x00, { "SLDT~p~r2", "STR~p~r2", "LLDT~p~r2", "LTR~p~r2", "VERR~p~r2", "VERW~p~r2", 0, 0 } }, { 0x0f, 0x01, { "SGDT~p~m?", "SIDT~p~m?", "LGDT~p~m?", "LIDT~p~m?", "SMSW~p~m2", 0, "LMSW~p~m2", "INVLPG~p~m?" } }, { 0x0f, 0xc7, { 0, "CMPXCHG8B~p~m?", 0, 0, 0, 0, 0, 0 } } }; static const int twob_digit_n = sizeof(twob_digit) / sizeof(twob_digit[0]); /* Two constant bytes plus /r */ static const TWOBYTE twob_r[] = { { 0x0f, 0x02, "LAR~p~RO, ~rO" }, { 0x0f, 0x03, "LSL~p~RO, ~rO" }, { 0x0f, 0x10, "UMOV~p~r1, ~R1" }, { 0x0f, 0x11, "UMOV~p~rO, ~RO" }, { 0x0f, 0x12, "UMOV~p~R1, ~r1" }, { 0x0f, 0x13, "UMOV~p~RO, ~rO" }, { 0x0f, 0x20, "MOV~p~R4, ~RC" }, { 0x0f, 0x21, "MOV~p~R4, ~RD" }, { 0x0f, 0x22, "MOV~p~RC, ~R4" }, { 0x0f, 0x23, "MOV~p~RD, ~R4" }, { 0x0f, 0x24, "MOV~p~R4, ~RT" }, { 0x0f, 0x26, "MOV~p~RT, ~R4" }, { 0x0f, 0x50, "PAVEB~p~RM, ~r8" }, { 0x0f, 0x51, "PADDSIW~p~RM, ~r8" }, { 0x0f, 0x52, "PMAGW~p~RM, ~r8" }, { 0x0f, 0x54, "PDISTIB~p~RM, ~m8" }, { 0x0f, 0x55, "PSUBSIW~p~RM, ~r8" }, { 0x0f, 0x58, "PMVZB~p~RM, ~m8" }, { 0x0f, 0x59, "PMULHRW~p~RM, ~r8" }, { 0x0f, 0x5a, "PMVNZB~p~RM, ~m8" }, { 0x0f, 0x5b, "PMVLZB~p~RM, ~m8" }, { 0x0f, 0x5c, "PMVGEZB~p~RM, ~m8" }, { 0x0f, 0x5d, "PMULHRIW~p~RM, ~r8" }, { 0x0f, 0x5e, "PMACHRIW~p~RM, ~m8" }, { 0x0f, 0x60, "PUNPCKLBW~p~RM, ~r8" }, { 0x0f, 0x61, "PUNPCKLWD~p~RM, ~r8" }, { 0x0f, 0x62, "PUNPCKLDQ~p~RM, ~r8" }, { 0x0f, 0x63, "PACKSSWB~p~RM, ~r8" }, { 0x0f, 0x64, "PCMPGTB~p~RM, ~r8" }, { 0x0f, 0x65, "PCMPGTW~p~RM, ~r8" }, { 0x0f, 0x66, "PCMPGTD~p~RM, ~r8" }, { 0x0f, 0x67, "PACKUSWB~p~RM, ~r8" }, { 0x0f, 0x68, "PUNPCKHBW~p~RM, ~r8" }, { 0x0f, 0x69, "PUNPCKHWD~p~RM, ~r8" }, { 0x0f, 0x6a, "PUNPCKHDQ~p~RM, ~r8" }, { 0x0f, 0x6b, "PACKSSDW~p~RM, ~r8" }, { 0x0f, 0x6e, "MOVD~p~RM, ~r4" }, { 0x0f, 0x6f, "MOVQ~p~RM, ~r8" }, { 0x0f, 0x74, "PCMPEQB~p~RM, ~r8" }, { 0x0f, 0x75, "PCMPEQW~p~RM, ~r8" }, { 0x0f, 0x76, "PCMPEQD~p~RM, ~r8" }, { 0x0f, 0x7e, "MOVD~p~r4, ~RM" }, { 0x0f, 0x7f, "MOVQ~p~r8, ~RM" }, { 0x0f, 0xa3, "BT~p~rO, ~RO" }, { 0x0f, 0xa5, "SHLD~p~rO, ~RO, CL" }, { 0x0f, 0xa6, "XBTS~p~RO, ~rO" }, { 0x0f, 0xa7, "IBTS~p~rO, ~RO" }, { 0x0f, 0xab, "BTS~p~rO, ~RO" }, { 0x0f, 0xad, "SHRD~p~rO, ~RO, CL" }, { 0x0f, 0xaf, "IMUL~p~RO, ~rO" }, { 0x0f, 0xb0, "CMPXCHG~p~r1, ~R1" }, { 0x0f, 0xb1, "CMPXCHG~p~rO, ~RO" }, { 0x0f, 0xb2, "LSS~prO, ~m?" }, { 0x0f, 0xb3, "BTR~p~rO, ~RO" }, { 0x0f, 0xb4, "LFS~prO, ~m?" }, { 0x0f, 0xb5, "LGS~prO, ~m?" }, { 0x0f, 0xb6, "MOVZX~p~RO, ~r1" }, { 0x0f, 0xb7, "~?o~F~.MOVZX~p~R4, ~r2" }, { 0x0f, 0xbb, "BTC~p~rO, ~RO" }, { 0x0f, 0xbc, "BSF~p~RO, ~rO" }, { 0x0f, 0xbd, "BSR~p~RO, ~rO" }, { 0x0f, 0xbe, "MOVSX~p~RO, ~r1" }, { 0x0f, 0xbf, "~?o~F~.MOVSX~p~R4, ~r2" }, { 0x0f, 0xc0, "XADD~p~r1, ~R1" }, { 0x0f, 0xc1, "XADD~p~rO, ~RO" }, { 0x0f, 0xd1, "PSRLW~p~RM, ~r8" }, { 0x0f, 0xd2, "PSRLD~p~RM, ~r8" }, { 0x0f, 0xd3, "PSRLQ~p~RM, ~r8" }, { 0x0f, 0xd5, "PMULLW~p~RM, ~r8" }, { 0x0f, 0xd8, "PSUBUSB~p~RM, ~r8" }, { 0x0f, 0xd9, "PSUBUSW~p~RM, ~r8" }, { 0x0f, 0xdb, "PAND~p~RM, ~r8" }, { 0x0f, 0xdc, "PADDUSB~p~RM, ~r8" }, { 0x0f, 0xdd, "PADDUSW~p~RM, ~r8" }, { 0x0f, 0xdf, "PANDN~p~RM, ~r8" }, { 0x0f, 0xe1, "PSRAW~p~RM, ~r8" }, { 0x0f, 0xe2, "PSRAD~p~RM, ~r8" }, { 0x0f, 0xe5, "PMULHW~p~RM, ~r8" }, { 0x0f, 0xe8, "PSUBSB~p~RM, ~r8" }, { 0x0f, 0xe9, "PSUBSW~p~RM, ~r8" }, { 0x0f, 0xeb, "POR~p~RM, ~r8" }, { 0x0f, 0xec, "PADDSB~p~RM, ~r8" }, { 0x0f, 0xed, "PADDSW~p~RM, ~r8" }, { 0x0f, 0xef, "PXOR~p~RM, ~r8" }, { 0x0f, 0xf1, "PSLLW~p~RM, ~r8" }, { 0x0f, 0xf2, "PSLLD~p~RM, ~r8" }, { 0x0f, 0xf3, "PSLLQ~p~RM, ~r8" }, { 0x0f, 0xf5, "PMADDWD~p~RM, ~r8" }, { 0x0f, 0xf8, "PSUBB~p~RM, ~r8" }, { 0x0f, 0xf9, "PSUBW~p~RM, ~r8" }, { 0x0f, 0xfa, "PSUBD~p~RM, ~r8" }, { 0x0f, 0xfc, "PADDB~p~RM, ~r8" }, { 0x0f, 0xfd, "PADDW~p~RM, ~r8" }, { 0x0f, 0xfe, "PADDD~p~RM, ~r8" } }; static const int twob_r_n = sizeof(twob_r) / sizeof(twob_r[0]); /* Two bytes, first constant, second +r */ static const TWOBYTE twob_plusr[] = { { 0x0f, 0xc8, "BSWAP~p~R4" }, { 0xd8, 0xc0, "FADD~p~RF" }, { 0xd8, 0xc8, "FMUL~p~RF" }, { 0xd8, 0xd0, "FCOM~p~RF" }, { 0xd8, 0xd8, "FCOMP~p~RF" }, { 0xd8, 0xe0, "FSUB~p~RF" }, { 0xd8, 0xe8, "FSUBR~p~RF" }, { 0xd8, 0xf0, "FDIV~p~RF" }, { 0xd8, 0xf8, "FDIVR~p~RF" }, { 0xd9, 0xc0, "FLD~p~RF" }, { 0xd9, 0xc8, "FXCH~p~RF" }, { 0xda, 0xc0, "FCMOVB~p~RF" }, { 0xda, 0xc8, "FCMOVE~p~RF" }, { 0xda, 0xd0, "FCMOVBE~p~RF" }, { 0xda, 0xd8, "FCMOVU~p~RF" }, { 0xdb, 0xc0, "FCMOVNB~p~RF" }, { 0xdb, 0xc8, "FCMOVNE~p~RF" }, { 0xdb, 0xd0, "FCMOVNBE~p~RF" }, { 0xdb, 0xd8, "FCMOVNU~p~RF" }, { 0xdb, 0xe8, "FUCOMI~p~RF" }, { 0xdb, 0xf0, "FCOMI~p~RF" }, { 0xdc, 0xc0, "FADD~pTO ~RF" }, { 0xdc, 0xc8, "FMUL~pTO ~RF" }, { 0xdc, 0xe0, "FSUBR~pTO ~RF" }, { 0xdc, 0xe8, "FSUB~pTO ~RF" }, { 0xdc, 0xf0, "FDIVR~pTO ~RF" }, { 0xdc, 0xf8, "FDIV~pTO ~RF" }, { 0xdd, 0xc0, "FFREE~p~RF" }, { 0xdd, 0xd0, "FST~p~RF" }, { 0xdd, 0xd8, "FSTP~p~RF" }, { 0xdd, 0xe0, "FUCOM~p~RF" }, { 0xdd, 0xe8, "FUCOMP~p~RF" }, { 0xde, 0xc0, "FADDP~p~RF" }, { 0xde, 0xc8, "FMULP~p~RF" }, { 0xde, 0xe0, "FSUBRP~p~RF" }, { 0xde, 0xe8, "FSUBP~p~RF" }, { 0xde, 0xf0, "FDIVRP~p~RF" }, { 0xde, 0xf8, "FDIVP~p~RF" }, { 0xdf, 0xe8, "FUCOMIP~p~RF" }, { 0xdf, 0xf0, "FCOMIP~p~RF" } }; static const int twob_plusr_n = sizeof(twob_plusr) / sizeof(twob_plusr[0]); /* Constant byte, /digit, immediate */ static const ONEB_DIGIT oneb_digit_i[] = { { 0x80, { "ADD~p~r1, ~i1", "OR~p~r1, ~i1", "ADC~p~r1, ~i1", "SBB~p~r1, ~i1", "AND~p~r1, ~i1", "SUB~p~r1, ~i1", "XOR~p~r1, ~i1", "CMP~p~r1, ~i1" } }, { 0x81, { "ADD~p~rO, ~iO", "OR~p~rO, ~iO", "ADC~p~rO, ~iO", "SBB~p~rO, ~iO", "AND~p~rO, ~iO", "SUB~p~rO, ~iO", "XOR~p~rO, ~iO", "CMP~p~rO, ~iO" } }, { 0x83, { "ADD~p~rO, ~i1", "OR~p~rO, ~i1", "ADC~p~rO, ~i1", "SBB~p~rO, ~i1", "AND~p~rO, ~i1", "SUB~p~rO, ~i1", "XOR~p~rO, ~i1", "CMP~p~rO, ~i1" } }, { 0xc0, { "ROL~p~r1, ~i1", "ROR~p~r1, ~i1", "RCL~p~r1, ~i1", "RCR~p~r1, ~i1", "SHL~p~r1, ~i1", "SHR~p~r1, ~i1", 0, "SAR~p~r1, ~i1" } }, { 0xc1, { "ROL~p~rO, ~i1", "ROR~p~rO, ~i1", "RCL~p~rO, ~i1", "RCR~p~rO, ~i1", "SHL~p~rO, ~i1", "SHR~p~rO, ~i1", 0, "SAR~p~rO, ~i1" } }, { 0xc6, { "MOV~p~r1, ~i1", 0, 0, 0, 0, 0, 0, 0 } }, { 0xc7, { "MOV~p~rO, ~iO", 0, 0, 0, 0, 0, 0, 0 } }, { 0xf6, { "TEST~p~r1, ~i1", 0, 0, 0, 0, 0, 0, 0 } }, { 0xf7, { "TEST~p~rO, ~iO", 0, 0, 0, 0, 0, 0, 0 } } }; static const int oneb_digit_i_n = sizeof(oneb_digit_i) / sizeof(oneb_digit_i[0]); /* Two constant bytes, /digit, immediate */ static const TWOB_DIGIT twob_digit_i[] = { { 0x0f, 0x71, { 0, 0, "PSRLW~p~RM, ~i1", 0, "PSRAW~p~RM, ~i1", 0, "PSLLW~p~RM, ~i1", 0 } }, { 0x0f, 0x72, { 0, 0, "PSRLD~p~RM, ~i1", 0, "PSRAD~p~RM, ~i1", 0, "PSLLD~p~RM, ~i1", 0 } }, { 0x0f, 0x73, { 0, 0, "PSRLQ~p~RM, ~i1", 0, 0, 0, "PSLLQ~p~RM, ~i1", 0 } }, { 0x0f, 0xba, { 0, 0, 0, 0, "BT~p~rO, ~i1", "BTS~p~rO, ~i1", "BTR~p~rO, ~i1", "BTC~p~rO, ~i1" } } }; static const int twob_digit_i_n = sizeof(twob_digit_i) / sizeof(twob_digit_i[0]); #define REP4(x) x, x, x, x #define REP8(x) REP4(x), REP4(x) #define REP16(x) REP8(x), REP8(x) #define REP32(x) REP16(x), REP16(x) #define REP64(x) REP32(x), REP32(x) #define REP128(x) REP64(x), REP64(x) #define REP256(x) REP128(x), REP128(x) #define REP2b(x) REP4(x) #define REP3b(x) REP8(x) #define REP4b(x) REP16(x) #define REP5b(x) REP32(x) #define REP6b(x) REP64(x) #define REP7b(x) REP128(x) #define REP8b(x) REP256(x) static unsigned char rep; static unsigned char lock; static unsigned char seg; static unsigned char asize; static unsigned char osize; static ADDR addr; static ADDR prefaddr; static CFLAG flg; static void (*pfn)(char); static void (*failfn)(void); #define FAIL failfn_() static void (*nodisfn)(void); #define NODIS nodisfn_() static unsigned char rmb; static int regno; static int ccno; #define OBUFSIZE 1024 static char obuf[OBUFSIZE+1]; static int ofill; static char otmp[OBUFSIZE]; static void nodisfn_(void) { (*nodisfn)(); } static void failfn_(void) { (*failfn)(); } static void dis_prefixes(unsigned int flags) { ADDR a; unsigned char b; for (a=prefaddr;a+1!=addr;a++) { b = corefetchu(a,1); switch (b) { case 0xf2: fnprintf(pfn,"REPNE "); break; case 0xf3: fnprintf(pfn,(flags&F_REPE)?"REPE ":"REP "); break; case 0xf0: fnprintf(pfn,"LOCK "); break; case 0x2e: fnprintf(pfn,"CS "); break; case 0x36: fnprintf(pfn,"SS "); break; case 0x3e: fnprintf(pfn,"DS "); break; case 0x26: fnprintf(pfn,"ES "); break; case 0x64: fnprintf(pfn,"FS "); break; case 0x65: fnprintf(pfn,"GS "); break; case 0x66: fnprintf(pfn,"O16 "); break; case 0x67: fnprintf(pfn,"A16 "); break; default: fnprintf(pfn,"?p%02x ",b); break; } } } static void dis_text(const char *s) { char c; char size; unsigned int cdepth; unsigned int ccurtrue; unsigned int cevertrue; int mark; int marks[10]; int i; if (s == 0) NODIS; for (i=0;i<10;i++) marks[i] = -1; cdepth = 0; while (1) { c = *s++; switch (c) { case '\0': eos:; if (cdepth != 0) fnprintf(pfn,"",cdepth); return; break; case '~': break; default: if ((cdepth == 0) || (ccurtrue & 1)) { (*pfn)(c); } continue; break; } c = *s++; switch (c) { case '\0': (*pfn)('~'); (*pfn)('\\'); (*pfn)('0'); goto eos; break; default: (*pfn)('~'); (*pfn)(c); break; case 'p': if ((cdepth == 0) || (ccurtrue & 1)) { (*pfn)(' '); (*pfn)(' '); while (ofill < 16) (*pfn)(' '); } break; case 'W': if ((cdepth == 0) || (ccurtrue & 1)) (*pfn)((osize==16)?'W':'D'); break; case 'E': if (((cdepth == 0) || (ccurtrue & 1)) && (osize == 32)) (*pfn)('E'); break; case 'F': if ((cdepth == 0) || (ccurtrue & 1)) NODIS; break; case '.': if (cdepth == 0) { (*pfn)('~'); (*pfn)('.'); } else { cdepth --; ccurtrue >>= 1; cevertrue >>= 1; } break; case '|': if (cdepth == 0) { (*pfn)('~'); (*pfn)('|'); } else { if (cevertrue & 1) ccurtrue &= ~1U; else ccurtrue |= 1; cevertrue |= 1; } break; case '?': c = *s++; switch (c) { case '\0': (*pfn)('~'); (*pfn)('?'); (*pfn)('\\'); (*pfn)('0'); goto eos; break; default: (*pfn)('~'); (*pfn)('?'); (*pfn)(c); break; case 'a': case 'o': case 'A': case 'O': { int cond; cdepth ++; ccurtrue <<= 1; cevertrue <<= 1; switch (c) { case 'a': cond = (asize == 16); break; case 'o': cond = (osize == 16); break; case 'A': cond = (asize == 32); break; case 'O': cond = (osize == 32); break; } if ((cdepth == 1) || (ccurtrue & 2)) { if (cond) { ccurtrue |= 1; cevertrue |= 1; } } else { cevertrue |= 1; } } break; } break; case 'm': if ((cdepth == 0) || (ccurtrue & 1)) { if ((rmb >> 6) == 3) NODIS; } /* fall through */ case 'r': if ((cdepth == 0) || (ccurtrue & 1)) { size = *s++; if (size == '\0') { (*pfn)('~'); (*pfn)('r'); (*pfn)('\\'); (*pfn)('0'); goto eos; } switch ((rmb >> 6) & 3) { int dsize; const char *basereg; const char *addreg; int addregmul; const char *pref; case 0: dsize = 0; if (0) { case 1: dsize = 1; } if (0) { case 2: dsize = asize >> 3; } switch (asize) { case 16: switch (rmb & 7) { case 0: basereg = "BX"; addreg = "SI"; break; case 1: basereg = "BX"; addreg = "DI"; break; case 2: basereg = "BP"; addreg = "SI"; break; case 3: basereg = "BP"; addreg = "DI"; break; case 4: basereg = "SI"; addreg = 0; break; case 5: basereg = "DI"; addreg = 0; break; case 6: basereg = "BP"; addreg = 0; break; case 7: basereg = "BX"; addreg = 0; break; } addregmul = 1; if ((rmb & 0307) == 0006) { basereg = 0; dsize = 2; } break; case 32: { unsigned char sib; if ((rmb & 0307) == 0005) { basereg = 0; addreg = 0; dsize = 4; } else if ((rmb & 7) == 4) { if (addr >= coresize) NODIS; sib = corefetchu(addr,1); addr ++; basereg = regs_32[sib&7]; addreg = ((sib & 070) == 040) ? 0 : regs_32[(sib>>3)&7]; addregmul = 1 << ((sib >> 6) & 3); if (((rmb & 0300) == 0) && ((sib & 7) == 5)) { basereg = 0; dsize = 4; } } else { basereg = regs_32[rmb&7]; addreg = 0; } } break; } switch (size) { case '1': fnprintf(pfn,"BYTE ["); break; case '2': fnprintf(pfn,"WORD ["); break; case '4': fnprintf(pfn,"DWORD ["); break; case '8': fnprintf(pfn,"QUAD ["); break; case 'a': fnprintf(pfn,"XFLOAT ["); break; case 'O': switch (osize) { case 16: fnprintf(pfn,"WORD ["); break; case 32: fnprintf(pfn,"DWORD ["); break; } break; case '?': fnprintf(pfn,"["); break; default: fnprintf(pfn," [",size); break; } pref = ""; if (basereg) { fnprintf(pfn,"%s%s",pref,basereg); pref = "+"; } if (addreg) { fnprintf(pfn,"%s%s",pref,addreg); if (addregmul > 1) fnprintf(pfn,"*%d",addregmul); pref = "+"; } if (dsize != 0) { unsigned long int displ; if (addr+dsize > coresize) NODIS; displ = corefetchu(addr,dsize); addr += dsize; fnprintf(pfn,"%s%0*lx",pref,dsize*2,displ); if (flg & CFF_INST_PTRLITS) { maybe_print_ptrlit(pfn,displ); maybe_print_stringptr(pfn,displ); } /*pref = "+";*/ } (*pfn)(']'); break; case 3: { const char **regnames; switch (size) { case '1': regnames = ®s_8[0]; break; case '2': regnames = ®s_16[0]; break; case '4': regnames = ®s_32[0]; break; case '8': regnames = ®s_mmx[0]; break; case 'O': regnames = (osize == 16) ? ®s_16[0] : ®s_32[0]; break; default: abort(); break; } if (regnames[rmb&7] == 0) NODIS; fnprintf(pfn,"%s",regnames[rmb&7]); } break; } } break; case 'R': if ((cdepth == 0) || (ccurtrue & 1)) { const char **regnames; size = *s++; if (size == '\0') { (*pfn)('~'); (*pfn)('R'); (*pfn)('\\'); (*pfn)('0'); goto eos; } switch (size) { case '1': regnames = ®s_8[0]; break; case '2': regnames = ®s_16[0]; break; case '4': regnames = ®s_32[0]; break; case '8': regnames = ®s_mmx[0]; break; case 'O': regnames = (osize == 16) ? ®s_16[0] : ®s_32[0]; break; case 'S': regnames = ®s_seg[0]; break; case 'C': regnames = ®s_ctl[0]; break; case 'D': regnames = ®s_dbg[0]; break; case 'T': regnames = ®s_test[0]; break; case 'F': regnames = ®s_fp[0]; break; case 'M': regnames = ®s_mmx[0]; break; default: (*pfn)('~'); (*pfn)('R'); (*pfn)(size); regnames = 0; break; } if (regnames) { if (regnames[regno] == 0) NODIS; fnprintf(pfn,"%s",regnames[regno]); } } break; case 'i': if ((cdepth == 0) || (ccurtrue & 1)) { unsigned long int ival; int isize; size = *s++; if (size == '\0') { (*pfn)('~'); (*pfn)('i'); (*pfn)('\\'); (*pfn)('0'); goto eos; } switch (size) { case '1': isize = 1; break; case '2': isize = 2; break; case '4': isize = 4; break; case 'A': isize = asize >> 3; break; case 'O': isize = osize >> 3; break; default: abort(); break; } if (addr+isize > coresize) NODIS; ival = corefetchu(addr,isize); addr += isize; fnprintf(pfn,"#%0*lx",isize*2,ival); if (flg & CFF_INST_PTRLITS) { maybe_print_ptrlit(pfn,ival); maybe_print_stringptr(pfn,ival); } } break; case 'j': if ((cdepth == 0) || (ccurtrue & 1)) { signed long int jdisp; int jsize; size = *s++; if (size == '\0') { (*pfn)('~'); (*pfn)('i'); (*pfn)('\\'); (*pfn)('0'); goto eos; } switch (size) { case '1': jsize = 1; break; case 'O': jsize = osize >> 3; break; default: abort(); break; } if (addr+jsize > coresize) NODIS; jdisp = corefetchs(addr,jsize); addr += jsize; print_symbol_or_hex(pfn,corebase+addr+jdisp); } break; case 'c': if ((cdepth == 0) || (ccurtrue & 1)) fnprintf(pfn,"%s",cc_name[ccno]); break; case '!': if ((cdepth == 0) || (ccurtrue & 1)) { c = *s++; switch (c) { case '\0': (*pfn)('~'); (*pfn)('!'); (*pfn)('\\'); (*pfn)('0'); goto eos; break; default: (*pfn)('~'); (*pfn)('!'); (*pfn)(c); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i = c - '0'; marks[i] = ofill; (*pfn)('!'); break; } } break; case '<': if ((cdepth == 0) || (ccurtrue & 1)) mark = ofill; break; case '>': if ((cdepth == 0) || (ccurtrue & 1)) { c = *s++; switch (c) { case '\0': (*pfn)('~'); (*pfn)('>'); (*pfn)('\\'); (*pfn)('0'); goto eos; break; default: (*pfn)('~'); (*pfn)('>'); (*pfn)(c); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i = c - '0'; if (marks[i] < 0) { fnprintf(pfn,"(~<~>%d sans ~!%d)",i,i); } else { int l1; int l2; int m; m = marks[i]; l1 = mark - (m+1); l2 = ofill - mark; if (l1 > 0) bcopy(&obuf[m+1],&otmp[0],l1); if (l2 > 0) bcopy(&obuf[mark],&obuf[m],l2); if (l1 > 0) bcopy(&otmp[0],&obuf[m+l2],l1); ofill --; marks[i] = -1; if (l2 != 1) { for (i=0;i<10;i++) { if (marks[i] > m) marks[i] += l2 - 1; } } } break; } } break; } } } static int dis_wrap(void (*fn)(unsigned char), unsigned char arg) { __label__ fail; ADDR addrsave; int ofillsave; static void _fail(void) { goto fail; } if (0) { fail:; addr = addrsave; ofill = ofillsave; return(0); } addrsave = addr; ofillsave = ofill; nodisfn = &_fail; (*fn)(arg); return(1); } static void dis_onebyte(unsigned char opc) { int l; int m; int h; l = -1; h = onebyte_n; while (h-l > 1) { m = (h + l) >> 1; if (onebyte[m].byte <= opc) l = m; if (onebyte[m].byte >= opc) h = m; } if (l != h) NODIS; dis_prefixes(onebyte[m].flags); dis_text(onebyte[m].text); } static void dis_oneb_digit(unsigned char opc) { int l; int m; int h; l = -1; h = oneb_digit_n; while (h-l > 1) { m = (h + l) >> 1; if (oneb_digit[m].byte <= opc) l = m; if (oneb_digit[m].byte >= opc) h = m; } if (l != h) NODIS; if (addr >= coresize) NODIS; rmb = corefetchu(addr,1); addr ++; dis_text(oneb_digit[m].texts[(rmb>>3)&7]); } static void dis_oneb_r(unsigned char opc) { int l; int m; int h; l = -1; h = oneb_r_n; while (h-l > 1) { m = (h + l) >> 1; if (oneb_r[m].byte <= opc) l = m; if (oneb_r[m].byte >= opc) h = m; } if (l != h) NODIS; if (addr >= coresize) NODIS; rmb = corefetchu(addr,1); addr ++; regno = (rmb >> 3) & 7; dis_text(oneb_r[m].text); } static void dis_oneb_i(unsigned char opc) { int l; int m; int h; l = -1; h = oneb_i_n; while (h-l > 1) { m = (h + l) >> 1; if (oneb_i[m].byte <= opc) l = m; if (oneb_i[m].byte >= opc) h = m; } if (l != h) NODIS; dis_text(oneb_i[m].text); } static void dis_twobyte(unsigned char opc1) { unsigned char opc2; int l; int m; int h; if (addr >= coresize) NODIS; opc2 = corefetchu(addr,1); addr ++; l = -1; h = twobyte_n; while (h-l > 1) { m = (h + l) >> 1; if (twobyte[m].byte1 < opc1) { l = m; continue; } if (twobyte[m].byte1 > opc1) { h = m; continue; } if (twobyte[m].byte2 <= opc2) l = m; if (twobyte[m].byte2 >= opc2) h = m; } if (l != h) NODIS; dis_text(twobyte[m].text); } static void dis_twob_digit(unsigned char opc1) { unsigned char opc2; int l; int m; int h; if (addr >= coresize) NODIS; opc2 = corefetchu(addr,1); addr ++; l = -1; h = twob_digit_n; while (h-l > 1) { m = (h + l) >> 1; if (twob_digit[m].byte1 < opc1) { l = m; continue; } if (twob_digit[m].byte1 > opc1) { h = m; continue; } if (twob_digit[m].byte2 <= opc2) l = m; if (twob_digit[m].byte2 >= opc2) h = m; } if (l != h) NODIS; if (addr >= coresize) NODIS; rmb = corefetchu(addr,1); addr ++; regno = (rmb >> 3) & 7; dis_text(twob_digit[m].texts[(rmb>>3)&7]); } static void dis_twob_r(unsigned char opc1) { unsigned char opc2; int l; int m; int h; if (addr >= coresize) NODIS; opc2 = corefetchu(addr,1); addr ++; l = -1; h = twob_r_n; while (h-l > 1) { m = (h + l) >> 1; if (twob_r[m].byte1 < opc1) { l = m; continue; } if (twob_r[m].byte1 > opc1) { h = m; continue; } if (twob_r[m].byte2 <= opc2) l = m; if (twob_r[m].byte2 >= opc2) h = m; } if (l != h) NODIS; if (addr >= coresize) NODIS; rmb = corefetchu(addr,1); addr ++; regno = (rmb >> 3) & 7; dis_text(twob_r[m].text); } static void dis_twob_plusr(unsigned char opc1) { unsigned char opc2; int l; int m; int h; if (addr >= coresize) NODIS; opc2 = corefetchu(addr,1); addr ++; regno = opc2 & 7; opc2 &= ~7; l = -1; h = twob_plusr_n; while (h-l > 1) { m = (h + l) >> 1; if (twob_plusr[m].byte1 < opc1) { l = m; continue; } if (twob_plusr[m].byte1 > opc1) { h = m; continue; } if (twob_plusr[m].byte2 <= opc2) l = m; if (twob_plusr[m].byte2 >= opc2) h = m; } if (l != h) NODIS; dis_text(twob_plusr[m].text); } static void dis_oneb_digit_i(unsigned char opc) { int l; int m; int h; l = -1; h = oneb_digit_i_n; while (h-l > 1) { m = (h + l) >> 1; if (oneb_digit_i[m].byte <= opc) l = m; if (oneb_digit_i[m].byte >= opc) h = m; } if (l != h) NODIS; if (addr >= coresize) NODIS; rmb = corefetchu(addr,1); addr ++; dis_text(oneb_digit_i[m].texts[(rmb>>3)&7]); } static void dis_twob_digit_i(unsigned char opc1) { unsigned char opc2; int l; int m; int h; if (addr >= coresize) NODIS; opc2 = corefetchu(addr,1); addr ++; l = -1; h = twob_digit_i_n; while (h-l > 1) { m = (h + l) >> 1; if (twob_digit_i[m].byte1 < opc1) { l = m; continue; } if (twob_digit_i[m].byte1 > opc1) { h = m; continue; } if (twob_digit_i[m].byte2 <= opc2) l = m; if (twob_digit_i[m].byte2 >= opc2) h = m; } if (l != h) NODIS; if (addr >= coresize) NODIS; rmb = corefetchu(addr,1); addr ++; dis_text(twob_digit_i[m].texts[(rmb>>3)&7]); } static void dis_other(unsigned char opc) { unsigned char opc2; switch (opc) { default: NODIS; break; case 0x0f: { int did; if (addr >= coresize) NODIS; opc2 = corefetchu(addr,1); addr ++; did = 1; switch (opc2 & 0xf0) { case 0x40: if (addr >= coresize) NODIS; rmb = corefetchu(addr,1); addr ++; regno = (rmb >> 3) & 7; ccno = opc2 & 15; dis_text("CMOV~c~p~RO, ~rO"); break; case 0x80: if (addr >= coresize) NODIS; ccno = opc2 & 15; dis_text("J~c~pNEAR ~jO"); break; case 0x90: if (addr >= coresize) NODIS; rmb = corefetchu(addr,1); addr ++; ccno = opc2 & 15; switch ((rmb >> 3) & 7) { case 0: dis_text("SET~c/0~p~r1"); break; case 1: dis_text("SET~c/1~p~r1"); break; case 2: dis_text("SET~c/2~p~r1"); break; case 3: dis_text("SET~c/3~p~r1"); break; case 4: dis_text("SET~c/4~p~r1"); break; case 5: dis_text("SET~c/5~p~r1"); break; case 6: dis_text("SET~c/6~p~r1"); break; case 7: dis_text("SET~c/7~p~r1"); break; } break; default: did = 0; break; } switch (opc2) { case 0xa4: rmb = corefetchu(addr,1); addr ++; regno = (rmb >> 3) & 7; dis_text("SHLD~p~rO, ~RO, ~i1"); did = 1; break; case 0xac: rmb = corefetchu(addr,1); addr ++; regno = (rmb >> 3) & 7; dis_text("SHRD~p~rO, ~RO, ~i1"); did = 1; break; } if (! did) NODIS; } break; case 0x69: rmb = corefetchu(addr,1); addr ++; regno = (rmb >> 3) & 7; dis_text("IMUL~p~rO, ~RO, ~iO"); break; case 0x6b: rmb = corefetchu(addr,1); addr ++; regno = (rmb >> 3) & 7; dis_text("IMUL~p~rO, ~RO, ~i1"); break; case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: ccno = opc & 15; dis_text("J~c~pSHORT ~j1"); break; case 0x9a: dis_text("CALL~p~!1:~!2~<~iO~>2~<~i2~>1"); break; case 0xa0: dis_text("MOV~pAL, BYTE [~iA]"); break; case 0xa1: dis_text("MOV~p~EAX, ~?OD~.WORD [~iA]"); break; case 0xa2: dis_text("MOV~pBYTE [~iA], AL"); break; case 0xa3: dis_text("MOV~p~?OD~.WORD [~iA], ~EAX"); break; case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: regno = opc & 7; dis_text("MOV~p~R1, ~i1"); break; case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: regno = opc & 7; dis_text("MOV~p~RO, ~iO"); break; case 0xc2: dis_text("RETN~p~i2"); break; case 0xc8: dis_text("ENTER~p~i2, ~i1"); break; case 0xca: dis_text("RETF~p~i2"); break; case 0xea: dis_text("JMP~p~!1:~!2~<~iO~>2~<~i2~>1"); break; } } static void obuf_char(char c) { if (ofill < OBUFSIZE) obuf[ofill++] = c; } static int do_dis_inst(ADDR aarg, void (*fn)(char), CFLAG flgarg) { __label__ fail; unsigned char opc; int n; static void _fail(void) { goto fail; } if (0) { fail:; return(-1); } flg = flgarg; pfn = obuf_char; ofill = 0; failfn = &_fail; addr = aarg - corebase; prefaddr = addr; rep = 0; lock = 0; seg = 0; asize = 32; osize = 32; while (1) { if (addr >= coresize) FAIL; opc = corefetchu(addr,1); addr ++; switch (opc) { case 0xf2: case 0xf3: rep = opc; continue; break; case 0xf0: lock = opc; continue; break; case 0x2e: case 0x36: case 0x3e: case 0x26: case 0x64: case 0x65: seg = opc; continue; break; case 0x66: osize = 16; continue; case 0x67: asize = 16; continue; } break; } /* This code knows that the only instructions that pass other than 0 to dis_prefixes are handled by dis_onebyte. */ if (dis_wrap(dis_onebyte,opc)) goto done; dis_prefixes(0); if ( dis_wrap(dis_oneb_digit,opc) || dis_wrap(dis_oneb_r,opc) || dis_wrap(dis_oneb_i,opc) || dis_wrap(dis_twobyte,opc) || dis_wrap(dis_twob_digit,opc) || dis_wrap(dis_twob_r,opc) || dis_wrap(dis_twob_plusr,opc) || dis_wrap(dis_oneb_digit_i,opc) || dis_wrap(dis_twob_digit_i,opc) || dis_wrap(dis_other,opc) ) goto done; fnprintf(pfn,"[?%02x]",opc); done:; if (flg & CFF_INST_PARALLEL) { fnprintf(pfn," {parallel %#lx}",(unsigned long int)addr); n = 1; } else { n = addr - prefaddr; if (n > 0) for (addr--;addr!=prefaddr;addr--) flags[addr] = CF_PREV; } obuf[ofill] = '\0'; fnprintf(fn,"%s",&obuf[0]); return(n); } static void _386_init(void) { } static int _386_dis(ADDR addr, void (*fn)(char)) { int rv; if (ISINST(flags[addr-corebase])) { rv = do_dis_inst(addr,fn,flags[addr-corebase]); } else { fnprintf(fn,"",(unsigned long int)flags[addr-corebase]); rv = 1; } return(rv); } static unsigned long int _386_fetch(const void *base, int size) #define bp(n) ((unsigned long int)(((const unsigned char *)base)[(n)])) { switch (size) { case 1: return(bp(0)); break; case 2: return((bp(1)<<8)|bp(0)); break; case 4: return((bp(3)<<24)|(bp(2)<<16)|(bp(1)<<8)|bp(0)); break; } abort(); } #undef bp static const char *_386_names[] = { "80386", "386", 0 }; MACHINE machine_386 = { &_386_names[0], 4, &_386_init, 0, &_386_dis, &_386_fetch, 0 };