From patchwork Sun Oct 6 21:16:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Omair Javaid X-Patchwork-Id: 20843 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vb0-f71.google.com (mail-vb0-f71.google.com [209.85.212.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id B12C825DF4 for ; Sun, 6 Oct 2013 21:16:48 +0000 (UTC) Received: by mail-vb0-f71.google.com with SMTP id g17sf12599330vbg.2 for ; Sun, 06 Oct 2013 14:16:48 -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:in-reply-to:references :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=wwx4QeywdUeFId2Vtr4kQY9jQhKtnlN6RiJF5bOjIWg=; b=jHSix+nZKZgejtwkoITsE7DtkTAEHcqmPAfRcQtDQNZULjk3u3kpIrCZ0qvnidWc3f HmGSXh7LM7rYDj3CmSa2li4qBURpV+Rv5xObVTpI8fJRLXZGFtHCSS1Lx3x70g4QKikD z+Dn48wyMG7LVtpKW/BDAq2l+vU/QmD1AZtrSqtQqsgRSRjD2GeOvxFuBw9KHjuX3h1K k4Bv+ZUaqeM0qD5h6j/j2Isy/KtKEppwGfIar9IpSDKU8sdZWUmvWT+Jic0X+j9WInYI yoL+RMYK/P1B/ii/O56UO6OE2RORimfYHbf/1mz7XAQv546wR3yrq1nMAewKhnP9lAMU 9hrQ== X-Received: by 10.236.180.2 with SMTP id i2mr22414450yhm.4.1381094208017; Sun, 06 Oct 2013 14:16:48 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.48.66 with SMTP id j2ls1712659qen.90.gmail; Sun, 06 Oct 2013 14:16:47 -0700 (PDT) X-Received: by 10.58.137.167 with SMTP id qj7mr22848086veb.1.1381094207827; Sun, 06 Oct 2013 14:16:47 -0700 (PDT) Received: from mail-ve0-f170.google.com (mail-ve0-f170.google.com [209.85.128.170]) by mx.google.com with ESMTPS id dt10si6816034vdb.138.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 06 Oct 2013 14:16:47 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.170 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.170; Received: by mail-ve0-f170.google.com with SMTP id c14so3429764vea.15 for ; Sun, 06 Oct 2013 14:16:47 -0700 (PDT) X-Gm-Message-State: ALoCoQnstUTzObP4L4jY/wViueM5NMz6WoyMTFLHhWNcEPH5niw2hP76GYbO+CAvnUQ6mHf5VZiE X-Received: by 10.52.27.243 with SMTP id w19mr18716583vdg.3.1381094207474; Sun, 06 Oct 2013 14:16:47 -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 u4csp80102vcz; Sun, 6 Oct 2013 14:16:46 -0700 (PDT) X-Received: by 10.224.89.73 with SMTP id d9mr23384102qam.5.1381094206119; Sun, 06 Oct 2013 14:16:46 -0700 (PDT) Received: from mail-qe0-f47.google.com (mail-qe0-f47.google.com [209.85.128.47]) by mx.google.com with ESMTPS id dd9si4917802qcb.18.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 06 Oct 2013 14:16:46 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.47 is neither permitted nor denied by best guess record for domain of omair.javaid@linaro.org) client-ip=209.85.128.47; Received: by mail-qe0-f47.google.com with SMTP id b4so4572174qen.20 for ; Sun, 06 Oct 2013 14:16:45 -0700 (PDT) X-Received: by 10.229.47.71 with SMTP id m7mr56535qcf.25.1381094205777; Sun, 06 Oct 2013 14:16:45 -0700 (PDT) MIME-Version: 1.0 Received: by 10.49.87.39 with HTTP; Sun, 6 Oct 2013 14:16:25 -0700 (PDT) In-Reply-To: References: From: Omair Javaid Date: Mon, 7 Oct 2013 02:16:25 +0500 Message-ID: Subject: Re: [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.128.170 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: , On 1 October 2013 14:56, Omair Javaid wrote: > On 18 September 2013 20:37, Omair Javaid 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 >> >> * 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 * arm-tdep.c: Adds support for thumb32 instructions in arm process record. --- gdb/arm-tdep.c | 751 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 745 insertions(+), 6 deletions(-) static int @@ -12469,6 +13171,27 @@ decode_insn (insn_decode_record *arm_record, record_type_t record_type, thumb_record_branch /* 111. */ }; + /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb instruction. */ + static const sti_arm_hdl_fp_t const thumb2_handle_insn[16] = + { \ + thumb2_record_ld_st_mulitple, /* 00. */ + thumb2_record_ld_st_dual_ex_tbb, /* 01. */ + thumb2_record_data_proc_sreg, /* 02. */ + thumb2_record_coproc, /* 03. */ + thumb2_record_data_proc_mod_imm, /* 04. */ + thumb2_record_data_proc_bin_imm, /* 05. */ + thumb2_record_branch_misc_cntrl, /* 06. */ + thumb2_record_str_single_data, /* 07. */ + thumb2_record_simd_struct_ld_st, /* 08. */ + thumb2_record_ld_mem_hints, /* 09. */ + thumb2_record_ld_mem_hints, /* 10. */ + thumb2_record_ld_word, /* 11. */ + thumb2_record_data_proc_reg, /* 12. */ + thumb2_record_mul_mla_abs_diff, /* 13. */ + thumb2_record_lmul_lmla_div, /* 14. */ + thumb2_record_coproc /* 15. */ + }; + uint32_t ret = 0; /* return value: negative:failure 0:success. */ uint32_t insn_id = 0; @@ -12503,11 +13226,27 @@ decode_insn (insn_decode_record *arm_record, record_type_t record_type, } else if (THUMB2_RECORD == record_type) { - printf_unfiltered (_("Process record doesnt support thumb32 instruction " - "0x%0x at address %s.\n"),arm_record->arm_insn, - paddress (arm_record->gdbarch, - arm_record->this_addr)); - ret = -1; + /* As thumb does not have condition codes, we set negative. */ + arm_record->cond = -1; + + /* Swap first half of 32bit thumb instruction with second half */ + arm_record->arm_insn = (arm_record->arm_insn >> 16) | + (arm_record->arm_insn << 16); + + insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn); + + if (insn_id >= 0) + { + ret = thumb2_handle_insn[insn_id] (arm_record); + } + else + { + printf_unfiltered (_("Process record doesnt support instruction " + "0x%0x at address %s.\n"),arm_record->arm_insn, + paddress (arm_record->gdbarch, + arm_record->this_addr)); + ret = -1; + } } else { -- 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. */