summaryrefslogtreecommitdiff
path: root/gdb/arm-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/arm-tdep.c')
-rw-r--r--gdb/arm-tdep.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 22a08f845b2..899dd06da87 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -888,6 +888,45 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
cache->frameoffset = 0;
}
+/* This function tries to guess whether we are in the epilogue of an
+ ARM function. We need to detect whether the stack frame has
+ already been destroyed - if it has, then neither the prologue
+ scanner nor GCC's unwind tables will be valid. This is very hokey
+ and generally unsafe. */
+
+static int
+arm_scan_epilogue (struct frame_info *next_frame,
+ struct arm_prologue_cache *cache)
+{
+ unsigned int insn;
+ gdb_byte buf[4];
+ CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
+
+ /* Assume there is no frame until proven otherwise. */
+ if (cache != NULL)
+ {
+ cache->framereg = ARM_SP_REGNUM;
+ cache->framesize = 0;
+ cache->frameoffset = 0;
+ }
+
+ /* Check for Thumb epilogue. */
+ if (arm_pc_is_thumb (prev_pc))
+ /* Not yet implemented. */
+ return 0;
+
+ if (target_read_memory (prev_pc, buf, 4) != 0)
+ return 0;
+ insn = extract_unsigned_integer (buf, 4);
+
+ if (insn == 0xe12fff1e) /* bx lr */
+ /* If this is a return, we have no frame left and no saved
+ registers. */
+ return 1;
+
+ return 0;
+}
+
static struct arm_prologue_cache *
arm_make_prologue_cache (struct frame_info *next_frame)
{
@@ -898,7 +937,8 @@ arm_make_prologue_cache (struct frame_info *next_frame)
cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- arm_scan_prologue (next_frame, cache);
+ if (arm_scan_epilogue (next_frame, cache) == 0)
+ arm_scan_prologue (next_frame, cache);
unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
if (unwound_fp == 0)
@@ -995,6 +1035,15 @@ arm_prologue_unwind_sniffer (struct frame_info *next_frame)
return &arm_prologue_unwind;
}
+static const struct frame_unwind *
+arm_epilogue_unwind_sniffer (struct frame_info *next_frame)
+{
+ if (arm_scan_epilogue (next_frame, NULL))
+ return &arm_prologue_unwind;
+ else
+ return NULL;
+}
+
static struct arm_prologue_cache *
arm_make_stub_cache (struct frame_info *next_frame)
{
@@ -2996,6 +3045,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Add some default predicates. */
frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer);
+ frame_unwind_append_sniffer (gdbarch, arm_epilogue_unwind_sniffer);
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);