From 20a0aab3ed0f4bb5c304e560751b09b7b82a3e65 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 21 Dec 2015 16:34:15 -0800 Subject: [PATCH] Dump register notes for each thread when generating a FreeBSD core. gdb/ChangeLog: * fbsd-tdep.c (find_stop_signal): Remove. (struct fbsd_collect_regset_section_cb) : New field. : New field. : 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 | 13 +++++ gdb/fbsd-tdep.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 131 insertions(+), 26 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2cdf2fa..e8277f3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,18 @@ 2016-01-19 John Baldwin + * fbsd-tdep.c (find_stop_signal): Remove. + (struct fbsd_collect_regset_section_cb) : New field. + : New field. + : 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 + * configure.ac: Check for support for LWP names on FreeBSD. * fbsd-nat.c [PT_LWPINFO] New variable debug_fbsd_lwp. [TDP_RFPPWAIT || HAVE_STRUCT_PTRACE_LWPINFO_PL_TDNAME] diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c index 4284f38..7310ea0 100644 --- a/gdb/fbsd-tdep.c +++ b/gdb/fbsd-tdep.c @@ -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; } -- 2.7.4