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]

[rfc][2/3] Remote core file generation: register notes


Hello,

write_gcore_file today uses a target hook target_make_corefile_notes in
order to generate the core file note section.  Having this as a target
hook is really inappropriate when we want to support remote core file
generation; it should really be a gdbarch callback instead.

Note that this is the same transition we had with *reading* core files;
that was intially supported on native targets only, but is now usually
supported for remote targets via gdbarch hooks.

To avoid having to complete that transition in one go across all
targets, the patch for now adds a gdbarch_make_corefile_notes routine
in addition to target_make_corefile_notes.  For architectures that
do not yet provide a gdbarch_make_corefile_notes routine, common
code will fall back on the target hook.

The patch implements this routine for all Linux targets in linux-tdep.c,
moving code from linux-nat.c there.  Note that not even all Linux targets
can be converted at this point, only those that already implement the
gdbarch_core_regset_sections hook -- if we don't have that, we do not
know the sizes of core file register sections, and have to fall back
on using regset data types from native system headers.

Therefore, I'm keeping a fall-back native-only implementation in
linux-nat.c for now; to avoid duplication this uses a helper routine
in linux-tdep.c for everything except the core register sets.

Note that the previous BFD patch is a prerequiste; otherwise, we might
get link failures due to unresolved symbols for cross GDB builds.

Bye,
Ulrich


ChangeLog:

	* gdbarch.sh (make_corefile_notes): New architecture callback.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Likewise.

	* gcore.c (write_gcore_file): Try gdbarch_make_corefile_notes
	before target_make_corefile_notes.  If NULL is returned, the
	target does not support core file generation.

	* linux-nat.c: Include "linux-tdep.h".
	(find_signalled_thread, find_stop_signal): Remove.
	(linux_nat_do_thread_registers): Likewise.
	(struct linux_nat_corefile_thread_data): Likewise.
	(linux_nat_corefile_thread_callback): Likewise.
	(iterate_over_spus): Likewise.
	(struct linux_spu_corefile_data): Likewise.
	(linux_spu_corefile_callback): Likewise.
	(linux_spu_make_corefile_notes): Likewise.
	(linux_nat_collect_thread_registers): New function.
	(linux_nat_make_corefile_notes): Replace contents by call to
	linux_make_corefile_notes passing linux_nat_collect_thread_registers
	as native-only callback.

	* linux-tdep.h: Include "bfd.h".
	(struct regcache): Add forward declaration.
	(linux_collect_thread_registers_ftype): New typedef.
	(linux_make_corefile_notes): Add prototype.
	* linux-tdep.c: Include "gdbthread.h", "gdbcore.h", "regcache.h",
	"regset.h", and "elf-bfd.h".
	(find_signalled_thread, find_stop_signal): New functions.
	(linux_spu_make_corefile_notes): Likewise.
	(linux_collect_thread_registers): Likewise.
	(struct linux_corefile_thread_data): New data structure.
	(linux_corefile_thread_callback): New funcion.
	(linux_make_corefile_notes): Likewise.
	(linux_make_corefile_notes_1): Likewise.
	(linux_init_abi): Install it.


Index: gdb/gcore.c
===================================================================
RCS file: /cvs/src/src/gdb/gcore.c,v
retrieving revision 1.45
diff -u -p -r1.45 gcore.c
--- gdb/gcore.c	7 Jan 2011 19:36:17 -0000	1.45
+++ gdb/gcore.c	21 Oct 2011 18:37:18 -0000
@@ -72,35 +72,37 @@ write_gcore_file (bfd *obfd)
   asection *note_sec = NULL;
 
   /* An external target method must build the notes section.  */
-  note_data = target_make_corefile_notes (obfd, &note_size);
+  /* FIXME: uweigand/2011-10-06: All architectures that support core file
+     generation should be converted to gdbarch_make_corefile_notes; at that
+     point, the target vector method can be removed.  */
+  if (!gdbarch_make_corefile_notes_p (target_gdbarch))
+    note_data = target_make_corefile_notes (obfd, &note_size);
+  else
+    note_data = gdbarch_make_corefile_notes (target_gdbarch, obfd, &note_size);
 
