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