From patchwork Wed Sep 18 15:37:45 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Omair Javaid X-Patchwork-Id: 20439 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ve0-f197.google.com (mail-ve0-f197.google.com [209.85.128.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 5E753246E9 for ; Wed, 18 Sep 2013 15:38:08 +0000 (UTC) Received: by mail-ve0-f197.google.com with SMTP id jy13sf7573136veb.4 for ; Wed, 18 Sep 2013 08:38:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:mime-version:from:date:message-id :subject:to:cc:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe:content-type; bh=ejJibtM5KD3epYr8nRu/TJWJmX3VqauvNAEyHi/ReTk=; b=kSGn1OsJqSJMNPiJfsLaY0Q0IHmYt1PwJBuMIa+cOlVduNOdF2R0h4udv5i9XP5V/W LF2ujcfvdZSbkctafL7Ev/r6KTz/KRx4qVjKd+98A8rTt3/vNthgeZ73OSZ5KAgtgW15 gxkynWlfMD5O4A+XTJHKbmpUaaZ6CS77EkGMbSEweQ9jQVS0iMCvZCY0I6dNL5dQVLJa FjwY+YRlPhloh6lf+3wuyoh+RwMjtOGekxz3UMJOejrFhWgz+cics3qx6ey/fz/BqdYF NcMU3eabi9ThUE/RVKdsYTLDBU5vMein8qiux6nAouN0UkLVmMUpSgEqF6PbpbOExMpY 6bGQ== X-Gm-Message-State: ALoCoQmCEwnMArrTADICJifxki3EtNj+Z5fsOjttHpJYppBPR0ZvdLLM5mZarJuHUOqM9NtSGt2J X-Received: by 10.236.14.100 with SMTP id c64mr15195372yhc.38.1379518687432; Wed, 18 Sep 2013 08:38:07 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.110.9 with SMTP id hw9ls3260481qeb.16.gmail; Wed, 18 Sep 2013 08:38:07 -0700 (PDT) X-Received: by 10.52.103.101 with SMTP id fv5mr942801vdb.31.1379518687331; Wed, 18 Sep 2013 08:38:07 -0700 (PDT) Received: from mail-vb0-f45.google.com (mail-vb0-f45.google.com [209.85.212.45]) by mx.google.com with ESMTPS id rx3si659049vcb.80.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 18 Sep 2013 08:38:07 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.45 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.45; Received: by mail-vb0-f45.google.com with SMTP id e15so5320338vbg.18 for ; Wed, 18 Sep 2013 08:38:07 -0700 (PDT) X-Received: by 10.52.166.200 with SMTP id zi8mr733181vdb.38.1379518687194; Wed, 18 Sep 2013 08:38:07 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp225112vcz; Wed, 18 Sep 2013 08:38:06 -0700 (PDT) X-Received: by 10.49.50.232 with SMTP id f8mr62277893qeo.63.1379518686527; Wed, 18 Sep 2013 08:38:06 -0700 (PDT) Received: from mail-ob0-f170.google.com (mail-ob0-f170.google.com [209.85.214.170]) by mx.google.com with ESMTPS id w2si1190390qef.11.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 18 Sep 2013 08:38:06 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.214.170 is neither permitted nor denied by best guess record for domain of omair.javaid@linaro.org) client-ip=209.85.214.170; Received: by mail-ob0-f170.google.com with SMTP id va2so7923315obc.29 for ; Wed, 18 Sep 2013 08:38:05 -0700 (PDT) X-Received: by 10.60.70.134 with SMTP id m6mr34682624oeu.14.1379518685518; Wed, 18 Sep 2013 08:38:05 -0700 (PDT) MIME-Version: 1.0 Received: by 10.182.137.135 with HTTP; Wed, 18 Sep 2013 08:37:45 -0700 (PDT) From: Omair Javaid Date: Wed, 18 Sep 2013 16:37:45 +0100 Message-ID: Subject: [PATCH] Record and replay: ARM thumb 32bit instructions support To: gdb-patches@sourceware.org Cc: Patch Tracking X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: omair.javaid@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.45 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , 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 * arm-tdep.c: Adds support for thumb32 instructions in arm record and replay and positive val on fauilure. */ @@ -12469,6 +13172,28 @@ decode_insn (insn_decode_record *arm_rec thumb_record_branch /* 111. */ }; + /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb + instruction. */ + static const sti_arm_hdl_fp_t const thumb2_handle_insn[16] = + { \ + thumb2_record_ld_st_mulitple, /* 00. */ + thumb2_record_ld_st_dual_ex_tbb, /* 01. */ + thumb2_record_data_proc_sreg, /* 02. */ + thumb2_record_coproc, /* 03. */ + thumb2_record_data_proc_mod_imm, /* 04. */ + thumb2_record_data_proc_bin_imm, /* 05. */ + thumb2_record_branch_misc_cntrl, /* 06. */ + thumb2_record_str_single_data, /* 07. */ + thumb2_record_simd_struct_ld_st, /* 08. */ + thumb2_record_ld_mem_hints, /* 09. */ + thumb2_record_ld_mem_hints, /* 10. */ + thumb2_record_ld_word, /* 11. */ + thumb2_record_data_proc_reg, /* 12. */ + thumb2_record_mul_mla_abs_diff, /* 13. */ + thumb2_record_lmul_lmla_div, /* 14. */ + thumb2_record_coproc /* 15. */ + }; + uint32_t ret = 0; /* return value: negative:failure 0:success. */ uint32_t insn_id = 0; @@ -12503,11 +13228,22 @@ decode_insn (insn_decode_record *arm_rec } else if (THUMB2_RECORD == record_type) { - printf_unfiltered (_("Process record doesnt support thumb32 instruction " - "0x%0x at address %s.\n"),arm_record->arm_insn, - paddress (arm_record->gdbarch, - arm_record->this_addr)); - ret = -1; + /* As thumb does not have condition codes, we set negative. */ + arm_record->cond = -1; + insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn); + + if (insn_id > 0) + { + ret = thumb_handle_insn[insn_id] (arm_record); + } + else + { + printf_unfiltered (_("Process record doesnt support instruction " + "0x%0x at address %s.\n"),arm_record->arm_insn, + paddress (arm_record->gdbarch, + arm_record->this_addr)); + ret = -1; + } } else { =================================================================== 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