-  /* Create the note section.  */
-  if (note_data != NULL && note_size != 0)
-    {
-      note_sec = bfd_make_section_anyway_with_flags (obfd, "note0",
-						     SEC_HAS_CONTENTS
-						     | SEC_READONLY
-						     | SEC_ALLOC);
-      if (note_sec == NULL)
-	error (_("Failed to create 'note' section for corefile: %s"),
-	       bfd_errmsg (bfd_get_error ()));
+  if (note_data == NULL || note_size == 0)
+    error (_("Target does not support core file generation."));
 
-      bfd_set_section_vma (obfd, note_sec, 0);
-      bfd_set_section_alignment (obfd, note_sec, 0);
-      bfd_set_section_size (obfd, note_sec, note_size);
-    }
+  /* Create the note section.  */
+  note_sec = bfd_make_section_anyway_with_flags (obfd, "note0",
+						 SEC_HAS_CONTENTS
+						 | SEC_READONLY
+						 | SEC_ALLOC);
+  if (note_sec == NULL)
+    error (_("Failed to create 'note' section for corefile: %s"),
+	   bfd_errmsg (bfd_get_error ()));
+
+  bfd_set_section_vma (obfd, note_sec, 0);
+  bfd_set_section_alignment (obfd, note_sec, 0);
+  bfd_set_section_size (obfd, note_sec, note_size);
 
   /* Now create the memory/load sections.  */
   if (gcore_memory_sections (obfd) == 0)
     error (_("gcore: failed to get corefile memory sections from target."));
 
   /* Write out the contents of the note section.  */
-  if (note_data != NULL && note_size != 0)
-    {
-      if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
-	warning (_("writing note section (%s)"), 
-		 bfd_errmsg (bfd_get_error ()));
-    }
+  if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
+    warning (_("writing note section (%s)"), bfd_errmsg (bfd_get_error ()));
 }
 
 static void
Index: gdb/gdbarch.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.c,v
retrieving revision 1.479
diff -u -p -r1.479 gdbarch.c
--- gdb/gdbarch.c	11 Oct 2011 19:08:58 -0000	1.479
+++ gdb/gdbarch.c	21 Oct 2011 18:37:19 -0000
@@ -239,6 +239,7 @@ struct gdbarch
   gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
   gdbarch_regset_from_core_section_ftype *regset_from_core_section;
   struct core_regset_section * core_regset_sections;
+  gdbarch_make_corefile_notes_ftype *make_corefile_notes;
   gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries;
   gdbarch_core_pid_to_str_ftype *core_pid_to_str;
   const char * gcore_bfd_target;
@@ -394,6 +395,7 @@ struct gdbarch startup_gdbarch =
   0,  /* fetch_pointer_argument */
   0,  /* regset_from_core_section */
   0,  /* core_regset_sections */
+  0,  /* make_corefile_notes */
   0,  /* core_xfer_shared_libraries */
   0,  /* core_pid_to_str */
   0,  /* gcore_bfd_target */
@@ -681,6 +683,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of register_reggroup_p, invalid_p == 0 */
   /* Skip verify of fetch_pointer_argument, has predicate.  */
   /* Skip verify of regset_from_core_section, has predicate.  */
+  /* Skip verify of make_corefile_notes, has predicate.  */
   /* Skip verify of core_xfer_shared_libraries, has predicate.  */
   /* Skip verify of core_pid_to_str, has predicate.  */
   /* Skip verify of gcore_bfd_target, has predicate.  */
@@ -1030,6 +1033,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: long_long_bit = %s\n",
                       plongest (gdbarch->long_long_bit));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_make_corefile_notes_p() = %d\n",
