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.
This commit is contained in:
Pedro Alves 2015-11-24 18:11:20 +00:00
parent 2cc57ad8d1
commit 050c224b67
2 changed files with 69 additions and 57 deletions

View File

@ -1,3 +1,15 @@
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.
2015-11-23 Simon Marchi <simon.marchi@ericsson.com>
* breakpoint.c (tracepoint_print_recreate): Fix logic error

View File

@ -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;
struct cleanup *old_chain;
struct regcache *regcache;
gdb_byte *siginfo_data;
LONGEST siginfo_size = 0;
/* It can be current thread
which cannot be removed by update_thread_list. */
if (info->state == THREAD_EXITED)
return 0;
regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
if (ptid_get_pid (info->ptid) == args->pid)
{
struct cleanup *old_chain;
struct regcache *regcache;
gdb_byte *siginfo_data;
LONGEST siginfo_size = 0;
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);
regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
old_chain = make_cleanup (xfree, siginfo_data);
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);
args->note_data = linux_collect_thread_registers
(regcache, info->ptid, args->obfd, args->note_data,
args->note_size, args->stop_signal);
old_chain = make_cleanup (xfree, siginfo_data);
/* 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);
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;
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;