aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorUlrich Weigand <uweigand@de.ibm.com>2007-03-09 03:51:04 +0000
committerUlrich Weigand <uweigand@de.ibm.com>2007-03-09 03:51:04 +0000
commitfe5febed21bc129092057077cac3283f4a2021dc (patch)
treedd3aa782848ab40ef30f2b06df081a249a528a7f /gdb
parentb8953b0e7ef9a2c8de1d8cd7c5c2cedab201129a (diff)
downloadgdb-fe5febed21bc129092057077cac3283f4a2021dc.zip
gdb-fe5febed21bc129092057077cac3283f4a2021dc.tar.gz
gdb-fe5febed21bc129092057077cac3283f4a2021dc.tar.bz2
* spu-tdep.c (spu_in_function_epilogue_p): New function.
(spu_gdbarch_init): Install it.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog5
-rw-r--r--gdb/spu-tdep.c96
2 files changed, 101 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2624660..563d665 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2007-03-09 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * spu-tdep.c (spu_in_function_epilogue_p): New function.
+ (spu_gdbarch_init): Install it.
+
2007-03-08 Ulrich Weigand <uweigand@de.ibm.com>
* spu-linux-nat.c (spu_xfer_partial): Return -1 for unsupported
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 14e6e6d..5f584ea 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -559,6 +559,101 @@ spu_virtual_frame_pointer (CORE_ADDR pc, int *reg, LONGEST *offset)
}
}
+/* Return true if we are in the function's epilogue, i.e. after the
+ instruction that destroyed the function's stack frame.
+
+ 1) scan forward from the point of execution:
+ a) If you find an instruction that modifies the stack pointer
+ or transfers control (except a return), execution is not in
+ an epilogue, return.
+ b) Stop scanning if you find a return instruction or reach the
+ end of the function or reach the hard limit for the size of
+ an epilogue.
+ 2) scan backward from the point of execution:
+ a) If you find an instruction that modifies the stack pointer,
+ execution *is* in an epilogue, return.
+ b) Stop scanning if you reach an instruction that transfers
+ control or the beginning of the function or reach the hard
+ limit for the size of an epilogue. */
+
+static int
+spu_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end;
+ bfd_byte buf[4];
+ unsigned int insn;
+ int rt, ra, rb, rc, immed;
+
+ /* Find the search limits based on function boundaries and hard limit.
+ We assume the epilogue can be up to 64 instructions long. */
+
+ const int spu_max_epilogue_size = 64 * 4;
+
+ if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+ return 0;
+
+ if (pc - func_start < spu_max_epilogue_size)
+ epilogue_start = func_start;
+ else
+ epilogue_start = pc - spu_max_epilogue_size;
+
+ if (func_end - pc < spu_max_epilogue_size)
+ epilogue_end = func_end;
+ else
+ epilogue_end = pc + spu_max_epilogue_size;
+
+ /* Scan forward until next 'bi $0'. */
+
+ for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += 4)
+ {
+ if (target_read_memory (scan_pc, buf, 4))
+ return 0;
+ insn = extract_unsigned_integer (buf, 4);
+
+ if (is_branch (insn, &immed, &ra))
+ {
+ if (immed == 0 && ra == SPU_LR_REGNUM)
+ break;
+
+ return 0;
+ }
+
+ if (is_ri10 (insn, op_ai, &rt, &ra, &immed)
+ || is_rr (insn, op_a, &rt, &ra, &rb)
+ || is_ri10 (insn, op_lqd, &rt, &ra, &immed))
+ {
+ if (rt == SPU_RAW_SP_REGNUM)
+ return 0;
+ }
+ }
+
+ if (scan_pc >= epilogue_end)
+ return 0;
+
+ /* Scan backward until adjustment to stack pointer (R1). */
+
+ for (scan_pc = pc - 4; scan_pc >= epilogue_start; scan_pc -= 4)
+ {
+ if (target_read_memory (scan_pc, buf, 4))
+ return 0;
+ insn = extract_unsigned_integer (buf, 4);
+
+ if (is_branch (insn, &immed, &ra))
+ return 0;
+
+ if (is_ri10 (insn, op_ai, &rt, &ra, &immed)
+ || is_rr (insn, op_a, &rt, &ra, &rb)
+ || is_ri10 (insn, op_lqd, &rt, &ra, &immed))
+ {
+ if (rt == SPU_RAW_SP_REGNUM)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
/* Normal stack frames. */
struct spu_unwind_cache
@@ -1100,6 +1195,7 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_virtual_frame_pointer (gdbarch, spu_virtual_frame_pointer);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_skip_prologue (gdbarch, spu_skip_prologue);
+ set_gdbarch_in_function_epilogue_p (gdbarch, spu_in_function_epilogue_p);
/* Breakpoints. */
set_gdbarch_decr_pc_after_break (gdbarch, 4);