This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH] Record and replay: ARM thumb 32bit instructions support
- From: Omair Javaid <omair dot javaid at linaro dot org>
- To: gdb-patches at sourceware dot org
- Cc: Patch Tracking <patches at linaro dot org>
- Date: Mon, 7 Oct 2013 02:16:25 +0500
- Subject: Re: [PATCH] Record and replay: ARM thumb 32bit instructions support
- Authentication-results: sourceware.org; auth=none
- References: <CANW4E-0ErD9CWAOjnvQhn2yaQZpAaDh_quMi0R6VDbM8p8uLtg at mail dot gmail dot com> <CANW4E-3aHm772oQtn=N4FNrZA9dhLaX6+nOyyXPkwkWNbxvXsw at mail dot gmail dot com>
On 1 October 2013 14:56, Omair Javaid <omair.javaid@linaro.org> wrote:
> On 18 September 2013 20:37, Omair Javaid <omair.javaid@linaro.org> wrote:
>> This patch improves gdb record and replay support for arm targets by
>> adding support for 32bit thumb instruction set. Record and replay test
>> suite is disabled for arm targets by default as some instructions and
>> system calls are still not functional. This patch can be tested by
>> recording a simple thumb mode C program on arm targets. It will not
>> work with any programs requiring syscall support or any program that
>> uses instruction not yet decoded by arm process record code. More
>> improvements including test suite improvement will be posted in future
>> patches.
>>
>> gdb/testsuite/ChangeLog:
>>
>> 2013-09-18 Omair Javaid <Omair.Javaid@linaro.org>
>>
>> * arm-tdep.c: Adds support for thumb32 instructions in
>> arm record and replay
>>
>> ===================================================================
>> RCS file: /cvs/src/src/gdb/arm-tdep.c,v
>> retrieving revision 1.381
>> diff -u -p -r1.381 arm-tdep.c
>> --- gdb/arm-tdep.c 24 Jun 2013 22:18:31 -0000 1.381
>> +++ gdb/arm-tdep.c 18 Sep 2013 12:13:34 -0000
>> @@ -12414,6 +12414,709 @@ thumb_record_branch (insn_decode_record
>> return 0;
>> }
>>
>> +/* Handler for thumb2 load/store multiple instructions. */
>> +
>> +static int
>> +thumb2_record_ld_st_mulitple (insn_decode_record *thumb2_insn_r)
>> +{
>> + struct regcache *reg_cache = thumb2_insn_r->regcache;
>> +
>> + uint32_t reg_rn = 0;
>> + uint32_t op = 0, register_bits = 0, register_count = 0;
>> + uint32_t index = 0, start_address = 0;
>> + uint32_t record_buf[24], record_buf_mem[48];
>> +
>> + ULONGEST u_regval = 0;
>> +
>> + op = bits (thumb2_insn_r->arm_insn, 23, 24);
>> +
>> + if (0 == op || 3 == op)
>> + {
>> + if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
>> + {
>> + /* Handle RFE instruction. */
>> + record_buf[0] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 1;
>> + }
>> + else
>> + {
>> + /* Handle SRS instruction after reading banked SP. */
>> + printf_unfiltered (_("Process record does not support instruction "
>> + "0x%0x at address %s.\n"),
>> + thumb2_insn_r->arm_insn,
>> + paddress (thumb2_insn_r->gdbarch,
>> + thumb2_insn_r->this_addr));
>> + return -1;
>> + }
>> + }
>> + else if(1 == op || 2 == op)
>> + {
>> + if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
>> + {
>> + /* Handle LDM/LDMIA/LDMFD and LDMDB/LDMEA instructions. */
>> + register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
>> + while (register_bits)
>> + {
>> + if (register_bits & 0x00000001)
>> + {
>> + record_buf[index++] = register_count;
>> + }
>> + register_count++;
>> + register_bits = register_bits >> 1;
>> + }
>> + record_buf[index++] = reg_rn;
>> + record_buf[index++] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = index;
>> + }
>> + else
>> + {
>> + /* Handle STM/STMIA/STMEA and STMDB/STMFD. */
>> + register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
>> + regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
>> + while (register_bits)
>> + {
>> + if (register_bits & 0x00000001)
>> + {
>> + register_count++;
>> + }
>> + register_bits = register_bits >> 1;
>> + }
>> +
>> + if (1 == op)
>> + {
>> + /* Start address calculation for LDMDB/LDMEA. */
>> + start_address = u_regval;
>> + }
>> + else if (2 == op)
>> + {
>> + /* Start address calculation for LDMDB/LDMEA. */
>> + start_address = (u_regval) - (register_count * 4);
>> + }
>> +
>> + thumb2_insn_r->mem_rec_count = register_count;
>> + while (register_count)
>> + {
>> + record_buf_mem[(register_count * 2) - 1] = start_address;
>> + record_buf_mem[(register_count * 2) - 2] = 4;
>> + start_address = start_address + 4;
>> + register_count--;
>> + }
>> + record_buf[0] = reg_rn;
>> + record_buf[1] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> + }
>> + }
>> +
>> + MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
>> + record_buf_mem);
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> + return 0;
>> +}
>> +
>> +/* Handler for thumb2 ld/st dual, ld/st exclusive, table branch
>> + instructions. */
>> +
>> +static int
>> +thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
>> +{
>> + struct regcache *reg_cache = thumb2_insn_r->regcache;
>> +
>> + uint32_t reg_rd = 0, reg_rn = 0, offset_imm = 0;
>> + uint32_t reg_dest1 = 0, reg_dest2 = 0;
>> + uint32_t address = 0, offset_addr = 0;
>> + uint32_t record_buf[8], record_buf_mem[8];
>> + uint32_t op1 = 0, op2 = 0, op3 = 0;
>> + LONGEST s_word;
>> +
>> + ULONGEST u_regval[2];
>> +
>> + op1 = bits (thumb2_insn_r->arm_insn, 23, 24);
>> + op2 = bits (thumb2_insn_r->arm_insn, 20, 21);
>> + op3 = bits (thumb2_insn_r->arm_insn, 4, 7);
>> +
>> + if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
>> + {
>> + if(!(1 == op1 && 1 == op2 && (0 == op3 || 1 == op3)))
>> + {
>> + reg_dest1 = bits (thumb2_insn_r->arm_insn, 12, 15);
>> + record_buf[0] = reg_dest1;
>> + record_buf[1] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> + }
>> +
>> + if (3 == op2 || (op1 & 2) || (1 == op1 && 1 == op2 && 7 == op3))
>> + {
>> + reg_dest2 = bits (thumb2_insn_r->arm_insn, 8, 11);
>> + record_buf[2] = reg_dest2;
>> + thumb2_insn_r->reg_rec_count = 3;
>> + }
>> + }
>> + else
>> + {
>> + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
>> + regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
>> +
>> + if (0 == op1 && 0 == op2)
>> + {
>> + /* Handle STREX. */
>> + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
>> + address = u_regval[0] + (offset_imm * 4);
>> + record_buf_mem[0] = 4;
>> + record_buf_mem[1] = address;
>> + thumb2_insn_r->mem_rec_count = 1;
>> + reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
>> + record_buf[0] = reg_rd;
>> + thumb2_insn_r->reg_rec_count = 1;
>> + }
>> + else if (1 == op1 && 0 == op2)
>> + {
>> + reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
>> + record_buf[0] = reg_rd;
>> + thumb2_insn_r->reg_rec_count = 1;
>> + address = u_regval[0];
>> + record_buf_mem[1] = address;
>> +
>> + if (4 == op3)
>> + {
>> + /* Handle STREXB. */
>> + record_buf_mem[0] = 1;
>> + thumb2_insn_r->mem_rec_count = 1;
>> + }
>> + else if (5 == op3)
>> + {
>> + /* Handle STREXH. */
>> + record_buf_mem[0] = 2 ;
>> + thumb2_insn_r->mem_rec_count = 1;
>> + }
>> + else if (7 == op3)
>> + {
>> + /* Handle STREXD */
>> + address = u_regval[0];
>> + record_buf_mem[0] = 4;
>> + record_buf_mem[2] = 4;
>> + record_buf_mem[3] = address + 4;
>> + thumb2_insn_r->mem_rec_count = 2;
>> + }
>> + }
>> + else
>> + {
>> + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
>> +
>> + if (bit (thumb2_insn_r->arm_insn, 24))
>> + {
>> + if (bit (thumb2_insn_r->arm_insn, 23))
>> + {
>> + offset_addr = u_regval[0] + (offset_imm * 4);
>> + }
>> + else
>> + {
>> + offset_addr = u_regval[0] - (offset_imm * 4);
>> + }
>> + address = offset_addr;
>> + }
>> + else
>> + {
>> + address = u_regval[0];
>> + }
>> +
>> + record_buf_mem[0] = 4;
>> + record_buf_mem[1] = address;
>> + record_buf_mem[2] = 4;
>> + record_buf_mem[3] = address + 4;
>> + thumb2_insn_r->mem_rec_count = 2;
>> + record_buf[0] = reg_rn;
>> + thumb2_insn_r->reg_rec_count = 1;
>> + }
>> + }
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> + MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
>> + record_buf_mem);
>> + return 0;
>> +}
>> +
>> +/* Handler for thumb2 data-processing shifted register instructions. */
>> +
>> +static int
>> +thumb2_record_data_proc_sreg (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t ret = 0; /* Return value: -1:record failure ; 0:success. */
>> + uint32_t reg_rd = 0;
>> + uint32_t op = 0;
>> + uint32_t record_buf[8];
>> +
>> + op = bits (thumb2_insn_r->arm_insn, 8, 11);
>> + reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
>> +
>> + if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
>> + {
>> + record_buf[0] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 1;
>> + }
>> + else
>> + {
>> + record_buf[0] = reg_rd;
>> + record_buf[1] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> + }
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> +
>> + return ret;
>> +}
>> +
>> +/* Handler for thumb2 co-processor instructions. */
>> +
>> +static int
>> +thumb2_record_coproc (insn_decode_record *thumb2_insn_r)
>> +{
>> + printf_unfiltered (_("Process record does not support instruction "
>> + "0x%0x at address %s.\n"),thumb2_insn_r->arm_insn,
>> + paddress (thumb2_insn_r->gdbarch,
>> + thumb2_insn_r->this_addr));
>> +
>> + return -1;
>> +}
>> +
>> +/* Handler for thumb2 data-processing (modified immediate) instructions. */
>> +
>> +static int
>> +thumb2_record_data_proc_mod_imm (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t ret = 0 ; /* Return value: -1:record failure ; 0:success. */
>> + uint32_t reg_rd = 0;
>> + uint32_t op = 0;
>> + uint32_t record_buf[8];
>> +
>> + op = bits (thumb2_insn_r->arm_insn, 8, 11);
>> + reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
>> +
>> + if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
>> + {
>> + record_buf[0] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 1;
>> + }
>> + else
>> + {
>> + record_buf[0] = reg_rd;
>> + record_buf[1] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> + }
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> +
>> + return ret;
>> +}
>> +
>> +/* Handler for thumb2 data-processing plain binary immediate instructions. */
>> +
>> +static int
>> +thumb2_record_data_proc_bin_imm (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t ret = 0; /* Return value: -1:record failure ; 0:success. */
>> + uint32_t reg_rd = 0;
>> + uint32_t record_buf[8];
>> +
>> + reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
>> +
>> + record_buf[0] = reg_rd;
>> + record_buf[1] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> +
>> + return ret;
>> +}
>> +
>> +/* Handler for thumb2 branch and miscellaneous control instructions. */
>> +
>> +static int
>> +thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t op = 0, op1 = 0, op2 = 0;
>> + uint32_t record_buf[8];
>> +
>> + op = bits (thumb2_insn_r->arm_insn, 20, 26);
>> + op1 = bits (thumb2_insn_r->arm_insn, 12, 14);
>> + op2 = bits (thumb2_insn_r->arm_insn, 8, 11);
>> +
>> + /* Handle MSR insn. */
>> + if (!(op1 & 0x2) && 0x38 == op)
>> + {
>> + if (!(op2 & 0x3))
>> + {
>> + /* CPSR is going to be changed. */
>> + record_buf[0] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 1;
>> + }
>> + else
>> + {
>> + /* SPSR is going to be changed. */
>> + printf_unfiltered (_("Process record does not support instruction "
>> + "0x%0x at address %s.\n"),
>> + thumb2_insn_r->arm_insn,
>> + paddress (thumb2_insn_r->gdbarch,
>> + thumb2_insn_r->this_addr));
>> + return -1;
>> + }
>> + }
>> + else if (4 == (op1 & 0x5) || 5 == (op1 & 0x5))
>> + {
>> + /* BLX. */
>> + record_buf[0] = ARM_PS_REGNUM;
>> + record_buf[1] = ARM_LR_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> + }
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> +
>> + return 0;
>> +}
>> +
>> +/* Handler for thumb2 store single data item instructions. */
>> +
>> +static int
>> +thumb2_record_str_single_data (insn_decode_record *thumb2_insn_r)
>> +{
>> + struct regcache *reg_cache = thumb2_insn_r->regcache;
>> +
>> + uint32_t reg_rn = 0, reg_rm = 0, offset_imm = 0, shift_imm = 0;
>> + uint32_t address = 0, offset_addr = 0;
>> + uint32_t record_buf[8], record_buf_mem[8];
>> + uint32_t op1 = 0, op2 = 0;
>> +
>> + ULONGEST u_regval[2];
>> +
>> + op1 = bits (thumb2_insn_r->arm_insn, 21, 23);
>> + op2 = bits (thumb2_insn_r->arm_insn, 6, 11);
>> + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
>> + regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
>> +
>> + if (bit (thumb2_insn_r->arm_insn, 23))
>> + {
>> + /* T2 encoding. */
>> + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 11);
>> + offset_addr = u_regval[0] + offset_imm;
>> + address = offset_addr;
>> + }
>> + else
>> + {
>> + /* T3 encoding. */
>> + if ((0 == op1 || 1 == op1 || 2 == op1) && !(op2 & 0x20))
>> + {
>> + /* Handle STRB (register). */
>> + reg_rm = bits (thumb2_insn_r->arm_insn, 0, 3);
>> + regcache_raw_read_unsigned (reg_cache, reg_rm, &u_regval[1]);
>> + shift_imm = bits (thumb2_insn_r->arm_insn, 4, 5);
>> + offset_addr = u_regval[1] << shift_imm;
>> + address = u_regval[0] + offset_addr;
>> + }
>> + else
>> + {
>> + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
>> + if (bit (thumb2_insn_r->arm_insn, 10))
>> + {
>> + if (bit (thumb2_insn_r->arm_insn, 9))
>> + {
>> + offset_addr = u_regval[0] + offset_imm;
>> + }
>> + else
>> + {
>> + offset_addr = u_regval[0] - offset_imm;
>> + }
>> + address = offset_addr;
>> + }
>> + else
>> + {
>> + address = u_regval[0];
>> + }
>> + }
>> + }
>> +
>> + switch (op1)
>> + {
>> + /* Store byte instructions. */
>> + case 4:
>> + case 0:
>> + record_buf_mem[0] = 1;
>> + break;
>> + /* Store half word instructions. */
>> + case 1:
>> + case 5:
>> + record_buf_mem[0] = 2;
>> + break;
>> + /* Store word instructions. */
>> + case 2:
>> + case 6:
>> + record_buf_mem[0] = 4;
>> + break;
>> +
>> + default:
>> + gdb_assert_not_reached ("no decoding pattern found");
>> + break;
>> + }
>> +
>> + record_buf_mem[1] = address;
>> + thumb2_insn_r->mem_rec_count = 1;
>> + record_buf[0] = reg_rn;
>> + thumb2_insn_r->reg_rec_count = 1;
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> + MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
>> + record_buf_mem);
>> + return 0;
>> +}
>> +
>> +/* Handler for thumb2 SIMD element and structure load/store instructions. */
>> +
>> +static int
>> +thumb2_record_simd_struct_ld_st (insn_decode_record *thumb2_insn_r)
>> +{
>> + printf_unfiltered (_("Process record does not support instruction "
>> + "0x%0x at address %s.\n"), thumb2_insn_r->arm_insn,
>> + paddress (thumb2_insn_r->gdbarch,
>> + thumb2_insn_r->this_addr));
>> + return -1;
>> +}
>> +
>> +/* Handler for thumb2 load memory hints instructions. */
>> +
>> +static int
>> +thumb2_record_ld_mem_hints (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t record_buf[8];
>> + uint32_t reg_rt = 0, reg_rn=0;
>> +
>> + reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
>> + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
>> +
>> + if (15 != reg_rt)
>> + {
>> + record_buf[0] = reg_rt;
>> + record_buf[1] = reg_rn;
>> + record_buf[2] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 3;
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> + return 0;
>> + }
>> +
>> + return -1;
>> +}
>> +
>> +/* Handler for thumb2 load word instructions. */
>> +
>> +static int
>> +thumb2_record_ld_word (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t ret = 0; /* Return value: -1:record failure ; 0:success. */
>> + uint32_t opcode1 = 0, opcode2 = 0;
>> + uint32_t record_buf[8];
>> +
>> + record_buf[0] = bits (thumb2_insn_r->arm_insn, 12, 15);
>> + record_buf[1] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> +
>> + return ret;
>> +}
>> +
>> +/* Handler for thumb2 data processing (register) instructions. */
>> +
>> +static int
>> +thumb2_record_data_proc_reg (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t ret = 0; /* Return value: -1:record failure ; 0:success. */
>> + uint32_t opcode1 = 0, opcode2 = 0;
>> + uint32_t record_buf[8];
>> +
>> + record_buf[0] = bits (thumb2_insn_r->arm_insn, 8, 11);
>> + record_buf[1] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> +
>> + return ret;
>> +}
>> +
>> +/* Handler for thumb2 multiply, multiply accumulate, and
>> + absolute difference instructions. */
>> +
>> +static int
>> +thumb2_record_mul_mla_abs_diff (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t ret = 0; /* Return value: -1:record failure ; 0:success. */
>> + uint32_t opcode1 = 0, opcode2 = 0;
>> + uint32_t record_buf[8];
>> +
>> + record_buf[0] = bits (thumb2_insn_r->arm_insn, 8, 11);
>> + record_buf[1] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 2;
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> +
>> + return ret;
>> +}
>> +
>> +/* Handler for thumb2 long multiply, long multiply accumulate, and
>> + divide instructions. */
>> +
>> +static int
>> +thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
>> +{
>> + uint32_t ret = 0; /* Return value: -1:record failure ; 0:success. */
>> + uint32_t opcode1 = 0, opcode2 = 0;
>> + uint32_t record_buf[8];
>> + uint32_t reg_src1 = 0;
>> +
>> + opcode1 = bits (thumb2_insn_r->arm_insn, 20, 22);
>> + opcode2 = bits (thumb2_insn_r->arm_insn, 4, 7);
>> +
>> + if (0 == opcode1 || 2 == opcode1 || (opcode1 >= 4 && opcode1 <= 6))
>> + {
>> + /* Handle SMULL, UMULL, SMULAL and
>> + SMLAL(S), SMULL(S), UMLAL(S), UMULL(S). */
>> + record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
>> + record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
>> + record_buf[2] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 3;
>> + }
>> + else if (1 == opcode1 || 3 == opcode2)
>> + {
>> + /* Handle SDIV and UDIV. */
>> + record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
>> + record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
>> + record_buf[2] = ARM_PS_REGNUM;
>> + thumb2_insn_r->reg_rec_count = 3;
>> + }
>> + else
>> + {
>> + ret = -1;
>> + }
>> +
>> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
>> + record_buf);
>> +
>> + return ret;
>> +}
>> +
>> +/* Decodes thumb2 instruction type and return an instruction id. */
>> +
>> +static unsigned int
>> +thumb2_record_decode_inst_id (uint32_t thumb2_insn)
>> +{
>> + uint32_t op = 0;
>> + uint32_t op1 = 0;
>> + uint32_t op2 = 0;
>> +
>> + op = bit (thumb2_insn, 15);
>> + op1 = bits (thumb2_insn, 27, 28);
>> + op2 = bits (thumb2_insn, 20, 26);
>> +
>> + if (op1 == 0x01)
>> + {
>> + if (!(op2 & 0x64 ))
>> + {
>> + /* Load/store multiple instruction. */
>> + return 0;
>> + }
>> + else if (!((op2 & 0x64) ^ 0x04))
>> + {
>> + /* Load/store dual/exclusive and table branch instructions. */
>> + return 1;
>> + }
>> + else if (!((op2 & 0x20) ^ 0x20))
>> + {
>> + /* Data-processing (shifted register). */
>> + return 2;
>> + }
>> + else if (op2 & 0x40)
>> + {
>> + /* Co-processor instructions. */
>> + return 3;
>> + }
>> + }
>> + else if (op1 == 0x02)
>> + {
>> + if (op)
>> + {
>> + /* Branches and miscellaneous control instructions. */
>> + return 6;
>> + }
>> + else if (op2 & 0x20)
>> + {
>> + /* Data-processing (plain binary immediate) instruction. */
>> + return 5;
>> + }
>> + else
>> + {
>> + /* Data-processing (modified immediate). */
>> + return 4;
>> + }
>> + }
>> + else if (op1 == 0x03)
>> + {
>> + if (!(op2 & 0x71 ))
>> + {
>> + /* Store single data item. */
>> + return 7;
>> + }
>> + else if (!((op2 & 0x71) ^ 0x10))
>> + {
>> + /* Advanced SIMD element or structure load/store instructions. */
>> + return 8;
>> + }
>> + else if (!((op2 & 0x67) ^ 0x01))
>> + {
>> + /* Load byte, memory hints instruction. */
>> + return 9;
>> + }
>> + else if (!((op2 & 0x67) ^ 0x03))
>> + {
>> + /* Load halfword, memory hints instruction. */
>> + return 10;
>> + }
>> + else if (!((op2 & 0x67) ^ 0x05))
>> + {
>> + /* Load word instruction. */
>> + return 11;
>> + }
>> + else if (!((op2 & 0x70) ^ 0x20))
>> + {
>> + /* Data-processing (register) instruction. */
>> + return 12;
>> + }
>> + else if (!((op2 & 0x78) ^ 0x30))
>> + {
>> + /* Multiply, multiply accumulate, absolute difference instruction. */
>> + return 13;
>> + }
>> + else if (!((op2 & 0x78) ^ 0x38))
>> + {
>> + /* Long multiply, long multiply accumulate, and divide. */
>> + return 14;
>> + }
>> + else if (op2 & 0x40)
>> + {
>> + /* Co-processor instructions. */
>> + return 15;
>> + }
>> + }
>> +
>> + return -1;
>> +}
>>
>> /* Extracts arm/thumb/thumb2 insn depending on the size, and returns
>> 0 on success
>> and positive val on fauilure. */
>> @@ -12469,6 +13172,28 @@ decode_insn (insn_decode_record *arm_rec
>> thumb_record_branch /* 111. */
>> };
>>
>> + /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
>> + instruction. */
>> + static const sti_arm_hdl_fp_t const thumb2_handle_insn[16] =
>> + { \
>> + thumb2_record_ld_st_mulitple, /* 00. */
>> + thumb2_record_ld_st_dual_ex_tbb, /* 01. */
>> + thumb2_record_data_proc_sreg, /* 02. */
>> + thumb2_record_coproc, /* 03. */
>> + thumb2_record_data_proc_mod_imm, /* 04. */
>> + thumb2_record_data_proc_bin_imm, /* 05. */
>> + thumb2_record_branch_misc_cntrl, /* 06. */
>> + thumb2_record_str_single_data, /* 07. */
>> + thumb2_record_simd_struct_ld_st, /* 08. */
>> + thumb2_record_ld_mem_hints, /* 09. */
>> + thumb2_record_ld_mem_hints, /* 10. */
>> + thumb2_record_ld_word, /* 11. */
>> + thumb2_record_data_proc_reg, /* 12. */
>> + thumb2_record_mul_mla_abs_diff, /* 13. */
>> + thumb2_record_lmul_lmla_div, /* 14. */
>> + thumb2_record_coproc /* 15. */
>> + };
>> +
>> uint32_t ret = 0; /* return value: negative:failure 0:success. */
>> uint32_t insn_id = 0;
>>
>> @@ -12503,11 +13228,22 @@ decode_insn (insn_decode_record *arm_rec
>> }
>> else if (THUMB2_RECORD == record_type)
>> {
>> - printf_unfiltered (_("Process record doesnt support thumb32 instruction "
>> - "0x%0x at address %s.\n"),arm_record->arm_insn,
>> - paddress (arm_record->gdbarch,
>> - arm_record->this_addr));
>> - ret = -1;
>> + /* As thumb does not have condition codes, we set negative. */
>> + arm_record->cond = -1;
>> + insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn);
>> +
>> + if (insn_id > 0)
>> + {
>> + ret = thumb_handle_insn[insn_id] (arm_record);
>> + }
>> + else
>> + {
>> + printf_unfiltered (_("Process record doesnt support instruction "
>> + "0x%0x at address %s.\n"),arm_record->arm_insn,
>> + paddress (arm_record->gdbarch,
>> + arm_record->this_addr));
>> + ret = -1;
>> + }
>> }
>> else
>> {
>
> There is an update to this patch and a bunch of testsuite results
> indicating a good number of test cases passing. I ll be posting them
> soon.
The patch has been updated with some minor fixes. Reverse debug
testsuite shows significant improvement. Here are the reverse debug
test suite statistics taken on Linux chromebook (arm v7) hardware:
* Without thumb32 Patch
Native GDB (with support process record enabled) # of expected passes 32
Native GDB (with support process record and reverse debug enabled) #
of expected passes 518
Remote GDB (with support process record enabled) # of expected passes 506
Remote GDB (with support process record and reverse debug enabled) #
of expected passes 506
* With thumb32 Patch
Native GDB (with support process record enabled) # of expected passes
105 (73 new passed tests after thumb32 patch)
Native GDB (with support process record and reverse debug enabled) #
of expected passes 1133 (627 new passed tests after thumb32 patch)
Remote GDB (with support process record enabled) # of expected passes
973 (467 new passed tests after thumb32 patch)
Remote GDB (with support process record and reverse debug enabled) #
of expected passes 978 (472 new passed tests after thumb32 patch)
gdb/testsuite/ChangeLog:
2013-10-06 Omair Javaid <Omair.Javaid@linaro.org>
* arm-tdep.c: Adds support for thumb32 instructions in
arm process record.
---
gdb/arm-tdep.c | 751 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 745 insertions(+), 6 deletions(-)
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 7c78a61..0427bdb 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -12414,8 +12414,710 @@ thumb_record_branch (insn_decode_record *thumb_insn_r)
return 0;
}
+/* Handler for thumb2 load/store multiple instructions */
-/* Extracts arm/thumb/thumb2 insn depending on the size, and returns
0 on success
+static int
+thumb2_record_ld_st_mulitple (insn_decode_record *thumb2_insn_r)
+{
+ struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+ uint32_t reg_rn = 0;
+ uint32_t op = 0, register_bits = 0, register_count = 0;
+ uint32_t index = 0, start_address = 0;
+ uint32_t record_buf[24], record_buf_mem[48];
+
+ ULONGEST u_regval = 0;
+
+ op = bits (thumb2_insn_r->arm_insn, 23, 24);
+
+ if (0 == op || 3 == op)
+ {
+ if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ /* Handle RFE instruction */
+ record_buf[0] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ /* Handle SRS instruction after reading banked SP */
+ printf_unfiltered (_("Process record does not support instruction "
+ "0x%0x at address %s.\n"),
+ thumb2_insn_r->arm_insn,
+ paddress (thumb2_insn_r->gdbarch,
+ thumb2_insn_r->this_addr));
+ return -1;
+ }
+ }
+ else if(1 == op || 2 == op)
+ {
+ if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ /* Handle LDM/LDMIA/LDMFD and LDMDB/LDMEA instructions*/
+ register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ {
+ record_buf[index++] = register_count;
+ }
+ register_count++;
+ register_bits = register_bits >> 1;
+ }
+ record_buf[index++] = reg_rn;
+ record_buf[index++] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = index;
+ }
+ else
+ {
+ /* Handle STM/STMIA/STMEA and STMDB/STMFD */
+ register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
+ regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ {
+ register_count++;
+ }
+ register_bits = register_bits >> 1;
+ }
+
+ if (1 == op)
+ {
+ /* Start address calculation for LDMDB/LDMEA */
+ start_address = u_regval;
+ }
+ else if (2 == op)
+ {
+ /* Start address calculation for LDMDB/LDMEA */
+ start_address = (u_regval) - (register_count * 4);
+ }
+
+ thumb2_insn_r->mem_rec_count = register_count;
+ while (register_count)
+ {
+ record_buf_mem[(register_count * 2) - 1] = start_address;
+ record_buf_mem[(register_count * 2) - 2] = 4;
+ start_address = start_address + 4;
+ register_count--;
+ }
+ record_buf[0] = reg_rn;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+ }
+
+ MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+ record_buf_mem);
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return 0;
+}
+
+/* Handler for thumb2 ld/st dual, ld/st exclusive, table branch instructions */
+
+static int
+thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
+{
+ struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+ uint32_t reg_rd = 0, reg_rn = 0, offset_imm = 0;
+ uint32_t reg_dest1 = 0, reg_dest2 = 0;
+ uint32_t address = 0, offset_addr = 0;
+ uint32_t record_buf[8], record_buf_mem[8];
+ uint32_t op1 = 0, op2 = 0, op3 = 0;
+ LONGEST s_word;
+
+ ULONGEST u_regval[2];
+
+ op1 = bits (thumb2_insn_r->arm_insn, 23, 24);
+ op2 = bits (thumb2_insn_r->arm_insn, 20, 21);
+ op3 = bits (thumb2_insn_r->arm_insn, 4, 7);
+
+ if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ if(!(1 == op1 && 1 == op2 && (0 == op3 || 1 == op3)))
+ {
+ reg_dest1 = bits (thumb2_insn_r->arm_insn, 12, 15);
+ record_buf[0] = reg_dest1;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+
+ if (3 == op2 || (op1 & 2) || (1 == op1 && 1 == op2 && 7 == op3))
+ {
+ reg_dest2 = bits (thumb2_insn_r->arm_insn, 8, 11);
+ record_buf[2] = reg_dest2;
+ thumb2_insn_r->reg_rec_count = 3;
+ }
+ }
+ else
+ {
+ reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
+
+ if (0 == op1 && 0 == op2)
+ {
+ /* Handle STREX */
+ offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+ address = u_regval[0] + (offset_imm * 4);
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = address;
+ thumb2_insn_r->mem_rec_count = 1;
+ reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
+ record_buf[0] = reg_rd;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else if (1 == op1 && 0 == op2)
+ {
+ reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
+ record_buf[0] = reg_rd;
+ thumb2_insn_r->reg_rec_count = 1;
+ address = u_regval[0];
+ record_buf_mem[1] = address;
+
+ if (4 == op3)
+ {
+ /* Handle STREXB */
+ record_buf_mem[0] = 1;
+ thumb2_insn_r->mem_rec_count = 1;
+ }
+ else if (5 == op3)
+ {
+ /* Handle STREXH */
+ record_buf_mem[0] = 2 ;
+ thumb2_insn_r->mem_rec_count = 1;
+ }
+ else if (7 == op3)
+ {
+ /* Handle STREXD */
+ address = u_regval[0];
+ record_buf_mem[0] = 4;
+ record_buf_mem[2] = 4;
+ record_buf_mem[3] = address + 4;
+ thumb2_insn_r->mem_rec_count = 2;
+ }
+ }
+ else
+ {
+ offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+
+ if (bit (thumb2_insn_r->arm_insn, 24))
+ {
+ if (bit (thumb2_insn_r->arm_insn, 23))
+ {
+ offset_addr = u_regval[0] + (offset_imm * 4);
+ }
+ else
+ {
+ offset_addr = u_regval[0] - (offset_imm * 4);
+ }
+ address = offset_addr;
+ }
+ else
+ {
+ address = u_regval[0];
+ }
+
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = address;
+ record_buf_mem[2] = 4;
+ record_buf_mem[3] = address + 4;
+ thumb2_insn_r->mem_rec_count = 2;
+ record_buf[0] = reg_rn;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+ record_buf_mem);
+ return 0;
+}
+
+/* Handler for thumb2 data-processing shifted register instructions */
+
+static int
+thumb2_record_data_proc_sreg (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t ret = 0; /* Return value: -1:record failure ; 0:success */
+ uint32_t reg_rd = 0;
+ uint32_t op = 0;
+ uint32_t record_buf[8];
+
+ op = bits (thumb2_insn_r->arm_insn, 8, 11);
+ reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+ if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
+ {
+ record_buf[0] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ record_buf[0] = reg_rd;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+
+ return ret;
+}
+
+/* Handler for thumb2 co-processor instructions */
+
+static int
+thumb2_record_coproc (insn_decode_record *thumb2_insn_r)
+{
+ printf_unfiltered (_("Process record does not support instruction "
+ "0x%0x at address %s.\n"),thumb2_insn_r->arm_insn,
+ paddress (thumb2_insn_r->gdbarch,
+ thumb2_insn_r->this_addr));
+
+ return -1;
+}
+
+/* Handler for thumb2 data-processing (modified immediate) instructions */
+
+static int
+thumb2_record_data_proc_mod_imm (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t ret = 0 ; /* Return value: -1:record failure ; 0:success */
+ uint32_t reg_rd = 0;
+ uint32_t op = 0;
+ uint32_t record_buf[8];
+
+ op = bits (thumb2_insn_r->arm_insn, 8, 11);
+ reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+ if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
+ {
+ record_buf[0] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ record_buf[0] = reg_rd;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+
+ return ret;
+}
+
+/* Handler for thumb2 data-processing (plain binary immediate) instructions */
+
+static int
+thumb2_record_data_proc_bin_imm (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t ret = 0; /* Return value: -1:record failure ; 0:success */
+ uint32_t reg_rd = 0;
+ uint32_t record_buf[8];
+
+ reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+ record_buf[0] = reg_rd;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+
+ return ret;
+}
+
+/* Handler for thumb2 branch and miscellaneous control instructions */
+
+static int
+thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t op = 0, op1 = 0, op2 = 0;
+ uint32_t record_buf[8];
+
+ op = bits (thumb2_insn_r->arm_insn, 20, 26);
+ op1 = bits (thumb2_insn_r->arm_insn, 12, 14);
+ op2 = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+ /* Handle MSR insn. */
+ if (!(op1 & 0x2) && 0x38 == op)
+ {
+ if (!(op2 & 0x3))
+ {
+ /* CPSR is going to be changed. */
+ record_buf[0] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ /* SPSR is going to be changed. */
+ printf_unfiltered (_("Process record does not support instruction "
+ "0x%0x at address %s.\n"),
+ thumb2_insn_r->arm_insn,
+ paddress (thumb2_insn_r->gdbarch,
+ thumb2_insn_r->this_addr));
+ return -1;
+ }
+ }
+ else if (4 == (op1 & 0x5) || 5 == (op1 & 0x5))
+ {
+ /* BLX. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+
+ return 0;
+}
+
+/* Handler for thumb2 store single data item instructions */
+
+static int
+thumb2_record_str_single_data (insn_decode_record *thumb2_insn_r)
+{
+ struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+ uint32_t reg_rn = 0, reg_rm = 0, offset_imm = 0, shift_imm = 0;
+ uint32_t address = 0, offset_addr = 0;
+ uint32_t record_buf[8], record_buf_mem[8];
+ uint32_t op1 = 0, op2 = 0;
+
+ ULONGEST u_regval[2];
+
+ op1 = bits (thumb2_insn_r->arm_insn, 21, 23);
+ op2 = bits (thumb2_insn_r->arm_insn, 6, 11);
+ reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
+
+ if (bit (thumb2_insn_r->arm_insn, 23))
+ {
+ /* T2 encoding */
+ offset_imm = bits (thumb2_insn_r->arm_insn, 0, 11);
+ offset_addr = u_regval[0] + offset_imm;
+ address = offset_addr;
+ }
+ else
+ {
+ /* T3 encoding */
+ if ((0 == op1 || 1 == op1 || 2 == op1) && !(op2 & 0x20))
+ {
+ /* Handle STRB (register) */
+ reg_rm = bits (thumb2_insn_r->arm_insn, 0, 3);
+ regcache_raw_read_unsigned (reg_cache, reg_rm, &u_regval[1]);
+ shift_imm = bits (thumb2_insn_r->arm_insn, 4, 5);
+ offset_addr = u_regval[1] << shift_imm;
+ address = u_regval[0] + offset_addr;
+ }
+ else
+ {
+ offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+ if (bit (thumb2_insn_r->arm_insn, 10))
+ {
+ if (bit (thumb2_insn_r->arm_insn, 9))
+ {
+ offset_addr = u_regval[0] + offset_imm;
+ }
+ else
+ {
+ offset_addr = u_regval[0] - offset_imm;
+ }
+ address = offset_addr;
+ }
+ else
+ {
+ address = u_regval[0];
+ }
+ }
+ }
+
+ switch (op1)
+ {
+ /* Store byte instructions */
+ case 4:
+ case 0:
+ record_buf_mem[0] = 1;
+ break;
+ /* Store half word instructions */
+ case 1:
+ case 5:
+ record_buf_mem[0] = 2;
+ break;
+ /* Store word instructions */
+ case 2:
+ case 6:
+ record_buf_mem[0] = 4;
+ break;
+
+ default:
+ gdb_assert_not_reached ("no decoding pattern found");
+ break;
+ }
+
+ record_buf_mem[1] = address;
+ thumb2_insn_r->mem_rec_count = 1;
+ record_buf[0] = reg_rn;
+ thumb2_insn_r->reg_rec_count = 1;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+ record_buf_mem);
+ return 0;
+}
+
+/* Handler for thumb2 SIMD element and structure load/store instructions */
+
+static int
+thumb2_record_simd_struct_ld_st (insn_decode_record *thumb2_insn_r)
+{
+ printf_unfiltered (_("Process record does not support instruction "
+ "0x%0x at address %s.\n"), thumb2_insn_r->arm_insn,
+ paddress (thumb2_insn_r->gdbarch,
+ thumb2_insn_r->this_addr));
+ return -1;
+}
+
+/* Handler for thumb2 load memory hints instructions */
+
+static int
+thumb2_record_ld_mem_hints (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t record_buf[8];
+ uint32_t reg_rt = 0, reg_rn=0;
+
+ reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
+ reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+
+ if (15 != reg_rt)
+ {
+ record_buf[0] = reg_rt;
+ record_buf[1] = reg_rn;
+ record_buf[2] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 3;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return 0;
+ }
+
+ return -1;
+}
+
+/* Handler for thumb2 load word instructions */
+
+static int
+thumb2_record_ld_word (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t ret = 0; /* Return value: -1:record failure ; 0:success */
+ uint32_t opcode1 = 0, opcode2 = 0;
+ uint32_t record_buf[8];
+
+ record_buf[0] = bits (thumb2_insn_r->arm_insn, 12, 15);
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+
+ return ret;
+}
+
+/* Handler for thumb2 data processing (register) instructions */
+
+static int
+thumb2_record_data_proc_reg (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t ret = 0; /* Return value: -1:record failure ; 0:success */
+ uint32_t opcode1 = 0, opcode2 = 0;
+ uint32_t record_buf[8];
+
+ record_buf[0] = bits (thumb2_insn_r->arm_insn, 8, 11);
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+
+ return ret;
+}
+
+/* Handler for thumb2 multiply, multiply accumulate, and
+ absolute difference instructions */
+
+static int
+thumb2_record_mul_mla_abs_diff (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t ret = 0; /* Return value: -1:record failure ; 0:success */
+ uint32_t opcode1 = 0, opcode2 = 0;
+ uint32_t record_buf[8];
+
+ record_buf[0] = bits (thumb2_insn_r->arm_insn, 8, 11);
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+
+ return ret;
+}
+
+/* Handler for thumb2 long multiply, long multiply accumulate, and
+ divide instructions */
+
+static int
+thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t ret = 0; /* Return value: -1:record failure ; 0:success */
+ uint32_t opcode1 = 0, opcode2 = 0;
+ uint32_t record_buf[8];
+ uint32_t reg_src1 = 0;
+
+ opcode1 = bits (thumb2_insn_r->arm_insn, 20, 22);
+ opcode2 = bits (thumb2_insn_r->arm_insn, 4, 7);
+
+ if (0 == opcode1 || 2 == opcode1 || (opcode1 >= 4 && opcode1 <= 6))
+ {
+ /* Handle SMULL, UMULL, SMULAL */
+ /* Handle SMLAL(S), SMULL(S), UMLAL(S), UMULL(S). */
+ record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
+ record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
+ record_buf[2] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 3;
+ }
+ else if (1 == opcode1 || 3 == opcode2)
+ {
+ /* Handle SDIV and UDIV */
+ record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
+ record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
+ record_buf[2] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 3;
+ }
+ else
+ {
+ ret = -1;
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+
+ return ret;
+}
+
+/* Decodes thumb2 instruction type and return an instruction id */
+
+static unsigned int
+thumb2_record_decode_inst_id (uint32_t thumb2_insn)
+{
+ uint32_t op = 0;
+ uint32_t op1 = 0;
+ uint32_t op2 = 0;
+
+ op = bit (thumb2_insn, 15);
+ op1 = bits (thumb2_insn, 27, 28);
+ op2 = bits (thumb2_insn, 20, 26);
+
+ if (op1 == 0x01)
+ {
+ if (!(op2 & 0x64 ))
+ {
+ /* Load/store multiple instruction */
+ return 0;
+ }
+ else if (!((op2 & 0x64) ^ 0x04))
+ {
+ /* Load/store dual, load/store exclusive, table branch instruction */
+ return 1;
+ }
+ else if (!((op2 & 0x20) ^ 0x20))
+ {
+ /* Data-processing (shifted register) */
+ return 2;
+ }
+ else if (op2 & 0x40)
+ {
+ /* Co-processor instructions */
+ return 3;
+ }
+ }
+ else if (op1 == 0x02)
+ {
+ if (op)
+ {
+ /* Branches and miscellaneous control instructions */
+ return 6;
+ }
+ else if (op2 & 0x20)
+ {
+ /* Data-processing (plain binary immediate) instruction */
+ return 5;
+ }
+ else
+ {
+ /* Data-processing (modified immediate) */
+ return 4;
+ }
+ }
+ else if (op1 == 0x03)
+ {
+ if (!(op2 & 0x71 ))
+ {
+ /* Store single data item */
+ return 7;
+ }
+ else if (!((op2 & 0x71) ^ 0x10))
+ {
+ /* Advanced SIMD element or structure load/store instructions */
+ return 8;
+ }
+ else if (!((op2 & 0x67) ^ 0x01))
+ {
+ /* Load byte, memory hints instruction */
+ return 9;
+ }
+ else if (!((op2 & 0x67) ^ 0x03))
+ {
+ /* Load halfword, memory hints instruction */
+ return 10;
+ }
+ else if (!((op2 & 0x67) ^ 0x05))
+ {
+ /* Load word instruction */
+ return 11;
+ }
+ else if (!((op2 & 0x70) ^ 0x20))
+ {
+ /* Data-processing (register) instruction */
+ return 12;
+ }
+ else if (!((op2 & 0x78) ^ 0x30))
+ {
+ /* Multiply, multiply accumulate, absolute difference instruction */
+ return 13;
+ }
+ else if (!((op2 & 0x78) ^ 0x38))
+ {
+ /* Long multiply, long multiply accumulate, and divide */
+ return 14;
+ }
+ else if (op2 & 0x40)
+ {
+ /* Co-processor instructions */
+ return 15;
+ }
+ }
+
+ return -1;
+}
+
+/* Extracts arm/thumb/thumb2 insn depending on the size, and returns
0 on success
and positive val on fauilure. */
static int
@@ -12469,6 +13171,27 @@ decode_insn (insn_decode_record *arm_record,
record_type_t record_type,
thumb_record_branch /* 111. */
};
+ /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
instruction. */
+ static const sti_arm_hdl_fp_t const thumb2_handle_insn[16] =
+ { \
+ thumb2_record_ld_st_mulitple, /* 00. */
+ thumb2_record_ld_st_dual_ex_tbb, /* 01. */
+ thumb2_record_data_proc_sreg, /* 02. */
+ thumb2_record_coproc, /* 03. */
+ thumb2_record_data_proc_mod_imm, /* 04. */
+ thumb2_record_data_proc_bin_imm, /* 05. */
+ thumb2_record_branch_misc_cntrl, /* 06. */
+ thumb2_record_str_single_data, /* 07. */
+ thumb2_record_simd_struct_ld_st, /* 08. */
+ thumb2_record_ld_mem_hints, /* 09. */
+ thumb2_record_ld_mem_hints, /* 10. */
+ thumb2_record_ld_word, /* 11. */
+ thumb2_record_data_proc_reg, /* 12. */
+ thumb2_record_mul_mla_abs_diff, /* 13. */
+ thumb2_record_lmul_lmla_div, /* 14. */
+ thumb2_record_coproc /* 15. */
+ };
+
uint32_t ret = 0; /* return value: negative:failure 0:success. */
uint32_t insn_id = 0;
@@ -12503,11 +13226,27 @@ decode_insn (insn_decode_record *arm_record,
record_type_t record_type,
}
else if (THUMB2_RECORD == record_type)
{
- printf_unfiltered (_("Process record doesnt support thumb32 instruction "
- "0x%0x at address %s.\n"),arm_record->arm_insn,
- paddress (arm_record->gdbarch,
- arm_record->this_addr));
- ret = -1;
+ /* As thumb does not have condition codes, we set negative. */
+ arm_record->cond = -1;
+
+ /* Swap first half of 32bit thumb instruction with second half */
+ arm_record->arm_insn = (arm_record->arm_insn >> 16) |
+ (arm_record->arm_insn << 16);
+
+ insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn);
+
+ if (insn_id >= 0)
+ {
+ ret = thumb2_handle_insn[insn_id] (arm_record);
+ }
+ else
+ {
+ printf_unfiltered (_("Process record doesnt support instruction "
+ "0x%0x at address %s.\n"),arm_record->arm_insn,
+ paddress (arm_record->gdbarch,
+ arm_record->this_addr));
+ ret = -1;
+ }
}
else
{
--