This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][SH] Implement core-file support for sh-linux


This patch adds support for debugging core-files on SH Linux targets.

I've added code to read both the general-purpose registers, and the floating point registers from core files. This code is adapted from the SH NBSD files.

OK?

Andrew
2009-10-12  Andrew Stubbs  <ams@codesourcery.com>

	* configure.tgt (sh*-*-linux*): Add corelow.o to gdb_target_obs.
	* sh-linux-tdep.c: Include gdb_assert.h, gdb_string.h, regcache.h,
	regset.h and sh-tdep.h.
	(struct sh_linux_pt_regs, struct sh_linux_user_fpu_struct): New types.
	(sh_linux_supply_gregset, sh_linux_collect_gregset): New functions.
	(sh_linux_supply_fpregset, sh_linux_collect_fpregset): New functions.
	(sh_linux_gregset, sh_linux_fpregset): New variables.
	(sh_linux_regset_from_core_section): New function.
	(sh_linux_init_abi): Call set_gdbarch_regset_from_core_section.

---
 src/gdb-mainline/gdb/configure.tgt   |    3 
 src/gdb-mainline/gdb/sh-linux-tdep.c |  208 ++++++++++++++++++++++++++++++++++
 2 files changed, 210 insertions(+), 1 deletions(-)


diff --git a/src/gdb-mainline/gdb/configure.tgt b/src/gdb-mainline/gdb/configure.tgt
index 20b739e..0d3074a 100644
--- a/src/gdb-mainline/gdb/configure.tgt
+++ b/src/gdb-mainline/gdb/configure.tgt
@@ -407,7 +407,8 @@ score-*-*)
 sh*-*-linux*)
 	# Target: GNU/Linux Super-H
 	gdb_target_obs="sh-tdep.o sh64-tdep.o sh-linux-tdep.o monitor.o \
-			dsrec.o solib.o solib-svr4.o symfile-mem.o glibc-tdep.o"
+			dsrec.o solib.o solib-svr4.o symfile-mem.o \
+			glibc-tdep.o corelow.o"
 	gdb_sim=../sim/sh/libsim.a
 	build_gdbserver=yes
 	;;
diff --git a/src/gdb-mainline/gdb/sh-linux-tdep.c b/src/gdb-mainline/gdb/sh-linux-tdep.c
index 46aad1d..27db8ff 100644
--- a/src/gdb-mainline/gdb/sh-linux-tdep.c
+++ b/src/gdb-mainline/gdb/sh-linux-tdep.c
@@ -20,10 +20,213 @@
 #include "defs.h"
 #include "osabi.h"
 
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
 #include "solib-svr4.h"
 #include "symtab.h"
+#include "regcache.h"
+#include "regset.h"
 
 #include "glibc-tdep.h"