+                      gdbarch_make_corefile_notes_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: make_corefile_notes = <%s>\n",
+                      host_address_to_string (gdbarch->make_corefile_notes));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_max_insn_length_p() = %d\n",
                       gdbarch_max_insn_length_p (gdbarch));
   fprintf_unfiltered (file,
@@ -3236,6 +3245,30 @@ set_gdbarch_core_regset_sections (struct
 }
 
 int
+gdbarch_make_corefile_notes_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->make_corefile_notes != NULL;
+}
+
+char *
+gdbarch_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->make_corefile_notes != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_make_corefile_notes called\n");
+  return gdbarch->make_corefile_notes (gdbarch, obfd, note_size);
+}
+
+void
+set_gdbarch_make_corefile_notes (struct gdbarch *gdbarch,
+                                 gdbarch_make_corefile_notes_ftype make_corefile_notes)
+{
+  gdbarch->make_corefile_notes = make_corefile_notes;
+}
+
+int
 gdbarch_core_xfer_shared_libraries_p (struct gdbarch *gdbarch)
 {
   gdb_assert (gdbarch != NULL);
Index: gdb/gdbarch.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.h,v
retrieving revision 1.427
diff -u -p -r1.427 gdbarch.h
--- gdb/gdbarch.h	11 Oct 2011 19:08:58 -0000	1.427
+++ gdb/gdbarch.h	21 Oct 2011 18:37:19 -0000
@@ -709,6 +709,14 @@ extern void set_gdbarch_regset_from_core
 extern struct core_regset_section * gdbarch_core_regset_sections (struct gdbarch *gdbarch);
 extern void set_gdbarch_core_regset_sections (struct gdbarch *gdbarch, struct core_regset_section * core_regset_sections);
 
+/* Create core file notes */
+
+extern int gdbarch_make_corefile_notes_p (struct gdbarch *gdbarch);
+
+typedef char * (gdbarch_make_corefile_notes_ftype) (struct gdbarch *gdbarch, bfd *obfd, int *note_size);
+extern char * gdbarch_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size);
+extern void set_gdbarch_make_corefile_notes (struct gdbarch *gdbarch, gdbarch_make_corefile_notes_ftype *make_corefile_notes);
+
 /* Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared libraries list from
    core file into buffer READBUF with length LEN. */
 
Index: gdb/gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.525
diff -u -p -r1.525 gdbarch.sh
--- gdb/gdbarch.sh	11 Oct 2011 19:08:58 -0000	1.525
+++ gdb/gdbarch.sh	21 Oct 2011 18:37:19 -0000
@@ -632,6 +632,9 @@ M:const struct regset *:regset_from_core
 # Supported register notes in a core file.
 v:struct core_regset_section *:core_regset_sections:const char *name, int len::::::host_address_to_string (gdbarch->core_regset_sections)
 
+# Create core file notes
+M:char *:make_corefile_notes:bfd *obfd, int *note_size:obfd, note_size
+
 # Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared libraries list from
 # core file into buffer READBUF with length LEN.
 M:LONGEST:core_xfer_shared_libraries:gdb_byte *readbuf, ULONGEST offset, LONGEST len:readbuf, offset, len
Index: gdb/linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.223
diff -u -p -r1.223 linux-nat.c
--- gdb/linux-nat.c	12 Oct 2011 12:11:26 -0000	1.223
+++ gdb/linux-nat.c	21 Oct 2011 18:37:20 -0000
@@ -59,6 +59,7 @@
 #include <sys/vfs.h>
 #include "solib.h"
 #include "linux-osdata.h"
+#include "linux-tdep.h"
 
 #ifndef SPUFS_MAGIC
 #define SPUFS_MAGIC 0x23c9b64e
@@ -4390,325 +4391,59 @@ linux_nat_find_memory_regions (find_memo
   return 0;
 }
 
