diff mbox

Record and replay: ARM thumb 32bit instructions support

Message ID CANW4E-0ErD9CWAOjnvQhn2yaQZpAaDh_quMi0R6VDbM8p8uLtg@mail.gmail.com
State Superseded
Headers show

Commit Message

Omair Javaid Sept. 18, 2013, 3:37 p.m. UTC
This patch improves gdb record and replay support for arm targets by
adding support for 32bit thumb instruction set. Record and replay test
suite is disabled for arm targets by default as some instructions and
system calls are still not functional. This patch can be tested by
recording a simple thumb mode C program on arm targets. It will not
work with any programs requiring syscall support or any program that
uses instruction not yet decoded by arm process record code. More
improvements including test suite improvement will be posted in future
patches.

gdb/testsuite/ChangeLog:

2013-09-18  Omair Javaid  <Omair.Javaid@linaro.org>

        * arm-tdep.c: Adds support for thumb32 instructions in
          arm record and replay

 and positive val on fauilure.  */
@@ -12469,6 +13172,28 @@ decode_insn (insn_decode_record *arm_rec
     thumb_record_branch                /* 111.  */
   };

+  /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
+     instruction.  */
+  static const sti_arm_hdl_fp_t const thumb2_handle_insn[16] =
+  { \
+    thumb2_record_ld_st_mulitple,       /* 00. */
+    thumb2_record_ld_st_dual_ex_tbb,    /* 01. */
+    thumb2_record_data_proc_sreg,       /* 02. */
+    thumb2_record_coproc,               /* 03. */
+    thumb2_record_data_proc_mod_imm,    /* 04. */
+    thumb2_record_data_proc_bin_imm,    /* 05. */
+    thumb2_record_branch_misc_cntrl,    /* 06. */
+    thumb2_record_str_single_data,      /* 07. */
+    thumb2_record_simd_struct_ld_st,    /* 08. */
+    thumb2_record_ld_mem_hints,         /* 09. */
+    thumb2_record_ld_mem_hints,         /* 10. */
+    thumb2_record_ld_word,              /* 11. */
+    thumb2_record_data_proc_reg,        /* 12. */
+    thumb2_record_mul_mla_abs_diff,     /* 13. */
+    thumb2_record_lmul_lmla_div,        /* 14. */
+    thumb2_record_coproc                /* 15. */
+  };
+
   uint32_t ret = 0;    /* return value: negative:failure   0:success.  */
   uint32_t insn_id = 0;

