gdb: revert "gdb: unify parts of the Linux and FreeBSD core dumping code"

This reverts commit 82a1fd3a4935fe665cf08bc6820942c4a091184c.

It was pointed out:

  https://sourceware.org/pipermail/gdb-patches/2021-February/175750.html

that commit 82a1fd3a4935 caused GDB to have an unconditional
dependency on ELF specific parts of BFD.  What this means is that if
GDB and BFD are built for a non-elf target then there will be
undefined symbol references within GDB.

The right solution isn't immediately obvious.  So rather than rush a
fix in I'm reverting this commit for now, and will bring it back once
I have a good solution.

gdb/ChangeLog:

	* gcore.c (struct gcore_collect_regset_section_cb_data): Delete.
	(gcore_collect_regset_section_cb): Delete.
	(gcore_collect_thread_registers): Delete.
	(gcore_build_thread_register_notes): Delete.
	(gcore_find_signalled_thread): Delete.
	* gcore.h: Remove 'gdbsupport/gdb_signals.h' include and delete
	'gdbarch' and 'thread_info' declarations.
	(gcore_build_thread_register_notes): Delete declaration.
	(gcore_find_signalled_thread): Likewise.
	* fbsd-tdep.c: Remove 'gcore.h' include.
	(struct fbsd_collect_regset_section_cb_data): New struct.
	(fbsd_collect_regset_section_cb): New function.
	(fbsd_collect_thread_registers): New function.
	(struct fbsd_corefile_thread_data): New struct.
	(fbsd_corefile_thread): New function.
	(fbsd_make_corefile_notes): Call FreeBSD specific code.
	* linux-tdep.c: Remove 'gcore.h' include.
	(struct linux_collect_regset_section_cb_data): New struct.
	(linux_collect_regset_section_cb): New function.
	(linux_collect_thread_registers): New function.
	(linux_corefile_thread): Call Linux specific code.
	(find_signalled_thread): New function.
	(linux_make_corefile_notes): Call find_signalled_thread.
This commit is contained in:
Andrew Burgess
2021-02-09 21:41:30 +00:00
parent b61f78118a
commit 03642b7189
5 changed files with 288 additions and 170 deletions

View File

