public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Record and replay: ARM thumb 32bit instructions support
@ 2013-09-18 15:38 Omair Javaid
  2013-10-01  9:57 ` Omair Javaid
  0 siblings, 1 reply; 5+ messages in thread
From: Omair Javaid @ 2013-09-18 15:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: Patch Tracking

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
     {

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Record and replay: ARM thumb 32bit instructions support
  2013-09-18 15:38 [PATCH] Record and replay: ARM thumb 32bit instructions support Omair Javaid
@ 2013-10-01  9:57 ` Omair Javaid
  2013-10-06 21:16   ` Omair Javaid
  0 siblings, 1 reply; 5+ messages in thread
From: Omair Javaid @ 2013-10-01  9:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: Patch Tracking

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.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Record and replay: ARM thumb 32bit instructions support
  2013-10-01  9:57 ` Omair Javaid
@ 2013-10-06 21:16   ` Omair Javaid
  2013-10-10 12:14     ` Will Newton
  2013-10-16 10:05     ` Yao Qi
  0 siblings, 2 replies; 5+ messages in thread
From: Omair Javaid @ 2013-10-06 21:16 UTC (permalink / raw)
  To: gdb-patches; +Cc: Patch Tracking

On 1 October 2013 14:56, Omair Javaid <omair.javaid@linaro.org> wrote:
> 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.

The patch has been updated with some minor fixes. Reverse debug
testsuite shows significant improvement. Here are the reverse debug
test suite statistics taken on Linux chromebook (arm v7) hardware:

* Without thumb32 Patch
Native GDB (with support process record enabled) # of expected passes 32
Native GDB (with support process record and reverse debug enabled) #
of expected passes 518
Remote GDB (with support process record enabled) # of expected passes 506
Remote GDB (with support process record and reverse debug enabled) #
of expected passes 506

* With thumb32 Patch
Native GDB (with support process record enabled) # of expected passes
105 (73 new passed tests after thumb32 patch)
Native GDB (with support process record and reverse debug enabled) #
of expected passes 1133 (627 new passed tests after thumb32 patch)
Remote GDB (with support process record enabled) # of expected passes
973 (467 new passed tests after thumb32 patch)
Remote GDB (with support process record and reverse debug enabled) #
of expected passes 978 (472 new passed tests after thumb32 patch)

gdb/testsuite/ChangeLog:

2013-10-06  Omair Javaid  <Omair.Javaid@linaro.org>

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

---
 gdb/arm-tdep.c |  751 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 745 insertions(+), 6 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 7c78a61..0427bdb 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -12414,8 +12414,710 @@ thumb_record_branch (insn_decode_record *thumb_insn_r)
   return 0;
 }

+/* Handler for thumb2 load/store multiple instructions */

-/* Extracts arm/thumb/thumb2 insn depending on the size, and returns
0 on success
+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 */
+      /* Handle 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, load/store exclusive, table branch instruction */
+          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.  */

 static int
@@ -12469,6 +13171,27 @@ decode_insn (insn_decode_record *arm_record,
record_type_t record_type,
     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 +13226,27 @@ decode_insn (insn_decode_record *arm_record,
record_type_t record_type,
     }
   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;
+
+      /* Swap first half of 32bit thumb instruction with second half */
+      arm_record->arm_insn = (arm_record->arm_insn >> 16) |
+                             (arm_record->arm_insn << 16);
+
+      insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn);
+
+      if (insn_id >= 0)
+        {
+          ret = thumb2_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
     {
--

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Record and replay: ARM thumb 32bit instructions support
  2013-10-06 21:16   ` Omair Javaid
@ 2013-10-10 12:14     ` Will Newton
  2013-10-16 10:05     ` Yao Qi
  1 sibling, 0 replies; 5+ messages in thread
From: Will Newton @ 2013-10-10 12:14 UTC (permalink / raw)
  To: Omair Javaid; +Cc: gdb-patches, Patch Tracking

On 06/10/13 22:16, Omair Javaid wrote:

Hi Omair,

> The patch has been updated with some minor fixes. Reverse debug
> testsuite shows significant improvement. Here are the reverse debug
> test suite statistics taken on Linux chromebook (arm v7) hardware:
> 
> * Without thumb32 Patch
> Native GDB (with support process record enabled) # of expected passes 32
> Native GDB (with support process record and reverse debug enabled) #
> of expected passes 518
> Remote GDB (with support process record enabled) # of expected passes 506
> Remote GDB (with support process record and reverse debug enabled) #
> of expected passes 506
> 
> * With thumb32 Patch
> Native GDB (with support process record enabled) # of expected passes
> 105 (73 new passed tests after thumb32 patch)
> Native GDB (with support process record and reverse debug enabled) #
> of expected passes 1133 (627 new passed tests after thumb32 patch)
> Remote GDB (with support process record enabled) # of expected passes
> 973 (467 new passed tests after thumb32 patch)
> Remote GDB (with support process record and reverse debug enabled) #
> of expected passes 978 (472 new passed tests after thumb32 patch)
> 
> gdb/testsuite/ChangeLog:
> 
> 2013-10-06  Omair Javaid  <Omair.Javaid@linaro.org>
> 
>         * arm-tdep.c: Adds support for thumb32 instructions in
>           arm process record.
> 
> ---
>  gdb/arm-tdep.c |  751 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 745 insertions(+), 6 deletions(-)