@@ -12503,11 +13228,22 @@ decode_insn (insn_decode_record *arm_rec
     }
   else if (THUMB2_RECORD == record_type)
     {
-      printf_unfiltered (_("Process record doesnt support thumb32 instruction "
-                           "0x%0x at address %s.\n"),arm_record->arm_insn,
-                           paddress (arm_record->gdbarch,
-                           arm_record->this_addr));
-      ret = -1;
+      /* As thumb does not have condition codes, we set negative.  */
+      arm_record->cond = -1;
+      insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn);
+
+      if (insn_id > 0)
+        {
+          ret = thumb_handle_insn[insn_id] (arm_record);
+        }
+      else
+        {
+          printf_unfiltered (_("Process record doesnt support instruction "
+                            "0x%0x at address %s.\n"),arm_record->arm_insn,
+                            paddress (arm_record->gdbarch,
+                            arm_record->this_addr));
+          ret = -1;
+        }
     }
   else
     {

Comments

Omair Javaid Oct. 1, 2013, 9:56 a.m. UTC | #1
On 18 September 2013 20:37, Omair Javaid <omair.javaid@linaro.org> wrote:
> This patch improves gdb record and replay support for arm targets by
> adding support for 32bit thumb instruction set. Record and replay test
> suite is disabled for arm targets by default as some instructions and
> system calls are still not functional. This patch can be tested by
> recording a simple thumb mode C program on arm targets. It will not
> work with any programs requiring syscall support or any program that
> uses instruction not yet decoded by arm process record code. More
> improvements including test suite improvement will be posted in future
> patches.
>
> gdb/testsuite/ChangeLog:
>
> 2013-09-18  Omair Javaid  <Omair.Javaid@linaro.org>
>
>         * arm-tdep.c: Adds support for thumb32 instructions in
>           arm record and replay
>
> ===================================================================
> RCS file: /cvs/src/src/gdb/arm-tdep.c,v
> retrieving revision 1.381
> diff -u -p -r1.381 arm-tdep.c
> --- gdb/arm-tdep.c 24 Jun 2013 22:18:31 -0000 1.381
> +++ gdb/arm-tdep.c 18 Sep 2013 12:13:34 -0000
> @@ -12414,6 +12414,709 @@ thumb_record_branch (insn_decode_record
>    return 0;
>  }
>
> +/* Handler for thumb2 load/store multiple instructions.  */
> +
> +static int
> +thumb2_record_ld_st_mulitple (insn_decode_record *thumb2_insn_r)
> +{
> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
> +
> +  uint32_t reg_rn = 0;
> +  uint32_t op = 0, register_bits = 0, register_count = 0;
> +  uint32_t index = 0, start_address = 0;
> +  uint32_t record_buf[24], record_buf_mem[48];
> +
> +  ULONGEST u_regval = 0;
> +
> +  op = bits (thumb2_insn_r->arm_insn, 23, 24);
> +
> +  if (0 == op || 3 == op)
> +    {
> +      if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
> +        {
> +          /* Handle RFE instruction.  */
> +          record_buf[0] = ARM_PS_REGNUM;
> +          thumb2_insn_r->reg_rec_count = 1;
> +        }
> +      else
> +        {
> +          /* Handle SRS instruction after reading banked SP.  */
> +          printf_unfiltered (_("Process record does not support instruction "
> +                            "0x%0x at address %s.\n"),
> +                            thumb2_insn_r->arm_insn,
> +                            paddress (thumb2_insn_r->gdbarch,
> +                            thumb2_insn_r->this_addr));
> +          return -1;
> +        }
> +    }
> +  else if(1 == op || 2 == op)
> +    {
> +      if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
> +        {
> +          /* Handle LDM/LDMIA/LDMFD and LDMDB/LDMEA instructions.  */
> +          register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
> +          while (register_bits)
> +            {
> +              if (register_bits & 0x00000001)
> +                {
> +                  record_buf[index++] = register_count;
> +                }
> +              register_count++;
> +              register_bits = register_bits >> 1;
> +            }
> +          record_buf[index++] = reg_rn;
> +          record_buf[index++] = ARM_PS_REGNUM;
> +          thumb2_insn_r->reg_rec_count = index;
> +        }
> +      else
> +        {
> +          /* Handle STM/STMIA/STMEA and STMDB/STMFD.  */
> +          register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
> +          regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
> +          while (register_bits)
> +            {
> +              if (register_bits & 0x00000001)
> +                {
> +                  register_count++;
> +                }
> +              register_bits = register_bits >> 1;
> +            }
> +
> +          if (1 == op)
> +            {
> +              /* Start address calculation for LDMDB/LDMEA.  */
> +              start_address = u_regval;
> +            }
> +          else if (2 == op)
> +            {
> +              /* Start address calculation for LDMDB/LDMEA.  */
> +              start_address = (u_regval) - (register_count * 4);
> +            }
> +
> +          thumb2_insn_r->mem_rec_count = register_count;
> +          while (register_count)
> +            {
> +              record_buf_mem[(register_count * 2) - 1] = start_address;
> +              record_buf_mem[(register_count * 2) - 2] = 4;
> +              start_address = start_address + 4;
> +              register_count--;
> +            }
> +          record_buf[0] = reg_rn;
> +          record_buf[1] = ARM_PS_REGNUM;
> +          thumb2_insn_r->reg_rec_count = 2;
> +        }
> +    }
> +
> +  MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
> +            record_buf_mem);
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +  return 0;
> +}
> +
> +/* Handler for thumb2 ld/st dual, ld/st exclusive, table branch
> +   instructions.  */
> +
> +static int
> +thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
> +{
> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
> +
> +  uint32_t reg_rd = 0, reg_rn = 0, offset_imm = 0;
> +  uint32_t reg_dest1 = 0, reg_dest2 = 0;
> +  uint32_t address = 0, offset_addr = 0;
> +  uint32_t record_buf[8], record_buf_mem[8];
> +  uint32_t op1 = 0, op2 = 0, op3 = 0;
> +  LONGEST s_word;
> +
> +  ULONGEST u_regval[2];
> +
> +  op1 = bits (thumb2_insn_r->arm_insn, 23, 24);
> +  op2 = bits (thumb2_insn_r->arm_insn, 20, 21);
> +  op3 = bits (thumb2_insn_r->arm_insn, 4, 7);
> +
> +  if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
> +    {
> +      if(!(1 == op1 && 1 == op2 && (0 == op3 || 1 == op3)))
> +        {
> +          reg_dest1 = bits (thumb2_insn_r->arm_insn, 12, 15);
> +          record_buf[0] = reg_dest1;
> +          record_buf[1] = ARM_PS_REGNUM;
> +          thumb2_insn_r->reg_rec_count = 2;
> +        }
> +
> +      if (3 == op2 || (op1 & 2) || (1 == op1 && 1 == op2 && 7 == op3))
> +        {
> +          reg_dest2 = bits (thumb2_insn_r->arm_insn, 8, 11);
> +          record_buf[2] = reg_dest2;
> +          thumb2_insn_r->reg_rec_count = 3;
> +        }
> +    }
> +  else
> +    {
> +      reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
> +      regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
> +
> +      if (0 == op1 && 0 == op2)
> +        {
> +          /* Handle STREX.  */
> +          offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
> +          address = u_regval[0] + (offset_imm * 4);
> +          record_buf_mem[0] = 4;
> +          record_buf_mem[1] = address;
> +          thumb2_insn_r->mem_rec_count = 1;
> +          reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
> +          record_buf[0] = reg_rd;
> +          thumb2_insn_r->reg_rec_count = 1;
> +        }
> +      else if (1 == op1 && 0 == op2)
> +        {
> +          reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
> +          record_buf[0] = reg_rd;
> +          thumb2_insn_r->reg_rec_count = 1;
> +          address = u_regval[0];
> +          record_buf_mem[1] = address;
> +
> +          if (4 == op3)
> +            {
> +              /* Handle STREXB.  */
> +              record_buf_mem[0] = 1;
> +              thumb2_insn_r->mem_rec_count = 1;
> +            }
> +          else if (5 == op3)
> +            {
> +              /* Handle STREXH.  */
> +              record_buf_mem[0] = 2 ;
> +              thumb2_insn_r->mem_rec_count = 1;
> +            }
> +          else if (7 == op3)
> +            {
> +              /* Handle STREXD */
> +              address = u_regval[0];
> +              record_buf_mem[0] = 4;
> +              record_buf_mem[2] = 4;
> +              record_buf_mem[3] = address + 4;
> +              thumb2_insn_r->mem_rec_count = 2;
> +            }
> +        }
> +      else
> +        {
> +          offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
> +
> +          if (bit (thumb2_insn_r->arm_insn, 24))
> +            {
> +              if (bit (thumb2_insn_r->arm_insn, 23))
> +                {
> +                  offset_addr = u_regval[0] + (offset_imm * 4);
> +                }
> +              else
> +                {
> +                  offset_addr = u_regval[0] - (offset_imm * 4);
> +                }
> +              address = offset_addr;
> +            }
> +          else
> +            {
> +              address = u_regval[0];
> +            }
> +
> +          record_buf_mem[0] = 4;
> +          record_buf_mem[1] = address;
> +          record_buf_mem[2] = 4;
> +          record_buf_mem[3] = address + 4;
> +          thumb2_insn_r->mem_rec_count = 2;
> +          record_buf[0] = reg_rn;
> +          thumb2_insn_r->reg_rec_count = 1;
> +        }
> +    }
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +  MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
> +            record_buf_mem);
> +  return 0;
> +}
> +
> +/* Handler for thumb2 data-processing shifted register instructions.  */
> +
> +static int
> +thumb2_record_data_proc_sreg (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
> +  uint32_t reg_rd = 0;
> +  uint32_t op = 0;
> +  uint32_t record_buf[8];
> +
> +  op = bits (thumb2_insn_r->arm_insn, 8, 11);
> +  reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
> +
> +  if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
> +    {
> +      record_buf[0] = ARM_PS_REGNUM;
> +      thumb2_insn_r->reg_rec_count = 1;
> +    }
> +  else
> +    {
> +      record_buf[0] = reg_rd;
> +      record_buf[1] = ARM_PS_REGNUM;
> +      thumb2_insn_r->reg_rec_count = 2;
> +    }
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +
> +  return ret;
> +}
> +
> +/* Handler for thumb2 co-processor instructions.  */
> +
> +static int
> +thumb2_record_coproc (insn_decode_record *thumb2_insn_r)
> +{
> +  printf_unfiltered (_("Process record does not support instruction "
> +                    "0x%0x at address %s.\n"),thumb2_insn_r->arm_insn,
> +                    paddress (thumb2_insn_r->gdbarch,
> +                    thumb2_insn_r->this_addr));
> +
> +  return -1;
> +}
> +
> +/* Handler for thumb2 data-processing (modified immediate) instructions.  */
> +
> +static int
> +thumb2_record_data_proc_mod_imm (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0 ;  /* Return value: -1:record failure ;  0:success.   */
> +  uint32_t reg_rd = 0;
> +  uint32_t op = 0;
> +  uint32_t record_buf[8];
> +
> +  op = bits (thumb2_insn_r->arm_insn, 8, 11);
> +  reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
> +
> +  if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
> +    {
> +      record_buf[0] = ARM_PS_REGNUM;
> +      thumb2_insn_r->reg_rec_count = 1;
> +    }
> +  else
> +    {
> +      record_buf[0] = reg_rd;
> +      record_buf[1] = ARM_PS_REGNUM;
> +      thumb2_insn_r->reg_rec_count = 2;
> +    }
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +
> +  return ret;
> +}
> +
> +/* Handler for thumb2 data-processing plain binary immediate instructions.  */
> +
> +static int
> +thumb2_record_data_proc_bin_imm (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
> +  uint32_t reg_rd = 0;
> +  uint32_t record_buf[8];
> +
> +  reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
> +
> +  record_buf[0] = reg_rd;
> +  record_buf[1] = ARM_PS_REGNUM;
> +  thumb2_insn_r->reg_rec_count = 2;
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +
> +  return ret;
> +}
> +
> +/* Handler for thumb2 branch and miscellaneous control instructions.  */
> +
> +static int
> +thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t op = 0, op1 = 0, op2 = 0;
> +  uint32_t record_buf[8];
> +
> +  op = bits (thumb2_insn_r->arm_insn, 20, 26);
> +  op1 = bits (thumb2_insn_r->arm_insn, 12, 14);
> +  op2 = bits (thumb2_insn_r->arm_insn, 8, 11);
> +
> +  /* Handle MSR insn.  */
> +  if (!(op1 & 0x2) && 0x38 == op)
> +    {
> +      if (!(op2 & 0x3))
> +        {
> +          /* CPSR is going to be changed.  */
> +          record_buf[0] = ARM_PS_REGNUM;
> +          thumb2_insn_r->reg_rec_count = 1;
> +        }
> +      else
> +        {
> +          /* SPSR is going to be changed.  */
> +          printf_unfiltered (_("Process record does not support instruction "
> +                            "0x%0x at address %s.\n"),
> +                            thumb2_insn_r->arm_insn,
> +                            paddress (thumb2_insn_r->gdbarch,
> +                            thumb2_insn_r->this_addr));
> +          return -1;
> +        }
> +    }
> +  else if (4 == (op1 & 0x5) || 5 == (op1 & 0x5))
> +    {
> +      /* BLX.  */
> +      record_buf[0] = ARM_PS_REGNUM;
> +      record_buf[1] = ARM_LR_REGNUM;
> +      thumb2_insn_r->reg_rec_count = 2;
> +    }
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +
> +  return 0;
> +}
> +
> +/* Handler for thumb2 store single data item instructions.  */
> +
> +static int
> +thumb2_record_str_single_data (insn_decode_record *thumb2_insn_r)
> +{
> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
> +
> +  uint32_t reg_rn = 0, reg_rm = 0, offset_imm = 0, shift_imm = 0;
> +  uint32_t address = 0, offset_addr = 0;
> +  uint32_t record_buf[8], record_buf_mem[8];
> +  uint32_t op1 = 0, op2 = 0;
> +
> +  ULONGEST u_regval[2];
> +
> +  op1 = bits (thumb2_insn_r->arm_insn, 21, 23);
> +  op2 = bits (thumb2_insn_r->arm_insn, 6, 11);
> +  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
> +  regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
> +
> +  if (bit (thumb2_insn_r->arm_insn, 23))
> +    {
> +      /* T2 encoding.  */
> +      offset_imm = bits (thumb2_insn_r->arm_insn, 0, 11);
> +      offset_addr = u_regval[0] + offset_imm;
> +      address = offset_addr;
> +    }
> +  else
> +    {
> +      /* T3 encoding.  */
> +      if ((0 == op1 || 1 == op1 || 2 == op1) && !(op2 & 0x20))
> +        {
> +          /* Handle STRB (register).  */
> +          reg_rm = bits (thumb2_insn_r->arm_insn, 0, 3);
> +          regcache_raw_read_unsigned (reg_cache, reg_rm, &u_regval[1]);
> +          shift_imm = bits (thumb2_insn_r->arm_insn, 4, 5);
> +          offset_addr = u_regval[1] << shift_imm;
> +          address = u_regval[0] + offset_addr;
> +        }
> +      else
> +        {
> +          offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
> +          if (bit (thumb2_insn_r->arm_insn, 10))
> +            {
> +              if (bit (thumb2_insn_r->arm_insn, 9))
> +                {
> +                  offset_addr = u_regval[0] + offset_imm;
> +                }
> +              else
> +                {
> +                  offset_addr = u_regval[0] - offset_imm;
> +                }
> +              address = offset_addr;
> +            }
> +          else
> +            {
> +              address = u_regval[0];
> +            }
> +        }
> +    }
> +
> +  switch (op1)
> +    {
> +      /* Store byte instructions.  */
> +      case 4:
> +      case 0:
> +        record_buf_mem[0] = 1;
> +      break;
> +      /* Store half word instructions.  */
> +      case 1:
> +      case 5:
> +        record_buf_mem[0] = 2;
> +      break;
> +      /* Store word instructions.  */
> +      case 2:
> +      case 6:
> +        record_buf_mem[0] = 4;
> +      break;
> +
> +      default:
> +        gdb_assert_not_reached ("no decoding pattern found");
> +      break;
> +    }
> +
> +  record_buf_mem[1] = address;
> +  thumb2_insn_r->mem_rec_count = 1;
> +  record_buf[0] = reg_rn;
> +  thumb2_insn_r->reg_rec_count = 1;
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +  MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
> +            record_buf_mem);
> +  return 0;
> +}
> +
> +/* Handler for thumb2 SIMD element and structure load/store instructions.  */
> +
> +static int
> +thumb2_record_simd_struct_ld_st (insn_decode_record *thumb2_insn_r)
> +{
> +  printf_unfiltered (_("Process record does not support instruction "
> +                    "0x%0x at address %s.\n"), thumb2_insn_r->arm_insn,
> +                    paddress (thumb2_insn_r->gdbarch,
> +                    thumb2_insn_r->this_addr));
> +  return -1;
> +}
> +
> +/* Handler for thumb2 load memory hints instructions.  */
> +
> +static int
> +thumb2_record_ld_mem_hints (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t record_buf[8];
> +  uint32_t reg_rt = 0, reg_rn=0;
> +
> +  reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
> +  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
> +
> +  if (15 != reg_rt)
> +    {
> +      record_buf[0] = reg_rt;
> +      record_buf[1] = reg_rn;
> +      record_buf[2] = ARM_PS_REGNUM;
> +      thumb2_insn_r->reg_rec_count = 3;
> +
> +      REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +                record_buf);
> +      return 0;
> +    }
> +
> +  return -1;
> +}
> +
> +/* Handler for thumb2 load word instructions.  */
> +
> +static int
> +thumb2_record_ld_word (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
> +  uint32_t opcode1 = 0, opcode2 = 0;
> +  uint32_t record_buf[8];
> +
> +  record_buf[0] = bits (thumb2_insn_r->arm_insn, 12, 15);
> +  record_buf[1] = ARM_PS_REGNUM;
> +  thumb2_insn_r->reg_rec_count = 2;
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +
> +  return ret;
> +}
> +
> +/* Handler for thumb2 data processing (register) instructions.  */
> +
> +static int
> +thumb2_record_data_proc_reg (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
> +  uint32_t opcode1 = 0, opcode2 = 0;
> +  uint32_t record_buf[8];
> +
> +  record_buf[0] = bits (thumb2_insn_r->arm_insn, 8, 11);
> +  record_buf[1] = ARM_PS_REGNUM;
> +  thumb2_insn_r->reg_rec_count = 2;
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +
> +  return ret;
> +}
> +
> +/* Handler for thumb2 multiply, multiply accumulate, and
> +   absolute difference instructions.  */
> +
> +static int
> +thumb2_record_mul_mla_abs_diff (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
> +  uint32_t opcode1 = 0, opcode2 = 0;
> +  uint32_t record_buf[8];
> +
> +  record_buf[0] = bits (thumb2_insn_r->arm_insn, 8, 11);
> +  record_buf[1] = ARM_PS_REGNUM;
> +  thumb2_insn_r->reg_rec_count = 2;
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +
> +  return ret;
> +}
> +
> +/* Handler for thumb2 long multiply, long multiply accumulate, and
> +   divide instructions.  */
> +
> +static int
> +thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
> +  uint32_t opcode1 = 0, opcode2 = 0;
> +  uint32_t record_buf[8];
> +  uint32_t reg_src1 = 0;
> +
> +  opcode1 = bits (thumb2_insn_r->arm_insn, 20, 22);
> +  opcode2 = bits (thumb2_insn_r->arm_insn, 4, 7);
> +
> +  if (0 == opcode1 || 2 == opcode1 || (opcode1 >= 4 && opcode1 <= 6))
> +    {
> +      /* Handle SMULL, UMULL, SMULAL and
> +         SMLAL(S), SMULL(S), UMLAL(S), UMULL(S).  */
> +      record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
> +      record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
> +      record_buf[2] = ARM_PS_REGNUM;
> +      thumb2_insn_r->reg_rec_count = 3;
> +    }
> +  else if (1 == opcode1 || 3 == opcode2)
> +    {
> +      /* Handle SDIV and UDIV.  */
> +      record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
> +      record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
> +      record_buf[2] = ARM_PS_REGNUM;
> +      thumb2_insn_r->reg_rec_count = 3;
> +    }
> +  else
> +    {
> +      ret = -1;
> +    }
> +
> +  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
> +            record_buf);
> +
> +  return ret;
> +}
> +
> +/* Decodes thumb2 instruction type and return an instruction id.  */
> +
> +static unsigned int
> +thumb2_record_decode_inst_id (uint32_t thumb2_insn)
> +{
> +  uint32_t op = 0;
> +  uint32_t op1 = 0;
> +  uint32_t op2 = 0;
> +
> +  op = bit (thumb2_insn, 15);
> +  op1 = bits (thumb2_insn, 27, 28);
> +  op2 = bits (thumb2_insn, 20, 26);
> +
> +  if (op1 == 0x01)
> +    {
> +      if (!(op2 & 0x64 ))
> +        {
> +          /* Load/store multiple instruction.  */
> +          return 0;
> +        }
> +      else if (!((op2 & 0x64) ^ 0x04))
> +        {
> +          /* Load/store dual/exclusive and table branch instructions.  */
> +          return 1;
> +        }
> +      else if (!((op2 & 0x20) ^ 0x20))
> +        {
> +          /* Data-processing (shifted register).  */
> +          return 2;
> +        }
> +      else if (op2 & 0x40)
> +        {
> +          /* Co-processor instructions.  */
> +          return 3;
> +        }
> +    }
> +  else if (op1 == 0x02)
> +    {
> +      if (op)
> +        {
> +          /* Branches and miscellaneous control instructions.  */
> +          return 6;
> +        }
> +      else if (op2 & 0x20)
> +        {
> +          /* Data-processing (plain binary immediate) instruction.  */
> +          return 5;
> +        }
> +      else
> +        {
> +          /* Data-processing (modified immediate).  */
> +          return 4;
> +        }
> +    }
> +  else if (op1 == 0x03)
> +   {
> +      if (!(op2 & 0x71 ))
> +        {
> +      /* Store single data item.  */
> +          return 7;
> +        }
> +      else if (!((op2 & 0x71) ^ 0x10))
> +        {
> +          /* Advanced SIMD element or structure load/store instructions.  */
> +          return 8;
> +        }
> +      else if (!((op2 & 0x67) ^ 0x01))
> +        {
> +          /* Load byte, memory hints instruction.  */
> +          return 9;
> +        }
> +      else if (!((op2 & 0x67) ^ 0x03))
> +        {
> +      /* Load halfword, memory hints instruction.  */
> +          return 10;
> +        }
> +      else if (!((op2 & 0x67) ^ 0x05))
> +        {
> +      /* Load word instruction.  */
> +          return 11;
> +        }
> +      else if (!((op2 & 0x70) ^ 0x20))
> +        {
> +      /* Data-processing (register) instruction.  */
> +          return 12;
> +        }
> +      else if (!((op2 & 0x78) ^ 0x30))
> +        {
> +      /* Multiply, multiply accumulate, absolute difference instruction.  */
> +          return 13;
> +        }
> +      else if (!((op2 & 0x78) ^ 0x38))
> +        {
> +          /* Long multiply, long multiply accumulate, and divide.  */
> +          return 14;
> +        }
> +      else if (op2 & 0x40)
> +        {
> +          /* Co-processor instructions.  */
> +          return 15;
> +        }
> +   }
> +
> +  return -1;
> +}
>
>  /* Extracts arm/thumb/thumb2 insn depending on the size, and returns
> 0 on success
>  and positive val on fauilure.  */
> @@ -12469,6 +13172,28 @@ decode_insn (insn_decode_record *arm_rec
>      thumb_record_branch                /* 111.  */
>    };
>
> +  /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
> +     instruction.  */
> +  static const sti_arm_hdl_fp_t const thumb2_handle_insn[16] =
> +  { \
> +    thumb2_record_ld_st_mulitple,       /* 00. */
> +    thumb2_record_ld_st_dual_ex_tbb,    /* 01. */
> +    thumb2_record_data_proc_sreg,       /* 02. */
> +    thumb2_record_coproc,               /* 03. */
> +    thumb2_record_data_proc_mod_imm,    /* 04. */
> +    thumb2_record_data_proc_bin_imm,    /* 05. */
> +    thumb2_record_branch_misc_cntrl,    /* 06. */
> +    thumb2_record_str_single_data,      /* 07. */
> +    thumb2_record_simd_struct_ld_st,    /* 08. */
> +    thumb2_record_ld_mem_hints,         /* 09. */
> +    thumb2_record_ld_mem_hints,         /* 10. */
> +    thumb2_record_ld_word,              /* 11. */
> +    thumb2_record_data_proc_reg,        /* 12. */
> +    thumb2_record_mul_mla_abs_diff,     /* 13. */
> +    thumb2_record_lmul_lmla_div,        /* 14. */
> +    thumb2_record_coproc                /* 15. */
> +  };
> +
>    uint32_t ret = 0;    /* return value: negative:failure   0:success.  */
>    uint32_t insn_id = 0;
>
> @@ -12503,11 +13228,22 @@ decode_insn (insn_decode_record *arm_rec
>      }
>    else if (THUMB2_RECORD == record_type)
>      {
> -      printf_unfiltered (_("Process record doesnt support thumb32 instruction "
> -                           "0x%0x at address %s.\n"),arm_record->arm_insn,
> -                           paddress (arm_record->gdbarch,
> -                           arm_record->this_addr));
> -      ret = -1;
> +      /* As thumb does not have condition codes, we set negative.  */
> +      arm_record->cond = -1;
> +      insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn);
> +
> +      if (insn_id > 0)
> +        {
> +          ret = thumb_handle_insn[insn_id] (arm_record);
> +        }
> +      else
> +        {
> +          printf_unfiltered (_("Process record doesnt support instruction "
> +                            "0x%0x at address %s.\n"),arm_record->arm_insn,
> +                            paddress (arm_record->gdbarch,
> +                            arm_record->this_addr));
> +          ret = -1;
> +        }
>      }
>    else
>      {

There is an update to this patch and a bunch of testsuite results
indicating a good number of test cases passing. I ll be posting them
soon.
diff mbox

Patch

===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.381
diff -u -p -r1.381 arm-tdep.c
--- gdb/arm-tdep.c 24 Jun 2013 22:18:31 -0000 1.381
+++ gdb/arm-tdep.c 18 Sep 2013 12:13:34 -0000
@@ -12414,6 +12414,709 @@  thumb_record_branch (insn_decode_record
   return 0;
 }

+/* Handler for thumb2 load/store multiple instructions.  */
+
+static int
+thumb2_record_ld_st_mulitple (insn_decode_record *thumb2_insn_r)
+{
+  struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+  uint32_t reg_rn = 0;
+  uint32_t op = 0, register_bits = 0, register_count = 0;
+  uint32_t index = 0, start_address = 0;
+  uint32_t record_buf[24], record_buf_mem[48];
+
+  ULONGEST u_regval = 0;
+
+  op = bits (thumb2_insn_r->arm_insn, 23, 24);
+
+  if (0 == op || 3 == op)
+    {
+      if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+        {
+          /* Handle RFE instruction.  */
+          record_buf[0] = ARM_PS_REGNUM;
+          thumb2_insn_r->reg_rec_count = 1;
+        }
+      else
+        {
+          /* Handle SRS instruction after reading banked SP.  */
+          printf_unfiltered (_("Process record does not support instruction "
+                            "0x%0x at address %s.\n"),
+                            thumb2_insn_r->arm_insn,
+                            paddress (thumb2_insn_r->gdbarch,
+                            thumb2_insn_r->this_addr));
+          return -1;
+        }
+    }
+  else if(1 == op || 2 == op)
+    {
+      if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+        {
+          /* Handle LDM/LDMIA/LDMFD and LDMDB/LDMEA instructions.  */
+          register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
+          while (register_bits)
+            {
+              if (register_bits & 0x00000001)
+                {
+                  record_buf[index++] = register_count;
+                }
+              register_count++;
+              register_bits = register_bits >> 1;
+            }
+          record_buf[index++] = reg_rn;
+          record_buf[index++] = ARM_PS_REGNUM;
+          thumb2_insn_r->reg_rec_count = index;
+        }
+      else
+        {
+          /* Handle STM/STMIA/STMEA and STMDB/STMFD.  */
+          register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
+          regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
+          while (register_bits)
+            {
+              if (register_bits & 0x00000001)
+                {
+                  register_count++;
+                }
+              register_bits = register_bits >> 1;
+            }
+
+          if (1 == op)
+            {
+              /* Start address calculation for LDMDB/LDMEA.  */
+              start_address = u_regval;
+            }
+          else if (2 == op)
+            {
+              /* Start address calculation for LDMDB/LDMEA.  */
+              start_address = (u_regval) - (register_count * 4);
+            }
+
+          thumb2_insn_r->mem_rec_count = register_count;
+          while (register_count)
+            {
+              record_buf_mem[(register_count * 2) - 1] = start_address;
+              record_buf_mem[(register_count * 2) - 2] = 4;
+              start_address = start_address + 4;
+              register_count--;
+            }
+          record_buf[0] = reg_rn;
+          record_buf[1] = ARM_PS_REGNUM;
+          thumb2_insn_r->reg_rec_count = 2;
+        }
+    }
+
+  MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+            record_buf_mem);
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+  return 0;
+}
+
+/* Handler for thumb2 ld/st dual, ld/st exclusive, table branch
+   instructions.  */
+
+static int
+thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
+{
+  struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+  uint32_t reg_rd = 0, reg_rn = 0, offset_imm = 0;
+  uint32_t reg_dest1 = 0, reg_dest2 = 0;
+  uint32_t address = 0, offset_addr = 0;
+  uint32_t record_buf[8], record_buf_mem[8];
+  uint32_t op1 = 0, op2 = 0, op3 = 0;
+  LONGEST s_word;
+
+  ULONGEST u_regval[2];
+
+  op1 = bits (thumb2_insn_r->arm_insn, 23, 24);
+  op2 = bits (thumb2_insn_r->arm_insn, 20, 21);
+  op3 = bits (thumb2_insn_r->arm_insn, 4, 7);
+
+  if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+    {
+      if(!(1 == op1 && 1 == op2 && (0 == op3 || 1 == op3)))
+        {
+          reg_dest1 = bits (thumb2_insn_r->arm_insn, 12, 15);
+          record_buf[0] = reg_dest1;
+          record_buf[1] = ARM_PS_REGNUM;
+          thumb2_insn_r->reg_rec_count = 2;
+        }
+
+      if (3 == op2 || (op1 & 2) || (1 == op1 && 1 == op2 && 7 == op3))
+        {
+          reg_dest2 = bits (thumb2_insn_r->arm_insn, 8, 11);
+          record_buf[2] = reg_dest2;
+          thumb2_insn_r->reg_rec_count = 3;
+        }
+    }
+  else
+    {
+      reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+      regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
+
+      if (0 == op1 && 0 == op2)
+        {
+          /* Handle STREX.  */
+          offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+          address = u_regval[0] + (offset_imm * 4);
+          record_buf_mem[0] = 4;
+          record_buf_mem[1] = address;
+          thumb2_insn_r->mem_rec_count = 1;
+          reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
+          record_buf[0] = reg_rd;
+          thumb2_insn_r->reg_rec_count = 1;
+        }
+      else if (1 == op1 && 0 == op2)
+        {
+          reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
+          record_buf[0] = reg_rd;
+          thumb2_insn_r->reg_rec_count = 1;
+          address = u_regval[0];
+          record_buf_mem[1] = address;
+
+          if (4 == op3)
+            {
+              /* Handle STREXB.  */
+              record_buf_mem[0] = 1;
+              thumb2_insn_r->mem_rec_count = 1;
+            }
+          else if (5 == op3)
+            {
+              /* Handle STREXH.  */
+              record_buf_mem[0] = 2 ;
+              thumb2_insn_r->mem_rec_count = 1;
+            }
+          else if (7 == op3)
+            {
+              /* Handle STREXD */
+              address = u_regval[0];
+              record_buf_mem[0] = 4;
+              record_buf_mem[2] = 4;
+              record_buf_mem[3] = address + 4;
+              thumb2_insn_r->mem_rec_count = 2;
+            }
+        }
+      else
+        {
+          offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+
+          if (bit (thumb2_insn_r->arm_insn, 24))
+            {
+              if (bit (thumb2_insn_r->arm_insn, 23))
+                {
+                  offset_addr = u_regval[0] + (offset_imm * 4);
+                }
+              else
+                {
+                  offset_addr = u_regval[0] - (offset_imm * 4);
+                }
+              address = offset_addr;
+            }
+          else
+            {
+              address = u_regval[0];
+            }
+
+          record_buf_mem[0] = 4;
+          record_buf_mem[1] = address;
+          record_buf_mem[2] = 4;
+          record_buf_mem[3] = address + 4;
+          thumb2_insn_r->mem_rec_count = 2;
+          record_buf[0] = reg_rn;
+          thumb2_insn_r->reg_rec_count = 1;
+        }
+    }
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+  MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+            record_buf_mem);
+  return 0;
+}
+
+/* Handler for thumb2 data-processing shifted register instructions.  */
+
+static int
+thumb2_record_data_proc_sreg (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
+  uint32_t reg_rd = 0;
+  uint32_t op = 0;
+  uint32_t record_buf[8];
+
+  op = bits (thumb2_insn_r->arm_insn, 8, 11);
+  reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+  if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
+    {
+      record_buf[0] = ARM_PS_REGNUM;
+      thumb2_insn_r->reg_rec_count = 1;
+    }
+  else
+    {
+      record_buf[0] = reg_rd;
+      record_buf[1] = ARM_PS_REGNUM;
+      thumb2_insn_r->reg_rec_count = 2;
+    }
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+
+  return ret;
+}
+
+/* Handler for thumb2 co-processor instructions.  */
+
+static int
+thumb2_record_coproc (insn_decode_record *thumb2_insn_r)
+{
+  printf_unfiltered (_("Process record does not support instruction "
+                    "0x%0x at address %s.\n"),thumb2_insn_r->arm_insn,
+                    paddress (thumb2_insn_r->gdbarch,
+                    thumb2_insn_r->this_addr));
+
+  return -1;
+}
+
+/* Handler for thumb2 data-processing (modified immediate) instructions.  */
+
+static int
+thumb2_record_data_proc_mod_imm (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t ret = 0 ;  /* Return value: -1:record failure ;  0:success.   */
+  uint32_t reg_rd = 0;
+  uint32_t op = 0;
+  uint32_t record_buf[8];
+
+  op = bits (thumb2_insn_r->arm_insn, 8, 11);
+  reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+  if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
+    {
+      record_buf[0] = ARM_PS_REGNUM;
+      thumb2_insn_r->reg_rec_count = 1;
+    }
+  else
+    {
+      record_buf[0] = reg_rd;
+      record_buf[1] = ARM_PS_REGNUM;
+      thumb2_insn_r->reg_rec_count = 2;
+    }
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+
+  return ret;
+}
+
+/* Handler for thumb2 data-processing plain binary immediate instructions.  */
+
+static int
+thumb2_record_data_proc_bin_imm (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
+  uint32_t reg_rd = 0;
+  uint32_t record_buf[8];
+
+  reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+  record_buf[0] = reg_rd;
+  record_buf[1] = ARM_PS_REGNUM;
+  thumb2_insn_r->reg_rec_count = 2;
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+
+  return ret;
+}
+
+/* Handler for thumb2 branch and miscellaneous control instructions.  */
+
+static int
+thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t op = 0, op1 = 0, op2 = 0;
+  uint32_t record_buf[8];
+
+  op = bits (thumb2_insn_r->arm_insn, 20, 26);
+  op1 = bits (thumb2_insn_r->arm_insn, 12, 14);
+  op2 = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+  /* Handle MSR insn.  */
+  if (!(op1 & 0x2) && 0x38 == op)
+    {
+      if (!(op2 & 0x3))
+        {
+          /* CPSR is going to be changed.  */
+          record_buf[0] = ARM_PS_REGNUM;
+          thumb2_insn_r->reg_rec_count = 1;
+        }
+      else
+        {
+          /* SPSR is going to be changed.  */
+          printf_unfiltered (_("Process record does not support instruction "
+                            "0x%0x at address %s.\n"),
+                            thumb2_insn_r->arm_insn,
+                            paddress (thumb2_insn_r->gdbarch,
+                            thumb2_insn_r->this_addr));
+          return -1;
+        }
+    }
+  else if (4 == (op1 & 0x5) || 5 == (op1 & 0x5))
+    {
+      /* BLX.  */
+      record_buf[0] = ARM_PS_REGNUM;
+      record_buf[1] = ARM_LR_REGNUM;
+      thumb2_insn_r->reg_rec_count = 2;
+    }
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+
+  return 0;
+}
+
+/* Handler for thumb2 store single data item instructions.  */
+
+static int
+thumb2_record_str_single_data (insn_decode_record *thumb2_insn_r)
+{
+  struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+  uint32_t reg_rn = 0, reg_rm = 0, offset_imm = 0, shift_imm = 0;
+  uint32_t address = 0, offset_addr = 0;
+  uint32_t record_buf[8], record_buf_mem[8];
+  uint32_t op1 = 0, op2 = 0;
+
+  ULONGEST u_regval[2];
+
+  op1 = bits (thumb2_insn_r->arm_insn, 21, 23);
+  op2 = bits (thumb2_insn_r->arm_insn, 6, 11);
+  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+  regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
+
+  if (bit (thumb2_insn_r->arm_insn, 23))
+    {
+      /* T2 encoding.  */
+      offset_imm = bits (thumb2_insn_r->arm_insn, 0, 11);
+      offset_addr = u_regval[0] + offset_imm;
+      address = offset_addr;
+    }
+  else
+    {
+      /* T3 encoding.  */
+      if ((0 == op1 || 1 == op1 || 2 == op1) && !(op2 & 0x20))
+        {
+          /* Handle STRB (register).  */
+          reg_rm = bits (thumb2_insn_r->arm_insn, 0, 3);
+          regcache_raw_read_unsigned (reg_cache, reg_rm, &u_regval[1]);
+          shift_imm = bits (thumb2_insn_r->arm_insn, 4, 5);
+          offset_addr = u_regval[1] << shift_imm;
+          address = u_regval[0] + offset_addr;
+        }
+      else
+        {
+          offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+          if (bit (thumb2_insn_r->arm_insn, 10))
+            {
+              if (bit (thumb2_insn_r->arm_insn, 9))
+                {
+                  offset_addr = u_regval[0] + offset_imm;
+                }
+              else
+                {
+                  offset_addr = u_regval[0] - offset_imm;
+                }
+              address = offset_addr;
+            }
+          else
+            {
+              address = u_regval[0];
+            }
+        }
+    }
+
+  switch (op1)
+    {
+      /* Store byte instructions.  */
+      case 4:
+      case 0:
+        record_buf_mem[0] = 1;
+      break;
+      /* Store half word instructions.  */
+      case 1:
+      case 5:
+        record_buf_mem[0] = 2;
+      break;
+      /* Store word instructions.  */
+      case 2:
+      case 6:
+        record_buf_mem[0] = 4;
+      break;
+
+      default:
+        gdb_assert_not_reached ("no decoding pattern found");
+      break;
+    }
+
+  record_buf_mem[1] = address;
+  thumb2_insn_r->mem_rec_count = 1;
+  record_buf[0] = reg_rn;
+  thumb2_insn_r->reg_rec_count = 1;
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+  MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+            record_buf_mem);
+  return 0;
+}
+
+/* Handler for thumb2 SIMD element and structure load/store instructions.  */
+
+static int
+thumb2_record_simd_struct_ld_st (insn_decode_record *thumb2_insn_r)
+{
+  printf_unfiltered (_("Process record does not support instruction "
+                    "0x%0x at address %s.\n"), thumb2_insn_r->arm_insn,
+                    paddress (thumb2_insn_r->gdbarch,
+                    thumb2_insn_r->this_addr));
+  return -1;
+}
+
+/* Handler for thumb2 load memory hints instructions.  */
+
+static int
+thumb2_record_ld_mem_hints (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t record_buf[8];
+  uint32_t reg_rt = 0, reg_rn=0;
+
+  reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
+  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+
+  if (15 != reg_rt)
+    {
+      record_buf[0] = reg_rt;
+      record_buf[1] = reg_rn;
+      record_buf[2] = ARM_PS_REGNUM;
+      thumb2_insn_r->reg_rec_count = 3;
+
+      REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+                record_buf);
+      return 0;
+    }
+
+  return -1;
+}
+
+/* Handler for thumb2 load word instructions.  */
+
+static int
+thumb2_record_ld_word (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
+  uint32_t opcode1 = 0, opcode2 = 0;
+  uint32_t record_buf[8];
+
+  record_buf[0] = bits (thumb2_insn_r->arm_insn, 12, 15);
+  record_buf[1] = ARM_PS_REGNUM;
+  thumb2_insn_r->reg_rec_count = 2;
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+
+  return ret;
+}
+
+/* Handler for thumb2 data processing (register) instructions.  */
+
+static int
+thumb2_record_data_proc_reg (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
+  uint32_t opcode1 = 0, opcode2 = 0;
+  uint32_t record_buf[8];
+
+  record_buf[0] = bits (thumb2_insn_r->arm_insn, 8, 11);
+  record_buf[1] = ARM_PS_REGNUM;
+  thumb2_insn_r->reg_rec_count = 2;
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+
+  return ret;
+}
+
+/* Handler for thumb2 multiply, multiply accumulate, and
+   absolute difference instructions.  */
+
+static int
+thumb2_record_mul_mla_abs_diff (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
+  uint32_t opcode1 = 0, opcode2 = 0;
+  uint32_t record_buf[8];
+
+  record_buf[0] = bits (thumb2_insn_r->arm_insn, 8, 11);
+  record_buf[1] = ARM_PS_REGNUM;
+  thumb2_insn_r->reg_rec_count = 2;
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+
+  return ret;
+}
+
+/* Handler for thumb2 long multiply, long multiply accumulate, and
+   divide instructions.  */
+
+static int
+thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t ret = 0;  /* Return value: -1:record failure ;  0:success.  */
+  uint32_t opcode1 = 0, opcode2 = 0;
+  uint32_t record_buf[8];
+  uint32_t reg_src1 = 0;
+
+  opcode1 = bits (thumb2_insn_r->arm_insn, 20, 22);
+  opcode2 = bits (thumb2_insn_r->arm_insn, 4, 7);
+
+  if (0 == opcode1 || 2 == opcode1 || (opcode1 >= 4 && opcode1 <= 6))
+    {
+      /* Handle SMULL, UMULL, SMULAL and
+         SMLAL(S), SMULL(S), UMLAL(S), UMULL(S).  */
+      record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
+      record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
+      record_buf[2] = ARM_PS_REGNUM;
+      thumb2_insn_r->reg_rec_count = 3;
+    }
+  else if (1 == opcode1 || 3 == opcode2)
+    {
+      /* Handle SDIV and UDIV.  */
+      record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
+      record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
+      record_buf[2] = ARM_PS_REGNUM;
+      thumb2_insn_r->reg_rec_count = 3;
+    }
+  else
+    {
+      ret = -1;
+    }
+
+  REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+            record_buf);
+
+  return ret;
+}
+
+/* Decodes thumb2 instruction type and return an instruction id.  */
+
+static unsigned int
+thumb2_record_decode_inst_id (uint32_t thumb2_insn)
+{
+  uint32_t op = 0;
+  uint32_t op1 = 0;
+  uint32_t op2 = 0;
+
+  op = bit (thumb2_insn, 15);
+  op1 = bits (thumb2_insn, 27, 28);
+  op2 = bits (thumb2_insn, 20, 26);
+
+  if (op1 == 0x01)
+    {
+      if (!(op2 & 0x64 ))
+        {
+          /* Load/store multiple instruction.  */
+          return 0;
+        }
+      else if (!((op2 & 0x64) ^ 0x04))
+        {
+          /* Load/store dual/exclusive and table branch instructions.  */
+          return 1;
+        }
+      else if (!((op2 & 0x20) ^ 0x20))
+        {
+          /* Data-processing (shifted register).  */
+          return 2;
+        }
+      else if (op2 & 0x40)
+        {
+          /* Co-processor instructions.  */
+          return 3;
+        }
+    }
+  else if (op1 == 0x02)
+    {
+      if (op)
+        {
+          /* Branches and miscellaneous control instructions.  */
+          return 6;
+        }
+      else if (op2 & 0x20)
+        {
+          /* Data-processing (plain binary immediate) instruction.  */
+          return 5;
+        }
+      else
+        {
+          /* Data-processing (modified immediate).  */
+          return 4;
+        }
+    }
+  else if (op1 == 0x03)
+   {
+      if (!(op2 & 0x71 ))
+        {
+      /* Store single data item.  */
+          return 7;
+        }
+      else if (!((op2 & 0x71) ^ 0x10))
+        {
+          /* Advanced SIMD element or structure load/store instructions.  */
+          return 8;
+        }
+      else if (!((op2 & 0x67) ^ 0x01))
+        {
+          /* Load byte, memory hints instruction.  */
+          return 9;
+        }
+      else if (!((op2 & 0x67) ^ 0x03))
+        {
+      /* Load halfword, memory hints instruction.  */
+          return 10;
+        }
+      else if (!((op2 & 0x67) ^ 0x05))
+        {
+      /* Load word instruction.  */
+          return 11;
+        }
+      else if (!((op2 & 0x70) ^ 0x20))
+        {
+      /* Data-processing (register) instruction.  */
+          return 12;
+        }
+      else if (!((op2 & 0x78) ^ 0x30))
+        {
+      /* Multiply, multiply accumulate, absolute difference instruction.  */
+          return 13;
+        }
+      else if (!((op2 & 0x78) ^ 0x38))
+        {
+          /* Long multiply, long multiply accumulate, and divide.  */
+          return 14;
+        }
+      else if (op2 & 0x40)
+        {
+          /* Co-processor instructions.  */
+          return 15;
+        }
+   }
+
+  return -1;
+}

 /* Extracts arm/thumb/thumb2 insn depending on the size, and returns
0 on success