+#include "sh-tdep.h"
+
+/* Copied from asm/ptrace.h, and made 64-bit safe:
+   This struct defines the way the registers are stored on the
+   kernel stack during a system call or other kernel entry.  */
+struct sh_linux_pt_regs
+  {
+    uint32_t regs[16];
+    uint32_t pc;
+    uint32_t pr;
+    uint32_t sr;
+    uint32_t gbr;
+    uint32_t mach;
+    uint32_t macl;
+    int32_t tra;
+  };
+
+/* Copied from sys/user.h, and made 64-bit safe.  */
+struct sh_linux_user_fpu_struct
+  {
+    uint32_t fp_regs[16];
+    uint32_t xfp_regs[16];
+    uint32_t fpscr;
+    uint32_t fpul;
+  };
+
+/* Supply register REGNUM from the buffer specified by GREGS and LEN
+   in the general-purpose register set REGSET to register cache
+   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
+
+static void
+sh_linux_supply_gregset (const struct regset *regset,
+		       struct regcache *regcache,
+		       int regnum, const void *gregs, size_t len)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  const struct sh_linux_pt_regs *regs = gregs;
+  int i;
+
+  gdb_assert (len >= sizeof (struct sh_linux_pt_regs));
+
+  if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1)
+    regcache_raw_supply (regcache, gdbarch_pc_regnum (gdbarch),
+			 &regs->pc);
+
+  if (regnum == SR_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, SR_REGNUM, &regs->sr);
+
+  if (regnum == PR_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, PR_REGNUM, &regs->pr);
+
+  if (regnum == GBR_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, PR_REGNUM, &regs->gbr);
+
+  if (regnum == MACH_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, MACH_REGNUM, &regs->mach);
+
+  if (regnum == MACL_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, MACL_REGNUM, &regs->macl);
+
+  for (i = R0_REGNUM; i <= (R0_REGNUM + 15); i++)
+    {
+      if (regnum == i || regnum == -1)
+	regcache_raw_supply (regcache, i, &regs->regs[i - R0_REGNUM]);
+    }
+}
+
+/* Collect register REGNUM in the general-purpose register set
+   REGSET. from register cache REGCACHE into the buffer specified by
+   GREGS and LEN.  If REGNUM is -1, do this for all registers in
+   REGSET.  */
+
+static void
+sh_linux_collect_gregset (const struct regset *regset,
+			const struct regcache *regcache,
+			int regnum, void *gregs, size_t len)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct sh_linux_pt_regs *regs = gregs;
+  int i;
+
+  gdb_assert (len >= sizeof (struct sh_linux_pt_regs));
+
+  if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1)
+    regcache_raw_collect (regcache, gdbarch_pc_regnum (gdbarch),
+			  &regs->pc);
+
+  if (regnum == SR_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, SR_REGNUM, &regs->sr);
+
+  if (regnum == PR_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, PR_REGNUM, &regs->pr);
+
+  if (regnum == GBR_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, GBR_REGNUM, &regs->gbr);
+
+  if (regnum == MACH_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, MACH_REGNUM, &regs->mach);
+
+  if (regnum == MACL_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, MACL_REGNUM, &regs->macl);
+
+  for (i = R0_REGNUM; i <= (R0_REGNUM + 15); i++)
+    {
+      if (regnum == i || regnum == -1)
+	regcache_raw_collect (regcache, i, &regs->regs[i - R0_REGNUM]);
+    }
+}
+
+/* Supply register REGNUM from the buffer specified by FPREGS and LEN
+   in the floating point register set REGSET to register cache
+   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
+
+static void
+sh_linux_supply_fpregset (const struct regset *regset,
+			  struct regcache *regcache,
+			  int regnum, const void *fpregs, size_t len)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  const struct sh_linux_user_fpu_struct *regs = fpregs;
+  int fp0_regnum = gdbarch_fp0_regnum (gdbarch);
+  int i;
+
+  gdb_assert (len >= sizeof (struct sh_linux_user_fpu_struct));
+
+  if (regnum == FPSCR_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, FPSCR_REGNUM, &regs->fpscr);
+
+  if (regnum == FPUL_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, FPUL_REGNUM, &regs->fpul);
+
+  if (fp0_regnum >= 0)
+    for (i = fp0_regnum; i <= (fp0_regnum + 15); i++)
+      if (regnum == i || regnum == -1)
+	regcache_raw_supply (regcache, i, &regs->fp_regs[i - fp0_regnum]);
+}
+
+/* Collect register REGNUM in the floating point register set
+   REGSET. from register cache REGCACHE into the buffer specified by
+   FPREGS and LEN.  If REGNUM is -1, do this for all registers in
+   REGSET.  */
+
+static void
+sh_linux_collect_fpregset (const struct regset *regset,
+			   const struct regcache *regcache,
+			   int regnum, void *fpregs, size_t len)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct sh_linux_user_fpu_struct *regs = fpregs;
+  int fp0_regnum = gdbarch_fp0_regnum (gdbarch);
+  int i;
+
+  gdb_assert (len >= sizeof (struct sh_linux_user_fpu_struct));
+
+  if (regnum == FPSCR_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, FPSCR_REGNUM, &regs->fpscr);
+
+  if (regnum == FPUL_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, FPUL_REGNUM, &regs->fpul);
+
+  if (fp0_regnum >= 0)
+    for (i = fp0_regnum; i <= (fp0_regnum + 15); i++)
+      if (regnum == i || regnum == -1)
+	regcache_raw_collect (regcache, i, &regs->fp_regs[i - fp0_regnum]);
+}
+
+/* SH register sets.  */
+
+static struct regset sh_linux_gregset =
+{
+  NULL,
+  sh_linux_supply_gregset,
+  sh_linux_collect_gregset
+};
+
+static struct regset sh_linux_fpregset =
+{
+  NULL,
+  sh_linux_supply_fpregset,
+  sh_linux_collect_fpregset
+};
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+static const struct regset *
+sh_linux_regset_from_core_section (struct gdbarch *gdbarch,
+				   const char *sect_name, size_t sect_size)
+{
+  if (strcmp (sect_name, ".reg") == 0
+      && sect_size >= sizeof (struct sh_linux_pt_regs))
+    return &sh_linux_gregset;
+  else if (strcmp (sect_name, ".reg2") == 0
+	   && sect_size >= sizeof (struct sh_linux_user_fpu_struct))
+    return &sh_linux_fpregset;
+
+  return NULL;
+}
 
 static void
 sh_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -36,6 +239,11 @@ sh_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
                                              svr4_fetch_objfile_link_map);
+
+  /* Core files are supported for 32-bit SH only, at present.  */
+  if (info.bfd_arch_info->mach != bfd_mach_sh5)
+    set_gdbarch_regset_from_core_section
+      (gdbarch, sh_linux_regset_from_core_section);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]