summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2015-12-21 16:34:15 -0800
committerJohn Baldwin <jhb@FreeBSD.org>2016-01-19 08:19:40 -0800
commit20a0aab3ed0f4bb5c304e560751b09b7b82a3e65 (patch)
tree037e99f4c7dd9466fd2aaaa098139798629a6c96
parent6e9567fe2ab39d1de89ecc5105c17443b66c9b48 (diff)
downloadbinutils-gdb-20a0aab3ed0f4bb5c304e560751b09b7b82a3e65.tar.gz
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) <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.
-rw-r--r--gdb/ChangeLog13
-rw-r--r--gdb/fbsd-tdep.c144
2 files changed, 131 insertions, 26 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2cdf2fa8e27..e8277f3c8cc 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,18 @@
2016-01-19 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-19 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 4284f3809b4..7310ea09208 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;
}