Fix PR threads/19422 - show which thread caused stop
[deliverable/binutils-gdb.git] / gdb / linux-tdep.c
index 30740c0391ff69786dd595b9c9f48f032db83e03..29f5f3c003ee024ac441b0e36ac15e948e0133e9 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for GNU/Linux, architecture independent.
 
-   Copyright (C) 2009-2015 Free Software Foundation, Inc.
+   Copyright (C) 2009-2016 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -1347,18 +1347,6 @@ 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;
-}
-
 /* Generate corefile notes for SPU contexts.  */
 
 static char *
@@ -1661,62 +1649,49 @@ linux_get_siginfo_data (struct gdbarch *gdbarch, LONGEST *size)
 struct linux_corefile_thread_data
 {
   struct gdbarch *gdbarch;
-  int pid;
   bfd *obfd;
   char *note_data;
   int *note_size;
   enum gdb_signal stop_signal;
 };
 
-/* Called by gdbthread.c once per thread.  Records the thread's
-   register state for the corefile note section.  */
+/* Records the thread's register state for the corefile note
+   section.  */
 
-static int
-linux_corefile_thread_callback (struct thread_info *info, void *data)
+static void
+linux_corefile_thread (struct thread_info *info,
+                      struct linux_corefile_thread_data *args)
 {
-  struct linux_corefile_thread_data *args
-    = (struct linux_corefile_thread_data *) data;
-
-  /* It can be current thread
-     which cannot be removed by update_thread_list.  */
-  if (info->state == THREAD_EXITED)
-    return 0;
-
-  if (ptid_get_pid (info->ptid) == args->pid)
-    {
-      struct cleanup *old_chain;
-      struct regcache *regcache;
-      gdb_byte *siginfo_data;
-      LONGEST siginfo_size = 0;
-
-      regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
-
-      old_chain = save_inferior_ptid ();
-      inferior_ptid = info->ptid;
-      target_fetch_registers (regcache, -1);
-      siginfo_data = linux_get_siginfo_data (args->gdbarch, &siginfo_size);
-      do_cleanups (old_chain);
-
-      old_chain = make_cleanup (xfree, siginfo_data);
-
-      args->note_data = linux_collect_thread_registers
-       (regcache, info->ptid, args->obfd, args->note_data,
-        args->note_size, args->stop_signal);
-
-      /* Don't return anything if we got no register information above,
-         such a core file is useless.  */
-      if (args->note_data != NULL)
-       if (siginfo_data != NULL)
-         args->note_data = elfcore_write_note (args->obfd,
-                                               args->note_data,
-                                               args->note_size,
-                                               "CORE", NT_SIGINFO,
-                                               siginfo_data, siginfo_size);
-
-      do_cleanups (old_chain);
-    }
-
-  return !args->note_data;
+  struct cleanup *old_chain;
+  struct regcache *regcache;
+  gdb_byte *siginfo_data;
+  LONGEST siginfo_size = 0;
+
+  regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
+
+  old_chain = save_inferior_ptid ();
+  inferior_ptid = info->ptid;
+  target_fetch_registers (regcache, -1);
+  siginfo_data = linux_get_siginfo_data (args->gdbarch, &siginfo_size);
+  do_cleanups (old_chain);
+
+  old_chain = make_cleanup (xfree, siginfo_data);
+
+  args->note_data = linux_collect_thread_registers
+    (regcache, info->ptid, args->obfd, args->note_data,
+     args->note_size, args->stop_signal);
+
+  /* Don't return anything if we got no register information above,
+     such a core file is useless.  */
+  if (args->note_data != NULL)
+    if (siginfo_data != NULL)
+      args->note_data = elfcore_write_note (args->obfd,
+                                           args->note_data,
+                                           args->note_size,
+                                           "CORE", NT_SIGINFO,
+                                           siginfo_data, siginfo_size);
+
+  do_cleanups (old_chain);
 }
 
 /* Fill the PRPSINFO structure with information about the process being
@@ -1932,6 +1907,7 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
   char *note_data = NULL;
   gdb_byte *auxv;
   int auxv_len;
+  struct thread_info *curr_thr, *signalled_thr, *thr;
 
   if (! gdbarch_iterate_over_regset_sections_p (gdbarch))
     return NULL;
@@ -1968,13 +1944,37 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
     }
   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.pid = ptid_get_pid (inferior_ptid);
   thread_args.obfd = obfd;
   thread_args.note_data = note_data;
   thread_args.note_size = note_size;
-  thread_args.stop_signal = find_stop_signal ();
-  iterate_over_threads (linux_corefile_thread_callback, &thread_args);
+  thread_args.stop_signal = signalled_thr->suspend.stop_signal;
+
+  linux_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;
+
+      linux_corefile_thread (thr, &thread_args);
+    }
+
   note_data = thread_args.note_data;
   if (!note_data)
     return NULL;
This page took 0.025444 seconds and 4 git commands to generate.