From patchwork Fri Nov 8 03:19:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Omair Javaid X-Patchwork-Id: 21408 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ie0-f200.google.com (mail-ie0-f200.google.com [209.85.223.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 7603B25E16 for ; Fri, 8 Nov 2013 03:20:01 +0000 (UTC) Received: by mail-ie0-f200.google.com with SMTP id aq17sf4977098iec.11 for ; Thu, 07 Nov 2013 19:20:01 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:message-id:date:from:user-agent :mime-version:to:cc:subject:references:in-reply-to:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe:content-type :content-transfer-encoding; bh=KlYzFSMZOUfVB0EGd4YJcbFwWr9wJB4edoOjUPAO//Y=; b=k/0bjEEO47uACFNGhC9T6lM36bkf3OcjdaEAWzOnTFCmLK51e7b9LNbLF+jyTyrr1A l1F5kSKE/M6uCvT4o5rfkR0kg4QNs8i/stFi5udfjSu4DZ1O4ZFUQWRncRpZbVXEkbLN 8dvG4PjfO/AzKYLqiObW6EHiStJJrDNIjlQ/QtFlVAjsiJ1SsGMlP/7BmikAe6D4QWwf WkGXs4whCdnj6TrPXy//XI5NeDb3NfZearw5AEPTxE943dKVBOlB4o14Qn1EIrZZdI9o dsPLvtSf/pm9ha+jR8Zyelgp9+AWuj2MqN0qtjoKqi73Mccx2eri8Hs2E44INURvEUdu TYog== X-Gm-Message-State: ALoCoQkZLCGP/P776+mRYdxt2nT2l99ez3qM0bzQ0Ms2vwllg96HOQrVM9/9nYDAocAA7Zob6JCN X-Received: by 10.182.191.8 with SMTP id gu8mr3974112obc.8.1383880801206; Thu, 07 Nov 2013 19:20:01 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.25.40 with SMTP id z8ls1406603qef.81.gmail; Thu, 07 Nov 2013 19:20:01 -0800 (PST) X-Received: by 10.220.184.70 with SMTP id cj6mr9695174vcb.23.1383880801081; Thu, 07 Nov 2013 19:20:01 -0800 (PST) Received: from mail-vc0-f180.google.com (mail-vc0-f180.google.com [209.85.220.180]) by mx.google.com with ESMTPS id tj6si2965925vcb.118.2013.11.07.19.20.00 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 07 Nov 2013 19:20:00 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.180 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.180; Received: by mail-vc0-f180.google.com with SMTP id lc6so1014768vcb.39 for ; Thu, 07 Nov 2013 19:20:00 -0800 (PST) X-Received: by 10.52.227.6 with SMTP id rw6mr8095379vdc.19.1383880800775; Thu, 07 Nov 2013 19:20:00 -0800 (PST) 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 u4csp6vcz; Thu, 7 Nov 2013 19:19:59 -0800 (PST) X-Received: by 10.15.100.198 with SMTP id bn46mr13086731eeb.11.1383880798308; Thu, 07 Nov 2013 19:19:58 -0800 (PST) Received: from mail-ea0-f173.google.com (mail-ea0-f173.google.com [209.85.215.173]) by mx.google.com with ESMTPS id h46si5365350eex.73.2013.11.07.19.19.56 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 07 Nov 2013 19:19:58 -0800 (PST) Received-SPF: neutral (google.com: 209.85.215.173 is neither permitted nor denied by best guess record for domain of omair.javaid@linaro.org) client-ip=209.85.215.173; Received: by mail-ea0-f173.google.com with SMTP id g10so769836eak.32 for ; Thu, 07 Nov 2013 19:19:56 -0800 (PST) X-Received: by 10.14.107.68 with SMTP id n44mr13512433eeg.26.1383880796360; Thu, 07 Nov 2013 19:19:56 -0800 (PST) Received: from [192.168.1.1] ([182.185.163.58]) by mx.google.com with ESMTPSA id e13sm17053969eeu.4.2013.11.07.19.19.53 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 07 Nov 2013 19:19:55 -0800 (PST) Message-ID: <527C5856.50500@linaro.org> Date: Fri, 08 Nov 2013 08:19:50 +0500 From: Omair Javaid User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.1.0 MIME-Version: 1.0 To: Yao Qi CC: gdb-patches@sourceware.org, Patch Tracking Subject: Re: [PATCH 1/2] GDB process record and reverse debugging improvements for arm*-linux* References: <526884D5.309@codesourcery.com> In-Reply-To: <526884D5.309@codesourcery.com> 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.220.180 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 Thu 24 Oct 2013 07:24:21 AM PKT, Yao Qi wrote: > On 10/24/2013 08:09 AM, Omair Javaid wrote: >> gdb: >> >> 2013-10-24 Omair Javaid >> >> * arm-tdep.c (struct arm_mem_r): Update. > > "Update" is too general. Please describe what is changed. > >> (arm_record_coproc_data_proc): Update. >> (thumb_record_ldm_stm_swi): Update. >> (thumb2_record_ld_st_multiple): New function. >> (thumb2_record_ld_st_dual_ex_tbb): New function. >> (thumb2_record_data_proc_sreg_mimm): New function. >> (thumb2_record_unsupported_insn): New function. >> (thumb2_record_ps_dest_generic): New function. >> (thumb2_record_branch_misc_cntrl): New function. >> (thumb2_record_str_single_data): New function. >> (thumb2_record_ld_mem_hints): New function. >> (thumb2_record_ld_word): New function. >> (thumb2_record_lmul_lmla_div): New function. >> (thumb2_record_decode_inst_id): New function. >> (decode_insn): Update. > > Each line of changelog should be prefixed by tab. > >> + { >> + if (tdep->arm_syscall_record != NULL) >> + { >> + ULONGEST svc_operand, svc_number; >> >> - printf_unfiltered (_("Process record does not support instruction " >> + svc_operand = (0x00ffffff & arm_insn_r->arm_insn); >> + >> + if (svc_operand) /* OABI. */ >> + { >> + svc_number = svc_operand - 0x900000; >> + } > > Unnecessary braces. > >> + else /* EABI. */ >> + { >> + regcache_raw_read_unsigned (reg_cache, 7, &svc_number); >> + } > > > Unnecessary braces. > >> + >> + ret = tdep->arm_syscall_record(reg_cache, svc_number); >> + } >> + else >> + { >> + printf_unfiltered (_("no syscall record support\n")); >> + ret = -1; >> + } >> + } >> + else >> + { >> + printf_unfiltered (_("Process record does not support >> instruction " >> "0x%0x at address >> %s.\n"),arm_insn_r->arm_insn, >> paddress (arm_insn_r->gdbarch, >> arm_insn_r->this_addr)); > > I find this statements appear many times, probably, we can move it > into a function named arm_record_unsupported_insn. > >> + ret = -1; >> + } >> return ret; >> } >> >> @@ -12361,9 +12377,10 @@ thumb_record_ldm_stm_swi (insn_decode_re >> else if (0x1F == opcode1) >> { >> /* Handle arm syscall insn. */ >> - if (tdep->arm_swi_record != NULL) >> + if (tdep->arm_syscall_record != NULL) >> { >> - ret = tdep->arm_swi_record(reg_cache); >> + regcache_raw_read_unsigned (reg_cache, 7, &u_regval); >> + ret = tdep->arm_syscall_record(reg_cache, u_regval); > > Space is needed before "(". This change belongs to support recording > syscall instructions, and IWBN to move this part to patch 2/2. > >> } >> else >> { >> @@ -12414,6 +12431,630 @@ thumb_record_branch (insn_decode_record >> return 0; >> } >> >> +/* Handler for thumb2 load/store multiple instructions. */ >> + >> +static int >> +thumb2_record_ld_st_multiple (insn_decode_record *thumb2_insn_r) >> +{ >> + struct regcache *reg_cache = thumb2_insn_r->regcache; >> + >> + uint32_t reg_rn, op; >> + uint32_t register_bits = 0, register_count = 0; >> + uint32_t index = 0, start_address = 0; >> + uint32_t record_buf[24], record_buf_mem[48]; >> + >> + ULONGEST u_regval = 0; >> + >> + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19); >> + op = bits (thumb2_insn_r->arm_insn, 23, 24); >> + >> + if (0 == op || 3 == op) >> + { >> + if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM)) >> + { >> + /* Handle RFE instruction. */ >> + record_buf[0] = ARM_PS_REGNUM; >> + thumb2_insn_r->reg_rec_count = 1; >> + } >> + else >> + { >> + /* Handle SRS instruction after reading banked SP. */ >> + 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)); > > Use thumb2_record_unsupported_insn? > >> + 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; >> + } > > Unnecessary braces. > >> + 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++; >> + } > > Unnecessary braces. > >> + 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. */ > > Looks your mailer wraps the patch. See > https://sourceware.org/gdb/wiki/ContributionChecklist#Submitting_patches > on how to adjust your mailer. > >> + >> +/* Handler for thumb2 data processing (shift register and modified >> immediate) >> + instructions. */ >> + >> +static int >> +thumb2_record_data_proc_sreg_mimm (insn_decode_record *thumb2_insn_r) >> +{ >> + uint32_t ret = 0; /* Return value: -1:record failure ; >> 0:success. */ > > This function always return 0. > >> + uint32_t reg_rd, op; >> + uint32_t record_buf[8]; >> + >> + op = bits (thumb2_insn_r->arm_insn, 21, 24); >> + reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11); >> + >> + if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd) >> + { >> + record_buf[0] = ARM_PS_REGNUM; >> + thumb2_insn_r->reg_rec_count = 1; >> + } >> + else >> + { >> + record_buf[0] = reg_rd; >> + record_buf[1] = ARM_PS_REGNUM; >> + thumb2_insn_r->reg_rec_count = 2; >> + } >> + >> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, >> + record_buf); >> + >> + return ret; >> +} >> + > >> + >> +/* Generic handler for thumb2 instructions which need to save PS and >> + destination registers is saved. Handles multiply, multiply >> accumulate, > > Two spaces after period. > >> + and absolute difference instructions. Also handles data-processing > > and here. > >> + (register and plain binary immediate) instructions. */ >> + >> +static int >> +thumb2_record_ps_dest_generic (insn_decode_record *thumb2_insn_r) >> +{ >> + uint32_t ret = 0; /* Return value: -1:record failure ; >> 0:success. */ > > Document the meaning of return value in function header comment and > remove this line of comment. > >> + >> +/* Handler for thumb2 branch and miscellaneous control >> instructions. */ >> + >> +static int >> +thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r) >> +{ >> + uint32_t op, op1, op2; >> + uint32_t record_buf[8]; >> + >> + op = bits (thumb2_insn_r->arm_insn, 20, 26); >> + op1 = bits (thumb2_insn_r->arm_insn, 12, 14); >> + op2 = bits (thumb2_insn_r->arm_insn, 8, 11); >> + >> + /* Handle MSR insn. */ >> + if (!(op1 & 0x2) && 0x38 == op) >> + { >> + if (!(op2 & 0x3)) >> + { >> + /* CPSR is going to be changed. */ >> + record_buf[0] = ARM_PS_REGNUM; >> + thumb2_insn_r->reg_rec_count = 1; >> + } >> + else >> + { >> + /* 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)); > > Use thumb2_record_unsupported_insn? > >> + return -1; >> + } >> + } >> + else if (4 == (op1 & 0x5) || 5 == (op1 & 0x5)) >> + { >> + /* BLX. */ >> + record_buf[0] = ARM_PS_REGNUM; >> + record_buf[1] = ARM_LR_REGNUM; >> + thumb2_insn_r->reg_rec_count = 2; >> + } >> + >> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, >> + record_buf); >> + >> + return 0; >> +} >> + >> +/* Handler for thumb2 store single data item instructions. */ >> + >> +static int >> +thumb2_record_str_single_data (insn_decode_record *thumb2_insn_r) >> +{ >> + struct regcache *reg_cache = thumb2_insn_r->regcache; >> + >> + uint32_t reg_rn, reg_rm, offset_imm, shift_imm; >> + uint32_t address, offset_addr; >> + uint32_t record_buf[8], record_buf_mem[8]; >> + uint32_t op1, op2; >> + >> + ULONGEST u_regval[2]; >> + >> + op1 = bits (thumb2_insn_r->arm_insn, 21, 23); >> + op2 = bits (thumb2_insn_r->arm_insn, 6, 11); >> + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19); >> + regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]); >> + >> + if (bit (thumb2_insn_r->arm_insn, 23)) >> + { >> + /* T2 encoding. */ >> + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 11); >> + offset_addr = u_regval[0] + offset_imm; >> + address = offset_addr; >> + } >> + else >> + { >> + /* T3 encoding. */ >> + if ((0 == op1 || 1 == op1 || 2 == op1) && !(op2 & 0x20)) >> + { >> + /* Handle STRB (register). */ >> + reg_rm = bits (thumb2_insn_r->arm_insn, 0, 3); >> + regcache_raw_read_unsigned (reg_cache, reg_rm, &u_regval[1]); >> + shift_imm = bits (thumb2_insn_r->arm_insn, 4, 5); >> + offset_addr = u_regval[1] << shift_imm; >> + address = u_regval[0] + offset_addr; >> + } >> + else >> + { >> + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7); >> + if (bit (thumb2_insn_r->arm_insn, 10)) >> + { >> + if (bit (thumb2_insn_r->arm_insn, 9)) >> + { >> + offset_addr = u_regval[0] + offset_imm; >> + } > > Unnecessary braces. > >> + else >> + { >> + offset_addr = u_regval[0] - offset_imm; >> + } >> + address = offset_addr; >> + } >> + else >> + { >> + address = u_regval[0]; >> + } > > Unnecessary braces. > >> + } >> + } >> + >> + switch (op1) >> + { >> + /* Store byte instructions. */ >> + case 4: >> + case 0: >> + record_buf_mem[0] = 1; >> + break; >> + /* Store half word instructions. */ >> + case 1: >> + case 5: >> + record_buf_mem[0] = 2; >> + break; >> + /* Store word instructions. */ >> + case 2: >> + case 6: >> + record_buf_mem[0] = 4; >> + break; >> + >> + default: >> + gdb_assert_not_reached ("no decoding pattern found"); >> + break; >> + } >> + >> + record_buf_mem[1] = address; >> + thumb2_insn_r->mem_rec_count = 1; >> + record_buf[0] = reg_rn; >> + thumb2_insn_r->reg_rec_count = 1; >> + >> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, >> + record_buf); >> + MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count, >> + record_buf_mem); >> + return 0; >> +} >> + >> +/* Handler for thumb2 load memory hints instructions. */ >> + >> +static int >> +thumb2_record_ld_mem_hints (insn_decode_record *thumb2_insn_r) >> +{ >> + uint32_t record_buf[8]; >> + uint32_t reg_rt, reg_rn; >> + >> + reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15); >> + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19); >> + >> + if (15 != reg_rt) > > Replace 15 with ARM_PC_REGNUM. > >> + { >> + 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; > > Is PC allowed to be used in load memory hints? If reference manual > says PC is not allowed, we don't have to worry about "reg_rt == 15". > >> +} >> + >> +/* 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. */ > > Looks this function always return 0. > >> + 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; > > "return 0;" > >> +} >> + >> +/* 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. */ > > Move this line of comment to function header comment. > >> + 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; >> + } > > Unncessary braces. > >> + >> + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, >> + record_buf); >> + >> + return ret; >> +} >> + > >> >> /* Extracts arm/thumb/thumb2 insn depending on the size, and returns >> 0 on success >> and positive val on fauilure. */ >> @@ -12469,6 +13110,27 @@ decode_insn (insn_decode_record *arm_rec >> thumb_record_branch /* 111. */ >> }; >> >> + /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb >> instruction. */ >> + static const sti_arm_hdl_fp_t const thumb2_handle_insn[16] = >> + { \ >> + thumb2_record_ld_st_multiple, /* 00. */ >> + thumb2_record_ld_st_dual_ex_tbb, /* 01. */ >> + thumb2_record_data_proc_sreg_mimm, /* 02. */ >> + thumb2_record_unsupported_insn, /* 03. */ >> + thumb2_record_data_proc_sreg_mimm, /* 04. */ >> + thumb2_record_ps_dest_generic, /* 05. */ >> + thumb2_record_branch_misc_cntrl, /* 06. */ >> + thumb2_record_str_single_data, /* 07. */ >> + thumb2_record_unsupported_insn, /* 08. */ >> + thumb2_record_ld_mem_hints, /* 09. */ >> + thumb2_record_ld_mem_hints, /* 10. */ >> + thumb2_record_ld_word, /* 11. */ >> + thumb2_record_ps_dest_generic, /* 12. */ >> + thumb2_record_ps_dest_generic, /* 13. */ >> + thumb2_record_lmul_lmla_div, /* 14. */ >> + thumb2_record_unsupported_insn /* 15. */ >> + }; >> + >> uint32_t ret = 0; /* return value: negative:failure >> 0:success. */ >> uint32_t insn_id = 0; >> >> @@ -12503,11 +13165,27 @@ 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; >> + >> + /* 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); >> + } > > Unnessary braces. > >> + 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; >> + } > > Use thumb2_record_unsupported_insn? > Here's is an updated patch. This patch adds support for recording thumb32 instructions. This patch also fixes bugs in arm process record instruction decoding. gdb: 2013-11-08 Omair Javaid * arm-tdep.c (struct arm_mem_r): Use uint32_t for memory address. (arm_record_unsupported_insn): New function. (arm_record_coproc_data_proc): Removed. (thumb2_record_ld_st_multiple): New function. (thumb2_record_ld_st_dual_ex_tbb): New function. (thumb2_record_data_proc_sreg_mimm): New function. (thumb2_record_ps_dest_generic): New function. (thumb2_record_branch_misc_cntrl): New function. (thumb2_record_str_single_data): New function. (thumb2_record_ld_mem_hints): New function. (thumb2_record_ld_word): New function. (thumb2_record_lmul_lmla_div): New function. (thumb2_record_decode_inst_id): New function. (decode_insn): Add thumb32 instruction handlers. + } + } + + return -1; +} /* Extracts arm/thumb/thumb2 insn depending on the size, and returns 0 on success and positive val on fauilure. */ @@ -12452,7 +13034,7 @@ decode_insn (insn_decode_record *arm_rec arm_record_ld_st_reg_offset, /* 011. */ arm_record_ld_st_multiple, /* 100. */ arm_record_b_bl, /* 101. */ - arm_record_coproc, /* 110. */ + arm_record_unsupported_insn, /* 110. */ arm_record_coproc_data_proc /* 111. */ }; @@ -12469,6 +13051,27 @@ decode_insn (insn_decode_record *arm_rec thumb_record_branch /* 111. */ }; + /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb instruction. */ + static const sti_arm_hdl_fp_t const thumb2_handle_insn[16] = + { \ + thumb2_record_ld_st_multiple, /* 00. */ + thumb2_record_ld_st_dual_ex_tbb, /* 01. */ + thumb2_record_data_proc_sreg_mimm, /* 02. */ + arm_record_unsupported_insn, /* 03. */ + thumb2_record_data_proc_sreg_mimm, /* 04. */ + thumb2_record_ps_dest_generic, /* 05. */ + thumb2_record_branch_misc_cntrl, /* 06. */ + thumb2_record_str_single_data, /* 07. */ + arm_record_unsupported_insn, /* 08. */ + thumb2_record_ld_mem_hints, /* 09. */ + thumb2_record_ld_mem_hints, /* 10. */ + thumb2_record_ld_word, /* 11. */ + thumb2_record_ps_dest_generic, /* 12. */ + thumb2_record_ps_dest_generic, /* 13. */ + thumb2_record_lmul_lmla_div, /* 14. */ + arm_record_unsupported_insn /* 15. */ + }; + uint32_t ret = 0; /* return value: negative:failure 0:success. */ uint32_t insn_id = 0; @@ -12503,11 +13106,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; + + /* Swap first half of 32bit thumb instruction with second half. */ + arm_record->arm_insn = (arm_record->arm_insn >> 16) | + (arm_record->arm_insn << 16); + + insn_id = thumb2_record_decode_inst_id (arm_record->arm_insn); + + if (insn_id >= 0) + ret = thumb2_handle_insn[insn_id] (arm_record); + else + { + arm_record_unsupported_insn(arm_record); + ret = -1; + } } else { Index: gdb/arm-tdep.c =================================================================== 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 7 Nov 2013 23:52:43 -0000 @@ -10618,7 +10618,7 @@ vfp - VFP co-processor."), struct arm_mem_r { uint32_t len; /* Record length. */ - CORE_ADDR addr; /* Memory address. */ + uint32_t addr; /* Memory address. */ }; /* ARM instruction record contains opcode of current insn @@ -11919,7 +11919,7 @@ arm_record_b_bl (insn_decode_record *arm /* Handling opcode 110 insns. */ static int -arm_record_coproc (insn_decode_record *arm_insn_r) +arm_record_unsupported_insn (insn_decode_record *arm_insn_r) { printf_unfiltered (_("Process record does not support instruction " "0x%0x at address %s.\n"),arm_insn_r->arm_insn, @@ -12414,6 +12414,588 @@ thumb_record_branch (insn_decode_record return 0; } +/* Handler for thumb2 load/store multiple instructions. */ + +static int +thumb2_record_ld_st_multiple (insn_decode_record *thumb2_insn_r) +{ + struct regcache *reg_cache = thumb2_insn_r->regcache; + + uint32_t reg_rn, op; + uint32_t register_bits = 0, register_count = 0; + uint32_t index = 0, start_address = 0; + uint32_t record_buf[24], record_buf_mem[48]; + + ULONGEST u_regval = 0; + + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19); + op = bits (thumb2_insn_r->arm_insn, 23, 24); + + if (0 == op || 3 == op) + { + if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM)) + { + /* Handle RFE instruction. */ + record_buf[0] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 1; + } + else + { + /* Handle SRS instruction after reading banked SP. */ + return arm_record_unsupported_insn (thumb2_insn_r); + } + } + else if(1 == op || 2 == op) + { + if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM)) + { + /* Handle LDM/LDMIA/LDMFD and LDMDB/LDMEA instructions. */ + register_bits = bits (thumb2_insn_r->arm_insn, 0, 15); + while (register_bits) + { + if (register_bits & 0x00000001) + record_buf[index++] = register_count; + + register_count++; + register_bits = register_bits >> 1; + } + record_buf[index++] = reg_rn; + record_buf[index++] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = index; + } + else + { + /* Handle STM/STMIA/STMEA and STMDB/STMFD. */ + register_bits = bits (thumb2_insn_r->arm_insn, 0, 15); + regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval); + while (register_bits) + { + if (register_bits & 0x00000001) + register_count++; + + register_bits = register_bits >> 1; + } + + if (1 == op) + { + /* Start address calculation for LDMDB/LDMEA. */ + start_address = u_regval; + } + else if (2 == op) + { + /* Start address calculation for LDMDB/LDMEA. */ + start_address = (u_regval) - (register_count * 4); + } + + thumb2_insn_r->mem_rec_count = register_count; + while (register_count) + { + record_buf_mem[(register_count * 2) - 1] = start_address; + record_buf_mem[(register_count * 2) - 2] = 4; + start_address = start_address + 4; + register_count--; + } + record_buf[0] = reg_rn; + record_buf[1] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 2; + } + } + + MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count, + record_buf_mem); + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + return 0; +} + +/* Handler for thumb2 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, reg_rn, offset_imm; + uint32_t reg_dest1, reg_dest2; + uint32_t address, offset_addr; + uint32_t record_buf[8], record_buf_mem[8]; + uint32_t op1, op2, op3; + LONGEST s_word; + + ULONGEST u_regval[2]; + + op1 = bits (thumb2_insn_r->arm_insn, 23, 24); + op2 = bits (thumb2_insn_r->arm_insn, 20, 21); + op3 = bits (thumb2_insn_r->arm_insn, 4, 7); + + if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM)) + { + if(!(1 == op1 && 1 == op2 && (0 == op3 || 1 == op3))) + { + reg_dest1 = bits (thumb2_insn_r->arm_insn, 12, 15); + record_buf[0] = reg_dest1; + record_buf[1] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 2; + } + + if (3 == op2 || (op1 & 2) || (1 == op1 && 1 == op2 && 7 == op3)) + { + reg_dest2 = bits (thumb2_insn_r->arm_insn, 8, 11); + record_buf[2] = reg_dest2; + thumb2_insn_r->reg_rec_count = 3; + } + } + else + { + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19); + regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]); + + if (0 == op1 && 0 == op2) + { + /* Handle STREX. */ + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7); + address = u_regval[0] + (offset_imm * 4); + record_buf_mem[0] = 4; + record_buf_mem[1] = address; + thumb2_insn_r->mem_rec_count = 1; + reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3); + record_buf[0] = reg_rd; + thumb2_insn_r->reg_rec_count = 1; + } + else if (1 == op1 && 0 == op2) + { + reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3); + record_buf[0] = reg_rd; + thumb2_insn_r->reg_rec_count = 1; + address = u_regval[0]; + record_buf_mem[1] = address; + + if (4 == op3) + { + /* Handle STREXB. */ + record_buf_mem[0] = 1; + thumb2_insn_r->mem_rec_count = 1; + } + else if (5 == op3) + { + /* Handle STREXH. */ + record_buf_mem[0] = 2 ; + thumb2_insn_r->mem_rec_count = 1; + } + else if (7 == op3) + { + /* Handle STREXD. */ + address = u_regval[0]; + record_buf_mem[0] = 4; + record_buf_mem[2] = 4; + record_buf_mem[3] = address + 4; + thumb2_insn_r->mem_rec_count = 2; + } + } + else + { + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7); + + if (bit (thumb2_insn_r->arm_insn, 24)) + { + if (bit (thumb2_insn_r->arm_insn, 23)) + { + offset_addr = u_regval[0] + (offset_imm * 4); + } + else + { + offset_addr = u_regval[0] - (offset_imm * 4); + } + address = offset_addr; + } + else + { + address = u_regval[0]; + } + + record_buf_mem[0] = 4; + record_buf_mem[1] = address; + record_buf_mem[2] = 4; + record_buf_mem[3] = address + 4; + thumb2_insn_r->mem_rec_count = 2; + record_buf[0] = reg_rn; + thumb2_insn_r->reg_rec_count = 1; + } + } + + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count, + record_buf_mem); + return 0; +} + +/* Handler for thumb2 data processing (shift register and modified immediate) + instructions. */ + +static int +thumb2_record_data_proc_sreg_mimm (insn_decode_record *thumb2_insn_r) +{ + uint32_t reg_rd, op; + uint32_t record_buf[8]; + + op = bits (thumb2_insn_r->arm_insn, 21, 24); + reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11); + + if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd) + { + record_buf[0] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 1; + } + else + { + record_buf[0] = reg_rd; + record_buf[1] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 2; + } + + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + return 0; +} + +/* Generic handler for thumb2 instructions which effect destination and PS + registers. */ + +static int +thumb2_record_ps_dest_generic (insn_decode_record *thumb2_insn_r) +{ + uint32_t reg_rd; + uint32_t record_buf[8]; + + reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11); + + record_buf[0] = reg_rd; + record_buf[1] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 2; + + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + return 0; +} + +/* Handler for thumb2 branch and miscellaneous control instructions. */ + +static int +thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r) +{ + uint32_t op, op1, op2; + uint32_t record_buf[8]; + + op = bits (thumb2_insn_r->arm_insn, 20, 26); + op1 = bits (thumb2_insn_r->arm_insn, 12, 14); + op2 = bits (thumb2_insn_r->arm_insn, 8, 11); + + /* Handle MSR insn. */ + if (!(op1 & 0x2) && 0x38 == op) + { + if (!(op2 & 0x3)) + { + /* CPSR is going to be changed. */ + record_buf[0] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 1; + } + else + { + arm_record_unsupported_insn(thumb2_insn_r); + return -1; + } + } + else if (4 == (op1 & 0x5) || 5 == (op1 & 0x5)) + { + /* BLX. */ + record_buf[0] = ARM_PS_REGNUM; + record_buf[1] = ARM_LR_REGNUM; + thumb2_insn_r->reg_rec_count = 2; + } + + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + return 0; +} + +/* Handler for thumb2 store single data item instructions. */ + +static int +thumb2_record_str_single_data (insn_decode_record *thumb2_insn_r) +{ + struct regcache *reg_cache = thumb2_insn_r->regcache; + + uint32_t reg_rn, reg_rm, offset_imm, shift_imm; + uint32_t address, offset_addr; + uint32_t record_buf[8], record_buf_mem[8]; + uint32_t op1, op2; + + ULONGEST u_regval[2]; + + op1 = bits (thumb2_insn_r->arm_insn, 21, 23); + op2 = bits (thumb2_insn_r->arm_insn, 6, 11); + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19); + regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]); + + if (bit (thumb2_insn_r->arm_insn, 23)) + { + /* T2 encoding. */ + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 11); + offset_addr = u_regval[0] + offset_imm; + address = offset_addr; + } + else + { + /* T3 encoding. */ + if ((0 == op1 || 1 == op1 || 2 == op1) && !(op2 & 0x20)) + { + /* Handle STRB (register). */ + reg_rm = bits (thumb2_insn_r->arm_insn, 0, 3); + regcache_raw_read_unsigned (reg_cache, reg_rm, &u_regval[1]); + shift_imm = bits (thumb2_insn_r->arm_insn, 4, 5); + offset_addr = u_regval[1] << shift_imm; + address = u_regval[0] + offset_addr; + } + else + { + offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7); + if (bit (thumb2_insn_r->arm_insn, 10)) + { + if (bit (thumb2_insn_r->arm_insn, 9)) + offset_addr = u_regval[0] + offset_imm; + else + offset_addr = u_regval[0] - offset_imm; + + address = offset_addr; + } + else + address = u_regval[0]; + } + } + + switch (op1) + { + /* Store byte instructions. */ + case 4: + case 0: + record_buf_mem[0] = 1; + break; + /* Store half word instructions. */ + case 1: + case 5: + record_buf_mem[0] = 2; + break; + /* Store word instructions. */ + case 2: + case 6: + record_buf_mem[0] = 4; + break; + + default: + gdb_assert_not_reached ("no decoding pattern found"); + break; + } + + record_buf_mem[1] = address; + thumb2_insn_r->mem_rec_count = 1; + record_buf[0] = reg_rn; + thumb2_insn_r->reg_rec_count = 1; + + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count, + record_buf_mem); + return 0; +} + +/* Handler for thumb2 load memory hints instructions. */ + +static int +thumb2_record_ld_mem_hints (insn_decode_record *thumb2_insn_r) +{ + uint32_t record_buf[8]; + uint32_t reg_rt, reg_rn; + + reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15); + reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19); + + if (ARM_PC_REGNUM != reg_rt) + { + record_buf[0] = reg_rt; + record_buf[1] = reg_rn; + record_buf[2] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 3; + + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + return 0; + } + + return -1; +} + +/* Handler for thumb2 load word instructions. */ + +static int +thumb2_record_ld_word (insn_decode_record *thumb2_insn_r) +{ + uint32_t opcode1 = 0, opcode2 = 0; + uint32_t record_buf[8]; + + record_buf[0] = bits (thumb2_insn_r->arm_insn, 12, 15); + record_buf[1] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 2; + + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + return 0; +} + +/* Handler for thumb2 long multiply, long multiply accumulate, and + divide instructions. Return value: -1:record failure ; 0:success. */ + +static int +thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r) +{ + uint32_t ret = 0; + uint32_t opcode1 = 0, opcode2 = 0; + uint32_t record_buf[8]; + uint32_t reg_src1 = 0; + + opcode1 = bits (thumb2_insn_r->arm_insn, 20, 22); + opcode2 = bits (thumb2_insn_r->arm_insn, 4, 7); + + if (0 == opcode1 || 2 == opcode1 || (opcode1 >= 4 && opcode1 <= 6)) + { + /* Handle SMULL, UMULL, SMULAL. */ + /* Handle SMLAL(S), SMULL(S), UMLAL(S), UMULL(S). */ + record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19); + record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15); + record_buf[2] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 3; + } + else if (1 == opcode1 || 3 == opcode2) + { + /* Handle SDIV and UDIV. */ + record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19); + record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15); + record_buf[2] = ARM_PS_REGNUM; + thumb2_insn_r->reg_rec_count = 3; + } + else + ret = -1; + + REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count, + record_buf); + return ret; +} + +/* Decodes thumb2 instruction type and return an instruction id. */ + +static unsigned int +thumb2_record_decode_inst_id (uint32_t thumb2_insn) +{ + uint32_t op = 0; + uint32_t op1 = 0; + uint32_t op2 = 0; + + op = bit (thumb2_insn, 15); + op1 = bits (thumb2_insn, 27, 28); + op2 = bits (thumb2_insn, 20, 26); + + if (op1 == 0x01) + { + if (!(op2 & 0x64 )) + { + /* Load/store multiple instruction. */ + return 0; + } + else if (!((op2 & 0x64) ^ 0x04)) + { + /* Load/store dual, 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;