aboutsummaryrefslogtreecommitdiff
path: root/gdb/spu-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/spu-tdep.c')
-rw-r--r--gdb/spu-tdep.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index aa456d7..5e70521 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -1088,6 +1088,110 @@ spu_write_pc (struct regcache *regcache, CORE_ADDR pc)
}
+/* Cell/B.E. cross-architecture unwinder support. */
+
+struct spu2ppu_cache
+{
+ struct frame_id frame_id;
+ struct regcache *regcache;
+};
+
+static struct gdbarch *
+spu2ppu_prev_arch (struct frame_info *this_frame, void **this_cache)
+{
+ struct spu2ppu_cache *cache = *this_cache;
+ return get_regcache_arch (cache->regcache);
+}
+
+static void
+spu2ppu_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct spu2ppu_cache *cache = *this_cache;
+ *this_id = cache->frame_id;
+}
+
+static struct value *
+spu2ppu_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct spu2ppu_cache *cache = *this_cache;
+ struct gdbarch *gdbarch = get_regcache_arch (cache->regcache);
+ gdb_byte *buf;
+
+ buf = alloca (register_size (gdbarch, regnum));
+ regcache_cooked_read (cache->regcache, regnum, buf);
+ return frame_unwind_got_bytes (this_frame, regnum, buf);
+}
+
+static int
+spu2ppu_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame, void **this_prologue_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR base, func, backchain;
+ gdb_byte buf[4];
+
+ if (gdbarch_bfd_arch_info (target_gdbarch)->arch == bfd_arch_spu)
+ return 0;
+
+ base = get_frame_sp (this_frame);
+ func = get_frame_pc (this_frame);
+ if (target_read_memory (base, buf, 4))
+ return 0;
+ backchain = extract_unsigned_integer (buf, 4, byte_order);
+
+ if (!backchain)
+ {
+ struct frame_info *fi;
+
+ struct spu2ppu_cache *cache
+ = FRAME_OBSTACK_CALLOC (1, struct spu2ppu_cache);
+
+ cache->frame_id = frame_id_build (base + 16, func);
+
+ for (fi = get_next_frame (this_frame); fi; fi = get_next_frame (fi))
+ if (gdbarch_bfd_arch_info (get_frame_arch (fi))->arch != bfd_arch_spu)
+ break;
+
+ if (fi)
+ {
+ cache->regcache = frame_save_as_regcache (fi);
+ *this_prologue_cache = cache;
+ return 1;
+ }
+ else
+ {
+ struct regcache *regcache;
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
+ cache->regcache = regcache_dup (regcache);
+ *this_prologue_cache = cache;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+spu2ppu_dealloc_cache (struct frame_info *self, void *this_cache)
+{
+ struct spu2ppu_cache *cache = this_cache;
+ regcache_xfree (cache->regcache);
+}
+
+static const struct frame_unwind spu2ppu_unwind = {
+ ARCH_FRAME,
+ spu2ppu_this_id,
+ spu2ppu_prev_register,
+ NULL,
+ spu2ppu_sniffer,
+ spu2ppu_dealloc_cache,
+ spu2ppu_prev_arch,
+};
+
+
/* Function calling convention. */
static CORE_ADDR
@@ -2310,6 +2414,9 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_skip_prologue (gdbarch, spu_skip_prologue);
set_gdbarch_in_function_epilogue_p (gdbarch, spu_in_function_epilogue_p);
+ /* Cell/B.E. cross-architecture unwinder support. */
+ frame_unwind_prepend_unwinder (gdbarch, &spu2ppu_unwind);
+
/* Breakpoints. */
set_gdbarch_decr_pc_after_break (gdbarch, 4);
set_gdbarch_breakpoint_from_pc (gdbarch, spu_breakpoint_from_pc);