diff mbox

Record and replay: ARM thumb 32bit instructions support

Message ID CANW4E-04VhnBLveF_7uSjLaPstpwW-Yw02LhRbS=Y1eYr7Mmbg@mail.gmail.com
State Superseded
Headers show

Commit Message

Omair Javaid Oct. 6, 2013, 9:16 p.m. UTC
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(-)


 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
     {
--

Comments

Will Newton Oct. 10, 2013, 12:14 p.m. UTC | #1
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
>      {
> --
>
Yao Qi Oct. 16, 2013, 10:03 a.m. UTC | #2
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?
diff mbox

Patch

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