From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25769 invoked by alias); 13 Nov 2009 14:45:58 -0000 Received: (qmail 25755 invoked by uid 22791); 13 Nov 2009 14:45:54 -0000 X-SWARE-Spam-Status: No, hits=-1.3 required=5.0 tests=AWL,BAYES_00,SPF_PASS,TBC X-Spam-Check-By: sourceware.org Received: from cam-admin0.cambridge.arm.com (HELO cam-admin0.cambridge.arm.com) (217.140.96.50) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 13 Nov 2009 14:45:50 +0000 Received: from cam-owa2.Emea.Arm.com (cam-owa2.emea.arm.com [10.1.105.18]) by cam-admin0.cambridge.arm.com (8.12.6/8.12.6) with ESMTP id nADEjjeI014338; Fri, 13 Nov 2009 14:45:45 GMT Received: from [10.1.129.63] ([10.1.255.212]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 13 Nov 2009 14:45:45 +0000 Subject: [RFC ARM] Backport Thumb2 debug fixes to gdb 7.0 branch ? From: Ramana Radhakrishnan Reply-To: ramana.radhakrishnan@arm.com To: gdb-patches@sourceware.org Cc: dan@codesourcery.com Content-Type: multipart/mixed; boundary="=-00kemtws/3jyOS48qhMl" Date: Fri, 13 Nov 2009 14:45:00 -0000 Message-Id: <1258123544.23100.68.camel@e200593-lin.cambridge.arm.com> Mime-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-11/txt/msg00298.txt.bz2 --=-00kemtws/3jyOS48qhMl Content-Type: text/plain Content-Transfer-Encoding: 7bit Content-length: 1752 Hi, A colleague at work noticed that gdb7.0 didn't support Thumb2 debugging and it appears as though the Thumb2 debugging fixes were committed after the 7.0 release branch was created. The current state of the art with Thumb2 debugging in the 7.0 release branch is that basic debug like single step doesn't work. By doesn't work I mean that I get an error such as the following on single stepping in a simple hello world program because next_pc doesn't know how to disassemble Thumb2 instructions. Could not insert single-step breakpoint at 0x249ca2 I've backported the patches here to the 7.0 release branch http://sourceware.org/ml/gdb-patches/2009-07/msg00683.html http://sourceware.org/ml/gdb-patches/2009-10/msg00679.html and tested this by building a native arm-linux-gnueabi gdb and testing specifically by running the testsuite for Thumb2 debug using a native gcc 4.4 compiler on my babbage board. The test results look very similar to the results on trunk as of yesterday. A full testsuite run is on for ARM state as well to see nothing is broken by this patch. Ok to backport ? cheers Ramana 2009-11-13 Ramana Radhakrishnan Backport from mainline. 2009-07-28 Daniel Jacobowitz * arm-tdep.c (arm_push_dummy_call): Set the low bit of LR for a Thumb entry point. (thumb_get_next_pc): Handle Thumb-2 and ARM v6 instructions. Refuse to single step into IT blocks. 2009-10-28 Daniel Jacobowitz Reported by Antti Hatala . * arm-tdep.c (thumb_get_next_pc): Limit check to IT instructions correctly. -- Ramana Radhakrishnan GNU Tools ARM Ltd. --=-00kemtws/3jyOS48qhMl Content-Disposition: attachment; filename=gdb.patch Content-Type: text/x-patch; name=gdb.patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-length: 8096 Index: arm-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/arm-tdep.c,v retrieving revision 1.288 diff -a -u -r1.288 arm-tdep.c --- arm-tdep.c 11 Sep 2009 18:51:31 -0000 1.288 +++ arm-tdep.c 13 Nov 2009 14:10:02 -0000 @@ -1627,7 +1627,8 @@ /* Set the return address. For the ARM, the return breakpoint is always at BP_ADDR. */ - /* XXX Fix for Thumb. */ + if (arm_pc_is_thumb (bp_addr)) + bp_addr |= 1; regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr); /* Walk through the list of args and determine how large a temporary @@ -2263,9 +2264,43 @@ unsigned short inst1; CORE_ADDR nextpc = pc + 2; /* default is next instruction */ unsigned long offset; + ULONGEST status, it; inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code); + /* Thumb-2 conditional execution support. There are eight bits in + the CPSR which describe conditional execution state. Once + reconstructed (they're in a funny order), the low five bits + describe the low bit of the condition for each instruction and + how many instructions remain. The high three bits describe the + base condition. One of the low four bits will be set if an IT + block is active. These bits read as zero on earlier + processors. */ + status = get_frame_register_unsigned (frame, ARM_PS_REGNUM); + it = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3); + + /* On GNU/Linux, where this routine is used, we use an undefined + instruction as a breakpoint. Unlike BKPT, IT can disable execution + of the undefined instruction. So we might miss the breakpoint! */ + if (((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0) || (it & 0x0f)) + error (_("Stepping through Thumb-2 IT blocks is not yet supported")); + + if (it & 0x0f) + { + /* We are in a conditional block. Check the condition. */ + int cond = it >> 4; + + if (! condition_true (cond, status)) + { + /* Advance to the next instruction. All the 32-bit + instructions share a common prefix. */ + if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0) + return pc + 4; + else + return pc + 2; + } + } + if ((inst1 & 0xff00) == 0xbd00) /* pop {rlist, pc} */ { CORE_ADDR sp; @@ -2281,7 +2316,6 @@ } else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */ { - unsigned long status = get_frame_register_unsigned (frame, ARM_PS_REGNUM); unsigned long cond = bits (inst1, 8, 11); if (cond != 0x0f && condition_true (cond, status)) /* 0x0f = SWI */ nextpc = pc_val + (sbits (inst1, 0, 7) << 1); @@ -2290,15 +2324,166 @@ { nextpc = pc_val + (sbits (inst1, 0, 10) << 1); } - else if ((inst1 & 0xf800) == 0xf000) /* long branch with link, and blx */ + else if ((inst1 & 0xe000) == 0xe000) /* 32-bit instruction */ { unsigned short inst2; inst2 = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code); - offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1); - nextpc = pc_val + offset; - /* For BLX make sure to clear the low bits. */ - if (bits (inst2, 11, 12) == 1) - nextpc = nextpc & 0xfffffffc; + + /* Default to the next instruction. */ + nextpc = pc + 4; + + if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000) + { + /* Branches and miscellaneous control instructions. */ + + if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000) + { + /* B, BL, BLX. */ + int j1, j2, imm1, imm2; + + imm1 = sbits (inst1, 0, 10); + imm2 = bits (inst2, 0, 10); + j1 = bit (inst2, 13); + j2 = bit (inst2, 11); + + offset = ((imm1 << 12) + (imm2 << 1)); + offset ^= ((!j2) << 22) | ((!j1) << 23); + + nextpc = pc_val + offset; + /* For BLX make sure to clear the low bits. */ + if (bit (inst2, 12) == 0) + nextpc = nextpc & 0xfffffffc; + } + else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00) + { + /* SUBS PC, LR, #imm8. */ + nextpc = get_frame_register_unsigned (frame, ARM_LR_REGNUM); + nextpc -= inst2 & 0x00ff; + } + else if ((inst2 & 0xd000) == 0xc000 && (inst1 & 0x0380) != 0x0380) + { + /* Conditional branch. */ + if (condition_true (bits (inst1, 6, 9), status)) + { + int sign, j1, j2, imm1, imm2; + + sign = sbits (inst1, 10, 10); + imm1 = bits (inst1, 0, 5); + imm2 = bits (inst2, 0, 10); + j1 = bit (inst2, 13); + j2 = bit (inst2, 11); + + offset = (sign << 20) + (j2 << 19) + (j1 << 18); + offset += (imm1 << 12) + (imm2 << 1); + + nextpc = pc_val + offset; + } + } + } + else if ((inst1 & 0xfe50) == 0xe810) + { + /* Load multiple or RFE. */ + int rn, offset, load_pc = 1; + + rn = bits (inst1, 0, 3); + if (bit (inst1, 7) && !bit (inst1, 8)) + { + /* LDMIA or POP */ + if (!bit (inst2, 15)) + load_pc = 0; + offset = bitcount (inst2) * 4 - 4; + } + else if (!bit (inst1, 7) && bit (inst1, 8)) + { + /* LDMDB */ + if (!bit (inst2, 15)) + load_pc = 0; + offset = -4; + } + else if (bit (inst1, 7) && bit (inst1, 8)) + { + /* RFEIA */ + offset = 0; + } + else if (!bit (inst1, 7) && !bit (inst1, 8)) + { + /* RFEDB */ + offset = -8; + } + else + load_pc = 0; + + if (load_pc) + { + CORE_ADDR addr = get_frame_register_unsigned (frame, rn); + nextpc = get_frame_memory_unsigned (frame, addr + offset, 4); + } + } + else if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00) + { + /* MOV PC or MOVS PC. */ + nextpc = get_frame_register_unsigned (frame, bits (inst2, 0, 3)); + } + else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000) + { + /* LDR PC. */ + CORE_ADDR base; + int rn, load_pc = 1; + + rn = bits (inst1, 0, 3); + base = get_frame_register_unsigned (frame, rn); + if (rn == 15) + { + base = (base + 4) & ~(CORE_ADDR) 0x3; + if (bit (inst1, 7)) + base += bits (inst2, 0, 11); + else + base -= bits (inst2, 0, 11); + } + else if (bit (inst1, 7)) + base += bits (inst2, 0, 11); + else if (bit (inst2, 11)) + { + if (bit (inst2, 10)) + { + if (bit (inst2, 9)) + base += bits (inst2, 0, 7); + else + base -= bits (inst2, 0, 7); + } + } + else if ((inst2 & 0x0fc0) == 0x0000) + { + int shift = bits (inst2, 4, 5), rm = bits (inst2, 0, 3); + base += get_frame_register_unsigned (frame, rm) << shift; + } + else + /* Reserved. */ + load_pc = 0; + + if (load_pc) + nextpc = get_frame_memory_unsigned (frame, base, 4); + } + else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000) + { + /* TBB. */ + CORE_ADDR table, offset, length; + + table = get_frame_register_unsigned (frame, bits (inst1, 0, 3)); + offset = get_frame_register_unsigned (frame, bits (inst2, 0, 3)); + length = 2 * get_frame_memory_unsigned (frame, table + offset, 1); + nextpc = pc_val + length; + } + else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000) + { + /* TBH. */ + CORE_ADDR table, offset, length; + + table = get_frame_register_unsigned (frame, bits (inst1, 0, 3)); + offset = 2 * get_frame_register_unsigned (frame, bits (inst2, 0, 3)); + length = 2 * get_frame_memory_unsigned (frame, table + offset, 2); + nextpc = pc_val + length; + } } else if ((inst1 & 0xff00) == 0x4700) /* bx REG, blx REG */ { @@ -2311,6 +2496,17 @@ if (nextpc == pc) error (_("Infinite loop detected")); } + else if ((inst1 & 0xf500) == 0xb100) + { + /* CBNZ or CBZ. */ + int imm = (bit (inst1, 9) << 6) + (bits (inst1, 3, 7) << 1); + ULONGEST reg = get_frame_register_unsigned (frame, bits (inst1, 0, 2)); + + if (bit (inst1, 11) && reg != 0) + nextpc = pc_val + imm; + else if (!bit (inst1, 11) && reg == 0) + nextpc = pc_val + imm; + } return nextpc; } --=-00kemtws/3jyOS48qhMl--