/* * mdbdis86.c for mdb.c - 8086-386 and 8087 disassembler * From Bruce Evans db */ #include "mdb.h" #include #include #include #include "proto.h" struct address_s { off_t off; off_t base; }; PRIVATE int bits32; PRIVATE struct address_s uptr; FORWARD _PROTOTYPE( u8_t get8, (void) ); FORWARD _PROTOTYPE( u16_t get16, (void) ); FORWARD _PROTOTYPE( u32_t get32, (void) ); FORWARD _PROTOTYPE( u8_t peek_byte, (off_t addr) ); FORWARD _PROTOTYPE( u16_t peek_word, (off_t addr) ); FORWARD _PROTOTYPE( int puti, (void) ); FORWARD _PROTOTYPE( int outsegaddr, (struct address_s *addr) ); FORWARD _PROTOTYPE( int outssegaddr, (struct address_s *addr) ); FORWARD _PROTOTYPE( int show1instruction , (void)); /************************* UNASM ******************************/ #define LINDIRECT '[' #define RINDIRECT ']' #define BASE_MASK 0x07 #define INDEX_MASK 0x38 #define INDEX_SHIFT 3 #define MOD_MASK 0xC0 /* mod reg r/m is mmrrrRRR */ #define REG_MOD 0xC0 #define MEM0_MOD 0x00 #define MEM1_MOD 0x40 #define MEM2_MOD 0x80 #define REG_MASK 0x38 #define REG_SHIFT 3 #define RM_MASK 0x07 #define RM_SHIFT 0 #define SS_MASK 0xC0 #define SS_SHIFT 6 #define SIGNBIT 0x02 /* opcode bits xxxxxxsw for immediates */ #define WORDBIT 0x01 #define TOREGBIT 0x02 /* opcode bit for non-immediates */ #define MAX_SIGNED_CHAR 0x7F /* will assume 2's complement */ #define MAX_UNSIGNED_CHAR 0xFF typedef unsigned opcode_pt; /* promote to unsigned and not int */ typedef int reg_pt; typedef int su16_t; typedef int su8_pt; FORWARD _PROTOTYPE( su8_pt get8s , (void)); FORWARD _PROTOTYPE( void getmodregrm , (void)); FORWARD _PROTOTYPE( void i_00_to_3f , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_40_to_5f , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_60_to_6f , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_70_to_7f , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_80 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_88 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_90 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_98 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_a0 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_a8 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_b0 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_b8 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_c0 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_c8 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_d0 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_d8 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_e0 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_e8 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_f0 , (opcode_pt opc )); FORWARD _PROTOTYPE( void i_f8 , (opcode_pt opc )); FORWARD _PROTOTYPE( void outad , (opcode_pt opc )); FORWARD _PROTOTYPE( void outad1 , (opcode_pt opc )); FORWARD _PROTOTYPE( void outalorx , (opcode_pt opc )); FORWARD _PROTOTYPE( void outax , (void)); FORWARD _PROTOTYPE( void outbptr , (void)); FORWARD _PROTOTYPE( void outbwptr , (opcode_pt opc )); FORWARD _PROTOTYPE( void outea , (opcode_pt wordflags )); FORWARD _PROTOTYPE( void outf1 , (void)); FORWARD _PROTOTYPE( void out32offset , (void)); FORWARD _PROTOTYPE( void outfishy , (void)); FORWARD _PROTOTYPE( void outgetaddr , (void)); FORWARD _PROTOTYPE( void outimmed , (opcode_pt signwordflag )); FORWARD _PROTOTYPE( void outpc , (off_t pc )); FORWARD _PROTOTYPE( void outsegpc , (void)); FORWARD _PROTOTYPE( void oututstr , (char *s )); FORWARD _PROTOTYPE( void outword , (void)); FORWARD _PROTOTYPE( void outwptr , (void)); FORWARD _PROTOTYPE( void outwsize , (void)); FORWARD _PROTOTYPE( void pagef , (void)); FORWARD _PROTOTYPE( void shift , (opcode_pt opc )); FORWARD _PROTOTYPE( void checkmemory , (void)); FORWARD _PROTOTYPE( void CL , (void)); FORWARD _PROTOTYPE( void Eb , (void)); FORWARD _PROTOTYPE( void Ev , (void)); FORWARD _PROTOTYPE( void EvGv , (void)); FORWARD _PROTOTYPE( void EvIb , (void)); FORWARD _PROTOTYPE( void Ew , (void)); FORWARD _PROTOTYPE( void EwRw , (void)); FORWARD _PROTOTYPE( void Gv , (void)); FORWARD _PROTOTYPE( void Gv1 , (void)); FORWARD _PROTOTYPE( void GvEv , (void)); FORWARD _PROTOTYPE( void GvEw , (void)); FORWARD _PROTOTYPE( void GvM , (void)); FORWARD _PROTOTYPE( void GvMa , (void)); FORWARD _PROTOTYPE( void GvMp , (void)); FORWARD _PROTOTYPE( void Ib , (void)); FORWARD _PROTOTYPE( void Iw , (void)); FORWARD _PROTOTYPE( void Iv , (void)); FORWARD _PROTOTYPE( void Jb , (void)); FORWARD _PROTOTYPE( void Jv , (void)); FORWARD _PROTOTYPE( void Ms , (void)); _PROTOTYPE( typedef void (*pfv_t),(opcode_pt opc )); PRIVATE pfv_t optable[] = { i_00_to_3f, i_00_to_3f, i_00_to_3f, i_00_to_3f, i_00_to_3f, i_00_to_3f, i_00_to_3f, i_00_to_3f, i_40_to_5f, i_40_to_5f, i_40_to_5f, i_40_to_5f, i_60_to_6f, i_60_to_6f, i_70_to_7f, i_70_to_7f, i_80, i_88, i_90, i_98, i_a0, i_a8, i_b0, i_b8, i_c0, i_c8, i_d0, i_d8, i_e0, i_e8, i_f0, i_f8, }; PRIVATE char fishy[] = "???"; PRIVATE char movtab[] = "mov\t"; PRIVATE char *genreg[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", }; PRIVATE char *segreg[] = { "es", "cs", "ss", "ds", "fs", "gs", "?s", "?s", }; PRIVATE char *indreg[] = { "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx", }; PRIVATE char *str_00_to_3f[] = { /* index by (opcode >> 3) & 7 */ "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp", }; PRIVATE char *sstr_00_to_3f[] = { /* index ((opc>>2) & 0x0E) + (opc & 7) - 6 */ "push\tes", "pop\tes", "push\tcs", "pop\tcs", "push\tss", "pop\tss", "push\tds", "pop\tds", "es:", "daa", "cs:", "das", "ss:", "aaa", "ds:", "aas", }; PRIVATE char *sstr_0f[] = { "push\tfs", "pop\tfs", fishy, "bt\t", "shld\t", "shld\t", fishy, fishy, "push\tgs", "pop\tgs", fishy, "bts\t", "shrd\t", "shrd\t", fishy, "imul\t", fishy, fishy, "lss\t", "btr\t", "lfs\t", "lgs\t", "movzx\t", "movzx\t", fishy, fishy, "", "btc\t", "bsf\t", "bsr\t", "movsx\t", "movsx\t", }; PRIVATE char *ssstr_0f[] = { "sldt\t", "str\t", "lldt\t", "ltr\t", "verr\t", "verw\t", fishy, fishy, "sgdt\t", "sidt\t", "lgdt\t", "lidt\t", "smsw\t", fishy, "lmsw\t", fishy, fishy, fishy, fishy, fishy, "bt\t", "bts\t", "btr\t", "btc\t", }; PRIVATE char *str_40_to_5f[] = { /* index by (opcode >> 3) & 3 */ "inc\t", "dec\t", "push\t", "pop\t", }; PRIVATE char *str_60_to_6f[] = { "pusha", "popa", "bound\t", "arpl\t", "fs:", "gs:", "os:", "as:", "push\t", "imul\t", "push\t", "imul\t", "insb", "ins", "outsb", "outs", }; PRIVATE char *str_flags[] = { /* opcodes 0x70 to 0x7F, and 0x0F80 to 0x0F9F */ "o", "no", "b", "nb", "z", "nz", "be", "a", "s", "ns", "pe", "po", "l", "ge", "le", "g", }; PRIVATE char *str_98[] = { "cbw", "cwd", "call\t", "wait", "pushf", "popf", "sahf", "lahf", "cwde", "cdq", "call\t", "wait", "pushfd", "popfd", "sahf", "lahf", }; PRIVATE char *str_a0[] = { movtab, movtab, movtab, movtab, "movsb", "movs", "cmpsb", "cmps", }; PRIVATE char *str_a8[] = { "test\t", "test\t", "stosb", "stos", "lodsb", "lods", "scasb", "scas", }; PRIVATE char *str_c0[] = { "", "", "ret\t", "ret", "les\t", "lds\t", movtab, movtab, }; PRIVATE char *str_c8[] = { "enter\t", "leave", "retf\t", "retf", "int\t3", "int\t", "into", "iret", }; PRIVATE char *str_d0[] = { "aam", "aad", "db\td6", "xlat", }; PRIVATE char *sstr_d0[] = { "rol", "ror", "rcl", "rcr", "shl", "shr", fishy, "sar", }; PRIVATE char *str_d8[] = { "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", NULL, "fist", "fistp", NULL, "fld", NULL, "fstp", "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", "fld", NULL, "fst", "fstp", "frstor", NULL, "fsave", "fstsw", "fiadd", "fimul", "ficom", "ficomp", "fisub", "fisubr", "fidiv", "fidivr", "fild", NULL, "fist", "fistp", "fbld", "fild", "fbstp", "fistp", }; PRIVATE char *str1_d8[] = { "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", "fld", "fxch", "\0\0", NULL, "\0\10", "\0\20", "\0\30", "\0\40", NULL, NULL, NULL, NULL, NULL, "\0\50", NULL, NULL, NULL, NULL, NULL, NULL, "\0\60", NULL, NULL, NULL, "fadd", "fmul", NULL, NULL, "fsubr", "fsub", "fdivr", "fdiv", "ffree", NULL, "fst", "fstp", "fucom", "fucomp", NULL, NULL, "faddp", "fmulp", NULL, "\0\70", "fsubrp", "fsubp", "fdivrp", "fdivp", NULL, NULL, NULL, NULL, "\0\100", NULL, NULL, NULL, }; PRIVATE unsigned char size_d8[] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 14-28, 2, 14-28, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 0, 10, 0, 10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 8, 8, 94-108, 0, 94-108, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 10, 8, 10, 8, }; PRIVATE char *sstr_d8[] = { "fnop", NULL, NULL, NULL, /* D9D0 */ NULL, NULL, NULL, NULL, "fchs", "fabs", NULL, NULL, /* D9E0 */ "ftst", "fxam", NULL, NULL, "fld1", "fldl2t", "fldl2e", "fldpi", /* D9E8 */ "fldlg2", "fldln2", "fldz", NULL, "f2xm1", "fyl2x", "fptan", "fpatan", /* D9F0 */ "fxtract", "fprem1", "fdecstp", "fincstp", "fprem", "fyl2xp1", "fsqrt", "fsincos", /* D9F8 */ "frndint", "fscale", "fsin", "fcos", NULL, "fucompp", NULL, NULL, /* DAE8 */ NULL, NULL, NULL, NULL, "feni", "fdisi", "fclex", "finit", /* DBE0 */ "fsetpm", NULL, NULL, NULL, NULL, "fcompp", NULL, NULL, /* DED8 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* DFE0 */ "fstsw\tax", NULL, NULL, NULL, }; PRIVATE char *str_e0[] = { "loopnz\t", "loopz\t", "loop\t", "jcxz\t", "in\t", "in\t", "out\t", "out\t", }; PRIVATE char *str_e8[] = { "call\t", "jmp\t", "jmp\t", "jmp\t", "in\t", "in\t", "out\t", "out\t", }; PRIVATE char *str_f0[] = { "lock\t", "db\tf1", "repnz\t", "repz\t", "hlt", "cmc", /* other 2 from sstr_f0 */ }; PRIVATE char *sstr_f0[] = { "test\t", fishy, "not\t", "neg\t", "mul\t", "imul\t", "div\t", "idiv\t", }; PRIVATE char *str_f8[] = { "clc", "stc", "cli", "sti", "cld", "std", /* other 2 from sstr_f8 */ }; PRIVATE char *sstr_f8[] = { "inc\t", "dec\t", "call\t", "call\tfar ", "jmp\t", "jmp\tfar ", "push\t", "???\t", }; PRIVATE int data_seg; /* data segment (munged name for asld) */ PRIVATE unsigned hasize; /* half address size in bits */ PRIVATE unsigned hdefsize; PRIVATE unsigned hosize; /* half operand size in bits */ /* for easy index into reg tables */ PRIVATE opcode_pt mod; PRIVATE off_t offtable[2]; PRIVATE off_t *offptr; PRIVATE off_t *off1ptr; PRIVATE opcode_pt reg; PRIVATE opcode_pt rm; PRIVATE su8_pt get8s() { u8_t got; if ((got = get8()) > MAX_SIGNED_CHAR) got -= (MAX_UNSIGNED_CHAR + 1); return got; } PRIVATE void getmodregrm() { opcode_pt modregrm; modregrm = get8(); mod = modregrm & MOD_MASK; reg = (modregrm & REG_MASK) >> REG_SHIFT; rm = (modregrm & RM_MASK) >> RM_SHIFT; } PRIVATE void i_00_to_3f(opc) opcode_pt opc; { opcode_pt sub; if (opc == 15) pagef(); else if ((sub = opc & 7) >= 6) { outustr((sstr_00_to_3f - 6)[((opc >> 2) & 0x0E) + sub]); if (!(opc & 1)) data_seg = opc; } else { oututstr(str_00_to_3f[(opc >> 3) & 7]); if (sub == 4) { outustr(genreg[0]); outcomma(); Ib(); } else if (sub == 5) { outax(); outcomma(); Iv(); } else outad(sub); } } PRIVATE void i_40_to_5f(opc) opcode_pt opc; { outustr(str_40_to_5f[(opc >> 3) & 3]); outustr(genreg[hosize + (opc & 7)]); } PRIVATE void i_60_to_6f(opc) opcode_pt opc; { /* most for 386, some for 286 */ outustr((str_60_to_6f - 0x60)[opc]); switch (opc) { case 0x60: case 0x61: if (hosize == 16) outwsize(); break; case 0x62: GvMa(); break; case 0x63: EwRw(); break; case 0x64: case 0x65: data_seg = opc; break; case 0x66: hosize = (16 + 8) - hdefsize; break; case 0x67: hasize = (16 + 8) - hdefsize; break; case 0x68: outword(); Iv(); break; case 0x6A: outword(); outimmed(SIGNBIT | WORDBIT); break; case 0x69: GvEv(); outcomma(); Iv(); break; case 0x6B: GvEv(); outcomma(); outimmed(SIGNBIT | WORDBIT); break; case 0x6D: case 0x6F: outwsize(); break; } } PRIVATE void i_70_to_7f(opc) opcode_pt opc; { outustr("j"); oututstr((str_flags - 0x70)[opc]); Jb(); } PRIVATE void i_80(opc) opcode_pt opc; { if (opc >= 4) { outustr(opc >= 6 ? "xchg\t" : "test\t"); outad(opc); } else { getmodregrm(); oututstr(str_00_to_3f[reg]); outbwptr(opc); outea(opc); outcomma(); outimmed(opc); #ifdef SIGNED_LOGICALS if (opc & SIGNBIT && (reg == 1 || reg == 4 || reg == 6)) /* and, or and xor with signe extension are not documented in some * 8086 and 80286 manuals, but make sense and work */ outfishy(); #endif } } PRIVATE void i_88(opc) opcode_pt opc; { if (opc < 4) { outustr(movtab); outad(opc); } else if (opc == 5) { oututstr("lea"); GvM(); } else if (opc == 7) { oututstr("pop"); getmodregrm(); outwptr(); Ev(); if (reg != 0) outfishy(); } else { getmodregrm(); outustr(movtab); if (!(opc & TOREGBIT)) { Ev(); outcomma(); } outustr(segreg[reg]); if (opc & TOREGBIT) { outcomma(); Ev(); } } } PRIVATE void i_90(opc) opcode_pt opc; { if (opc == 0) outustr("nop"); else { outustr("xchg\t"); outax(); outcomma(); outustr(genreg[hosize + opc]); } } PRIVATE void i_98(opc) opcode_pt opc; { outustr((str_98 - 8)[opc + hosize]); if (opc == 2) outsegpc(); } PRIVATE void i_a0(opc) opcode_pt opc; { outustr(str_a0[opc]); if (opc < 4) { mod = MEM0_MOD; /* fake */ reg = 0; /* fake ax */ if (hasize == 16) rm = 5; /* fake [d16] */ else rm = 6; /* fake [d32] */ outad1(opc ^ TOREGBIT); } else if (opc & 1) outwsize(); } PRIVATE void i_a8(opc) opcode_pt opc; { outustr(str_a8[opc]); if (opc < 2) { outalorx(opc); outcomma(); outimmed(opc); } else if (opc & 1) outwsize(); } PRIVATE void i_b0(opc) opcode_pt opc; { outustr(movtab); outustr(genreg[opc]); outcomma(); Ib(); } PRIVATE void i_b8(opc) opcode_pt opc; { outustr(movtab); outustr(genreg[hosize + opc]); outcomma(); Iv(); } PRIVATE void i_c0(opc) opcode_pt opc; { outustr(str_c0[opc]); if (opc >= 6) { getmodregrm(); outbwptr(opc); outea(opc); outcomma(); outimmed(opc & WORDBIT); if (reg != 0) /* not completely decoded (like DEBUG) */ outfishy(); } else if (opc >= 4) GvMp(); else if (opc == 2) Iv(); else if (opc < 2) shift(opc); } PRIVATE void i_c8(opc) opcode_pt opc; { outustr(str_c8[opc]); if (opc == 0) { Iw(); outcomma(); Ib(); } if (opc == 2) Iv(); else if (opc == 5) Ib(); else if (opc == 7 && hosize == 16) outwsize(); } PRIVATE void i_d0(opc) opcode_pt opc; { opcode_pt aabyte; if (opc < 4) shift(opc | 0xD0); else { outustr((str_d0 - 4)[opc]); if (opc < 6 && (aabyte = get8()) != 0x0A) { outtab(); outh8(aabyte); outfishy(); } } } PRIVATE void i_d8(opc) opcode_pt opc; { opcode_pt esc; char *str; getmodregrm(); esc = (opc << 3) | reg; if ((str = (mod == REG_MOD ? str1_d8 : str_d8)[esc]) == NULL) { escape: oututstr("esc"); outh8(esc); outcomma(); outea(0); return; } if (*str == 0) { str = sstr_d8[str[1] + rm]; if (str == NULL) goto escape; outustr(str); return; } outustr(str); outtab(); if (mod == REG_MOD) { if (opc == 0 && reg != 2 && reg != 3) outustr("st,"); outf1(); if (opc == 4 || opc == 6) outustr(",st"); return; } switch(size_d8[esc]) { case 4: outustr("d"); case 2: outwptr(); break; case 8: outustr("q"); outwptr(); break; case 10: outustr("t"); outbptr(); break; } outea(opc); } PRIVATE void i_e0(opc) opcode_pt opc; { outustr(str_e0[opc]); if (opc < 4) Jb(); else if (opc < 6) { outalorx(opc); outcomma(); Ib(); } else { Ib(); outcomma(); outalorx(opc); } } PRIVATE void i_e8(opc) opcode_pt opc; { outustr(str_e8[opc]); if (opc < 2) Jv(); else if (opc == 2) outsegpc(); else if (opc == 3) Jb(); else { if (opc & TOREGBIT) { outustr(genreg[10]); outcomma(); outalorx(opc); } else { outalorx(opc); outcomma(); outustr(genreg[10]); } } } PRIVATE void i_f0(opc) opcode_pt opc; { if (opc < 6) outustr(str_f0[opc]); else { getmodregrm(); outustr(sstr_f0[reg]); outbwptr(opc); outea(opc); if (reg == 0) { outcomma(); outimmed(opc & WORDBIT); } } } PRIVATE void i_f8(opc) opcode_pt opc; { if (opc < 6) outustr(str_f8[opc]); else { getmodregrm(); if (opc == 6 && reg >= 2) outustr("fishy\t"); else outustr(sstr_f8[reg]); outbwptr(opc); outea(opc); } } PRIVATE void outad(opc) opcode_pt opc; { getmodregrm(); outad1(opc); } PRIVATE void outad1(opc) opcode_pt opc; { if (!(opc & TOREGBIT)) { outea(opc); outcomma(); } if (opc & WORDBIT) Gv1(); else outustr(genreg[reg]); if (opc & TOREGBIT) { outcomma(); outea(opc); } } PRIVATE void outalorx(opc) opcode_pt opc; { if (opc & WORDBIT) outax(); else outustr(genreg[0]); } PRIVATE void outax() { outustr(genreg[hosize]); } PRIVATE void outbptr() { outustr("byte ptr "); } PRIVATE void outbwptr(opc) opcode_pt opc; { if (mod != REG_MOD) { if (opc & WORDBIT) outwptr(); else outbptr(); } } PRIVATE void outea(wordflags) opcode_pt wordflags; { reg_pt base; reg_pt index; opcode_pt ss; opcode_pt ssindexbase; if (mod == REG_MOD) outustr(genreg[hosize * (wordflags & WORDBIT) + rm]); else { outbyte(LINDIRECT); if (hasize == 16) { if (rm == 4) { base = (ssindexbase = get8()) & BASE_MASK; if (mod == MEM0_MOD && base == 5) outgetaddr(); else outustr((genreg + 16)[base]); ss = (ssindexbase & SS_MASK) >> SS_SHIFT; if ((index = (ssindexbase & INDEX_MASK) >> INDEX_SHIFT) != 4) { outbyte('+'); outustr((genreg + 16)[index]); outstr("\0\0\0*2\0*4\0*8\0" + (3 * ss)); } } else if (mod == MEM0_MOD && rm == 5) outgetaddr(); else outustr((genreg + 16)[rm]); } else if (mod == MEM0_MOD && rm == 6) outgetaddr(); else outustr(indreg[rm]); if (mod == MEM1_MOD) /* fake sign extension to get +- */ outimmed(SIGNBIT | WORDBIT); else if (mod == MEM2_MOD) { outbyte('+'); #if (_WORD_SIZE == 4) out32offset(); #else outgetaddr(); #endif } outbyte(RINDIRECT); if (hasize == 16 && rm == 4 && index == 4 && ss != 0) outfishy(); } } PRIVATE void outf1() { outustr("st("); outbyte((int) (rm + '0')); outbyte(')'); } #if (_WORD_SIZE == 4) PRIVATE void out32offset() { off_t off; if (hasize == 16) off = get32(); else outfishy(); outh32(off); } #endif PRIVATE void outfishy() { outustr("\t???"); } PRIVATE void outgetaddr() { off_t off; if (hasize == 16) off = get32(); else off = get16(); if ( finds_data(off,data_seg) ) *offptr++ = off; else if (hasize == 16) outh32(off); else outh16((u16_t) off); } PRIVATE void outimmed(signwordflag) opcode_pt signwordflag; { su8_pt byte; if (signwordflag & WORDBIT) { if (signwordflag & SIGNBIT) { if ((byte = get8s()) < 0) { outbyte('-'); byte = -byte; } else outbyte('+'); outh8((u8_t) byte); } else Iv(); } else Ib(); } PRIVATE void outpc(pc) off_t pc; { if (hosize == 8) pc = (u16_t) pc; if ( finds_pc(pc) ) *offptr++ = pc; else if (hosize == 16) outh32(pc); else outh16((u16_t) pc); } PRIVATE void outsegpc() { off_t oldbase; off_t pc; if (hosize == 16) pc = get32(); else pc = get16(); oldbase = uptr.base; outh16((u16_t) (uptr.base = get16())); /* fake seg for lookup of pc */ /* TODO - convert to offset in protected mode */ outbyte(':'); outpc(pc); uptr.base = oldbase; } PRIVATE void oututstr(s) char *s; { outustr(s); outtab(); } PRIVATE void outword() { outustr("dword " + ((16 - hosize) >> 3)); } PRIVATE void outwptr() { outword(); outustr("ptr "); } PRIVATE void outwsize() { if (hosize == 16) outustr("d"); else outustr("w"); } PRIVATE void pagef() { opcode_pt opc; int regbad; if ((opc = get8()) <= 1 || opc == 0xBA) { if (opc == 0xBA) opc = 16; else opc *= 8; getmodregrm(); outustr(ssstr_0f[opc += reg]); if (opc < 6 || opc == 12 || opc == 14) Ew(); else if (opc >= 8 && opc < 13) Ms(); else if (opc >= 20) { outbwptr(WORDBIT); EvIb(); } } else if (opc < 4) { oututstr("lar\0lsl" + 4 * (opc - 2)); GvEw(); } else if (opc == 5) { outustr("loadall"); outfishy(); } else if (opc == 6) outustr("clts"); else if (opc < 0x20) outstr(fishy); else if (opc < 0x27 && opc != 0x25) { outustr(movtab); getmodregrm(); hosize = 16; if (!(opc & TOREGBIT)) { Ev(); /* Rd() since hosize is 16 */ outcomma(); } regbad = FALSE; if (opc & 1) { outustr("dr"); if (reg == 4 || reg == 5) regbad = TRUE; } else if (opc < 0x24) { outustr("cr"); if (reg >= 4 || reg == 1) regbad = TRUE; } else { outustr("tr"); if (reg < 6) regbad = TRUE; } outbyte((int) (reg + '0')); if (opc & TOREGBIT) { outcomma(); Ev(); } if (regbad || mod != REG_MOD) outfishy(); } else if (opc < 0x80) outstr(fishy); else if (opc < 0x90) { outustr("j"); oututstr((str_flags - 0x80)[opc]); Jv(); } else if (opc < 0xA0) { outustr("set"); oututstr((str_flags - 0x90)[opc]); getmodregrm(); outbwptr(0); Eb(); } else if (opc < 0xC0) { outustr((sstr_0f - 0xA0)[opc]); switch (opc) { case 0xA3: case 0xAB: case 0xB3: case 0xBB: EvGv(); break; case 0xA4: case 0xAC: EvGv(); outcomma(); Ib(); break; case 0xA5: case 0xAD: EvGv(); outcomma(); CL(); break; case 0xAF: case 0xBC: case 0xBD: GvEv(); break; case 0xB2: case 0xB4: case 0xB5: GvMp(); break; case 0xB6: case 0xBE: Gv(); outcomma(); outbwptr(opc); Eb(); break; case 0xB7: case 0xBF: Gv(); outcomma(); hosize = 8; /* done in Ew(), but too late */ outbwptr(opc); Ew(); break; } } else outstr(fishy); } PRIVATE int puti() { static int hadprefix; opcode_pt opcode; more: offptr = offtable; opcode = get8(); if (!hadprefix) { data_seg = DSEG; hdefsize = 8; if (bits32) hdefsize = 16; hosize = hasize = hdefsize; } (*optable[opcode >> 3])(opcode < 0x80 ? opcode : opcode & 7); if (offptr > offtable) { if (stringtab() >= 31) { outspace(); outspace(); } else while (stringtab() < 32) outtab(); outbyte(';'); for (off1ptr = offtable; off1ptr < offptr; ++off1ptr) { outspace(); if (*off1ptr < 0x10000) outh16((u16_t) *off1ptr); else outh32(*off1ptr); } offptr = offtable; } if ((opcode & 0xE7) == 0x26 || opcode >= 0x64 && opcode < 0x68 || opcode == 0xF0 || opcode == 0xF2 || opcode == 0xF3) /* not finished instruction for 0x26, 0x2E, 0x36, 0x3E seg overrides * and 0x64, 0x65 386 seg overrides * and 0x66, 0x67 386 size prefixes * and 0xF0 lock, 0xF2 repne, 0xF3 rep */ { hadprefix = TRUE; goto more; /* TODO - print prefixes better */ return FALSE; } hadprefix = FALSE; return TRUE; } PRIVATE void shift(opc) opcode_pt opc; { getmodregrm(); oututstr(sstr_d0[reg]); outbwptr(opc); outea(opc); outcomma(); if (opc < 0xD0) Ib(); else if (opc & 2) CL(); else outbyte('1'); } PRIVATE void checkmemory() { if (mod == REG_MOD) outfishy(); } PRIVATE void CL() { outustr(genreg[1]); } PRIVATE void Eb() { outea(0); } PRIVATE void Ev() { outea(WORDBIT); } PRIVATE void EvGv() { getmodregrm(); Ev(); outcomma(); Gv1(); } PRIVATE void EvIb() { Ev(); outcomma(); Ib(); } PRIVATE void Ew() { hosize = 8; Ev(); } PRIVATE void EwRw() { hosize = 8; EvGv(); } PRIVATE void Gv() { getmodregrm(); Gv1(); } PRIVATE void Gv1() { outustr(genreg[hosize + reg]); } PRIVATE void GvEv() { Gv(); outcomma(); Ev(); } PRIVATE void GvEw() { Gv(); outcomma(); Ew(); } PRIVATE void GvM() { GvEv(); checkmemory(); } PRIVATE void GvMa() { GvM(); } PRIVATE void GvMp() { GvM(); } PRIVATE void Ib() { outh8(get8()); } PRIVATE void Iw() { outh16(get16()); } PRIVATE void Iv() { if (hosize == 16) outh32(get32()); else Iw(); } PRIVATE void Jb() { off_t pcjump; pcjump = get8s(); outpc(pcjump + uptr.off); } PRIVATE void Jv() { off_t pcjump; if (hosize == 16) pcjump = get32(); else pcjump = (su16_t) get16(); outpc(pcjump + uptr.off); } PRIVATE void Ms() { Ev(); checkmemory(); } /********************* DASM ******************************/ PUBLIC long dasm( addr, count, symflg ) long addr; int count; int symflg; { #if (_WORD_SIZE == 4) bits32 = TRUE; /* Set mode */ #else bits32 = FALSE; #endif uptr.off = addr; uptr.base = 0; /* not known */ while ( count-- != 0 && show1instruction() ) ; } PRIVATE int show1instruction() { register int column; int idone; static char line[81]; int maxcol; struct address_s newuptr; struct address_s olduptr; outbyte('\r'); do { if ( text_symbol(uptr.off) ) { outbyte(':'); outbyte('\n'); } olduptr = uptr; openstring(line); idone = puti(); line[stringpos()] = 0; closestring(); newuptr = uptr; uptr = olduptr; column = outssegaddr(&uptr); while (uptr.off != newuptr.off) { outh8(get8()); column += 2; } maxcol = bits32 ? 24 : 16; while (column < maxcol) { outtab(); column += 8; } outtab(); outstr(line); outbyte('\n'); } while (!idone); /* eat all prefixes */ return TRUE; } PRIVATE u8_t get8() { /* get 8 bits current instruction pointer and advance pointer */ u8_t temp; temp = peek_byte(uptr.off + uptr.base); ++uptr.off; return temp; } PRIVATE u16_t get16() { /* get 16 bits from current instruction pointer and advance pointer */ u16_t temp; temp = peek_word(uptr.off + uptr.base); uptr.off += 2; return temp; } PRIVATE u32_t get32() { /* get 32 bits from current instruction pointer and advance pointer */ u32_t temp; temp = peek_dword(uptr.off + uptr.base); uptr.off += 4; return temp; } PRIVATE int outsegaddr(addr) struct address_s *addr; { /* print segmented address */ int bytes_printed; bytes_printed = 2; bytes_printed = outsegreg(addr->base); if (bytes_printed > 4) outbyte('+'); else outbyte(':'); ++bytes_printed; if (addr->off >= 0x10000) { outh32(addr->off); return bytes_printed + 8; } outh16((u16_t) addr->off); return bytes_printed + 4; } PRIVATE int outssegaddr(addr) struct address_s *addr; { /* print 32 bit segmented address and 2 spaces */ int bytes_printed; bytes_printed = outsegaddr(addr); outspace(); outspace(); return bytes_printed + 2; } PRIVATE u8_t peek_byte(addr) off_t addr; { return (u8_t) peek_dword(addr) & 0xFF; /* 8 bits only */ } PRIVATE u16_t peek_word(addr) off_t addr; { return (u16_t) peek_dword(addr); }