-static int
-find_signalled_thread (struct thread_info *info, void *data)
-{
-  if (info->suspend.stop_signal != TARGET_SIGNAL_0
-      && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
-    return 1;
-
-  return 0;
-}
-
-static enum target_signal
-find_stop_signal (void)
-{
-  struct thread_info *info =
-    iterate_over_threads (find_signalled_thread, NULL);
-
-  if (info)
-    return info->suspend.stop_signal;
-  else
-    return TARGET_SIGNAL_0;
-}
-
 /* Records the thread's register state for the corefile note
    section.  */
 
 static char *
-linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
-			       char *note_data, int *note_size,
-			       enum target_signal stop_signal)
-{
-  unsigned long lwp = ptid_get_lwp (ptid);
-  struct gdbarch *gdbarch = target_gdbarch;
-  struct regcache *regcache = get_thread_arch_regcache (ptid, gdbarch);
+linux_nat_collect_thread_registers (const struct regcache *regcache,
+				    ptid_t ptid, bfd *obfd,
+				    char *note_data, int *note_size,
+				    enum target_signal stop_signal)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   const struct regset *regset;
   int core_regset_p;
-  struct cleanup *old_chain;
-  struct core_regset_section *sect_list;
-  char *gdb_regset;
-
-  old_chain = save_inferior_ptid ();
-  inferior_ptid = ptid;
-  target_fetch_registers (regcache, -1);
-  do_cleanups (old_chain);
+  gdb_gregset_t gregs;
+  gdb_fpregset_t fpregs;
 
   core_regset_p = gdbarch_regset_from_core_section_p (gdbarch);
-  sect_list = gdbarch_core_regset_sections (gdbarch);
-
-  /* The loop below uses the new struct core_regset_section, which stores
-     the supported section names and sizes for the core file.  Note that
-     note PRSTATUS needs to be treated specially.  But the other notes are
-     structurally the same, so they can benefit from the new struct.  */
-  if (core_regset_p && sect_list != NULL)
-    while (sect_list->sect_name != NULL)
-      {
-	regset = gdbarch_regset_from_core_section (gdbarch,
-						   sect_list->sect_name,
-						   sect_list->size);
-	gdb_assert (regset && regset->collect_regset);
-	gdb_regset = xmalloc (sect_list->size);
-	regset->collect_regset (regset, regcache, -1,
-				gdb_regset, sect_list->size);
-
-	if (strcmp (sect_list->sect_name, ".reg") == 0)
-	  note_data = (char *) elfcore_write_prstatus
-				(obfd, note_data, note_size,
-				 lwp, target_signal_to_host (stop_signal),
-				 gdb_regset);
-	else
-	  note_data = (char *) elfcore_write_register_note
-				(obfd, note_data, note_size,
-				 sect_list->sect_name, gdb_regset,
-				 sect_list->size);
-	xfree (gdb_regset);
-	sect_list++;
-      }
 
-  /* For architectures that does not have the struct core_regset_section
-     implemented, we use the old method.  When all the architectures have
-     the new support, the code below should be deleted.  */
+  if (core_regset_p
+      && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
+						     sizeof (gregs)))
+	 != NULL && regset->collect_regset != NULL)
+    regset->collect_regset (regset, regcache, -1, &gregs, sizeof (gregs));
   else
-    {
-      gdb_gregset_t gregs;
-      gdb_fpregset_t fpregs;
+    fill_gregset (regcache, &gregs, -1);
 
-      if (core_regset_p
-	  && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
-							 sizeof (gregs)))
+  note_data = (char *) elfcore_write_prstatus
+			 (obfd, note_data, note_size, ptid_get_lwp (ptid),
+			  target_signal_to_host (stop_signal), &gregs);
+
+  if (core_regset_p
+      && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
+						     sizeof (fpregs)))
 	  != NULL && regset->collect_regset != NULL)
-	regset->collect_regset (regset, regcache, -1,
-				&gregs, sizeof (gregs));
-      else
-	fill_gregset (regcache, &gregs, -1);
-
-      note_data = (char *) elfcore_write_prstatus
-	(obfd, note_data, note_size, lwp, target_signal_to_host (stop_signal),
-	 &gregs);
-
-      if (core_regset_p
-          && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
-							 sizeof (fpregs)))
-	  != NULL && regset->collect_regset != NULL)
-	regset->collect_regset (regset, regcache, -1,
-				&fpregs, sizeof (fpregs));
-      else
-	fill_fpregset (regcache, &fpregs, -1);
+    regset->collect_regset (regset, regcache, -1, &fpregs, sizeof (fpregs));
+  else
+    fill_fpregset (regcache, &fpregs, -1);
 
