From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7251 invoked by alias); 7 Oct 2010 16:12:27 -0000 Received: (qmail 7231 invoked by uid 22791); 7 Oct 2010 16:12:24 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL,BAYES_00,MSGID_FROM_MTA_HEADER,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mtagate5.de.ibm.com (HELO mtagate5.de.ibm.com) (195.212.17.165) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 07 Oct 2010 16:12:18 +0000 Received: from d12nrmr1607.megacenter.de.ibm.com (d12nrmr1607.megacenter.de.ibm.com [9.149.167.49]) by mtagate5.de.ibm.com (8.13.1/8.13.1) with ESMTP id o97GCEm8013744 for ; Thu, 7 Oct 2010 16:12:14 GMT Received: from d12av02.megacenter.de.ibm.com (d12av02.megacenter.de.ibm.com [9.149.165.228]) by d12nrmr1607.megacenter.de.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o97GCEuC3567788 for ; Thu, 7 Oct 2010 18:12:14 +0200 Received: from d12av02.megacenter.de.ibm.com (loopback [127.0.0.1]) by d12av02.megacenter.de.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id o97GCERu024363 for ; Thu, 7 Oct 2010 18:12:14 +0200 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d12av02.megacenter.de.ibm.com (8.12.11.20060308/8.12.11) with SMTP id o97GCDt7024334; Thu, 7 Oct 2010 18:12:13 +0200 Message-Id: <201010071612.o97GCDt7024334@d12av02.megacenter.de.ibm.com> Received: by tuxmaker.boeblingen.de.ibm.com (sSMTP sendmail emulation); Thu, 07 Oct 2010 18:12:13 +0200 Subject: [rfa, v3] Fix software-watchpoint failures on ARM by adding epilogue detection To: dan@codesourcery.com (Daniel Jacobowitz), rearnsha@arm.com Date: Thu, 07 Oct 2010 16:12:00 -0000 From: "Ulrich Weigand" Cc: gdb-patches@sourceware.org In-Reply-To: <20100928163216.GH6886@caradoc.them.org> from "Daniel Jacobowitz" at Sep 28, 2010 12:32:17 PM MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 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: 2010-10/txt/msg00123.txt.bz2 Daniel Jacobowitz wrote: > On Tue, Sep 28, 2010 at 06:04:14PM +0200, Ulrich Weigand wrote: > > I'm wondering how "bx lr" could be an indirect call; for a call, > > lr would have to point to the return address, so it couldn't also > > contain the target address ... Am I missing something here? > > Bah, you are correct. Poor choice of example. bx ip is a better > example; that can be an indirect call, a return, or a tail call. > > > As far as I can see, GCC never uses bx with any other register but > > lr to implement a return instruction. Do you know whether this is > > also true for other compilers? If so, maybe the easiest fix would > > be to change this back to only accepting "bx lr". > > Sorry, I don't know :-( Does GCC also only use lr for an indirect > tail call? I can't tell - I couldn't get GCC to issue an indirect > tail call. OK, so it looks like we do have to add a backward scanning pass in order to reliably distinguish whether a BX is an indirect call or an indirect tail call (which GCC doesn't issue today, but probably could in the future, and RealView already does). Fortunately, this is relatively straightforward, since we at most need to scan back one instruction. *Every* instruction in the default epilogue sequence modifies SP, except possibly the return itself. Therefore, we either found some instruction(s) modifying SP during the forward-scanning pass before hitting the return, or else we check back one instruction. The following patch implements this approach for Thumb (the ARM part remains unchanged from your version). Re-tested (with the same results) on armv7l-linux-gnueabi. Richard, would this be OK with you? Bye, Ulrich 2010-10-07 Ulrich Weigand Daniel Jacobowitz * arm-tdep.c (thumb_in_function_epilogue_p) (arm_in_function_epilogue_p): New. (arm_gdbarch_init): Install arm_in_function_epilogue_p as gdbarch_in_function_epilogue_p callback. Index: gdb/arm-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/arm-tdep.c,v retrieving revision 1.307 diff -u -p -r1.307 arm-tdep.c --- gdb/arm-tdep.c 30 Aug 2010 15:26:28 -0000 1.307 +++ gdb/arm-tdep.c 7 Oct 2010 11:55:02 -0000 @@ -1706,6 +1706,203 @@ arm_dwarf2_frame_init_reg (struct gdbarc } } +/* Return true if we are in the function's epilogue, i.e. after the + instruction that destroyed the function's stack frame. */ + +static int +thumb_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); + unsigned int insn, insn2; + int found_return = 0, found_stack_adjust = 0; + CORE_ADDR func_start, func_end; + CORE_ADDR scan_pc; + gdb_byte buf[4]; + + if (!find_pc_partial_function (pc, NULL, &func_start, &func_end)) + return 0; + + /* The epilogue is a sequence of instructions along the following lines: + + - add stack frame size to SP or FP + - [if frame pointer used] restore SP from FP + - restore registers from SP [may include PC] + - a return-type instruction [if PC wasn't already restored] + + In a first pass, we scan forward from the current PC and verify the + instructions we find as compatible with this sequence, ending in a + return instruction. + + However, this is not sufficient to distinguish indirect function calls + within a function from indirect tail calls in the epilogue in some cases. + Therefore, if we didn't already find any SP-changing instruction during + forward scan, we add a backward scanning heuristic to ensure we actually + are in the epilogue. */ + + scan_pc = pc; + while (scan_pc < func_end && !found_return) + { + if (target_read_memory (scan_pc, buf, 2)) + break; + + scan_pc += 2; + insn = extract_unsigned_integer (buf, 2, byte_order_for_code); + + if ((insn & 0xff80) == 0x4700) /* bx */ + found_return = 1; + else if (insn == 0x46f7) /* mov pc, lr */ + found_return = 1; + else if (insn == 0x46bd) /* mov sp, r7 */ + found_stack_adjust = 1; + else if ((insn & 0xff00) == 0xb000) /* add sp, imm or sub sp, imm */ + found_stack_adjust = 1; + else if ((insn & 0xfe00) == 0xbc00) /* pop */ + { + found_stack_adjust = 1; + if (insn & 0x0100) /* include PC. */ + found_return = 1; + } + else if ((insn & 0xe000) == 0xe000) /* 32-bit Thumb-2 instruction */ + { + if (target_read_memory (scan_pc, buf, 2)) + break; + + scan_pc += 2; + insn2 = extract_unsigned_integer (buf, 2, byte_order_for_code); + + if (insn == 0xe8bd) /* ldm.w sp!, */ + { + found_stack_adjust = 1; + if (insn2 & 0x8000) /* include PC. */ + found_return = 1; + } + else if (insn == 0xf85d /* ldr.w , [sp], #4 */ + && (insn2 & 0x0fff) == 0x0b04) + { + found_stack_adjust = 1; + if ((insn2 & 0xf000) == 0xf000) /* is PC. */ + found_return = 1; + } + else if ((insn & 0xffbf) == 0xecbd /* vldm sp!, */ + && (insn2 & 0x0e00) == 0x0a00) + found_stack_adjust = 1; + else + break; + } + else + break; + } + + if (!found_return) + return 0; + + /* Since any instruction in the epilogue sequence, with the possible + exception of return itself, updates the stack pointer, we need to + scan backwards for at most one instruction. Try either a 16-bit or + a 32-bit instruction. This is just a heuristic, so we do not worry + too much about false positives.*/ + + if (!found_stack_adjust) + { + if (pc - 4 < func_start) + return 0; + if (target_read_memory (pc - 4, buf, 4)) + return 0; + + insn = extract_unsigned_integer (buf, 2, byte_order_for_code); + insn2 = extract_unsigned_integer (buf + 2, 2, byte_order_for_code); + + if (insn2 == 0x46bd) /* mov sp, r7 */ + found_stack_adjust = 1; + else if ((insn2 & 0xff00) == 0xb000) /* add sp, imm or sub sp, imm */ + found_stack_adjust = 1; + else if ((insn2 & 0xff00) == 0xbc00) /* pop without PC */ + found_stack_adjust = 1; + else if (insn == 0xe8bd) /* ldm.w sp!, */ + found_stack_adjust = 1; + else if (insn == 0xf85d /* ldr.w , [sp], #4 */ + && (insn2 & 0x0fff) == 0x0b04) + found_stack_adjust = 1; + else if ((insn & 0xffbf) == 0xecbd /* vldm sp!, */ + && (insn2 & 0x0e00) == 0x0a00) + found_stack_adjust = 1; + } + + return found_stack_adjust; +} + +/* Return true if we are in the function's epilogue, i.e. after the + instruction that destroyed the function's stack frame. */ + +static int +arm_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); + unsigned int insn; + int found_return, found_stack_adjust; + CORE_ADDR func_start, func_end; + + if (arm_pc_is_thumb (gdbarch, pc)) + return thumb_in_function_epilogue_p (gdbarch, pc); + + if (!find_pc_partial_function (pc, NULL, &func_start, &func_end)) + return 0; + + /* We are in the epilogue if the previous instruction was a stack + adjustment and the next instruction is a possible return (bx, mov + pc, or pop). We could have to scan backwards to find the stack + adjustment, or forwards to find the return, but this is a decent + approximation. First scan forwards. */ + + found_return = 0; + insn = read_memory_unsigned_integer (pc, 4, byte_order_for_code); + if (bits (insn, 28, 31) != INST_NV) + { + if ((insn & 0x0ffffff0) == 0x012fff10) + /* BX. */ + found_return = 1; + else if ((insn & 0x0ffffff0) == 0x01a0f000) + /* MOV PC. */ + found_return = 1; + else if ((insn & 0x0fff0000) == 0x08bd0000 + && (insn & 0x0000c000) != 0) + /* POP (LDMIA), including PC or LR. */ + found_return = 1; + } + + if (!found_return) + return 0; + + /* Scan backwards. This is just a heuristic, so do not worry about + false positives from mode changes. */ + + if (pc < func_start + 4) + return 0; + + insn = read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code); + if (bits (insn, 28, 31) != INST_NV) + { + if ((insn & 0x0df0f000) == 0x0080d000) + /* ADD SP (register or immediate). */ + found_stack_adjust = 1; + else if ((insn & 0x0df0f000) == 0x0040d000) + /* SUB SP (register or immediate). */ + found_stack_adjust = 1; + else if ((insn & 0x0ffffff0) == 0x01a0d000) + /* MOV SP. */ + found_return = 1; + else if ((insn & 0x0fff0000) == 0x08bd0000) + /* POP (LDMIA). */ + found_stack_adjust = 1; + } + + if (found_stack_adjust) + return 1; + + return 0; +} + + /* When arguments must be pushed onto the stack, they go on in reverse order. The code below implements a FILO (stack) to do this. */ @@ -6881,6 +7078,9 @@ arm_gdbarch_init (struct gdbarch_info in /* Advance PC across function entry code. */ set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue); + /* Detect whether PC is in function epilogue. */ + set_gdbarch_in_function_epilogue_p (gdbarch, arm_in_function_epilogue_p); + /* Skip trampolines. */ set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub); -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com