aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYao Qi <yao@codesourcery.com>2014-05-30 15:51:45 +0800
committerYao Qi <yao@codesourcery.com>2014-06-24 09:30:24 +0800
commit80d8d3908b7ef70c325fcdfb455bf5dbc2c68e16 (patch)
tree68779827803470f7675ccf8fed2564e7b99b3156
parent03e46fbd3584d08285cb80e5ca235c48d2fa849c (diff)
downloadgdb-80d8d3908b7ef70c325fcdfb455bf5dbc2c68e16.zip
gdb-80d8d3908b7ef70c325fcdfb455bf5dbc2c68e16.tar.gz
gdb-80d8d3908b7ef70c325fcdfb455bf5dbc2c68e16.tar.bz2
Skip 'bx reg' trampoline on arm-none-eabi
After this patch <https://gcc.gnu.org/ml/gcc-patches/2005-01/msg00813.html> applied to GCC, a new trampoline is generated but GDB doesn't recognize it. This patch is to teach GDB to understand this trampoline. See details about this trampoline and the heuristics in the comments. gdb: 2014-06-24 Yao Qi <yao@codesourcery.com> * arm-tdep.c (arm_skip_bx_reg): New function. (arm_skip_stub): Call arm_skip_bx_reg.
-rw-r--r--gdb/ChangeLog5
-rw-r--r--gdb/arm-tdep.c68
2 files changed, 72 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 59b205b..bc81f4f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2014-06-24 Yao Qi <yao@codesourcery.com>
+
+ * arm-tdep.c (arm_skip_bx_reg): New function.
+ (arm_skip_stub): Call arm_skip_bx_reg.
+
2014-06-23 Don Breazeal <donb@codesourcery.com>
* MAINTAINERS: Add myself as write-after-approval maintainer.
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 74942b1..eabca4c 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -2870,6 +2870,64 @@ struct frame_unwind arm_exidx_unwind = {
arm_exidx_unwind_sniffer
};
+/* Recognize GCC's trampoline for thumb call-indirect. If we are in a
+ trampoline, return the target PC. Otherwise return 0.
+
+ void call0a (char c, short s, int i, long l) {}
+
+ int main (void)
+ {
+ (*pointer_to_call0a) (c, s, i, l);
+ }
+
+ Instead of calling a stub library function _call_via_xx (xx is
+ the register name), GCC may inline the trampoline in the object
+ file as below (register r2 has the address of call0a).
+
+ .global main
+ .type main, %function
+ ...
+ bl .L1
+ ...
+ .size main, .-main
+
+ .L1:
+ bx r2
+
+ The trampoline 'bx r2' doesn't belong to main. */
+
+static CORE_ADDR
+arm_skip_bx_reg (struct frame_info *frame, CORE_ADDR pc)
+{
+ /* The heuristics of recognizing such trampoline is that FRAME is
+ executing in Thumb mode and the instruction on PC is 'bx Rm'. */
+ if (arm_frame_is_thumb (frame))
+ {
+ gdb_byte buf[2];
+
+ if (target_read_memory (pc, buf, 2) == 0)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ enum bfd_endian byte_order_for_code
+ = gdbarch_byte_order_for_code (gdbarch);
+ uint16_t insn
+ = extract_unsigned_integer (buf, 2, byte_order_for_code);
+
+ if ((insn & 0xff80) == 0x4700) /* bx <Rm> */
+ {
+ CORE_ADDR dest
+ = get_frame_register_unsigned (frame, bits (insn, 3, 6));
+
+ /* Clear the LSB so that gdb core sets step-resume
+ breakpoint at the right address. */
+ return UNMAKE_THUMB_ADDR (dest);
+ }
+ }
+ }
+
+ return 0;
+}
+
static struct arm_prologue_cache *
arm_make_stub_cache (struct frame_info *this_frame)
{
@@ -9226,7 +9284,15 @@ arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
/* Find the starting address and name of the function containing the PC. */
if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
- return 0;
+ {
+ /* Trampoline 'bx reg' doesn't belong to any functions. Do the
+ check here. */
+ start_addr = arm_skip_bx_reg (frame, pc);
+ if (start_addr != 0)
+ return start_addr;
+
+ return 0;
+ }
/* If PC is in a Thumb call or return stub, return the address of the
target PC, which is in a register. The thunk functions are called