opcodes: blackfin: fix decoding of many invalid insns
authorMike Frysinger <vapier@gentoo.org>
Wed, 22 Sep 2010 21:53:46 +0000 (21:53 +0000)
committerMike Frysinger <vapier@gentoo.org>
Wed, 22 Sep 2010 21:53:46 +0000 (21:53 +0000)
The Blackfin disassembler was originally based on the premise of parsing
valid opcodes all the time, so some of the opcode checking can be a bit
fuzzy.  This is exemplified in decoding of parallel insns where many
times things are decoded as invalid when in reality, they may not be
used in parallel combinations.  So add parallel checking to most insn
decoding routines so we see ILLEGAL and not just whatever insn happens
to be close to a valid mnemonic, as well as some additional sub-opcode
checks.

Signed-off-by: Robin Getz <robin.getz@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
opcodes/ChangeLog
opcodes/bfin-dis.c

index f11938c3403e76ef63c421825df8dc32ad185645..a142b91a3d3205f107dc2b8806ce2e08ab4f6f0e 100644 (file)
@@ -1,3 +1,25 @@
+2010-09-22  Robin Getz  <robin.getz@analog.com>
+
+       * bfin-dis.c (decode_ProgCtrl_0): Check for parallel insns.
+       Reject P6/P7 to TESTSET.
+       (decode_PushPopReg_0): Check for parallel insns.  Reject pushing
+       SP onto the stack.
+       (decode_PushPopMultiple_0): Check for parallel insns.  Make sure
+       P/D fields match all the time.
+       (decode_CCflag_0): Check for parallel insns.  Verify x/y fields
+       are 0 for accumulator compares.
+       (decode_CC2stat_0): Check for parallel insns.  Reject CC<op>CC.
+       (decode_CaCTRL_0, decode_ccMV_0, decode_CC2dreg_0, decode_BRCC_0,
+       decode_UJUMP_0, decode_LOGI2op_0, decode_COMPI2opD_0,
+       decode_COMPI2opP_0, decode_LoopSetup_0, decode_LDIMMhalf_0,
+       decode_CALLa_0, decode_linkage_0, decode_pseudoDEBUG_0,
+       decode_pseudoOChar_0, decode_pseudodbg_assert_0): Check for parallel
+       insns.
+       (decode_dagMODim_0): Verify br field for IREG ops.
+       (decode_LDST_0): Reject preg load into same preg.
+       (_print_insn_bfin): Handle returns for ILLEGAL decodes.
+       (print_insn_bfin): Likewise.
+
 2010-09-22  Mike Frysinger  <vapier@gentoo.org>
 
        * bfin-dis.c (decode_PushPopMultiple_0): Return 0 when pr > 5.
index 0ce0ecf46f7ea32be49a5d875e5dd894351c00ff..c77a5dad90578523576e01594b966c3ecd21a244 100644 (file)
@@ -760,6 +760,8 @@ decode_ProgCtrl_0 (TIword iw0, disassemble_info *outf)
 
   if (prgfunc == 0 && poprnd == 0)
     OUTS (outf, "NOP");
+  else if (parallel)
+    return 0;
   else if (prgfunc == 1 && poprnd == 0)
     OUTS (outf, "RTS");
   else if (prgfunc == 1 && poprnd == 1)
@@ -822,7 +824,7 @@ decode_ProgCtrl_0 (TIword iw0, disassemble_info *outf)
       OUTS (outf, "EXCPT ");
       OUTS (outf, uimm4 (poprnd));
     }