-      note_data = (char *) elfcore_write_prfpreg (obfd,
-						  note_data,
-						  note_size,
-						  &fpregs, sizeof (fpregs));
-    }
+  note_data = (char *) elfcore_write_prfpreg (obfd, note_data, note_size,
+					      &fpregs, sizeof (fpregs));
 
   return note_data;
 }
 
-struct linux_nat_corefile_thread_data
-{
-  bfd *obfd;
-  char *note_data;
-  int *note_size;
-  int num_notes;
-  enum target_signal stop_signal;
-};
-
-/* Called by gdbthread.c once per thread.  Records the thread's
-   register state for the corefile note section.  */
-
-static int
-linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
-{
-  struct linux_nat_corefile_thread_data *args = data;
-
-  args->note_data = linux_nat_do_thread_registers (args->obfd,
-						   ti->ptid,
-						   args->note_data,
-						   args->note_size,
-						   args->stop_signal);
-  args->num_notes++;
-
-  return 0;
-}
-
-/* Enumerate spufs IDs for process PID.  */
-
-static void
-iterate_over_spus (int pid, void (*callback) (void *, int), void *data)
-{
-  char path[128];
-  DIR *dir;
-  struct dirent *entry;
-
-  xsnprintf (path, sizeof path, "/proc/%d/fd", pid);
-  dir = opendir (path);
-  if (!dir)
-    return;
-
-  rewinddir (dir);
-  while ((entry = readdir (dir)) != NULL)
-    {
-      struct stat st;
-      struct statfs stfs;
-      int fd;
-
-      fd = atoi (entry->d_name);
-      if (!fd)
-	continue;
-
-      xsnprintf (path, sizeof path, "/proc/%d/fd/%d", pid, fd);
-      if (stat (path, &st) != 0)
-	continue;
-      if (!S_ISDIR (st.st_mode))
-	continue;
-
-      if (statfs (path, &stfs) != 0)
-	continue;
-      if (stfs.f_type != SPUFS_MAGIC)
-	continue;
-
-      callback (data, fd);
-    }
-
-  closedir (dir);
-}
-
-/* Generate corefile notes for SPU contexts.  */
-
-struct linux_spu_corefile_data
-{
-  bfd *obfd;
-  char *note_data;
-  int *note_size;
-};
-
-static void
-linux_spu_corefile_callback (void *data, int fd)
-{
-  struct linux_spu_corefile_data *args = data;
-  int i;
-
-  static const char *spu_files[] =
-    {
-      "object-id",
-      "mem",
-      "regs",
-      "fpcr",
-      "lslr",
-      "decr",
-      "decr_status",
-      "signal1",
-      "signal1_type",
-      "signal2",
-      "signal2_type",
-      "event_mask",
-      "event_status",
-      "mbox_info",
-      "ibox_info",
-      "wbox_info",
-      "dma_info",
-      "proxydma_info",
-   };
-
-  for (i = 0; i < sizeof (spu_files) / sizeof (spu_files[0]); i++)
-    {
-      char annex[32], note_name[32];
-      gdb_byte *spu_data;
-      LONGEST spu_len;
-
-      xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[i]);
-      spu_len = target_read_alloc (&current_target, TARGET_OBJECT_SPU,
-				   annex, &spu_data);
-      if (spu_len > 0)
-	{
-	  xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
-	  args->note_data = elfcore_write_note (args->obfd, args->note_data,
-						args->note_size, note_name,
-						NT_SPU, spu_data, spu_len);
-	  xfree (spu_data);
-	}
-    }
-}
-
-static char *
-linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
-{
-  struct linux_spu_corefile_data args;
-
-  args.obfd = obfd;
-  args.note_data = note_data;
-  args.note_size = note_size;
-
-  iterate_over_spus (PIDGET (inferior_ptid),
-		     linux_spu_corefile_callback, &args);
-
-  return args.note_data;
-}
-
 /* Fills the "to_make_corefile_note" target vector.  Builds the note
    section for a corefile, and returns it in a malloc buffer.  */
 
 static char *
 linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 {
-  struct linux_nat_corefile_thread_data thread_args;
-  /* The variable size must be >= sizeof (prpsinfo_t.pr_fname).  */
-  char fname[16] = { '\0' };
-  /* The variable size must be >= sizeof (prpsinfo_t.pr_psargs).  */
-  char psargs[80] = { '\0' };
-  char *note_data = NULL;
-  ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  gdb_byte *auxv;
-  int auxv_len;
-
-  if (get_exec_file (0))
-    {
-      strncpy (fname, lbasename (get_exec_file (0)), sizeof (fname));
-      strncpy (psargs, get_exec_file (0), sizeof (psargs));
-      if (get_inferior_args ())
-	{
-	  char *string_end;
-	  char *psargs_end = psargs + sizeof (psargs);
-
-	  /* linux_elfcore_write_prpsinfo () handles zero unterminated
-	     strings fine.  */
-	  string_end = memchr (psargs, 0, sizeof (psargs));
-	  if (string_end != NULL)
-	    {
-	      *string_end++ = ' ';
-	      strncpy (string_end, get_inferior_args (),
-		       psargs_end - string_end);
-	    }
-	}
-      note_data = (char *) elfcore_write_prpsinfo (obfd,
-						   note_data,
-						   note_size, fname, psargs);
-    }
-
-  /* Dump information for threads.  */
-  thread_args.obfd = obfd;
-  thread_args.note_data = note_data;
-  thread_args.note_size = note_size;
-  thread_args.num_notes = 0;
-  thread_args.stop_signal = find_stop_signal ();
-  iterate_over_lwps (filter, linux_nat_corefile_thread_callback, &thread_args);
-  gdb_assert (thread_args.num_notes != 0);
-  note_data = thread_args.note_data;
-
-  auxv_len = target_read_alloc (&current_target, TARGET_OBJECT_AUXV,
-				NULL, &auxv);
-  if (auxv_len > 0)
-    {
-      note_data = elfcore_write_note (obfd, note_data, note_size,
-				      "CORE", NT_AUXV, auxv, auxv_len);
-      xfree (auxv);
-    }
-
-  note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
-
-  make_cleanup (xfree, note_data);
-  return note_data;
+  /* FIXME: uweigand/2011-10-06: Once all GNU/Linux architectures have been
+     converted to gdbarch_core_regset_sections, this function can go away.  */
+  return linux_make_corefile_notes (target_gdbarch, obfd, note_size,
+				    linux_nat_collect_thread_registers);
 }
 
 /* Implement the "info proc" command.  */
