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.
This commit is contained in:
parent
6e9567fe2a
commit
20a0aab3ed
2 changed files with 131 additions and 26 deletions
|
@ -1,3 +1,16 @@
|
|||
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.
|
||||
|
|
144
gdb/fbsd-tdep.c
144
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue