Dump register notes for each thread when generating a FreeBSD core.
authorJohn Baldwin <jhb@FreeBSD.org>
Tue, 22 Dec 2015 00:34:15 +0000 (16:34 -0800)
committerJohn Baldwin <jhb@FreeBSD.org>
Tue, 19 Jan 2016 16:19:40 +0000 (08:19 -0800)
gdb/ChangeLog:

* fbsd-tdep.c (find_stop_signal): Remove.
(struct fbsd_collect_regset_section_cb) <lwp>: New field.
<stop_signal>: New field.
<abort_iteration>: New field.
(fbsd_collect_regset_section_cb): Use new fields.
(fbsd_collect_thread_registers): New function.
(struct fbsd_corefile_thread_data): New structure.
(fbsd_corefile_thread): New function.
(fbsd_make_corefile_notes): Use new function to dump notes for each
non-exited thread in a process.

gdb/ChangeLog
gdb/fbsd-tdep.c

index 2cdf2fa8e27eefd8033b478dda31a95684a9014c..e8277f3c8cccc0f38a28d6ce54c60231e869b889 100644 (file)
@@ -1,3 +1,16 @@
+2016-01-19  John Baldwin  <jhb@FreeBSD.org>
+
+       * fbsd-tdep.c (find_stop_signal): Remove.
+       (struct fbsd_collect_regset_section_cb) <lwp>: New field.
+       <stop_signal>: New field.
+       <abort_iteration>: New field.
+       (fbsd_collect_regset_section_cb): Use new fields.
+       (fbsd_collect_thread_registers): New function.
+       (struct fbsd_corefile_thread_data): New structure.
+       (fbsd_corefile_thread): New function.
+       (fbsd_make_corefile_notes): Use new function to dump notes for each
+       non-exited thread in a process.
+
 2016-01-19  John Baldwin  <jhb@FreeBSD.org>
 
        * configure.ac: Check for support for LWP names on FreeBSD.
index 4284f3809b41ed65f15de41f221481b61aeea90a..7310ea09208cc066f612275e8ead6ff38a3421b6 100644 (file)
@@ -102,17 +102,9 @@ find_signalled_thread (struct thread_info *info, void *data)
   return 0;
 }
 
-static enum gdb_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 GDB_SIGNAL_0;
-}
+/* Structure for passing information from
+   fbsd_collect_thread_registers via an iterator to
+   fbsd_collect_regset_section_cb. */
 
 struct fbsd_collect_regset_section_cb_data
 {
@@ -120,6 +112,9 @@ struct fbsd_collect_regset_section_cb_data
   bfd *obfd;
   char *note_data;
   int *note_size;
+  unsigned long lwp;
+  enum gdb_signal stop_signal;
+  int abort_iteration;
 };
 
 static void
@@ -131,6 +126,9 @@ fbsd_collect_regset_section_cb (const char *sect_name, int size,
   struct fbsd_collect_regset_section_cb_data *data
     = (struct fbsd_collect_regset_section_cb_data *) cb_data;
 
+  if (data->abort_iteration)
+    return;
+
   gdb_assert (regset->collect_regset);
 
   buf = (char *) xmalloc (size);
@@ -139,13 +137,73 @@ fbsd_collect_regset_section_cb (const char *sect_name, int size,
   /* PRSTATUS still needs to be treated specially.  */
   if (strcmp (sect_name, ".reg") == 0)
     data->note_data = (char *) elfcore_write_prstatus
-      (data->obfd, data->note_data, data->note_size,
-       ptid_get_pid (inferior_ptid), find_stop_signal (), buf);
+      (data->obfd, data->note_data, data->note_size, data->lwp,
+       gdb_signal_to_host (data->stop_signal), buf);
   else
     data->note_data = (char *) elfcore_write_register_note
       (data->obfd, data->note_data, data->note_size,
        sect_name, buf, size);
   xfree (buf);
+
+  if (data->note_data == NULL)
+    data->abort_iteration = 1;
+}
+
+/* Records the thread's register state for the corefile note
+   section.  */
+
+static char *
+fbsd_collect_thread_registers (const struct regcache *regcache,
+                              ptid_t ptid, bfd *obfd,
+                              char *note_data, int *note_size,
+                              enum gdb_signal stop_signal)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct fbsd_collect_regset_section_cb_data data;
+
+  data.regcache = regcache;
+  data.obfd = obfd;
+  data.note_data = note_data;
+  data.note_size = note_size;
+  data.stop_signal = stop_signal;
+  data.abort_iteration = 0;
+  data.lwp = ptid_get_lwp (ptid);
+
+  gdbarch_iterate_over_regset_sections (gdbarch,
+                                       fbsd_collect_regset_section_cb,
+                                       &data, regcache);
+  return data.note_data;
+}
+
+struct fbsd_corefile_thread_data
+{
+  struct gdbarch *gdbarch;
+  bfd *obfd;
+  char *note_data;
+  int *note_size;
+  enum gdb_signal stop_signal;
+};
+
+/* Records the thread's register state for the corefile note
+   section.  */
+
+static void
+fbsd_corefile_thread (struct thread_info *info,
+                     struct fbsd_corefile_thread_data *args)
+{
+  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 = fbsd_collect_thread_registers
+    (regcache, info->ptid, args->obfd, args->note_data,
+     args->note_size, args->stop_signal);
 }
 
 /* Create appropriate note sections for a corefile, returning them in
@@ -154,10 +212,10 @@ fbsd_collect_regset_section_cb (const char *sect_name, int size,
 static char *
 fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
 {
-  struct regcache *regcache = get_current_regcache ();
-  char *note_data;
+  struct fbsd_corefile_thread_data thread_args;
+  char *note_data = NULL;
   Elf_Internal_Ehdr *i_ehdrp;
-  struct fbsd_collect_regset_section_cb_data data;
+  struct thread_info *curr_thr, *signalled_thr, *thr;
 
   /* Put a "FreeBSD" label in the ELF header.  */
   i_ehdrp = elf_elfheader (obfd);
@@ -165,16 +223,6 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
 
   gdb_assert (gdbarch_iterate_over_regset_sections_p (gdbarch));
 
-  data.regcache = regcache;
-  data.obfd = obfd;
-  data.note_data = NULL;
-  data.note_size = note_size;
-  target_fetch_registers (regcache, -1);
-  gdbarch_iterate_over_regset_sections (gdbarch,
-                                       fbsd_collect_regset_section_cb,
-                                       &data, regcache);
-  note_data = data.note_data;
-
   if (get_exec_file (0))
     {
       const char *fname = lbasename (get_exec_file (0));
@@ -188,6 +236,50 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
                                          fname, psargs);
     }
 
+  /* Thread register information.  */
+  TRY
+    {
+      update_thread_list ();
+    }
+  CATCH (e, RETURN_MASK_ERROR)
+    {
+      exception_print (gdb_stderr, e);
+    }
+  END_CATCH
+
+  /* Like the kernel, prefer dumping the signalled thread first.
+     "First thread" is what tools use to infer the signalled thread.
+     In case there's more than one signalled thread, prefer the
+     current thread, if it is signalled.  */
+  curr_thr = inferior_thread ();
+  if (curr_thr->suspend.stop_signal != GDB_SIGNAL_0)
+    signalled_thr = curr_thr;
+  else
+    {
+      signalled_thr = iterate_over_threads (find_signalled_thread, NULL);
+      if (signalled_thr == NULL)
+       signalled_thr = curr_thr;
+    }
+
+  thread_args.gdbarch = gdbarch;
+  thread_args.obfd = obfd;
+  thread_args.note_data = note_data;
+  thread_args.note_size = note_size;
+  thread_args.stop_signal = signalled_thr->suspend.stop_signal;
+
+  fbsd_corefile_thread (signalled_thr, &thread_args);
+  ALL_NON_EXITED_THREADS (thr)
+    {
+      if (thr == signalled_thr)
+       continue;
+      if (ptid_get_pid (thr->ptid) != ptid_get_pid (inferior_ptid))
+       continue;
+
+      fbsd_corefile_thread (thr, &thread_args);
+    }
+
+  note_data = thread_args.note_data;
+
   return note_data;
 }