Rework last checkin to the following:
authorIan Lance Taylor <ian@airs.com>
Sun, 13 Jun 1999 17:04:42 +0000 (17:04 +0000)
committerIan Lance Taylor <ian@airs.com>
Sun, 13 Jun 1999 17:04:42 +0000 (17:04 +0000)
* 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

index b534698a83aa0b2b3f4545ae68bb70c0781bdaa8..0dcbc62dfa41ffe1cc6bb1c25914f215f8d1def4 100644 (file)
@@ -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)
+         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)
        {
-         unsigned char *p;
-
-         p = memchr (inbuf, FWAIT_OPCODE, codep - inbuf);
-         if (p != NULL)
+         name = prefix_name (inbuf[0], orig_sizeflag);
+         if (name != NULL)
+           (*info->fprintf_func) (info->stream, "%s", name);
+         else
            {
-             (*info->fprintf_func) (info->stream, "fwait");
-             return (p + 1) - inbuf;
+             /* Just print the first byte as a .byte instruction.  */
+             (*info->fprintf_func) (info->stream, ".byte 0x%x",
+                                    (unsigned int) inbuf[0]);
            }
-       }
 
-      if (codep > inbuf)
-       {
-         /* This will at least let objdump print the bytes followed
-             by the error message generated by fetch_data.  */
-         return codep - inbuf;
+         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