DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/debug/debug_disasm.cpp
00001 
00002 /*
00003         Ripped out some stuff from the mame releae to only make it for 386's 
00004         Changed some variables to use the standard DOSBox data types 
00005         Added my callback opcode 
00006         
00007 */
00008 
00009 /*
00010  * 2asm: Convert binary files to 80*86 assembler. Version 1.00
00011  * Adapted by Andrea Mazzoleni for use with MAME
00012  * HJB 990321:
00013  * Changed output of hex values from 0xxxxh to $xxxx format
00014  * Removed "ptr" from "byte ptr", "word ptr" and "dword ptr"
00015 */
00016 
00017 /* 2asm comments
00018 
00019 License:
00020 
00021    This program is free software; you can redistribute it and/or modify
00022    it under the terms of the GNU General Public License as published by
00023    the Free Software Foundation.
00024 
00025    This program is distributed in the hope that it will be useful,
00026    but WITHOUT ANY WARRANTY; without even the implied warranty of
00027    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00028    GNU General Public License for more details.
00029 
00030 Comments:
00031 
00032    The code was originally snaffled from the GNU C++ debugger, as ported
00033    to DOS by DJ Delorie and Kent Williams (williams@herky.cs.uiowa.edu).
00034    Extensively modified by Robin Hilliard in Jan and May 1992.
00035 
00036    This source compiles under Turbo C v2.01.  The disassembler is entirely
00037    table driven so it's fairly easy to change to suit your own tastes.
00038 
00039    The instruction table has been modified to correspond with that in
00040    `Programmer's Technical Reference: The Processor and Coprocessor',
00041    Robert L. Hummel, Ziff-Davis Press, 1992.  Missing (read "undocumented")
00042    instructions were added and many mistakes and omissions corrected.
00043 
00044 
00045 Health warning:
00046 
00047    When writing and degbugging this code, I didn't have (and still don't have)
00048    a 32-bit disassembler to compare this guy's output with.  It's therefore
00049    quite likely that bugs will appear when disassembling instructions which use
00050    the 386 and 486's native 32 bit mode.  It seems to work fine in 16 bit mode.
00051 
00052 Any comments/updates/bug reports to:
00053 
00054    Robin Hilliard, Lough Guitane, Killarney, Co. Kerry, Ireland.
00055    Tel:         [+353] 64-54014
00056    Internet:    softloft@iruccvax.ucc.ie
00057    Compu$erve:  100042, 1237
00058 
00059    If you feel like registering, and possibly get notices of updates and
00060    other items of software, then send me a post card of your home town.
00061 
00062    Thanks and enjoy!
00063 
00064 */
00065 #include "dosbox.h"
00066 #if C_DEBUG
00067 #include <stdio.h>
00068 #include <string.h>
00069 #include <stdarg.h>
00070 #include <stdlib.h>
00071 #include "mem.h"
00072 #include "paging.h"
00073 
00074 typedef Bit8u  UINT8;
00075 typedef Bit16u UINT16;
00076 typedef Bit32u UINT32;
00077 
00078 typedef Bit8s  INT8;
00079 typedef Bit16s INT16;
00080 typedef Bit32s INT32;
00081 
00082 
00083 /* Little endian uint read */
00084 #define le_uint8(ptr) (*(UINT8*)ptr)
00085 
00086 INLINE UINT16 le_uint16(const void* ptr) {
00087         const UINT8* ptr8 = (const UINT8*)ptr;
00088         return (UINT16)ptr8[0] | (UINT16)ptr8[1] << 8;
00089 }
00090 INLINE UINT32 le_uint32(const void* ptr) {
00091         const UINT8* ptr8 = (const UINT8*)ptr;
00092         return (UINT32)ptr8[0] | (UINT32)ptr8[1] << 8 | (UINT32)ptr8[2] << 16 | (UINT32)ptr8[3] << 24;
00093 }
00094 
00095 /* Little endian int read */
00096 #define le_int8(ptr) ((INT8)le_uint8(ptr))
00097 #define le_int16(ptr) ((INT16)le_uint16(ptr))
00098 #define le_int32(ptr) ((INT32)le_uint32(ptr))
00099 
00100 #define fp_segment(dw) ((dw >> 16) & 0xFFFFU)
00101 #define fp_offset(dw) (dw & 0xFFFFU)
00102 #define fp_addr(seg, off) ( (seg<<4)+off )
00103 
00104 static UINT8 must_do_size;   /* used with size of operand */
00105 static int wordop;           /* dealing with word or byte operand */
00106 
00107 static int instruction_offset;
00108 //static UINT16 instruction_segment;
00109 
00110 static char* ubufs;           /* start of buffer */
00111 static char* ubufp;           /* last position of buffer */
00112 static int invalid_opcode = 0;
00113 static int first_space = 1;
00114 
00115 static int prefix;            /* segment override prefix byte */
00116 static int modrmv;            /* flag for getting modrm byte */
00117 static int sibv;              /* flag for getting sib byte   */
00118 static int opsize;            /* just like it says ...       */
00119 static int addrsize;
00120 static int addr32bit=0;
00121 
00122 /* some defines for extracting instruction bit fields from bytes */
00123 
00124 #define MOD(a)    (((a)>>6)&7)
00125 #define REG(a)    (((a)>>3)&7)
00126 #define RM(a)     ((a)&7)
00127 #define SCALE(a)  (((a)>>6)&7)
00128 #define INDEX(a)  (((a)>>3)&7)
00129 #define BASE(a)   ((a)&7)
00130 
00131 /* Percent tokens in strings:
00132    First char after '%':
00133         A - direct address
00134         C - reg of r/m picks control register
00135         D - reg of r/m picks debug register
00136         E - r/m picks operand
00137         F - flags register
00138         G - reg of r/m picks general register
00139         I - immediate data
00140         J - relative IP offset
00141 +       K - call/jmp distance
00142         M - r/m picks memory
00143         O - no r/m, offset only
00144         R - mod of r/m picks register only
00145         S - reg of r/m picks segment register
00146         T - reg of r/m picks test register
00147         X - DS:ESI
00148         Y - ES:EDI
00149         2 - prefix of two-byte opcode
00150 +       e - put in 'e' if use32 (second char is part of reg name)
00151 +           put in 'w' for use16 or 'd' for use32 (second char is 'w')
00152 +       j - put in 'e' in jcxz if prefix==0x66
00153         f - floating point (second char is esc value)
00154         g - do r/m group 'n', n==0..7
00155         p - prefix
00156         s - size override (second char is a,o)
00157 +       d - put d if double arg, nothing otherwise (pushfd, popfd &c)
00158 +       w - put w if word, d if double arg, nothing otherwise (lodsw/lodsd)
00159 +       P - simple prefix
00160 
00161    Second char after '%':
00162         a - two words in memory (BOUND)
00163         b - byte
00164         c - byte or word
00165         d - dword
00166 +       f - far call/jmp
00167 +       n - near call/jmp
00168         p - 32 or 48 bit pointer
00169 +       q - byte/word thingy
00170         s - six byte pseudo-descriptor
00171         v - word or dword
00172         w - word
00173 +       x - sign extended byte
00174         F - use floating regs in mod/rm
00175         1-8 - group number, esc value, etc
00176 */
00177 
00178 /* watch out for aad && aam with odd operands */
00179 
00180 static char const* (*opmap1)[256];
00181 
00182 static char const * op386map1[256] = {
00183 /* 0 */
00184   "add %Eb,%Gb",      "add %Ev,%Gv",     "add %Gb,%Eb",    "add %Gv,%Ev",
00185   "add al,%Ib",       "add %eax,%Iv",    "push es",        "pop es",
00186   "or %Eb,%Gb",       "or %Ev,%Gv",      "or %Gb,%Eb",     "or %Gv,%Ev",
00187   "or al,%Ib",        "or %eax,%Iv",     "push cs",        "%2 ",
00188 /* 1 */
00189   "adc %Eb,%Gb",      "adc %Ev,%Gv",     "adc %Gb,%Eb",    "adc %Gv,%Ev",
00190   "adc al,%Ib",       "adc %eax,%Iv",    "push ss",        "pop ss",
00191   "sbb %Eb,%Gb",      "sbb %Ev,%Gv",     "sbb %Gb,%Eb",    "sbb %Gv,%Ev",
00192   "sbb al,%Ib",       "sbb %eax,%Iv",    "push ds",        "pop ds",
00193 /* 2 */
00194   "and %Eb,%Gb",      "and %Ev,%Gv",     "and %Gb,%Eb",    "and %Gv,%Ev",
00195   "and al,%Ib",       "and %eax,%Iv",    "%pe",            "daa",
00196   "sub %Eb,%Gb",      "sub %Ev,%Gv",     "sub %Gb,%Eb",    "sub %Gv,%Ev",
00197   "sub al,%Ib",       "sub %eax,%Iv",    "%pc",            "das",
00198 /* 3 */
00199   "xor %Eb,%Gb",      "xor %Ev,%Gv",     "xor %Gb,%Eb",    "xor %Gv,%Ev",
00200   "xor al,%Ib",       "xor %eax,%Iv",    "%ps",            "aaa",
00201   "cmp %Eb,%Gb",      "cmp %Ev,%Gv",     "cmp %Gb,%Eb",    "cmp %Gv,%Ev",
00202   "cmp al,%Ib",       "cmp %eax,%Iv",    "%pd",            "aas",
00203 /* 4 */
00204   "inc %eax",         "inc %ecx",        "inc %edx",       "inc %ebx",
00205   "inc %esp",         "inc %ebp",        "inc %esi",       "inc %edi",
00206   "dec %eax",         "dec %ecx",        "dec %edx",       "dec %ebx",
00207   "dec %esp",         "dec %ebp",        "dec %esi",       "dec %edi",
00208 /* 5 */
00209   "push %eax",        "push %ecx",       "push %edx",      "push %ebx",
00210   "push %esp",        "push %ebp",       "push %esi",      "push %edi",
00211   "pop %eax",         "pop %ecx",        "pop %edx",       "pop %ebx",
00212   "pop %esp",         "pop %ebp",        "pop %esi",       "pop %edi",
00213 /* 6 */
00214   "pusha%d ",         "popa%d ",         "bound %Gv,%Ma",  "arpl %Ew,%Rw",
00215   "%pf",              "%pg",             "%so",            "%sa",
00216   "push %Iv",         "imul %Gv,%Ev,%Iv","push %Ix",       "imul %Gv,%Ev,%Ib",
00217   "insb",             "ins%ew",          "outsb",          "outs%ew",
00218 /* 7 */
00219   "jo %Jb",           "jno %Jb",         "jc %Jb",         "jnc %Jb",
00220   "je %Jb",           "jne %Jb",         "jbe %Jb",        "ja %Jb",
00221   "js %Jb",           "jns %Jb",         "jpe %Jb",        "jpo %Jb",
00222   "jl %Jb",           "jge %Jb",         "jle %Jb",        "jg %Jb",
00223 /* 8 */
00224   "%g0 %Eb,%Ib",      "%g0 %Ev,%Iv",     "%g0 %Eb,%Ib",    "%g0 %Ev,%Ix",
00225   "test %Eb,%Gb",     "test %Ev,%Gv",    "xchg %Eb,%Gb",   "xchg %Ev,%Gv",
00226   "mov %Eb,%Gb",      "mov %Ev,%Gv",     "mov %Gb,%Eb",    "mov %Gv,%Ev",
00227   "mov %Ew,%Sw",      "lea %Gv,%M ",     "mov %Sw,%Ew",    "pop %Ev",
00228 /* 9 */
00229   "nop",              "xchg %ecx,%eax",  "xchg %edx,%eax", "xchg %ebx,%eax",
00230   "xchg %esp,%eax",   "xchg %ebp,%eax",  "xchg %esi,%eax", "xchg %edi,%eax",
00231   "cbw",              "cwd",             "call %Ap",       "fwait",
00232   "pushf%d ",         "popf%d ",         "sahf",           "lahf",
00233 /* a */
00234   "mov al,%Oc",       "mov %eax,%Ov",    "mov %Oc,al",     "mov %Ov,%eax",
00235   "%P movsb",         "%P movs%w",       "%P cmpsb",       "%P cmps%w ",
00236   "test al,%Ib",      "test %eax,%Iv",   "%P stosb",       "%P stos%w ",
00237   "%P lodsb",         "%P lods%w ",      "%P scasb",       "%P scas%w ",
00238 /* b */
00239   "mov al,%Ib",       "mov cl,%Ib",      "mov dl,%Ib",     "mov bl,%Ib",
00240   "mov ah,%Ib",       "mov ch,%Ib",      "mov dh,%Ib",     "mov bh,%Ib",
00241   "mov %eax,%Iv",     "mov %ecx,%Iv",    "mov %edx,%Iv",   "mov %ebx,%Iv",
00242   "mov %esp,%Iv",     "mov %ebp,%Iv",    "mov %esi,%Iv",   "mov %edi,%Iv",
00243 /* c */
00244   "%g1 %Eb,%Ib",      "%g1 %Ev,%Ib",     "ret %Iw",        "ret",
00245   "les %Gv,%Mp",      "lds %Gv,%Mp",     "mov %Eb,%Ib",    "mov %Ev,%Iv",
00246   "enter %Iw,%Ib",    "leave",           "retf %Iw",       "retf",
00247   "int 03",           "int %Ib",         "into",           "iret",
00248 /* d */
00249   "%g1 %Eb,1",        "%g1 %Ev,1",       "%g1 %Eb,cl",     "%g1 %Ev,cl",
00250   "aam ; %Ib",        "aad ; %Ib",       "setalc",         "xlat",
00251 #if 0
00252   "esc 0,%Ib",        "esc 1,%Ib",       "esc 2,%Ib",      "esc 3,%Ib",
00253   "esc 4,%Ib",        "esc 5,%Ib",       "esc 6,%Ib",      "esc 7,%Ib",
00254 #else
00255   "%f0",              "%f1",             "%f2",            "%f3",
00256   "%f4",              "%f5",             "%f6",            "%f7",
00257 #endif
00258 /* e */
00259   "loopne %Jb",       "loope %Jb",       "loop %Jb",       "j%j cxz %Jb",
00260   "in al,%Ib",        "in %eax,%Ib",     "out %Ib,al",     "out %Ib,%eax",
00261   "call %Jv",         "jmp %Jv",         "jmp %Ap",        "jmp %Ks%Jb",
00262   "in al,dx",         "in %eax,dx",      "out dx,al",      "out dx,%eax",
00263 /* f */
00264   "lock %p ",         "icebp",           "repne %p ",      "repe %p ",
00265   "hlt",              "cmc",             "%g2",            "%g2",
00266   "clc",              "stc",             "cli",            "sti",
00267   "cld",              "std",             "%g3",            "%g4"
00268 };
00269 
00270 static char const *second[] = {
00271 /* 0 */
00272   "%g5",              "%g6",             "lar %Gv,%Ew",    "lsl %Gv,%Ew",
00273   0,                  "[loadall]",       "clts",           "[loadall]",
00274   "invd",             "wbinvd",          0,                "UD2",
00275   0,                  0,                 0,                0,
00276 /* 1 */
00277   "mov %Eb,%Gb",      "mov %Ev,%Gv",     "mov %Gb,%Eb",    "mov %Gv,%Ev",
00278   0,                  0,                 0,                0,
00279   0,                  0,                 0,                0,
00280   0,                  0,                 0,                0,
00281 /* 2 */
00282   "mov %Rd,%Cd",      "mov %Rd,%Dd",     "mov %Cd,%Rd",    "mov %Dd,%Rd",
00283   "mov %Rd,%Td",      0,                 "mov %Td,%Rd",    0,
00284   0,                  0,                 0,                0,
00285   0,                  0,                 0,                0,
00286 /* 3 */
00287   0,                  "rdtsc",           0,                0,
00288   0,                  0,                 0,                0,
00289   0,                  0,                 0,                0,
00290   0,                  0,                 0,                0,
00291 /* 4 */
00292   0, 0, 0, 0, 0, 0, 0, 0,
00293   0, 0, 0, 0, 0, 0, 0, 0,
00294 /* 5 */
00295   0, 0, 0, 0, 0, 0, 0, 0,
00296   0, 0, 0, 0, 0, 0, 0, 0,
00297 /* 6 */
00298   0, 0, 0, 0, 0, 0, 0, 0,
00299   0, 0, 0, 0, 0, 0, 0, 0,
00300 /* 7 */
00301   0, 0, 0, 0, 0, 0, 0, 0,
00302   0, 0, 0, 0, 0, 0, 0, 0,
00303 /* 8 */
00304   "jo %Jv",           "jno %Jv",         "jb %Jv",         "jnb %Jv",
00305   "jz %Jv",           "jnz %Jv",         "jbe %Jv",        "ja %Jv",
00306   "js %Jv",           "jns %Jv",         "jp %Jv",         "jnp %Jv",
00307   "jl %Jv",           "jge %Jv",         "jle %Jv",        "jg %Jv",
00308 /* 9 */
00309   "seto %Eb",         "setno %Eb",       "setc %Eb",       "setnc %Eb",
00310   "setz %Eb",         "setnz %Eb",       "setbe %Eb",      "setnbe %Eb",
00311   "sets %Eb",         "setns %Eb",       "setp %Eb",       "setnp %Eb",
00312   "setl %Eb",         "setge %Eb",       "setle %Eb",      "setg %Eb",
00313 /* a */
00314   "push fs",          "pop fs",          "cpuid",          "bt %Ev,%Gv",
00315   "shld %Ev,%Gv,%Ib", "shld %Ev,%Gv,cl", 0,                0,
00316   "push gs",          "pop gs",          0,                "bts %Ev,%Gv",
00317   "shrd %Ev,%Gv,%Ib", "shrd %Ev,%Gv,cl", 0,                "imul %Gv,%Ev",
00318 /* b */
00319   "cmpxchg %Eb,%Gb",  "cmpxchg %Ev,%Gv", "lss %Mp",        "btr %Ev,%Gv",
00320   "lfs %Mp",          "lgs %Mp",         "movzx %Gv,%Eb",  "movzx %Gv,%Ew",
00321   0,                  0,                 "%g7 %Ev,%Ib",    "btc %Ev,%Gv",
00322   "bsf %Gv,%Ev",      "bsr %Gv,%Ev",     "movsx %Gv,%Eb",  "movsx %Gv,%Ew",
00323 /* c */
00324   "xadd %Eb,%Gb",     "xadd %Ev,%Gv",    0,                0,
00325   0,                  0,                 0,                0,
00326   "bswap eax",        "bswap ecx",       "bswap edx",      "bswap ebx",
00327   "bswap esp",        "bswap ebp",       "bswap esi",      "bswap edi",
00328 /* d */
00329   0, 0, 0, 0, 0, 0, 0, 0,
00330   0, 0, 0, 0, 0, 0, 0, 0,
00331 /* e */
00332   0, 0, 0, 0, 0, 0, 0, 0,
00333   0, 0, 0, 0, 0, 0, 0, 0,
00334 /* f */
00335   0, 0, 0, 0, 0, 0, 0, 0,
00336   0, 0, 0, 0, 0, 0, 0, 0,
00337 };
00338 
00339 static char const *groups[][8] = {   /* group 0 is group 3 for %Ev set */
00340 /* 0 */
00341   { "add",            "or",              "adc",            "sbb",
00342     "and",            "sub",             "xor",            "cmp"           },
00343 /* 1 */
00344   { "rol",            "ror",             "rcl",            "rcr",
00345     "shl",            "shr",             "shl",            "sar"           },
00346 /* 2 */  /* v   v*/
00347   { "test %Eq,%Iq",   "test %Eq,%Iq",    "not %Ec",        "neg %Ec",
00348     "mul %Ec",        "imul %Ec",        "div %Ec",        "idiv %Ec"      },
00349 /* 3 */
00350   { "inc %Eb",        "dec %Eb",         0,                0,
00351     0,                0,                 0,                "callback %Iw"  },
00352 /* 4 */
00353   { "inc %Ev",        "dec %Ev",         "call %Kn%Ev",  "call %Kf%Ep",
00354     "jmp %Kn%Ev",     "jmp %Kf%Ep",      "push %Ev",       0               },
00355 /* 5 */
00356   { "sldt %Ew",       "str %Ew",         "lldt %Ew",       "ltr %Ew",
00357     "verr %Ew",       "verw %Ew",        0,                0               },
00358 /* 6 */
00359   { "sgdt %Ms",       "sidt %Ms",        "lgdt %Ms",       "lidt %Ms",
00360     "smsw %Ew",       0,                 "lmsw %Ew",       "invlpg"        },
00361 /* 7 */
00362   { 0,                0,                 0,                0,
00363     "bt",             "bts",             "btr",            "btc"           }
00364 };
00365 
00366 /* zero here means invalid.  If first entry starts with '*', use st(i) */
00367 /* no assumed %EFs here.  Indexed by RM(modrm())                       */
00368 static char const *f0[]     = { 0, 0, 0, 0, 0, 0, 0, 0};
00369 static char const *fop_8[]  = { "*fld st,%GF" };
00370 static char const *fop_9[]  = { "*fxch st,%GF" };
00371 static char const *fop_10[] = { "fnop", 0, 0, 0, 0, 0, 0, 0 };
00372 static char const *fop_11[]  = { "*fst st,%GF" };
00373 static char const *fop_12[] = { "fchs", "fabs", 0, 0, "ftst", "fxam", 0, 0 };
00374 static char const *fop_13[] = { "fld1", "fldl2t", "fldl2e", "fldpi",
00375                    "fldlg2", "fldln2", "fldz", 0 };
00376 static char const *fop_14[] = { "f2xm1", "fyl2x", "fptan", "fpatan",
00377                    "fxtract", "fprem1", "fdecstp", "fincstp" };
00378 static char const *fop_15[] = { "fprem", "fyl2xp1", "fsqrt", "fsincos",
00379                    "frndint", "fscale", "fsin", "fcos" };
00380 static char const *fop_21[] = { 0, "fucompp", 0, 0, 0, 0, 0, 0 };
00381 static char const *fop_28[] = { "[fneni]", "[fndis]", "fclex", "finit", "[fnsetpm]", "[frstpm]", 0, 0 };
00382 static char const *fop_32[] = { "*fadd %GF,st" };
00383 static char const *fop_33[] = { "*fmul %GF,st" };
00384 static char const *fop_34[] = { "*fcom %GF,st" };
00385 static char const *fop_35[] = { "*fcomp %GF,st" };
00386 static char const *fop_36[] = { "*fsubr %GF,st" };
00387 static char const *fop_37[] = { "*fsub %GF,st" };
00388 static char const *fop_38[] = { "*fdivr %GF,st" };
00389 static char const *fop_39[] = { "*fdiv %GF,st" };
00390 static char const *fop_40[] = { "*ffree %GF" };
00391 static char const *fop_41[] = { "*fxch %GF" };
00392 static char const *fop_42[] = { "*fst %GF" };
00393 static char const *fop_43[] = { "*fstp %GF" };
00394 static char const *fop_44[] = { "*fucom %GF" };
00395 static char const *fop_45[] = { "*fucomp %GF" };
00396 static char const *fop_48[] = { "*faddp %GF,st" };
00397 static char const *fop_49[] = { "*fmulp %GF,st" };
00398 static char const *fop_50[] = { "*fcomp %GF,st" };
00399 static char const *fop_51[] = { 0, "fcompp", 0, 0, 0, 0, 0, 0 };
00400 static char const *fop_52[] = { "*fsubrp %GF,st" };
00401 static char const *fop_53[] = { "*fsubp %GF,st" };
00402 static char const *fop_54[] = { "*fdivrp %GF,st" };
00403 static char const *fop_55[] = { "*fdivp %GF,st" };
00404 static char const *fop_56[] = { "*ffreep %GF" };
00405 static char const *fop_60[] = { "fstsw ax", 0, 0, 0, 0, 0, 0, 0 };
00406 
00407 static char const **fspecial[] = { /* 0=use st(i), 1=undefined 0 in fop_* means undefined */
00408   0, 0, 0, 0, 0, 0, 0, 0,
00409   fop_8, fop_9, fop_10, fop_11, fop_12, fop_13, fop_14, fop_15,
00410   f0, f0, f0, f0, f0, fop_21, f0, f0,
00411   f0, f0, f0, f0, fop_28, f0, f0, f0,
00412   fop_32, fop_33, fop_34, fop_35, fop_36, fop_37, fop_38, fop_39,
00413   fop_40, fop_41, fop_42, fop_43, fop_44, fop_45, f0, f0,
00414   fop_48, fop_49, fop_50, fop_51, fop_52, fop_53, fop_54, fop_55,
00415   fop_56, f0, f0, f0, fop_60, f0, f0, f0,
00416 };
00417 
00418 static const char *floatops[] = { /* assumed " %EF" at end of each.  mod != 3 only */
00419 /*00*/ "fadd", "fmul", "fcom", "fcomp",
00420        "fsub", "fsubr", "fdiv", "fdivr",
00421 /*08*/ "fld", 0, "fst", "fstp",
00422        "fldenv", "fldcw", "fstenv", "fstcw",
00423 /*16*/ "fiadd", "fimul", "ficomw", "ficompw",
00424        "fisub", "fisubr", "fidiv", "fidivr",
00425 /*24*/ "fild", 0, "fist", "fistp",
00426        "frstor", "fldt", 0, "fstpt",
00427 /*32*/ "faddq", "fmulq", "fcomq", "fcompq",
00428        "fsubq", "fsubrq", "fdivq", "fdivrq",
00429 /*40*/ "fldq", 0, "fstq", "fstpq",
00430        0, 0, "fsave", "fstsw",
00431 /*48*/ "fiaddw", "fimulw", "ficomw", "ficompw",
00432        "fisubw", "fisubrw", "fidivw", "fidivr",
00433 /*56*/ "fildw", 0, "fistw", "fistpw",
00434        "fbldt", "fildq", "fbstpt", "fistpq"
00435 };
00436 
00437 static char *addr_to_hex(UINT32 addr, int splitup) {
00438   static char buffer[11];
00439 
00440   if (splitup) {
00441     if (fp_segment(addr)==0 || fp_offset(addr)==0xffff) /* 'coz of wraparound */
00442       sprintf(buffer, "%04X", (unsigned)fp_offset(addr) );
00443     else
00444       sprintf(buffer, "%04X:%04X", (unsigned)fp_segment(addr), (unsigned)fp_offset(addr) );
00445   } else {
00446 #if 0
00447           /* Pet outcommented, reducing address size to 4
00448                  when segment is 0 or 0xffff */
00449     if (fp_segment(addr)==0 || fp_segment(addr)==0xffff) /* 'coz of wraparound */
00450       sprintf(buffer, "%04X", (unsigned)fp_offset(addr) );
00451     else
00452 #endif
00453 
00454         sprintf(buffer, "%08X", addr );
00455         
00456   }
00457 
00458   return buffer;
00459 }
00460 
00461 static PhysPt getbyte_mac;
00462 static PhysPt startPtr;
00463 
00464 static UINT8 getbyte(void) {
00465     Bit8u c;
00466 
00467         if (!mem_readb_checked(getbyte_mac++,&c))
00468         return c;
00469 
00470     return 0xFF;
00471 }
00472 
00473 /*
00474    only one modrm or sib byte per instruction, tho' they need to be
00475    returned a few times...
00476 */
00477 
00478 static int modrm(void)
00479 {
00480   if (modrmv == -1)
00481     modrmv = getbyte();
00482   return modrmv;
00483 }
00484 
00485 static int sib(void)
00486 {
00487   if (sibv == -1)
00488     sibv = getbyte();
00489   return sibv;
00490 }
00491 
00492 /*------------------------------------------------------------------------*/
00493 
00494 static void uprintf(char const *s, ...)
00495 {
00496         va_list arg_ptr;
00497         va_start (arg_ptr, s);
00498         vsprintf(ubufp, s, arg_ptr);
00499         while (*ubufp)
00500                 ubufp++;
00501 }
00502 
00503 static void uputchar(char c)
00504 {
00505   *ubufp++ = c;
00506   *ubufp = 0;
00507 }
00508 
00509 /*------------------------------------------------------------------------*/
00510 
00511 static int bytes(char c)
00512 {
00513   switch (c) {
00514   case 'b':
00515        return 1;
00516   case 'w':
00517        return 2;
00518   case 'd':
00519        return 4;
00520   case 'v':
00521        if (opsize == 32)
00522          return 4;
00523        else
00524          return 2;
00525   }
00526   return 0;
00527 }
00528 
00529 /*------------------------------------------------------------------------*/
00530 static void outhex(char subtype, int extend, int optional, int defsize, int sign)
00531 {
00532   int n=0, s=0, i;
00533   INT32 delta = 0;
00534   unsigned char buff[6];
00535   char *name;
00536   char  signchar;
00537 
00538   switch (subtype) {
00539   case 'q':
00540        if (wordop) {
00541          if (opsize==16) {
00542            n = 2;
00543          } else {
00544            n = 4;
00545          }
00546        } else {
00547          n = 1;
00548        }
00549        break;
00550 
00551   case 'a':
00552        break;
00553   case 'x':
00554        extend = 2;
00555        n = 1;
00556        break;
00557   case 'b':
00558        n = 1;
00559        break;
00560   case 'w':
00561        n = 2;
00562        break;
00563   case 'd':
00564        n = 4;
00565        break;
00566   case 's':
00567        n = 6;
00568        break;
00569   case 'c':
00570   case 'v':
00571        if (defsize == 32)
00572          n = 4;
00573        else
00574          n = 2;
00575        break;
00576   case 'p':
00577        if (defsize == 32)
00578          n = 6;
00579        else
00580          n = 4;
00581        s = 1;
00582        break;
00583   }
00584   for (i=0; i<n; i++)
00585     buff[i] = getbyte();
00586   for (; i<extend; i++)
00587     buff[i] = (buff[i-1] & 0x80) ? 0xff : 0;
00588   if (s) {
00589     uprintf("%02X%02X:", (unsigned)buff[n-1], (unsigned)buff[n-2]);
00590     n -= 2;
00591   }
00592   switch (n) {
00593   case 1:
00594        delta = le_int8(buff);
00595        break;
00596   case 2:
00597        delta = le_int16(buff);
00598        break;
00599   case 4:
00600        delta = le_int32(buff);
00601        break;
00602   }
00603   if (extend > n) {
00604     if (subtype!='x') {
00605       if (delta<0) {
00606         delta = -delta;
00607         signchar = '-';
00608       } else
00609         signchar = '+';
00610       if (delta || !optional)
00611                 uprintf("%c%0*lX", (char)signchar, (int)(extend), (long)delta);
00612     } else {
00613       if (extend==2)
00614         delta = (UINT16)delta;
00615           uprintf("%0.*lX", (int)(2*extend), (long)delta );
00616     }
00617     return;
00618   }
00619   if ((n == 4) && !sign) {
00620     name = addr_to_hex((UINT32)delta, 0);
00621     uprintf("%s", name);
00622     return;
00623   }
00624   switch (n) {
00625   case 1:
00626        if (sign && (char)delta<0) {
00627          delta = -delta;
00628          signchar = '-';
00629        } else
00630          signchar = '+';
00631        if (sign)
00632                  uprintf("%c%02lX", (char)signchar, delta & 0xFFL);
00633        else
00634                  uprintf("%02lX", delta & 0xFFL);
00635        break;
00636 
00637   case 2:
00638        if (sign && delta<0) {
00639          signchar = '-';
00640          delta = -delta;
00641        } else
00642          signchar = '+';
00643        if (sign)
00644                  uprintf("%c%04lX", (char)signchar, delta & 0xFFFFL);
00645        else
00646                  uprintf("%04lX", delta & 0xFFFFL);
00647        break;
00648 
00649   case 4:
00650        if (sign && delta<0) {
00651          delta = -delta;
00652          signchar = '-';
00653        } else
00654          signchar = '+';
00655        if (sign)
00656                  uprintf("%c%08lX", (char)signchar, delta & 0xFFFFFFFFL);
00657        else
00658                  uprintf("%08lX", delta & 0xFFFFFFFFL);
00659        break;
00660   }
00661 }
00662 
00663 
00664 /*------------------------------------------------------------------------*/
00665 
00666 static void reg_name(int regnum, char size)
00667 {
00668   if (size == 'F') { /* floating point register? */
00669     uprintf("st(%d)", regnum);
00670     return;
00671   }
00672   if ((((size == 'c') || (size == 'v')) && (opsize == 32)) || (size == 'd'))
00673     uputchar('e');
00674   if ((size=='q' || size == 'b' || size=='c') && !wordop) {
00675     uputchar("acdbacdb"[regnum]);
00676     uputchar("llllhhhh"[regnum]);
00677   } else {
00678     uputchar("acdbsbsd"[regnum]);
00679     uputchar("xxxxppii"[regnum]);
00680   }
00681 }
00682 
00683 
00684 /*------------------------------------------------------------------------*/
00685 
00686 static void ua_str(char const *str);
00687 
00688 static void do_sib(int m)
00689 {
00690   int s, i, b;
00691 
00692   s = SCALE(sib());
00693   i = INDEX(sib());
00694   b = BASE(sib());
00695   switch (b) {     /* pick base */
00696   case 0: ua_str("%p:[eax"); break;
00697   case 1: ua_str("%p:[ecx"); break;
00698   case 2: ua_str("%p:[edx"); break;
00699   case 3: ua_str("%p:[ebx"); break;
00700   case 4: ua_str("%p:[esp"); break;
00701   case 5:
00702        if (m == 0) {
00703          ua_str("%p:[");
00704          outhex('d', 4, 0, addrsize, 0);
00705        } else {
00706          ua_str("%p:[ebp");
00707        }
00708        break;
00709   case 6: ua_str("%p:[esi"); break;
00710   case 7: ua_str("%p:[edi"); break;
00711   }
00712   switch (i) {     /* and index */
00713   case 0: uprintf("+eax"); break;
00714   case 1: uprintf("+ecx"); break;
00715   case 2: uprintf("+edx"); break;
00716   case 3: uprintf("+ebx"); break;
00717   case 4: break;
00718   case 5: uprintf("+ebp"); break;
00719   case 6: uprintf("+esi"); break;
00720   case 7: uprintf("+edi"); break;
00721   }
00722   if (i != 4) {
00723     switch (s) {    /* and scale */
00724       case 0: /*uprintf("");*/ break;
00725       case 1: uprintf("*2"); break;
00726       case 2: uprintf("*4"); break;
00727       case 3: uprintf("*8"); break;
00728     }
00729   }
00730 }
00731 
00732 
00733 
00734 /*------------------------------------------------------------------------*/
00735 static void do_modrm(char subtype)
00736 {
00737   int mod = MOD(modrm());
00738   int rm = RM(modrm());
00739   int extend = (addrsize == 32) ? 4 : 2;
00740 
00741   if (mod == 3) { /* specifies two registers */
00742     reg_name(rm, subtype);
00743     return;
00744   }
00745   if (must_do_size) {
00746     if (wordop) {
00747       if (addrsize==32 || opsize==32) {       /* then must specify size */
00748                 ua_str("dword ");
00749       } else {
00750                 ua_str("word ");
00751       }
00752     } else {
00753           ua_str("byte ");
00754     }
00755   }
00756   if ((mod == 0) && (rm == 5) && (addrsize == 32)) {/* mem operand with 32 bit ofs */
00757     ua_str("%p:[");
00758     outhex('d', extend, 0, addrsize, 0);
00759     uputchar(']');
00760     return;
00761   }
00762   if ((mod == 0) && (rm == 6) && (addrsize == 16)) { /* 16 bit dsplcmnt */
00763     ua_str("%p:[");
00764     outhex('w', extend, 0, addrsize, 0);
00765     uputchar(']');
00766     return;
00767   }
00768   if ((addrsize != 32) || (rm != 4))
00769     ua_str("%p:[");
00770   if (addrsize == 16) {
00771     switch (rm) {
00772     case 0: uprintf("bx+si"); break;
00773     case 1: uprintf("bx+di"); break;
00774     case 2: uprintf("bp+si"); break;
00775     case 3: uprintf("bp+di"); break;
00776     case 4: uprintf("si"); break;
00777     case 5: uprintf("di"); break;
00778     case 6: uprintf("bp"); break;
00779     case 7: uprintf("bx"); break;
00780     }
00781   } else {
00782     switch (rm) {
00783     case 0: uprintf("eax"); break;
00784     case 1: uprintf("ecx"); break;
00785     case 2: uprintf("edx"); break;
00786     case 3: uprintf("ebx"); break;
00787     case 4: do_sib(mod); break;
00788     case 5: uprintf("ebp"); break;
00789     case 6: uprintf("esi"); break;
00790     case 7: uprintf("edi"); break;
00791     }
00792   }
00793   switch (mod) {
00794   case 1:
00795        outhex('b', extend, 1, addrsize, 0);
00796        break;
00797   case 2:
00798        outhex('v', extend, 1, addrsize, 1);
00799        break;
00800   }
00801   uputchar(']');
00802 }
00803 
00804 
00805 
00806 /*------------------------------------------------------------------------*/
00807 static void floating_point(int e1)
00808 {
00809   int esc = e1*8 + REG(modrm());
00810 
00811   if ((MOD(modrm()) == 3)&&fspecial[esc]) {
00812     if (fspecial[esc][0]) {
00813       if (fspecial[esc][0][0] == '*') {
00814         ua_str(fspecial[esc][0]+1);
00815       } else {
00816         ua_str(fspecial[esc][RM(modrm())]);
00817       }
00818     } else {
00819       ua_str(floatops[esc]);
00820       ua_str(" %EF");
00821     }
00822   } else {
00823     ua_str(floatops[esc]);
00824     ua_str(" %EF");
00825   }
00826 }
00827 
00828 
00829 /*------------------------------------------------------------------------*/
00830 /* Main table driver                                                      */
00831 
00832 #define INSTRUCTION_SIZE ( (int)getbyte_mac - (int)startPtr )
00833 
00834 static void percent(char type, char subtype)
00835 {
00836   INT32 vofs = 0;
00837   char *name=NULL;
00838   int extend = (addrsize == 32) ? 4 : 2;
00839   UINT8 c;
00840 
00841   switch (type) {
00842   case 'A':                          /* direct address */
00843        outhex(subtype, extend, 0, addrsize, 0);
00844        break;
00845 
00846   case 'C':                          /* reg(r/m) picks control reg */
00847        uprintf("CR%d", REG(modrm()));
00848        must_do_size = 0;
00849        break;
00850 
00851   case 'D':                          /* reg(r/m) picks debug reg */
00852        uprintf("DR%d", REG(modrm()));
00853        must_do_size = 0;
00854        break;
00855 
00856   case 'E':                          /* r/m picks operand */
00857        do_modrm(subtype);
00858        break;
00859 
00860   case 'G':                          /* reg(r/m) picks register */
00861        if (subtype == 'F')                 /* 80*87 operand?   */
00862          reg_name(RM(modrm()), subtype);
00863        else
00864          reg_name(REG(modrm()), subtype);
00865        must_do_size = 0;
00866        break;
00867 
00868   case 'I':                            /* immed data */
00869        outhex(subtype, 0, 0, opsize, 0);
00870        break;
00871 
00872   case 'J':                            /* relative IP offset */
00873        switch (bytes(subtype)) {              /* sizeof offset value */
00874        case 1:
00875             vofs = (INT8)getbyte();
00876                         name = addr_to_hex((UINT32)vofs+(UINT32)instruction_offset+(UINT32)INSTRUCTION_SIZE,0);
00877             break;
00878        case 2:
00879             vofs  = (INT32)((UINT32)getbyte());
00880             vofs |= (INT32)((UINT32)getbyte() << 8);
00881             vofs  = (INT16)vofs;
00882                         name  = addr_to_hex((UINT32)vofs+(UINT32)instruction_offset+(UINT32)INSTRUCTION_SIZE,0);
00883             break;
00884                         /* i386 */
00885        case 4:
00886             vofs  = (INT32)((UINT32)getbyte());           /* yuk! */
00887             vofs |= (INT32)((UINT32)getbyte() << 8);
00888             vofs |= (INT32)((UINT32)getbyte() << 16);
00889             vofs |= (INT32)((UINT32)getbyte() << 24);
00890                         name = addr_to_hex((UINT32)vofs+(UINT32)instruction_offset+(UINT32)INSTRUCTION_SIZE,(addrsize == 32)?0:1);
00891             break;
00892        }
00893            if (vofs<0)
00894                    uprintf("%s ($-%x)", name, -vofs);
00895            else
00896                    uprintf("%s ($+%x)", name, vofs);
00897        break;
00898 
00899   case 'K':
00900        switch (subtype) {
00901        case 'f':
00902             ua_str("far ");
00903             break;
00904        case 'n':
00905             ua_str("near ");
00906             break;
00907        case 's':
00908             ua_str("short ");
00909             break;
00910        }
00911        break;
00912 
00913   case 'M':                            /* r/m picks memory */
00914        do_modrm(subtype);
00915        break;
00916 
00917   case 'O':                            /* offset only */
00918        ua_str("%p:[");
00919        outhex(subtype, extend, 0, addrsize, 0);
00920        uputchar(']');
00921        break;
00922 
00923   case 'P':                            /* prefix byte (rh) */
00924        ua_str("%p:");
00925        break;
00926 
00927   case 'R':                            /* mod(r/m) picks register */
00928        reg_name(RM(modrm()), subtype);      /* rh */
00929        must_do_size = 0;
00930        break;
00931 
00932   case 'S':                            /* reg(r/m) picks segment reg */
00933        uputchar("ecsdfg"[REG(modrm())]);
00934        uputchar('s');
00935        must_do_size = 0;
00936        break;
00937 
00938   case 'T':                            /* reg(r/m) picks T reg */
00939        uprintf("tr%d", REG(modrm()));
00940        must_do_size = 0;
00941        break;
00942 
00943   case 'X':                            /* ds:si type operator */
00944        uprintf("ds:[");
00945        if (addrsize == 32)
00946          uputchar('e');
00947        uprintf("si]");
00948        break;
00949 
00950   case 'Y':                            /* es:di type operator */
00951        uprintf("es:[");
00952        if (addrsize == 32)
00953          uputchar('e');
00954        uprintf("di]");
00955        break;
00956 
00957   case '2':                            /* old [pop cs]! now indexes */
00958        c = getbyte();
00959        wordop = c & 1;
00960        ua_str(second[c]);              /* instructions in 386/486   */
00961        break;
00962 
00963   case 'g':                            /* modrm group `subtype' (0--7) */
00964        ua_str(groups[subtype-'0'][REG(modrm())]);
00965        break;
00966 
00967   case 'd':                             /* sizeof operand==dword? */
00968        if (opsize == 32)
00969          uputchar('d');
00970        uputchar(subtype);
00971        break;
00972 
00973   case 'w':                             /* insert explicit size specifier */
00974        if (opsize == 32)
00975          uputchar('d');
00976        else
00977          uputchar('w');
00978        uputchar(subtype);
00979        break;
00980 
00981   case 'e':                         /* extended reg name */
00982        if (opsize == 32) {
00983          if (subtype == 'w')
00984            uputchar('d');
00985          else {
00986            uputchar('e');
00987            uputchar(subtype);
00988          }
00989        } else
00990          uputchar(subtype);
00991        break;
00992 
00993   case 'f':                    /* '87 opcode */
00994        floating_point(subtype-'0');
00995        break;
00996 
00997   case 'j':
00998        if (addrsize==32 || opsize==32) /* both of them?! */
00999          uputchar('e');
01000        break;
01001 
01002   case 'p':                    /* prefix byte */
01003        switch (subtype)  {
01004        case 'c':
01005        case 'd':
01006        case 'e':
01007        case 'f':
01008        case 'g':
01009        case 's':
01010             prefix = subtype;
01011             c = getbyte();
01012             wordop = c & 1;
01013             ua_str((*opmap1)[c]);
01014             break;
01015        case ':':
01016             if (prefix)
01017               uprintf("%cs:", prefix);
01018             break;
01019        case ' ':
01020             c = getbyte();
01021             wordop = c & 1;
01022             ua_str((*opmap1)[c]);
01023             break;
01024        }
01025        break;
01026 
01027   case 's':                           /* size override */
01028        switch (subtype) {
01029        case 'a':
01030             addrsize = 48 - addrsize;
01031             c = getbyte();
01032             wordop = c & 1;
01033             ua_str((*opmap1)[c]);
01034 /*            ua_str(opmap1[getbyte()]); */
01035             break;
01036        case 'o':
01037             opsize = 48 - opsize;
01038             c = getbyte();
01039             wordop = c & 1;
01040             ua_str((*opmap1)[c]);
01041 /*            ua_str(opmap1[getbyte()]); */
01042             break;
01043        }
01044        break;
01045    }
01046 }
01047 
01048 
01049 static void ua_str(char const *str)
01050 {
01051   char c;
01052 
01053   if (str == 0) {
01054     invalid_opcode = 1;
01055     uprintf("?");
01056     return;
01057   }
01058 
01059   if (strpbrk(str, "CDFGRST")) /* specifiers for registers=>no size 2b specified */
01060     must_do_size = 0;
01061 
01062   while ((c = *str++) != 0) {
01063         if (c == ' ' && first_space)
01064         {
01065                 first_space = 0;
01066                 do
01067                 {
01068                         uputchar(' ');
01069                 } while ( (int)(ubufp - ubufs) < 5 );
01070         }
01071         else
01072     if (c == '%') {
01073       c = *str++;
01074       percent(c, *str++);
01075     } else {
01076       uputchar(c);
01077     }
01078   }
01079 }
01080 
01081 
01082 Bitu DasmI386(char* buffer, PhysPt pc, Bitu cur_ip, bool bit32)
01083 {
01084         Bitu c;
01085 
01086 
01087         instruction_offset = cur_ip;
01088         /* input buffer */
01089         startPtr        = pc;
01090         getbyte_mac = pc;
01091 
01092         /* output buffer */
01093         ubufs = buffer;
01094         ubufp = buffer;
01095         first_space = 1;
01096 
01097         addr32bit=1;
01098 
01099         prefix = 0;
01100         modrmv = sibv = -1;     /* set modrm and sib flags */
01101         if (bit32) opsize = addrsize = 32;
01102         else opsize = addrsize = 16;
01103         c = getbyte();
01104         wordop = c & 1;
01105         must_do_size = 1;
01106         invalid_opcode = 0;
01107         opmap1=&op386map1;
01108         ua_str(op386map1[c]);
01109 
01110         if (invalid_opcode) {
01111                 /* restart output buffer */
01112                 ubufp = buffer;
01113                 /* invalid instruction, use db xx */
01114                 uprintf("db %02X", (unsigned)c);
01115                 return 1;
01116         }
01117 
01118         return getbyte_mac-pc;
01119 }
01120 
01121 int DasmLastOperandSize()
01122 {
01123         return opsize;
01124 }
01125 
01126 
01127 #endif
01128