X86: Properly handle bad FPU opcode
[deliverable/binutils-gdb.git] / opcodes / i386-dis.c
index fb7574704e8f9cbc9b9bdf56fb03a0a735e22703..ec4a697ff0c1f738642a88daf6d8cd18a9c95cc1 100644 (file)
@@ -706,7 +706,7 @@ enum
 {
   REG_80 = 0,
   REG_81,
-  REG_82,
+  REG_83,
   REG_8F,
   REG_C0,
   REG_C1,
@@ -988,7 +988,6 @@ enum
   PREFIX_MOD_3_0FAE_REG_4,
   PREFIX_0FAE_REG_6,
   PREFIX_0FAE_REG_7,
-  PREFIX_RM_0_0FAE_REG_7,
   PREFIX_0FB8,
   PREFIX_0FBC,
   PREFIX_0FBD,
@@ -1549,6 +1548,8 @@ enum
   PREFIX_EVEX_0F384D,
   PREFIX_EVEX_0F384E,
   PREFIX_EVEX_0F384F,
+  PREFIX_EVEX_0F3852,
+  PREFIX_EVEX_0F3853,
   PREFIX_EVEX_0F3858,
   PREFIX_EVEX_0F3859,
   PREFIX_EVEX_0F385A,
@@ -1693,6 +1694,7 @@ enum
   X86_64_63,
   X86_64_6D,
   X86_64_6F,
+  X86_64_82,
   X86_64_9A,
   X86_64_C4,
   X86_64_C5,
@@ -2661,8 +2663,8 @@ static const struct dis386 dis386[] = {
   /* 80 */
   { REG_TABLE (REG_80) },
   { REG_TABLE (REG_81) },
-  { Bad_Opcode },
-  { REG_TABLE (REG_82) },
+  { X86_64_TABLE (X86_64_82) },
+  { REG_TABLE (REG_83) },
   { "testB",           { Eb, Gb }, 0 },
   { "testS",           { Ev, Gv }, 0 },
   { "xchgB",           { Ebh2, Gb }, 0 },
@@ -3399,7 +3401,7 @@ static const struct dis386 reg_table[][8] = {
     { "xorQ",  { Evh1, Iv }, 0 },
     { "cmpQ",  { Ev, Iv }, 0 },
   },
-  /* REG_82 */
+  /* REG_83 */
   {
     { "addQ",  { Evh1, sIb }, 0 },
     { "orQ",   { Evh1, sIb }, 0 },
@@ -4094,13 +4096,6 @@ static const struct dis386 prefix_table[][4] = {
     { "clflushopt",    { Mb }, 0 },
   },
 
-  /* PREFIX_RM_0_0FAE_REG_7 */
-  {
-    { "sfence",                { Skip_MODRM }, 0 },
-    { Bad_Opcode },
-    { "pcommit",               { Skip_MODRM }, 0 },
-  },
-
   /* PREFIX_0FB8 */
   {
     { Bad_Opcode },
@@ -6893,6 +6888,12 @@ static const struct dis386 x86_64_table[][2] = {
     { "outs{G|}", { indirDXr, Xz }, 0 },
   },
 
+  /* X86_64_82 */
+  {
+    /* Opcode 0x82 is an alias of of opcode 0x80 in 32-bit mode.  */
+    { REG_TABLE (REG_80) },
+  },
+
   /* X86_64_9A */
   {
     { "Jcall{T|}", { Ap }, 0 },
@@ -7591,7 +7592,7 @@ static const struct dis386 three_byte_table[][256] = {
     { Bad_Opcode },
     { Bad_Opcode },
     /* 20 */
-    { "ptest",         { XX }, PREFIX_OPCODE },
+    { Bad_Opcode },
     { Bad_Opcode },
     { Bad_Opcode },
     { Bad_Opcode },
@@ -12484,7 +12485,8 @@ static const struct dis386 rm_table[][8] = {
   },
   {
     /* RM_0FAE_REG_7 */
-    { PREFIX_TABLE (PREFIX_RM_0_0FAE_REG_7) },
+    { "sfence",                { Skip_MODRM }, 0 },
+
   },
 };
 
@@ -13022,17 +13024,20 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info)
        }
       codep++;
       vex.w = *codep & 0x80;
-      if (vex.w && address_mode == mode_64bit)
-       rex |= REX_W;
-
-      vex.register_specifier = (~(*codep >> 3)) & 0xf;
-      if (address_mode != mode_64bit
-         && vex.register_specifier > 0x7)
+      if (address_mode == mode_64bit)
        {
-         dp = &bad_opcode;
-         return dp;
+         if (vex.w)
+           rex |= REX_W;
+         vex.register_specifier = (~(*codep >> 3)) & 0xf;
+       }
+      else
+       {
+         /* For the 3-byte VEX prefix in 32-bit mode, the REX_B bit
+            is ignored, other REX bits are 0 and the highest bit in
+            VEX.vvvv is also ignored.  */
+         rex = 0;
+         vex.register_specifier = (~(*codep >> 3)) & 0x7;
        }
-
       vex.length = (*codep & 0x4) ? 256 : 128;
       switch ((*codep & 0x3))
        {
@@ -13072,16 +13077,10 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info)
       rex_ignored = rex;
       rex = (*codep & 0x80) ? 0 : REX_R;
 
+      /* For the 2-byte VEX prefix in 32-bit mode, the highest bit in
+        VEX.vvvv is 1.  */
       vex.register_specifier = (~(*codep >> 3)) & 0xf;
-      if (address_mode != mode_64bit
-         && vex.register_specifier > 0x7)
-       {
-         dp = &bad_opcode;
-         return dp;
-       }
-
       vex.w = 0;
-
       vex.length = (*codep & 0x4) ? 256 : 128;
       switch ((*codep & 0x3))
        {
@@ -13831,15 +13830,15 @@ static const unsigned char float_mem_mode[] = {
 #define ST { OP_ST, 0 }
 #define STi { OP_STi, 0 }
 
-#define FGRPd9_2 NULL, { { NULL, 0 } }, 0
-#define FGRPd9_4 NULL, { { NULL, 1 } }, 0
-#define FGRPd9_5 NULL, { { NULL, 2 } }, 0
-#define FGRPd9_6 NULL, { { NULL, 3 } }, 0
-#define FGRPd9_7 NULL, { { NULL, 4 } }, 0
-#define FGRPda_5 NULL, { { NULL, 5 } }, 0
-#define FGRPdb_4 NULL, { { NULL, 6 } }, 0
-#define FGRPde_3 NULL, { { NULL, 7 } }, 0
-#define FGRPdf_4 NULL, { { NULL, 8 } }, 0
+#define FGRPd9_2 NULL, { { NULL, 1 } }, 0
+#define FGRPd9_4 NULL, { { NULL, 2 } }, 0
+#define FGRPd9_5 NULL, { { NULL, 3 } }, 0
+#define FGRPd9_6 NULL, { { NULL, 4 } }, 0
+#define FGRPd9_7 NULL, { { NULL, 5 } }, 0
+#define FGRPda_5 NULL, { { NULL, 6 } }, 0
+#define FGRPdb_4 NULL, { { NULL, 7 } }, 0
+#define FGRPde_3 NULL, { { NULL, 8 } }, 0
+#define FGRPdf_4 NULL, { { NULL, 9 } }, 0
 
 static const struct dis386 float_reg[][8] = {
   /* d8 */
@@ -13933,48 +13932,53 @@ static const struct dis386 float_reg[][8] = {
 };
 
 static char *fgrps[][8] = {
-  /* d9_2  0 */
+  /* Bad opcode 0 */
+  {
+    "(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+
+  /* d9_2  1 */
   {
     "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
   },
 
-  /* d9_4  1 */
+  /* d9_4  2 */
   {
     "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)",
   },
 
-  /* d9_5  2 */
+  /* d9_5  3 */
   {
     "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)",
   },
 
-  /* d9_6  3 */
+  /* d9_6  4 */
   {
     "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp",
   },
 
-  /* d9_7  4 */
+  /* d9_7  5 */
   {
     "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos",
   },
 
-  /* da_5  5 */
+  /* da_5  6 */
   {
     "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
   },
 
-  /* db_4  6 */
+  /* db_4  7 */
   {
     "fNeni(8087 only)","fNdisi(8087 only)","fNclex","fNinit",
     "fNsetpm(287 only)","frstpm(287 only)","(bad)","(bad)",
   },
 
-  /* de_3  7 */
+  /* de_3  8 */
   {
     "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
   },
 
-  /* df_4  8 */
+  /* df_4  9 */
   {
     "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
   },
@@ -14095,7 +14099,6 @@ putop (const char *in_template, int sizeflag)
          cond = 0;
          break;
        case '{':
-         alt = 0;
          if (intel_syntax)
            {
              while (*++p != '|')
@@ -14851,13 +14854,14 @@ intel_operand_size (int bytemode, int sizeflag)
          oappend ("QWORD PTR ");
          break;
        }
+      /* Fall through.  */
     case stack_v_mode:
       if (address_mode == mode_64bit && ((sizeflag & DFLAG) || (rex & REX_W)))
        {
          oappend ("QWORD PTR ");
          break;
        }
-      /* FALLTHRU */
+      /* Fall through.  */
     case v_mode:
     case v_swap_mode:
     case dq_mode:
@@ -15234,6 +15238,7 @@ OP_E_register (int bytemode, int sizeflag)
          names = names64;
          break;
        }
+      /* Fall through.  */
     case stack_v_mode:
       if (address_mode == mode_64bit && ((sizeflag & DFLAG) || (rex & REX_W)))
        {
@@ -15241,7 +15246,7 @@ OP_E_register (int bytemode, int sizeflag)
          break;
        }
       bytemode = v_mode;
-      /* FALLTHRU */
+      /* Fall through.  */
     case v_mode:
     case v_swap_mode:
     case dq_mode:
@@ -15265,6 +15270,11 @@ OP_E_register (int bytemode, int sizeflag)
       break;
     case mask_bd_mode:
     case mask_mode:
+      if (reg > 0x7)
+       {
+         oappend ("(bad)");
+         return;
+       }
       names = names_mask;
       break;
     case 0:
@@ -15322,7 +15332,7 @@ OP_E_memory (int bytemode, int sizeflag)
              shift = vex.w ? 3 : 2;
              break;
            }
-         /* Fall through if vex.b == 0.  */
+         /* Fall through.  */
        case xmmqd_mode:
        case xmmdw_mode:
        case ymmq_mode:
@@ -15522,7 +15532,7 @@ OP_E_memory (int bytemode, int sizeflag)
            if (riprel)
              {
                set_op (disp, 1);
-               oappend (sizeflag & AFLAG ? "(%rip)" : "(%eip)");
+               oappend (!addr32flag ? "(%rip)" : "(%eip)");
              }
          }
 
@@ -15537,7 +15547,7 @@ OP_E_memory (int bytemode, int sizeflag)
          if (intel_syntax && riprel)
            {
              set_op (disp, 1);
-             oappend (sizeflag & AFLAG ? "rip" : "eip");
+             oappend (!addr32flag ? "rip" : "eip");
            }
          *obufp = '\0';
          if (havebase)
@@ -15794,6 +15804,11 @@ OP_G (int bytemode, int sizeflag)
       break;
     case mask_bd_mode:
     case mask_mode:
+      if ((modrm.reg + add) > 0x7)
+       {
+         oappend ("(bad)");
+         return;
+       }
       oappend (names_mask[modrm.reg + add]);
       break;
     default:
@@ -17224,6 +17239,11 @@ OP_VEX (int bytemode, int sizeflag ATTRIBUTE_UNUSED)
          break;
        case mask_bd_mode:
        case mask_mode:
+         if (reg > 0x7)
+           {
+             oappend ("(bad)");
+             return;
+           }
          names = names_mask;
          break;
        default:
@@ -17244,6 +17264,11 @@ OP_VEX (int bytemode, int sizeflag ATTRIBUTE_UNUSED)
          break;
        case mask_bd_mode:
        case mask_mode:
+         if (reg > 0x7)
+           {
+             oappend ("(bad)");
+             return;
+           }
          names = names_mask;
          break;
        default:
@@ -17302,6 +17327,7 @@ get_vex_imm8 (int sizeflag, int opnum)
                    if (base != 5)
                      /* No displacement. */
                      break;
+                   /* Fall through.  */
                  case 2:
                    /* 4 byte displacement.  */
                    bytes_before_imm += 4;
@@ -17328,6 +17354,7 @@ get_vex_imm8 (int sizeflag, int opnum)
                  if (modrm.rm != 6)
                    /* No displacement. */
                    break;
+                 /* Fall through.  */
                case 2:
                  /* 2 byte displacement.  */
                  bytes_before_imm += 2;
This page took 0.034507 seconds and 4 git commands to generate.