-  else if (prgfunc == 11 && IS_PREG (1, poprnd))
+  else if (prgfunc == 11 && IS_PREG (1, poprnd) && poprnd <= 5)
     {
       OUTS (outf, "TESTSET (");
       OUTS (outf, pregs (poprnd));
@@ -844,6 +846,9 @@ decode_CaCTRL_0 (TIword iw0, disassemble_info *outf)
   int op  = ((iw0 >> CaCTRL_op_bits) & CaCTRL_op_mask);
   int reg = ((iw0 >> CaCTRL_reg_bits) & CaCTRL_reg_mask);
 
+  if (parallel)
+    return 0;
+
   if (a == 0 && op == 0)
     {
       OUTS (outf, "PREFETCH[");
@@ -908,12 +913,15 @@ decode_PushPopReg_0 (TIword iw0, disassemble_info *outf)
   int grp = ((iw0 >> PushPopReg_grp_bits) & PushPopReg_grp_mask);
   int reg = ((iw0 >> PushPopReg_reg_bits) & PushPopReg_reg_mask);
 
+  if (parallel)
+    return 0;
+
   if (W == 0 && mostreg (reg, grp))
     {
       OUTS (outf, allregs (reg, grp));
       OUTS (outf, " = [SP++]");
     }
-  else if (W == 1 && allreg (reg, grp))
+  else if (W == 1 && allreg (reg, grp) && !(grp == 1 && reg == 6))
     {
       OUTS (outf, "[--SP] = ");
       OUTS (outf, allregs (reg, grp));
@@ -936,6 +944,9 @@ decode_PushPopMultiple_0 (TIword iw0, disassemble_info *outf)
   int dr = ((iw0 >> PushPopMultiple_dr_bits) & PushPopMultiple_dr_mask);
   int pr = ((iw0 >> PushPopMultiple_pr_bits) & PushPopMultiple_pr_mask);
 
+  if (parallel)
+    return 0;
+
   if (pr > 5)
     return 0;
 
@@ -947,13 +958,13 @@ decode_PushPopMultiple_0 (TIword iw0, disassemble_info *outf)
       OUTS (outf, imm5d (pr));
       OUTS (outf, ")");
     }
-  else if (W == 1 && d == 1 && p == 0)
+  else if (W == 1 && d == 1 && p == 0 && pr == 0)
     {
       OUTS (outf, "[--SP] = (R7:");
       OUTS (outf, imm5d (dr));
       OUTS (outf, ")");
     }
-  else if (W == 1 && d == 0 && p == 1)
+  else if (W == 1 && d == 0 && p == 1 && dr == 0)
     {
       OUTS (outf, "[--SP] = (P5:");
       OUTS (outf, imm5d (pr));
@@ -967,13 +978,13 @@ decode_PushPopMultiple_0 (TIword iw0, disassemble_info *outf)
       OUTS (outf, imm5d (pr));
       OUTS (outf, ") = [SP++]");
     }
-  else if (W == 0 && d == 1 && p == 0)
+  else if (W == 0 && d == 1 && p == 0 && pr == 0)
     {
       OUTS (outf, "(R7:");
       OUTS (outf, imm5d (dr));
       OUTS (outf, ") = [SP++]");
     }
-  else if (W == 0 && d == 0 && p == 1)
+  else if (W == 0 && d == 0 && p == 1 && dr == 0)
     {
       OUTS (outf, "(P5:");
       OUTS (outf, imm5d (pr));
@@ -997,6 +1008,9 @@ decode_ccMV_0 (TIword iw0, disassemble_info *outf)
   int src = ((iw0 >> CCmv_src_bits) & CCmv_src_mask);
   int dst = ((iw0 >> CCmv_dst_bits) & CCmv_dst_mask);
 
+  if (parallel)
+    return 0;
+
   if (T == 1)
     {
       OUTS (outf, "IF CC ");
@@ -1029,6 +1043,9 @@ decode_CCflag_0 (TIword iw0, disassemble_info *outf)
   int G = ((iw0 >> CCflag_G_bits) & CCflag_G_mask);
   int opc = ((iw0 >> CCflag_opc_bits) & CCflag_opc_mask);
 
+  if (parallel)
+    return 0;
+
   if (opc == 0 && I == 0 && G == 0)
     {
       OUTS (outf, "CC = ");
@@ -1177,13 +1194,13 @@ decode_CCflag_0 (TIword iw0, disassemble_info *outf)
       OUTS (outf, uimm3 (y));
       OUTS (outf, " (IU)");
     }
-  else if (opc == 5 && I == 0 && G == 0)
+  else if (opc == 5 && I == 0 && G == 0 && x == 0 && y == 0)
     OUTS (outf, "CC = A0 == A1");
 
-  else if (opc == 6 && I == 0 && G == 0)
+  else if (opc == 6 && I == 0 && G == 0 && x == 0 && y == 0)
     OUTS (outf, "CC = A0 < A1");
 
-  else if (opc == 7 && I == 0 && G == 0)
+  else if (opc == 7 && I == 0 && G == 0 && x == 0 && y == 0)
     OUTS (outf, "CC = A0 <= A1");
 
   else
@@ -1201,6 +1218,9 @@ decode_CC2dreg_0 (TIword iw0, disassemble_info *outf)
   int op  = ((iw0 >> CC2dreg_op_bits) & CC2dreg_op_mask);
   int reg = ((iw0 >> CC2dreg_reg_bits) & CC2dreg_reg_mask);
 
+  if (parallel)
+    return 0;
+
   if (op == 0)
     {
       OUTS (outf, dregs (reg));
@@ -1231,6 +1251,10 @@ decode_CC2stat_0 (TIword iw0, disassemble_info *outf)
   int cbit = ((iw0 >> CC2stat_cbit_bits) & CC2stat_cbit_mask);
 
   const char *bitname = statbits (cbit);
+
+  if (parallel)
+    return 0;
+
   if (decode_statbits[cbit] == REG_LASTREG)
     {
       /* All ASTAT bits except CC may be operated on in hardware, but may
@@ -1239,7 +1263,8 @@ decode_CC2stat_0 (TIword iw0, disassemble_info *outf)
       if (cbit != 5)
        sprintf (bitnames, "ASTAT[%i /* unused bit */]", cbit);
       else
-       strcpy (bitnames, "CC /* ... Illegal register ... */");
+       return 0;
+
       bitname = bitnames;
     }
 
@@ -1300,6 +1325,9 @@ decode_BRCC_0 (TIword iw0, bfd_vma pc, disassemble_info *outf)
   int T = ((iw0 >> BRCC_T_bits) & BRCC_T_mask);
   int offset = ((iw0 >> BRCC_offset_bits) & BRCC_offset_mask);
 
+  if (parallel)
+    return 0;
+
   if (T == 1 && B == 1)
     {
       OUTS (outf, "IF CC JUMP 0x");
@@ -1337,6 +1365,9 @@ decode_UJUMP_0 (TIword iw0, bfd_vma pc, disassemble_info *outf)
      +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+  */
   int offset = ((iw0 >> UJump_offset_bits) & UJump_offset_mask);
 
+  if (parallel)
+    return 0;
+
   OUTS (outf, "JUMP.S 0x");
   OUTS (outf, pcrel12 (offset));
   return 2;
@@ -1568,6 +1599,9 @@ decode_LOGI2op_0 (TIword iw0, disassemble_info *outf)
   int opc = ((iw0 >> LOGI2op_opc_bits) & LOGI2op_opc_mask);
   int dst = ((iw0 >> LOGI2op_dst_bits) & LOGI2op_dst_mask);
 
+  if (parallel)
+    return 0;
+
   if (opc == 0)
     {
       OUTS (outf, "CC = !BITTST (");
@@ -1751,6 +1785,9 @@ decode_COMPI2opD_0 (TIword iw0, disassemble_info *outf)
 
   bu32 *pval = get_allreg (0, dst);
 
+  if (parallel)
+    return 0;
+
   /* Since we don't have 32-bit immediate loads, we allow the disassembler
      to combine them, so it prints out the right values.
      Here we keep track of the registers.  */
@@ -1806,6 +1843,9 @@ decode_COMPI2opP_0 (TIword iw0, disassemble_info *outf)
 
   bu32 *pval = get_allreg (1, dst);
 
+  if (parallel)
+    return 0;
+
   if (op == 0)
     {
       *pval = imm7_val (src);
@@ -1989,7 +2029,7 @@ decode_dagMODim_0 (TIword iw0, disassemble_info *outf)
       OUTS (outf, " += ");
       OUTS (outf, mregs (m));
     }
-  else if (op == 1)
+  else if (op == 1 && br == 0)
     {
       OUTS (outf, iregs (i));
       OUTS (outf, " -= ");
@@ -2232,7 +2272,7 @@ decode_LDST_0 (TIword iw0, disassemble_info *outf)
       OUTS (outf, pregs (ptr));
       OUTS (outf, "++]");
     }
-  else if (aop == 0 && sz == 0 && Z == 1 && W == 0)
+  else if (aop == 0 && sz == 0 && Z == 1 && W == 0 && reg != ptr)
     {
       OUTS (outf, pregs (reg));
       OUTS (outf, " = [");
@@ -2274,7 +2314,7 @@ decode_LDST_0 (TIword iw0, disassemble_info *outf)
       OUTS (outf, pregs (ptr));
       OUTS (outf, "--]");
     }
-  else if (aop == 1 && sz == 0 && Z == 1 && W == 0)
+  else if (aop == 1 && sz == 0 && Z == 1 && W == 0 && reg != ptr)
     {
       OUTS (outf, pregs (reg));
       OUTS (outf, " = [");
@@ -2568,6 +2608,9 @@ decode_LoopSetup_0 (TIword iw0, TIword iw1, bfd_vma pc, disassemble_info *outf)
   int soffset = ((iw0 >> (LoopSetup_soffset_bits - 16)) & LoopSetup_soffset_mask);
   int eoffset = ((iw1 >> LoopSetup_eoffset_bits) & LoopSetup_eoffset_mask);
 
+  if (parallel)
+    return 0;
+
   if (rop == 0)
     {
       OUTS (outf, "LSETUP");
@@ -2626,6 +2669,9 @@ decode_LDIMMhalf_0 (TIword iw0, TIword iw1, disassemble_info *outf)
 
   bu32 *pval = get_allreg (grp, reg);
 
+  if (parallel)
+    return 0;
+
   /* Since we don't have 32-bit immediate loads, we allow the disassembler
      to combine them, so it prints out the right values.
      Here we keep track of the registers.  */
@@ -2759,6 +2805,9 @@ decode_CALLa_0 (TIword iw0, TIword iw1, bfd_vma pc, disassemble_info *outf)
   int lsw = ((iw1 >> 0) & 0xffff);
   int msw = ((iw0 >> 0) & 0xff);
 
+  if (parallel)
+    return 0;
+
   if (S == 1)
     OUTS (outf, "CALL 0x");
   else if (S == 0)
@@ -2892,6 +2941,9 @@ decode_linkage_0 (TIword iw0, TIword iw1, disassemble_info *outf)
   int R = ((iw0 >> (Linkage_R_bits - 16)) & Linkage_R_mask);
   int framesize = ((iw1 >> Linkage_framesize_bits) & Linkage_framesize_mask);
 
+  if (parallel)
+    return 0;
+
   if (R == 0)
     {
       OUTS (outf, "LINK ");
@@ -4551,6 +4603,9 @@ decode_pseudoDEBUG_0 (TIword iw0, disassemble_info *outf)
   int grp = ((iw0 >> PseudoDbg_grp_bits) & PseudoDbg_grp_mask);
   int reg = ((iw0 >> PseudoDbg_reg_bits) & PseudoDbg_reg_mask);
 
+  if (parallel)
+    return 0;
+
   if (reg == 0 && fn == 3)
     OUTS (outf, "DBG A0");
 
@@ -4605,6 +4660,9 @@ decode_pseudoOChar_0 (TIword iw0, disassemble_info *outf)
      +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+  */
   int ch = ((iw0 >> PseudoChr_ch_bits) & PseudoChr_ch_mask);
 
+  if (parallel)
+    return 0;
+
   OUTS (outf, "OUTC ");
   OUTS (outf, uimm8 (ch));
 
@@ -4624,6 +4682,9 @@ decode_pseudodbg_assert_0 (TIword iw0, TIword iw1, disassemble_info *outf)
   int grp      = ((iw0 >> (PseudoDbg_Assert_grp_bits - 16)) & PseudoDbg_Assert_grp_mask);
   int regtest  = ((iw0 >> (PseudoDbg_Assert_regtest_bits - 16)) & PseudoDbg_Assert_regtest_mask);
 
+  if (parallel)
+    return 0;
+
   if (dbgop == 0)
     {
       OUTS (outf, "DBGA (");
@@ -4682,6 +4743,11 @@ _print_insn_bfin (bfd_vma pc, disassemble_info *outf)
 
   if ((iw0 & 0xf7ff) == 0xc003 && iw1 == 0x1800)
     {
+      if (parallel)
+       {
+          OUTS (outf, "ILLEGAL");
+          return 0;
+       }
       OUTS (outf, "MNOP");
       return 4;
     }
@@ -4760,6 +4826,9 @@ _print_insn_bfin (bfd_vma pc, disassemble_info *outf)
   else if ((iw0 & 0xFF00) == 0xf000 && (iw1 & 0x0000) == 0x0000)
     rv = decode_pseudodbg_assert_0 (iw0, iw1, outf);
 
+  if (rv == 0)
+    OUTS (outf, "ILLEGAL");
+
   return rv;
 }
 
@@ -4781,24 +4850,39 @@ print_insn_bfin (bfd_vma pc, disassemble_info *outf)
 
   /* Proper display of multiple issue instructions.  */
 
-  if ((iw0 & 0xc000) == 0xc000 && (iw0 & BIT_MULTI_INS)
+  if (count == 4 && (iw0 & 0xc000) == 0xc000 && (iw0 & BIT_MULTI_INS)
       && ((iw0 & 0xe800) != 0xe800 /* Not Linkage.  */ ))
     {
+      int legal = 1;
+      int len;
+
       parallel = 1;
       outf->fprintf_func (outf->stream, " || ");
-      count += _print_insn_bfin (pc + 4, outf);
+      len = _print_insn_bfin (pc + 4, outf);
       outf->fprintf_func (outf->stream, " || ");
-      count += _print_insn_bfin (pc + 6, outf);
+      if (len != 2)
+         legal = 0;
+      len = _print_insn_bfin (pc + 6, outf);
+      if (len != 2)
+       legal = 0;
+
+      if (legal)
+       count = 8;
+      else
+       {
+         outf->fprintf_func (outf->stream, ";\t\t/* ILLEGAL PARALLEL INSTRUCTION */");
+         comment = 1;
+         count = 0;
+       }
       parallel = 0;
     }
-  if (count == 0)
-    {
-      outf->fprintf_func (outf->stream, "ILLEGAL");
-      return 2;
-    }
+
   if (!comment)
     outf->fprintf_func (outf->stream, ";");
 
+  if (count == 0)
+    return 2;
+
   comment = 0;
 
   return count;