From patchwork Thu Oct 16 16:48:29 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Machado X-Patchwork-Id: 3250 Received: (qmail 31598 invoked by alias); 16 Oct 2014 16:48:48 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 31588 invoked by uid 89); 16 Oct 2014 16:48:47 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=AWL, BAYES_00 autolearn=ham version=3.3.2 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 16 Oct 2014 16:48:46 +0000 Received: from svr-orw-fem-02x.mgc.mentorg.com ([147.34.96.206] helo=SVR-ORW-FEM-02.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1XeoEE-0005BY-V7 from Luis_Gustavo@mentor.com for gdb-patches@sourceware.org; Thu, 16 Oct 2014 09:48:42 -0700 Received: from [172.30.12.133] (147.34.91.1) by svr-orw-fem-02.mgc.mentorg.com (147.34.96.168) with Microsoft SMTP Server id 14.3.181.6; Thu, 16 Oct 2014 09:48:42 -0700 Message-ID: <543FF6DD.3070006@codesourcery.com> Date: Thu, 16 Oct 2014 13:48:29 -0300 From: Luis Machado Reply-To: User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.2.0 MIME-Version: 1.0 To: "'gdb-patches@sourceware.org'" Subject: [PATCH] Fix ARM machine state testcase failures X-IsSubscribed: yes Hi, When running GDB's reverse debugging testsuite against a few ARM multilibs, i noticed failures in the machinestate* testcases. Further investigation showed that push and pop instruction encodings A1 and A2 were not being handled properly, thus we missed saving important contents from registers and memory. When going backwards, such contents were not restored and thus we ended up with a corrupted state that did not correspond to the real values we had at a particular point in time. Attached is a patch that fixes around 36 failures for both gdb.reverse/machinestate.exp and gdb.reverse/machinestate-precsave.exp testcases, making them fully pass. This is for both armv7 and armv4. I still see failures for armv4 thumb though, so it needs a bit more investigation. I see no regressions due to this patch for armv7, armv7 thumb, armv4 and armv4 thumb. Ok for trunk? Regards, Luis 2014-10-16 Luis Machado * arm-tdep.c (POP_A2, PUSH_A2): New #defines. (arm_record_ld_st_imm_offset): Handle single-register ARM mode push and pop instructions. (POP_A1, PUSH_A1, PUSH_POP_SP_REG_MASK): New #defines. (arm_record_ld_st_multiple): Handle multi-register ARM mode push and pop instructions. diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index e2559ec..c488906 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -11473,6 +11473,10 @@ arm_record_data_proc_imm (insn_decode_record *arm_insn_r) return 0; } +/* Masks for PUSH and POP instructions that take a single register. */ +#define POP_A2 0x049d0004 /* POP */ +#define PUSH_A2 0x052d0004 /* PUSH */ + /* Handling opcode 010 insns. */ static int @@ -11489,7 +11493,39 @@ arm_record_ld_st_imm_offset (insn_decode_record *arm_insn_r) arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24); arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7); - if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM)) + if ((arm_insn_r->arm_insn & POP_A2) == POP_A2) + { + /* Handle single-register pop. */ + int regno = bits (arm_insn_r->arm_insn, 12, 15); + + record_buf[0] = regno; + arm_insn_r->reg_rec_count = 1; + + /* The stack pointer register is always modified. Check if we have + already saved it though. */ + if (regno != ARM_SP_REGNUM) + { + record_buf[1] = ARM_SP_REGNUM; + arm_insn_r->reg_rec_count = 2; + } + } + else if ((arm_insn_r->arm_insn & PUSH_A2) == PUSH_A2) + { + /* Handle single-register push. */ + + /* The stack pointer register is always updated. */ + record_buf[0] = ARM_SP_REGNUM; + arm_insn_r->reg_rec_count = 1; + + /* The pushed register goes into the stack, so we need to record that + chunk of memory as well. */ + regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval); + tgt_mem_addr = (uint32_t) u_regval; + record_buf_mem[0] = INT_REGISTER_SIZE; + record_buf_mem[1] = tgt_mem_addr - INT_REGISTER_SIZE; + arm_insn_r->mem_rec_count = 1; + } + else if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM)) { reg_dest = bits (arm_insn_r->arm_insn, 12, 15); /* LDR insn has a capability to do branching, if @@ -11847,6 +11883,11 @@ arm_record_ld_st_reg_offset (insn_decode_record *arm_insn_r) return 0; } +/* Masks for PUSH and POP instructions that take multiple registers. */ +#define POP_A1 0x08bd0000 /* POP */ +#define PUSH_A1 0x092d0000 /* PUSH */ +#define PUSH_POP_SP_REG_MASK 0x00002000 + /* Handling opcode 100 insns. */ static int @@ -11861,12 +11902,66 @@ arm_record_ld_st_multiple (insn_decode_record *arm_insn_r) ULONGEST u_regval[2] = {0}; + if ((arm_insn_r->arm_insn & POP_A1) == POP_A1) + { + /* Handle multi-register pop. */ + int regno = 0; + + register_bits = bits (arm_insn_r->arm_insn, 0, 15); + + /* Record which registers are going to be modified. */ + while (register_bits) + { + if (register_bits & 0x00000001) + record_buf[arm_insn_r->reg_rec_count++] = regno; + register_bits = register_bits >> 1; + regno++; + } + + /* The stack pointer register is always modified. Check if we have + already saved it though. */ + if ((bits (arm_insn_r->arm_insn, 0, 15) & PUSH_POP_SP_REG_MASK) == 0) + { + record_buf[arm_insn_r->reg_rec_count] = ARM_SP_REGNUM; + arm_insn_r->reg_rec_count++; + } + } + else if ((arm_insn_r->arm_insn & PUSH_A1) == PUSH_A1) + { + /* Handle multi-register push. */ + int mem_chunks = 0; + uint32_t sp_addr; + ULONGEST u_regval; + + register_bits = bits (arm_insn_r->arm_insn, 0, 15); + regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval); + sp_addr = (uint32_t) u_regval; + + /* The stack pointer register is always modified. */ + record_buf[0] = ARM_SP_REGNUM; + arm_insn_r->reg_rec_count = 1; + + /* The pushed registers go into the stack, so we need to record those + chunks of memory as well. Count how many registers are going to be + saved. */ + while (register_bits) + { + if (register_bits & 0x00000001) + mem_chunks++; + + register_bits = register_bits >> 1; + } + + /* Record the chunks in one continuous block. */ + record_buf_mem[0] = mem_chunks * INT_REGISTER_SIZE; + record_buf_mem[1] = sp_addr - mem_chunks * INT_REGISTER_SIZE; + arm_insn_r->mem_rec_count = 1; + } /* This mode is exclusively for load and store multiple. */ /* Handle incremenrt after/before and decrment after.before mode; Rn is changing depending on W bit, but as of now we store Rn too without optimization. */ - - if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM)) + else if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM)) { /* LDM (1,2,3) where LDM (3) changes CPSR too. */