summaryrefslogtreecommitdiff
path: root/gdb/linux-tdep.c
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2021-02-09 21:41:30 +0000
committerAndrew Burgess <andrew.burgess@embecosm.com>2021-02-09 21:46:12 +0000
commit03642b7189bc0bfdf61354a6d9a3f3e46d82709c (patch)
tree4c18b49e25fceaab1b1a658fc868b55d61d4387f /gdb/linux-tdep.c
parentb61f78118a850a28a41a461fdaea4026ddc17658 (diff)
downloadbinutils-gdb-03642b7189bc0bfdf61354a6d9a3f3e46d82709c.tar.gz
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.
Diffstat (limited to 'gdb/linux-tdep.c')
-rw-r--r--gdb/linux-tdep.c141
1 files changed, 134 insertions, 7 deletions
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 3db4d31de37..e9f8e1b6133 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -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;