Index: gdb/linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-tdep.c,v
retrieving revision 1.11
diff -u -p -r1.11 linux-tdep.c
--- gdb/linux-tdep.c	5 Mar 2011 21:21:32 -0000	1.11
+++ gdb/linux-tdep.c	21 Oct 2011 18:37:20 -0000
@@ -22,7 +22,12 @@
 #include "linux-tdep.h"
 #include "auxv.h"
 #include "target.h"
+#include "gdbthread.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "regset.h"
 #include "elf/common.h"
+#include "elf-bfd.h"            /* for elfcore_write_* */
 #include "inferior.h"
 
 static struct gdbarch_data *linux_gdbarch_data_handle;
@@ -196,6 +201,275 @@ linux_core_pid_to_str (struct gdbarch *g
   return normal_pid_to_str (ptid);
 }
 
+/* Determine which signal stopped execution.  */
+
+static int
+find_signalled_thread (struct thread_info *info, void *data)
+{
+  if (info->suspend.stop_signal != TARGET_SIGNAL_0
+      && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
+    return 1;
+
+  return 0;
+}
+
+static enum target_signal
+find_stop_signal (void)
+{
+  struct thread_info *info =
+    iterate_over_threads (find_signalled_thread, NULL);
+
+  if (info)
+    return info->suspend.stop_signal;
+  else
+    return TARGET_SIGNAL_0;
+}
+
+/* Generate corefile notes for SPU contexts.  */
+
+static char *
+linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
+{
+  static const char *spu_files[] =
+    {
+      "object-id",
+      "mem",
+      "regs",
+      "fpcr",
+      "lslr",
+      "decr",
+      "decr_status",
+      "signal1",
+      "signal1_type",
+      "signal2",
+      "signal2_type",
+      "event_mask",
+      "event_status",
+      "mbox_info",
+      "ibox_info",
+      "wbox_info",
+      "dma_info",
+      "proxydma_info",
+   };
+
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  gdb_byte *spu_ids;
+  LONGEST i, j, size;
+
+  /* Determine list of SPU ids.  */
+  size = target_read_alloc (&current_target, TARGET_OBJECT_SPU,
+			    NULL, &spu_ids);
+
+  /* Generate corefile notes for each SPU file.  */
+  for (i = 0; i < size; i += 4)
+    {
+      int fd = extract_unsigned_integer (spu_ids + i, 4, byte_order);
+
+      for (j = 0; j < sizeof (spu_files) / sizeof (spu_files[0]); j++)
+	{
+	  char annex[32], note_name[32];
+	  gdb_byte *spu_data;
+	  LONGEST spu_len;
+
+	  xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[j]);
+	  spu_len = target_read_alloc (&current_target, TARGET_OBJECT_SPU,
+				       annex, &spu_data);
+	  if (spu_len > 0)
+	    {
+	      xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
+	      note_data = elfcore_write_note (obfd, note_data, note_size,
+					      note_name, NT_SPU,
+					      spu_data, spu_len);
+	      xfree (spu_data);
+
+	      if (!note_data)
+		{
+		  xfree (spu_ids);
+		  return NULL;
+		}
+	    }
+	}
+    }
+
+  if (size > 0)
+    xfree (spu_ids);
+
+  return note_data;
+}
+
+/* Records the thread's register state for the corefile note
+   section.  */
+
+static char *
+linux_collect_thread_registers (const struct regcache *regcache,
+				ptid_t ptid, bfd *obfd,
+				char *note_data, int *note_size,
+				enum target_signal stop_signal)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct core_regset_section *sect_list;
+  unsigned long lwp;
+
+  sect_list = gdbarch_core_regset_sections (gdbarch);
+  gdb_assert (sect_list);
+
+  /* For remote targets the LWP may not be available, so use the TID.  */
+  lwp = ptid_get_lwp (ptid);
+  if (!lwp)
+    lwp = ptid_get_tid (ptid);
+
+  while (sect_list->sect_name != NULL)
+    {
+      const struct regset *regset;
+      char *buf;
+
+      regset = gdbarch_regset_from_core_section (gdbarch,
+						 sect_list->sect_name,
+						 sect_list->size);
+      gdb_assert (regset && regset->collect_regset);
+
+      buf = xmalloc (sect_list->size);
+      regset->collect_regset (regset, regcache, -1, buf, sect_list->size);
+
+      /* PRSTATUS still needs to be treated specially.  */
+      if (strcmp (sect_list->sect_name, ".reg") == 0)
+	note_data = (char *) elfcore_write_prstatus
+			       (obfd, note_data, note_size, lwp,
+				target_signal_to_host (stop_signal), buf);
+      else
+	note_data = (char *) elfcore_write_register_note
+			       (obfd, note_data, note_size,
+				sect_list->sect_name, buf, sect_list->size);
+      xfree (buf);
+      sect_list++;
+
+      if (!note_data)
+	return NULL;
+    }
+
+  return note_data;
+}
+
+struct linux_corefile_thread_data
+{
+  struct gdbarch *gdbarch;
+  int pid;
+  bfd *obfd;
+  char *note_data;
+  int *note_size;
+  int num_notes;
+  enum target_signal stop_signal;
+  linux_collect_thread_registers_ftype collect;
+};
+
+/* Called by gdbthread.c once per thread.  Records the thread's
+   register state for the corefile note section.  */
+
+static int
+linux_corefile_thread_callback (struct thread_info *info, void *data)
+{
+  struct linux_corefile_thread_data *args = data;
+
+  if (ptid_get_pid (info->ptid) == args->pid)
+    {
+      struct cleanup *old_chain;
+      struct regcache *regcache;
+      regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
+
+      old_chain = save_inferior_ptid ();
+      inferior_ptid = info->ptid;
+      target_fetch_registers (regcache, -1);
+      do_cleanups (old_chain);
+
+      args->note_data = args->collect (regcache, info->ptid, args->obfd,
+				       args->note_data, args->note_size,
+				       args->stop_signal);
+      args->num_notes++;
+    }
+
+  return !args->note_data;
+}
+
+/* Fills the "to_make_corefile_note" target vector.  Builds the note
+   section for a corefile, and returns it in a malloc buffer.  */
+
+char *
+linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size,
+			   linux_collect_thread_registers_ftype collect)
+{
+  struct linux_corefile_thread_data thread_args;
+  char *note_data = NULL;
+  gdb_byte *auxv;
+  int auxv_len;
+
+  /* Process information.  */
+  if (get_exec_file (0))
+    {
+      const char *fname = lbasename (get_exec_file (0));
+      char *psargs = xstrdup (fname);
+
+      if (get_inferior_args ())
+        psargs = reconcat (psargs, psargs, " ", get_inferior_args (),
+			   (char *) NULL);
+
+      note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
+                                          fname, psargs);
+      xfree (psargs);
+
+      if (!note_data)
+	return NULL;
+    }
+
+  /* Thread register information.  */
+  thread_args.gdbarch = gdbarch;
+  thread_args.pid = ptid_get_pid (inferior_ptid);
+  thread_args.obfd = obfd;
+  thread_args.note_data = note_data;
+  thread_args.note_size = note_size;
+  thread_args.num_notes = 0;
+  thread_args.stop_signal = find_stop_signal ();
+  thread_args.collect = collect;
+  iterate_over_threads (linux_corefile_thread_callback, &thread_args);
+  note_data = thread_args.note_data;
+  if (!note_data)
+    return NULL;
+
+  /* Auxillary vector.  */
+  auxv_len = target_read_alloc (&current_target, TARGET_OBJECT_AUXV,
+				NULL, &auxv);
+  if (auxv_len > 0)
+    {
+      note_data = elfcore_write_note (obfd, note_data, note_size,
+				      "CORE", NT_AUXV, auxv, auxv_len);
+      xfree (auxv);
+
+      if (!note_data)
+	return NULL;
+    }
+
+  /* SPU information.  */
+  note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
+  if (!note_data)
+    return NULL;
+
+  make_cleanup (xfree, note_data);
+  return note_data;
+}
+
+static char *
+linux_make_corefile_notes_1 (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
+{
+  /* FIXME: uweigand/2011-10-06: Once all GNU/Linux architectures have been
+     converted to gdbarch_core_regset_sections, we no longer need to fall back
+     to the target method at this point.  */
+
+  if (!gdbarch_core_regset_sections (gdbarch))
+    return target_make_corefile_notes (obfd, note_size);
+  else
+    return linux_make_corefile_notes (gdbarch, obfd, note_size,
+				      linux_collect_thread_registers);
+}
+
 /* To be called from the various GDB_OSABI_LINUX handlers for the
    various GNU/Linux architectures and machine types.  */
 
@@ -203,6 +477,7 @@ void
 linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   set_gdbarch_core_pid_to_str (gdbarch, linux_core_pid_to_str);
+  set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes_1);
 }
 
 void
Index: gdb/linux-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/linux-tdep.h,v
retrieving revision 1.4
diff -u -p -r1.4 linux-tdep.h
--- gdb/linux-tdep.h	1 Jan 2011 15:33:10 -0000	1.4
+++ gdb/linux-tdep.h	21 Oct 2011 18:37:20 -0000
@@ -20,6 +20,18 @@
 #ifndef LINUX_TDEP_H
 #define LINUX_TDEP_H
 
+#include "bfd.h"
+
+struct regcache;
+
+typedef char *(*linux_collect_thread_registers_ftype) (const struct regcache *,
+						       ptid_t,
+						       bfd *, char *, int *,
+						       enum target_signal);
+
+char *linux_make_corefile_notes (struct gdbarch *, bfd *, int *,
+                                 linux_collect_thread_registers_ftype);
+
 struct type *linux_get_siginfo_type (struct gdbarch *);
 
 extern void linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


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