The patch itself appears to be line-wrapped so I couldn't apply it.

> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
> index 7c78a61..0427bdb 100644
> --- a/gdb/arm-tdep.c
> +++ b/gdb/arm-tdep.c
> @@ -12414,8 +12414,710 @@ thumb_record_branch (insn_decode_record *thumb_insn_r)
>    return 0;
>  }
> 
> +/* Handler for thumb2 load/store multiple instructions */

Comments should end with a full-stop and two spaces. There's quite a lot of places
where this should be fixed.

> -/* Extracts arm/thumb/thumb2 insn depending on the size, and returns
> 0 on success
> +static int
> +thumb2_record_ld_st_mulitple (insn_decode_record *thumb2_insn_r)

Typo here, "multiple".

> +{
> +  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  */

This does not seem to ever be set to a non-zero value.

> +  uint32_t reg_rd = 0;
> +  uint32_t op = 0;

These are initialized immediately so we could drop the initialization to zero.

> +  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;

Same comments as above.

> +  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;

These initializations are not required either.

> +  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;
> +}

This function and the one for coproc instructions are identical, and the same
string is also used for misc_cntrl decoding. It shoudl be possibel to refactor
the code to just use the same function.

> +
> +/* 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;

Space around the =, but these initializations can just be removed.

> +
> +  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;

ret is not required and opcode1 and opcode2 do not seem to be used.

> +  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;

As above.

> +  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 */
> +      /* Handle 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 ))

Trailing space can be removed.

> +        {
> +          /* Load/store multiple instruction */
> +          return 0;
> +        }
> +      else if (!((op2 & 0x64) ^ 0x04))
> +        {
> +          /* Load/store dual, load/store exclusive, table branch instruction */
> +          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 */

Indentation seems off here and a couple of places below too.

> +          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.  */

This line is too long an typo "failure".

>  static int
> @@ -12469,6 +13171,27 @@ decode_insn (insn_decode_record *arm_record,
> record_type_t record_type,
>      thumb_record_branch                /* 111.  */
>    };
> 
> +  /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
> instruction.  */

This line also looks long.

> +  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 +13226,27 @@ decode_insn (insn_decode_record *arm_record,
> record_type_t record_type,
>      }
>    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;
> +
> +      /* Swap first half of 32bit thumb instruction with second half */
> +      arm_record->arm_insn = (arm_record->arm_insn >> 16) |
> +                             (arm_record->arm_insn << 16);
> +
> +      insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn);
> +
> +      if (insn_id >= 0)
> +        {
> +          ret = thumb2_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
>      {
> --
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Record and replay: ARM thumb 32bit instructions support
  2013-10-06 21:16   ` Omair Javaid
  2013-10-10 12:14     ` Will Newton
@ 2013-10-16 10:05     ` Yao Qi
  1 sibling, 0 replies; 5+ messages in thread
From: Yao Qi @ 2013-10-16 10:05 UTC (permalink / raw)
  To: Omair Javaid; +Cc: gdb-patches, Patch Tracking

On 10/07/2013 05:16 AM, Omair Javaid wrote:
> * Without thumb32 Patch
> Native GDB (with support process record enabled) # of expected passes 32
> Native GDB (with support process record and reverse debug enabled) #
> of expected passes 518
> Remote GDB (with support process record enabled) # of expected passes 506
> Remote GDB (with support process record and reverse debug enabled) #
> of expected passes 506
>
> * With thumb32 Patch
> Native GDB (with support process record enabled) # of expected passes
> 105 (73 new passed tests after thumb32 patch)
> Native GDB (with support process record and reverse debug enabled) #
> of expected passes 1133 (627 new passed tests after thumb32 patch)
> Remote GDB (with support process record enabled) # of expected passes
> 973 (467 new passed tests after thumb32 patch)
> Remote GDB (with support process record and reverse debug enabled) #
> of expected passes 978 (472 new passed tests after thumb32 patch)
>

The result looks good.

> gdb/testsuite/ChangeLog:
>
> 2013-10-06  Omair Javaid<Omair.Javaid@linaro.org>
>
>          * arm-tdep.c: Adds support for thumb32 instructions in
>            arm process record.

Your changelog entry is too simple.  We still need to list the added new 
function names here, even it is quite mechanical.

We still need a NEWS entry.

> +      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);
> +                }

braces are not needed if the statement is single-line.  Here and
elsewhere.

Why don't you add "arm*-*-linux*" triplet into proc 
supports_process_record and supports_reverse in testsuite/lib/gdb.exp?
-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-10-16 10:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-18 15:38 [PATCH] Record and replay: ARM thumb 32bit instructions support Omair Javaid
2013-10-01  9:57 ` Omair Javaid
2013-10-06 21:16   ` Omair Javaid
2013-10-10 12:14     ` Will Newton
2013-10-16 10:05     ` Yao Qi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).