@ -39,7 +39,6 @@
#include "gdb_regex.h"
#include "gdbsupport/enum-flags.h"
#include "gdbsupport/gdb_optional.h"
#include "gcore.h"
#include <ctype.h>
@ -1598,6 +1597,104 @@ linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
}
}
/* Structure for passing information from
linux_collect_thread_registers via an iterator to
linux_collect_regset_section_cb. */
struct linux_collect_regset_section_cb_data
{
linux_collect_regset_section_cb_data (struct gdbarch *gdbarch,
const struct regcache *regcache,
bfd *obfd,
gdb::unique_xmalloc_ptr<char> &note_data,
int *note_size,
unsigned long lwp,
gdb_signal stop_signal)
: gdbarch (gdbarch), regcache (regcache), obfd (obfd),
note_data (note_data), note_size (note_size), lwp (lwp),
stop_signal (stop_signal)
{}
struct gdbarch *gdbarch;
const struct regcache *regcache;
bfd *obfd;
gdb::unique_xmalloc_ptr<char> &note_data;
int *note_size;
unsigned long lwp;
enum gdb_signal stop_signal;
bool abort_iteration = false;
};
/* Callback for iterate_over_regset_sections that records a single
regset in the corefile note section. */
static void
linux_collect_regset_section_cb (const char *sect_name, int supply_size,
int collect_size, const struct regset *regset,
const char *human_name, void *cb_data)
{
struct linux_collect_regset_section_cb_data *data
= (struct linux_collect_regset_section_cb_data *) cb_data;
bool variable_size_section = (regset != NULL
&& regset->flags & REGSET_VARIABLE_SIZE);
if (!variable_size_section)
gdb_assert (supply_size == collect_size);
if (data->abort_iteration)
return;
gdb_assert (regset && regset->collect_regset);
/* This is intentionally zero-initialized by using std::vector, so
that any padding bytes in the core file will show as 0. */
std::vector<gdb_byte> buf (collect_size);
regset->collect_regset (regset, data->regcache, -1, buf.data (),
collect_size);
/* PRSTATUS still needs to be treated specially. */
if (strcmp (sect_name, ".reg") == 0)
data->note_data.reset (elfcore_write_prstatus
(data->obfd, data->note_data.release (),
data->note_size, data->lwp,
gdb_signal_to_host (data->stop_signal),
buf.data ()));
else
data->note_data.reset (elfcore_write_register_note
(data->obfd, data->note_data.release (),
data->note_size, sect_name, buf.data (),
collect_size));
if (data->note_data == NULL)
data->abort_iteration = true;
}
/* Records the thread's register state for the corefile note
section. */
static void
linux_collect_thread_registers (const struct regcache *regcache,
ptid_t ptid, bfd *obfd,
gdb::unique_xmalloc_ptr<char> &note_data,
int *note_size,
enum gdb_signal stop_signal)
{
struct gdbarch *gdbarch = regcache->arch ();
/* For remote targets the LWP may not be available, so use the TID. */
long lwp = ptid.lwp ();
if (lwp == 0)
lwp = ptid.tid ();
linux_collect_regset_section_cb_data data (gdbarch, regcache, obfd, note_data,
note_size, lwp, stop_signal);
gdbarch_iterate_over_regset_sections (gdbarch,
linux_collect_regset_section_cb,
&data, regcache);
}
/* Fetch the siginfo data for the specified thread, if it exists. If
there is no data, or we could not read it, return an empty
buffer. */
@ -1649,16 +1746,22 @@ static void
linux_corefile_thread (struct thread_info *info,
struct linux_corefile_thread_data *args)
{
gcore_build_thread_register_notes (args->gdbarch, info, args->stop_signal,
args->obfd, &args->note_data,
args->note_size);
struct regcache *regcache;
regcache = get_thread_arch_regcache (info->inf->process_target (),
info->ptid, args->gdbarch);
target_fetch_registers (regcache, -1);
gdb::byte_vector siginfo_data = linux_get_siginfo_data (info, args->gdbarch);
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)
{
gdb::byte_vector siginfo_data
= linux_get_siginfo_data (info, args->gdbarch);
if (!siginfo_data.empty ())
args->note_data.reset (elfcore_write_note (args->obfd,
args->note_data.release (),
@ -1857,6 +1960,30 @@ linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p)
return 1;
}
/* Find the signalled thread. In case there's more than one signalled
thread, prefer the current thread, if it is signalled. If no
thread was signalled, default to the current thread, unless it has
exited, in which case return NULL. */
static thread_info *
find_signalled_thread ()
{
thread_info *curr_thr = inferior_thread ();
if (curr_thr->state != THREAD_EXITED
&& curr_thr->suspend.stop_signal != GDB_SIGNAL_0)
return curr_thr;
for (thread_info *thr : current_inferior ()->non_exited_threads ())
if (thr->suspend.stop_signal != GDB_SIGNAL_0)
return thr;
/* Default to the current thread, unless it has exited. */
if (curr_thr->state != THREAD_EXITED)
return curr_thr;
return nullptr;
}
/* Build the note section for a corefile, and return it in a malloc
buffer. */
@ -1894,7 +2021,7 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
/* Like the kernel, prefer dumping the signalled thread first.
"First thread" is what tools use to infer the signalled
thread. */
thread_info *signalled_thr = gcore_find_signalled_thread ();
thread_info *signalled_thr = find_signalled_thread ();
gdb_signal stop_signal;
if (signalled_thr != nullptr)
stop_signal = signalled_thr->suspend.stop_signal;