[PATCH v2 6/6] Dump register notes for each thread when generating a FreeBSD core.

John Baldwin
2016-01-13T21:46:35Z

gdb/ChangeLog:

* fbsd-tdep.c (find_stop_signal): Remove.
(struct fbsd_collect_regset_section_cb) <lwp>: New field.
<stop_signal>: New field.
<abort_iteration>: 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 fdf35b0..178046d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,18 @@
2016-01-10 John Baldwin <jhb@FreeBSD.org>

+ * fbsd-tdep.c (find_stop_signal): Remove.
+ (struct fbsd_collect_regset_section_cb) <lwp>: New field.
+ <stop_signal>: New field.
+ <abort_iteration>: 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-10 John Baldwin <jhb@FreeBSD.org>
+
* 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 6851cc1..be3350e 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -78,17 +78,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
{
@@ -96,6 +88,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
@@ -107,6 +102,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);
@@ -115,13 +113,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
@@ -130,10 +188,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);
@@ -141,16 +199,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));
@@ -164,6 +212,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.0