Rework last checkin to the following:

* i386-dis.c (FWAIT_OPCODE): Define.
	(used_prefixes): New static variable.
	(fetch_data): Don't print an error message if we have already
	fetched some bytes successfully.
	(ckprefix): Clear used_prefixes.  Use FWAIT_OPCODE, not 0x9b.
	(prefix_name): New static function.
	(print_insn_i386): If setjmp fails, indicating a data error, but
	we have managed to fetch some bytes, print the first one as a
	prefix or a .byte pseudo-op.  If fwait is followed by a non
	floating point instruction, print the first prefix.  Set
	used_prefixes when prefixes are used.  If any prefixes were not
	used after disassembling the instruction, print the first prefix
	instead of printing the instruction.
	(putop): Set used_prefixes when prefixes are used.
	(append_seg, OP_E, OP_G, OP_REG, OP_I, OP_sI, OP_J): Likewise.
	(OP_DIR, OP_SIMD_Suffix): Likewise.
This commit is contained in:
Ian Lance Taylor 1999-06-13 17:04:42 +00:00
parent 42751cf354
commit 7d4210142a
1 changed files with 144 additions and 41 deletions

View File

@ -65,6 +65,10 @@ struct dis_private
/* Flags for the prefixes for the current instruction. See below. */ /* Flags for the prefixes for the current instruction. See below. */
static int prefixes; static int prefixes;
/* Flags for prefixes which we somehow handled when printing the
current instruction. */
static int used_prefixes;
/* Flags stored in PREFIXES. */ /* Flags stored in PREFIXES. */
#define PREFIX_REPZ 1 #define PREFIX_REPZ 1
#define PREFIX_REPNZ 2 #define PREFIX_REPNZ 2
@ -101,15 +105,11 @@ fetch_data (info, addr)
info); info);
if (status != 0) if (status != 0)
{ {
/* If we have found an fwait prefix and an fwait opcode, then /* If we did manage to read at least one byte, then
print_insn_i386 will arrange to print an instruction after we print_insn_i386 will do something sensible. Otherwise, print
longjmp, and we don't want to print an error message here. an error. We do that here because this is where we know
This hack is required because we treat fwait as a prefix, but STATUS. */
since fwait is really an instruction we want to print a if (priv->max_fetched == priv->the_buffer)
standalone fwait correctly. */
if ((prefixes & PREFIX_FWAIT) == 0
|| memchr (priv->the_buffer, FWAIT_OPCODE,
priv->max_fetched - priv->the_buffer) == NULL)
(*info->memory_error_func) (status, start, info); (*info->memory_error_func) (status, start, info);
longjmp (priv->bailout, 1); longjmp (priv->bailout, 1);
} }
@ -230,6 +230,7 @@ static void dofloat PARAMS ((int sizeflag));
static int get16 PARAMS ((void)); static int get16 PARAMS ((void));
static int get32 PARAMS ((void)); static int get32 PARAMS ((void));
static void ckprefix PARAMS ((void)); static void ckprefix PARAMS ((void));
static const char *prefix_name PARAMS ((int, int));
static void ptr_reg PARAMS ((int, int)); static void ptr_reg PARAMS ((int, int));
static void BadOp PARAMS ((void)); static void BadOp PARAMS ((void));
@ -1881,6 +1882,7 @@ static void
ckprefix () ckprefix ()
{ {
prefixes = 0; prefixes = 0;
used_prefixes = 0;
while (1) while (1)
{ {
FETCH_DATA (the_info, codep + 1); FETCH_DATA (the_info, codep + 1);
@ -1938,6 +1940,45 @@ ckprefix ()
} }
} }
/* Return the name of the prefix byte PREF, or NULL if PREF is not a
prefix byte. */
static const char *
prefix_name (pref, sizeflag)
int pref;
int sizeflag;
{
switch (pref)
{
case 0xf3:
return "repz";
case 0xf2:
return "repnz";
case 0xf0:
return "lock";
case 0x2e:
return "cs";
case 0x36:
return "ss";
case 0x3e:
return "ds";
case 0x26:
return "es";
case 0x64:
return "fs";
case 0x65:
return "gs";
case 0x66:
return (sizeflag & DFLAG) ? "data16" : "data32";
case 0x67:
return (sizeflag & AFLAG) ? "addr16" : "addr32";
case FWAIT_OPCODE:
return "fwait";
default:
return NULL;
}
}
static char op1out[100], op2out[100], op3out[100]; static char op1out[100], op2out[100], op3out[100];
static int op_ad, op_index[3]; static int op_ad, op_index[3];
static unsigned int op_address[3]; static unsigned int op_address[3];
@ -2002,7 +2043,7 @@ print_insn_i386 (pc, info)
int needcomma; int needcomma;
unsigned char need_modrm; unsigned char need_modrm;
unsigned char uses_f3_prefix; unsigned char uses_f3_prefix;
int sizeflag; int sizeflag, orig_sizeflag;
struct dis_private priv; struct dis_private priv;
bfd_byte *inbuf = priv.the_buffer; bfd_byte *inbuf = priv.the_buffer;
@ -2014,6 +2055,7 @@ print_insn_i386 (pc, info)
sizeflag = 0; sizeflag = 0;
else else
abort (); abort ();
orig_sizeflag = sizeflag;
/* The output looks better if we put 6 bytes on a line, since that /* The output looks better if we put 6 bytes on a line, since that
puts most long word instructions on a single line. */ puts most long word instructions on a single line. */
@ -2037,27 +2079,24 @@ print_insn_i386 (pc, info)
if (setjmp (priv.bailout) != 0) if (setjmp (priv.bailout) != 0)
{ {
const char *name;
/* Getting here means we tried for data but didn't get it. That /* Getting here means we tried for data but didn't get it. That
means we have an incomplete instruction of some sort. means we have an incomplete instruction of some sort. Just
However, we need to check at least one case here: fwait is a print the first byte as a prefix or a .byte pseudo-op. */
complete instruction, although we treat it as a prefix. */
if (prefixes & PREFIX_FWAIT)
{
unsigned char *p;
p = memchr (inbuf, FWAIT_OPCODE, codep - inbuf);
if (p != NULL)
{
(*info->fprintf_func) (info->stream, "fwait");
return (p + 1) - inbuf;
}
}
if (codep > inbuf) if (codep > inbuf)
{ {
/* This will at least let objdump print the bytes followed name = prefix_name (inbuf[0], orig_sizeflag);
by the error message generated by fetch_data. */ if (name != NULL)
return codep - inbuf; (*info->fprintf_func) (info->stream, "%s", name);
else
{
/* Just print the first byte as a .byte instruction. */
(*info->fprintf_func) (info->stream, ".byte 0x%x",
(unsigned int) inbuf[0]);
}
return 1;
} }
return -1; return -1;
@ -2075,10 +2114,15 @@ print_insn_i386 (pc, info)
if ((prefixes & PREFIX_FWAIT) if ((prefixes & PREFIX_FWAIT)
&& ((*codep < 0xd8) || (*codep > 0xdf))) && ((*codep < 0xd8) || (*codep > 0xdf)))
{ {
/* fwait not followed by floating point instruction. */ const char *name;
(*info->fprintf_func) (info->stream, "fwait");
/* There may be other prefixes. Skip any before the fwait. */ /* fwait not followed by floating point instruction. Print the
return codep - inbuf; first prefix, which is probably fwait itself. */
name = prefix_name (inbuf[0], orig_sizeflag);
if (name == NULL)
name = INTERNAL_DISASSEMBLER_ERROR;
(*info->fprintf_func) (info->stream, "%s", name);
return 1;
} }
if (*codep == 0x0f) if (*codep == 0x0f)
@ -2103,11 +2147,20 @@ print_insn_i386 (pc, info)
codep++; codep++;
if (!uses_f3_prefix && (prefixes & PREFIX_REPZ)) if (!uses_f3_prefix && (prefixes & PREFIX_REPZ))
oappend ("repz "); {
oappend ("repz ");
used_prefixes |= PREFIX_REPZ;
}
if (prefixes & PREFIX_REPNZ) if (prefixes & PREFIX_REPNZ)
oappend ("repnz "); {
oappend ("repnz ");
used_prefixes |= PREFIX_REPNZ;
}
if (prefixes & PREFIX_LOCK) if (prefixes & PREFIX_LOCK)
oappend ("lock "); {
oappend ("lock ");
used_prefixes |= PREFIX_LOCK;
}
if (prefixes & PREFIX_DATA) if (prefixes & PREFIX_DATA)
sizeflag ^= DFLAG; sizeflag ^= DFLAG;
@ -2119,6 +2172,7 @@ print_insn_i386 (pc, info)
oappend ("addr32 "); oappend ("addr32 ");
else else
oappend ("addr16 "); oappend ("addr16 ");
used_prefixes |= PREFIX_ADDR;
} }
if (need_modrm) if (need_modrm)
@ -2144,6 +2198,7 @@ print_insn_i386 (pc, info)
break; break;
case USE_PREFIX_USER_TABLE: case USE_PREFIX_USER_TABLE:
dp = &prefix_user_table[dp->bytemode1][prefixes & PREFIX_REPZ ? 1 : 0]; dp = &prefix_user_table[dp->bytemode1][prefixes & PREFIX_REPZ ? 1 : 0];
used_prefixes |= (prefixes & PREFIX_REPZ);
break; break;
default: default:
oappend (INTERNAL_DISASSEMBLER_ERROR); oappend (INTERNAL_DISASSEMBLER_ERROR);
@ -2169,6 +2224,21 @@ print_insn_i386 (pc, info)
(*dp->op3)(dp->bytemode3, sizeflag); (*dp->op3)(dp->bytemode3, sizeflag);
} }
/* See if any prefixes were not used. If so, print the first one
separately. If we don't do this, we'll wind up printing an
instruction stream which does not precisely correspond to the
bytes we are disassembling. */
if ((prefixes & ~used_prefixes) != 0)
{
const char *name;
name = prefix_name (inbuf[0], orig_sizeflag);
if (name == NULL)
name = INTERNAL_DISASSEMBLER_ERROR;
(*info->fprintf_func) (info->stream, "%s", name);
return 1;
}
obufp = obuf + strlen (obuf); obufp = obuf + strlen (obuf);
for (i = strlen (obuf); i < 6; i++) for (i = strlen (obuf); i < 6; i++)
oappend (" "); oappend (" ");
@ -2656,6 +2726,8 @@ putop (template, sizeflag)
case 'N': case 'N':
if ((prefixes & PREFIX_FWAIT) == 0) if ((prefixes & PREFIX_FWAIT) == 0)
*obufp++ = 'n'; *obufp++ = 'n';
else
used_prefixes |= PREFIX_FWAIT;
break; break;
case 'P': case 'P':
if (intel_syntax) if (intel_syntax)
@ -2670,6 +2742,7 @@ putop (template, sizeflag)
*obufp++ = 'l'; *obufp++ = 'l';
else else
*obufp++ = 'w'; *obufp++ = 'w';
used_prefixes |= (prefixes & PREFIX_DATA);
} }
break; break;
case 'Q': case 'Q':
@ -2685,6 +2758,7 @@ putop (template, sizeflag)
*obufp++ = 'l'; *obufp++ = 'l';
else else
*obufp++ = 'w'; *obufp++ = 'w';
used_prefixes |= (prefixes & PREFIX_DATA);
} }
break; break;
case 'R': case 'R':
@ -2708,6 +2782,7 @@ putop (template, sizeflag)
else else
*obufp++ = 'w'; *obufp++ = 'w';
} }
used_prefixes |= (prefixes & PREFIX_DATA);
break; break;
case 'S': case 'S':
if (intel_syntax) if (intel_syntax)
@ -2719,6 +2794,7 @@ putop (template, sizeflag)
*obufp++ = 'l'; *obufp++ = 'l';
else else
*obufp++ = 'w'; *obufp++ = 'w';
used_prefixes |= (prefixes & PREFIX_DATA);
} }
#endif #endif
break; break;
@ -2740,6 +2816,7 @@ putop (template, sizeflag)
*obufp++ = 'w'; *obufp++ = 'w';
} }
} }
used_prefixes |= (prefixes & PREFIX_DATA);
break; break;
} }
} }
@ -2758,17 +2835,35 @@ static void
append_seg () append_seg ()
{ {
if (prefixes & PREFIX_CS) if (prefixes & PREFIX_CS)
oappend ("%cs:"); {
oappend ("%cs:");
used_prefixes |= PREFIX_CS;
}
if (prefixes & PREFIX_DS) if (prefixes & PREFIX_DS)
oappend ("%ds:"); {
oappend ("%ds:");
used_prefixes |= PREFIX_DS;
}
if (prefixes & PREFIX_SS) if (prefixes & PREFIX_SS)
oappend ("%ss:"); {
oappend ("%ss:");
used_prefixes |= PREFIX_SS;
}
if (prefixes & PREFIX_ES) if (prefixes & PREFIX_ES)
oappend ("%es:"); {
oappend ("%es:");
used_prefixes |= PREFIX_ES;
}
if (prefixes & PREFIX_FS) if (prefixes & PREFIX_FS)
oappend ("%fs:"); {
oappend ("%fs:");
used_prefixes |= PREFIX_FS;
}
if (prefixes & PREFIX_GS) if (prefixes & PREFIX_GS)
oappend ("%gs:"); {
oappend ("%gs:");
used_prefixes |= PREFIX_GS;
}
} }
static void static void
@ -2809,6 +2904,7 @@ OP_E (bytemode, sizeflag)
oappend (names32[rm]); oappend (names32[rm]);
else else
oappend (names16[rm]); oappend (names16[rm]);
used_prefixes |= (prefixes & PREFIX_DATA);
break; break;
case 0: case 0:
if ( !(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */)) if ( !(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */))
@ -3031,6 +3127,7 @@ OP_G (bytemode, sizeflag)
oappend (names32[reg]); oappend (names32[reg]);
else else
oappend (names16[reg]); oappend (names16[reg]);
used_prefixes |= (prefixes & PREFIX_DATA);
break; break;
default: default:
oappend (INTERNAL_DISASSEMBLER_ERROR); oappend (INTERNAL_DISASSEMBLER_ERROR);
@ -3100,6 +3197,7 @@ OP_REG (code, sizeflag)
s = names32[code - eAX_reg]; s = names32[code - eAX_reg];
else else
s = names16[code - eAX_reg]; s = names16[code - eAX_reg];
used_prefixes |= (prefixes & PREFIX_DATA);
break; break;
default: default:
s = INTERNAL_DISASSEMBLER_ERROR; s = INTERNAL_DISASSEMBLER_ERROR;
@ -3126,6 +3224,7 @@ OP_I (bytemode, sizeflag)
op = get32 (); op = get32 ();
else else
op = get16 (); op = get16 ();
used_prefixes |= (prefixes & PREFIX_DATA);
break; break;
case w_mode: case w_mode:
op = get16 (); op = get16 ();
@ -3167,6 +3266,7 @@ OP_sI (bytemode, sizeflag)
if ((op & 0x8000) != 0) if ((op & 0x8000) != 0)
op -= 0x10000; op -= 0x10000;
} }
used_prefixes |= (prefixes & PREFIX_DATA);
break; break;
case w_mode: case w_mode:
op = get16 (); op = get16 ();
@ -3211,6 +3311,7 @@ OP_J (bytemode, sizeflag)
displacement is added! */ displacement is added! */
mask = 0xffff; mask = 0xffff;
} }
used_prefixes |= (prefixes & PREFIX_DATA);
break; break;
default: default:
oappend (INTERNAL_DISASSEMBLER_ERROR); oappend (INTERNAL_DISASSEMBLER_ERROR);
@ -3253,6 +3354,7 @@ OP_DIR (dummy, sizeflag)
offset = get16 (); offset = get16 ();
seg = get16 (); seg = get16 ();
} }
used_prefixes |= (prefixes & PREFIX_DATA);
sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset);
oappend (scratchbuf); oappend (scratchbuf);
} }
@ -3549,6 +3651,7 @@ OP_SIMD_Suffix (bytemode, sizeflag)
sprintf (scratchbuf, "cmp%s%cs", sprintf (scratchbuf, "cmp%s%cs",
simd_cmp_op[cmp_type], simd_cmp_op[cmp_type],
prefixes & PREFIX_REPZ ? 's' : 'p'); prefixes & PREFIX_REPZ ? 's' : 'p');
used_prefixes |= (prefixes & PREFIX_REPZ);
oappend (scratchbuf); oappend (scratchbuf);
} }
else else