aboutsummaryrefslogtreecommitdiff
path: root/gdb/linux-tdep.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2015-11-24 18:11:20 +0000
committerPedro Alves <palves@redhat.com>2015-11-24 18:36:09 +0000
commit050c224b67b0cb62a5620d294997254d5b6675f9 (patch)
treebda88fb03a8200420e8378fd23de716396eae23a /gdb/linux-tdep.c
parent2cc57ad8d14499775e4b9de4a3ffaf73ac728781 (diff)
downloadgdb-050c224b67b0cb62a5620d294997254d5b6675f9.zip
gdb-050c224b67b0cb62a5620d294997254d5b6675f9.tar.gz
gdb-050c224b67b0cb62a5620d294997254d5b6675f9.tar.bz2
Linux: dump the signalled thread first
... like the kernel does. gcore-thread.exp has a check to make sure the signalled thread is the current thread after loading the core back, but that just works by accident, because the signalled thread happened to be the last thread on the thread list, and gdb currently iterates over threads in reverse order. So this fixes gcore-thread.exp once we start walking threads in ascending number. gdb/ChangeLog: 2015-11-24 Pedro Alves <palves@redhat.com> * linux-tdep.c (find_stop_signal): Delete. (struct linux_corefile_thread_data) <pid>: Remove field. (linux_corefile_thread_callback): Rename to ... (linux_corefile_thread): ... this. Now takes a struct linux_corefile_thread_data pointer rather than a void pointer. Remove thread state and thread pid checks. (linux_make_corefile_notes): Prefer dumping the signalled thread first. Use ALL_NON_EXITED_THREADS instead of iterate_over_threads.
Diffstat (limited to 'gdb/linux-tdep.c')
-rw-r--r--gdb/linux-tdep.c126
1 files changed, 63 insertions, 63 deletions
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 30740c0..000efc8 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -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;