From 050c224b67b0cb62a5620d294997254d5b6675f9 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Tue, 24 Nov 2015 18:11:20 +0000 Subject: [PATCH] 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 * linux-tdep.c (find_stop_signal): Delete. (struct linux_corefile_thread_data) : 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. --- gdb/ChangeLog | 12 +++++ gdb/linux-tdep.c | 126 +++++++++++++++++++++++------------------------ 2 files changed, 75 insertions(+), 63 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index bc1a29ef01d..9a79b056917 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2015-11-24 Pedro Alves + + * linux-tdep.c (find_stop_signal): Delete. + (struct linux_corefile_thread_data) : 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 * breakpoint.c (tracepoint_print_recreate): Fix logic error diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 30740c0391f..000efc806b7 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; -- 2.30.2