diff mbox

[1/2] GDB process record and reverse debugging improvements for arm*-linux*

Message ID 52929080.1030304@linaro.org
State Accepted
Headers show

Commit Message

Omair Javaid Nov. 24, 2013, 11:49 p.m. UTC
On 11/11/2013 03:09 PM, Yao Qi wrote:
> Patch looks good to me, and you still need a maintainer's approval.
> 
> Some of the comments are too long.  Please make sure they don't exceed 
> the limitation (around 74 characters should be fine).
> 
> On 11/08/2013 11:19 AM, Omair Javaid wrote:
>> +/* Handler for thumb2 ld/st dual, ld/st exclusive, table branch
>> instructions.  */
>> +
> 
> here.
> 
>> +static int
>> +thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
>> +{
>> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
>> +
> 
> ....
> 
>> +
>> +/* 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.  */
> 
> and here.
> 
> 
>> +          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.  */
> 
> here.
> 
>> +          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.  */
> 
> here.
> 
>> +          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.  */
>> @@ -12452,7 +13034,7 @@ decode_insn (insn_decode_record *arm_rec
>>       arm_record_ld_st_reg_offset,        /* 011.  */
>>       arm_record_ld_st_multiple,          /* 100.  */
>>       arm_record_b_bl,                    /* 101.  */
>> -    arm_record_coproc,                  /* 110.  */
>> +    arm_record_unsupported_insn,                  /* 110.  */
>>       arm_record_coproc_data_proc         /* 111.  */
>>     };
>>
>> @@ -12469,6 +13051,27 @@ decode_insn (insn_decode_record *arm_rec
>>       thumb_record_branch                /* 111.  */
>>     };
>>
>> +  /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
>> instruction.  */
> 
> here.
> 

Patch has been updated after incorporating suggestions. Looking for a final
commit verdict.

This patch adds support for recording thumb32 instructions. This patch also
fixes bugs in arm process record instruction decoding.

gdb:

2013-11-08  Omair Javaid  <omair.javaid@linaro.org>

	* arm-tdep.c (struct arm_mem_r): Use uint32_t for memory address.
	(arm_record_unsupported_insn): New function.
	(arm_record_coproc_data_proc): Removed.
	(thumb2_record_ld_st_multiple): New function.
	(thumb2_record_ld_st_dual_ex_tbb): New function.
	(thumb2_record_data_proc_sreg_mimm): New function.
	(thumb2_record_ps_dest_generic): New function.
	(thumb2_record_branch_misc_cntrl): New function.
	(thumb2_record_str_single_data): New function.
	(thumb2_record_ld_mem_hints): New function.
	(thumb2_record_ld_word): New function.
	(thumb2_record_lmul_lmla_div): New function.
	(thumb2_record_decode_inst_id): New function.
	(decode_insn): Add thumb32 instruction handlers.

---
 gdb/arm-tdep.c |  627 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 619 insertions(+), 8 deletions(-)

--

Comments

oza Pawandeep Nov. 25, 2013, 1:07 p.m. UTC | #1
Hi Omar,

couple of comments.

1) you this part of code is still using MAGIC numbers.
+      if (!(op2 & 0x71 ))
+        {
+          /* Store single data item.  */
+          return 7;
+        }
+      else if (!((op2 & 0x71) ^ 0x10))
+        {
+          /* Advanced SIMD 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;
+        }


2) following code else part is not required.

  /* 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
+        {
+          arm_record_unsupported_insn(
thumb2_insn_r);
+          return -1;
+        }

because of folowing.
// SPSRWriteByInstr()
// ==================
SPSRWriteByInstr(bits(32) value, bits(4) bytemask)
if CurrentModeIsUserOrSystem() then UNPREDICTABLE;

gdb is for user space; and use space is not allowed to use SPSR
directly using MSR instruction.
so old code base + new code base whereever we have got SPSR getting
modified we need to remove the same.

3) did you run the testsuite at whole code-base ?


ps: I am still struggling to get my public key setup at gdb git. will
try to get it done as soonas I can.

Regards,
Oza.



On Mon, Nov 25, 2013 at 5:19 AM, Omair Javaid <omair.javaid@linaro.org> wrote:
> On 11/11/2013 03:09 PM, Yao Qi wrote:
>> Patch looks good to me, and you still need a maintainer's approval.
>>
>> Some of the comments are too long.  Please make sure they don't exceed
>> the limitation (around 74 characters should be fine).
>>
>> On 11/08/2013 11:19 AM, Omair Javaid wrote:
>>> +/* Handler for thumb2 ld/st dual, ld/st exclusive, table branch
>>> instructions.  */
>>> +
>>
>> here.
>>
>>> +static int
>>> +thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
>>> +{
>>> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
>>> +
>>
>> ....
>>
>>> +
>>> +/* 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.  */
>>
>> and here.
>>
>>
>>> +          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.  */
>>
>> here.
>>
>>> +          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.  */
>>
>> here.
>>
>>> +          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.  */
>>> @@ -12452,7 +13034,7 @@ decode_insn (insn_decode_record *arm_rec
>>>       arm_record_ld_st_reg_offset,        /* 011.  */
>>>       arm_record_ld_st_multiple,          /* 100.  */
>>>       arm_record_b_bl,                    /* 101.  */
>>> -    arm_record_coproc,                  /* 110.  */
>>> +    arm_record_unsupported_insn,                  /* 110.  */
>>>       arm_record_coproc_data_proc         /* 111.  */
>>>     };
>>>
>>> @@ -12469,6 +13051,27 @@ decode_insn (insn_decode_record *arm_rec
>>>       thumb_record_branch                /* 111.  */
>>>     };
>>>
>>> +  /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
>>> instruction.  */
>>
>> here.
>>
>
> Patch has been updated after incorporating suggestions. Looking for a final
> commit verdict.
>
> This patch adds support for recording thumb32 instructions. This patch also
> fixes bugs in arm process record instruction decoding.
>
> gdb:
>
> 2013-11-08  Omair Javaid  <omair.javaid@linaro.org>
>
>         * arm-tdep.c (struct arm_mem_r): Use uint32_t for memory address.
>         (arm_record_unsupported_insn): New function.
>         (arm_record_coproc_data_proc): Removed.
>         (thumb2_record_ld_st_multiple): New function.
>         (thumb2_record_ld_st_dual_ex_tbb): New function.
>         (thumb2_record_data_proc_sreg_mimm): New function.
>         (thumb2_record_ps_dest_generic): New function.
>         (thumb2_record_branch_misc_cntrl): New function.
>         (thumb2_record_str_single_data): New function.
>         (thumb2_record_ld_mem_hints): New function.
>         (thumb2_record_ld_word): New function.
>         (thumb2_record_lmul_lmla_div): New function.
>         (thumb2_record_decode_inst_id): New function.
>         (decode_insn): Add thumb32 instruction handlers.
>
> ---
>  gdb/arm-tdep.c |  627 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 619 insertions(+), 8 deletions(-)
>
> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
> index 7c78a61..ecaced7 100644
> --- a/gdb/arm-tdep.c
> +++ b/gdb/arm-tdep.c
> @@ -10618,7 +10618,7 @@ vfp - VFP co-processor."),
>  struct arm_mem_r
>  {
>    uint32_t len;    /* Record length.  */
> -  CORE_ADDR addr;  /* Memory address.  */
> +  uint32_t addr;   /* Memory address.  */
>  };
>
>  /* ARM instruction record contains opcode of current insn
> @@ -11919,7 +11919,7 @@ arm_record_b_bl (insn_decode_record *arm_insn_r)
>  /* Handling opcode 110 insns.  */
>
>  static int
> -arm_record_coproc (insn_decode_record *arm_insn_r)
> +arm_record_unsupported_insn (insn_decode_record *arm_insn_r)
>  {
>    printf_unfiltered (_("Process record does not support instruction "
>                      "0x%0x at address %s.\n"),arm_insn_r->arm_insn,
> @@ -12414,6 +12414,584 @@ thumb_record_branch (insn_decode_record *thumb_insn_r)
>    return 0;
>  }
>
> +/* Handler for thumb2 load/store multiple instructions.  */
> +
> +static int
> +thumb2_record_ld_st_multiple (insn_decode_record *thumb2_insn_r)
> +{
> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
> +
> +  uint32_t reg_rn, op;
> +  uint32_t 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;
> +
> +  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
> +  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.  */
> +          return arm_record_unsupported_insn (thumb2_insn_r);
> +        }
> +    }
> +  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 load/store (dual/exclusive) and 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, reg_rn, offset_imm;
> +  uint32_t reg_dest1, reg_dest2;
> +  uint32_t address, offset_addr;
> +  uint32_t record_buf[8], record_buf_mem[8];
> +  uint32_t op1, op2, op3;
> +  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 (shift register and modified immediate)
> +   instructions.  */
> +
> +static int
> +thumb2_record_data_proc_sreg_mimm (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t reg_rd, op;
> +  uint32_t record_buf[8];
> +
> +  op = bits (thumb2_insn_r->arm_insn, 21, 24);
> +  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 0;
> +}
> +
> +/* Generic handler for thumb2 instructions which effect destination and PS
> +   registers.  */
> +
> +static int
> +thumb2_record_ps_dest_generic (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t reg_rd;
> +  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 0;
> +}
> +
> +/* Handler for thumb2 branch and miscellaneous control instructions.  */
> +
> +static int
> +thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t op, op1, op2;
> +  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
> +        {
> +          arm_record_unsupported_insn(thumb2_insn_r);
> +          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, reg_rm, offset_imm, shift_imm;
> +  uint32_t address, offset_addr;
> +  uint32_t record_buf[8], record_buf_mem[8];
> +  uint32_t op1, op2;
> +
> +  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 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, reg_rn;
> +
> +  reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
> +  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
> +
> +  if (ARM_PC_REGNUM != 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 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 0;
> +}
> +
> +/* Handler for thumb2 long multiply, long multiply accumulate, and
> +   divide instructions.  Return value: -1:record failure ;  0:success.  */
> +
> +static int
> +thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0;
> +  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/exclusive) and 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 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, abs diff 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.  */
> @@ -12452,7 +13030,7 @@ decode_insn (insn_decode_record *arm_record, record_type_t record_type,
>      arm_record_ld_st_reg_offset,        /* 011.  */
>      arm_record_ld_st_multiple,          /* 100.  */
>      arm_record_b_bl,                    /* 101.  */
> -    arm_record_coproc,                  /* 110.  */
> +    arm_record_unsupported_insn,                  /* 110.  */
>      arm_record_coproc_data_proc         /* 111.  */
>    };
>
> @@ -12469,6 +13047,28 @@ 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_multiple,       /* 00.  */
> +    thumb2_record_ld_st_dual_ex_tbb,    /* 01.  */
> +    thumb2_record_data_proc_sreg_mimm,  /* 02.  */
> +    arm_record_unsupported_insn,        /* 03.  */
> +    thumb2_record_data_proc_sreg_mimm,  /* 04.  */
> +    thumb2_record_ps_dest_generic,      /* 05.  */
> +    thumb2_record_branch_misc_cntrl,    /* 06.  */
> +    thumb2_record_str_single_data,      /* 07.  */
> +    arm_record_unsupported_insn,        /* 08.  */
> +    thumb2_record_ld_mem_hints,         /* 09.  */
> +    thumb2_record_ld_mem_hints,         /* 10.  */
> +    thumb2_record_ld_word,              /* 11.  */
> +    thumb2_record_ps_dest_generic,      /* 12.  */
> +    thumb2_record_ps_dest_generic,      /* 13.  */
> +    thumb2_record_lmul_lmla_div,        /* 14.  */
> +    arm_record_unsupported_insn         /* 15.  */
> +  };
> +
>    uint32_t ret = 0;    /* return value: negative:failure   0:success.  */
>    uint32_t insn_id = 0;
>
> @@ -12503,11 +13103,22 @@ 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
> +        {
> +          arm_record_unsupported_insn(arm_record);
> +          ret = -1;
> +        }
>      }
>    else
>      {
> --
Omair Javaid Nov. 27, 2013, 10:04 p.m. UTC | #2
On 11/25/2013 06:07 PM, Oza Pawandeep wrote:
> Hi Omar,
> 
> couple of comments.
> 
> 1) you this part of code is still using MAGIC numbers.
> +      if (!(op2 & 0x71 ))
> +        {
> +          /* Store single data item.  */
> +          return 7;
> +        }
> +      else if (!((op2 & 0x71) ^ 0x10))
> +        {
> +          /* Advanced SIMD 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;
> +        }
> 
In principle I agree that code must be more readable overall but that is applicable to all the code residing in arm-tdep.c. The nomenclature and bit manipulations in above code is used in line with ARM reference manual and can be understood if we have Thumb32 instruction encoding page infront.
> 
> 2) following code else part is not required.
> 
>   /* 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
> +        {
> +          arm_record_unsupported_insn(
> thumb2_insn_r);
> +          return -1;
> +        }
> 
> because of folowing.
> // SPSRWriteByInstr()
> // ==================
> SPSRWriteByInstr(bits(32) value, bits(4) bytemask)
> if CurrentModeIsUserOrSystem() then UNPREDICTABLE;
> 
> gdb is for user space; and use space is not allowed to use SPSR
> directly using MSR instruction.
> so old code base + new code base whereever we have got SPSR getting
> modified we need to remove the same.
> 
I agree with you that we have to do a lot of rework of previous process record code. But I am not sure it would be productive for us to get working code out and loose the functionality or delay its submission. As Record/Replay is pretty much functional with this set of patches I am hoping that we can do a complete rework if required later on.

> 3) did you run the testsuite at whole code-base ?
I have tested with a a fresh git checkout alongwith 4 patches I have sent. In native mode on a samsung chromebook there are only 69 failures left out of around 2500 test cases. I am working on more bug fixes and hopefully will be able to resolve rest of issues as well. 
> 
> 
> ps: I am still struggling to get my public key setup at gdb git. will
> try to get it done as soonas I can.
> 
> Regards,
> Oza.
> 
> 
> 
> On Mon, Nov 25, 2013 at 5:19 AM, Omair Javaid <omair.javaid@linaro.org> wrote:
>> On 11/11/2013 03:09 PM, Yao Qi wrote:
>>> Patch looks good to me, and you still need a maintainer's approval.
>>>
>>> Some of the comments are too long.  Please make sure they don't exceed
>>> the limitation (around 74 characters should be fine).
>>>
>>> On 11/08/2013 11:19 AM, Omair Javaid wrote:
>>>> +/* Handler for thumb2 ld/st dual, ld/st exclusive, table branch
>>>> instructions.  */
>>>> +
>>>
>>> here.
>>>
>>>> +static int
>>>> +thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
>>>> +{
>>>> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
>>>> +
>>>
>>> ....
>>>
>>>> +
>>>> +/* 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.  */
>>>
>>> and here.
>>>
>>>
>>>> +          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.  */
>>>
>>> here.
>>>
>>>> +          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.  */
>>>
>>> here.
>>>
>>>> +          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.  */
>>>> @@ -12452,7 +13034,7 @@ decode_insn (insn_decode_record *arm_rec
>>>>       arm_record_ld_st_reg_offset,        /* 011.  */
>>>>       arm_record_ld_st_multiple,          /* 100.  */
>>>>       arm_record_b_bl,                    /* 101.  */
>>>> -    arm_record_coproc,                  /* 110.  */
>>>> +    arm_record_unsupported_insn,                  /* 110.  */
>>>>       arm_record_coproc_data_proc         /* 111.  */
>>>>     };
>>>>
>>>> @@ -12469,6 +13051,27 @@ decode_insn (insn_decode_record *arm_rec
>>>>       thumb_record_branch                /* 111.  */
>>>>     };
>>>>
>>>> +  /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
>>>> instruction.  */
>>>
>>> here.
>>>
>>
>> Patch has been updated after incorporating suggestions. Looking for a final
>> commit verdict.
>>
>> This patch adds support for recording thumb32 instructions. This patch also
>> fixes bugs in arm process record instruction decoding.
>>
>> gdb:
>>
>> 2013-11-08  Omair Javaid  <omair.javaid@linaro.org>
>>
>>         * arm-tdep.c (struct arm_mem_r): Use uint32_t for memory address.
>>         (arm_record_unsupported_insn): New function.
>>         (arm_record_coproc_data_proc): Removed.
>>         (thumb2_record_ld_st_multiple): New function.
>>         (thumb2_record_ld_st_dual_ex_tbb): New function.
>>         (thumb2_record_data_proc_sreg_mimm): New function.
>>         (thumb2_record_ps_dest_generic): New function.
>>         (thumb2_record_branch_misc_cntrl): New function.
>>         (thumb2_record_str_single_data): New function.
>>         (thumb2_record_ld_mem_hints): New function.
>>         (thumb2_record_ld_word): New function.
>>         (thumb2_record_lmul_lmla_div): New function.
>>         (thumb2_record_decode_inst_id): New function.
>>         (decode_insn): Add thumb32 instruction handlers.
>>
>> ---
>>  gdb/arm-tdep.c |  627 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 619 insertions(+), 8 deletions(-)
>>
>> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
>> index 7c78a61..ecaced7 100644
>> --- a/gdb/arm-tdep.c
>> +++ b/gdb/arm-tdep.c
>> @@ -10618,7 +10618,7 @@ vfp - VFP co-processor."),
>>  struct arm_mem_r
>>  {
>>    uint32_t len;    /* Record length.  */
>> -  CORE_ADDR addr;  /* Memory address.  */
>> +  uint32_t addr;   /* Memory address.  */
>>  };
>>
>>  /* ARM instruction record contains opcode of current insn
>> @@ -11919,7 +11919,7 @@ arm_record_b_bl (insn_decode_record *arm_insn_r)
>>  /* Handling opcode 110 insns.  */
>>
>>  static int
>> -arm_record_coproc (insn_decode_record *arm_insn_r)
>> +arm_record_unsupported_insn (insn_decode_record *arm_insn_r)
>>  {
>>    printf_unfiltered (_("Process record does not support instruction "
>>                      "0x%0x at address %s.\n"),arm_insn_r->arm_insn,
>> @@ -12414,6 +12414,584 @@ thumb_record_branch (insn_decode_record *thumb_insn_r)
>>    return 0;
>>  }
>>
>> +/* Handler for thumb2 load/store multiple instructions.  */
>> +
>> +static int
>> +thumb2_record_ld_st_multiple (insn_decode_record *thumb2_insn_r)
>> +{
>> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
>> +
>> +  uint32_t reg_rn, op;
>> +  uint32_t 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;
>> +
>> +  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
>> +  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.  */
>> +          return arm_record_unsupported_insn (thumb2_insn_r);
>> +        }
>> +    }
>> +  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 load/store (dual/exclusive) and 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, reg_rn, offset_imm;
>> +  uint32_t reg_dest1, reg_dest2;
>> +  uint32_t address, offset_addr;
>> +  uint32_t record_buf[8], record_buf_mem[8];
>> +  uint32_t op1, op2, op3;
>> +  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 (shift register and modified immediate)
>> +   instructions.  */
>> +
>> +static int
>> +thumb2_record_data_proc_sreg_mimm (insn_decode_record *thumb2_insn_r)
>> +{
>> +  uint32_t reg_rd, op;
>> +  uint32_t record_buf[8];
>> +
>> +  op = bits (thumb2_insn_r->arm_insn, 21, 24);
>> +  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 0;
>> +}
>> +
>> +/* Generic handler for thumb2 instructions which effect destination and PS
>> +   registers.  */
>> +
>> +static int
>> +thumb2_record_ps_dest_generic (insn_decode_record *thumb2_insn_r)
>> +{
>> +  uint32_t reg_rd;
>> +  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 0;
>> +}
>> +
>> +/* Handler for thumb2 branch and miscellaneous control instructions.  */
>> +
>> +static int
>> +thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
>> +{
>> +  uint32_t op, op1, op2;
>> +  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
>> +        {
>> +          arm_record_unsupported_insn(thumb2_insn_r);
>> +          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, reg_rm, offset_imm, shift_imm;
>> +  uint32_t address, offset_addr;
>> +  uint32_t record_buf[8], record_buf_mem[8];
>> +  uint32_t op1, op2;
>> +
>> +  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 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, reg_rn;
>> +
>> +  reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
>> +  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
>> +
>> +  if (ARM_PC_REGNUM != 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 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 0;
>> +}
>> +
>> +/* Handler for thumb2 long multiply, long multiply accumulate, and
>> +   divide instructions.  Return value: -1:record failure ;  0:success.  */
>> +
>> +static int
>> +thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
>> +{
>> +  uint32_t ret = 0;
>> +  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/exclusive) and 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 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, abs diff 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.  */
>> @@ -12452,7 +13030,7 @@ decode_insn (insn_decode_record *arm_record, record_type_t record_type,
>>      arm_record_ld_st_reg_offset,        /* 011.  */
>>      arm_record_ld_st_multiple,          /* 100.  */
>>      arm_record_b_bl,                    /* 101.  */
>> -    arm_record_coproc,                  /* 110.  */
>> +    arm_record_unsupported_insn,                  /* 110.  */
>>      arm_record_coproc_data_proc         /* 111.  */
>>    };
>>
>> @@ -12469,6 +13047,28 @@ 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_multiple,       /* 00.  */
>> +    thumb2_record_ld_st_dual_ex_tbb,    /* 01.  */
>> +    thumb2_record_data_proc_sreg_mimm,  /* 02.  */
>> +    arm_record_unsupported_insn,        /* 03.  */
>> +    thumb2_record_data_proc_sreg_mimm,  /* 04.  */
>> +    thumb2_record_ps_dest_generic,      /* 05.  */
>> +    thumb2_record_branch_misc_cntrl,    /* 06.  */
>> +    thumb2_record_str_single_data,      /* 07.  */
>> +    arm_record_unsupported_insn,        /* 08.  */
>> +    thumb2_record_ld_mem_hints,         /* 09.  */
>> +    thumb2_record_ld_mem_hints,         /* 10.  */
>> +    thumb2_record_ld_word,              /* 11.  */
>> +    thumb2_record_ps_dest_generic,      /* 12.  */
>> +    thumb2_record_ps_dest_generic,      /* 13.  */
>> +    thumb2_record_lmul_lmla_div,        /* 14.  */
>> +    arm_record_unsupported_insn         /* 15.  */
>> +  };
>> +
>>    uint32_t ret = 0;    /* return value: negative:failure   0:success.  */
>>    uint32_t insn_id = 0;
>>
>> @@ -12503,11 +13103,22 @@ 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
>> +        {
>> +          arm_record_unsupported_insn(arm_record);
>> +          ret = -1;
>> +        }
>>      }
>>    else
>>      {
>> --
>
Yao Qi Nov. 28, 2013, 12:19 p.m. UTC | #3
On 11/28/2013 06:04 AM, Omair Javaid wrote:
>> gdb is for user space; and use space is not allowed to use SPSR
>> >directly using MSR instruction.
>> >so old code base + new code base whereever we have got SPSR getting
>> >modified we need to remove the same.
>> >
> I agree with you that we have to do a lot of rework of previous process record code. But I am not sure it would be productive for us to get working code out and loose the functionality or delay its submission. As Record/Replay is pretty much functional with this set of patches I am hoping that we can do a complete rework if required later on.
>

If there is something broken related to the submissions, the common 
practise could be one of them below:

  1. Fix them first,
  2. Document the existing limitations/problems or write a test case to 
kfail it.  In this way, people are aware of this.
  3. Continue the submission and revisit the problems later.

Personally, I choose one of them, depending on the complexity of fixing 
the existing problems.  This patch series is a large one, and based on 
some existing code.  I would like to fix existing problems first, before 
doing something new, if it doesn't take much time on fixing existing 
problems.  These patches are preparatory, and usually simple.  so they 
have more chances to be reviewed in a timely manner.  These preparatory 
patches set up a context for your large patch series, and the context is 
helpful to understanding your patch series.  As a result, the review 
process may be shortened.

I don't want you to fix existing problems first, or take other actions.
Just let you know something submitters can do to help maintainers to 
approve patches.
Omair Javaid Dec. 17, 2013, 10:22 a.m. UTC | #4
On Thu 28 Nov 2013 05:19:15 PM PKT, Yao Qi wrote:
> On 11/28/2013 06:04 AM, Omair Javaid wrote:
>>> gdb is for user space; and use space is not allowed to use SPSR
>>>> directly using MSR instruction.
>>>> so old code base + new code base whereever we have got SPSR getting
>>>> modified we need to remove the same.
>>>>
>> I agree with you that we have to do a lot of rework of previous process record code. But I am not sure it would be productive for us to get working code out and loose the functionality or delay its submission. As Record/Replay is pretty much functional with this set of patches I am hoping that we can do a complete rework if required later on.
>>
>
> If there is something broken related to the submissions, the common
> practise could be one of them below:
>
>   1. Fix them first,
>   2. Document the existing limitations/problems or write a test case to
> kfail it.  In this way, people are aware of this.
>   3. Continue the submission and revisit the problems later.
>
> Personally, I choose one of them, depending on the complexity of fixing
> the existing problems.  This patch series is a large one, and based on
> some existing code.  I would like to fix existing problems first, before
> doing something new, if it doesn't take much time on fixing existing
> problems.  These patches are preparatory, and usually simple.  so they
> have more chances to be reviewed in a timely manner.  These preparatory
> patches set up a context for your large patch series, and the context is
> helpful to understanding your patch series.  As a result, the review
> process may be shortened.
>
> I don't want you to fix existing problems first, or take other actions.
> Just let you know something submitters can do to help maintainers to
> approve patches.
>

Ping! Looking for maintainer's approval for arm process record/replay 
improvement patches.
Pedro Alves Dec. 20, 2013, 12:37 p.m. UTC | #5
On 11/24/2013 11:49 PM, Omair Javaid wrote:

> Patch has been updated after incorporating suggestions. Looking for a final
> commit verdict.
> 
> This patch adds support for recording thumb32 instructions. This patch also
> fixes bugs in arm process record instruction decoding.

It's not clear what this "also fixes bugs" refers to.  Could that part be
something that could be split into it's own patch?

> gdb:
> 
> 2013-11-08  Omair Javaid  <omair.javaid@linaro.org>
> 
> 	* arm-tdep.c (struct arm_mem_r): Use uint32_t for memory address.
> 	(arm_record_unsupported_insn): New function.
> 	(arm_record_coproc_data_proc): Removed.
> 	(thumb2_record_ld_st_multiple): New function.
> 	(thumb2_record_ld_st_dual_ex_tbb): New function.
> 	(thumb2_record_data_proc_sreg_mimm): New function.
> 	(thumb2_record_ps_dest_generic): New function.
> 	(thumb2_record_branch_misc_cntrl): New function.
> 	(thumb2_record_str_single_data): New function.
> 	(thumb2_record_ld_mem_hints): New function.
> 	(thumb2_record_ld_word): New function.
> 	(thumb2_record_lmul_lmla_div): New function.
> 	(thumb2_record_decode_inst_id): New function.
> 	(decode_insn): Add thumb32 instruction handlers.
> 


> +/* Handler for thumb2 load/store multiple instructions.  */
> +
> +static int
> +thumb2_record_ld_st_multiple (insn_decode_record *thumb2_insn_r)
> +{
> +  struct regcache *reg_cache = thumb2_insn_r->regcache;
> +
> +  uint32_t reg_rn, op;
> +  uint32_t 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;
> +
> +  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
> +  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.  */
> +          return arm_record_unsupported_insn (thumb2_insn_r);
> +        }
> +    }
> +  else if(1 == op || 2 == op)

Missing space before parens.

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

Unnecessary parens.

> +            }
> +
> +          thumb2_insn_r->mem_rec_count = register_count;
> +          while (register_count)

          while (register_count > 0)

> +            {
> +              record_buf_mem[(register_count * 2) - 1] = start_address;
> +              record_buf_mem[(register_count * 2) - 2] = 4;

Unnecessary parens.

> +              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 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, reg_rn;
> +
> +  reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
> +  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
> +
> +  if (ARM_PC_REGNUM != 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 long multiply, long multiply accumulate, and
> +   divide instructions.  Return value: -1:record failure ;  0:success.  */

"Returns -1 on failure, 0 on success."

Most of the other functions lack describing the return.  Please update
them too.

> +
> +static int
> +thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
> +{
> +  uint32_t ret = 0;
> +  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.  */

Mention also the -1 on failure.  But, where are these instruction ids
described?  Can this be an enum?

> +
> +static unsigned int
> +thumb2_record_decode_inst_id (uint32_t thumb2_insn)
> +{

> +  return -1;
> +}
>  

> +  /* (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] =
> +  { \

No need for that \.

> +    thumb2_record_ld_st_multiple,       /* 00.  */
> +    thumb2_record_ld_st_dual_ex_tbb,    /* 01.  */
> +    thumb2_record_data_proc_sreg_mimm,  /* 02.  */
> +    arm_record_unsupported_insn,        /* 03.  */
> +    thumb2_record_data_proc_sreg_mimm,  /* 04.  */
> +    thumb2_record_ps_dest_generic,      /* 05.  */
> +    thumb2_record_branch_misc_cntrl,    /* 06.  */
> +    thumb2_record_str_single_data,      /* 07.  */
> +    arm_record_unsupported_insn,        /* 08.  */
> +    thumb2_record_ld_mem_hints,         /* 09.  */
> +    thumb2_record_ld_mem_hints,         /* 10.  */
> +    thumb2_record_ld_word,              /* 11.  */
> +    thumb2_record_ps_dest_generic,      /* 12.  */
> +    thumb2_record_ps_dest_generic,      /* 13.  */
> +    thumb2_record_lmul_lmla_div,        /* 14.  */
> +    arm_record_unsupported_insn         /* 15.  */
> +  };

So, that number was an index into this table?  Why not simply
have thumb2_record_decode_inst_id return a sti_arm_hdl_fp_t directly?
Or better, just have thumb2_record_decode_inst_id call the function
directly (renamed to thumb2_record_handle_insn)?  AFAICS, this
is only used in one place:

> +
> +      insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn);
> +
> +      if (insn_id >= 0)
> +        ret = thumb2_handle_insn[insn_id] (arm_record);
> +      else
> +        {
> +          arm_record_unsupported_insn(arm_record);
> +          ret = -1;
> +        }

That could then just be:

 	 ret = thumb2_record_handle_insn (arm_record->arm_insn);

BTW, "insn" is much more common in GDB as short for instruction
than inst.

> +
>    uint32_t ret = 0;    /* return value: negative:failure   0:success.  */

Please use full sentences instead of that ':' syntax.  Document the
return code in the function's intro instead, and then you don't need
to document it here.  A variable called 'ret' becomes self describing.
diff mbox

Patch

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 7c78a61..ecaced7 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -10618,7 +10618,7 @@  vfp - VFP co-processor."),
 struct arm_mem_r
 {
   uint32_t len;    /* Record length.  */
-  CORE_ADDR addr;  /* Memory address.  */
+  uint32_t addr;   /* Memory address.  */
 };
 
 /* ARM instruction record contains opcode of current insn
@@ -11919,7 +11919,7 @@  arm_record_b_bl (insn_decode_record *arm_insn_r)
 /* Handling opcode 110 insns.  */
 
 static int
-arm_record_coproc (insn_decode_record *arm_insn_r)
+arm_record_unsupported_insn (insn_decode_record *arm_insn_r)
 {
   printf_unfiltered (_("Process record does not support instruction "
                     "0x%0x at address %s.\n"),arm_insn_r->arm_insn,
@@ -12414,6 +12414,584 @@  thumb_record_branch (insn_decode_record *thumb_insn_r)
   return 0;     
 }
 
+/* Handler for thumb2 load/store multiple instructions.  */
+
+static int
+thumb2_record_ld_st_multiple (insn_decode_record *thumb2_insn_r)
+{
+  struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+  uint32_t reg_rn, op;
+  uint32_t 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;
+
+  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+  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.  */
+          return arm_record_unsupported_insn (thumb2_insn_r);
+        }
+    }
+  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 load/store (dual/exclusive) and 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, reg_rn, offset_imm;
+  uint32_t reg_dest1, reg_dest2;
+  uint32_t address, offset_addr;
+  uint32_t record_buf[8], record_buf_mem[8];
+  uint32_t op1, op2, op3;
+  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 (shift register and modified immediate)
+   instructions.  */
+
+static int
+thumb2_record_data_proc_sreg_mimm (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t reg_rd, op;
+  uint32_t record_buf[8];
+
+  op = bits (thumb2_insn_r->arm_insn, 21, 24);
+  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 0;
+}
+
+/* Generic handler for thumb2 instructions which effect destination and PS
+   registers.  */
+
+static int
+thumb2_record_ps_dest_generic (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t reg_rd;
+  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 0;
+}
+
+/* Handler for thumb2 branch and miscellaneous control instructions.  */
+
+static int
+thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t op, op1, op2;
+  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
+        {
+          arm_record_unsupported_insn(thumb2_insn_r);
+          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, reg_rm, offset_imm, shift_imm;
+  uint32_t address, offset_addr;
+  uint32_t record_buf[8], record_buf_mem[8];
+  uint32_t op1, op2;
+
+  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 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, reg_rn;
+
+  reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
+  reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+
+  if (ARM_PC_REGNUM != 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 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 0;
+}
+
+/* Handler for thumb2 long multiply, long multiply accumulate, and
+   divide instructions.  Return value: -1:record failure ;  0:success.  */
+
+static int
+thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
+{
+  uint32_t ret = 0;
+  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/exclusive) and 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 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, abs diff 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.  */
@@ -12452,7 +13030,7 @@  decode_insn (insn_decode_record *arm_record, record_type_t record_type,
     arm_record_ld_st_reg_offset,        /* 011.  */
     arm_record_ld_st_multiple,          /* 100.  */
     arm_record_b_bl,                    /* 101.  */
-    arm_record_coproc,                  /* 110.  */
+    arm_record_unsupported_insn,                  /* 110.  */
     arm_record_coproc_data_proc         /* 111.  */
   };
 
@@ -12469,6 +13047,28 @@  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_multiple,       /* 00.  */
+    thumb2_record_ld_st_dual_ex_tbb,    /* 01.  */
+    thumb2_record_data_proc_sreg_mimm,  /* 02.  */
+    arm_record_unsupported_insn,        /* 03.  */
+    thumb2_record_data_proc_sreg_mimm,  /* 04.  */
+    thumb2_record_ps_dest_generic,      /* 05.  */
+    thumb2_record_branch_misc_cntrl,    /* 06.  */
+    thumb2_record_str_single_data,      /* 07.  */
+    arm_record_unsupported_insn,        /* 08.  */
+    thumb2_record_ld_mem_hints,         /* 09.  */
+    thumb2_record_ld_mem_hints,         /* 10.  */
+    thumb2_record_ld_word,              /* 11.  */
+    thumb2_record_ps_dest_generic,      /* 12.  */
+    thumb2_record_ps_dest_generic,      /* 13.  */
+    thumb2_record_lmul_lmla_div,        /* 14.  */
+    arm_record_unsupported_insn         /* 15.  */
+  };
+
   uint32_t ret = 0;    /* return value: negative:failure   0:success.  */
   uint32_t insn_id = 0;
 
@@ -12503,11 +13103,22 @@  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
+        {
+          arm_record_unsupported_insn(arm_record);
+          ret = -1;
+        }
     }
   else
     {