public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCHv2 0/9] Bare-metal core dumps for RISC-V
@ 2021-01-20 20:23 Andrew Burgess
  2021-01-20 20:23 ` [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
                   ` (10 more replies)
  0 siblings, 11 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

This is an update of this patch series:

  https://sourceware.org/pipermail/gdb-patches/2020-December/173697.html

But also includes an update of this patch:

  https://sourceware.org/pipermail/gdb-patches/2020-October/172845.html

Here is a summary of what's changed:

Patch #1 - This is new.  Unify some of the core dump logic between
           Linux and OpenBSD.  This unified code will then be reused
           again for the bare metal core dumping.

Patch #2 - The constant NT_GDB_TDESC has received a new value, along
           with an extended comment at its definition site.

Patch #3 - Force null byte at the end of the description string, and
           add an extra null pointer check into the code.

Patch #4 - Minor updates to wording as suggested by Jim.

Patch #5 - The bare metal core dump support is now split between a
           common file and a riscv specific file.  The common file
           also reuses some of the code factored out in patch 1.

           Finally, the commit message for this commit includes a much
           fuller description of the core dump format.  Please see the
           patch email for more details.

Patch #6 - New number suggested for NT_RISCV_CSR constant, see the
           patch email for more details on why.

Patch #7 - No change.

Patch #8 - No change.

Patch #9 - This is new (in this series).  This is a rebase of
           Fredrik's patch adding bare metal core dump support for
           ARM.  I don't know if I would actually merge this patch as
           part of this series, I guess it depends on the feedback (my
           interest is RISC-V), but I wanted to include this to show
           how the patch would look when integrated with my work.

           As with patch 5 I have included a description of the core
           file format in the commit message.  Please see the patch
           email for more details.

All feedback welcome.

Thanks,
Andrew


---

Andrew Burgess (9):
  gdb: unify parts of the Linux and FreeBSD core dumping code
  bfd/binutils: support for gdb target descriptions in the core file
  gdb: write target description into core file
  bfd/riscv: prepare to handle bare metal core dump creation
  gdb/riscv: introduce bare metal core dump support
  bfd/binutils: add support for RISC-V CSRs in core files
  gdb/riscv: make riscv target description names global
  gdb/riscv: write CSRs into baremetal core dumps
  gdb/arm: add support for bare-metal core dumps

 bfd/ChangeLog         |  24 +++++
 bfd/elf-bfd.h         |   4 +
 bfd/elf.c             |  46 ++++++++++
 bfd/elfnn-riscv.c     |  72 +++++++++++++++
 binutils/ChangeLog    |  10 ++
 binutils/readelf.c    |   4 +
 gdb/ChangeLog         |  76 +++++++++++++++
 gdb/Makefile.in       |   6 ++
 gdb/arm-none-tdep.c   | 208 ++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.tgt     |   5 +-
 gdb/corelow.c         |  24 +++++
 gdb/fbsd-tdep.c       | 135 ++-------------------------
 gdb/gcore.c           | 157 +++++++++++++++++++++++++++++++
 gdb/gcore.h           |  20 ++++
 gdb/linux-tdep.c      | 141 ++--------------------------
 gdb/none-tdep.c       | 119 ++++++++++++++++++++++++
 gdb/none-tdep.h       |  30 ++++++
 gdb/riscv-none-tdep.c | 168 ++++++++++++++++++++++++++++++++++
 gdb/riscv-tdep.c      |  14 ++-
 gdb/riscv-tdep.h      |   3 +
 include/ChangeLog     |  10 ++
 include/elf/common.h  |   6 ++
 22 files changed, 1014 insertions(+), 268 deletions(-)
 create mode 100644 gdb/arm-none-tdep.c
 create mode 100644 gdb/none-tdep.c
 create mode 100644 gdb/none-tdep.h
 create mode 100644 gdb/riscv-none-tdep.c

-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-01-22 12:01   ` Strasuns, Mihails
                     ` (2 more replies)
  2021-01-20 20:23 ` [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
                   ` (9 subsequent siblings)
  10 siblings, 3 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

While reviewing the Linux and FreeBSD core dumping code within GDB for
another patch series, I noticed that the code that collects the
registers for each thread and writes these into ELF note format is
basically identical between Linux and FreeBSD.

This commit merges this code and moves it into the gcore.c file,
which seemed like the right place for generic writing a core file
code.

The function find_signalled_thread is moved from linux-tdep.c despite
not being shared.  A later commit will make use of this function.

There are a couple of minor changes to the FreeBSD target after this
commit, but I believe that these are changes for the better:

(1) For FreeBSD we always used to record the thread-id in the core file by
using ptid_t.lwp ().  In contrast the Linux code did this:

    /* For remote targets the LWP may not be available, so use the TID.  */
    long lwp = ptid.lwp ();
    if (lwp == 0)
      lwp = ptid.tid ();

Both target now do this:

    /* The LWP is often not available for bare metal target, in which case
       use the tid instead.  */
    if (ptid.lwp_p ())
      lwp = ptid.lwp ();
    else
      lwp = ptid.tid ();

Which is equivalent for Linux, but is a change for FreeBSD.  I think
that all this means is that in some cases where GDB might have
previously recorded a thread-id of 0 for each thread, we might now get
something more useful.

(2) When collecting the registers for Linux we collected into a zero
initialised buffer.  By contrast on FreeBSD the buffer is left
uninitialised.  In the new code the buffer is always zero initialised.
I suspect once the registers are copied into the buffer there's
probably no gaps left so this makes no difference, but if it does then
using zeros rather than random bits of GDB's memory is probably a good
thing.

Otherwise, there should be no other user visible changes after this
commit.

Tested this on x86-64/GNU-Linux and x86-64/FreeBSD-12.2 with no
regressions.

gdb/ChangeLog:

	* Makefile.in (HFILES_NO_SRCDIR): Add corefile.h.
	* gcore.c (struct gcore_collect_regset_section_cb_data): Moved
	here from linux-tdep.c and given a new name.  Minor cleanups.
	(gcore_collect_regset_section_cb): Likewise.
	(gcore_collect_thread_registers): Likewise.
	(gcore_build_thread_register_notes): Likewise.
	(gcore_find_signalled_thread): Likewise.
	* gcore.h (gcore_build_thread_register_notes): Declare.
	(gcore_find_signalled_thread): Declare.
	* fbsd-tdep.c: Add 'gcore.h' include.
	(struct fbsd_collect_regset_section_cb_data): Delete.
	(fbsd_collect_regset_section_cb): Delete.
	(fbsd_collect_thread_registers): Delete.
	(struct fbsd_corefile_thread_data): Delete.
	(fbsd_corefile_thread): Delete.
	(fbsd_make_corefile_notes): Call
	gcore_build_thread_register_notes instead of the now deleted
	FreeBSD code.
	* linux-tdep.c: Add 'gcore.h' include.
	(struct linux_collect_regset_section_cb_data): Delete.
	(linux_collect_regset_section_cb): Delete.
	(linux_collect_thread_registers): Delete.
	(linux_corefile_thread): Call
	gcore_build_thread_register_notes.
	(find_signalled_thread): Delete.
	(linux_make_corefile_notes): Call gcore_find_signalled_thread.
---
 gdb/ChangeLog    |  29 ++++++++++
 gdb/fbsd-tdep.c  | 135 +++------------------------------------------
 gdb/gcore.c      | 136 +++++++++++++++++++++++++++++++++++++++++++++
 gdb/gcore.h      |  20 +++++++
 gdb/linux-tdep.c | 141 +++--------------------------------------------
 5 files changed, 199 insertions(+), 262 deletions(-)

diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index cc51e921ae2..edd3edc4220 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -32,6 +32,7 @@
 
 #include "elf-bfd.h"
 #include "fbsd-tdep.h"
+#include "gcore.h"
 
 /* This enum is derived from FreeBSD's <sys/signal.h>.  */
 
@@ -583,129 +584,6 @@ find_signalled_thread (struct thread_info *info, void *data)
   return 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
-{
-  fbsd_collect_regset_section_cb_data (const struct regcache *regcache,
-				       bfd *obfd,
-				       gdb::unique_xmalloc_ptr<char> &note_data,
-				       int *note_size,
-				       unsigned long lwp,
-				       gdb_signal stop_signal)
-    : regcache (regcache),
-      obfd (obfd),
-      note_data (note_data),
-      note_size (note_size),
-      lwp (lwp),
-      stop_signal (stop_signal)
-  {}
-
-  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;
-};
-
-static void
-fbsd_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)
-{
-  char *buf;
-  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 (collect_size);
-  regset->collect_regset (regset, data->regcache, -1, buf, 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));
-  else
-    data->note_data.reset (elfcore_write_register_note
-			     (data->obfd, data->note_data.release (),
-			      data->note_size, sect_name, buf,
-			      collect_size));
-  xfree (buf);
-
-  if (data->note_data == NULL)
-    data->abort_iteration = true;
-}
-
-/* Records the thread's register state for the corefile note
-   section.  */
-
-static void
-fbsd_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)
-{
-  fbsd_collect_regset_section_cb_data data (regcache, obfd, note_data,
-					    note_size, ptid.lwp (),
-					    stop_signal);
-
-  gdbarch_iterate_over_regset_sections (regcache->arch (),
-					fbsd_collect_regset_section_cb,
-					&data, regcache);
-}
-
-struct fbsd_corefile_thread_data
-{
-  fbsd_corefile_thread_data (struct gdbarch *gdbarch,
-			     bfd *obfd,
-			     gdb::unique_xmalloc_ptr<char> &note_data,
-			     int *note_size,
-			     gdb_signal stop_signal)
-    : gdbarch (gdbarch),
-      obfd (obfd),
-      note_data (note_data),
-      note_size (note_size),
-      stop_signal (stop_signal)
-  {}
-
-  struct gdbarch *gdbarch;
-  bfd *obfd;
-  gdb::unique_xmalloc_ptr<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 regcache *regcache;
-
-  regcache = get_thread_arch_regcache (info->inf->process_target (),
-				       info->ptid, args->gdbarch);
-
-  target_fetch_registers (regcache, -1);
-
-  fbsd_collect_thread_registers (regcache, info->ptid, args->obfd,
-				 args->note_data, args->note_size,
-				 args->stop_signal);
-}
-
 /* Return a byte_vector containing the contents of a core dump note
    for the target object of type OBJECT.  If STRUCTSIZE is non-zero,
    the data is prefixed with a 32-bit integer size to match the format
@@ -782,16 +660,17 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
 	signalled_thr = curr_thr;
     }
 
-  fbsd_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
-					 signalled_thr->suspend.stop_signal);
-
-  fbsd_corefile_thread (signalled_thr, &thread_args);
+  gcore_build_thread_register_notes (gdbarch, signalled_thr,
+				     signalled_thr->suspend.stop_signal,
+				     obfd, &note_data, note_size);
   for (thread_info *thr : current_inferior ()->non_exited_threads ())
     {
       if (thr == signalled_thr)
 	continue;
 
-      fbsd_corefile_thread (thr, &thread_args);
+      gcore_build_thread_register_notes (gdbarch, thr,
+					 signalled_thr->suspend.stop_signal,
+					 obfd, &note_data, note_size);
     }
 
   /* Auxiliary vector.  */
diff --git a/gdb/gcore.c b/gdb/gcore.c
index 73ac6b09c70..d62aa3a7109 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -579,6 +579,142 @@ gcore_memory_sections (bfd *obfd)
   return 1;
 }
 
+/* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS
+   via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */
+
+struct gcore_collect_regset_section_cb_data
+{
+  gcore_collect_regset_section_cb_data (struct gdbarch *gdbarch,
+					const struct regcache *regcache,
+					bfd *obfd, ptid_t ptid,
+					gdb_signal stop_signal,
+					gdb::unique_xmalloc_ptr<char> *note_data,
+					int *note_size)
+
+    : gdbarch (gdbarch), regcache (regcache), obfd (obfd),
+      note_data (note_data), note_size (note_size),
+      stop_signal (stop_signal)
+  {
+    /* The LWP is often not available for bare metal target, in which case
+       use the tid instead.  */
+    if (ptid.lwp_p ())
+      lwp = ptid.lwp ();
+    else
+      lwp = ptid.tid ();
+  }
+
+  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 core file note section.  */
+
+static void
+gcore_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 gcore_collect_regset_section_cb_data *data
+    = (struct gcore_collect_regset_section_cb_data *) cb_data;
+  bool variable_size_section = (regset != NULL
+				&& regset->flags & REGSET_VARIABLE_SIZE);
+
+  gdb_assert (variable_size_section || supply_size == collect_size);
+
+  if (data->abort_iteration)
+    return;
+
+  gdb_assert (regset != nullptr && regset->collect_regset != nullptr);
+
+  /* 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 == nullptr)
+    data->abort_iteration = true;
+}
+
+/* Records the register state of thread PTID out of REGCACHE into the note
+   buffer represented by *NOTE_DATA and NOTE_SIZE.  OBFD is the bfd into
+   which the core file is being created, and STOP_SIGNAL is the signal that
+   cause thread PTID to stop.  */
+
+static void
+gcore_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 ();
+  gcore_collect_regset_section_cb_data data (gdbarch, regcache, obfd, ptid,
+					     stop_signal, note_data,
+					     note_size);
+  gdbarch_iterate_over_regset_sections (gdbarch,
+					gcore_collect_regset_section_cb,
+					&data, regcache);
+}
+
+/* See gcore.h.  */
+
+void
+gcore_build_thread_register_notes
+  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
+   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
+{
+  struct regcache *regcache
+    = get_thread_arch_regcache (info->inf->process_target (),
+				info->ptid, gdbarch);
+  target_fetch_registers (regcache, -1);
+  gcore_collect_thread_registers (regcache, info->ptid, obfd, note_data,
+				  note_size, stop_signal);
+}
+
+/* See gcore.h.  */
+
+thread_info *
+gcore_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;
+}
+
 void _initialize_gcore ();
 void
 _initialize_gcore ()
diff --git a/gdb/gcore.h b/gdb/gcore.h
index af37ff39b41..ce60841c1a5 100644
--- a/gdb/gcore.h
+++ b/gdb/gcore.h
@@ -21,6 +21,10 @@
 #define GCORE_H 1
 
 #include "gdb_bfd.h"
+#include "gdbsupport/gdb_signals.h"
+
+struct gdbarch;
+struct thread_info;
 
 extern gdb_bfd_ref_ptr create_gcore_bfd (const char *filename);
 extern void write_gcore_file (bfd *obfd);
@@ -28,4 +32,20 @@ extern int objfile_find_memory_regions (struct target_ops *self,
 					find_memory_region_ftype func,
 					void *obfd);
 
+/* Add content to *NOTE_DATA (and update *NOTE_SIZE) to describe the
+   registers of thread INFO.  Report the thread as having stopped with
+   STOP_SIGNAL.  The core file is being written to OFD, and GDBARCH is the
+   architecture for which the core file is being generated.  */
+
+extern void gcore_build_thread_register_notes
+  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
+   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size);
+
+/* 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.  */
+
+extern thread_info *gcore_find_signalled_thread ();
+
 #endif /* GCORE_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 5b3b8874d11..de814fc6832 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -39,6 +39,7 @@
 #include "gdb_regex.h"
 #include "gdbsupport/enum-flags.h"
 #include "gdbsupport/gdb_optional.h"
+#include "gcore.h"
 
 #include <ctype.h>
 
@@ -1599,104 +1600,6 @@ 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.  */
@@ -1748,22 +1651,16 @@ static void
 linux_corefile_thread (struct thread_info *info,
 		       struct linux_corefile_thread_data *args)
 {
-  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);
+  gcore_build_thread_register_notes (args->gdbarch, info, args->stop_signal,
+				     args->obfd, &args->note_data,
+				     args->note_size);
 
   /* 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 (),
@@ -1962,30 +1859,6 @@ 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.  */
 
@@ -2023,7 +1896,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 = find_signalled_thread ();
+  thread_info *signalled_thr = gcore_find_signalled_thread ();
   gdb_signal stop_signal;
   if (signalled_thr != nullptr)
     stop_signal = signalled_thr->suspend.stop_signal;
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
  2021-01-20 20:23 ` [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-01-22 10:47   ` Strasuns, Mihails
                     ` (3 more replies)
  2021-01-20 20:23 ` [PATCHv2 3/9] gdb: write target description into " Andrew Burgess
                   ` (8 subsequent siblings)
  10 siblings, 4 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

This commit lays the ground work for allowing GDB to write its target
description into a generated core file.

The goal of this work is to allow a user to connect to a remote
target, capture a core file from within GDB, then pass the executable
and core file to another user and have the user be able to examine the
state of the machine without needing to connect to a running target.

Different remote targets can have different register sets and this
information is communicated from the target to GDB in the target
description.

It is possible for a user to extract the target description from GDB
and pass this along with the core file so that when the core file is
used the target description can be fed back into GDB, however this is
not a great user experience.

It would be nicer, I think, if GDB could write the target description
directly into the core file, and then make use of this description
when loading a core file.

This commit performs the binutils/bfd side of this task, adding the
boiler plate functions to access the target description from within a
core file note, and reserving a new number for a note containing the
target description.

Later commits will extend GDB to make use of this.

bfd/ChangeLog:

	* elf-bfd.h (elfcore_write_gdb_tdesc): Declare new function.
	* elf.c (elfcore_grok_gdb_tdesc): New function.
	(elfcore_grok_note): Handle NT_GDB_TDESC.
	(elfcore_write_gdb_tdesc): New function.
	(elfcore_write_register_note): Handle NT_GDB_TDESC.

binutils/ChangeLog:

	* readelf.c (get_note_type): Handle NT_GDB_TDESC.

include/ChangeLog:

	* elf/common.h (NT_GDB_TDESC): Define.
---
 bfd/ChangeLog        |  9 +++++++++
 bfd/elf-bfd.h        |  2 ++
 bfd/elf.c            | 23 +++++++++++++++++++++++
 binutils/ChangeLog   |  5 +++++
 binutils/readelf.c   |  2 ++
 include/ChangeLog    |  5 +++++
 include/elf/common.h |  4 ++++
 7 files changed, 50 insertions(+)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 15206b4e876..4dce8114c0f 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2797,6 +2797,8 @@ extern char *elfcore_write_aarch_pauth
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_arc_v2
   (bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_gdb_tdesc
+  (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_lwpstatus
   (bfd *, char *, int *, long, int, const void *);
 extern char *elfcore_write_register_note
diff --git a/bfd/elf.c b/bfd/elf.c
index 84a5d942817..9892ffa9faf 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9912,6 +9912,12 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
 }
 
+static bfd_boolean
+elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".gdb-tdesc", note);
+}
+
 #if defined (HAVE_PRPSINFO_T)
 typedef prpsinfo_t   elfcore_psinfo_t;
 #if defined (HAVE_PRPSINFO32_T)		/* Sparc64 cross Sparc32 */
@@ -10570,6 +10576,9 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
 	return TRUE;
 
+    case NT_GDB_TDESC:
+      return elfcore_grok_gdb_tdesc (abfd, note);
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -11951,6 +11960,18 @@ elfcore_write_arc_v2 (bfd *abfd,
 			     note_name, NT_ARC_V2, arc_v2, size);
 }
 
+char *
+elfcore_write_gdb_tdesc (bfd *abfd,
+			 char *buf,
+			 int *bufsiz,
+			 const void *tdesc,
+			 int size)
+{
+  const char *note_name = "CORE";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_GDB_TDESC, tdesc, size);
+}
+
 char *
 elfcore_write_register_note (bfd *abfd,
 			     char *buf,
@@ -12035,6 +12056,8 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-arc-v2") == 0)
     return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".gdb-tdesc") == 0)
+    return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
   return NULL;
 }
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5df51086226..feb458877c8 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18296,6 +18296,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
 	return _("NT_PRPSINFO (prpsinfo structure)");
       case NT_TASKSTRUCT:
 	return _("NT_TASKSTRUCT (task structure)");
+      case NT_GDB_TDESC:
+        return _("NT_GDB_TDESC (GDB XML target description)");
       case NT_PRXFPREG:
 	return _("NT_PRXFPREG (user_xfpregs structure)");
       case NT_PPC_VMX:
diff --git a/include/elf/common.h b/include/elf/common.h
index e7d55ae0782..e6e9c278faa 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -677,6 +677,10 @@
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */
 
+/* The range 0xff000000 to 0xffffffff is set aside for notes that don't
+   originate from any particular operating system.  */
+#define NT_GDB_TDESC	0xff000000	/* Contains copy of GDB's target description XML.  */
+
 /* Note segments for core files on dir-style procfs systems.  */
 
 #define NT_PSTATUS	10		/* Has a struct pstatus */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 3/9] gdb: write target description into core file
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
  2021-01-20 20:23 ` [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
  2021-01-20 20:23 ` [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-01-22 19:15   ` Tom Tromey
  2021-02-01 13:37   ` Luis Machado
  2021-01-20 20:23 ` [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

When a core file is created from within GDB add the target description
into a note within the core file.

When loading a core file, if the target description note is present
then load the target description from the core file.

The benefit of this is that we can be sure that, when analysing the
core file within GDB, that we are using the exact same target
description as was in use at the time the core file was created.

In future commits I intend to add support for bare metal core dumps
for some targets.  These core dumps will include auxiliary registers,
the availability of which can only be established by looking at the
target description.

gdb/ChangeLog:

	* corelow.c: Add 'xml-tdesc.h' include.
	(core_target::read_description): Load the target description from
	the core file when possible.
	* gcore.c: Add 'gdbsupport/tdesc.h' include.
	(write_gcore_file_1): Write out the target description.
---
 gdb/ChangeLog |  9 +++++++++
 gdb/corelow.c | 24 ++++++++++++++++++++++++
 gdb/gcore.c   | 21 +++++++++++++++++++++
 3 files changed, 54 insertions(+)

diff --git a/gdb/corelow.c b/gdb/corelow.c
index a63eab4852b..fd8a5c71e22 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -49,6 +49,7 @@
 #include <unordered_map>
 #include <unordered_set>
 #include "gdbcmd.h"
+#include "xml-tdesc.h"
 
 #ifndef O_LARGEFILE
 #define O_LARGEFILE 0
@@ -1000,6 +1001,29 @@ core_target::thread_alive (ptid_t ptid)
 const struct target_desc *
 core_target::read_description ()
 {
+  /* If the core file contains a target description note then we will use
+     that in preference to anything else.  */
+  bfd_size_type tdesc_note_size = 0;
+  struct bfd_section *tdesc_note_section
+    = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
+  if (tdesc_note_section != nullptr)
+    tdesc_note_size = bfd_section_size (tdesc_note_section);
+  if (tdesc_note_size > 0)
+    {
+      gdb::char_vector contents (tdesc_note_size + 1);
+      if (bfd_get_section_contents (core_bfd, tdesc_note_section,
+				    contents.data (), (file_ptr) 0,
+				    tdesc_note_size))
+	{
+	  /* Ensure we have a null terminator.  */
+	  contents [tdesc_note_size] = '\0';
+	  const struct target_desc *result
+	    = string_read_description_xml (contents.data ());
+	  if (result != NULL)
+	    return result;
+	}
+    }
+
   if (m_core_gdbarch && gdbarch_core_read_description_p (m_core_gdbarch))
     {
       const struct target_desc *result;
diff --git a/gdb/gcore.c b/gdb/gcore.c
index d62aa3a7109..cecb9146994 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -38,6 +38,7 @@
 #include "gdbsupport/gdb_unlinker.h"
 #include "gdbsupport/byte-vector.h"
 #include "gdbsupport/scope-exit.h"
+#include "gdbsupport/tdesc.h"
 
 /* The largest amount of memory to read from the target at once.  We
    must throttle it to limit the amount of memory used by GDB during
@@ -82,6 +83,26 @@ write_gcore_file_1 (bfd *obfd)
     note_data = gdbarch_make_corefile_notes (target_gdbarch (), obfd,
 					     &note_size);
 
+  /* Append the target description to the core file.  */
+  const struct target_desc *tdesc = gdbarch_target_desc (target_gdbarch ());
+  const char *tdesc_xml
+    = tdesc == nullptr ? nullptr : tdesc_get_features_xml (tdesc);
+  if (tdesc_xml != nullptr && *tdesc_xml != '\0')
+    {
+      /* Skip the leading '@'.  */
+      if (*tdesc_xml == '@')
+	++tdesc_xml;
+
+      /* Include the null terminator in the length.  */
+      size_t tdesc_len = strlen (tdesc_xml) + 1;
+
+      /* Now add the target description into the core file.  */
+      note_data.reset (elfcore_write_register_note (obfd,
+						    note_data.release (),
+						    &note_size, ".gdb-tdesc",
+						    tdesc_xml, tdesc_len));
+    }
+
   if (note_data == NULL || note_size == 0)
     error (_("Target does not support core file generation."));
 
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
                   ` (2 preceding siblings ...)
  2021-01-20 20:23 ` [PATCHv2 3/9] gdb: write target description into " Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-02-01 12:03   ` PING: " Andrew Burgess
                     ` (2 more replies)
  2021-01-20 20:23 ` [PATCHv2 5/9] gdb/riscv: introduce bare metal core dump support Andrew Burgess
                   ` (6 subsequent siblings)
  10 siblings, 3 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

When creating a core file GDB will call the function
elfcore_write_prstatus to write out the general purpose registers
along with the pid/tid for the thread.

However, for a bare metal RISC-V tool chain the prstatus*_t types are
not defined so the elfcore_write_prstatus function will return NULL,
preventing core file creation.

This commit provides the `elf_backend_write_core_note' hook and uses
the provided function to write out the ptstatus information.

In order to keep changes in the non bare metal tools to a minimum, the
provided backend function will itself return NULL when the prstatus*_t
types are available, the consequence of this is that the generic code
in elfcore_write_prstatus will be used just as before.  But, when
prstatus*_t is not available, the new backend function will write out
the prstatus information using predefined offsets.

This new functionality will be used by a later GDB commit that will
add bare metal core dumps for RISC-V.

bfd/ChangeLog:

	* elfnn-riscv.c (riscv_write_core_note): New function.
	(elf_backend_write_core_note): Define.
---
 bfd/ChangeLog     |  6 ++++
 bfd/elfnn-riscv.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index b2ec6a29fbf..70a683b45a3 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -4886,6 +4886,77 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 # define PRPSINFO_OFFSET_PR_PSARGS	56
 #endif
 
+/* Write PRSTATUS and PRPSINFO note into core file.  This will be called
+   before the generic code in elf.c.  By checking the compiler defines we
+   only perform any action here if the generic code would otherwise not be
+   able to help us.  The intention is that bare metal core dumps (where the
+   prstatus_t and/or prpsinfo_t might not be available) will use this code,
+   while non bare metal tools will use the generic elf code.  */
+
+static char *
+riscv_write_core_note (bfd *abfd ATTRIBUTE_UNUSED,
+                       char *buf ATTRIBUTE_UNUSED,
+                       int *bufsiz ATTRIBUTE_UNUSED,
+                       int note_type ATTRIBUTE_UNUSED, ...)
+{
+  switch (note_type)
+    {
+    default:
+      return NULL;
+
+#if !defined (HAVE_PRPSINFO_T)
+    case NT_PRPSINFO:
+      {
+	char data[PRPSINFO_SIZE] ATTRIBUTE_NONSTRING;
+	va_list ap;
+
+	va_start (ap, note_type);
+	memset (data, 0, sizeof (data));
+	strncpy (data + PRPSINFO_OFFSET_PR_FNAME, va_arg (ap, const char *), 16);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+	DIAGNOSTIC_PUSH;
+	/* GCC 8.0 and 8.1 warn about 80 equals destination size with
+	   -Wstringop-truncation:
+	   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+	 */
+	DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
+	strncpy (data + PRPSINFO_OFFSET_PR_PSARGS, va_arg (ap, const char *), 80);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+	DIAGNOSTIC_POP;
+#endif
+	va_end (ap);
+	return elfcore_write_note (abfd, buf, bufsiz,
+				   "CORE", note_type, data, sizeof (data));
+      }
+#endif /* !HAVE_PRPSINFO_T */
+
+#if !defined (HAVE_PRSTATUS_T)
+    case NT_PRSTATUS:
+      {
+        char data[PRSTATUS_SIZE];
+        va_list ap;
+        long pid;
+        int cursig;
+        const void *greg;
+
+        va_start (ap, note_type);
+        memset (data, 0, sizeof(data));
+        pid = va_arg (ap, long);
+        bfd_put_32 (abfd, pid, data + PRSTATUS_OFFSET_PR_PID);
+        cursig = va_arg (ap, int);
+        bfd_put_16 (abfd, cursig, data + PRSTATUS_OFFSET_PR_CURSIG);
+        greg = va_arg (ap, const void *);
+        memcpy (data + PRSTATUS_OFFSET_PR_REG, greg,
+                PRSTATUS_SIZE - PRSTATUS_OFFSET_PR_REG - ARCH_SIZE / 8);
+        va_end (ap);
+        return elfcore_write_note (abfd, buf, bufsiz,
+                                   "CORE", note_type, data, sizeof (data));
+      }
+#endif /* !HAVE_PRSTATUS_T */
+    }
+}
+
 /* Support for core dump NOTE sections.  */
 
 static bfd_boolean
@@ -5000,6 +5071,7 @@ riscv_elf_obj_attrs_arg_type (int tag)
 #define elf_backend_grok_prstatus		riscv_elf_grok_prstatus
 #define elf_backend_grok_psinfo			riscv_elf_grok_psinfo
 #define elf_backend_object_p			riscv_elf_object_p
+#define elf_backend_write_core_note		riscv_write_core_note
 #define elf_info_to_howto_rel			NULL
 #define elf_info_to_howto			riscv_info_to_howto_rela
 #define bfd_elfNN_bfd_relax_section		_bfd_riscv_relax_section
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 5/9] gdb/riscv: introduce bare metal core dump support
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
                   ` (3 preceding siblings ...)
  2021-01-20 20:23 ` [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-02-01 14:05   ` Luis Machado
  2021-01-20 20:23 ` [PATCHv2 6/9] bfd/binutils: add support for RISC-V CSRs in core files Andrew Burgess
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

The commit message below includes a description of the core file
format.  Though this description could exist in the commit message, I
don't imagine this is really the right place to document something
like this.

For RISC-V I imagine the correct place would be here:

  https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md

And I have a commit for this repository that replicates the
description below.  However, I wanted to post this to the binutils/gdb
list first, and see if this description was good enough for all
stakeholders.

If people here are happy with this commit and the documentation, then
I would image creating a pull request against the RISC-V ABI document,
and then if there's no negative feedback, merge this patch at that
point.

All feedback, on docs or implementation, is welcome,

Thanks,
Andrew





----

This commit adds the ability for bare metal RISC-V target to generate
core files from within GDB.

The intended use case is that a user will connect to a remote bare
metal target, debug up to some error condition, then generate a core
file in the normal way using:

  (gdb) generate-core-file

This core file can then be used to revisit the state of the remote
target without having to reconnect to the remote target.

The core file creation code is split between two new files.  In
none-tdep.c is code designed to support the architecture agnostic
parts of a bare metal core dump.

In riscv-none-tdep.c are the RISC-V specific parts, this is where the
regset and regcache_map_entry structures are defined that control how
registers are laid out in the core file.

Currently for RISC-V only the x-regs and f-regs (if present) are
written out.  In future commits I plan to add support for writing out
the RISC-V CSRs.

The cores dump format is based around generating an ELF containing
sections for the writable regions of memory that a user could be
using.  Which regions are dumped rely on GDB's existing common core
dumping code, GDB will attempt to figure out the stack and heap as
well as copying out writable data sections as identified by the
original ELF.

Register information is added to the core dump using notes, just as it
is for Linux of FreeBSD core dumps.  The note types used consist of
the 3 basic types you would expect in a OS based core dump,
NT_PRPSINFO, NT_PRSTATUS, NT_FPREGSET.

The layout of these notes differs slightly (due to field sizes)
between RV32 and RV64.  Below I describe the data layout for each
note.  In all case, all padding fields should be set to zero.

Note NT_PRPSINFO is optional.  Its data layout is:

  struct prpsinfo32_t		/* For RV32.  */
  {
    uint8_t padding[32];
    char fname[16];
    char psargs[80];
  }

  struct prpsinfo64_t		/* For RV64.  */
  {
    uint8_t padding[40];
    char fname[16];
    char psargs[80];
  }

Field 'fname' - null terminated string consisting of the basename of
    (up to the fist 15 characters of) the executable.  Any additional
    space should be set to zero.  If there's no executable name then
    this field can be set to all zero.

Field 'psargs' - a null terminated string up to 80 characters in
    length.  Any additional space should be filled with zero.  This
    field contains the full executable path and any arguments passed
    to the executable.  If there's nothing sensible to write in this
    field then fill it with zero.

Note NT_PRSTATUS is required, its data layout is:

  struct prstatus32_t		/* For RV32.  */
  {
    uint8_t padding_1[12];
    uint16_t sig;
    uint8_t padding_2[10];
    uint32_t thread_id;
    uint8_t padding_3[44];
    uint32_t x_regs[32];
    uint8_t padding_4[4];
  }

  struct prstatus64_t		/* For RV64.  */
  {
    uint8_t padding_1[12];
    uint16_t sig;
    uint8_t padding_2[18];
    uint32_t thread_id;
    uint8_t padding_3[76];
    uint64_t x_regs[32];
    uint8_t padding_4[4];
  }

Field 'sig' - the signal that stopped this thread.  Its implementation
    defined what this field actually means.  Within GDB this will be
    the signal number that the remote target reports as the stop
    reason for this thread.

Field 'thread_is' - the thread id for this thread, its implementation
    defined what this field actually means.  Within GDB this will be
    thread thread-id that is assigned to each remote thread.

Field 'x_regs' - at index 0 we store the program counter, and at
    indices 1 to 31 we store x-registers 1 to 31.  x-register 0 is not
    stored, its value is always zero anyway.

Note NT_FPREGSET is optional, its data layout is:

  fpregset32_t			/* For targets with 'F' extension.  */
  {
    uint32_t f_regs[32];
    uint32_t fcsr;
  }

  fpregset64_t			/* For targets with 'D' extension .  */
  {
    uint64_t f_regs[32];
    uint32_t fcsr;
  }

Field 'f_regs' - stores f-registers 0 to 31.

Field 'fcsr' - stores the fcsr CSR register, and is always 4-bytes.

The rules for ordering the notes is the same as for Linux.  The
NT_PRSTATUS note must come before any other notes about additional
register sets.  And for multi-threaded targets all registers for a
single thread should be grouped together.  This is because only
NT_PRSTATUS includes a thread-id, all additional register notes after
a NT_PRSTATUS are assumed to belong to the same thread until a
different NT_PRSTATUS is seen.

gdb/ChangeLog:

	* Makefile.in (ALL_TARGET_OBS): Add riscv-none-tdep.o.
	(ALLDEPFILES): Add riscv-none-tdep.c.
	* configure.tgt (riscv*-*-*): Include riscv-none-tdep.c.
	* none-tdep.c: New file.
	* none-tdep.h: New file.
	* riscv-none-tdep.c: New file.
---
 gdb/ChangeLog         |  10 ++++
 gdb/Makefile.in       |   4 ++
 gdb/configure.tgt     |   2 +-
 gdb/none-tdep.c       | 119 ++++++++++++++++++++++++++++++++++++++++++
 gdb/none-tdep.h       |  30 +++++++++++
 gdb/riscv-none-tdep.c | 108 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 272 insertions(+), 1 deletion(-)
 create mode 100644 gdb/none-tdep.c
 create mode 100644 gdb/none-tdep.h
 create mode 100644 gdb/riscv-none-tdep.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9267bea7beb..5f88b6a78cf 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -807,6 +807,7 @@ ALL_TARGET_OBS = \
 	ravenscar-thread.o \
 	riscv-fbsd-tdep.o \
 	riscv-linux-tdep.o \
+	riscv-none-tdep.o \
 	riscv-ravenscar-thread.o \
 	riscv-tdep.o \
 	rl78-tdep.o \
@@ -1100,6 +1101,7 @@ COMMON_SFILES = \
 	minsyms.c \
 	mipsread.c \
 	namespace.c \
+	none-tdep.c \
 	objc-lang.c \
 	objfiles.c \
 	observable.c \
@@ -1360,6 +1362,7 @@ HFILES_NO_SRCDIR = \
 	netbsd-tdep.h \
 	nds32-tdep.h \
 	nios2-tdep.h \
+	none-tdep.h \
 	nto-tdep.h \
 	objc-lang.h \
 	objfiles.h \
@@ -2271,6 +2274,7 @@ ALLDEPFILES = \
 	riscv-fbsd-tdep.c \
 	riscv-linux-nat.c \
 	riscv-linux-tdep.c \
+	riscv-none-tdep.c \
 	riscv-ravenscar-thread.c \
 	riscv-tdep.c \
 	rl78-tdep.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 6e039838748..ad88ddd9302 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -85,7 +85,7 @@ ia64*-*-*)
 	;;
 
 riscv*-*-*)
-	cpu_obs="riscv-tdep.o arch/riscv.o \
+	cpu_obs="riscv-tdep.o riscv-none-tdep.o arch/riscv.o \
 	         ravenscar-thread.o riscv-ravenscar-thread.o";;
 
 x86_64-*-*)
diff --git a/gdb/none-tdep.c b/gdb/none-tdep.c
new file mode 100644
index 00000000000..8ec2407ad45
--- /dev/null
+++ b/gdb/none-tdep.c
@@ -0,0 +1,119 @@
+/* Target-dependent code for none, architecture independent.
+
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "none-tdep.h"
+#include "regset.h"
+#include "elf-bfd.h"            /* for elfcore_write_* */
+#include "inferior.h"
+#include "regcache.h"
+#include "gdbarch.h"
+#include "gcore.h"
+
+/* Build the note section for a corefile, and return it in a malloc
+   buffer.  Currently this just  dumps all available registers for each
+   thread.  */
+
+static gdb::unique_xmalloc_ptr<char>
+none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
+{
+  gdb::unique_xmalloc_ptr<char> note_data;
+
+  /* Add note information about the executable and its arguments.  */
+  std::string fname;
+  std::string psargs;
+  static const size_t fname_len = 16;
+  static const size_t psargs_len = 80;
+  if (get_exec_file (0))
+    {
+      const char *exe = get_exec_file (0);
+      fname = lbasename (exe);
+      psargs = std::string (exe);
+
+      const char *infargs = get_inferior_args ();
+      if (infargs != nullptr)
+	psargs += " " + std::string (infargs);
+
+      /* All existing targets that handling writing out prpsinfo expect the
+	 fname and psargs strings to be at least 16 and 80 characters long
+	 respectively, including a null terminator at the end.  Resize to
+	 the expected length minus one to ensure there is a null within the
+	 required length.  */
+      fname.resize (fname_len - 1);
+      psargs.resize (psargs_len - 1);
+    }
+
+  /* Resize the buffers up to their required lengths.  This will fill any
+     remaining space with the null character.  */
+  fname.resize (fname_len);
+  psargs.resize (psargs_len);
+
+  /* Now write out the prpsinfo structure.  */
+  note_data.reset (elfcore_write_prpsinfo (obfd, note_data.release (),
+					   note_size, fname.c_str (),
+					   psargs.c_str ()));
+  if (note_data == nullptr)
+    return nullptr;
+
+  /* Thread register information.  */
+  try
+    {
+      update_thread_list ();
+    }
+  catch (const gdb_exception_error &e)
+    {
+      exception_print (gdb_stderr, e);
+    }
+
+  /* Like the Linux 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 ();
+
+  /* All threads are reported as having been stopped by the same signal
+     that stopped SIGNALLED_THR.  */
+  gdb_signal stop_signal;
+  if (signalled_thr != nullptr)
+    stop_signal = signalled_thr->suspend.stop_signal;
+  else
+    stop_signal = GDB_SIGNAL_0;
+
+  if (signalled_thr != nullptr)
+    gcore_build_thread_register_notes (gdbarch, signalled_thr,
+				       stop_signal, obfd, &note_data,
+				       note_size);
+  for (thread_info *thr : current_inferior ()->non_exited_threads ())
+    {
+      if (thr == signalled_thr)
+	continue;
+
+      gcore_build_thread_register_notes (gdbarch, thr, stop_signal, obfd,
+					 &note_data, note_size);
+    }
+
+  return note_data;
+}
+
+/* See none-tdep.h.  */
+
+void
+none_init_abi (struct gdbarch *gdbarch)
+{
+  /* Default core file support.  */
+  set_gdbarch_make_corefile_notes (gdbarch, none_make_corefile_notes);
+}
diff --git a/gdb/none-tdep.h b/gdb/none-tdep.h
new file mode 100644
index 00000000000..46dcfe219ef
--- /dev/null
+++ b/gdb/none-tdep.h
@@ -0,0 +1,30 @@
+/* Architecture independent code for ABI 'none' (bare-metal).
+
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NONE_TDEP_H
+#define NONE_TDEP_H
+
+struct gdbarch;
+
+/* Initialize support for cross-architecture features applicable for the
+   GDB_OSABI_NONE ABI, that is bare-metal targets.  */
+
+void none_init_abi (struct gdbarch *gdbarch);
+
+#endif /* NONE_TDEP_H */
diff --git a/gdb/riscv-none-tdep.c b/gdb/riscv-none-tdep.c
new file mode 100644
index 00000000000..e06ee0981fe
--- /dev/null
+++ b/gdb/riscv-none-tdep.c
@@ -0,0 +1,108 @@
+/* Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This file contain code that is specific for bare-metal RISC-V targets.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "riscv-tdep.h"
+#include "elf-bfd.h"
+#include "regset.h"
+#include "none-tdep.h"
+
+/* Define the general register mapping.  This follows the same format as
+   the RISC-V linux corefile.  The linux kernel puts the PC at offset 0,
+   gdb puts it at offset 32.  Register x0 is always 0 and can be ignored.
+   Registers x1 to x31 are in the same place.  */
+
+static const struct regcache_map_entry riscv_gregmap[] =
+{
+  { 1,  RISCV_PC_REGNUM, 0 },
+  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
+  { 0 }
+};
+
+/* Define the FP register mapping.  This follows the same format as the
+   RISC-V linux corefile.  The kernel puts the 32 FP regs first, and then
+   FCSR.  */
+
+static const struct regcache_map_entry riscv_fregmap[] =
+{
+  { 32, RISCV_FIRST_FP_REGNUM, 0 },
+  { 1, RISCV_CSR_FCSR_REGNUM, 4 },	/* Always stored as 4-bytes.  */
+  { 0 }
+};
+
+/* Define the general register regset.  */
+
+static const struct regset riscv_gregset =
+{
+  riscv_gregmap, riscv_supply_regset, regcache_collect_regset
+};
+
+/* Define the FP register regset.  */
+
+static const struct regset riscv_fregset =
+{
+  riscv_fregmap, riscv_supply_regset, regcache_collect_regset
+};
+
+/* Implement the "iterate_over_regset_sections" gdbarch method.  */
+
+static void
+riscv_iterate_over_regset_sections (struct gdbarch *gdbarch,
+				    iterate_over_regset_sections_cb *cb,
+				    void *cb_data,
+				    const struct regcache *regcache)
+{
+  /* Write out the GPRs.  */
+  int sz = 32 * riscv_isa_xlen (gdbarch);
+  cb (".reg", sz, sz, &riscv_gregset, NULL, cb_data);
+
+  /* Write out the FPRs, but only if present.  */
+  if (riscv_isa_flen (gdbarch) > 0)
+    {
+      sz = (32 * riscv_isa_flen (gdbarch)
+	    + register_size (gdbarch, RISCV_CSR_FCSR_REGNUM));
+      cb (".reg2", sz, sz, &riscv_fregset, NULL, cb_data);
+    }
+}
+
+/* Initialize RISC-V bare-metal ABI info.  */
+
+static void
+riscv_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  none_init_abi (gdbarch);
+
+  /* Iterate over registers for reading and writing bare metal RISC-V core
+     files.  */
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, riscv_iterate_over_regset_sections);
+
+}
+
+/* Initialize RISC-V bare-metal target support.  */
+
+void _initialize_riscv_none_tdep ();
+void
+_initialize_riscv_none_tdep ()
+{
+  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_NONE,
+			  riscv_none_init_abi);
+}
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 6/9] bfd/binutils: add support for RISC-V CSRs in core files
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
                   ` (4 preceding siblings ...)
  2021-01-20 20:23 ` [PATCHv2 5/9] gdb/riscv: introduce bare metal core dump support Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-02-01 12:00   ` Andrew Burgess
  2021-01-20 20:23 ` [PATCHv2 7/9] gdb/riscv: make riscv target description names global Andrew Burgess
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

Adds support for including RISC-V control and status registers into
core files.

The value for the define NT_RISCV_CSR is set to 0x900, this
corresponds to a patch I have proposed for the Linux kernel here:

  http://lists.infradead.org/pipermail/linux-riscv/2020-December/003910.html

bfd/ChangeLog:

	* elf-bfd.h (elfcore_write_riscv_csr): Declare.
	* elf.c (elfcore_grok_riscv_csr): New function.
	(elfcore_grok_note): Handle NT_RISCV_CSR.
	(elfcore_write_riscv_csr): New function.
	(elfcore_write_register_note): Handle '.reg-riscv-csr'.

binutils/ChangeLog:

	* readelf.c (get_note_type): Handle NT_RISCV_CSR.

include/ChangeLog:

	* elf/common.h (NT_RISCV_CSR): Define.
---
 bfd/ChangeLog        |  9 +++++++++
 bfd/elf-bfd.h        |  2 ++
 bfd/elf.c            | 31 +++++++++++++++++++++++++++----
 binutils/ChangeLog   |  5 +++++
 binutils/readelf.c   |  2 ++
 include/ChangeLog    |  5 +++++
 include/elf/common.h |  2 ++
 7 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 4dce8114c0f..f0d90d070c3 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2797,6 +2797,8 @@ extern char *elfcore_write_aarch_pauth
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_arc_v2
   (bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_riscv_csr
+  (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_gdb_tdesc
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_lwpstatus
diff --git a/bfd/elf.c b/bfd/elf.c
index 9892ffa9faf..bdc15bf21ba 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9912,6 +9912,12 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
 }
 
+static bfd_boolean
+elfcore_grok_riscv_csr (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-riscv-csr", note);
+}
+
 static bfd_boolean
 elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
 {
@@ -10579,6 +10585,9 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
     case NT_GDB_TDESC:
       return elfcore_grok_gdb_tdesc (abfd, note);
 
+    case NT_RISCV_CSR:
+      return elfcore_grok_riscv_csr (abfd, note);
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -11960,12 +11969,24 @@ elfcore_write_arc_v2 (bfd *abfd,
 			     note_name, NT_ARC_V2, arc_v2, size);
 }
 
+char *
+elfcore_write_riscv_csr (bfd *abfd,
+                         char *buf,
+                         int *bufsiz,
+                         const void *csrs,
+                         int size)
+{
+  const char *note_name = "CORE";
+  return elfcore_write_note (abfd, buf, bufsiz,
+			     note_name, NT_RISCV_CSR, csrs, size);
+}
+
 char *
 elfcore_write_gdb_tdesc (bfd *abfd,
-			 char *buf,
-			 int *bufsiz,
-			 const void *tdesc,
-			 int size)
+                     char *buf,
+                     int *bufsiz,
+                     const void *tdesc,
+                     int size)
 {
   const char *note_name = "CORE";
   return elfcore_write_note (abfd, buf, bufsiz,
@@ -12058,6 +12079,8 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".gdb-tdesc") == 0)
     return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-riscv-csr") == 0)
+    return elfcore_write_riscv_csr (abfd, buf, bufsiz, data, size);
   return NULL;
 }
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index feb458877c8..807eccfb026 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18374,6 +18374,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
 	return _("NT_ARM_HW_WATCH (AArch hardware watchpoint registers)");
       case NT_ARC_V2:
 	return _("NT_ARC_V2 (ARC HS accumulator/extra registers)");
+      case NT_RISCV_CSR:
+	return _("NT_RISCV_CSR (RISC-V control and status registers)");
       case NT_PSTATUS:
 	return _("NT_PSTATUS (pstatus structure)");
       case NT_FPREGS:
diff --git a/include/elf/common.h b/include/elf/common.h
index e6e9c278faa..79ec9cc09a8 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -674,6 +674,8 @@
 					/*   note name must be "LINUX".  */
 #define NT_ARC_V2	0x600		/* ARC HS accumulator/extra registers.  */
 					/*   note name must be "LINUX".  */
+#define NT_RISCV_CSR    0x900           /* RISC-V Control and Status Registers */
+                                        /*   note name must be "CORE".  */
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */
 
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 7/9] gdb/riscv: make riscv target description names global
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
                   ` (5 preceding siblings ...)
  2021-01-20 20:23 ` [PATCHv2 6/9] bfd/binutils: add support for RISC-V CSRs in core files Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-02-01 14:22   ` Luis Machado
  2021-01-20 20:23 ` [PATCHv2 8/9] gdb/riscv: write CSRs into baremetal core dumps Andrew Burgess
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

A later commit will need the names of the RISC-V target description
features in files other than riscv-tdep.c.  This commit just makes the
names global strings that can be accessed from other riscv-*.c files.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* riscv-tdep.c (riscv_feature_name_csr): Define.
	(riscv_feature_name_cpu): Define.
	(riscv_feature_name_fpu): Define.
	(riscv_feature_name_virtual): Define.
	(riscv_xreg_feature): Use riscv_feature_name_cpu.
	(riscv_freg_feature): Use riscv_feature_name_fpu.
	(riscv_virtual_feature): Use riscv_feature_name_virtual.
	(riscv_csr_feature): Use riscv_feature_name_csr.
	* riscv-tdep.h (riscv_feature_name_csr): Declare.
---
 gdb/ChangeLog    | 12 ++++++++++++
 gdb/riscv-tdep.c | 14 ++++++++++----
 gdb/riscv-tdep.h |  3 +++
 3 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index b16e7d78fc5..cb917247bab 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -94,6 +94,12 @@ static unsigned int riscv_debug_unwinder = 0;
 
 static unsigned int riscv_debug_gdbarch = 0;
 
+/* The names of the RISC-V target description features.  */
+const char *riscv_feature_name_csr = "org.gnu.gdb.riscv.csr";
+static const char *riscv_feature_name_cpu = "org.gnu.gdb.riscv.cpu";
+static const char *riscv_feature_name_fpu = "org.gnu.gdb.riscv.fpu";
+static const char *riscv_feature_name_virtual = "org.gnu.gdb.riscv.virtual";
+
 /* Cached information about a frame.  */
 
 struct riscv_unwind_cache
@@ -257,7 +263,7 @@ riscv_register_feature::register_info::check
 struct riscv_xreg_feature : public riscv_register_feature
 {
   riscv_xreg_feature ()
-    : riscv_register_feature ("org.gnu.gdb.riscv.cpu")
+    : riscv_register_feature (riscv_feature_name_cpu)
   {
     m_registers =  {
       { RISCV_ZERO_REGNUM + 0, { "zero", "x0" } },
@@ -354,7 +360,7 @@ static const struct riscv_xreg_feature riscv_xreg_feature;
 struct riscv_freg_feature : public riscv_register_feature
 {
   riscv_freg_feature ()
-    : riscv_register_feature ("org.gnu.gdb.riscv.fpu")
+    : riscv_register_feature (riscv_feature_name_fpu)
   {
     m_registers =  {
       { RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" } },
@@ -482,7 +488,7 @@ static const struct riscv_freg_feature riscv_freg_feature;
 struct riscv_virtual_feature : public riscv_register_feature
 {
   riscv_virtual_feature ()
-    : riscv_register_feature ("org.gnu.gdb.riscv.virtual")
+    : riscv_register_feature (riscv_feature_name_virtual)
   {
     m_registers =  {
       { RISCV_PRIV_REGNUM, { "priv" } }
@@ -518,7 +524,7 @@ static const struct riscv_virtual_feature riscv_virtual_feature;
 struct riscv_csr_feature : public riscv_register_feature
 {
   riscv_csr_feature ()
-    : riscv_register_feature ("org.gnu.gdb.riscv.csr")
+    : riscv_register_feature (riscv_feature_name_csr)
   {
     m_registers = {
 #define DECLARE_CSR(NAME,VALUE,CLASS,DEFINE_VER,ABORT_VER)		\
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index d1f1cf17ba8..154097df5d0 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -160,4 +160,7 @@ extern void riscv_supply_regset (const struct regset *regset,
 				  struct regcache *regcache, int regnum,
 				  const void *regs, size_t len);
 
+/* The names of the RISC-V target description features.  */
+extern const char *riscv_feature_name_csr;
+
 #endif /* RISCV_TDEP_H */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 8/9] gdb/riscv: write CSRs into baremetal core dumps
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
                   ` (6 preceding siblings ...)
  2021-01-20 20:23 ` [PATCHv2 7/9] gdb/riscv: make riscv target description names global Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-02-01 14:33   ` Luis Machado
  2021-01-20 20:23 ` [PATCHv2 9/9] gdb/arm: add support for bare-metal " Andrew Burgess
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

Use the current target description to include CSRs into the RISC-V
baremetal core dumps.

Every CSR declared in the current target description will be included
in the core dump.  If a CSR fails to read then the value 0 will be
placed into the core dump instead.

It will be critical for users that they have the same target
description in use when loading the core file as was in use when
writing the core file.  This should be fine if the user allows the
target description to be written into the core file.

In more detail, this commit adds a NT_RISCV_CSR note type.  The
contents of this section is a series of either 4-byte (on RV32
targets), or 8-byte (on RV64 targets) regions.  Every CSR that
is mentioned in the current target description is written into one of
these regions in the order that the registers appear in the target
description.  As a consequence it is critical that the exact same
target description, including the same register order, is in use when
the CSRs are loaded from the core file.

gdb/ChangeLog:

	* riscv-non-tdep.c (riscv_csrset): New static global.
	(riscv_update_csrmap): New function.
	(riscv_iterate_over_regset_sections): Process CSRs.
---
 gdb/ChangeLog         |  7 +++++
 gdb/riscv-none-tdep.c | 60 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/gdb/riscv-none-tdep.c b/gdb/riscv-none-tdep.c
index e06ee0981fe..2392c132e69 100644
--- a/gdb/riscv-none-tdep.c
+++ b/gdb/riscv-none-tdep.c
@@ -24,6 +24,8 @@
 #include "elf-bfd.h"
 #include "regset.h"
 #include "none-tdep.h"
+#include "user-regs.h"
+#include "target-descriptions.h"
 
 /* Define the general register mapping.  This follows the same format as
    the RISC-V linux corefile.  The linux kernel puts the PC at offset 0,
@@ -62,6 +64,42 @@ static const struct regset riscv_fregset =
   riscv_fregmap, riscv_supply_regset, regcache_collect_regset
 };
 
+/* Define the CSR regset, this is not constant as the regmap field is
+   updated dynamically based on the current target description.  */
+
+static struct regset riscv_csrset =
+{
+  nullptr, regcache_supply_regset, regcache_collect_regset
+};
+
+/* Update the regmap field of RISCV_CSRSET based on the CSRs available in
+   the current target description.  */
+
+static void
+riscv_update_csrmap (struct gdbarch *gdbarch,
+		     const struct tdesc_feature *feature_csr)
+{
+  int i = 0;
+
+  /* Release any previously defined map.  */
+  delete[] ((struct regcache_map_entry *) riscv_csrset.regmap);
+
+  /* Now create a register map for every csr found in the target
+     description.  */
+  struct regcache_map_entry *riscv_csrmap
+    = new struct regcache_map_entry[feature_csr->registers.size() + 1];
+  for (auto &csr : feature_csr->registers)
+    {
+      int regnum = user_reg_map_name_to_regnum (gdbarch, csr->name.c_str(),
+						csr->name.length());
+      riscv_csrmap[i++] = {1, regnum, 0};
+    }
+
+  /* Mark the end of the array.  */
+  riscv_csrmap[i] = {0};
+  riscv_csrset.regmap = riscv_csrmap;
+}
+
 /* Implement the "iterate_over_regset_sections" gdbarch method.  */
 
 static void
@@ -81,6 +119,28 @@ riscv_iterate_over_regset_sections (struct gdbarch *gdbarch,
 	    + register_size (gdbarch, RISCV_CSR_FCSR_REGNUM));
       cb (".reg2", sz, sz, &riscv_fregset, NULL, cb_data);
     }
+
+  /* Read or write the CSRs.  The set of CSRs is defined by the current
+     target description.  The user is responsible for ensuring that the
+     same target description is in use when reading the core file as was
+     in use when writing the core file.  */
+  const struct target_desc *tdesc = gdbarch_target_desc (gdbarch);
+
+  /* Do not dump/load any CSRs if there is no target description or the target
+     description does not contain any CSRs.  */
+  if (tdesc != nullptr)
+    {
+      const struct tdesc_feature *feature_csr
+        = tdesc_find_feature (tdesc, riscv_feature_name_csr);
+      if (feature_csr != nullptr && feature_csr->registers.size () > 0)
+	{
+	  riscv_update_csrmap (gdbarch, feature_csr);
+	  cb (".reg-riscv-csr",
+	      (feature_csr->registers.size() * riscv_isa_xlen (gdbarch)),
+	      (feature_csr->registers.size() * riscv_isa_xlen (gdbarch)),
+	      &riscv_csrset, NULL, cb_data);
+	}
+    }
 }
 
 /* Initialize RISC-V bare-metal ABI info.  */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv2 9/9] gdb/arm: add support for bare-metal core dumps
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
                   ` (7 preceding siblings ...)
  2021-01-20 20:23 ` [PATCHv2 8/9] gdb/riscv: write CSRs into baremetal core dumps Andrew Burgess
@ 2021-01-20 20:23 ` Andrew Burgess
  2021-02-01 14:51   ` Luis Machado
  2021-01-22 19:28 ` [PATCHv2 0/9] Bare-metal core dumps for RISC-V Tom Tromey
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
  10 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-01-20 20:23 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna, Andrew Burgess

This commit is just a trimmed down version of Fredrik's patch (link
below), updated to fit in with my new common core dumping code.

As a significant piece of work Fredrik would need a copyright
assignment in place before this could be merged.  I don't know if that
is the case or not.

As with the RISC-V patch (#5) the documentation of the core file
format is given in the commit message, but it really needs a "better"
home.  Unlike RISC-V, I don't know where that home is for ARM.

I would prefer if most feedback on the documentation was given on the
RISC-V patch (#5 in this series), unless you're pointing out an error
that is specific just to this patch.

I have checked that this code builds, but otherwise I've done no
testing on this at all.  I assume Fredrik gave this some testing
before posting, but I have mucked about with things, so I'm sure any
mistakes are mine.

Thanks,
Andrew


---

This commit adds support for bare metal core dumps on the ARM target,
and is based off of this patch submitted to the mailing list:

  https://sourceware.org/pipermail/gdb-patches/2020-October/172845.html

Compared to the version linked above this version is updated to take
account of recent changes to the core dump infrastructure in GDB,
there is now more shared infrastructure for core dumping within GDB,
and also some common bare metal core dumping infrastructure.  As a
result this patch is smaller than the original proposed patch.

Further, the original patch included some unrelated changes to the
simulator that have been removed from this version.

I have written a ChangeLog entry as the original patch was missing
one.

I have done absolutely no testing of this patch.  It is based on the
original submitted patch, which I assume was tested, but after my
modifications things might have been broken.

The cores dump format is based around generating an ELF containing
sections for the writable regions of memory that a user could be
using.  Which regions are dumped rely on GDB's existing common core
dumping code, GDB will attempt to figure out the stack and heap as
well as copying out writable data sections as identified by the
original ELF.

Register information is added to the core dump using notes, just as it
is for Linux of FreeBSD core dumps.  The note types used consist of
the 2 basic types you would expect in a OS based core dump,
NT_PRPSINFO, NT_PRSTATUS, along with the architecture specific
NT_ARM_VFP note.

The data layouts for each note type are described blow, in all case,
all padding fields should be set to zero.

Note NT_PRPSINFO is optional.  Its data layout is:

  struct prpsinfo_t
  {
    uint8_t padding[28];
    char fname[16];
    char psargs[80];
  }

Field 'fname' - null terminated string consisting of the basename of
    (up to the fist 15 characters of) the executable.  Any additional
    space should be set to zero.  If there's no executable name then
    this field can be set to all zero.

Field 'psargs' - a null terminated string up to 80 characters in
    length.  Any additional space should be filled with zero.  This
    field contains the full executable path and any arguments passed
    to the executable.  If there's nothing sensible to write in this
    field then fill it with zero.

Note NT_PRSTATUS is required, its data layout is:

  struct prstatus_t
  {
    uint8_t padding_1[12];
    uint16_t sig;
    uint8_t padding_2[10];
    uint32_t thread_id;
    uint8_t padding_3[44];
    uint32_t gregs[18];
  }

Field 'sig' - the signal that stopped this thread.  Its implementation
    defined what this field actually means.  Within GDB this will be
    the signal number that the remote target reports as the stop
    reason for this thread.

Field 'thread_is' - the thread id for this thread, its implementation
    defined what this field actually means.  Within GDB this will be
    thread thread-id that is assigned to each remote thread.

Field 'gregs' - holds the general purpose registers $a1 through to $pc
    at indices 0 to 15.  At index 16 the program status register.
    Index 17 should be set to zero.

Note NT_ARM_VFP is optional, its data layout is:

  armvfp_t
  {
    uint64_t regs[32];
    uint32_t fpscr;
  }

Field 'regs' - holds the 32 d-registers 0 to 31 in order.

Field 'fpscr' - holds the fpscr register.

The rules for ordering the notes is the same as for Linux.  The
NT_PRSTATUS note must come before any other notes about additional
register sets.  And for multi-threaded targets all registers for a
single thread should be grouped together.  This is because only
NT_PRSTATUS includes a thread-id, all additional register notes after
a NT_PRSTATUS are assumed to belong to the same thread until a
different NT_PRSTATUS is seen.

gdb/ChangeLog:

	PR gdb/14383
	* Makefile.in (ALL_TARGET_OBS): Add arm-none-tdep.o.
	(ALLDEPFILES): Add arm-none-tdep.c
	* arm-none-tdep.c: New file.
	* configure.tgt (arm*-*-*): Add arm-none-tdep.o to cpu_obs.
---
 gdb/ChangeLog       |   9 ++
 gdb/Makefile.in     |   2 +
 gdb/arm-none-tdep.c | 208 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.tgt   |   3 +-
 4 files changed, 221 insertions(+), 1 deletion(-)
 create mode 100644 gdb/arm-none-tdep.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5f88b6a78cf..c40dd7d4688 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -726,6 +726,7 @@ ALL_TARGET_OBS = \
 	arm-fbsd-tdep.o \
 	arm-linux-tdep.o \
 	arm-netbsd-tdep.o \
+	arm-none-tdep.o \
 	arm-obsd-tdep.o \
 	arm-pikeos-tdep.o \
 	arm-symbian-tdep.o \
@@ -2167,6 +2168,7 @@ ALLDEPFILES = \
 	arm-linux-tdep.c \
 	arm-netbsd-nat.c \
 	arm-netbsd-tdep.c \
+	arm-none-tdep.c \
 	arm-obsd-tdep.c \
 	arm-symbian-tdep.c \
 	arm-tdep.c \
diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
new file mode 100644
index 00000000000..199ac652129
--- /dev/null
+++ b/gdb/arm-none-tdep.c
@@ -0,0 +1,208 @@
+/* none on ARM target support.
+
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arm-tdep.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "elf-bfd.h"
+#include "regset.h"
+#include "none-tdep.h"
+#include "user-regs.h"
+
+/* Core file and register set support.  */
+#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
+
+/* Support VFP register format.  */
+#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
+
+/* The index to access CSPR in user_regs as defined in GLIBC.  */
+#define ARM_NONE_CPSR_GREGNUM 16
+
+/* Supply register REGNUM from buffer GREGS_BUF (length LEN bytes) into
+   REGCACHE.  If REGNUM is -1 then supply all registers.  The set of
+   registers that this function will supply is limited to the general
+   purpose registers.
+
+   The layout of the registers here is based on the ARM GNU/Linux
+   layout.  */
+
+static void
+arm_none_supply_gregset (const struct regset *regset,
+			 struct regcache *regcache,
+			 int regnum, const void *gregs_buf, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
+
+  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
+
+  if (regnum == ARM_PS_REGNUM || regnum == -1)
+    {
+      if (arm_apcs_32)
+	regcache->raw_supply (ARM_PS_REGNUM,
+			      gregs + ARM_INT_REGISTER_SIZE
+			      * ARM_NONE_CPSR_GREGNUM);
+      else
+	regcache->raw_supply (ARM_PS_REGNUM,
+			     gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
+    }
+
+  if (regnum == ARM_PC_REGNUM || regnum == -1)
+    {
+      gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
+
+      CORE_ADDR reg_pc
+	= extract_unsigned_integer (gregs + ARM_INT_REGISTER_SIZE
+				    * ARM_PC_REGNUM,
+				    ARM_INT_REGISTER_SIZE, byte_order);
+      reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
+      store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
+			      reg_pc);
+      regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
+    }
+}
+
+/* Collect register REGNUM from REGCACHE and place it into buffer GREGS_BUF
+   (length LEN bytes).  If REGNUM is -1 then collect all registers.  The
+   set of registers that this function will collect is limited to the
+   general purpose registers.
+
+   The layout of the registers here is based on the ARM GNU/Linux
+   layout.  */
+
+static void
+arm_none_collect_gregset (const struct regset *regset,
+			  const struct regcache *regcache,
+			  int regnum, void *gregs_buf, size_t len)
+{
+  gdb_byte *gregs = (gdb_byte *) gregs_buf;
+
+  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_collect (regno,
+			     gregs + ARM_INT_REGISTER_SIZE * regno);
+
+  if (regnum == ARM_PS_REGNUM || regnum == -1)
+    {
+      if (arm_apcs_32)
+	regcache->raw_collect (ARM_PS_REGNUM,
+			       gregs + ARM_INT_REGISTER_SIZE
+			       * ARM_NONE_CPSR_GREGNUM);
+      else
+	regcache->raw_collect (ARM_PS_REGNUM,
+			       gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
+    }
+
+  if (regnum == ARM_PC_REGNUM || regnum == -1)
+    regcache->raw_collect (ARM_PC_REGNUM,
+			   gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
+}
+
+/* Supply VFP registers from REGS_BUF into REGCACHE.  */
+
+static void
+arm_none_supply_vfp (const struct regset *regset,
+		     struct regcache *regcache,
+		     int regnum, const void *regs_buf, size_t len)
+{
+  const gdb_byte *regs = (const gdb_byte *) regs_buf;
+
+  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
+    regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
+
+  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
+}
+
+/* Collect VFP registers from REGCACHE into REGS_BUF.  */
+
+static void
+arm_none_collect_vfp (const struct regset *regset,
+		      const struct regcache *regcache,
+		      int regnum, void *regs_buf, size_t len)
+{
+  gdb_byte *regs = (gdb_byte *) regs_buf;
+
+  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
+    regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
+
+  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
+}
+
+/* The general purpose register set.  */
+
+static const struct regset arm_none_gregset =
+  {
+    nullptr, arm_none_supply_gregset, arm_none_collect_gregset
+  };
+
+/* The VFP register set.  */
+
+static const struct regset arm_none_vfpregset =
+  {
+    nullptr, arm_none_supply_vfp, arm_none_collect_vfp
+  };
+
+/* Iterate over core file register note sections.  */
+
+static void
+arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
+				       iterate_over_regset_sections_cb *cb,
+				       void *cb_data,
+				       const struct regcache *regcache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET,
+      &arm_none_gregset, nullptr, cb_data);
+
+  if (tdep->vfp_register_count > 0)
+    cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP,
+	&arm_none_vfpregset, "VFP floating-point", cb_data);
+}
+
+/* Initialize ARM bare-metal ABI info.  */
+
+static void
+arm_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  none_init_abi (gdbarch);
+
+  /* Iterate over registers for reading and writing bare metal ARM core
+     files.  */
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, arm_none_iterate_over_regset_sections);
+}
+
+/* Initialize ARM bare-metal target support.  */
+
+void _initialize_arm_none_tdep ();
+void
+_initialize_arm_none_tdep ()
+{
+  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NONE,
+			  arm_none_init_abi);
+}
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index ad88ddd9302..4f3b9df90d7 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -65,7 +65,8 @@ arc*-*-*)
 
 arm*-*-*)
 	cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \
-		 arch/arm-get-next-pcs.o arm-tdep.o";;
+		 arch/arm-get-next-pcs.o arm-tdep.o arm-none-tdep.o"
+	;;
 
 hppa*-*-*)
 	# Target: HP PA-RISC
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-01-20 20:23 ` [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
@ 2021-01-22 10:47   ` Strasuns, Mihails
  2021-01-22 19:30     ` Andrew Burgess
  2021-02-01 12:05   ` PING: " Andrew Burgess
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 57+ messages in thread
From: Strasuns, Mihails @ 2021-01-22 10:47 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

> -----Original Message-----
> From: Gdb-patches <gdb-patches-bounces@sourceware.org> On Behalf Of
> Andrew Burgess
> Sent: Wednesday, January 20, 2021 9:23 PM
> To: gdb-patches@sourceware.org; binutils@sourceware.org
> Cc: Fredrik Hederstierna <fredrik@hederstierna.com>
> Subject: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in
> the core file
> 
> This commit lays the ground work for allowing GDB to write its target
> description into a generated core file.
> 
> The goal of this work is to allow a user to connect to a remote target, capture
> a core file from within GDB, then pass the executable and core file to another
> user and have the user be able to examine the state of the machine without
> needing to connect to a running target.
>
> Different remote targets can have different register sets and this information
> is communicated from the target to GDB in the target description.

Why is it necessary to store a GDB target description for this? Core files already define machine/arch, same as executable ELFs. There still can be some register variation between different platform versions, but it would still need to be denoted somehow in a native core file.

My concern is for making a "GDB core file" and a "native core file" even more different than it is currently on Linux. I guess this is aimed at a barebone environments where there is currently no native core dump support at all but even there it is not guaranteed.
 
> It is possible for a user to extract the target description from GDB and pass
> this along with the core file so that when the core file is used the target
> description can be fed back into GDB, however this is not a great user
> experience.
> 
> It would be nicer, I think, if GDB could write the target description directly
> into the core file, and then make use of this description when loading a core
> file.
> 
> This commit performs the binutils/bfd side of this task, adding the boiler
> plate functions to access the target description from within a core file note,
> and reserving a new number for a note containing the target description.
> 
> Later commits will extend GDB to make use of this.
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928


^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code
  2021-01-20 20:23 ` [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
@ 2021-01-22 12:01   ` Strasuns, Mihails
  2021-01-22 18:50   ` Tom Tromey
  2021-02-01 11:56   ` Andrew Burgess
  2 siblings, 0 replies; 57+ messages in thread
From: Strasuns, Mihails @ 2021-01-22 12:01 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

> -----Original Message-----
> From: Gdb-patches <gdb-patches-bounces@sourceware.org> On Behalf Of
> Andrew Burgess
> Sent: Wednesday, January 20, 2021 9:23 PM
> To: gdb-patches@sourceware.org; binutils@sourceware.org
> Cc: Fredrik Hederstierna <fredrik@hederstierna.com>
> Subject: [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core
> dumping code
> 
> While reviewing the Linux and FreeBSD core dumping code within GDB for
> another patch series, I noticed that the code that collects the registers for
> each thread and writes these into ELF note format is basically identical
> between Linux and FreeBSD.

Thank you, this is very useful. I was recently looking into adding a core file support for a new arch and ended up copying most of this exact code.

Mihails
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code
  2021-01-20 20:23 ` [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
  2021-01-22 12:01   ` Strasuns, Mihails
@ 2021-01-22 18:50   ` Tom Tromey
  2021-02-01 11:56   ` Andrew Burgess
  2 siblings, 0 replies; 57+ messages in thread
From: Tom Tromey @ 2021-01-22 18:50 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, binutils, Fredrik Hederstierna

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Andrew> While reviewing the Linux and FreeBSD core dumping code within GDB for
Andrew> another patch series, I noticed that the code that collects the
Andrew> registers for each thread and writes these into ELF note format is
Andrew> basically identical between Linux and FreeBSD.

Andrew> This commit merges this code and moves it into the gcore.c file,
Andrew> which seemed like the right place for generic writing a core file
Andrew> code.

FWIW this looks reasonable to me.

Tom

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 3/9] gdb: write target description into core file
  2021-01-20 20:23 ` [PATCHv2 3/9] gdb: write target description into " Andrew Burgess
@ 2021-01-22 19:15   ` Tom Tromey
  2021-02-01 13:37   ` Luis Machado
  1 sibling, 0 replies; 57+ messages in thread
From: Tom Tromey @ 2021-01-22 19:15 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, binutils, Fredrik Hederstierna

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Andrew> gdb/ChangeLog:

Andrew> 	* corelow.c: Add 'xml-tdesc.h' include.
Andrew> 	(core_target::read_description): Load the target description from
Andrew> 	the core file when possible.
Andrew> 	* gcore.c: Add 'gdbsupport/tdesc.h' include.
Andrew> 	(write_gcore_file_1): Write out the target description.

Seems reasonable to me.

Andrew> +	  contents [tdesc_note_size] = '\0';

Extra space before the '[' here.

Tom

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 0/9] Bare-metal core dumps for RISC-V
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
                   ` (8 preceding siblings ...)
  2021-01-20 20:23 ` [PATCHv2 9/9] gdb/arm: add support for bare-metal " Andrew Burgess
@ 2021-01-22 19:28 ` Tom Tromey
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
  10 siblings, 0 replies; 57+ messages in thread
From: Tom Tromey @ 2021-01-22 19:28 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, binutils, Fredrik Hederstierna

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Andrew> This is an update of this patch series:
Andrew>   https://sourceware.org/pipermail/gdb-patches/2020-December/173697.html

I skimmed through the rest of this series & it seemed ok to me.

Tom

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-01-22 10:47   ` Strasuns, Mihails
@ 2021-01-22 19:30     ` Andrew Burgess
  2021-01-25 10:11       ` Strasuns, Mihails
  0 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-01-22 19:30 UTC (permalink / raw)
  To: Strasuns, Mihails; +Cc: gdb-patches, binutils, Fredrik Hederstierna

* Strasuns, Mihails <mihails.strasuns@intel.com> [2021-01-22 10:47:23 +0000]:

> > -----Original Message-----
> > From: Gdb-patches <gdb-patches-bounces@sourceware.org> On Behalf Of
> > Andrew Burgess
> > Sent: Wednesday, January 20, 2021 9:23 PM
> > To: gdb-patches@sourceware.org; binutils@sourceware.org
> > Cc: Fredrik Hederstierna <fredrik@hederstierna.com>
> > Subject: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in
> > the core file
> > 
> > This commit lays the ground work for allowing GDB to write its target
> > description into a generated core file.
> > 
> > The goal of this work is to allow a user to connect to a remote target, capture
> > a core file from within GDB, then pass the executable and core file to another
> > user and have the user be able to examine the state of the machine without
> > needing to connect to a running target.
> >
> > Different remote targets can have different register sets and this information
> > is communicated from the target to GDB in the target description.
>
> Why is it necessary to store a GDB target description for this? Core
> files already define machine/arch, same as executable ELFs. There
> still can be some register variation between different platform
> versions, but it would still need to be denoted somehow in a native
> core file.
> 
> My concern is for making a "GDB core file" and a "native core file"
> even more different than it is currently on Linux. I guess this is
> aimed at a barebone environments where there is currently no native
> core dump support at all but even there it is not guaranteed.

I was following you until "... but even there it is not guaranteed."
I'm not sure what it is that is not guaranteed.

Yes, absolutely my interest here is bare metal core dumps, but I don't
see including the target description in all core files as a big
problem.

I'm not aware that GDB was ever aiming to create core dumps that would
be identical to kernel produced dumps, just that they should be
compatible.

Including an extra note should be transparent to any well behaved tool
(I'd hope), or at worst maybe a warning about not understanding the
note

The problem I'm trying to solve is that the RISC-V targets I'm working
with have a pretty random collection of control status registers
(CSRs), included off-spec registers.  I'd like to capture these in the
core dump, so the approach I have right now is just dump all of them
in target description order.

Anyway, back to your concerns...

...would making target description inclusion optional/switchable be
enough to alleviate your concerns?  Would you rather it was default
off, or would you be happy with switchable default on?

Thanks,
Andrew

>  
> > It is possible for a user to extract the target description from GDB and pass
> > this along with the core file so that when the core file is used the target
> > description can be fed back into GDB, however this is not a great user
> > experience.
> > 
> > It would be nicer, I think, if GDB could write the target description directly
> > into the core file, and then make use of this description when loading a core
> > file.
> > 
> > This commit performs the binutils/bfd side of this task, adding the boiler
> > plate functions to access the target description from within a core file note,
> > and reserving a new number for a note containing the target description.
> > 
> > Later commits will extend GDB to make use of this.
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de
> Managing Directors: Christin Eisenschmid, Gary Kershaw
> Chairperson of the Supervisory Board: Nicole Lau
> Registered Office: Munich
> Commercial Register: Amtsgericht Muenchen HRB 186928
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-01-22 19:30     ` Andrew Burgess
@ 2021-01-25 10:11       ` Strasuns, Mihails
  2021-01-25 11:20         ` Andrew Burgess
  0 siblings, 1 reply; 57+ messages in thread
From: Strasuns, Mihails @ 2021-01-25 10:11 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, binutils, Fredrik Hederstierna

> -----Original Message-----
> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Sent: Friday, January 22, 2021 8:30 PM
> To: Strasuns, Mihails <mihails.strasuns@intel.com>
> Cc: gdb-patches@sourceware.org; binutils@sourceware.org; Fredrik
> Hederstierna <fredrik@hederstierna.com>
> Subject: Re: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions
> in the core file
> 
> * Strasuns, Mihails <mihails.strasuns@intel.com> [2021-01-22 10:47:23
> +0000]:
> 
> > > -----Original Message-----
> > > From: Gdb-patches <gdb-patches-bounces@sourceware.org> On Behalf
> Of
> > > Andrew Burgess
> > > Sent: Wednesday, January 20, 2021 9:23 PM
> > > To: gdb-patches@sourceware.org; binutils@sourceware.org
> > > Cc: Fredrik Hederstierna <fredrik@hederstierna.com>
> > > Subject: [PATCHv2 2/9] bfd/binutils: support for gdb target
> > > descriptions in the core file
> > >
> > > This commit lays the ground work for allowing GDB to write its
> > > target description into a generated core file.
> > >
> > > The goal of this work is to allow a user to connect to a remote
> > > target, capture a core file from within GDB, then pass the
> > > executable and core file to another user and have the user be able
> > > to examine the state of the machine without needing to connect to a
> running target.
> > >
> > > Different remote targets can have different register sets and this
> > > information is communicated from the target to GDB in the target
> description.
> >
> > Why is it necessary to store a GDB target description for this? Core
> > files already define machine/arch, same as executable ELFs. There
> > still can be some register variation between different platform
> > versions, but it would still need to be denoted somehow in a native
> > core file.
> >
> > My concern is for making a "GDB core file" and a "native core file"
> > even more different than it is currently on Linux. I guess this is
> > aimed at a barebone environments where there is currently no native
> > core dump support at all but even there it is not guaranteed.
> 
> I was following you until "... but even there it is not guaranteed."
> I'm not sure what it is that is not guaranteed.

I have meant that even for a barebone platform that doesn't have any native core dump capabilities it theoretically can be added through firmware - and GDB would want to support that format too.
From you description below it seems impractical to worry about it right now though.

> Yes, absolutely my interest here is bare metal core dumps, but I don't see
> including the target description in all core files as a big problem.
> 
> I'm not aware that GDB was ever aiming to create core dumps that would be
> identical to kernel produced dumps, just that they should be compatible.
> 
> Including an extra note should be transparent to any well behaved tool (I'd
> hope), or at worst maybe a warning about not understanding the note
> 
> The problem I'm trying to solve is that the RISC-V targets I'm working with
> have a pretty random collection of control status registers (CSRs), included
> off-spec registers.  I'd like to capture these in the core dump, so the
> approach I have right now is just dump all of them in target description order.
>
> Anyway, back to your concerns...
> 
> ...would making target description inclusion optional/switchable be enough
> to alleviate your concerns?  Would you rather it was default off, or would you
> be happy with switchable default on?

I don't have a strong preference here, it is probably fine as it is. GDB test suite covers both native core and a generated one as separate test cases, correct? 

Context: I am currently looking into core dump support for Intel GPUs and using generate-core as a convenient way to quickly iterate through the different format prototypes.
However it is not affected by your patch, I was more curious/concerned about a general direction here.

> Thanks,
> Andrew
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-01-25 10:11       ` Strasuns, Mihails
@ 2021-01-25 11:20         ` Andrew Burgess
  0 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-01-25 11:20 UTC (permalink / raw)
  To: Strasuns, Mihails; +Cc: gdb-patches, binutils, Fredrik Hederstierna

* Strasuns, Mihails <mihails.strasuns@intel.com> [2021-01-25 10:11:42 +0000]:

> > -----Original Message-----
> > From: Andrew Burgess <andrew.burgess@embecosm.com>
> > Sent: Friday, January 22, 2021 8:30 PM
> > To: Strasuns, Mihails <mihails.strasuns@intel.com>
> > Cc: gdb-patches@sourceware.org; binutils@sourceware.org; Fredrik
> > Hederstierna <fredrik@hederstierna.com>
> > Subject: Re: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions
> > in the core file
> > 
> > * Strasuns, Mihails <mihails.strasuns@intel.com> [2021-01-22 10:47:23
> > +0000]:
> > 
> > > > -----Original Message-----
> > > > From: Gdb-patches <gdb-patches-bounces@sourceware.org> On Behalf
> > Of
> > > > Andrew Burgess
> > > > Sent: Wednesday, January 20, 2021 9:23 PM
> > > > To: gdb-patches@sourceware.org; binutils@sourceware.org
> > > > Cc: Fredrik Hederstierna <fredrik@hederstierna.com>
> > > > Subject: [PATCHv2 2/9] bfd/binutils: support for gdb target
> > > > descriptions in the core file
> > > >
> > > > This commit lays the ground work for allowing GDB to write its
> > > > target description into a generated core file.
> > > >
> > > > The goal of this work is to allow a user to connect to a remote
> > > > target, capture a core file from within GDB, then pass the
> > > > executable and core file to another user and have the user be able
> > > > to examine the state of the machine without needing to connect to a
> > running target.
> > > >
> > > > Different remote targets can have different register sets and this
> > > > information is communicated from the target to GDB in the target
> > description.
> > >
> > > Why is it necessary to store a GDB target description for this? Core
> > > files already define machine/arch, same as executable ELFs. There
> > > still can be some register variation between different platform
> > > versions, but it would still need to be denoted somehow in a native
> > > core file.
> > >
> > > My concern is for making a "GDB core file" and a "native core file"
> > > even more different than it is currently on Linux. I guess this is
> > > aimed at a barebone environments where there is currently no native
> > > core dump support at all but even there it is not guaranteed.
> > 
> > I was following you until "... but even there it is not guaranteed."
> > I'm not sure what it is that is not guaranteed.
> 
> I have meant that even for a barebone platform that doesn't have any
> native core dump capabilities it theoretically can be added through
> firmware - and GDB would want to support that format too.

Sure, but for some arbitrary format that would require significant
change in both BFD and GDB probably.

Certainly in the past when I've worked with various non-standard dump
formats its been easier to write a tool that converts the format to
ELF + NOTES and then load that in the normal way.

But I don't see the connection between this and adding target
descriptions to GDB generated dumps.

> From you description below it seems impractical to worry about it
> right now though.

I'm more worried that I don't understand what I should be worried
about :-/

> 
> > Yes, absolutely my interest here is bare metal core dumps, but I don't see
> > including the target description in all core files as a big problem.
> > 
> > I'm not aware that GDB was ever aiming to create core dumps that would be
> > identical to kernel produced dumps, just that they should be compatible.
> > 
> > Including an extra note should be transparent to any well behaved tool (I'd
> > hope), or at worst maybe a warning about not understanding the note
> > 
> > The problem I'm trying to solve is that the RISC-V targets I'm working with
> > have a pretty random collection of control status registers (CSRs), included
> > off-spec registers.  I'd like to capture these in the core dump, so the
> > approach I have right now is just dump all of them in target description order.
> >
> > Anyway, back to your concerns...
> > 
> > ...would making target description inclusion optional/switchable be enough
> > to alleviate your concerns?  Would you rather it was default off, or would you
> > be happy with switchable default on?
> 
> I don't have a strong preference here, it is probably fine as it
> is. GDB test suite covers both native core and a generated one as
> separate test cases, correct?

Yes I believe that there are at least some tests that rely on the OS
to generate a core file.

> Context: I am currently looking into core dump support for Intel
> GPUs and using generate-core as a convenient way to quickly iterate
> through the different format prototypes.
>
> However it is not affected by your patch, I was more
> curious/concerned about a general direction here.

For me personally, I would be happy with GDB adding any additional
information that it knows about the target into a generated core
file.

I'd be willing to accept that this might mean that a GDB generated
core file is more informative than a native core file.

I'd also accept that we might want to look at ways to derive the same
information for a core file that wasn't generated by GDB.

I'd be happy for both mechanisms to co-exist.

Others might disagree - I'm happy with that too :)


After some thought though, I have made one change to this patch.  In
the version below the target description is generated with a note name
of 'GDB' instead of 'CORE'.  This is then checked when the note is
read back in.

This should (hopefully) prevent conflicts in the future, if the note
type (0xff000000) is ever reused by some other core file producer.

Thanks,
Andrew

---


commit 9101b8a935dfe716fd978ef3e47624d0f8956582
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Fri Nov 27 15:41:37 2020 +0000

    bfd/binutils: support for gdb target descriptions in the core file
    
    This commit lays the ground work for allowing GDB to write its target
    description into a generated core file.
    
    The goal of this work is to allow a user to connect to a remote
    target, capture a core file from within GDB, then pass the executable
    and core file to another user and have the user be able to examine the
    state of the machine without needing to connect to a running target.
    
    Different remote targets can have different register sets and this
    information is communicated from the target to GDB in the target
    description.
    
    It is possible for a user to extract the target description from GDB
    and pass this along with the core file so that when the core file is
    used the target description can be fed back into GDB, however this is
    not a great user experience.
    
    It would be nicer, I think, if GDB could write the target description
    directly into the core file, and then make use of this description
    when loading a core file.
    
    This commit performs the binutils/bfd side of this task, adding the
    boiler plate functions to access the target description from within a
    core file note, and reserving a new number for a note containing the
    target description.  Later commits will extend GDB to make use of
    this.
    
    The new note is given the name 'GDB' and a type NT_GDB_TDESC.  This
    should hopefully protect us if there's ever a reuse of the number
    assigned to NT_GDB_TDESC by some other core file producer.  It should
    also, hopefully, make it clearer to users that this note carries GDB
    specific information.
    
    bfd/ChangeLog:
    
            * elf-bfd.h (elfcore_write_gdb_tdesc): Declare new function.
            * elf.c (elfcore_grok_gdb_tdesc): New function.
            (elfcore_grok_note): Handle NT_GDB_TDESC.
            (elfcore_write_gdb_tdesc): New function.
            (elfcore_write_register_note): Handle NT_GDB_TDESC.
    
    binutils/ChangeLog:
    
            * readelf.c (get_note_type): Handle NT_GDB_TDESC.
    
    include/ChangeLog:
    
            * elf/common.h (NT_GDB_TDESC): Define.

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 15206b4e876..4dce8114c0f 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2797,6 +2797,8 @@ extern char *elfcore_write_aarch_pauth
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_arc_v2
   (bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_gdb_tdesc
+  (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_lwpstatus
   (bfd *, char *, int *, long, int, const void *);
 extern char *elfcore_write_register_note
diff --git a/bfd/elf.c b/bfd/elf.c
index 84a5d942817..5b1adf17d8d 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9912,6 +9912,12 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
 }
 
+static bfd_boolean
+elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".gdb-tdesc", note);
+}
+
 #if defined (HAVE_PRPSINFO_T)
 typedef prpsinfo_t   elfcore_psinfo_t;
 #if defined (HAVE_PRPSINFO32_T)		/* Sparc64 cross Sparc32 */
@@ -10570,6 +10576,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
 	return TRUE;
 
+    case NT_GDB_TDESC:
+      if (note->namesz == 4
+          && strcmp (note->namedata, "GDB") == 0)
+        return elfcore_grok_gdb_tdesc (abfd, note);
+      else
+        return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -11951,6 +11964,18 @@ elfcore_write_arc_v2 (bfd *abfd,
 			     note_name, NT_ARC_V2, arc_v2, size);
 }
 
+char *
+elfcore_write_gdb_tdesc (bfd *abfd,
+			 char *buf,
+			 int *bufsiz,
+			 const void *tdesc,
+			 int size)
+{
+  const char *note_name = "GDB";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_GDB_TDESC, tdesc, size);
+}
+
 char *
 elfcore_write_register_note (bfd *abfd,
 			     char *buf,
@@ -12035,6 +12060,8 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-arc-v2") == 0)
     return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".gdb-tdesc") == 0)
+    return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
   return NULL;
 }
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5df51086226..feb458877c8 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18296,6 +18296,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
 	return _("NT_PRPSINFO (prpsinfo structure)");
       case NT_TASKSTRUCT:
 	return _("NT_TASKSTRUCT (task structure)");
+      case NT_GDB_TDESC:
+        return _("NT_GDB_TDESC (GDB XML target description)");
       case NT_PRXFPREG:
 	return _("NT_PRXFPREG (user_xfpregs structure)");
       case NT_PPC_VMX:
diff --git a/include/elf/common.h b/include/elf/common.h
index e7d55ae0782..e6e9c278faa 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -677,6 +677,10 @@
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */
 
+/* The range 0xff000000 to 0xffffffff is set aside for notes that don't
+   originate from any particular operating system.  */
+#define NT_GDB_TDESC	0xff000000	/* Contains copy of GDB's target description XML.  */
+
 /* Note segments for core files on dir-style procfs systems.  */
 
 #define NT_PSTATUS	10		/* Has a struct pstatus */

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code
  2021-01-20 20:23 ` [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
  2021-01-22 12:01   ` Strasuns, Mihails
  2021-01-22 18:50   ` Tom Tromey
@ 2021-02-01 11:56   ` Andrew Burgess
  2021-02-09 21:52     ` Andrew Burgess
  2 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-02-01 11:56 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna

I have pushed this patch only so far as this is a nice clean up in its
own right.

Thanks,
Andrew


* Andrew Burgess <andrew.burgess@embecosm.com> [2021-01-20 20:23:07 +0000]:

> While reviewing the Linux and FreeBSD core dumping code within GDB for
> another patch series, I noticed that the code that collects the
> registers for each thread and writes these into ELF note format is
> basically identical between Linux and FreeBSD.
> 
> This commit merges this code and moves it into the gcore.c file,
> which seemed like the right place for generic writing a core file
> code.
> 
> The function find_signalled_thread is moved from linux-tdep.c despite
> not being shared.  A later commit will make use of this function.
> 
> There are a couple of minor changes to the FreeBSD target after this
> commit, but I believe that these are changes for the better:
> 
> (1) For FreeBSD we always used to record the thread-id in the core file by
> using ptid_t.lwp ().  In contrast the Linux code did this:
> 
>     /* For remote targets the LWP may not be available, so use the TID.  */
>     long lwp = ptid.lwp ();
>     if (lwp == 0)
>       lwp = ptid.tid ();
> 
> Both target now do this:
> 
>     /* The LWP is often not available for bare metal target, in which case
>        use the tid instead.  */
>     if (ptid.lwp_p ())
>       lwp = ptid.lwp ();
>     else
>       lwp = ptid.tid ();
> 
> Which is equivalent for Linux, but is a change for FreeBSD.  I think
> that all this means is that in some cases where GDB might have
> previously recorded a thread-id of 0 for each thread, we might now get
> something more useful.
> 
> (2) When collecting the registers for Linux we collected into a zero
> initialised buffer.  By contrast on FreeBSD the buffer is left
> uninitialised.  In the new code the buffer is always zero initialised.
> I suspect once the registers are copied into the buffer there's
> probably no gaps left so this makes no difference, but if it does then
> using zeros rather than random bits of GDB's memory is probably a good
> thing.
> 
> Otherwise, there should be no other user visible changes after this
> commit.
> 
> Tested this on x86-64/GNU-Linux and x86-64/FreeBSD-12.2 with no
> regressions.
> 
> gdb/ChangeLog:
> 
> 	* Makefile.in (HFILES_NO_SRCDIR): Add corefile.h.
> 	* gcore.c (struct gcore_collect_regset_section_cb_data): Moved
> 	here from linux-tdep.c and given a new name.  Minor cleanups.
> 	(gcore_collect_regset_section_cb): Likewise.
> 	(gcore_collect_thread_registers): Likewise.
> 	(gcore_build_thread_register_notes): Likewise.
> 	(gcore_find_signalled_thread): Likewise.
> 	* gcore.h (gcore_build_thread_register_notes): Declare.
> 	(gcore_find_signalled_thread): Declare.
> 	* fbsd-tdep.c: Add 'gcore.h' include.
> 	(struct fbsd_collect_regset_section_cb_data): Delete.
> 	(fbsd_collect_regset_section_cb): Delete.
> 	(fbsd_collect_thread_registers): Delete.
> 	(struct fbsd_corefile_thread_data): Delete.
> 	(fbsd_corefile_thread): Delete.
> 	(fbsd_make_corefile_notes): Call
> 	gcore_build_thread_register_notes instead of the now deleted
> 	FreeBSD code.
> 	* linux-tdep.c: Add 'gcore.h' include.
> 	(struct linux_collect_regset_section_cb_data): Delete.
> 	(linux_collect_regset_section_cb): Delete.
> 	(linux_collect_thread_registers): Delete.
> 	(linux_corefile_thread): Call
> 	gcore_build_thread_register_notes.
> 	(find_signalled_thread): Delete.
> 	(linux_make_corefile_notes): Call gcore_find_signalled_thread.
> ---
>  gdb/ChangeLog    |  29 ++++++++++
>  gdb/fbsd-tdep.c  | 135 +++------------------------------------------
>  gdb/gcore.c      | 136 +++++++++++++++++++++++++++++++++++++++++++++
>  gdb/gcore.h      |  20 +++++++
>  gdb/linux-tdep.c | 141 +++--------------------------------------------
>  5 files changed, 199 insertions(+), 262 deletions(-)
> 
> diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
> index cc51e921ae2..edd3edc4220 100644
> --- a/gdb/fbsd-tdep.c
> +++ b/gdb/fbsd-tdep.c
> @@ -32,6 +32,7 @@
>  
>  #include "elf-bfd.h"
>  #include "fbsd-tdep.h"
> +#include "gcore.h"
>  
>  /* This enum is derived from FreeBSD's <sys/signal.h>.  */
>  
> @@ -583,129 +584,6 @@ find_signalled_thread (struct thread_info *info, void *data)
>    return 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
> -{
> -  fbsd_collect_regset_section_cb_data (const struct regcache *regcache,
> -				       bfd *obfd,
> -				       gdb::unique_xmalloc_ptr<char> &note_data,
> -				       int *note_size,
> -				       unsigned long lwp,
> -				       gdb_signal stop_signal)
> -    : regcache (regcache),
> -      obfd (obfd),
> -      note_data (note_data),
> -      note_size (note_size),
> -      lwp (lwp),
> -      stop_signal (stop_signal)
> -  {}
> -
> -  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;
> -};
> -
> -static void
> -fbsd_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)
> -{
> -  char *buf;
> -  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 (collect_size);
> -  regset->collect_regset (regset, data->regcache, -1, buf, 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));
> -  else
> -    data->note_data.reset (elfcore_write_register_note
> -			     (data->obfd, data->note_data.release (),
> -			      data->note_size, sect_name, buf,
> -			      collect_size));
> -  xfree (buf);
> -
> -  if (data->note_data == NULL)
> -    data->abort_iteration = true;
> -}
> -
> -/* Records the thread's register state for the corefile note
> -   section.  */
> -
> -static void
> -fbsd_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)
> -{
> -  fbsd_collect_regset_section_cb_data data (regcache, obfd, note_data,
> -					    note_size, ptid.lwp (),
> -					    stop_signal);
> -
> -  gdbarch_iterate_over_regset_sections (regcache->arch (),
> -					fbsd_collect_regset_section_cb,
> -					&data, regcache);
> -}
> -
> -struct fbsd_corefile_thread_data
> -{
> -  fbsd_corefile_thread_data (struct gdbarch *gdbarch,
> -			     bfd *obfd,
> -			     gdb::unique_xmalloc_ptr<char> &note_data,
> -			     int *note_size,
> -			     gdb_signal stop_signal)
> -    : gdbarch (gdbarch),
> -      obfd (obfd),
> -      note_data (note_data),
> -      note_size (note_size),
> -      stop_signal (stop_signal)
> -  {}
> -
> -  struct gdbarch *gdbarch;
> -  bfd *obfd;
> -  gdb::unique_xmalloc_ptr<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 regcache *regcache;
> -
> -  regcache = get_thread_arch_regcache (info->inf->process_target (),
> -				       info->ptid, args->gdbarch);
> -
> -  target_fetch_registers (regcache, -1);
> -
> -  fbsd_collect_thread_registers (regcache, info->ptid, args->obfd,
> -				 args->note_data, args->note_size,
> -				 args->stop_signal);
> -}
> -
>  /* Return a byte_vector containing the contents of a core dump note
>     for the target object of type OBJECT.  If STRUCTSIZE is non-zero,
>     the data is prefixed with a 32-bit integer size to match the format
> @@ -782,16 +660,17 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
>  	signalled_thr = curr_thr;
>      }
>  
> -  fbsd_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
> -					 signalled_thr->suspend.stop_signal);
> -
> -  fbsd_corefile_thread (signalled_thr, &thread_args);
> +  gcore_build_thread_register_notes (gdbarch, signalled_thr,
> +				     signalled_thr->suspend.stop_signal,
> +				     obfd, &note_data, note_size);
>    for (thread_info *thr : current_inferior ()->non_exited_threads ())
>      {
>        if (thr == signalled_thr)
>  	continue;
>  
> -      fbsd_corefile_thread (thr, &thread_args);
> +      gcore_build_thread_register_notes (gdbarch, thr,
> +					 signalled_thr->suspend.stop_signal,
> +					 obfd, &note_data, note_size);
>      }
>  
>    /* Auxiliary vector.  */
> diff --git a/gdb/gcore.c b/gdb/gcore.c
> index 73ac6b09c70..d62aa3a7109 100644
> --- a/gdb/gcore.c
> +++ b/gdb/gcore.c
> @@ -579,6 +579,142 @@ gcore_memory_sections (bfd *obfd)
>    return 1;
>  }
>  
> +/* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS
> +   via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */
> +
> +struct gcore_collect_regset_section_cb_data
> +{
> +  gcore_collect_regset_section_cb_data (struct gdbarch *gdbarch,
> +					const struct regcache *regcache,
> +					bfd *obfd, ptid_t ptid,
> +					gdb_signal stop_signal,
> +					gdb::unique_xmalloc_ptr<char> *note_data,
> +					int *note_size)
> +
> +    : gdbarch (gdbarch), regcache (regcache), obfd (obfd),
> +      note_data (note_data), note_size (note_size),
> +      stop_signal (stop_signal)
> +  {
> +    /* The LWP is often not available for bare metal target, in which case
> +       use the tid instead.  */
> +    if (ptid.lwp_p ())
> +      lwp = ptid.lwp ();
> +    else
> +      lwp = ptid.tid ();
> +  }
> +
> +  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 core file note section.  */
> +
> +static void
> +gcore_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 gcore_collect_regset_section_cb_data *data
> +    = (struct gcore_collect_regset_section_cb_data *) cb_data;
> +  bool variable_size_section = (regset != NULL
> +				&& regset->flags & REGSET_VARIABLE_SIZE);
> +
> +  gdb_assert (variable_size_section || supply_size == collect_size);
> +
> +  if (data->abort_iteration)
> +    return;
> +
> +  gdb_assert (regset != nullptr && regset->collect_regset != nullptr);
> +
> +  /* 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 == nullptr)
> +    data->abort_iteration = true;
> +}
> +
> +/* Records the register state of thread PTID out of REGCACHE into the note
> +   buffer represented by *NOTE_DATA and NOTE_SIZE.  OBFD is the bfd into
> +   which the core file is being created, and STOP_SIGNAL is the signal that
> +   cause thread PTID to stop.  */
> +
> +static void
> +gcore_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 ();
> +  gcore_collect_regset_section_cb_data data (gdbarch, regcache, obfd, ptid,
> +					     stop_signal, note_data,
> +					     note_size);
> +  gdbarch_iterate_over_regset_sections (gdbarch,
> +					gcore_collect_regset_section_cb,
> +					&data, regcache);
> +}
> +
> +/* See gcore.h.  */
> +
> +void
> +gcore_build_thread_register_notes
> +  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
> +   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
> +{
> +  struct regcache *regcache
> +    = get_thread_arch_regcache (info->inf->process_target (),
> +				info->ptid, gdbarch);
> +  target_fetch_registers (regcache, -1);
> +  gcore_collect_thread_registers (regcache, info->ptid, obfd, note_data,
> +				  note_size, stop_signal);
> +}
> +
> +/* See gcore.h.  */
> +
> +thread_info *
> +gcore_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;
> +}
> +
>  void _initialize_gcore ();
>  void
>  _initialize_gcore ()
> diff --git a/gdb/gcore.h b/gdb/gcore.h
> index af37ff39b41..ce60841c1a5 100644
> --- a/gdb/gcore.h
> +++ b/gdb/gcore.h
> @@ -21,6 +21,10 @@
>  #define GCORE_H 1
>  
>  #include "gdb_bfd.h"
> +#include "gdbsupport/gdb_signals.h"
> +
> +struct gdbarch;
> +struct thread_info;
>  
>  extern gdb_bfd_ref_ptr create_gcore_bfd (const char *filename);
>  extern void write_gcore_file (bfd *obfd);
> @@ -28,4 +32,20 @@ extern int objfile_find_memory_regions (struct target_ops *self,
>  					find_memory_region_ftype func,
>  					void *obfd);
>  
> +/* Add content to *NOTE_DATA (and update *NOTE_SIZE) to describe the
> +   registers of thread INFO.  Report the thread as having stopped with
> +   STOP_SIGNAL.  The core file is being written to OFD, and GDBARCH is the
> +   architecture for which the core file is being generated.  */
> +
> +extern void gcore_build_thread_register_notes
> +  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
> +   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size);
> +
> +/* 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.  */
> +
> +extern thread_info *gcore_find_signalled_thread ();
> +
>  #endif /* GCORE_H */
> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
> index 5b3b8874d11..de814fc6832 100644
> --- a/gdb/linux-tdep.c
> +++ b/gdb/linux-tdep.c
> @@ -39,6 +39,7 @@
>  #include "gdb_regex.h"
>  #include "gdbsupport/enum-flags.h"
>  #include "gdbsupport/gdb_optional.h"
> +#include "gcore.h"
>  
>  #include <ctype.h>
>  
> @@ -1599,104 +1600,6 @@ 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.  */
> @@ -1748,22 +1651,16 @@ static void
>  linux_corefile_thread (struct thread_info *info,
>  		       struct linux_corefile_thread_data *args)
>  {
> -  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);
> +  gcore_build_thread_register_notes (args->gdbarch, info, args->stop_signal,
> +				     args->obfd, &args->note_data,
> +				     args->note_size);
>  
>    /* 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 (),
> @@ -1962,30 +1859,6 @@ 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.  */
>  
> @@ -2023,7 +1896,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 = find_signalled_thread ();
> +  thread_info *signalled_thr = gcore_find_signalled_thread ();
>    gdb_signal stop_signal;
>    if (signalled_thr != nullptr)
>      stop_signal = signalled_thr->suspend.stop_signal;
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 6/9] bfd/binutils: add support for RISC-V CSRs in core files
  2021-01-20 20:23 ` [PATCHv2 6/9] bfd/binutils: add support for RISC-V CSRs in core files Andrew Burgess
@ 2021-02-01 12:00   ` Andrew Burgess
  2021-02-01 14:08     ` Luis Machado
  2021-02-10 21:00     ` Jim Wilson
  0 siblings, 2 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-01 12:00 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna

Here is an update version of this patch.

In this patch I have placed the CSRs into a note named "GDB".  This
should protect us if, in the future, the note type number I have used
is reused by some other core file producer (Linux / FreeBSD) and given
a different meaning.

Any feedback?

Thanks,
Andrew


---

commit 15bcb460981a000e74b2d3dc4f59f0f06bc0cd52
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Fri Nov 27 14:04:16 2020 +0000

    bfd/binutils: add support for RISC-V CSRs in core files
    
    Adds support for including RISC-V control and status registers into
    core files.
    
    The value for the define NT_RISCV_CSR is set to 0x900, this
    corresponds to a patch I have proposed for the Linux kernel here:
    
      http://lists.infradead.org/pipermail/linux-riscv/2020-December/003910.html
    
    As I have not yet heard if the above patch will be accepted into the
    kernel or not I have set the note name string to "GDB", and the note
    type to NT_RISCV_CSR.
    
    This means that if the above patch is rejected from the kernel, and
    the note type number 0x900 is assigned to some other note type, we
    will still be able to distinguish between the GDB produced
    NT_RISCV_CSR, and the kernel produced notes, where the name would be
    set to "CORE".
    
    bfd/ChangeLog:
    
            * elf-bfd.h (elfcore_write_riscv_csr): Declare.
            * elf.c (elfcore_grok_riscv_csr): New function.
            (elfcore_grok_note): Handle NT_RISCV_CSR.
            (elfcore_write_riscv_csr): New function.
            (elfcore_write_register_note): Handle '.reg-riscv-csr'.
    
    binutils/ChangeLog:
    
            * readelf.c (get_note_type): Handle NT_RISCV_CSR.
    
    include/ChangeLog:
    
            * elf/common.h (NT_RISCV_CSR): Define.

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 779acc745bc..5b7eb8897c8 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2797,6 +2797,8 @@ extern char *elfcore_write_aarch_pauth
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_arc_v2
   (bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_riscv_csr
+  (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_gdb_tdesc
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_lwpstatus
diff --git a/bfd/elf.c b/bfd/elf.c
index c6cf7fe2d6e..d1fd29f380a 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9912,6 +9912,12 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
 }
 
+static bfd_boolean
+elfcore_grok_riscv_csr (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-riscv-csr", note);
+}
+
 static bfd_boolean
 elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
 {
@@ -10583,6 +10589,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
         return TRUE;
 
+    case NT_RISCV_CSR:
+      if (note->namesz == 4
+          && strcmp (note->namedata, "GDB") == 0)
+        return elfcore_grok_riscv_csr (abfd, note);
+      else
+	return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -11964,6 +11977,18 @@ elfcore_write_arc_v2 (bfd *abfd,
 			     note_name, NT_ARC_V2, arc_v2, size);
 }
 
+char *
+elfcore_write_riscv_csr (bfd *abfd,
+                         char *buf,
+                         int *bufsiz,
+                         const void *csrs,
+                         int size)
+{
+  const char *note_name = "GDB";
+  return elfcore_write_note (abfd, buf, bufsiz,
+			     note_name, NT_RISCV_CSR, csrs, size);
+}
+
 char *
 elfcore_write_gdb_tdesc (bfd *abfd,
 			 char *buf,
@@ -12062,6 +12087,8 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".gdb-tdesc") == 0)
     return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-riscv-csr") == 0)
+    return elfcore_write_riscv_csr (abfd, buf, bufsiz, data, size);
   return NULL;
 }
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index feb458877c8..807eccfb026 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18374,6 +18374,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
 	return _("NT_ARM_HW_WATCH (AArch hardware watchpoint registers)");
       case NT_ARC_V2:
 	return _("NT_ARC_V2 (ARC HS accumulator/extra registers)");
+      case NT_RISCV_CSR:
+	return _("NT_RISCV_CSR (RISC-V control and status registers)");
       case NT_PSTATUS:
 	return _("NT_PSTATUS (pstatus structure)");
       case NT_FPREGS:
diff --git a/include/elf/common.h b/include/elf/common.h
index e6e9c278faa..4cb3748e4fd 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -674,6 +674,8 @@
 					/*   note name must be "LINUX".  */
 #define NT_ARC_V2	0x600		/* ARC HS accumulator/extra registers.  */
 					/*   note name must be "LINUX".  */
+#define NT_RISCV_CSR    0x900		/* RISC-V Control and Status Registers */
+					/*   note name must be "CORE".  */
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */
 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* PING: Re: [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation
  2021-01-20 20:23 ` [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
@ 2021-02-01 12:03   ` Andrew Burgess
  2021-02-01 13:48   ` Luis Machado
  2021-02-10 20:57   ` Jim Wilson
  2 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-01 12:03 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna

I believe that this patch was approved here:

   https://sourceware.org/pipermail/binutils/2020-December/114376.html

But I just thought I'd ping in case anyone else on the binutils side
wanted to comment.

Thanks,
Andrew

---

* Andrew Burgess <andrew.burgess@embecosm.com> [2021-01-20 20:23:10 +0000]:

> When creating a core file GDB will call the function
> elfcore_write_prstatus to write out the general purpose registers
> along with the pid/tid for the thread.
> 
> However, for a bare metal RISC-V tool chain the prstatus*_t types are
> not defined so the elfcore_write_prstatus function will return NULL,
> preventing core file creation.
> 
> This commit provides the `elf_backend_write_core_note' hook and uses
> the provided function to write out the ptstatus information.
> 
> In order to keep changes in the non bare metal tools to a minimum, the
> provided backend function will itself return NULL when the prstatus*_t
> types are available, the consequence of this is that the generic code
> in elfcore_write_prstatus will be used just as before.  But, when
> prstatus*_t is not available, the new backend function will write out
> the prstatus information using predefined offsets.
> 
> This new functionality will be used by a later GDB commit that will
> add bare metal core dumps for RISC-V.
> 
> bfd/ChangeLog:
> 
> 	* elfnn-riscv.c (riscv_write_core_note): New function.
> 	(elf_backend_write_core_note): Define.
> ---
>  bfd/ChangeLog     |  6 ++++
>  bfd/elfnn-riscv.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 78 insertions(+)
> 
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index b2ec6a29fbf..70a683b45a3 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -4886,6 +4886,77 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
>  # define PRPSINFO_OFFSET_PR_PSARGS	56
>  #endif
>  
> +/* Write PRSTATUS and PRPSINFO note into core file.  This will be called
> +   before the generic code in elf.c.  By checking the compiler defines we
> +   only perform any action here if the generic code would otherwise not be
> +   able to help us.  The intention is that bare metal core dumps (where the
> +   prstatus_t and/or prpsinfo_t might not be available) will use this code,
> +   while non bare metal tools will use the generic elf code.  */
> +
> +static char *
> +riscv_write_core_note (bfd *abfd ATTRIBUTE_UNUSED,
> +                       char *buf ATTRIBUTE_UNUSED,
> +                       int *bufsiz ATTRIBUTE_UNUSED,
> +                       int note_type ATTRIBUTE_UNUSED, ...)
> +{
> +  switch (note_type)
> +    {
> +    default:
> +      return NULL;
> +
> +#if !defined (HAVE_PRPSINFO_T)
> +    case NT_PRPSINFO:
> +      {
> +	char data[PRPSINFO_SIZE] ATTRIBUTE_NONSTRING;
> +	va_list ap;
> +
> +	va_start (ap, note_type);
> +	memset (data, 0, sizeof (data));
> +	strncpy (data + PRPSINFO_OFFSET_PR_FNAME, va_arg (ap, const char *), 16);
> +#if GCC_VERSION == 8000 || GCC_VERSION == 8001
> +	DIAGNOSTIC_PUSH;
> +	/* GCC 8.0 and 8.1 warn about 80 equals destination size with
> +	   -Wstringop-truncation:
> +	   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
> +	 */
> +	DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
> +#endif
> +	strncpy (data + PRPSINFO_OFFSET_PR_PSARGS, va_arg (ap, const char *), 80);
> +#if GCC_VERSION == 8000 || GCC_VERSION == 8001
> +	DIAGNOSTIC_POP;
> +#endif
> +	va_end (ap);
> +	return elfcore_write_note (abfd, buf, bufsiz,
> +				   "CORE", note_type, data, sizeof (data));
> +      }
> +#endif /* !HAVE_PRPSINFO_T */
> +
> +#if !defined (HAVE_PRSTATUS_T)
> +    case NT_PRSTATUS:
> +      {
> +        char data[PRSTATUS_SIZE];
> +        va_list ap;
> +        long pid;
> +        int cursig;
> +        const void *greg;
> +
> +        va_start (ap, note_type);
> +        memset (data, 0, sizeof(data));
> +        pid = va_arg (ap, long);
> +        bfd_put_32 (abfd, pid, data + PRSTATUS_OFFSET_PR_PID);
> +        cursig = va_arg (ap, int);
> +        bfd_put_16 (abfd, cursig, data + PRSTATUS_OFFSET_PR_CURSIG);
> +        greg = va_arg (ap, const void *);
> +        memcpy (data + PRSTATUS_OFFSET_PR_REG, greg,
> +                PRSTATUS_SIZE - PRSTATUS_OFFSET_PR_REG - ARCH_SIZE / 8);
> +        va_end (ap);
> +        return elfcore_write_note (abfd, buf, bufsiz,
> +                                   "CORE", note_type, data, sizeof (data));
> +      }
> +#endif /* !HAVE_PRSTATUS_T */
> +    }
> +}
> +
>  /* Support for core dump NOTE sections.  */
>  
>  static bfd_boolean
> @@ -5000,6 +5071,7 @@ riscv_elf_obj_attrs_arg_type (int tag)
>  #define elf_backend_grok_prstatus		riscv_elf_grok_prstatus
>  #define elf_backend_grok_psinfo			riscv_elf_grok_psinfo
>  #define elf_backend_object_p			riscv_elf_object_p
> +#define elf_backend_write_core_note		riscv_write_core_note
>  #define elf_info_to_howto_rel			NULL
>  #define elf_info_to_howto			riscv_info_to_howto_rela
>  #define bfd_elfNN_bfd_relax_section		_bfd_riscv_relax_section
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* PING: Re: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-01-20 20:23 ` [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
  2021-01-22 10:47   ` Strasuns, Mihails
@ 2021-02-01 12:05   ` Andrew Burgess
  2021-02-01 15:10     ` Strasuns, Mihails
  2021-02-01 13:29   ` Luis Machado
  2021-02-10 20:45   ` Jim Wilson
  3 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-02-01 12:05 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna

Ping!

This patch needs a review from the binutils side please.

I believe the conversation with Mihails was resolved and he is happy
with this patch as it is.

Thanks,
Andrew

* Andrew Burgess <andrew.burgess@embecosm.com> [2021-01-20 20:23:08 +0000]:

> This commit lays the ground work for allowing GDB to write its target
> description into a generated core file.
> 
> The goal of this work is to allow a user to connect to a remote
> target, capture a core file from within GDB, then pass the executable
> and core file to another user and have the user be able to examine the
> state of the machine without needing to connect to a running target.
> 
> Different remote targets can have different register sets and this
> information is communicated from the target to GDB in the target
> description.
> 
> It is possible for a user to extract the target description from GDB
> and pass this along with the core file so that when the core file is
> used the target description can be fed back into GDB, however this is
> not a great user experience.
> 
> It would be nicer, I think, if GDB could write the target description
> directly into the core file, and then make use of this description
> when loading a core file.
> 
> This commit performs the binutils/bfd side of this task, adding the
> boiler plate functions to access the target description from within a
> core file note, and reserving a new number for a note containing the
> target description.
> 
> Later commits will extend GDB to make use of this.
> 
> bfd/ChangeLog:
> 
> 	* elf-bfd.h (elfcore_write_gdb_tdesc): Declare new function.
> 	* elf.c (elfcore_grok_gdb_tdesc): New function.
> 	(elfcore_grok_note): Handle NT_GDB_TDESC.
> 	(elfcore_write_gdb_tdesc): New function.
> 	(elfcore_write_register_note): Handle NT_GDB_TDESC.
> 
> binutils/ChangeLog:
> 
> 	* readelf.c (get_note_type): Handle NT_GDB_TDESC.
> 
> include/ChangeLog:
> 
> 	* elf/common.h (NT_GDB_TDESC): Define.
> ---
>  bfd/ChangeLog        |  9 +++++++++
>  bfd/elf-bfd.h        |  2 ++
>  bfd/elf.c            | 23 +++++++++++++++++++++++
>  binutils/ChangeLog   |  5 +++++
>  binutils/readelf.c   |  2 ++
>  include/ChangeLog    |  5 +++++
>  include/elf/common.h |  4 ++++
>  7 files changed, 50 insertions(+)
> 
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index 15206b4e876..4dce8114c0f 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -2797,6 +2797,8 @@ extern char *elfcore_write_aarch_pauth
>    (bfd *, char *, int *, const void *, int);
>  extern char *elfcore_write_arc_v2
>    (bfd *, char *, int *, const void *, int);
> +extern char *elfcore_write_gdb_tdesc
> +  (bfd *, char *, int *, const void *, int);
>  extern char *elfcore_write_lwpstatus
>    (bfd *, char *, int *, long, int, const void *);
>  extern char *elfcore_write_register_note
> diff --git a/bfd/elf.c b/bfd/elf.c
> index 84a5d942817..9892ffa9faf 100644
> --- a/bfd/elf.c
> +++ b/bfd/elf.c
> @@ -9912,6 +9912,12 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
>    return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
>  }
>  
> +static bfd_boolean
> +elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
> +{
> +  return elfcore_make_note_pseudosection (abfd, ".gdb-tdesc", note);
> +}
> +
>  #if defined (HAVE_PRPSINFO_T)
>  typedef prpsinfo_t   elfcore_psinfo_t;
>  #if defined (HAVE_PRPSINFO32_T)		/* Sparc64 cross Sparc32 */
> @@ -10570,6 +10576,9 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
>        else
>  	return TRUE;
>  
> +    case NT_GDB_TDESC:
> +      return elfcore_grok_gdb_tdesc (abfd, note);
> +
>      case NT_PRPSINFO:
>      case NT_PSINFO:
>        if (bed->elf_backend_grok_psinfo)
> @@ -11951,6 +11960,18 @@ elfcore_write_arc_v2 (bfd *abfd,
>  			     note_name, NT_ARC_V2, arc_v2, size);
>  }
>  
> +char *
> +elfcore_write_gdb_tdesc (bfd *abfd,
> +			 char *buf,
> +			 int *bufsiz,
> +			 const void *tdesc,
> +			 int size)
> +{
> +  const char *note_name = "CORE";
> +  return elfcore_write_note (abfd, buf, bufsiz,
> +                             note_name, NT_GDB_TDESC, tdesc, size);
> +}
> +
>  char *
>  elfcore_write_register_note (bfd *abfd,
>  			     char *buf,
> @@ -12035,6 +12056,8 @@ elfcore_write_register_note (bfd *abfd,
>      return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
>    if (strcmp (section, ".reg-arc-v2") == 0)
>      return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
> +  if (strcmp (section, ".gdb-tdesc") == 0)
> +    return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
>    return NULL;
>  }
>  
> diff --git a/binutils/readelf.c b/binutils/readelf.c
> index 5df51086226..feb458877c8 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -18296,6 +18296,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
>  	return _("NT_PRPSINFO (prpsinfo structure)");
>        case NT_TASKSTRUCT:
>  	return _("NT_TASKSTRUCT (task structure)");
> +      case NT_GDB_TDESC:
> +        return _("NT_GDB_TDESC (GDB XML target description)");
>        case NT_PRXFPREG:
>  	return _("NT_PRXFPREG (user_xfpregs structure)");
>        case NT_PPC_VMX:
> diff --git a/include/elf/common.h b/include/elf/common.h
> index e7d55ae0782..e6e9c278faa 100644
> --- a/include/elf/common.h
> +++ b/include/elf/common.h
> @@ -677,6 +677,10 @@
>  #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
>  #define NT_FILE		0x46494c45	/* Description of mapped files.  */
>  
> +/* The range 0xff000000 to 0xffffffff is set aside for notes that don't
> +   originate from any particular operating system.  */
> +#define NT_GDB_TDESC	0xff000000	/* Contains copy of GDB's target description XML.  */
> +
>  /* Note segments for core files on dir-style procfs systems.  */
>  
>  #define NT_PSTATUS	10		/* Has a struct pstatus */
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-01-20 20:23 ` [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
  2021-01-22 10:47   ` Strasuns, Mihails
  2021-02-01 12:05   ` PING: " Andrew Burgess
@ 2021-02-01 13:29   ` Luis Machado
  2021-02-10 20:45   ` Jim Wilson
  3 siblings, 0 replies; 57+ messages in thread
From: Luis Machado @ 2021-02-01 13:29 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

On 1/20/21 5:23 PM, Andrew Burgess wrote:
> This commit lays the ground work for allowing GDB to write its target
> description into a generated core file.
> 
> The goal of this work is to allow a user to connect to a remote
> target, capture a core file from within GDB, then pass the executable
> and core file to another user and have the user be able to examine the
> state of the machine without needing to connect to a running target.
> 
> Different remote targets can have different register sets and this
> information is communicated from the target to GDB in the target
> description.
> 
> It is possible for a user to extract the target description from GDB
> and pass this along with the core file so that when the core file is
> used the target description can be fed back into GDB, however this is
> not a great user experience.
> 
> It would be nicer, I think, if GDB could write the target description
> directly into the core file, and then make use of this description
> when loading a core file.
> 
> This commit performs the binutils/bfd side of this task, adding the
> boiler plate functions to access the target description from within a
> core file note, and reserving a new number for a note containing the
> target description.
> 
> Later commits will extend GDB to make use of this.
> 
> bfd/ChangeLog:
> 
> 	* elf-bfd.h (elfcore_write_gdb_tdesc): Declare new function.
> 	* elf.c (elfcore_grok_gdb_tdesc): New function.
> 	(elfcore_grok_note): Handle NT_GDB_TDESC.
> 	(elfcore_write_gdb_tdesc): New function.
> 	(elfcore_write_register_note): Handle NT_GDB_TDESC.
> 
> binutils/ChangeLog:
> 
> 	* readelf.c (get_note_type): Handle NT_GDB_TDESC.
> 
> include/ChangeLog:
> 
> 	* elf/common.h (NT_GDB_TDESC): Define.
> ---
>   bfd/ChangeLog        |  9 +++++++++
>   bfd/elf-bfd.h        |  2 ++
>   bfd/elf.c            | 23 +++++++++++++++++++++++
>   binutils/ChangeLog   |  5 +++++
>   binutils/readelf.c   |  2 ++
>   include/ChangeLog    |  5 +++++
>   include/elf/common.h |  4 ++++
>   7 files changed, 50 insertions(+)
> 
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index 15206b4e876..4dce8114c0f 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -2797,6 +2797,8 @@ extern char *elfcore_write_aarch_pauth
>     (bfd *, char *, int *, const void *, int);
>   extern char *elfcore_write_arc_v2
>     (bfd *, char *, int *, const void *, int);
> +extern char *elfcore_write_gdb_tdesc
> +  (bfd *, char *, int *, const void *, int);
>   extern char *elfcore_write_lwpstatus
>     (bfd *, char *, int *, long, int, const void *);
>   extern char *elfcore_write_register_note
> diff --git a/bfd/elf.c b/bfd/elf.c
> index 84a5d942817..9892ffa9faf 100644
> --- a/bfd/elf.c
> +++ b/bfd/elf.c
> @@ -9912,6 +9912,12 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
>     return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
>   }
>   
> +static bfd_boolean
> +elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
> +{
> +  return elfcore_make_note_pseudosection (abfd, ".gdb-tdesc", note);
> +}
> +
>   #if defined (HAVE_PRPSINFO_T)
>   typedef prpsinfo_t   elfcore_psinfo_t;
>   #if defined (HAVE_PRPSINFO32_T)		/* Sparc64 cross Sparc32 */
> @@ -10570,6 +10576,9 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
>         else
>   	return TRUE;
>   
> +    case NT_GDB_TDESC:
> +      return elfcore_grok_gdb_tdesc (abfd, note);
> +
>       case NT_PRPSINFO:
>       case NT_PSINFO:
>         if (bed->elf_backend_grok_psinfo)
> @@ -11951,6 +11960,18 @@ elfcore_write_arc_v2 (bfd *abfd,
>   			     note_name, NT_ARC_V2, arc_v2, size);
>   }
>   
> +char *
> +elfcore_write_gdb_tdesc (bfd *abfd,
> +			 char *buf,
> +			 int *bufsiz,
> +			 const void *tdesc,
> +			 int size)
> +{
> +  const char *note_name = "CORE";
> +  return elfcore_write_note (abfd, buf, bufsiz,
> +                             note_name, NT_GDB_TDESC, tdesc, size);
> +}
> +
>   char *
>   elfcore_write_register_note (bfd *abfd,
>   			     char *buf,
> @@ -12035,6 +12056,8 @@ elfcore_write_register_note (bfd *abfd,
>       return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
>     if (strcmp (section, ".reg-arc-v2") == 0)
>       return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
> +  if (strcmp (section, ".gdb-tdesc") == 0)
> +    return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
>     return NULL;
>   }
>   
> diff --git a/binutils/readelf.c b/binutils/readelf.c
> index 5df51086226..feb458877c8 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -18296,6 +18296,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
>   	return _("NT_PRPSINFO (prpsinfo structure)");
>         case NT_TASKSTRUCT:
>   	return _("NT_TASKSTRUCT (task structure)");
> +      case NT_GDB_TDESC:
> +        return _("NT_GDB_TDESC (GDB XML target description)");
>         case NT_PRXFPREG:
>   	return _("NT_PRXFPREG (user_xfpregs structure)");
>         case NT_PPC_VMX:
> diff --git a/include/elf/common.h b/include/elf/common.h
> index e7d55ae0782..e6e9c278faa 100644
> --- a/include/elf/common.h
> +++ b/include/elf/common.h
> @@ -677,6 +677,10 @@
>   #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
>   #define NT_FILE		0x46494c45	/* Description of mapped files.  */
>   
> +/* The range 0xff000000 to 0xffffffff is set aside for notes that don't
> +   originate from any particular operating system.  */
> +#define NT_GDB_TDESC	0xff000000	/* Contains copy of GDB's target description XML.  */
> +
>   /* Note segments for core files on dir-style procfs systems.  */
>   
>   #define NT_PSTATUS	10		/* Has a struct pstatus */
> 

I went through this and it looks good to me in its current state (minus 
the discussion on whether this should be on/off by default). I don't 
mind if we always dump this information if available.

Having additional notes dumped into the core file doesn't sound bad, as 
it seems to be common practice to have notes carrying random bits of 
information.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 3/9] gdb: write target description into core file
  2021-01-20 20:23 ` [PATCHv2 3/9] gdb: write target description into " Andrew Burgess
  2021-01-22 19:15   ` Tom Tromey
@ 2021-02-01 13:37   ` Luis Machado
  1 sibling, 0 replies; 57+ messages in thread
From: Luis Machado @ 2021-02-01 13:37 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

On 1/20/21 5:23 PM, Andrew Burgess wrote:
> When a core file is created from within GDB add the target description
> into a note within the core file.
> 
> When loading a core file, if the target description note is present
> then load the target description from the core file.
> 
> The benefit of this is that we can be sure that, when analysing the
> core file within GDB, that we are using the exact same target
> description as was in use at the time the core file was created.
> 
> In future commits I intend to add support for bare metal core dumps
> for some targets.  These core dumps will include auxiliary registers,
> the availability of which can only be established by looking at the
> target description.
> 
> gdb/ChangeLog:
> 
> 	* corelow.c: Add 'xml-tdesc.h' include.
> 	(core_target::read_description): Load the target description from
> 	the core file when possible.
> 	* gcore.c: Add 'gdbsupport/tdesc.h' include.
> 	(write_gcore_file_1): Write out the target description.
> ---
>   gdb/ChangeLog |  9 +++++++++
>   gdb/corelow.c | 24 ++++++++++++++++++++++++
>   gdb/gcore.c   | 21 +++++++++++++++++++++
>   3 files changed, 54 insertions(+)
> 
> diff --git a/gdb/corelow.c b/gdb/corelow.c
> index a63eab4852b..fd8a5c71e22 100644
> --- a/gdb/corelow.c
> +++ b/gdb/corelow.c
> @@ -49,6 +49,7 @@
>   #include <unordered_map>
>   #include <unordered_set>
>   #include "gdbcmd.h"
> +#include "xml-tdesc.h"
>   
>   #ifndef O_LARGEFILE
>   #define O_LARGEFILE 0
> @@ -1000,6 +1001,29 @@ core_target::thread_alive (ptid_t ptid)
>   const struct target_desc *
>   core_target::read_description ()
>   {
> +  /* If the core file contains a target description note then we will use
> +     that in preference to anything else.  */
> +  bfd_size_type tdesc_note_size = 0;
> +  struct bfd_section *tdesc_note_section
> +    = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
> +  if (tdesc_note_section != nullptr)
> +    tdesc_note_size = bfd_section_size (tdesc_note_section);
> +  if (tdesc_note_size > 0)
> +    {
> +      gdb::char_vector contents (tdesc_note_size + 1);
> +      if (bfd_get_section_contents (core_bfd, tdesc_note_section,
> +				    contents.data (), (file_ptr) 0,
> +				    tdesc_note_size))
> +	{
> +	  /* Ensure we have a null terminator.  */
> +	  contents [tdesc_note_size] = '\0';
> +	  const struct target_desc *result
> +	    = string_read_description_xml (contents.data ());
> +	  if (result != NULL)
> +	    return result;

NULL -> nullptr

> +	}
> +    }
> +
>     if (m_core_gdbarch && gdbarch_core_read_description_p (m_core_gdbarch))
>       {
>         const struct target_desc *result;
> diff --git a/gdb/gcore.c b/gdb/gcore.c
> index d62aa3a7109..cecb9146994 100644
> --- a/gdb/gcore.c
> +++ b/gdb/gcore.c
> @@ -38,6 +38,7 @@
>   #include "gdbsupport/gdb_unlinker.h"
>   #include "gdbsupport/byte-vector.h"
>   #include "gdbsupport/scope-exit.h"
> +#include "gdbsupport/tdesc.h"
>   
>   /* The largest amount of memory to read from the target at once.  We
>      must throttle it to limit the amount of memory used by GDB during
> @@ -82,6 +83,26 @@ write_gcore_file_1 (bfd *obfd)
>       note_data = gdbarch_make_corefile_notes (target_gdbarch (), obfd,
>   					     &note_size);
>   
> +  /* Append the target description to the core file.  */
> +  const struct target_desc *tdesc = gdbarch_target_desc (target_gdbarch ());
> +  const char *tdesc_xml
> +    = tdesc == nullptr ? nullptr : tdesc_get_features_xml (tdesc);
> +  if (tdesc_xml != nullptr && *tdesc_xml != '\0')
> +    {
> +      /* Skip the leading '@'.  */
> +      if (*tdesc_xml == '@')
> +	++tdesc_xml;
> +
> +      /* Include the null terminator in the length.  */
> +      size_t tdesc_len = strlen (tdesc_xml) + 1;
> +
> +      /* Now add the target description into the core file.  */
> +      note_data.reset (elfcore_write_register_note (obfd,
> +						    note_data.release (),
> +						    &note_size, ".gdb-tdesc",
> +						    tdesc_xml, tdesc_len));
> +    }
> +
>     if (note_data == NULL || note_size == 0)
>       error (_("Target does not support core file generation."));
>   
> 

Otherwise this is OK.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation
  2021-01-20 20:23 ` [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
  2021-02-01 12:03   ` PING: " Andrew Burgess
@ 2021-02-01 13:48   ` Luis Machado
  2021-02-01 14:44     ` Andrew Burgess
  2021-02-10 20:57   ` Jim Wilson
  2 siblings, 1 reply; 57+ messages in thread
From: Luis Machado @ 2021-02-01 13:48 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

On 1/20/21 5:23 PM, Andrew Burgess wrote:
> When creating a core file GDB will call the function
> elfcore_write_prstatus to write out the general purpose registers
> along with the pid/tid for the thread.
> 
> However, for a bare metal RISC-V tool chain the prstatus*_t types are
> not defined so the elfcore_write_prstatus function will return NULL,
> preventing core file creation.
> 
> This commit provides the `elf_backend_write_core_note' hook and uses
> the provided function to write out the ptstatus information.

ptstatus -> prstatus?

> 
> In order to keep changes in the non bare metal tools to a minimum, the
> provided backend function will itself return NULL when the prstatus*_t
> types are available, the consequence of this is that the generic code
> in elfcore_write_prstatus will be used just as before.  But, when
> prstatus*_t is not available, the new backend function will write out
> the prstatus information using predefined offsets.
> 
> This new functionality will be used by a later GDB commit that will
> add bare metal core dumps for RISC-V.
> 
> bfd/ChangeLog:
> 
> 	* elfnn-riscv.c (riscv_write_core_note): New function.
> 	(elf_backend_write_core_note): Define.
> ---
>   bfd/ChangeLog     |  6 ++++
>   bfd/elfnn-riscv.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 78 insertions(+)
> 
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index b2ec6a29fbf..70a683b45a3 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -4886,6 +4886,77 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
>   # define PRPSINFO_OFFSET_PR_PSARGS	56
>   #endif
>   
> +/* Write PRSTATUS and PRPSINFO note into core file.  This will be called
> +   before the generic code in elf.c.  By checking the compiler defines we
> +   only perform any action here if the generic code would otherwise not be
> +   able to help us.  The intention is that bare metal core dumps (where the
> +   prstatus_t and/or prpsinfo_t might not be available) will use this code,
> +   while non bare metal tools will use the generic elf code.  */
> +
> +static char *
> +riscv_write_core_note (bfd *abfd ATTRIBUTE_UNUSED,
> +                       char *buf ATTRIBUTE_UNUSED,
> +                       int *bufsiz ATTRIBUTE_UNUSED,
> +                       int note_type ATTRIBUTE_UNUSED, ...)
> +{
> +  switch (note_type)
> +    {
> +    default:
> +      return NULL;
> +
> +#if !defined (HAVE_PRPSINFO_T)
> +    case NT_PRPSINFO:
> +      {
> +	char data[PRPSINFO_SIZE] ATTRIBUTE_NONSTRING;
> +	va_list ap;
> +
> +	va_start (ap, note_type);
> +	memset (data, 0, sizeof (data));
> +	strncpy (data + PRPSINFO_OFFSET_PR_FNAME, va_arg (ap, const char *), 16);
> +#if GCC_VERSION == 8000 || GCC_VERSION == 8001
> +	DIAGNOSTIC_PUSH;
> +	/* GCC 8.0 and 8.1 warn about 80 equals destination size with
> +	   -Wstringop-truncation:
> +	   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
> +	 */
> +	DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
> +#endif
> +	strncpy (data + PRPSINFO_OFFSET_PR_PSARGS, va_arg (ap, const char *), 80);
> +#if GCC_VERSION == 8000 || GCC_VERSION == 8001
> +	DIAGNOSTIC_POP;
> +#endif
> +	va_end (ap);
> +	return elfcore_write_note (abfd, buf, bufsiz,
> +				   "CORE", note_type, data, sizeof (data));
> +      }
> +#endif /* !HAVE_PRPSINFO_T */
> +
> +#if !defined (HAVE_PRSTATUS_T)
> +    case NT_PRSTATUS:
> +      {
> +        char data[PRSTATUS_SIZE];
> +        va_list ap;
> +        long pid;
> +        int cursig;
> +        const void *greg;
> +
> +        va_start (ap, note_type);
> +        memset (data, 0, sizeof(data));
> +        pid = va_arg (ap, long);
> +        bfd_put_32 (abfd, pid, data + PRSTATUS_OFFSET_PR_PID);
> +        cursig = va_arg (ap, int);
> +        bfd_put_16 (abfd, cursig, data + PRSTATUS_OFFSET_PR_CURSIG);
> +        greg = va_arg (ap, const void *);
> +        memcpy (data + PRSTATUS_OFFSET_PR_REG, greg,
> +                PRSTATUS_SIZE - PRSTATUS_OFFSET_PR_REG - ARCH_SIZE / 8);
> +        va_end (ap);
> +        return elfcore_write_note (abfd, buf, bufsiz,
> +                                   "CORE", note_type, data, sizeof (data));
> +      }
> +#endif /* !HAVE_PRSTATUS_T */
> +    }
> +}
> +
>   /* Support for core dump NOTE sections.  */
>   
>   static bfd_boolean
> @@ -5000,6 +5071,7 @@ riscv_elf_obj_attrs_arg_type (int tag)
>   #define elf_backend_grok_prstatus		riscv_elf_grok_prstatus
>   #define elf_backend_grok_psinfo			riscv_elf_grok_psinfo
>   #define elf_backend_object_p			riscv_elf_object_p
> +#define elf_backend_write_core_note		riscv_write_core_note
>   #define elf_info_to_howto_rel			NULL
>   #define elf_info_to_howto			riscv_info_to_howto_rela
>   #define bfd_elfNN_bfd_relax_section		_bfd_riscv_relax_section
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 5/9] gdb/riscv: introduce bare metal core dump support
  2021-01-20 20:23 ` [PATCHv2 5/9] gdb/riscv: introduce bare metal core dump support Andrew Burgess
@ 2021-02-01 14:05   ` Luis Machado
  2021-02-03  3:04     ` Palmer Dabbelt
  0 siblings, 1 reply; 57+ messages in thread
From: Luis Machado @ 2021-02-01 14:05 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

Andrew,

On 1/20/21 5:23 PM, Andrew Burgess wrote:
> The commit message below includes a description of the core file
> format.  Though this description could exist in the commit message, I
> don't imagine this is really the right place to document something
> like this.

Thanks for writing this down.

> 
> For RISC-V I imagine the correct place would be here:
> 
>    https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md
> 
> And I have a commit for this repository that replicates the
> description below.  However, I wanted to post this to the binutils/gdb
> list first, and see if this description was good enough for all
> stakeholders.
> 
> If people here are happy with this commit and the documentation, then
> I would image creating a pull request against the RISC-V ABI document,
> and then if there's no negative feedback, merge this patch at that
> point.
> 
> All feedback, on docs or implementation, is welcome,
> 
> Thanks,
> Andrew
> 
> 
> 
> 
> 
> ----
> 
> This commit adds the ability for bare metal RISC-V target to generate
> core files from within GDB.
> 
> The intended use case is that a user will connect to a remote bare
> metal target, debug up to some error condition, then generate a core
> file in the normal way using:
> 
>    (gdb) generate-core-file
> 
> This core file can then be used to revisit the state of the remote
> target without having to reconnect to the remote target.
> 
> The core file creation code is split between two new files.  In
> none-tdep.c is code designed to support the architecture agnostic
> parts of a bare metal core dump.
> 
> In riscv-none-tdep.c are the RISC-V specific parts, this is where the
> regset and regcache_map_entry structures are defined that control how
> registers are laid out in the core file.
> 
> Currently for RISC-V only the x-regs and f-regs (if present) are
> written out.  In future commits I plan to add support for writing out
> the RISC-V CSRs.
> 
> The cores dump format is based around generating an ELF containing

cores -> core

> sections for the writable regions of memory that a user could be
> using.  Which regions are dumped rely on GDB's existing common core
> dumping code, GDB will attempt to figure out the stack and heap as
> well as copying out writable data sections as identified by the
> original ELF.
> 
> Register information is added to the core dump using notes, just as it
> is for Linux of FreeBSD core dumps.  The note types used consist of
> the 3 basic types you would expect in a OS based core dump,
> NT_PRPSINFO, NT_PRSTATUS, NT_FPREGSET.
> 
> The layout of these notes differs slightly (due to field sizes)
> between RV32 and RV64.  Below I describe the data layout for each
> note.  In all case, all padding fields should be set to zero.

case -> cases

> 
> Note NT_PRPSINFO is optional.  Its data layout is:
> 
>    struct prpsinfo32_t		/* For RV32.  */
>    {
>      uint8_t padding[32];
>      char fname[16];
>      char psargs[80];
>    }
> 
>    struct prpsinfo64_t		/* For RV64.  */
>    {
>      uint8_t padding[40];
>      char fname[16];
>      char psargs[80];
>    }
> 
> Field 'fname' - null terminated string consisting of the basename of
>      (up to the fist 15 characters of) the executable.  Any additional
>      space should be set to zero.  If there's no executable name then
>      this field can be set to all zero.
> 
> Field 'psargs' - a null terminated string up to 80 characters in
>      length.  Any additional space should be filled with zero.  This
>      field contains the full executable path and any arguments passed
>      to the executable.  If there's nothing sensible to write in this
>      field then fill it with zero.
> 
> Note NT_PRSTATUS is required, its data layout is:
> 
>    struct prstatus32_t		/* For RV32.  */
>    {
>      uint8_t padding_1[12];
>      uint16_t sig;
>      uint8_t padding_2[10];
>      uint32_t thread_id;
>      uint8_t padding_3[44];
>      uint32_t x_regs[32];
>      uint8_t padding_4[4];
>    }
> 
>    struct prstatus64_t		/* For RV64.  */
>    {
>      uint8_t padding_1[12];
>      uint16_t sig;
>      uint8_t padding_2[18];
>      uint32_t thread_id;
>      uint8_t padding_3[76];
>      uint64_t x_regs[32];
>      uint8_t padding_4[4];
>    }
> 
> Field 'sig' - the signal that stopped this thread.  Its implementation

Its -> It's

>      defined what this field actually means.  Within GDB this will be
>      the signal number that the remote target reports as the stop
>      reason for this thread.
> 
> Field 'thread_is' - the thread id for this thread, its implementation

its -> it's

>      defined what this field actually means.  Within GDB this will be
>      thread thread-id that is assigned to each remote thread.
> 
> Field 'x_regs' - at index 0 we store the program counter, and at
>      indices 1 to 31 we store x-registers 1 to 31.  x-register 0 is not
>      stored, its value is always zero anyway.
> 
> Note NT_FPREGSET is optional, its data layout is:
> 
>    fpregset32_t			/* For targets with 'F' extension.  */
>    {
>      uint32_t f_regs[32];
>      uint32_t fcsr;
>    }
> 
>    fpregset64_t			/* For targets with 'D' extension .  */
>    {
>      uint64_t f_regs[32];
>      uint32_t fcsr;
>    }
> 
> Field 'f_regs' - stores f-registers 0 to 31.
> 
> Field 'fcsr' - stores the fcsr CSR register, and is always 4-bytes.
> 
> The rules for ordering the notes is the same as for Linux.  The
> NT_PRSTATUS note must come before any other notes about additional
> register sets.  And for multi-threaded targets all registers for a
> single thread should be grouped together.  This is because only
> NT_PRSTATUS includes a thread-id, all additional register notes after
> a NT_PRSTATUS are assumed to belong to the same thread until a
> different NT_PRSTATUS is seen.

I think the above documentation is a good start, and we can expand it 
with more information.

I'm wondering if we should document this in the GDB manual. Then again, 
it may be a bit too technical for the user manual.

Another idea is to document arch-specific bits in arch-specific files 
and the generic parts in the none-tdep.c file?

> 
> gdb/ChangeLog:
> 
> 	* Makefile.in (ALL_TARGET_OBS): Add riscv-none-tdep.o.
> 	(ALLDEPFILES): Add riscv-none-tdep.c.
> 	* configure.tgt (riscv*-*-*): Include riscv-none-tdep.c.
> 	* none-tdep.c: New file.
> 	* none-tdep.h: New file.
> 	* riscv-none-tdep.c: New file.
> ---
>   gdb/ChangeLog         |  10 ++++
>   gdb/Makefile.in       |   4 ++
>   gdb/configure.tgt     |   2 +-
>   gdb/none-tdep.c       | 119 ++++++++++++++++++++++++++++++++++++++++++
>   gdb/none-tdep.h       |  30 +++++++++++
>   gdb/riscv-none-tdep.c | 108 ++++++++++++++++++++++++++++++++++++++
>   6 files changed, 272 insertions(+), 1 deletion(-)
>   create mode 100644 gdb/none-tdep.c
>   create mode 100644 gdb/none-tdep.h
>   create mode 100644 gdb/riscv-none-tdep.c
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 9267bea7beb..5f88b6a78cf 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -807,6 +807,7 @@ ALL_TARGET_OBS = \
>   	ravenscar-thread.o \
>   	riscv-fbsd-tdep.o \
>   	riscv-linux-tdep.o \
> +	riscv-none-tdep.o \
>   	riscv-ravenscar-thread.o \
>   	riscv-tdep.o \
>   	rl78-tdep.o \
> @@ -1100,6 +1101,7 @@ COMMON_SFILES = \
>   	minsyms.c \
>   	mipsread.c \
>   	namespace.c \
> +	none-tdep.c \
>   	objc-lang.c \
>   	objfiles.c \
>   	observable.c \
> @@ -1360,6 +1362,7 @@ HFILES_NO_SRCDIR = \
>   	netbsd-tdep.h \
>   	nds32-tdep.h \
>   	nios2-tdep.h \
> +	none-tdep.h \
>   	nto-tdep.h \
>   	objc-lang.h \
>   	objfiles.h \
> @@ -2271,6 +2274,7 @@ ALLDEPFILES = \
>   	riscv-fbsd-tdep.c \
>   	riscv-linux-nat.c \
>   	riscv-linux-tdep.c \
> +	riscv-none-tdep.c \
>   	riscv-ravenscar-thread.c \
>   	riscv-tdep.c \
>   	rl78-tdep.c \
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index 6e039838748..ad88ddd9302 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -85,7 +85,7 @@ ia64*-*-*)
>   	;;
>   
>   riscv*-*-*)
> -	cpu_obs="riscv-tdep.o arch/riscv.o \
> +	cpu_obs="riscv-tdep.o riscv-none-tdep.o arch/riscv.o \
>   	         ravenscar-thread.o riscv-ravenscar-thread.o";;
>   
>   x86_64-*-*)
> diff --git a/gdb/none-tdep.c b/gdb/none-tdep.c
> new file mode 100644
> index 00000000000..8ec2407ad45
> --- /dev/null
> +++ b/gdb/none-tdep.c
> @@ -0,0 +1,119 @@
> +/* Target-dependent code for none, architecture independent.
> +
> +   Copyright (C) 2020 Free Software Foundation, Inc.

2020~2021 now I think.

> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "none-tdep.h"
> +#include "regset.h"
> +#include "elf-bfd.h"            /* for elfcore_write_* */
> +#include "inferior.h"
> +#include "regcache.h"
> +#include "gdbarch.h"
> +#include "gcore.h"
> +
> +/* Build the note section for a corefile, and return it in a malloc
> +   buffer.  Currently this just  dumps all available registers for each

Spurious whitespace in "just  dumps"

> +   thread.  */
> +
> +static gdb::unique_xmalloc_ptr<char>
> +none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
> +{
> +  gdb::unique_xmalloc_ptr<char> note_data;
> +
> +  /* Add note information about the executable and its arguments.  */
> +  std::string fname;
> +  std::string psargs;
> +  static const size_t fname_len = 16;
> +  static const size_t psargs_len = 80;
> +  if (get_exec_file (0))
> +    {
> +      const char *exe = get_exec_file (0);
> +      fname = lbasename (exe);
> +      psargs = std::string (exe);
> +
> +      const char *infargs = get_inferior_args ();
> +      if (infargs != nullptr)
> +	psargs += " " + std::string (infargs);
> +
> +      /* All existing targets that handling writing out prpsinfo expect the

handling -> handle

> +	 fname and psargs strings to be at least 16 and 80 characters long
> +	 respectively, including a null terminator at the end.  Resize to
> +	 the expected length minus one to ensure there is a null within the
> +	 required length.  */
> +      fname.resize (fname_len - 1);
> +      psargs.resize (psargs_len - 1);
> +    }
> +
> +  /* Resize the buffers up to their required lengths.  This will fill any
> +     remaining space with the null character.  */
> +  fname.resize (fname_len);
> +  psargs.resize (psargs_len);
> +
> +  /* Now write out the prpsinfo structure.  */
> +  note_data.reset (elfcore_write_prpsinfo (obfd, note_data.release (),
> +					   note_size, fname.c_str (),
> +					   psargs.c_str ()));
> +  if (note_data == nullptr)
> +    return nullptr;
> +
> +  /* Thread register information.  */
> +  try
> +    {
> +      update_thread_list ();
> +    }
> +  catch (const gdb_exception_error &e)
> +    {
> +      exception_print (gdb_stderr, e);
> +    }
> +
> +  /* Like the Linux 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 ();
> +
> +  /* All threads are reported as having been stopped by the same signal
> +     that stopped SIGNALLED_THR.  */
> +  gdb_signal stop_signal;
> +  if (signalled_thr != nullptr)
> +    stop_signal = signalled_thr->suspend.stop_signal;
> +  else
> +    stop_signal = GDB_SIGNAL_0;
> +
> +  if (signalled_thr != nullptr)
> +    gcore_build_thread_register_notes (gdbarch, signalled_thr,
> +				       stop_signal, obfd, &note_data,
> +				       note_size);
> +  for (thread_info *thr : current_inferior ()->non_exited_threads ())
> +    {
> +      if (thr == signalled_thr)
> +	continue;
> +
> +      gcore_build_thread_register_notes (gdbarch, thr, stop_signal, obfd,
> +					 &note_data, note_size);
> +    }
> +
> +  return note_data;
> +}
> +
> +/* See none-tdep.h.  */
> +
> +void
> +none_init_abi (struct gdbarch *gdbarch)
> +{
> +  /* Default core file support.  */
> +  set_gdbarch_make_corefile_notes (gdbarch, none_make_corefile_notes);
> +}
> diff --git a/gdb/none-tdep.h b/gdb/none-tdep.h
> new file mode 100644
> index 00000000000..46dcfe219ef
> --- /dev/null
> +++ b/gdb/none-tdep.h
> @@ -0,0 +1,30 @@
> +/* Architecture independent code for ABI 'none' (bare-metal).
> +
> +   Copyright (C) 2021 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef NONE_TDEP_H
> +#define NONE_TDEP_H
> +
> +struct gdbarch;
> +
> +/* Initialize support for cross-architecture features applicable for the
> +   GDB_OSABI_NONE ABI, that is bare-metal targets.  */
> +
> +void none_init_abi (struct gdbarch *gdbarch);
> +
> +#endif /* NONE_TDEP_H */
> diff --git a/gdb/riscv-none-tdep.c b/gdb/riscv-none-tdep.c
> new file mode 100644
> index 00000000000..e06ee0981fe
> --- /dev/null
> +++ b/gdb/riscv-none-tdep.c
> @@ -0,0 +1,108 @@
> +/* Copyright (C) 2020 Free Software Foundation, Inc.

2020~2021 now.

> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* This file contain code that is specific for bare-metal RISC-V targets.  */
> +
> +#include "defs.h"
> +#include "arch-utils.h"
> +#include "regcache.h"
> +#include "riscv-tdep.h"
> +#include "elf-bfd.h"
> +#include "regset.h"
> +#include "none-tdep.h"
> +
> +/* Define the general register mapping.  This follows the same format as
> +   the RISC-V linux corefile.  The linux kernel puts the PC at offset 0,
> +   gdb puts it at offset 32.  Register x0 is always 0 and can be ignored.
> +   Registers x1 to x31 are in the same place.  */
> +
> +static const struct regcache_map_entry riscv_gregmap[] =
> +{
> +  { 1,  RISCV_PC_REGNUM, 0 },
> +  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
> +  { 0 }
> +};
> +
> +/* Define the FP register mapping.  This follows the same format as the
> +   RISC-V linux corefile.  The kernel puts the 32 FP regs first, and then
> +   FCSR.  */
> +
> +static const struct regcache_map_entry riscv_fregmap[] =
> +{
> +  { 32, RISCV_FIRST_FP_REGNUM, 0 },
> +  { 1, RISCV_CSR_FCSR_REGNUM, 4 },	/* Always stored as 4-bytes.  */
> +  { 0 }
> +};
> +
> +/* Define the general register regset.  */
> +
> +static const struct regset riscv_gregset =
> +{
> +  riscv_gregmap, riscv_supply_regset, regcache_collect_regset
> +};
> +
> +/* Define the FP register regset.  */
> +
> +static const struct regset riscv_fregset =
> +{
> +  riscv_fregmap, riscv_supply_regset, regcache_collect_regset
> +};
> +
> +/* Implement the "iterate_over_regset_sections" gdbarch method.  */
> +
> +static void
> +riscv_iterate_over_regset_sections (struct gdbarch *gdbarch,
> +				    iterate_over_regset_sections_cb *cb,
> +				    void *cb_data,
> +				    const struct regcache *regcache)
> +{
> +  /* Write out the GPRs.  */
> +  int sz = 32 * riscv_isa_xlen (gdbarch);
> +  cb (".reg", sz, sz, &riscv_gregset, NULL, cb_data);
> +
> +  /* Write out the FPRs, but only if present.  */
> +  if (riscv_isa_flen (gdbarch) > 0)
> +    {
> +      sz = (32 * riscv_isa_flen (gdbarch)
> +	    + register_size (gdbarch, RISCV_CSR_FCSR_REGNUM));
> +      cb (".reg2", sz, sz, &riscv_fregset, NULL, cb_data);
> +    }
> +}
> +
> +/* Initialize RISC-V bare-metal ABI info.  */
> +
> +static void
> +riscv_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  none_init_abi (gdbarch);
> +
> +  /* Iterate over registers for reading and writing bare metal RISC-V core
> +     files.  */
> +  set_gdbarch_iterate_over_regset_sections
> +    (gdbarch, riscv_iterate_over_regset_sections);
> +
> +}
> +
> +/* Initialize RISC-V bare-metal target support.  */
> +
> +void _initialize_riscv_none_tdep ();
> +void
> +_initialize_riscv_none_tdep ()
> +{
> +  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_NONE,
> +			  riscv_none_init_abi);
> +}
> 

Otherwise this looks good to me.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 6/9] bfd/binutils: add support for RISC-V CSRs in core files
  2021-02-01 12:00   ` Andrew Burgess
@ 2021-02-01 14:08     ` Luis Machado
  2021-02-10 21:00     ` Jim Wilson
  1 sibling, 0 replies; 57+ messages in thread
From: Luis Machado @ 2021-02-01 14:08 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

On 2/1/21 9:00 AM, Andrew Burgess wrote:
> Here is an update version of this patch.
> 
> In this patch I have placed the CSRs into a note named "GDB".  This
> should protect us if, in the future, the note type number I have used
> is reused by some other core file producer (Linux / FreeBSD) and given
> a different meaning.
> 
> Any feedback?
> 
> Thanks,
> Andrew
> 
> 
> ---
> 
> commit 15bcb460981a000e74b2d3dc4f59f0f06bc0cd52
> Author: Andrew Burgess <andrew.burgess@embecosm.com>
> Date:   Fri Nov 27 14:04:16 2020 +0000
> 
>      bfd/binutils: add support for RISC-V CSRs in core files
>      
>      Adds support for including RISC-V control and status registers into
>      core files.
>      
>      The value for the define NT_RISCV_CSR is set to 0x900, this
>      corresponds to a patch I have proposed for the Linux kernel here:
>      
>        http://lists.infradead.org/pipermail/linux-riscv/2020-December/003910.html
>      
>      As I have not yet heard if the above patch will be accepted into the
>      kernel or not I have set the note name string to "GDB", and the note
>      type to NT_RISCV_CSR.
>      
>      This means that if the above patch is rejected from the kernel, and
>      the note type number 0x900 is assigned to some other note type, we
>      will still be able to distinguish between the GDB produced
>      NT_RISCV_CSR, and the kernel produced notes, where the name would be
>      set to "CORE".
>      
>      bfd/ChangeLog:
>      
>              * elf-bfd.h (elfcore_write_riscv_csr): Declare.
>              * elf.c (elfcore_grok_riscv_csr): New function.
>              (elfcore_grok_note): Handle NT_RISCV_CSR.
>              (elfcore_write_riscv_csr): New function.
>              (elfcore_write_register_note): Handle '.reg-riscv-csr'.
>      
>      binutils/ChangeLog:
>      
>              * readelf.c (get_note_type): Handle NT_RISCV_CSR.
>      
>      include/ChangeLog:
>      
>              * elf/common.h (NT_RISCV_CSR): Define.
> 
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index 779acc745bc..5b7eb8897c8 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -2797,6 +2797,8 @@ extern char *elfcore_write_aarch_pauth
>     (bfd *, char *, int *, const void *, int);
>   extern char *elfcore_write_arc_v2
>     (bfd *, char *, int *, const void *, int);
> +extern char *elfcore_write_riscv_csr
> +  (bfd *, char *, int *, const void *, int);
>   extern char *elfcore_write_gdb_tdesc
>     (bfd *, char *, int *, const void *, int);
>   extern char *elfcore_write_lwpstatus
> diff --git a/bfd/elf.c b/bfd/elf.c
> index c6cf7fe2d6e..d1fd29f380a 100644
> --- a/bfd/elf.c
> +++ b/bfd/elf.c
> @@ -9912,6 +9912,12 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
>     return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
>   }
>   
> +static bfd_boolean
> +elfcore_grok_riscv_csr (bfd *abfd, Elf_Internal_Note *note)
> +{
> +  return elfcore_make_note_pseudosection (abfd, ".reg-riscv-csr", note);
> +}
> +
>   static bfd_boolean
>   elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
>   {
> @@ -10583,6 +10589,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
>         else
>           return TRUE;
>   
> +    case NT_RISCV_CSR:
> +      if (note->namesz == 4
> +          && strcmp (note->namedata, "GDB") == 0)
> +        return elfcore_grok_riscv_csr (abfd, note);
> +      else
> +	return TRUE;
> +
>       case NT_PRPSINFO:
>       case NT_PSINFO:
>         if (bed->elf_backend_grok_psinfo)
> @@ -11964,6 +11977,18 @@ elfcore_write_arc_v2 (bfd *abfd,
>   			     note_name, NT_ARC_V2, arc_v2, size);
>   }
>   
> +char *
> +elfcore_write_riscv_csr (bfd *abfd,
> +                         char *buf,
> +                         int *bufsiz,
> +                         const void *csrs,
> +                         int size)
> +{
> +  const char *note_name = "GDB";
> +  return elfcore_write_note (abfd, buf, bufsiz,
> +			     note_name, NT_RISCV_CSR, csrs, size);
> +}
> +
>   char *
>   elfcore_write_gdb_tdesc (bfd *abfd,
>   			 char *buf,
> @@ -12062,6 +12087,8 @@ elfcore_write_register_note (bfd *abfd,
>       return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
>     if (strcmp (section, ".gdb-tdesc") == 0)
>       return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
> +  if (strcmp (section, ".reg-riscv-csr") == 0)
> +    return elfcore_write_riscv_csr (abfd, buf, bufsiz, data, size);
>     return NULL;
>   }
>   
> diff --git a/binutils/readelf.c b/binutils/readelf.c
> index feb458877c8..807eccfb026 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -18374,6 +18374,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
>   	return _("NT_ARM_HW_WATCH (AArch hardware watchpoint registers)");
>         case NT_ARC_V2:
>   	return _("NT_ARC_V2 (ARC HS accumulator/extra registers)");
> +      case NT_RISCV_CSR:
> +	return _("NT_RISCV_CSR (RISC-V control and status registers)");
>         case NT_PSTATUS:
>   	return _("NT_PSTATUS (pstatus structure)");
>         case NT_FPREGS:
> diff --git a/include/elf/common.h b/include/elf/common.h
> index e6e9c278faa..4cb3748e4fd 100644
> --- a/include/elf/common.h
> +++ b/include/elf/common.h
> @@ -674,6 +674,8 @@
>   					/*   note name must be "LINUX".  */
>   #define NT_ARC_V2	0x600		/* ARC HS accumulator/extra registers.  */
>   					/*   note name must be "LINUX".  */
> +#define NT_RISCV_CSR    0x900		/* RISC-V Control and Status Registers */
> +					/*   note name must be "CORE".  */
>   #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
>   #define NT_FILE		0x46494c45	/* Description of mapped files.  */
>   
> 

LGTM.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 7/9] gdb/riscv: make riscv target description names global
  2021-01-20 20:23 ` [PATCHv2 7/9] gdb/riscv: make riscv target description names global Andrew Burgess
@ 2021-02-01 14:22   ` Luis Machado
  0 siblings, 0 replies; 57+ messages in thread
From: Luis Machado @ 2021-02-01 14:22 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

On 1/20/21 5:23 PM, Andrew Burgess wrote:
> A later commit will need the names of the RISC-V target description
> features in files other than riscv-tdep.c.  This commit just makes the
> names global strings that can be accessed from other riscv-*.c files.
> 
> There should be no user visible changes after this commit.
> 
> gdb/ChangeLog:
> 
> 	* riscv-tdep.c (riscv_feature_name_csr): Define.
> 	(riscv_feature_name_cpu): Define.
> 	(riscv_feature_name_fpu): Define.
> 	(riscv_feature_name_virtual): Define.
> 	(riscv_xreg_feature): Use riscv_feature_name_cpu.
> 	(riscv_freg_feature): Use riscv_feature_name_fpu.
> 	(riscv_virtual_feature): Use riscv_feature_name_virtual.
> 	(riscv_csr_feature): Use riscv_feature_name_csr.
> 	* riscv-tdep.h (riscv_feature_name_csr): Declare.
> ---
>   gdb/ChangeLog    | 12 ++++++++++++
>   gdb/riscv-tdep.c | 14 ++++++++++----
>   gdb/riscv-tdep.h |  3 +++
>   3 files changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
> index b16e7d78fc5..cb917247bab 100644
> --- a/gdb/riscv-tdep.c
> +++ b/gdb/riscv-tdep.c
> @@ -94,6 +94,12 @@ static unsigned int riscv_debug_unwinder = 0;
>   
>   static unsigned int riscv_debug_gdbarch = 0;
>   
> +/* The names of the RISC-V target description features.  */
> +const char *riscv_feature_name_csr = "org.gnu.gdb.riscv.csr";
> +static const char *riscv_feature_name_cpu = "org.gnu.gdb.riscv.cpu";
> +static const char *riscv_feature_name_fpu = "org.gnu.gdb.riscv.fpu";
> +static const char *riscv_feature_name_virtual = "org.gnu.gdb.riscv.virtual";
> +
>   /* Cached information about a frame.  */
>   
>   struct riscv_unwind_cache
> @@ -257,7 +263,7 @@ riscv_register_feature::register_info::check
>   struct riscv_xreg_feature : public riscv_register_feature
>   {
>     riscv_xreg_feature ()
> -    : riscv_register_feature ("org.gnu.gdb.riscv.cpu")
> +    : riscv_register_feature (riscv_feature_name_cpu)
>     {
>       m_registers =  {
>         { RISCV_ZERO_REGNUM + 0, { "zero", "x0" } },
> @@ -354,7 +360,7 @@ static const struct riscv_xreg_feature riscv_xreg_feature;
>   struct riscv_freg_feature : public riscv_register_feature
>   {
>     riscv_freg_feature ()
> -    : riscv_register_feature ("org.gnu.gdb.riscv.fpu")
> +    : riscv_register_feature (riscv_feature_name_fpu)
>     {
>       m_registers =  {
>         { RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" } },
> @@ -482,7 +488,7 @@ static const struct riscv_freg_feature riscv_freg_feature;
>   struct riscv_virtual_feature : public riscv_register_feature
>   {
>     riscv_virtual_feature ()
> -    : riscv_register_feature ("org.gnu.gdb.riscv.virtual")
> +    : riscv_register_feature (riscv_feature_name_virtual)
>     {
>       m_registers =  {
>         { RISCV_PRIV_REGNUM, { "priv" } }
> @@ -518,7 +524,7 @@ static const struct riscv_virtual_feature riscv_virtual_feature;
>   struct riscv_csr_feature : public riscv_register_feature
>   {
>     riscv_csr_feature ()
> -    : riscv_register_feature ("org.gnu.gdb.riscv.csr")
> +    : riscv_register_feature (riscv_feature_name_csr)
>     {
>       m_registers = {
>   #define DECLARE_CSR(NAME,VALUE,CLASS,DEFINE_VER,ABORT_VER)		\
> diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
> index d1f1cf17ba8..154097df5d0 100644
> --- a/gdb/riscv-tdep.h
> +++ b/gdb/riscv-tdep.h
> @@ -160,4 +160,7 @@ extern void riscv_supply_regset (const struct regset *regset,
>   				  struct regcache *regcache, int regnum,
>   				  const void *regs, size_t len);
>   
> +/* The names of the RISC-V target description features.  */
> +extern const char *riscv_feature_name_csr;
> +
>   #endif /* RISCV_TDEP_H */
> 

This looks OK.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 8/9] gdb/riscv: write CSRs into baremetal core dumps
  2021-01-20 20:23 ` [PATCHv2 8/9] gdb/riscv: write CSRs into baremetal core dumps Andrew Burgess
@ 2021-02-01 14:33   ` Luis Machado
  0 siblings, 0 replies; 57+ messages in thread
From: Luis Machado @ 2021-02-01 14:33 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

On 1/20/21 5:23 PM, Andrew Burgess wrote:
> Use the current target description to include CSRs into the RISC-V
> baremetal core dumps.
> 
> Every CSR declared in the current target description will be included
> in the core dump.  If a CSR fails to read then the value 0 will be
> placed into the core dump instead.
> 
> It will be critical for users that they have the same target
> description in use when loading the core file as was in use when
> writing the core file.  This should be fine if the user allows the
> target description to be written into the core file.
> 
> In more detail, this commit adds a NT_RISCV_CSR note type.  The
> contents of this section is a series of either 4-byte (on RV32
> targets), or 8-byte (on RV64 targets) regions.  Every CSR that
> is mentioned in the current target description is written into one of
> these regions in the order that the registers appear in the target
> description.  As a consequence it is critical that the exact same
> target description, including the same register order, is in use when
> the CSRs are loaded from the core file.
> 
> gdb/ChangeLog:
> 
> 	* riscv-non-tdep.c (riscv_csrset): New static global.
> 	(riscv_update_csrmap): New function.
> 	(riscv_iterate_over_regset_sections): Process CSRs.
> ---
>   gdb/ChangeLog         |  7 +++++
>   gdb/riscv-none-tdep.c | 60 +++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 67 insertions(+)
> 
> diff --git a/gdb/riscv-none-tdep.c b/gdb/riscv-none-tdep.c
> index e06ee0981fe..2392c132e69 100644
> --- a/gdb/riscv-none-tdep.c
> +++ b/gdb/riscv-none-tdep.c
> @@ -24,6 +24,8 @@
>   #include "elf-bfd.h"
>   #include "regset.h"
>   #include "none-tdep.h"
> +#include "user-regs.h"
> +#include "target-descriptions.h"
>   
>   /* Define the general register mapping.  This follows the same format as
>      the RISC-V linux corefile.  The linux kernel puts the PC at offset 0,
> @@ -62,6 +64,42 @@ static const struct regset riscv_fregset =
>     riscv_fregmap, riscv_supply_regset, regcache_collect_regset
>   };
>   
> +/* Define the CSR regset, this is not constant as the regmap field is
> +   updated dynamically based on the current target description.  */
> +
> +static struct regset riscv_csrset =
> +{
> +  nullptr, regcache_supply_regset, regcache_collect_regset
> +};
> +
> +/* Update the regmap field of RISCV_CSRSET based on the CSRs available in
> +   the current target description.  */
> +
> +static void
> +riscv_update_csrmap (struct gdbarch *gdbarch,
> +		     const struct tdesc_feature *feature_csr)
> +{
> +  int i = 0;
> +
> +  /* Release any previously defined map.  */
> +  delete[] ((struct regcache_map_entry *) riscv_csrset.regmap);
> +
> +  /* Now create a register map for every csr found in the target
> +     description.  */
> +  struct regcache_map_entry *riscv_csrmap
> +    = new struct regcache_map_entry[feature_csr->registers.size() + 1];
> +  for (auto &csr : feature_csr->registers)
> +    {
> +      int regnum = user_reg_map_name_to_regnum (gdbarch, csr->name.c_str(),
> +						csr->name.length());
> +      riscv_csrmap[i++] = {1, regnum, 0};
> +    }
> +
> +  /* Mark the end of the array.  */
> +  riscv_csrmap[i] = {0};
> +  riscv_csrset.regmap = riscv_csrmap;
> +}
> +
>   /* Implement the "iterate_over_regset_sections" gdbarch method.  */
>   
>   static void
> @@ -81,6 +119,28 @@ riscv_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	    + register_size (gdbarch, RISCV_CSR_FCSR_REGNUM));
>         cb (".reg2", sz, sz, &riscv_fregset, NULL, cb_data);
>       }
> +
> +  /* Read or write the CSRs.  The set of CSRs is defined by the current
> +     target description.  The user is responsible for ensuring that the
> +     same target description is in use when reading the core file as was
> +     in use when writing the core file.  */
> +  const struct target_desc *tdesc = gdbarch_target_desc (gdbarch);
> +
> +  /* Do not dump/load any CSRs if there is no target description or the target
> +     description does not contain any CSRs.  */
> +  if (tdesc != nullptr)
> +    {
> +      const struct tdesc_feature *feature_csr
> +        = tdesc_find_feature (tdesc, riscv_feature_name_csr);
> +      if (feature_csr != nullptr && feature_csr->registers.size () > 0)
> +	{
> +	  riscv_update_csrmap (gdbarch, feature_csr);
> +	  cb (".reg-riscv-csr",
> +	      (feature_csr->registers.size() * riscv_isa_xlen (gdbarch)),
> +	      (feature_csr->registers.size() * riscv_isa_xlen (gdbarch)),
> +	      &riscv_csrset, NULL, cb_data);
> +	}
> +    }
>   }
>   
>   /* Initialize RISC-V bare-metal ABI info.  */
> 

Looks OK to me.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation
  2021-02-01 13:48   ` Luis Machado
@ 2021-02-01 14:44     ` Andrew Burgess
  0 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-01 14:44 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, binutils, Fredrik Hederstierna

* Luis Machado <luis.machado@linaro.org> [2021-02-01 10:48:15 -0300]:

> On 1/20/21 5:23 PM, Andrew Burgess wrote:
> > When creating a core file GDB will call the function
> > elfcore_write_prstatus to write out the general purpose registers
> > along with the pid/tid for the thread.
> > 
> > However, for a bare metal RISC-V tool chain the prstatus*_t types are
> > not defined so the elfcore_write_prstatus function will return NULL,
> > preventing core file creation.
> > 
> > This commit provides the `elf_backend_write_core_note' hook and uses
> > the provided function to write out the ptstatus information.
> 
> ptstatus -> prstatus?

Thanks for spotting this.  On re-reading the commit message I realised
it was actually lagging behind the patch a little, the patch now
handles prstatus_t and prpsinfo_t.  I fixed the typo you spotted, and
updated the commit message.

Thanks,
Andrew

---

commit 72e2e1f0e914c7018b7db41f0beb3736b3c37beb
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Mon Nov 30 12:14:38 2020 +0000

    bfd/riscv: prepare to handle bare metal core dump creation
    
    When creating a core file GDB will call the function
    elfcore_write_prstatus to write out the general purpose registers
    along with the pid/tid for the thread (into a prstatus structure) and
    the executable name and arguments (into a prpsinfo_t structure).
    
    However, for a bare metal RISC-V tool chain the prstatus_t and
    prpsinfo_t types are not defined so the elfcore_write_prstatus
    function will return NULL, preventing core file creation.
    
    This commit provides the `elf_backend_write_core_note' hook and uses
    the provided function to write out the required information.
    
    In order to keep changes in the non bare metal tools to a minimum, the
    provided backend function will itself return NULL when the prstatus_t
    or pspsinfo_t types are available, the consequence of this is that the
    generic code in elfcore_write_prstatus will be used just as before.
    But, when prstatus_t or prpsinfo_t is not available, the new backend
    function will write out the information using predefined offsets.
    
    This new functionality will be used by a later GDB commit that will
    add bare metal core dumps for RISC-V.
    
    bfd/ChangeLog:
    
            * elfnn-riscv.c (riscv_write_core_note): New function.
            (elf_backend_write_core_note): Define.

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index b2ec6a29fbf..70a683b45a3 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -4886,6 +4886,77 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 # define PRPSINFO_OFFSET_PR_PSARGS	56
 #endif
 
+/* Write PRSTATUS and PRPSINFO note into core file.  This will be called
+   before the generic code in elf.c.  By checking the compiler defines we
+   only perform any action here if the generic code would otherwise not be
+   able to help us.  The intention is that bare metal core dumps (where the
+   prstatus_t and/or prpsinfo_t might not be available) will use this code,
+   while non bare metal tools will use the generic elf code.  */
+
+static char *
+riscv_write_core_note (bfd *abfd ATTRIBUTE_UNUSED,
+                       char *buf ATTRIBUTE_UNUSED,
+                       int *bufsiz ATTRIBUTE_UNUSED,
+                       int note_type ATTRIBUTE_UNUSED, ...)
+{
+  switch (note_type)
+    {
+    default:
+      return NULL;
+
+#if !defined (HAVE_PRPSINFO_T)
+    case NT_PRPSINFO:
+      {
+	char data[PRPSINFO_SIZE] ATTRIBUTE_NONSTRING;
+	va_list ap;
+
+	va_start (ap, note_type);
+	memset (data, 0, sizeof (data));
+	strncpy (data + PRPSINFO_OFFSET_PR_FNAME, va_arg (ap, const char *), 16);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+	DIAGNOSTIC_PUSH;
+	/* GCC 8.0 and 8.1 warn about 80 equals destination size with
+	   -Wstringop-truncation:
+	   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+	 */
+	DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
+	strncpy (data + PRPSINFO_OFFSET_PR_PSARGS, va_arg (ap, const char *), 80);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+	DIAGNOSTIC_POP;
+#endif
+	va_end (ap);
+	return elfcore_write_note (abfd, buf, bufsiz,
+				   "CORE", note_type, data, sizeof (data));
+      }
+#endif /* !HAVE_PRPSINFO_T */
+
+#if !defined (HAVE_PRSTATUS_T)
+    case NT_PRSTATUS:
+      {
+        char data[PRSTATUS_SIZE];
+        va_list ap;
+        long pid;
+        int cursig;
+        const void *greg;
+
+        va_start (ap, note_type);
+        memset (data, 0, sizeof(data));
+        pid = va_arg (ap, long);
+        bfd_put_32 (abfd, pid, data + PRSTATUS_OFFSET_PR_PID);
+        cursig = va_arg (ap, int);
+        bfd_put_16 (abfd, cursig, data + PRSTATUS_OFFSET_PR_CURSIG);
+        greg = va_arg (ap, const void *);
+        memcpy (data + PRSTATUS_OFFSET_PR_REG, greg,
+                PRSTATUS_SIZE - PRSTATUS_OFFSET_PR_REG - ARCH_SIZE / 8);
+        va_end (ap);
+        return elfcore_write_note (abfd, buf, bufsiz,
+                                   "CORE", note_type, data, sizeof (data));
+      }
+#endif /* !HAVE_PRSTATUS_T */
+    }
+}
+
 /* Support for core dump NOTE sections.  */
 
 static bfd_boolean
@@ -5000,6 +5071,7 @@ riscv_elf_obj_attrs_arg_type (int tag)
 #define elf_backend_grok_prstatus		riscv_elf_grok_prstatus
 #define elf_backend_grok_psinfo			riscv_elf_grok_psinfo
 #define elf_backend_object_p			riscv_elf_object_p
+#define elf_backend_write_core_note		riscv_write_core_note
 #define elf_info_to_howto_rel			NULL
 #define elf_info_to_howto			riscv_info_to_howto_rela
 #define bfd_elfNN_bfd_relax_section		_bfd_riscv_relax_section

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 9/9] gdb/arm: add support for bare-metal core dumps
  2021-01-20 20:23 ` [PATCHv2 9/9] gdb/arm: add support for bare-metal " Andrew Burgess
@ 2021-02-01 14:51   ` Luis Machado
  0 siblings, 0 replies; 57+ messages in thread
From: Luis Machado @ 2021-02-01 14:51 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

Andrew,

Thanks a lot for going out of your way to come up with this patch and 
documentation changes. It is great that this can be reused for other 
architectures and it definitely saves developers some time. Much 
appreciated.

With the changes below, I think it will be pretty simple to support ARM 
bare metal cores files (it might even work as-is).

There are some nits in the patch, most of which I pointed out in the 
RISCV bare metal core file documentation patch. But other than those, I 
think this looks good.

Fredrik, would you mind taking a look at Andrew's changes for ARM bare 
metal core file support and rebase your changes on top of his RISCV 
series? I think that's the way forward.

You will also need a copyright assignment before your changes can be 
accepted upstream, as this work is not considered a trivial change.

Finally, it would be nice to have some testing to make sure this is 
working as expected. Do you have a test setup that you can use to 
validate things?

Patch nits below...

On 1/20/21 5:23 PM, Andrew Burgess wrote:
> This commit is just a trimmed down version of Fredrik's patch (link
> below), updated to fit in with my new common core dumping code.
> 
> As a significant piece of work Fredrik would need a copyright
> assignment in place before this could be merged.  I don't know if that
> is the case or not.
> 
> As with the RISC-V patch (#5) the documentation of the core file
> format is given in the commit message, but it really needs a "better"
> home.  Unlike RISC-V, I don't know where that home is for ARM.
> 
> I would prefer if most feedback on the documentation was given on the
> RISC-V patch (#5 in this series), unless you're pointing out an error
> that is specific just to this patch.
> 
> I have checked that this code builds, but otherwise I've done no
> testing on this at all.  I assume Fredrik gave this some testing
> before posting, but I have mucked about with things, so I'm sure any
> mistakes are mine.
> 
> Thanks,
> Andrew
> 
> 
> ---
> 
> This commit adds support for bare metal core dumps on the ARM target,
> and is based off of this patch submitted to the mailing list:
> 
>    https://sourceware.org/pipermail/gdb-patches/2020-October/172845.html
> 
> Compared to the version linked above this version is updated to take
> account of recent changes to the core dump infrastructure in GDB,
> there is now more shared infrastructure for core dumping within GDB,
> and also some common bare metal core dumping infrastructure.  As a
> result this patch is smaller than the original proposed patch.
> 
> Further, the original patch included some unrelated changes to the
> simulator that have been removed from this version.
> 
> I have written a ChangeLog entry as the original patch was missing
> one.
> 
> I have done absolutely no testing of this patch.  It is based on the
> original submitted patch, which I assume was tested, but after my
> modifications things might have been broken.
> 
> The cores dump format is based around generating an ELF containing

cores -> core

> sections for the writable regions of memory that a user could be
> using.  Which regions are dumped rely on GDB's existing common core
> dumping code, GDB will attempt to figure out the stack and heap as
> well as copying out writable data sections as identified by the
> original ELF.
> 
> Register information is added to the core dump using notes, just as it
> is for Linux of FreeBSD core dumps.  The note types used consist of
> the 2 basic types you would expect in a OS based core dump,
> NT_PRPSINFO, NT_PRSTATUS, along with the architecture specific
> NT_ARM_VFP note.
> 
> The data layouts for each note type are described blow, in all case,

blow -> below

case -> cases?

> all padding fields should be set to zero.
> 
> Note NT_PRPSINFO is optional.  Its data layout is:
> 
>    struct prpsinfo_t
>    {
>      uint8_t padding[28];
>      char fname[16];
>      char psargs[80];
>    }
> 
> Field 'fname' - null terminated string consisting of the basename of
>      (up to the fist 15 characters of) the executable.  Any additional
>      space should be set to zero.  If there's no executable name then
>      this field can be set to all zero.
> 
> Field 'psargs' - a null terminated string up to 80 characters in
>      length.  Any additional space should be filled with zero.  This
>      field contains the full executable path and any arguments passed
>      to the executable.  If there's nothing sensible to write in this
>      field then fill it with zero.
> 
> Note NT_PRSTATUS is required, its data layout is:
> 
>    struct prstatus_t
>    {
>      uint8_t padding_1[12];
>      uint16_t sig;
>      uint8_t padding_2[10];
>      uint32_t thread_id;
>      uint8_t padding_3[44];
>      uint32_t gregs[18];
>    }
> 
> Field 'sig' - the signal that stopped this thread.  Its implementation

Its -> It's

>      defined what this field actually means.  Within GDB this will be
>      the signal number that the remote target reports as the stop
>      reason for this thread.
> 
> Field 'thread_is' - the thread id for this thread, its implementation

its -> it's

>      defined what this field actually means.  Within GDB this will be
>      thread thread-id that is assigned to each remote thread.
> 
> Field 'gregs' - holds the general purpose registers $a1 through to $pc
>      at indices 0 to 15.  At index 16 the program status register.
>      Index 17 should be set to zero.
> 
> Note NT_ARM_VFP is optional, its data layout is:
> 
>    armvfp_t
>    {
>      uint64_t regs[32];
>      uint32_t fpscr;
>    }
> 
> Field 'regs' - holds the 32 d-registers 0 to 31 in order.
> 
> Field 'fpscr' - holds the fpscr register.
> 
> The rules for ordering the notes is the same as for Linux.  The
> NT_PRSTATUS note must come before any other notes about additional
> register sets.  And for multi-threaded targets all registers for a
> single thread should be grouped together.  This is because only
> NT_PRSTATUS includes a thread-id, all additional register notes after
> a NT_PRSTATUS are assumed to belong to the same thread until a
> different NT_PRSTATUS is seen.
> 
> gdb/ChangeLog:
> 
> 	PR gdb/14383
> 	* Makefile.in (ALL_TARGET_OBS): Add arm-none-tdep.o.
> 	(ALLDEPFILES): Add arm-none-tdep.c
> 	* arm-none-tdep.c: New file.
> 	* configure.tgt (arm*-*-*): Add arm-none-tdep.o to cpu_obs.
> ---
>   gdb/ChangeLog       |   9 ++
>   gdb/Makefile.in     |   2 +
>   gdb/arm-none-tdep.c | 208 ++++++++++++++++++++++++++++++++++++++++++++
>   gdb/configure.tgt   |   3 +-
>   4 files changed, 221 insertions(+), 1 deletion(-)
>   create mode 100644 gdb/arm-none-tdep.c
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 5f88b6a78cf..c40dd7d4688 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -726,6 +726,7 @@ ALL_TARGET_OBS = \
>   	arm-fbsd-tdep.o \
>   	arm-linux-tdep.o \
>   	arm-netbsd-tdep.o \
> +	arm-none-tdep.o \
>   	arm-obsd-tdep.o \
>   	arm-pikeos-tdep.o \
>   	arm-symbian-tdep.o \
> @@ -2167,6 +2168,7 @@ ALLDEPFILES = \
>   	arm-linux-tdep.c \
>   	arm-netbsd-nat.c \
>   	arm-netbsd-tdep.c \
> +	arm-none-tdep.c \
>   	arm-obsd-tdep.c \
>   	arm-symbian-tdep.c \
>   	arm-tdep.c \
> diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
> new file mode 100644
> index 00000000000..199ac652129
> --- /dev/null
> +++ b/gdb/arm-none-tdep.c
> @@ -0,0 +1,208 @@
> +/* none on ARM target support.
> +
> +   Copyright (C) 2020 Free Software Foundation, Inc.

2020~2021

> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "arm-tdep.h"
> +#include "arch-utils.h"
> +#include "regcache.h"
> +#include "elf-bfd.h"
> +#include "regset.h"
> +#include "none-tdep.h"
> +#include "user-regs.h"
> +
> +/* Core file and register set support.  */
> +#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
> +
> +/* Support VFP register format.  */
> +#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
> +
> +/* The index to access CSPR in user_regs as defined in GLIBC.  */

CSPR -> CPSR

> +#define ARM_NONE_CPSR_GREGNUM 16
> +
> +/* Supply register REGNUM from buffer GREGS_BUF (length LEN bytes) into
> +   REGCACHE.  If REGNUM is -1 then supply all registers.  The set of
> +   registers that this function will supply is limited to the general
> +   purpose registers.
> +
> +   The layout of the registers here is based on the ARM GNU/Linux
> +   layout.  */
> +
> +static void
> +arm_none_supply_gregset (const struct regset *regset,
> +			 struct regcache *regcache,
> +			 int regnum, const void *gregs_buf, size_t len)
> +{
> +  struct gdbarch *gdbarch = regcache->arch ();
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
> +
> +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
> +    if (regnum == -1 || regnum == regno)
> +      regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
> +
> +  if (regnum == ARM_PS_REGNUM || regnum == -1)
> +    {
> +      if (arm_apcs_32)
> +	regcache->raw_supply (ARM_PS_REGNUM,
> +			      gregs + ARM_INT_REGISTER_SIZE
> +			      * ARM_NONE_CPSR_GREGNUM);
> +      else
> +	regcache->raw_supply (ARM_PS_REGNUM,
> +			     gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> +    }
> +
> +  if (regnum == ARM_PC_REGNUM || regnum == -1)
> +    {
> +      gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
> +
> +      CORE_ADDR reg_pc
> +	= extract_unsigned_integer (gregs + ARM_INT_REGISTER_SIZE
> +				    * ARM_PC_REGNUM,
> +				    ARM_INT_REGISTER_SIZE, byte_order);
> +      reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
> +      store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
> +			      reg_pc);
> +      regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
> +    }
> +}
> +
> +/* Collect register REGNUM from REGCACHE and place it into buffer GREGS_BUF
> +   (length LEN bytes).  If REGNUM is -1 then collect all registers.  The
> +   set of registers that this function will collect is limited to the
> +   general purpose registers.
> +
> +   The layout of the registers here is based on the ARM GNU/Linux
> +   layout.  */
> +
> +static void
> +arm_none_collect_gregset (const struct regset *regset,
> +			  const struct regcache *regcache,
> +			  int regnum, void *gregs_buf, size_t len)
> +{
> +  gdb_byte *gregs = (gdb_byte *) gregs_buf;
> +
> +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
> +    if (regnum == -1 || regnum == regno)
> +      regcache->raw_collect (regno,
> +			     gregs + ARM_INT_REGISTER_SIZE * regno);
> +
> +  if (regnum == ARM_PS_REGNUM || regnum == -1)
> +    {
> +      if (arm_apcs_32)
> +	regcache->raw_collect (ARM_PS_REGNUM,
> +			       gregs + ARM_INT_REGISTER_SIZE
> +			       * ARM_NONE_CPSR_GREGNUM);
> +      else
> +	regcache->raw_collect (ARM_PS_REGNUM,
> +			       gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> +    }
> +
> +  if (regnum == ARM_PC_REGNUM || regnum == -1)
> +    regcache->raw_collect (ARM_PC_REGNUM,
> +			   gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> +}
> +
> +/* Supply VFP registers from REGS_BUF into REGCACHE.  */
> +
> +static void
> +arm_none_supply_vfp (const struct regset *regset,
> +		     struct regcache *regcache,
> +		     int regnum, const void *regs_buf, size_t len)
> +{
> +  const gdb_byte *regs = (const gdb_byte *) regs_buf;
> +
> +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
> +    regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
> +
> +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
> +    if (regnum == -1 || regnum == regno)
> +      regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
> +}
> +
> +/* Collect VFP registers from REGCACHE into REGS_BUF.  */
> +
> +static void
> +arm_none_collect_vfp (const struct regset *regset,
> +		      const struct regcache *regcache,
> +		      int regnum, void *regs_buf, size_t len)
> +{
> +  gdb_byte *regs = (gdb_byte *) regs_buf;
> +
> +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
> +    regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
> +
> +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
> +    if (regnum == -1 || regnum == regno)
> +      regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
> +}
> +
> +/* The general purpose register set.  */
> +
> +static const struct regset arm_none_gregset =
> +  {
> +    nullptr, arm_none_supply_gregset, arm_none_collect_gregset
> +  };
> +
> +/* The VFP register set.  */
> +
> +static const struct regset arm_none_vfpregset =
> +  {
> +    nullptr, arm_none_supply_vfp, arm_none_collect_vfp
> +  };
> +
> +/* Iterate over core file register note sections.  */
> +
> +static void
> +arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
> +				       iterate_over_regset_sections_cb *cb,
> +				       void *cb_data,
> +				       const struct regcache *regcache)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET,
> +      &arm_none_gregset, nullptr, cb_data);
> +
> +  if (tdep->vfp_register_count > 0)
> +    cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP,
> +	&arm_none_vfpregset, "VFP floating-point", cb_data);
> +}
> +
> +/* Initialize ARM bare-metal ABI info.  */
> +
> +static void
> +arm_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  none_init_abi (gdbarch);
> +
> +  /* Iterate over registers for reading and writing bare metal ARM core
> +     files.  */
> +  set_gdbarch_iterate_over_regset_sections
> +    (gdbarch, arm_none_iterate_over_regset_sections);
> +}
> +
> +/* Initialize ARM bare-metal target support.  */
> +
> +void _initialize_arm_none_tdep ();
> +void
> +_initialize_arm_none_tdep ()
> +{
> +  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NONE,
> +			  arm_none_init_abi);
> +}
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index ad88ddd9302..4f3b9df90d7 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -65,7 +65,8 @@ arc*-*-*)
>   
>   arm*-*-*)
>   	cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \
> -		 arch/arm-get-next-pcs.o arm-tdep.o";;
> +		 arch/arm-get-next-pcs.o arm-tdep.o arm-none-tdep.o"
> +	;;
>   
>   hppa*-*-*)
>   	# Target: HP PA-RISC
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: PING: Re: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-02-01 12:05   ` PING: " Andrew Burgess
@ 2021-02-01 15:10     ` Strasuns, Mihails
  0 siblings, 0 replies; 57+ messages in thread
From: Strasuns, Mihails @ 2021-02-01 15:10 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils; +Cc: Fredrik Hederstierna

> -----Original Message-----
> From: Gdb-patches <gdb-patches-bounces@sourceware.org> On Behalf Of
> Andrew Burgess
> Sent: Monday, February 1, 2021 1:05 PM
> To: gdb-patches@sourceware.org; binutils@sourceware.org
> Cc: Fredrik Hederstierna <fredrik@hederstierna.com>
> Subject: PING: Re: [PATCHv2 2/9] bfd/binutils: support for gdb target
> descriptions in the core file
> 
> Ping!
> 
> This patch needs a review from the binutils side please.
> 
> I believe the conversation with Mihails was resolved and he is happy with this
> patch as it is.

Correct, no objections from me.

BR,
Mihails
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 5/9] gdb/riscv: introduce bare metal core dump support
  2021-02-01 14:05   ` Luis Machado
@ 2021-02-03  3:04     ` Palmer Dabbelt
  0 siblings, 0 replies; 57+ messages in thread
From: Palmer Dabbelt @ 2021-02-03  3:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: andrew.burgess, gdb-patches, binutils, fredrik

On Mon, 01 Feb 2021 06:05:51 PST (-0800), gdb-patches@sourceware.org wrote:
> Andrew,
>
> On 1/20/21 5:23 PM, Andrew Burgess wrote:
>> The commit message below includes a description of the core file
>> format.  Though this description could exist in the commit message, I
>> don't imagine this is really the right place to document something
>> like this.
>
> Thanks for writing this down.
>
>>
>> For RISC-V I imagine the correct place would be here:
>>
>>    https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md
>>
>> And I have a commit for this repository that replicates the
>> description below.  However, I wanted to post this to the binutils/gdb
>> list first, and see if this description was good enough for all
>> stakeholders.
>>
>> If people here are happy with this commit and the documentation, then
>> I would image creating a pull request against the RISC-V ABI document,
>> and then if there's no negative feedback, merge this patch at that
>> point.
>>
>> All feedback, on docs or implementation, is welcome,

Thanks, this is great.  I have some minor comments in line, but regardless the 
psABI is probably the right place to put this sort of thing as it'll be more 
visible than just having it in GDB (though having it here seems fine as well).

>>
>> Thanks,
>> Andrew
>>
>>
>>
>>
>>
>> ----
>>
>> This commit adds the ability for bare metal RISC-V target to generate
>> core files from within GDB.
>>
>> The intended use case is that a user will connect to a remote bare
>> metal target, debug up to some error condition, then generate a core
>> file in the normal way using:
>>
>>    (gdb) generate-core-file
>>
>> This core file can then be used to revisit the state of the remote
>> target without having to reconnect to the remote target.
>>
>> The core file creation code is split between two new files.  In
>> none-tdep.c is code designed to support the architecture agnostic
>> parts of a bare metal core dump.
>>
>> In riscv-none-tdep.c are the RISC-V specific parts, this is where the
>> regset and regcache_map_entry structures are defined that control how
>> registers are laid out in the core file.
>>
>> Currently for RISC-V only the x-regs and f-regs (if present) are
>> written out.  In future commits I plan to add support for writing out
>> the RISC-V CSRs.
>>
>> The cores dump format is based around generating an ELF containing
>
> cores -> core
>
>> sections for the writable regions of memory that a user could be
>> using.  Which regions are dumped rely on GDB's existing common core
>> dumping code, GDB will attempt to figure out the stack and heap as
>> well as copying out writable data sections as identified by the
>> original ELF.
>>
>> Register information is added to the core dump using notes, just as it
>> is for Linux of FreeBSD core dumps.  The note types used consist of
>> the 3 basic types you would expect in a OS based core dump,
>> NT_PRPSINFO, NT_PRSTATUS, NT_FPREGSET.
>>
>> The layout of these notes differs slightly (due to field sizes)
>> between RV32 and RV64.  Below I describe the data layout for each
>> note.  In all case, all padding fields should be set to zero.

I always find "should" kind of mushy, if we're really saying this is reserved 
for future use by debuggers then we should just be explicit about that.

>
> case -> cases
>
>>
>> Note NT_PRPSINFO is optional.  Its data layout is:
>>
>>    struct prpsinfo32_t		/* For RV32.  */
>>    {
>>      uint8_t padding[32];
>>      char fname[16];
>>      char psargs[80];
>>    }
>>
>>    struct prpsinfo64_t		/* For RV64.  */
>>    {
>>      uint8_t padding[40];
>>      char fname[16];
>>      char psargs[80];
>>    }
>>
>> Field 'fname' - null terminated string consisting of the basename of
>>      (up to the fist 15 characters of) the executable.  Any additional
>>      space should be set to zero.  If there's no executable name then
>>      this field can be set to all zero.
>>
>> Field 'psargs' - a null terminated string up to 80 characters in
>>      length.  Any additional space should be filled with zero.  This
>>      field contains the full executable path and any arguments passed
>>      to the executable.  If there's nothing sensible to write in this
>>      field then fill it with zero.
>>
>> Note NT_PRSTATUS is required, its data layout is:
>>
>>    struct prstatus32_t		/* For RV32.  */
>>    {
>>      uint8_t padding_1[12];
>>      uint16_t sig;
>>      uint8_t padding_2[10];
>>      uint32_t thread_id;
>>      uint8_t padding_3[44];
>>      uint32_t x_regs[32];
>>      uint8_t padding_4[4];
>>    }
>>
>>    struct prstatus64_t		/* For RV64.  */
>>    {
>>      uint8_t padding_1[12];
>>      uint16_t sig;
>>      uint8_t padding_2[18];
>>      uint32_t thread_id;
>>      uint8_t padding_3[76];
>>      uint64_t x_regs[32];
>>      uint8_t padding_4[4];
>>    }
>>
>> Field 'sig' - the signal that stopped this thread.  Its implementation
>
> Its -> It's
>
>>      defined what this field actually means.  Within GDB this will be
>>      the signal number that the remote target reports as the stop
>>      reason for this thread.
>>
>> Field 'thread_is' - the thread id for this thread, its implementation
>
> its -> it's

IIUC "it's" means "it is", and "its" is the possessive of "it".  So "its" is 
correct here.

>
>>      defined what this field actually means.  Within GDB this will be
>>      thread thread-id that is assigned to each remote thread.
>>
>> Field 'x_regs' - at index 0 we store the program counter, and at
>>      indices 1 to 31 we store x-registers 1 to 31.  x-register 0 is not
>>      stored, its value is always zero anyway.
>>
>> Note NT_FPREGSET is optional, its data layout is:
>>
>>    fpregset32_t			/* For targets with 'F' extension.  */
>>    {
>>      uint32_t f_regs[32];
>>      uint32_t fcsr;
>>    }
>>
>>    fpregset64_t			/* For targets with 'D' extension .  */
>>    {
>>      uint64_t f_regs[32];
>>      uint32_t fcsr;
>>    }
>>
>> Field 'f_regs' - stores f-registers 0 to 31.
>>
>> Field 'fcsr' - stores the fcsr CSR register, and is always 4-bytes.
>>
>> The rules for ordering the notes is the same as for Linux.  The
>> NT_PRSTATUS note must come before any other notes about additional
>> register sets.  And for multi-threaded targets all registers for a
>> single thread should be grouped together.  This is because only
>> NT_PRSTATUS includes a thread-id, all additional register notes after
>> a NT_PRSTATUS are assumed to belong to the same thread until a
>> different NT_PRSTATUS is seen.
>
> I think the above documentation is a good start, and we can expand it
> with more information.
>
> I'm wondering if we should document this in the GDB manual. Then again,
> it may be a bit too technical for the user manual.
>
> Another idea is to document arch-specific bits in arch-specific files
> and the generic parts in the none-tdep.c file?
>
>>
>> gdb/ChangeLog:
>>
>> 	* Makefile.in (ALL_TARGET_OBS): Add riscv-none-tdep.o.
>> 	(ALLDEPFILES): Add riscv-none-tdep.c.
>> 	* configure.tgt (riscv*-*-*): Include riscv-none-tdep.c.
>> 	* none-tdep.c: New file.
>> 	* none-tdep.h: New file.
>> 	* riscv-none-tdep.c: New file.
>> ---
>>   gdb/ChangeLog         |  10 ++++
>>   gdb/Makefile.in       |   4 ++
>>   gdb/configure.tgt     |   2 +-
>>   gdb/none-tdep.c       | 119 ++++++++++++++++++++++++++++++++++++++++++
>>   gdb/none-tdep.h       |  30 +++++++++++
>>   gdb/riscv-none-tdep.c | 108 ++++++++++++++++++++++++++++++++++++++
>>   6 files changed, 272 insertions(+), 1 deletion(-)
>>   create mode 100644 gdb/none-tdep.c
>>   create mode 100644 gdb/none-tdep.h
>>   create mode 100644 gdb/riscv-none-tdep.c
>>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 9267bea7beb..5f88b6a78cf 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -807,6 +807,7 @@ ALL_TARGET_OBS = \
>>   	ravenscar-thread.o \
>>   	riscv-fbsd-tdep.o \
>>   	riscv-linux-tdep.o \
>> +	riscv-none-tdep.o \
>>   	riscv-ravenscar-thread.o \
>>   	riscv-tdep.o \
>>   	rl78-tdep.o \
>> @@ -1100,6 +1101,7 @@ COMMON_SFILES = \
>>   	minsyms.c \
>>   	mipsread.c \
>>   	namespace.c \
>> +	none-tdep.c \
>>   	objc-lang.c \
>>   	objfiles.c \
>>   	observable.c \
>> @@ -1360,6 +1362,7 @@ HFILES_NO_SRCDIR = \
>>   	netbsd-tdep.h \
>>   	nds32-tdep.h \
>>   	nios2-tdep.h \
>> +	none-tdep.h \
>>   	nto-tdep.h \
>>   	objc-lang.h \
>>   	objfiles.h \
>> @@ -2271,6 +2274,7 @@ ALLDEPFILES = \
>>   	riscv-fbsd-tdep.c \
>>   	riscv-linux-nat.c \
>>   	riscv-linux-tdep.c \
>> +	riscv-none-tdep.c \
>>   	riscv-ravenscar-thread.c \
>>   	riscv-tdep.c \
>>   	rl78-tdep.c \
>> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
>> index 6e039838748..ad88ddd9302 100644
>> --- a/gdb/configure.tgt
>> +++ b/gdb/configure.tgt
>> @@ -85,7 +85,7 @@ ia64*-*-*)
>>   	;;
>>
>>   riscv*-*-*)
>> -	cpu_obs="riscv-tdep.o arch/riscv.o \
>> +	cpu_obs="riscv-tdep.o riscv-none-tdep.o arch/riscv.o \
>>   	         ravenscar-thread.o riscv-ravenscar-thread.o";;
>>
>>   x86_64-*-*)
>> diff --git a/gdb/none-tdep.c b/gdb/none-tdep.c
>> new file mode 100644
>> index 00000000000..8ec2407ad45
>> --- /dev/null
>> +++ b/gdb/none-tdep.c
>> @@ -0,0 +1,119 @@
>> +/* Target-dependent code for none, architecture independent.
>> +
>> +   Copyright (C) 2020 Free Software Foundation, Inc.
>
> 2020~2021 now I think.
>
>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>> +
>> +#include "defs.h"
>> +#include "none-tdep.h"
>> +#include "regset.h"
>> +#include "elf-bfd.h"            /* for elfcore_write_* */
>> +#include "inferior.h"
>> +#include "regcache.h"
>> +#include "gdbarch.h"
>> +#include "gcore.h"
>> +
>> +/* Build the note section for a corefile, and return it in a malloc
>> +   buffer.  Currently this just  dumps all available registers for each
>
> Spurious whitespace in "just  dumps"
>
>> +   thread.  */
>> +
>> +static gdb::unique_xmalloc_ptr<char>
>> +none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
>> +{
>> +  gdb::unique_xmalloc_ptr<char> note_data;
>> +
>> +  /* Add note information about the executable and its arguments.  */
>> +  std::string fname;
>> +  std::string psargs;
>> +  static const size_t fname_len = 16;
>> +  static const size_t psargs_len = 80;
>> +  if (get_exec_file (0))
>> +    {
>> +      const char *exe = get_exec_file (0);
>> +      fname = lbasename (exe);
>> +      psargs = std::string (exe);
>> +
>> +      const char *infargs = get_inferior_args ();
>> +      if (infargs != nullptr)
>> +	psargs += " " + std::string (infargs);
>> +
>> +      /* All existing targets that handling writing out prpsinfo expect the
>
> handling -> handle
>
>> +	 fname and psargs strings to be at least 16 and 80 characters long
>> +	 respectively, including a null terminator at the end.  Resize to
>> +	 the expected length minus one to ensure there is a null within the
>> +	 required length.  */
>> +      fname.resize (fname_len - 1);
>> +      psargs.resize (psargs_len - 1);
>> +    }
>> +
>> +  /* Resize the buffers up to their required lengths.  This will fill any
>> +     remaining space with the null character.  */
>> +  fname.resize (fname_len);
>> +  psargs.resize (psargs_len);
>> +
>> +  /* Now write out the prpsinfo structure.  */
>> +  note_data.reset (elfcore_write_prpsinfo (obfd, note_data.release (),
>> +					   note_size, fname.c_str (),
>> +					   psargs.c_str ()));
>> +  if (note_data == nullptr)
>> +    return nullptr;
>> +
>> +  /* Thread register information.  */
>> +  try
>> +    {
>> +      update_thread_list ();
>> +    }
>> +  catch (const gdb_exception_error &e)
>> +    {
>> +      exception_print (gdb_stderr, e);
>> +    }
>> +
>> +  /* Like the Linux 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 ();
>> +
>> +  /* All threads are reported as having been stopped by the same signal
>> +     that stopped SIGNALLED_THR.  */
>> +  gdb_signal stop_signal;
>> +  if (signalled_thr != nullptr)
>> +    stop_signal = signalled_thr->suspend.stop_signal;
>> +  else
>> +    stop_signal = GDB_SIGNAL_0;
>> +
>> +  if (signalled_thr != nullptr)
>> +    gcore_build_thread_register_notes (gdbarch, signalled_thr,
>> +				       stop_signal, obfd, &note_data,
>> +				       note_size);
>> +  for (thread_info *thr : current_inferior ()->non_exited_threads ())
>> +    {
>> +      if (thr == signalled_thr)
>> +	continue;
>> +
>> +      gcore_build_thread_register_notes (gdbarch, thr, stop_signal, obfd,
>> +					 &note_data, note_size);
>> +    }
>> +
>> +  return note_data;
>> +}
>> +
>> +/* See none-tdep.h.  */
>> +
>> +void
>> +none_init_abi (struct gdbarch *gdbarch)
>> +{
>> +  /* Default core file support.  */
>> +  set_gdbarch_make_corefile_notes (gdbarch, none_make_corefile_notes);
>> +}
>> diff --git a/gdb/none-tdep.h b/gdb/none-tdep.h
>> new file mode 100644
>> index 00000000000..46dcfe219ef
>> --- /dev/null
>> +++ b/gdb/none-tdep.h
>> @@ -0,0 +1,30 @@
>> +/* Architecture independent code for ABI 'none' (bare-metal).
>> +
>> +   Copyright (C) 2021 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>> +
>> +#ifndef NONE_TDEP_H
>> +#define NONE_TDEP_H
>> +
>> +struct gdbarch;
>> +
>> +/* Initialize support for cross-architecture features applicable for the
>> +   GDB_OSABI_NONE ABI, that is bare-metal targets.  */
>> +
>> +void none_init_abi (struct gdbarch *gdbarch);
>> +
>> +#endif /* NONE_TDEP_H */
>> diff --git a/gdb/riscv-none-tdep.c b/gdb/riscv-none-tdep.c
>> new file mode 100644
>> index 00000000000..e06ee0981fe
>> --- /dev/null
>> +++ b/gdb/riscv-none-tdep.c
>> @@ -0,0 +1,108 @@
>> +/* Copyright (C) 2020 Free Software Foundation, Inc.
>
> 2020~2021 now.
>
>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>> +
>> +/* This file contain code that is specific for bare-metal RISC-V targets.  */
>> +
>> +#include "defs.h"
>> +#include "arch-utils.h"
>> +#include "regcache.h"
>> +#include "riscv-tdep.h"
>> +#include "elf-bfd.h"
>> +#include "regset.h"
>> +#include "none-tdep.h"
>> +
>> +/* Define the general register mapping.  This follows the same format as
>> +   the RISC-V linux corefile.  The linux kernel puts the PC at offset 0,
>> +   gdb puts it at offset 32.  Register x0 is always 0 and can be ignored.
>> +   Registers x1 to x31 are in the same place.  */
>> +
>> +static const struct regcache_map_entry riscv_gregmap[] =
>> +{
>> +  { 1,  RISCV_PC_REGNUM, 0 },
>> +  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
>> +  { 0 }
>> +};
>> +
>> +/* Define the FP register mapping.  This follows the same format as the
>> +   RISC-V linux corefile.  The kernel puts the 32 FP regs first, and then
>> +   FCSR.  */
>> +
>> +static const struct regcache_map_entry riscv_fregmap[] =
>> +{
>> +  { 32, RISCV_FIRST_FP_REGNUM, 0 },
>> +  { 1, RISCV_CSR_FCSR_REGNUM, 4 },	/* Always stored as 4-bytes.  */
>> +  { 0 }
>> +};
>> +
>> +/* Define the general register regset.  */
>> +
>> +static const struct regset riscv_gregset =
>> +{
>> +  riscv_gregmap, riscv_supply_regset, regcache_collect_regset
>> +};
>> +
>> +/* Define the FP register regset.  */
>> +
>> +static const struct regset riscv_fregset =
>> +{
>> +  riscv_fregmap, riscv_supply_regset, regcache_collect_regset
>> +};
>> +
>> +/* Implement the "iterate_over_regset_sections" gdbarch method.  */
>> +
>> +static void
>> +riscv_iterate_over_regset_sections (struct gdbarch *gdbarch,
>> +				    iterate_over_regset_sections_cb *cb,
>> +				    void *cb_data,
>> +				    const struct regcache *regcache)
>> +{
>> +  /* Write out the GPRs.  */
>> +  int sz = 32 * riscv_isa_xlen (gdbarch);
>> +  cb (".reg", sz, sz, &riscv_gregset, NULL, cb_data);
>> +
>> +  /* Write out the FPRs, but only if present.  */
>> +  if (riscv_isa_flen (gdbarch) > 0)
>> +    {
>> +      sz = (32 * riscv_isa_flen (gdbarch)
>> +	    + register_size (gdbarch, RISCV_CSR_FCSR_REGNUM));
>> +      cb (".reg2", sz, sz, &riscv_fregset, NULL, cb_data);
>> +    }
>> +}
>> +
>> +/* Initialize RISC-V bare-metal ABI info.  */
>> +
>> +static void
>> +riscv_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>> +{
>> +  none_init_abi (gdbarch);
>> +
>> +  /* Iterate over registers for reading and writing bare metal RISC-V core
>> +     files.  */
>> +  set_gdbarch_iterate_over_regset_sections
>> +    (gdbarch, riscv_iterate_over_regset_sections);
>> +
>> +}
>> +
>> +/* Initialize RISC-V bare-metal target support.  */
>> +
>> +void _initialize_riscv_none_tdep ();
>> +void
>> +_initialize_riscv_none_tdep ()
>> +{
>> +  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_NONE,
>> +			  riscv_none_init_abi);
>> +}
>>
>
> Otherwise this looks good to me.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code
  2021-02-01 11:56   ` Andrew Burgess
@ 2021-02-09 21:52     ` Andrew Burgess
  0 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-09 21:52 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna

* Andrew Burgess <andrew.burgess@embecosm.com> [2021-02-01 11:56:00 +0000]:

> I have pushed this patch only so far as this is a nice clean up in its
> own right.

I have now reverted this patch due to the regressions it introduced,
see here:

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

I still plan to bring this patch back as soon as I have a good
solution - I just don't have one immediately, hence the revert.

Any suggestions for good solutions will be appreciated :)

Thanks,
Andrew

---

commit 03642b7189bc0bfdf61354a6d9a3f3e46d82709c
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Tue Feb 9 21:41:30 2021 +0000

    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.

diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index edd3edc4220..cc51e921ae2 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -32,7 +32,6 @@
 
 #include "elf-bfd.h"
 #include "fbsd-tdep.h"
-#include "gcore.h"
 
 /* This enum is derived from FreeBSD's <sys/signal.h>.  */
 
@@ -584,6 +583,129 @@ find_signalled_thread (struct thread_info *info, void *data)
   return 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
+{
+  fbsd_collect_regset_section_cb_data (const struct regcache *regcache,
+				       bfd *obfd,
+				       gdb::unique_xmalloc_ptr<char> &note_data,
+				       int *note_size,
+				       unsigned long lwp,
+				       gdb_signal stop_signal)
+    : regcache (regcache),
+      obfd (obfd),
+      note_data (note_data),
+      note_size (note_size),
+      lwp (lwp),
+      stop_signal (stop_signal)
+  {}
+
+  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;
+};
+
+static void
+fbsd_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)
+{
+  char *buf;
+  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 (collect_size);
+  regset->collect_regset (regset, data->regcache, -1, buf, 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));
+  else
+    data->note_data.reset (elfcore_write_register_note
+			     (data->obfd, data->note_data.release (),
+			      data->note_size, sect_name, buf,
+			      collect_size));
+  xfree (buf);
+
+  if (data->note_data == NULL)
+    data->abort_iteration = true;
+}
+
+/* Records the thread's register state for the corefile note
+   section.  */
+
+static void
+fbsd_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)
+{
+  fbsd_collect_regset_section_cb_data data (regcache, obfd, note_data,
+					    note_size, ptid.lwp (),
+					    stop_signal);
+
+  gdbarch_iterate_over_regset_sections (regcache->arch (),
+					fbsd_collect_regset_section_cb,
+					&data, regcache);
+}
+
+struct fbsd_corefile_thread_data
+{
+  fbsd_corefile_thread_data (struct gdbarch *gdbarch,
+			     bfd *obfd,
+			     gdb::unique_xmalloc_ptr<char> &note_data,
+			     int *note_size,
+			     gdb_signal stop_signal)
+    : gdbarch (gdbarch),
+      obfd (obfd),
+      note_data (note_data),
+      note_size (note_size),
+      stop_signal (stop_signal)
+  {}
+
+  struct gdbarch *gdbarch;
+  bfd *obfd;
+  gdb::unique_xmalloc_ptr<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 regcache *regcache;
+
+  regcache = get_thread_arch_regcache (info->inf->process_target (),
+				       info->ptid, args->gdbarch);
+
+  target_fetch_registers (regcache, -1);
+
+  fbsd_collect_thread_registers (regcache, info->ptid, args->obfd,
+				 args->note_data, args->note_size,
+				 args->stop_signal);
+}
+
 /* Return a byte_vector containing the contents of a core dump note
    for the target object of type OBJECT.  If STRUCTSIZE is non-zero,
    the data is prefixed with a 32-bit integer size to match the format
@@ -660,17 +782,16 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
 	signalled_thr = curr_thr;
     }
 
-  gcore_build_thread_register_notes (gdbarch, signalled_thr,
-				     signalled_thr->suspend.stop_signal,
-				     obfd, &note_data, note_size);
+  fbsd_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
+					 signalled_thr->suspend.stop_signal);
+
+  fbsd_corefile_thread (signalled_thr, &thread_args);
   for (thread_info *thr : current_inferior ()->non_exited_threads ())
     {
       if (thr == signalled_thr)
 	continue;
 
-      gcore_build_thread_register_notes (gdbarch, thr,
-					 signalled_thr->suspend.stop_signal,
-					 obfd, &note_data, note_size);
+      fbsd_corefile_thread (thr, &thread_args);
     }
 
   /* Auxiliary vector.  */
diff --git a/gdb/gcore.c b/gdb/gcore.c
index d62aa3a7109..73ac6b09c70 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -579,142 +579,6 @@ gcore_memory_sections (bfd *obfd)
   return 1;
 }
 
-/* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS
-   via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */
-
-struct gcore_collect_regset_section_cb_data
-{
-  gcore_collect_regset_section_cb_data (struct gdbarch *gdbarch,
-					const struct regcache *regcache,
-					bfd *obfd, ptid_t ptid,
-					gdb_signal stop_signal,
-					gdb::unique_xmalloc_ptr<char> *note_data,
-					int *note_size)
-
-    : gdbarch (gdbarch), regcache (regcache), obfd (obfd),
-      note_data (note_data), note_size (note_size),
-      stop_signal (stop_signal)
-  {
-    /* The LWP is often not available for bare metal target, in which case
-       use the tid instead.  */
-    if (ptid.lwp_p ())
-      lwp = ptid.lwp ();
-    else
-      lwp = ptid.tid ();
-  }
-
-  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 core file note section.  */
-
-static void
-gcore_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 gcore_collect_regset_section_cb_data *data
-    = (struct gcore_collect_regset_section_cb_data *) cb_data;
-  bool variable_size_section = (regset != NULL
-				&& regset->flags & REGSET_VARIABLE_SIZE);
-
-  gdb_assert (variable_size_section || supply_size == collect_size);
-
-  if (data->abort_iteration)
-    return;
-
-  gdb_assert (regset != nullptr && regset->collect_regset != nullptr);
-
-  /* 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 == nullptr)
-    data->abort_iteration = true;
-}
-
-/* Records the register state of thread PTID out of REGCACHE into the note
-   buffer represented by *NOTE_DATA and NOTE_SIZE.  OBFD is the bfd into
-   which the core file is being created, and STOP_SIGNAL is the signal that
-   cause thread PTID to stop.  */
-
-static void
-gcore_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 ();
-  gcore_collect_regset_section_cb_data data (gdbarch, regcache, obfd, ptid,
-					     stop_signal, note_data,
-					     note_size);
-  gdbarch_iterate_over_regset_sections (gdbarch,
-					gcore_collect_regset_section_cb,
-					&data, regcache);
-}
-
-/* See gcore.h.  */
-
-void
-gcore_build_thread_register_notes
-  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
-   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
-{
-  struct regcache *regcache
-    = get_thread_arch_regcache (info->inf->process_target (),
-				info->ptid, gdbarch);
-  target_fetch_registers (regcache, -1);
-  gcore_collect_thread_registers (regcache, info->ptid, obfd, note_data,
-				  note_size, stop_signal);
-}
-
-/* See gcore.h.  */
-
-thread_info *
-gcore_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;
-}
-
 void _initialize_gcore ();
 void
 _initialize_gcore ()
diff --git a/gdb/gcore.h b/gdb/gcore.h
index ce60841c1a5..af37ff39b41 100644
--- a/gdb/gcore.h
+++ b/gdb/gcore.h
@@ -21,10 +21,6 @@
 #define GCORE_H 1
 
 #include "gdb_bfd.h"
-#include "gdbsupport/gdb_signals.h"
-
-struct gdbarch;
-struct thread_info;
 
 extern gdb_bfd_ref_ptr create_gcore_bfd (const char *filename);
 extern void write_gcore_file (bfd *obfd);
@@ -32,20 +28,4 @@ extern int objfile_find_memory_regions (struct target_ops *self,
 					find_memory_region_ftype func,
 					void *obfd);
 
-/* Add content to *NOTE_DATA (and update *NOTE_SIZE) to describe the
-   registers of thread INFO.  Report the thread as having stopped with
-   STOP_SIGNAL.  The core file is being written to OFD, and GDBARCH is the
-   architecture for which the core file is being generated.  */
-
-extern void gcore_build_thread_register_notes
-  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
-   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size);
-
-/* 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.  */
-
-extern thread_info *gcore_find_signalled_thread ();
-
 #endif /* GCORE_H */
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;

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-01-20 20:23 ` [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
                     ` (2 preceding siblings ...)
  2021-02-01 13:29   ` Luis Machado
@ 2021-02-10 20:45   ` Jim Wilson
  3 siblings, 0 replies; 57+ messages in thread
From: Jim Wilson @ 2021-02-10 20:45 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Binutils, Fredrik Hederstierna

On Wed, Jan 20, 2021 at 12:23 PM Andrew Burgess <andrew.burgess@embecosm.com>
wrote:

> bfd/ChangeLog:
>
>         * elf-bfd.h (elfcore_write_gdb_tdesc): Declare new function.
>         * elf.c (elfcore_grok_gdb_tdesc): New function.
>         (elfcore_grok_note): Handle NT_GDB_TDESC.
>         (elfcore_write_gdb_tdesc): New function.
>         (elfcore_write_register_note): Handle NT_GDB_TDESC.
>
> binutils/ChangeLog:
>
>         * readelf.c (get_note_type): Handle NT_GDB_TDESC.
>
> include/ChangeLog:
>
>         * elf/common.h (NT_GDB_TDESC): Define.
>

This looks OK.

Technically, new functions are supposed to have explanatory comments before
them, but there are others missing comments.  If you could add the missing
comments to the new functions in your patch that would be nice.

Jim

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation
  2021-01-20 20:23 ` [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
  2021-02-01 12:03   ` PING: " Andrew Burgess
  2021-02-01 13:48   ` Luis Machado
@ 2021-02-10 20:57   ` Jim Wilson
  2 siblings, 0 replies; 57+ messages in thread
From: Jim Wilson @ 2021-02-10 20:57 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Binutils, Fredrik Hederstierna

On Wed, Jan 20, 2021 at 12:24 PM Andrew Burgess <andrew.burgess@embecosm.com>
wrote:

> bfd/ChangeLog:
>
>         * elfnn-riscv.c (riscv_write_core_note): New function.
>         (elf_backend_write_core_note): Define.
>

This looks OK.

In the PRPSINFO code you are using hardwired constants in the strncpy
calls.  Maybe you can compute them from macros instead to make sure that we
don't end up with problems later if type sizes change?

>
> +       strncpy (data + PRPSINFO_OFFSET_PR_FNAME, va_arg (ap, const char
> *), 16);
>

Maybe the 16 can be PRPSINFO_OFFSET_PR_PID.

>
> +       strncpy (data + PRPSINFO_OFFSET_PR_PSARGS, va_arg (ap, const char
> *), 80);
>
Maybe  the 80 can be PRPSINFO_SIZE - PRPSINFO_OFFSET_PR_PSARGS.

it looks like you already did something similar with the memcpy call in the
PRSTATUS code so that looks OK.

Jim

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv2 6/9] bfd/binutils: add support for RISC-V CSRs in core files
  2021-02-01 12:00   ` Andrew Burgess
  2021-02-01 14:08     ` Luis Machado
@ 2021-02-10 21:00     ` Jim Wilson
  1 sibling, 0 replies; 57+ messages in thread
From: Jim Wilson @ 2021-02-10 21:00 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Binutils, Fredrik Hederstierna

On Mon, Feb 1, 2021 at 4:00 AM Andrew Burgess <andrew.burgess@embecosm.com>
wrote:

>     bfd/ChangeLog:
>
>             * elf-bfd.h (elfcore_write_riscv_csr): Declare.
>             * elf.c (elfcore_grok_riscv_csr): New function.
>             (elfcore_grok_note): Handle NT_RISCV_CSR.
>             (elfcore_write_riscv_csr): New function.
>             (elfcore_write_register_note): Handle '.reg-riscv-csr'.
>
>     binutils/ChangeLog:
>
>             * readelf.c (get_note_type): Handle NT_RISCV_CSR.
>
>     include/ChangeLog:
>
>             * elf/common.h (NT_RISCV_CSR): Define.
>
> Looks OK to me.

As before, ideally new functions should have explanatory comments before
them, unless maybe that rule has changed.

Jim

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 0/9] Bare-metal core dumps for RISC-V
  2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
                   ` (9 preceding siblings ...)
  2021-01-22 19:28 ` [PATCHv2 0/9] Bare-metal core dumps for RISC-V Tom Tromey
@ 2021-02-15 17:29 ` Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
                     ` (9 more replies)
  10 siblings, 10 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

After I pushed patch #1 from the v2 series it was pointed out that
this broke any build of GDB for non-ELF targets.  I then reverted
patch #1.  Now I'm back with an updated series.

For testing the build I have been using 'x86_64-apple-darwin20.3.0' as
a non-ELF target.  I haven't done any actual functional testing on
this target other than "it builds", but that's more than I did before
(for non-ELF targets).

Between v2 and v3 then the changes are basically around the idea of
not calling ELF specific functions from any generic code.  As far as
possible I wanted to avoid just blocking code out with #ifdef, though
I did use this trick in a limited way in patches #5 and #9, hopefully
this is acceptable, though I'm open to suggestions for better ways to
structure the code in these patches.

Here's a summary of which patches have changed:

(1) - Changed, common code from Linux and FreeBSD targets is now split
      between gcore.c (for non-ELF code) and a new file gcore-elf.c
      (for ELF specific code).  Changes to configure.ac ensure the ELF
      specific file is only pulled in when needed.  This probably
      needs a new review.

(2) - Minor updates to address Jim's review feedback.  Reviews are
      welcome, but I'm considering this patch approved.

(3) - Code to add the target description note is moved to gcore-elf.c,
      and each target must call this code (if the target is creating
      an ELF based core file).  I don't like this as much as the
      previous code where the target description note was added in one
      place, but I can't see a good way to do this without adding a
      #ifdef block to gcore.c.  This probably needs a new review.

(4) - Minor updates to address Jim's review feedback.  Reviews are
      welcome, but I'm considering this patch approved.

(5) - The common bare metal core dump code is now in elf-none-tdep.c.
      This is then called from the riscv-none-tdep.c code ONLY if we
      have ELF support.  This is the use of '#ifdef HAVE_ELF' which is
      a little yuck, but I can't see a better solution.  This probably
      needs a new review.

(6) - Minor updates to address Jim's review feedback.  Reviews are
      welcome, but I'm considering this patch approved.

(7) - No changes.  Reviews are welcome, but I'm considering this patch
      approved.

(8) - No changes.  Reviews are welcome, but I'm considering this patch
      approved.

(9) - No significant changes.  Like patch #5 it now includes a '#ifdef
      HAVE_ELF' block in order to guard the call from arm-none-tdep.c
      to elf-none-tdep.c.  I'd prefer reviews of this approach be
      addressed to patch #5, I'll apply any feedback I get there to
      this patch too.

---

Andrew Burgess (9):
  gdb: unify parts of the Linux and FreeBSD core dumping code
  bfd/binutils: support for gdb target descriptions in the core file
  gdb: write target description into core file
  bfd/riscv: prepare to handle bare metal core dump creation
  gdb/riscv: introduce bare metal core dump support
  bfd/binutils: add support for RISC-V CSRs in core files
  gdb/riscv: make riscv target description names global
  gdb/riscv: write CSRs into baremetal core dumps
  gdb/arm: add support for bare-metal core dumps

 bfd/ChangeLog         |  27 ++++++
 bfd/elf-bfd.h         |   4 +
 bfd/elf.c             |  70 ++++++++++++++
 bfd/elfnn-riscv.c     |  84 ++++++++++++++++-
 binutils/ChangeLog    |  10 ++
 binutils/readelf.c    |   4 +
 gdb/ChangeLog         |  88 +++++++++++++++++
 gdb/Makefile.in       |   8 ++
 gdb/arm-none-tdep.c   | 213 ++++++++++++++++++++++++++++++++++++++++++
 gdb/configure         |   3 +-
 gdb/configure.ac      |   3 +-
 gdb/configure.tgt     |   5 +-
 gdb/corelow.c         |  24 +++++
 gdb/elf-none-tdep.c   | 126 +++++++++++++++++++++++++
 gdb/elf-none-tdep.h   |  30 ++++++
 gdb/fbsd-tdep.c       | 137 ++-------------------------
 gdb/gcore-elf.c       | 166 ++++++++++++++++++++++++++++++++
 gdb/gcore-elf.h       |  47 ++++++++++
 gdb/gcore.c           |  21 +++++
 gdb/gcore.h           |   9 ++
 gdb/linux-tdep.c      | 146 +++--------------------------
 gdb/riscv-none-tdep.c | 173 ++++++++++++++++++++++++++++++++++
 gdb/riscv-tdep.c      |  14 ++-
 gdb/riscv-tdep.h      |   3 +
 include/ChangeLog     |  10 ++
 include/elf/common.h  |   6 ++
 26 files changed, 1159 insertions(+), 272 deletions(-)
 create mode 100644 gdb/arm-none-tdep.c
 create mode 100644 gdb/elf-none-tdep.c
 create mode 100644 gdb/elf-none-tdep.h
 create mode 100644 gdb/gcore-elf.c
 create mode 100644 gdb/gcore-elf.h
 create mode 100644 gdb/riscv-none-tdep.c

-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-02-15 22:56     ` Lancelot SIX
  2021-02-15 17:29   ` [PATCHv3 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
                     ` (8 subsequent siblings)
  9 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

While reviewing the Linux and FreeBSD core dumping code within GDB for
another patch series, I noticed that the code that collects the
registers for each thread and writes these into ELF note format is
basically identical between Linux and FreeBSD.

This commit merges this code and moves it into a new file gcore-elf.c.

The function find_signalled_thread is moved from linux-tdep.c to
gcore.c despite not being shared.  A later commit will make use of
this function.

I did merge, and then revert a previous version of this patch (commit
82a1fd3a4935 for the original patch and 03642b7189bc for the revert).
The problem with the original patch is that it introduced a
unconditional dependency between GDB and some ELF specific functions
in the BFD library, e.g. elfcore_write_prstatus and
elfcore_write_register_note.  It was pointed out in this mailing list
post:

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

that this change was breaking any build of GDB for non-ELF targets.
To confirm this breakage, and to test this new version of GDB I
configured and built for the target x86_64-apple-darwin20.3.0.

Where the previous version of this patch placed all of the common code
into gcore.c, which is included in all builds of GDB, this new patch
only places non-ELF specific generic code (i.e. find_signalled_thread)
into gcore.c, the ELF specific code is put into the new gcore-elf.c
file, which is only included in GDB if BFD has ELF support.

The contents of gcore-elf.c are referenced unconditionally from
linux-tdep.c and fbsd-tdep.c, this is fine, we previously always
assumed that these two targets required ELF support, and we continue
to make that assumption after this patch; nothing has changed there.

With my previous version of this patch the darwin target mentioned
above failed to build, but with the new version, the target builds
fine.

There are a couple of minor changes to the FreeBSD target after this
commit, but I believe that these are changes for the better:

(1) For FreeBSD we always used to record the thread-id in the core
file by using ptid_t.lwp ().  In contrast the Linux code did this:

    /* For remote targets the LWP may not be available, so use the TID.  */
    long lwp = ptid.lwp ();
    if (lwp == 0)
      lwp = ptid.tid ();

Both target now do this:

    /* The LWP is often not available for bare metal target, in which case
       use the tid instead.  */
    if (ptid.lwp_p ())
      lwp = ptid.lwp ();
    else
      lwp = ptid.tid ();

Which is equivalent for Linux, but is a change for FreeBSD.  I think
that all this means is that in some cases where GDB might have
previously recorded a thread-id of 0 for each thread, we might now get
something more useful.

(2) When collecting the registers for Linux we collected into a zero
initialised buffer.  By contrast on FreeBSD the buffer is left
uninitialised.  In the new code the buffer is always zero initialised.
I suspect once the registers are copied into the buffer there's
probably no gaps left so this makes no difference, but if it does then
using zeros rather than random bits of GDB's memory is probably a good
thing.

Otherwise, there should be no other user visible changes after this
commit.

Tested this on x86-64/GNU-Linux and x86-64/FreeBSD-12.2 with no
regressions.

gdb/ChangeLog:

	* Makefile.in (SFILES): Add gcore-elf.c.
	(HFILES_NO_SRCDIR): Add gcore-elf.h
	* configure: Regenerate.
	* configure.ac: Add gcore-elf.o to CONFIG_OBS if we have ELF
	support.
	* fbsd-tdep.c: Add 'gcore-elf.h' include.
	(struct fbsd_collect_regset_section_cb_data): Delete.
	(fbsd_collect_regset_section_cb): Delete.
	(fbsd_collect_thread_registers): Delete.
	(struct fbsd_corefile_thread_data): Delete.
	(fbsd_corefile_thread): Delete.
	(fbsd_make_corefile_notes): Call
	gcore_elf_build_thread_register_notes instead of the now deleted
	FreeBSD code.
	* gcore-elf.c: New file, the content was moved here from
	linux-tdep.c, functions were renamed and given minor cleanup.
	* gcore-elf.h: New file.
	* gcore.c (gcore_find_signalled_thread): Moved here from
	linux-tdep.c and given a new name.  Minor cleanups.
	* gcore.h (gcore_find_signalled_thread): Declare.
	* linux-tdep.c: Add 'gcore.h' and 'gcore-elf.h' includes.
	(struct linux_collect_regset_section_cb_data): Delete.
	(linux_collect_regset_section_cb): Delete.
	(linux_collect_thread_registers): Delete.
	(linux_corefile_thread): Call
	gcore_elf_build_thread_register_notes.
	(find_signalled_thread): Delete.
	(linux_make_corefile_notes): Call gcore_find_signalled_thread.
---
 gdb/ChangeLog    |  31 ++++++++++
 gdb/Makefile.in  |   2 +
 gdb/configure    |   2 +-
 gdb/configure.ac |   2 +-
 gdb/fbsd-tdep.c  | 134 ++------------------------------------------
 gdb/gcore-elf.c  | 136 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/gcore-elf.h  |  39 +++++++++++++
 gdb/gcore.c      |  21 +++++++
 gdb/gcore.h      |   9 +++
 gdb/linux-tdep.c | 143 +++--------------------------------------------
 10 files changed, 255 insertions(+), 264 deletions(-)
 create mode 100644 gdb/gcore-elf.c
 create mode 100644 gdb/gcore-elf.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ae89b85eb56..cf5017e7f66 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1191,6 +1191,7 @@ SFILES = \
 	dtrace-probe.c \
 	elfread.c \
 	f-exp.y \
+	gcore-elf.c \
 	gdb.c \
 	go-exp.y \
 	m2-exp.y \
@@ -1292,6 +1293,7 @@ HFILES_NO_SRCDIR = \
 	frame-unwind.h \
 	frv-tdep.h \
 	ft32-tdep.h \
+	gcore-elf.h \
 	gcore.h \
 	gdb_bfd.h \
 	gdb_curses.h \
diff --git a/gdb/configure b/gdb/configure
index 51b4d1921c5..4707fd01174 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -17264,7 +17264,7 @@ $as_echo "$gdb_cv_var_elf" >&6; }
   LDFLAGS=$OLD_LDFLAGS
   LIBS=$OLD_LIBS
 if test "$gdb_cv_var_elf" = yes; then
-  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
+  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
 
 $as_echo "#define HAVE_ELF 1" >>confdefs.h
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 618c59166e4..db765af0577 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1882,7 +1882,7 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
 GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
                  [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
 if test "$gdb_cv_var_elf" = yes; then
-  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
+  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
   AC_DEFINE(HAVE_ELF, 1,
 	    [Define if ELF support should be included.])
   # -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index cc51e921ae2..dc4278cd644 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -32,6 +32,7 @@
 
 #include "elf-bfd.h"
 #include "fbsd-tdep.h"
+#include "gcore-elf.h"
 
 /* This enum is derived from FreeBSD's <sys/signal.h>.  */
 
@@ -583,129 +584,6 @@ find_signalled_thread (struct thread_info *info, void *data)
   return 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
-{
-  fbsd_collect_regset_section_cb_data (const struct regcache *regcache,
-				       bfd *obfd,
-				       gdb::unique_xmalloc_ptr<char> &note_data,
-				       int *note_size,
-				       unsigned long lwp,
-				       gdb_signal stop_signal)
-    : regcache (regcache),
-      obfd (obfd),
-      note_data (note_data),
-      note_size (note_size),
-      lwp (lwp),
-      stop_signal (stop_signal)
-  {}
-
-  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;
-};
-
-static void
-fbsd_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)
-{
-  char *buf;
-  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 (collect_size);
-  regset->collect_regset (regset, data->regcache, -1, buf, 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));
-  else
-    data->note_data.reset (elfcore_write_register_note
-			     (data->obfd, data->note_data.release (),
-			      data->note_size, sect_name, buf,
-			      collect_size));
-  xfree (buf);
-
-  if (data->note_data == NULL)
-    data->abort_iteration = true;
-}
-
-/* Records the thread's register state for the corefile note
-   section.  */
-
-static void
-fbsd_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)
-{
-  fbsd_collect_regset_section_cb_data data (regcache, obfd, note_data,
-					    note_size, ptid.lwp (),
-					    stop_signal);
-
-  gdbarch_iterate_over_regset_sections (regcache->arch (),
-					fbsd_collect_regset_section_cb,
-					&data, regcache);
-}
-
-struct fbsd_corefile_thread_data
-{
-  fbsd_corefile_thread_data (struct gdbarch *gdbarch,
-			     bfd *obfd,
-			     gdb::unique_xmalloc_ptr<char> &note_data,
-			     int *note_size,
-			     gdb_signal stop_signal)
-    : gdbarch (gdbarch),
-      obfd (obfd),
-      note_data (note_data),
-      note_size (note_size),
-      stop_signal (stop_signal)
-  {}
-
-  struct gdbarch *gdbarch;
-  bfd *obfd;
-  gdb::unique_xmalloc_ptr<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 regcache *regcache;
-
-  regcache = get_thread_arch_regcache (info->inf->process_target (),
-				       info->ptid, args->gdbarch);
-
-  target_fetch_registers (regcache, -1);
-
-  fbsd_collect_thread_registers (regcache, info->ptid, args->obfd,
-				 args->note_data, args->note_size,
-				 args->stop_signal);
-}
-
 /* Return a byte_vector containing the contents of a core dump note
    for the target object of type OBJECT.  If STRUCTSIZE is non-zero,
    the data is prefixed with a 32-bit integer size to match the format
@@ -782,16 +660,16 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
 	signalled_thr = curr_thr;
     }
 
-  fbsd_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
-					 signalled_thr->suspend.stop_signal);
-
-  fbsd_corefile_thread (signalled_thr, &thread_args);
+  enum gdb_signal stop_signal = signalled_thr->suspend.stop_signal;
+  gcore_elf_build_thread_register_notes (gdbarch, signalled_thr, stop_signal,
+					 obfd, &note_data, note_size);
   for (thread_info *thr : current_inferior ()->non_exited_threads ())
     {
       if (thr == signalled_thr)
 	continue;
 
-      fbsd_corefile_thread (thr, &thread_args);
+      gcore_elf_build_thread_register_notes (gdbarch, thr, stop_signal,
+					     obfd, &note_data, note_size);
     }
 
   /* Auxiliary vector.  */
diff --git a/gdb/gcore-elf.c b/gdb/gcore-elf.c
new file mode 100644
index 00000000000..ebc94277d35
--- /dev/null
+++ b/gdb/gcore-elf.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "gcore-elf.h"
+#include "elf-bfd.h"
+#include "target.h"
+#include "regcache.h"
+#include "gdbarch.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "regset.h"
+
+/* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS
+   via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */
+
+struct gcore_elf_collect_regset_section_cb_data
+{
+  gcore_elf_collect_regset_section_cb_data
+	(struct gdbarch *gdbarch, const struct regcache *regcache,
+	 bfd *obfd, ptid_t ptid, gdb_signal stop_signal,
+	 gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
+    : gdbarch (gdbarch), regcache (regcache), obfd (obfd),
+      note_data (note_data), note_size (note_size),
+      stop_signal (stop_signal)
+  {
+    /* The LWP is often not available for bare metal target, in which case
+       use the tid instead.  */
+    if (ptid.lwp_p ())
+      lwp = ptid.lwp ();
+    else
+      lwp = ptid.tid ();
+  }
+
+  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 core file note section.  */
+
+static void
+gcore_elf_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 gcore_elf_collect_regset_section_cb_data *data
+    = (struct gcore_elf_collect_regset_section_cb_data *) cb_data;
+  bool variable_size_section = (regset != NULL
+				&& regset->flags & REGSET_VARIABLE_SIZE);
+
+  gdb_assert (variable_size_section || supply_size == collect_size);
+
+  if (data->abort_iteration)
+    return;
+
+  gdb_assert (regset != nullptr && regset->collect_regset != nullptr);
+
+  /* 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 == nullptr)
+    data->abort_iteration = true;
+}
+
+/* Records the register state of thread PTID out of REGCACHE into the note
+   buffer represented by *NOTE_DATA and NOTE_SIZE.  OBFD is the bfd into
+   which the core file is being created, and STOP_SIGNAL is the signal that
+   cause thread PTID to stop.  */
+
+static void
+gcore_elf_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 ();
+  gcore_elf_collect_regset_section_cb_data data (gdbarch, regcache, obfd,
+						 ptid, stop_signal,
+						 note_data, note_size);
+  gdbarch_iterate_over_regset_sections
+    (gdbarch, gcore_elf_collect_regset_section_cb, &data, regcache);
+}
+
+/* See gcore-elf.h.  */
+
+void
+gcore_elf_build_thread_register_notes
+  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
+   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
+{
+  struct regcache *regcache
+    = get_thread_arch_regcache (info->inf->process_target (),
+				info->ptid, gdbarch);
+  target_fetch_registers (regcache, -1);
+  gcore_elf_collect_thread_registers (regcache, info->ptid, obfd,
+				      note_data, note_size, stop_signal);
+}
diff --git a/gdb/gcore-elf.h b/gdb/gcore-elf.h
new file mode 100644
index 00000000000..d667686adc7
--- /dev/null
+++ b/gdb/gcore-elf.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This file contains generic functions for writing ELF based core files.  */
+
+#if !defined (GCORE_ELF_H)
+#define GCORE_ELF_H 1
+
+#include "gdb_bfd.h"
+#include "gdbsupport/gdb_signals.h"
+#include "gcore.h"
+
+struct gdbarch;
+struct thread_info;
+
+/* Add content to *NOTE_DATA (and update *NOTE_SIZE) to describe the
+   registers of thread INFO.  Report the thread as having stopped with
+   STOP_SIGNAL.  The core file is being written to OBFD, and GDBARCH is the
+   architecture for which the core file is being generated.  */
+
+extern void gcore_elf_build_thread_register_notes
+  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
+   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size);
+
+#endif /* GCORE_ELF_H */
diff --git a/gdb/gcore.c b/gdb/gcore.c
index 73ac6b09c70..3b9025322f3 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -579,6 +579,27 @@ gcore_memory_sections (bfd *obfd)
   return 1;
 }
 
+/* See gcore.h.  */
+
+thread_info *
+gcore_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;
+}
+
 void _initialize_gcore ();
 void
 _initialize_gcore ()
diff --git a/gdb/gcore.h b/gdb/gcore.h
index af37ff39b41..7e8e316926b 100644
--- a/gdb/gcore.h
+++ b/gdb/gcore.h
@@ -22,10 +22,19 @@
 
 #include "gdb_bfd.h"
 
+struct thread_info;
+
 extern gdb_bfd_ref_ptr create_gcore_bfd (const char *filename);
 extern void write_gcore_file (bfd *obfd);
 extern int objfile_find_memory_regions (struct target_ops *self,
 					find_memory_region_ftype func,
 					void *obfd);
 
+/* 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.  */
+
+extern thread_info *gcore_find_signalled_thread ();
+
 #endif /* GCORE_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index e9f8e1b6133..5bfd82d1673 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -39,6 +39,8 @@
 #include "gdb_regex.h"
 #include "gdbsupport/enum-flags.h"
 #include "gdbsupport/gdb_optional.h"
+#include "gcore.h"
+#include "gcore-elf.h"
 
 #include <ctype.h>
 
@@ -1597,104 +1599,6 @@ 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.  */
@@ -1746,22 +1650,17 @@ static void
 linux_corefile_thread (struct thread_info *info,
 		       struct linux_corefile_thread_data *args)
 {
-  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);
+  gcore_elf_build_thread_register_notes (args->gdbarch, info,
+					 args->stop_signal,
+					 args->obfd, &args->note_data,
+					 args->note_size);
 
   /* 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 (),
@@ -1960,30 +1859,6 @@ 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.  */
 
@@ -2021,7 +1896,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 = find_signalled_thread ();
+  thread_info *signalled_thr = gcore_find_signalled_thread ();
   gdb_signal stop_signal;
   if (signalled_thr != nullptr)
     stop_signal = signalled_thr->suspend.stop_signal;
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 2/9] bfd/binutils: support for gdb target descriptions in the core file
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 3/9] gdb: write target description into " Andrew Burgess
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

This commit lays the ground work for allowing GDB to write its target
description into a generated core file.

The goal of this work is to allow a user to connect to a remote
target, capture a core file from within GDB, then pass the executable
and core file to another user and have the user be able to examine the
state of the machine without needing to connect to a running target.

Different remote targets can have different register sets and this
information is communicated from the target to GDB in the target
description.

It is possible for a user to extract the target description from GDB
and pass this along with the core file so that when the core file is
used the target description can be fed back into GDB, however this is
not a great user experience.

It would be nicer, I think, if GDB could write the target description
directly into the core file, and then make use of this description
when loading a core file.

This commit performs the binutils/bfd side of this task, adding the
boiler plate functions to access the target description from within a
core file note, and reserving a new number for a note containing the
target description.  Later commits will extend GDB to make use of
this.

The new note is given the name 'GDB' and a type NT_GDB_TDESC.  This
should hopefully protect us if there's ever a reuse of the number
assigned to NT_GDB_TDESC by some other core file producer.  It should
also, hopefully, make it clearer to users that this note carries GDB
specific information.

bfd/ChangeLog:

	* elf-bfd.h (elfcore_write_gdb_tdesc): Declare new function.
	* elf.c (elfcore_grok_gdb_tdesc): New function.
	(elfcore_grok_note): Handle NT_GDB_TDESC.
	(elfcore_write_gdb_tdesc): New function.
	(elfcore_write_register_note): Handle NT_GDB_TDESC.

binutils/ChangeLog:

	* readelf.c (get_note_type): Handle NT_GDB_TDESC.

include/ChangeLog:

	* elf/common.h (NT_GDB_TDESC): Define.
---
 bfd/ChangeLog        |  9 +++++++++
 bfd/elf-bfd.h        |  2 ++
 bfd/elf.c            | 35 +++++++++++++++++++++++++++++++++++
 binutils/ChangeLog   |  5 +++++
 binutils/readelf.c   |  2 ++
 include/ChangeLog    |  5 +++++
 include/elf/common.h |  4 ++++
 7 files changed, 62 insertions(+)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 4b79ee8eb62..8b989e71580 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2796,6 +2796,8 @@ extern char *elfcore_write_aarch_pauth
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_arc_v2
   (bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_gdb_tdesc
+  (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_lwpstatus
   (bfd *, char *, int *, long, int, const void *);
 extern char *elfcore_write_register_note
diff --git a/bfd/elf.c b/bfd/elf.c
index 087f05e5cc8..2d66e9b999f 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9912,6 +9912,15 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
 }
 
+/* Convert NOTE into a bfd_section called ".gdb-tdesc".  Return TRUE if
+   successful otherwise, return FALSE.  */
+
+static bfd_boolean
+elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".gdb-tdesc", note);
+}
+
 #if defined (HAVE_PRPSINFO_T)
 typedef prpsinfo_t   elfcore_psinfo_t;
 #if defined (HAVE_PRPSINFO32_T)		/* Sparc64 cross Sparc32 */
@@ -10570,6 +10579,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
 	return TRUE;
 
+    case NT_GDB_TDESC:
+      if (note->namesz == 4
+          && strcmp (note->namedata, "GDB") == 0)
+        return elfcore_grok_gdb_tdesc (abfd, note);
+      else
+        return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -11951,6 +11967,23 @@ elfcore_write_arc_v2 (bfd *abfd,
 			     note_name, NT_ARC_V2, arc_v2, size);
 }
 
+/* Write the target description (a string) pointed to by TDESC, length
+   SIZE, into the note buffer BUF, and update *BUFSIZ.  ABFD is the bfd the
+   note is being written into.  Return a pointer to the new start of the
+   note buffer, to replace BUF which may no longer be valid.  */
+
+char *
+elfcore_write_gdb_tdesc (bfd *abfd,
+			 char *buf,
+			 int *bufsiz,
+			 const void *tdesc,
+			 int size)
+{
+  const char *note_name = "GDB";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_GDB_TDESC, tdesc, size);
+}
+
 char *
 elfcore_write_register_note (bfd *abfd,
 			     char *buf,
@@ -12035,6 +12068,8 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-arc-v2") == 0)
     return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".gdb-tdesc") == 0)
+    return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
   return NULL;
 }
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 755634dfe5d..277fcd3bc5a 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18318,6 +18318,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
 	return _("NT_PRPSINFO (prpsinfo structure)");
       case NT_TASKSTRUCT:
 	return _("NT_TASKSTRUCT (task structure)");
+      case NT_GDB_TDESC:
+        return _("NT_GDB_TDESC (GDB XML target description)");
       case NT_PRXFPREG:
 	return _("NT_PRXFPREG (user_xfpregs structure)");
       case NT_PPC_VMX:
diff --git a/include/elf/common.h b/include/elf/common.h
index e7d55ae0782..e6e9c278faa 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -677,6 +677,10 @@
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */
 
+/* The range 0xff000000 to 0xffffffff is set aside for notes that don't
+   originate from any particular operating system.  */
+#define NT_GDB_TDESC	0xff000000	/* Contains copy of GDB's target description XML.  */
+
 /* Note segments for core files on dir-style procfs systems.  */
 
 #define NT_PSTATUS	10		/* Has a struct pstatus */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 3/9] gdb: write target description into core file
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

When a core file is created from within GDB add the target description
into a note within the core file.

When loading a core file, if the target description note is present
then load the target description from the core file.

The benefit of this is that we can be sure that, when analysing the
core file within GDB, that we are using the exact same target
description as was in use at the time the core file was created.

GDB already supports a mechanism for figuring out the target
description from a given corefile; gdbarch_core_read_description.
This new mechanism (GDB adding the target description) is not going to
replace the old mechanism.  Core files generated outside of GDB will
not include a target description, and so GDB still needs to be able to
figure out a target description for these files.

My primary motivation for adding this feature is that, in a future
commit, I will be adding support for bare metal core dumps on some
targets.  For RISC-V specifically, I want to be able to dump all the
available control status registers.  As different targets will present
different sets of register in their target description, including
registers that are possibly not otherwise known to GDB I wanted a way
to capture these registers in the core dump.

I therefore need a mechanism to write out an arbitrary set of
registers, and to then derive a target description from this arbitrary
set when later loading the core file.  The obvious approach (I think)
is to just reuse the target description.

Once I'd decided to add support for writing out the target description
I could either choose to make this RISC-V only, or make it generic.  I
figure that having the target description in the core file doesn't
hurt, and _might_ be helpful.  So that's how I got here, general
support for including the target description in GDB generated core
files.

In previous versions of this patch I added the target description from
generic code (in gcore.c).  However, doing this creates a dependency
between GDB's common code and bfd ELF support.  As ELF support in gdb
is optional (for example the target x86_64-apple-darwin20.3.0 does not
include ELF support) then having gcore.c require ELF support would
break the GDB build in some cases.

Instead, in this version of the patch, writing the target description
note is done from each specific targets make notes function.  Each of
these now calls a common function in gcore-elf.c (which is only linked
in when bfd has ELF support).  And so only targets that are ELF based
will call the new function and we can therefore avoid an unconditional
dependency on ELF support.

gdb/ChangeLog:

	* corelow.c: Add 'xml-tdesc.h' include.
	(core_target::read_description): Load the target description from
	the core file when possible.
	* fbsd-tdep.c (fbsd_make_corefile_notes): Add target description
	note.
	* gcore-elf.c: Add 'gdbsupport/tdesc.h' include.
	(gcore_elf_make_tdesc_note): New function.
	* gcore-elf.h (gcore_elf_make_tdesc_note): Declare.
	* linux-tdep.c (linux_make_corefile_notes): Add target description
	note.
---
 gdb/ChangeLog    | 14 ++++++++++++++
 gdb/corelow.c    | 24 ++++++++++++++++++++++++
 gdb/fbsd-tdep.c  |  3 +++
 gdb/gcore-elf.c  | 30 ++++++++++++++++++++++++++++++
 gdb/gcore-elf.h  |  8 ++++++++
 gdb/linux-tdep.c |  3 +++
 6 files changed, 82 insertions(+)

diff --git a/gdb/corelow.c b/gdb/corelow.c
index a63eab4852b..a2d2d20afc6 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -49,6 +49,7 @@
 #include <unordered_map>
 #include <unordered_set>
 #include "gdbcmd.h"
+#include "xml-tdesc.h"
 
 #ifndef O_LARGEFILE
 #define O_LARGEFILE 0
@@ -1000,6 +1001,29 @@ core_target::thread_alive (ptid_t ptid)
 const struct target_desc *
 core_target::read_description ()
 {
+  /* If the core file contains a target description note then we will use
+     that in preference to anything else.  */
+  bfd_size_type tdesc_note_size = 0;
+  struct bfd_section *tdesc_note_section
+    = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
+  if (tdesc_note_section != nullptr)
+    tdesc_note_size = bfd_section_size (tdesc_note_section);
+  if (tdesc_note_size > 0)
+    {
+      gdb::char_vector contents (tdesc_note_size + 1);
+      if (bfd_get_section_contents (core_bfd, tdesc_note_section,
+				    contents.data (), (file_ptr) 0,
+				    tdesc_note_size))
+	{
+	  /* Ensure we have a null terminator.  */
+	  contents[tdesc_note_size] = '\0';
+	  const struct target_desc *result
+	    = string_read_description_xml (contents.data ());
+	  if (result != nullptr)
+	    return result;
+	}
+    }
+
   if (m_core_gdbarch && gdbarch_core_read_description_p (m_core_gdbarch))
     {
       const struct target_desc *result;
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index dc4278cd644..170e8f5e84e 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -712,6 +712,9 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
 	return NULL;
     }
 
+  /* Include the target description when possible.  */
+  gcore_elf_make_tdesc_note (obfd, &note_data, note_size);
+
   return note_data;
 }
 
diff --git a/gdb/gcore-elf.c b/gdb/gcore-elf.c
index ebc94277d35..036a40ca115 100644
--- a/gdb/gcore-elf.c
+++ b/gdb/gcore-elf.c
@@ -24,6 +24,7 @@
 #include "gdbthread.h"
 #include "inferior.h"
 #include "regset.h"
+#include "gdbsupport/tdesc.h"
 
 /* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS
    via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */
@@ -134,3 +135,32 @@ gcore_elf_build_thread_register_notes
   gcore_elf_collect_thread_registers (regcache, info->ptid, obfd,
 				      note_data, note_size, stop_signal);
 }
+
+/* See gcore-elf.h.  */
+
+void
+gcore_elf_make_tdesc_note (bfd *obfd,
+			   gdb::unique_xmalloc_ptr<char> *note_data,
+			   int *note_size)
+{
+  /* Append the target description to the core file.  */
+  const struct target_desc *tdesc = gdbarch_target_desc (target_gdbarch ());
+  const char *tdesc_xml
+    = tdesc == nullptr ? nullptr : tdesc_get_features_xml (tdesc);
+  if (tdesc_xml != nullptr && *tdesc_xml != '\0')
+    {
+      /* Skip the leading '@'.  */
+      if (*tdesc_xml == '@')
+	++tdesc_xml;
+
+      /* Include the null terminator in the length.  */
+      size_t tdesc_len = strlen (tdesc_xml) + 1;
+
+      /* Now add the target description into the core file.  */
+      note_data->reset (elfcore_write_register_note (obfd,
+						     note_data->release (),
+						     note_size,
+						     ".gdb-tdesc", tdesc_xml,
+						     tdesc_len));
+    }
+}
diff --git a/gdb/gcore-elf.h b/gdb/gcore-elf.h
index d667686adc7..b750165323e 100644
--- a/gdb/gcore-elf.h
+++ b/gdb/gcore-elf.h
@@ -36,4 +36,12 @@ extern void gcore_elf_build_thread_register_notes
   (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
    bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size);
 
+/* Add content to *NOTE_DATA (and update *NOTE_SIZE) to include a note
+   containing the current targtet's target description.  The core file is
+   being written to OBFD.  If something goes wrong then *NOTE_DATA can be
+   set to nullptr.  */
+
+extern void gcore_elf_make_tdesc_note
+  (bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size);
+
 #endif /* GCORE_ELF_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 5bfd82d1673..ab3402a41c2 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -1935,6 +1935,9 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
   /* File mappings.  */
   linux_make_mappings_corefile_notes (gdbarch, obfd, note_data, note_size);
 
+  /* Target description.  */
+  gcore_elf_make_tdesc_note (obfd, &note_data, note_size);
+
   return note_data;
 }
 
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 4/9] bfd/riscv: prepare to handle bare metal core dump creation
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
                     ` (2 preceding siblings ...)
  2021-02-15 17:29   ` [PATCHv3 3/9] gdb: write target description into " Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 5/9] gdb/riscv: introduce bare metal core dump support Andrew Burgess
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

When creating a core file GDB will call the function
elfcore_write_prstatus to write out the general purpose registers
along with the pid/tid for the thread (into a prstatus structure) and
the executable name and arguments (into a prpsinfo_t structure).

However, for a bare metal RISC-V tool chain the prstatus_t and
prpsinfo_t types are not defined so the elfcore_write_prstatus
function will return NULL, preventing core file creation.

This commit provides the `elf_backend_write_core_note' hook and uses
the provided function to write out the required information.

In order to keep changes in the non bare metal tools to a minimum, the
provided backend function will itself return NULL when the prstatus_t
or pspsinfo_t types are available, the consequence of this is that the
generic code in elfcore_write_prstatus will be used just as before.
But, when prstatus_t or prpsinfo_t is not available, the new backend
function will write out the information using predefined offsets.

This new functionality will be used by a later GDB commit that will
add bare metal core dumps for RISC-V.

bfd/ChangeLog:

	* elfnn-riscv.c (PRPSINFO_PR_FNAME_LENGTH): Define.
	(PRPSINFO_PR_PSARGS_LENGTH): Define.
	(riscv_write_core_note): New function.
	(riscv_elf_grok_psinfo): Make use of two new length defines.
	(elf_backend_write_core_note): Define.
---
 bfd/ChangeLog     |  9 +++++
 bfd/elfnn-riscv.c | 84 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index b2ec6a29fbf..4444dcdf263 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -4874,6 +4874,8 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 # define PRPSINFO_OFFSET_PR_PID		16
 # define PRPSINFO_OFFSET_PR_FNAME	32
 # define PRPSINFO_OFFSET_PR_PSARGS	48
+# define PRPSINFO_PR_FNAME_LENGTH	16
+# define PRPSINFO_PR_PSARGS_LENGTH	80
 #else
 # define PRSTATUS_SIZE			376
 # define PRSTATUS_OFFSET_PR_CURSIG	12
@@ -4884,8 +4886,83 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 # define PRPSINFO_OFFSET_PR_PID		24
 # define PRPSINFO_OFFSET_PR_FNAME	40
 # define PRPSINFO_OFFSET_PR_PSARGS	56
+# define PRPSINFO_PR_FNAME_LENGTH	16
+# define PRPSINFO_PR_PSARGS_LENGTH	80
 #endif
 
+/* Write PRSTATUS and PRPSINFO note into core file.  This will be called
+   before the generic code in elf.c.  By checking the compiler defines we
+   only perform any action here if the generic code would otherwise not be
+   able to help us.  The intention is that bare metal core dumps (where the
+   prstatus_t and/or prpsinfo_t might not be available) will use this code,
+   while non bare metal tools will use the generic elf code.  */
+
+static char *
+riscv_write_core_note (bfd *abfd ATTRIBUTE_UNUSED,
+                       char *buf ATTRIBUTE_UNUSED,
+                       int *bufsiz ATTRIBUTE_UNUSED,
+                       int note_type ATTRIBUTE_UNUSED, ...)
+{
+  switch (note_type)
+    {
+    default:
+      return NULL;
+
+#if !defined (HAVE_PRPSINFO_T)
+    case NT_PRPSINFO:
+      {
+	char data[PRPSINFO_SIZE] ATTRIBUTE_NONSTRING;
+	va_list ap;
+
+	va_start (ap, note_type);
+	memset (data, 0, sizeof (data));
+	strncpy (data + PRPSINFO_OFFSET_PR_FNAME, va_arg (ap, const char *),
+                 PRPSINFO_PR_FNAME_LENGTH);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+	DIAGNOSTIC_PUSH;
+	/* GCC 8.0 and 8.1 warn about 80 equals destination size with
+	   -Wstringop-truncation:
+	   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+	 */
+	DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
+	strncpy (data + PRPSINFO_OFFSET_PR_PSARGS, va_arg (ap, const char *),
+                 PRPSINFO_PR_PSARGS_LENGTH);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+	DIAGNOSTIC_POP;
+#endif
+	va_end (ap);
+	return elfcore_write_note (abfd, buf, bufsiz,
+				   "CORE", note_type, data, sizeof (data));
+      }
+#endif /* !HAVE_PRPSINFO_T */
+
+#if !defined (HAVE_PRSTATUS_T)
+    case NT_PRSTATUS:
+      {
+        char data[PRSTATUS_SIZE];
+        va_list ap;
+        long pid;
+        int cursig;
+        const void *greg;
+
+        va_start (ap, note_type);
+        memset (data, 0, sizeof(data));
+        pid = va_arg (ap, long);
+        bfd_put_32 (abfd, pid, data + PRSTATUS_OFFSET_PR_PID);
+        cursig = va_arg (ap, int);
+        bfd_put_16 (abfd, cursig, data + PRSTATUS_OFFSET_PR_CURSIG);
+        greg = va_arg (ap, const void *);
+        memcpy (data + PRSTATUS_OFFSET_PR_REG, greg,
+                PRSTATUS_SIZE - PRSTATUS_OFFSET_PR_REG - ARCH_SIZE / 8);
+        va_end (ap);
+        return elfcore_write_note (abfd, buf, bufsiz,
+                                   "CORE", note_type, data, sizeof (data));
+      }
+#endif /* !HAVE_PRSTATUS_T */
+    }
+}
+
 /* Support for core dump NOTE sections.  */
 
 static bfd_boolean
@@ -4927,11 +5004,13 @@ riscv_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 
 	/* pr_fname */
 	elf_tdata (abfd)->core->program = _bfd_elfcore_strndup
-	  (abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME, 16);
+	  (abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME,
+           PRPSINFO_PR_FNAME_LENGTH);
 
 	/* pr_psargs */
 	elf_tdata (abfd)->core->command = _bfd_elfcore_strndup
-	  (abfd, note->descdata + PRPSINFO_OFFSET_PR_PSARGS, 80);
+	  (abfd, note->descdata + PRPSINFO_OFFSET_PR_PSARGS,
+           PRPSINFO_PR_PSARGS_LENGTH);
 	break;
     }
 
@@ -5000,6 +5079,7 @@ riscv_elf_obj_attrs_arg_type (int tag)
 #define elf_backend_grok_prstatus		riscv_elf_grok_prstatus
 #define elf_backend_grok_psinfo			riscv_elf_grok_psinfo
 #define elf_backend_object_p			riscv_elf_object_p
+#define elf_backend_write_core_note		riscv_write_core_note
 #define elf_info_to_howto_rel			NULL
 #define elf_info_to_howto			riscv_info_to_howto_rela
 #define bfd_elfNN_bfd_relax_section		_bfd_riscv_relax_section
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 5/9] gdb/riscv: introduce bare metal core dump support
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
                     ` (3 preceding siblings ...)
  2021-02-15 17:29   ` [PATCHv3 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 6/9] bfd/binutils: add support for RISC-V CSRs in core files Andrew Burgess
                     ` (4 subsequent siblings)
  9 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

This commit adds the ability for bare metal RISC-V target to generate
core files from within GDB.

The intended use case is that a user will connect to a remote bare
metal target, debug up to some error condition, then generate a core
file in the normal way using:

  (gdb) generate-core-file

This core file can then be used to revisit the state of the remote
target without having to reconnect to the remote target.

The core file creation code is split between two new files.  In
elf-none-tdep.c is code for any architecture with the none
ABI (i.e. bare metal) when the BFD library is built with ELF support.

In riscv-none-tdep.c are the RISC-V specific parts.  This is where the
regset and regcache_map_entry structures are defined that control how
registers are laid out in the core file.  As this file could (in
theory at least) be used for a non-ELF bare metal RISC-V target, the
calls into elf-none-tdep.c are guarded with '#ifdef HAVE_ELF'.

Currently for RISC-V only the x-regs and f-regs (if present) are
written out.  In future commits I plan to add support for writing out
the RISC-V CSRs.

The core dump format is based around generating an ELF containing
sections for the writable regions of memory that a user could be
using.  Which regions are dumped rely on GDB's existing common core
dumping code, GDB will attempt to figure out the stack and heap as
well as copying out writable data sections as identified by the
original ELF.

Register information is added to the core dump using notes, just as it
is for Linux of FreeBSD core dumps.  The note types used consist of
the 3 basic types you would expect in a OS based core dump,
NT_PRPSINFO, NT_PRSTATUS, NT_FPREGSET.

The layout of these notes differs slightly (due to field sizes)
between RV32 and RV64.  Below I describe the data layout for each
note.  In all cases, all padding fields should be set to zero.

Note NT_PRPSINFO is optional.  Its data layout is:

  struct prpsinfo32_t		/* For RV32.  */
  {
    uint8_t padding[32];
    char fname[16];
    char psargs[80];
  }

  struct prpsinfo64_t		/* For RV64.  */
  {
    uint8_t padding[40];
    char fname[16];
    char psargs[80];
  }

Field 'fname' - null terminated string consisting of the basename of
    (up to the fist 15 characters of) the executable.  Any additional
    space should be set to zero.  If there's no executable name then
    this field can be set to all zero.

Field 'psargs' - a null terminated string up to 80 characters in
    length.  Any additional space should be filled with zero.  This
    field contains the full executable path and any arguments passed
    to the executable.  If there's nothing sensible to write in this
    field then fill it with zero.

Note NT_PRSTATUS is required, its data layout is:

  struct prstatus32_t		/* For RV32.  */
  {
    uint8_t padding_1[12];
    uint16_t sig;
    uint8_t padding_2[10];
    uint32_t thread_id;
    uint8_t padding_3[44];
    uint32_t x_regs[32];
    uint8_t padding_4[4];
  }

  struct prstatus64_t		/* For RV64.  */
  {
    uint8_t padding_1[12];
    uint16_t sig;
    uint8_t padding_2[18];
    uint32_t thread_id;
    uint8_t padding_3[76];
    uint64_t x_regs[32];
    uint8_t padding_4[4];
  }

Field 'sig' - the signal that stopped this thread.  It's implementation
    defined what this field actually means.  Within GDB this will be
    the signal number that the remote target reports as the stop
    reason for this thread.

Field 'thread_is' - the thread id for this thread.  It's implementation
    defined what this field actually means.  Within GDB this will be
    thread thread-id that is assigned to each remote thread.

Field 'x_regs' - at index 0 we store the program counter, and at
    indices 1 to 31 we store x-registers 1 to 31.  x-register 0 is not
    stored, its value is always zero anyway.

Note NT_FPREGSET is optional, its data layout is:

  fpregset32_t			/* For targets with 'F' extension.  */
  {
    uint32_t f_regs[32];
    uint32_t fcsr;
  }

  fpregset64_t			/* For targets with 'D' extension .  */
  {
    uint64_t f_regs[32];
    uint32_t fcsr;
  }

Field 'f_regs' - stores f-registers 0 to 31.

Field 'fcsr' - stores the fcsr CSR register, and is always 4-bytes.

The rules for ordering the notes is the same as for Linux.  The
NT_PRSTATUS note must come before any other notes about additional
register sets.  And for multi-threaded targets all registers for a
single thread should be grouped together.  This is because only
NT_PRSTATUS includes a thread-id, all additional register notes after
a NT_PRSTATUS are assumed to belong to the same thread until a
different NT_PRSTATUS is seen.

gdb/ChangeLog:

	* Makefile.in (ALL_TARGET_OBS): Add riscv-none-tdep.o.
	(ALLDEPFILES): Add riscv-none-tdep.c.
	* configure: Regenerate.
	* configure.ac (CONFIG_OBS): Add elf-none-tdep.o when BFD has ELF
	support.
	* configure.tgt (riscv*-*-*): Include riscv-none-tdep.c.
	* elf-none-tdep.c: New file.
	* elf-none-tdep.h: New file.
	* riscv-none-tdep.c: New file.
---
 gdb/ChangeLog         |  13 +++++
 gdb/Makefile.in       |   4 ++
 gdb/configure         |   3 +-
 gdb/configure.ac      |   3 +-
 gdb/configure.tgt     |   2 +-
 gdb/elf-none-tdep.c   | 126 ++++++++++++++++++++++++++++++++++++++++++
 gdb/elf-none-tdep.h   |  30 ++++++++++
 gdb/riscv-none-tdep.c | 113 +++++++++++++++++++++++++++++++++++++
 8 files changed, 291 insertions(+), 3 deletions(-)
 create mode 100644 gdb/elf-none-tdep.c
 create mode 100644 gdb/elf-none-tdep.h
 create mode 100644 gdb/riscv-none-tdep.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index cf5017e7f66..a6ca5a53655 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -808,6 +808,7 @@ ALL_TARGET_OBS = \
 	ravenscar-thread.o \
 	riscv-fbsd-tdep.o \
 	riscv-linux-tdep.o \
+	riscv-none-tdep.o \
 	riscv-ravenscar-thread.o \
 	riscv-tdep.o \
 	rl78-tdep.o \
@@ -1189,6 +1190,7 @@ SFILES = \
 	cp-name-parser.y \
 	d-exp.y \
 	dtrace-probe.c \
+	elf-none-tdep.c \
 	elfread.c \
 	f-exp.y \
 	gcore-elf.c \
@@ -1363,6 +1365,7 @@ HFILES_NO_SRCDIR = \
 	netbsd-tdep.h \
 	nds32-tdep.h \
 	nios2-tdep.h \
+	elf-none-tdep.h \
 	nto-tdep.h \
 	objc-lang.h \
 	objfiles.h \
@@ -2274,6 +2277,7 @@ ALLDEPFILES = \
 	riscv-fbsd-tdep.c \
 	riscv-linux-nat.c \
 	riscv-linux-tdep.c \
+	riscv-none-tdep.c \
 	riscv-ravenscar-thread.c \
 	riscv-tdep.c \
 	rl78-tdep.c \
diff --git a/gdb/configure b/gdb/configure
index 4707fd01174..4c80350596c 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -17264,7 +17264,8 @@ $as_echo "$gdb_cv_var_elf" >&6; }
   LDFLAGS=$OLD_LDFLAGS
   LIBS=$OLD_LIBS
 if test "$gdb_cv_var_elf" = yes; then
-  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
+  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o \
+		gcore-elf.o elf-none-tdep.o"
 
 $as_echo "#define HAVE_ELF 1" >>confdefs.h
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index db765af0577..7035014484e 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1882,7 +1882,8 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
 GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
                  [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
 if test "$gdb_cv_var_elf" = yes; then
-  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
+  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o \
+		gcore-elf.o elf-none-tdep.o"
   AC_DEFINE(HAVE_ELF, 1,
 	    [Define if ELF support should be included.])
   # -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 842e683f5f5..91020678bf0 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -85,7 +85,7 @@ ia64*-*-*)
 	;;
 
 riscv*-*-*)
-	cpu_obs="riscv-tdep.o arch/riscv.o \
+	cpu_obs="riscv-tdep.o riscv-none-tdep.o arch/riscv.o \
 	         ravenscar-thread.o riscv-ravenscar-thread.o";;
 
 x86_64-*-*)
diff --git a/gdb/elf-none-tdep.c b/gdb/elf-none-tdep.c
new file mode 100644
index 00000000000..4cbb664607e
--- /dev/null
+++ b/gdb/elf-none-tdep.c
@@ -0,0 +1,126 @@
+/* Common code for targets with the none ABI (bare-metal), but where the
+   BFD library is build with ELF support.
+
+   Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "elf-none-tdep.h"
+#include "regset.h"
+#include "elf-bfd.h"            /* for elfcore_write_* */
+#include "inferior.h"
+#include "regcache.h"
+#include "gdbarch.h"
+#include "gcore.h"
+#include "gcore-elf.h"
+
+/* Build the note section for a corefile, and return it in a malloc
+   buffer.  Currently this just dumps all available registers for each
+   thread.  */
+
+static gdb::unique_xmalloc_ptr<char>
+elf_none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
+			      int *note_size)
+{
+  gdb::unique_xmalloc_ptr<char> note_data;
+
+  /* Add note information about the executable and its arguments.  */
+  std::string fname;
+  std::string psargs;
+  static const size_t fname_len = 16;
+  static const size_t psargs_len = 80;
+  if (get_exec_file (0))
+    {
+      const char *exe = get_exec_file (0);
+      fname = lbasename (exe);
+      psargs = std::string (exe);
+
+      const char *infargs = get_inferior_args ();
+      if (infargs != nullptr)
+	psargs += " " + std::string (infargs);
+
+      /* All existing targets that handle writing out prpsinfo expect the
+	 fname and psargs strings to be at least 16 and 80 characters long
+	 respectively, including a null terminator at the end.  Resize to
+	 the expected length minus one to ensure there is a null within the
+	 required length.  */
+      fname.resize (fname_len - 1);
+      psargs.resize (psargs_len - 1);
+    }
+
+  /* Resize the buffers up to their required lengths.  This will fill any
+     remaining space with the null character.  */
+  fname.resize (fname_len);
+  psargs.resize (psargs_len);
+
+  /* Now write out the prpsinfo structure.  */
+  note_data.reset (elfcore_write_prpsinfo (obfd, note_data.release (),
+					   note_size, fname.c_str (),
+					   psargs.c_str ()));
+  if (note_data == nullptr)
+    return nullptr;
+
+  /* Thread register information.  */
+  try
+    {
+      update_thread_list ();
+    }
+  catch (const gdb_exception_error &e)
+    {
+      exception_print (gdb_stderr, e);
+    }
+
+  /* Like the Linux 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 ();
+
+  /* All threads are reported as having been stopped by the same signal
+     that stopped SIGNALLED_THR.  */
+  gdb_signal stop_signal;
+  if (signalled_thr != nullptr)
+    stop_signal = signalled_thr->suspend.stop_signal;
+  else
+    stop_signal = GDB_SIGNAL_0;
+
+  if (signalled_thr != nullptr)
+    gcore_elf_build_thread_register_notes (gdbarch, signalled_thr,
+					   stop_signal, obfd, &note_data,
+					   note_size);
+  for (thread_info *thr : current_inferior ()->non_exited_threads ())
+    {
+      if (thr == signalled_thr)
+	continue;
+
+      gcore_elf_build_thread_register_notes (gdbarch, thr, stop_signal, obfd,
+					     &note_data, note_size);
+    }
+
+
+  /* Target description.  */
+  gcore_elf_make_tdesc_note (obfd, &note_data, note_size);
+
+  return note_data;
+}
+
+/* See none-tdep.h.  */
+
+void
+elf_none_init_abi (struct gdbarch *gdbarch)
+{
+  /* Default core file support.  */
+  set_gdbarch_make_corefile_notes (gdbarch, elf_none_make_corefile_notes);
+}
diff --git a/gdb/elf-none-tdep.h b/gdb/elf-none-tdep.h
new file mode 100644
index 00000000000..9ce9a20e468
--- /dev/null
+++ b/gdb/elf-none-tdep.h
@@ -0,0 +1,30 @@
+/* Architecture independent code for ABI 'none' (bare-metal).
+
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NONE_TDEP_H
+#define NONE_TDEP_H
+
+struct gdbarch;
+
+/* Initialize support for cross-architecture features applicable for the
+   GDB_OSABI_NONE ABI, that is bare-metal targets.  */
+
+void elf_none_init_abi (struct gdbarch *gdbarch);
+
+#endif /* NONE_TDEP_H */
diff --git a/gdb/riscv-none-tdep.c b/gdb/riscv-none-tdep.c
new file mode 100644
index 00000000000..f1ac592bfac
--- /dev/null
+++ b/gdb/riscv-none-tdep.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This file contain code that is specific for bare-metal RISC-V targets.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "riscv-tdep.h"
+#include "elf-bfd.h"
+#include "regset.h"
+
+#ifdef HAVE_ELF
+#include "elf-none-tdep.h"
+#endif
+
+/* Define the general register mapping.  This follows the same format as
+   the RISC-V linux corefile.  The linux kernel puts the PC at offset 0,
+   gdb puts it at offset 32.  Register x0 is always 0 and can be ignored.
+   Registers x1 to x31 are in the same place.  */
+
+static const struct regcache_map_entry riscv_gregmap[] =
+{
+  { 1,  RISCV_PC_REGNUM, 0 },
+  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
+  { 0 }
+};
+
+/* Define the FP register mapping.  This follows the same format as the
+   RISC-V linux corefile.  The kernel puts the 32 FP regs first, and then
+   FCSR.  */
+
+static const struct regcache_map_entry riscv_fregmap[] =
+{
+  { 32, RISCV_FIRST_FP_REGNUM, 0 },
+  { 1, RISCV_CSR_FCSR_REGNUM, 4 },	/* Always stored as 4-bytes.  */
+  { 0 }
+};
+
+/* Define the general register regset.  */
+
+static const struct regset riscv_gregset =
+{
+  riscv_gregmap, riscv_supply_regset, regcache_collect_regset
+};
+
+/* Define the FP register regset.  */
+
+static const struct regset riscv_fregset =
+{
+  riscv_fregmap, riscv_supply_regset, regcache_collect_regset
+};
+
+/* Implement the "iterate_over_regset_sections" gdbarch method.  */
+
+static void
+riscv_iterate_over_regset_sections (struct gdbarch *gdbarch,
+				    iterate_over_regset_sections_cb *cb,
+				    void *cb_data,
+				    const struct regcache *regcache)
+{
+  /* Write out the GPRs.  */
+  int sz = 32 * riscv_isa_xlen (gdbarch);
+  cb (".reg", sz, sz, &riscv_gregset, NULL, cb_data);
+
+  /* Write out the FPRs, but only if present.  */
+  if (riscv_isa_flen (gdbarch) > 0)
+    {
+      sz = (32 * riscv_isa_flen (gdbarch)
+	    + register_size (gdbarch, RISCV_CSR_FCSR_REGNUM));
+      cb (".reg2", sz, sz, &riscv_fregset, NULL, cb_data);
+    }
+}
+
+/* Initialize RISC-V bare-metal ABI info.  */
+
+static void
+riscv_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+#ifdef HAVE_ELF
+  elf_none_init_abi (gdbarch);
+#endif
+
+  /* Iterate over registers for reading and writing bare metal RISC-V core
+     files.  */
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, riscv_iterate_over_regset_sections);
+
+}
+
+/* Initialize RISC-V bare-metal target support.  */
+
+void _initialize_riscv_none_tdep ();
+void
+_initialize_riscv_none_tdep ()
+{
+  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_NONE,
+			  riscv_none_init_abi);
+}
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 6/9] bfd/binutils: add support for RISC-V CSRs in core files
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
                     ` (4 preceding siblings ...)
  2021-02-15 17:29   ` [PATCHv3 5/9] gdb/riscv: introduce bare metal core dump support Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 7/9] gdb/riscv: make riscv target description names global Andrew Burgess
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

Adds support for including RISC-V control and status registers into
core files.

The value for the define NT_RISCV_CSR is set to 0x900, this
corresponds to a patch I have proposed for the Linux kernel here:

  http://lists.infradead.org/pipermail/linux-riscv/2020-December/003910.html

As I have not yet heard if the above patch will be accepted into the
kernel or not I have set the note name string to "GDB", and the note
type to NT_RISCV_CSR.

This means that if the above patch is rejected from the kernel, and
the note type number 0x900 is assigned to some other note type, we
will still be able to distinguish between the GDB produced
NT_RISCV_CSR, and the kernel produced notes, where the name would be
set to "CORE".

bfd/ChangeLog:

	* elf-bfd.h (elfcore_write_riscv_csr): Declare.
	* elf.c (elfcore_grok_riscv_csr): New function.
	(elfcore_grok_note): Handle NT_RISCV_CSR.
	(elfcore_write_riscv_csr): New function.
	(elfcore_write_register_note): Handle '.reg-riscv-csr'.

binutils/ChangeLog:

	* readelf.c (get_note_type): Handle NT_RISCV_CSR.

include/ChangeLog:

	* elf/common.h (NT_RISCV_CSR): Define.
---
 bfd/ChangeLog        |  9 +++++++++
 bfd/elf-bfd.h        |  2 ++
 bfd/elf.c            | 35 +++++++++++++++++++++++++++++++++++
 binutils/ChangeLog   |  5 +++++
 binutils/readelf.c   |  2 ++
 include/ChangeLog    |  5 +++++
 include/elf/common.h |  2 ++
 7 files changed, 60 insertions(+)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 8b989e71580..e4cf481965f 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2796,6 +2796,8 @@ extern char *elfcore_write_aarch_pauth
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_arc_v2
   (bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_riscv_csr
+  (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_gdb_tdesc
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_lwpstatus
diff --git a/bfd/elf.c b/bfd/elf.c
index 2d66e9b999f..553fa65a118 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9912,6 +9912,15 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
 }
 
+/* Convert NOTE into a bfd_section called ".reg-riscv-csr".  Return TRUE if
+   successful otherwise, return FALSE.  */
+
+static bfd_boolean
+elfcore_grok_riscv_csr (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-riscv-csr", note);
+}
+
 /* Convert NOTE into a bfd_section called ".gdb-tdesc".  Return TRUE if
    successful otherwise, return FALSE.  */
 
@@ -10586,6 +10595,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
         return TRUE;
 
+    case NT_RISCV_CSR:
+      if (note->namesz == 4
+          && strcmp (note->namedata, "GDB") == 0)
+        return elfcore_grok_riscv_csr (abfd, note);
+      else
+	return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -11967,6 +11983,23 @@ elfcore_write_arc_v2 (bfd *abfd,
 			     note_name, NT_ARC_V2, arc_v2, size);
 }
 
+/* Write the buffer of csr values in CSRS (length SIZE) into the note
+   buffer BUF and update *BUFSIZ.  ABFD is the bfd the note is being
+   written into.  Return a pointer to the new start of the note buffer, to
+   replace BUF which may no longer be valid.  */
+
+char *
+elfcore_write_riscv_csr (bfd *abfd,
+                         char *buf,
+                         int *bufsiz,
+                         const void *csrs,
+                         int size)
+{
+  const char *note_name = "GDB";
+  return elfcore_write_note (abfd, buf, bufsiz,
+			     note_name, NT_RISCV_CSR, csrs, size);
+}
+
 /* Write the target description (a string) pointed to by TDESC, length
    SIZE, into the note buffer BUF, and update *BUFSIZ.  ABFD is the bfd the
    note is being written into.  Return a pointer to the new start of the
@@ -12070,6 +12103,8 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".gdb-tdesc") == 0)
     return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-riscv-csr") == 0)
+    return elfcore_write_riscv_csr (abfd, buf, bufsiz, data, size);
   return NULL;
 }
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 277fcd3bc5a..ba624788633 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18396,6 +18396,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
 	return _("NT_ARM_HW_WATCH (AArch hardware watchpoint registers)");
       case NT_ARC_V2:
 	return _("NT_ARC_V2 (ARC HS accumulator/extra registers)");
+      case NT_RISCV_CSR:
+	return _("NT_RISCV_CSR (RISC-V control and status registers)");
       case NT_PSTATUS:
 	return _("NT_PSTATUS (pstatus structure)");
       case NT_FPREGS:
diff --git a/include/elf/common.h b/include/elf/common.h
index e6e9c278faa..4cb3748e4fd 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -674,6 +674,8 @@
 					/*   note name must be "LINUX".  */
 #define NT_ARC_V2	0x600		/* ARC HS accumulator/extra registers.  */
 					/*   note name must be "LINUX".  */
+#define NT_RISCV_CSR    0x900		/* RISC-V Control and Status Registers */
+					/*   note name must be "CORE".  */
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */
 
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 7/9] gdb/riscv: make riscv target description names global
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
                     ` (5 preceding siblings ...)
  2021-02-15 17:29   ` [PATCHv3 6/9] bfd/binutils: add support for RISC-V CSRs in core files Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 8/9] gdb/riscv: write CSRs into baremetal core dumps Andrew Burgess
                     ` (2 subsequent siblings)
  9 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

A later commit will need the names of the RISC-V target description
features in files other than riscv-tdep.c.  This commit just makes the
names global strings that can be accessed from other riscv-*.c files.

There should be no user visible changes after this commit.

gdb/ChangeLog:

        * riscv-tdep.c (riscv_feature_name_csr): Define.
        (riscv_feature_name_cpu): Define.
        (riscv_feature_name_fpu): Define.
        (riscv_feature_name_virtual): Define.
        (riscv_xreg_feature): Use riscv_feature_name_cpu.
        (riscv_freg_feature): Use riscv_feature_name_fpu.
        (riscv_virtual_feature): Use riscv_feature_name_virtual.
        (riscv_csr_feature): Use riscv_feature_name_csr.
        * riscv-tdep.h (riscv_feature_name_csr): Declare.
---
 gdb/ChangeLog    | 12 ++++++++++++
 gdb/riscv-tdep.c | 14 ++++++++++----
 gdb/riscv-tdep.h |  3 +++
 3 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 460746a9bfe..ee56d840c36 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -94,6 +94,12 @@ static unsigned int riscv_debug_unwinder = 0;
 
 static unsigned int riscv_debug_gdbarch = 0;
 
+/* The names of the RISC-V target description features.  */
+const char *riscv_feature_name_csr = "org.gnu.gdb.riscv.csr";
+static const char *riscv_feature_name_cpu = "org.gnu.gdb.riscv.cpu";
+static const char *riscv_feature_name_fpu = "org.gnu.gdb.riscv.fpu";
+static const char *riscv_feature_name_virtual = "org.gnu.gdb.riscv.virtual";
+
 /* Cached information about a frame.  */
 
 struct riscv_unwind_cache
@@ -257,7 +263,7 @@ riscv_register_feature::register_info::check
 struct riscv_xreg_feature : public riscv_register_feature
 {
   riscv_xreg_feature ()
-    : riscv_register_feature ("org.gnu.gdb.riscv.cpu")
+    : riscv_register_feature (riscv_feature_name_cpu)
   {
     m_registers =  {
       { RISCV_ZERO_REGNUM + 0, { "zero", "x0" } },
@@ -354,7 +360,7 @@ static const struct riscv_xreg_feature riscv_xreg_feature;
 struct riscv_freg_feature : public riscv_register_feature
 {
   riscv_freg_feature ()
-    : riscv_register_feature ("org.gnu.gdb.riscv.fpu")
+    : riscv_register_feature (riscv_feature_name_fpu)
   {
     m_registers =  {
       { RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" } },
@@ -482,7 +488,7 @@ static const struct riscv_freg_feature riscv_freg_feature;
 struct riscv_virtual_feature : public riscv_register_feature
 {
   riscv_virtual_feature ()
-    : riscv_register_feature ("org.gnu.gdb.riscv.virtual")
+    : riscv_register_feature (riscv_feature_name_virtual)
   {
     m_registers =  {
       { RISCV_PRIV_REGNUM, { "priv" } }
@@ -518,7 +524,7 @@ static const struct riscv_virtual_feature riscv_virtual_feature;
 struct riscv_csr_feature : public riscv_register_feature
 {
   riscv_csr_feature ()
-    : riscv_register_feature ("org.gnu.gdb.riscv.csr")
+    : riscv_register_feature (riscv_feature_name_csr)
   {
     m_registers = {
 #define DECLARE_CSR(NAME,VALUE,CLASS,DEFINE_VER,ABORT_VER)		\
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index d1f1cf17ba8..154097df5d0 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -160,4 +160,7 @@ extern void riscv_supply_regset (const struct regset *regset,
 				  struct regcache *regcache, int regnum,
 				  const void *regs, size_t len);
 
+/* The names of the RISC-V target description features.  */
+extern const char *riscv_feature_name_csr;
+
 #endif /* RISCV_TDEP_H */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 8/9] gdb/riscv: write CSRs into baremetal core dumps
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
                     ` (6 preceding siblings ...)
  2021-02-15 17:29   ` [PATCHv3 7/9] gdb/riscv: make riscv target description names global Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-02-15 17:29   ` [PATCHv3 9/9] gdb/arm: add support for bare-metal " Andrew Burgess
  2021-03-01 10:32   ` [PATCHv3 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
  9 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

Use the current target description to include CSRs into the RISC-V
baremetal core dumps.

Every CSR declared in the current target description will be included
in the core dump.

It will be critical for users that they have the same target
description in use when loading the core file as was in use when
writing the core file.  This should be fine if the user allows the
target description to be written into the core file.

In more detail, this commit adds a NT_RISCV_CSR note type.  The
contents of this section is a series of either 4-byte (on RV32
targets), or 8-byte (on RV64 targets) values.  Every CSR that is
mentioned in the current target description is written out in the
order the registers appear in the target description.  As a
consequence it is critical that the exact same target description,
including the same register order, is in use when the CSRs are loaded
from the core file.

gdb/ChangeLog:

	* riscv-none-tdep.c: Add 'user-regs.h' and 'target-description.h'
	includes.
	(riscv_csrset): New static global.
	(riscv_update_csrmap): New function.
	(riscv_iterate_over_regset_sections): Process CSRs.
---
 gdb/ChangeLog         |  9 +++++++
 gdb/riscv-none-tdep.c | 60 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/gdb/riscv-none-tdep.c b/gdb/riscv-none-tdep.c
index f1ac592bfac..3247346ee94 100644
--- a/gdb/riscv-none-tdep.c
+++ b/gdb/riscv-none-tdep.c
@@ -23,6 +23,8 @@
 #include "riscv-tdep.h"
 #include "elf-bfd.h"
 #include "regset.h"
+#include "user-regs.h"
+#include "target-descriptions.h"
 
 #ifdef HAVE_ELF
 #include "elf-none-tdep.h"
@@ -65,6 +67,42 @@ static const struct regset riscv_fregset =
   riscv_fregmap, riscv_supply_regset, regcache_collect_regset
 };
 
+/* Define the CSR regset, this is not constant as the regmap field is
+   updated dynamically based on the current target description.  */
+
+static struct regset riscv_csrset =
+{
+  nullptr, regcache_supply_regset, regcache_collect_regset
+};
+
+/* Update the regmap field of RISCV_CSRSET based on the CSRs available in
+   the current target description.  */
+
+static void
+riscv_update_csrmap (struct gdbarch *gdbarch,
+		     const struct tdesc_feature *feature_csr)
+{
+  int i = 0;
+
+  /* Release any previously defined map.  */
+  delete[] ((struct regcache_map_entry *) riscv_csrset.regmap);
+
+  /* Now create a register map for every csr found in the target
+     description.  */
+  struct regcache_map_entry *riscv_csrmap
+    = new struct regcache_map_entry[feature_csr->registers.size() + 1];
+  for (auto &csr : feature_csr->registers)
+    {
+      int regnum = user_reg_map_name_to_regnum (gdbarch, csr->name.c_str(),
+						csr->name.length());
+      riscv_csrmap[i++] = {1, regnum, 0};
+    }
+
+  /* Mark the end of the array.  */
+  riscv_csrmap[i] = {0};
+  riscv_csrset.regmap = riscv_csrmap;
+}
+
 /* Implement the "iterate_over_regset_sections" gdbarch method.  */
 
 static void
@@ -84,6 +122,28 @@ riscv_iterate_over_regset_sections (struct gdbarch *gdbarch,
 	    + register_size (gdbarch, RISCV_CSR_FCSR_REGNUM));
       cb (".reg2", sz, sz, &riscv_fregset, NULL, cb_data);
     }
+
+  /* Read or write the CSRs.  The set of CSRs is defined by the current
+     target description.  The user is responsible for ensuring that the
+     same target description is in use when reading the core file as was
+     in use when writing the core file.  */
+  const struct target_desc *tdesc = gdbarch_target_desc (gdbarch);
+
+  /* Do not dump/load any CSRs if there is no target description or the target
+     description does not contain any CSRs.  */
+  if (tdesc != nullptr)
+    {
+      const struct tdesc_feature *feature_csr
+        = tdesc_find_feature (tdesc, riscv_feature_name_csr);
+      if (feature_csr != nullptr && feature_csr->registers.size () > 0)
+	{
+	  riscv_update_csrmap (gdbarch, feature_csr);
+	  cb (".reg-riscv-csr",
+	      (feature_csr->registers.size() * riscv_isa_xlen (gdbarch)),
+	      (feature_csr->registers.size() * riscv_isa_xlen (gdbarch)),
+	      &riscv_csrset, NULL, cb_data);
+	}
+    }
 }
 
 /* Initialize RISC-V bare-metal ABI info.  */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCHv3 9/9] gdb/arm: add support for bare-metal core dumps
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
                     ` (7 preceding siblings ...)
  2021-02-15 17:29   ` [PATCHv3 8/9] gdb/riscv: write CSRs into baremetal core dumps Andrew Burgess
@ 2021-02-15 17:29   ` Andrew Burgess
  2021-05-13 13:42     ` Andrew Burgess
  2021-03-01 10:32   ` [PATCHv3 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
  9 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-02-15 17:29 UTC (permalink / raw)
  To: gdb-patches, binutils

       **************** WARNING ********************

This commit is based off a patch from the mailing list, I don't know
if the author of this patch has a copyright assignment in place.  As
such this commit MUST NOT be pushed to upstream master until this has
been cleared up.  A link to the original mailing list posting can be
found in the patch description below.

       ************** END WARNING ******************

This commit adds support for bare metal core dumps on the ARM target,
and is based off of this patch submitted to the mailing list:

  https://sourceware.org/pipermail/gdb-patches/2020-October/172845.html

Compared to the version linked above this version is updated to take
account of recent changes to the core dump infrastructure in GDB,
there is now more shared infrastructure for core dumping within GDB,
and also some common bare metal core dumping infrastructure.  As a
result this patch is smaller than the original proposed patch.

Further, the original patch included some unrelated changes to the
simulator that have been removed from this version.

I have written a ChangeLog entry as the original patch was missing
one.

I have done absolutely no testing of this patch.  It is based on the
original submitted patch, which I assume was tested, but after my
modifications things might have been broken.

The core dump format is based around generating an ELF containing
sections for the writable regions of memory that a user could be
using.  Which regions are dumped rely on GDB's existing common core
dumping code, GDB will attempt to figure out the stack and heap as
well as copying out writable data sections as identified by the
original ELF.

Register information is added to the core dump using notes, just as it
is for Linux of FreeBSD core dumps.  The note types used consist of
the 2 basic types you would expect in a OS based core dump,
NT_PRPSINFO, NT_PRSTATUS, along with the architecture specific
NT_ARM_VFP note.

The data layouts for each note type are described below, in all cases,
all padding fields should be set to zero.

Note NT_PRPSINFO is optional.  Its data layout is:

  struct prpsinfo_t
  {
    uint8_t padding[28];
    char fname[16];
    char psargs[80];
  }

Field 'fname' - null terminated string consisting of the basename of
    (up to the fist 15 characters of) the executable.  Any additional
    space should be set to zero.  If there's no executable name then
    this field can be set to all zero.

Field 'psargs' - a null terminated string up to 80 characters in
    length.  Any additional space should be filled with zero.  This
    field contains the full executable path and any arguments passed
    to the executable.  If there's nothing sensible to write in this
    field then fill it with zero.

Note NT_PRSTATUS is required, its data layout is:

  struct prstatus_t
  {
    uint8_t padding_1[12];
    uint16_t sig;
    uint8_t padding_2[10];
    uint32_t thread_id;
    uint8_t padding_3[44];
    uint32_t gregs[18];
  }

Field 'sig' - the signal that stopped this thread.  It's implementation
    defined what this field actually means.  Within GDB this will be
    the signal number that the remote target reports as the stop
    reason for this thread.

Field 'thread_is' - the thread id for this thread.  It's implementation
    defined what this field actually means.  Within GDB this will be
    thread thread-id that is assigned to each remote thread.

Field 'gregs' - holds the general purpose registers $a1 through to $pc
    at indices 0 to 15.  At index 16 the program status register.
    Index 17 should be set to zero.

Note NT_ARM_VFP is optional, its data layout is:

  armvfp_t
  {
    uint64_t regs[32];
    uint32_t fpscr;
  }

Field 'regs' - holds the 32 d-registers 0 to 31 in order.

Field 'fpscr' - holds the fpscr register.

The rules for ordering the notes is the same as for Linux.  The
NT_PRSTATUS note must come before any other notes about additional
register sets.  And for multi-threaded targets all registers for a
single thread should be grouped together.  This is because only
NT_PRSTATUS includes a thread-id, all additional register notes after
a NT_PRSTATUS are assumed to belong to the same thread until a
different NT_PRSTATUS is seen.

gdb/ChangeLog:

	PR gdb/14383
	* Makefile.in (ALL_TARGET_OBS): Add arm-none-tdep.o.
	(ALLDEPFILES): Add arm-none-tdep.c
	* arm-none-tdep.c: New file.
	* configure.tgt (arm*-*-*): Add arm-none-tdep.o to cpu_obs.
---
 gdb/ChangeLog       |   9 ++
 gdb/Makefile.in     |   2 +
 gdb/arm-none-tdep.c | 213 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.tgt   |   3 +-
 4 files changed, 226 insertions(+), 1 deletion(-)
 create mode 100644 gdb/arm-none-tdep.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a6ca5a53655..77c2401e272 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -728,6 +728,7 @@ ALL_TARGET_OBS = \
 	arm-fbsd-tdep.o \
 	arm-linux-tdep.o \
 	arm-netbsd-tdep.o \
+	arm-none-tdep.o \
 	arm-obsd-tdep.o \
 	arm-pikeos-tdep.o \
 	arm-tdep.o \
@@ -2171,6 +2172,7 @@ ALLDEPFILES = \
 	arm-linux-tdep.c \
 	arm-netbsd-nat.c \
 	arm-netbsd-tdep.c \
+	arm-none-tdep.c \
 	arm-obsd-tdep.c \
 	arm-tdep.c \
 	avr-tdep.c \
diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
new file mode 100644
index 00000000000..2816c5954b3
--- /dev/null
+++ b/gdb/arm-none-tdep.c
@@ -0,0 +1,213 @@
+/* none on ARM target support.
+
+   Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arm-tdep.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "elf-bfd.h"
+#include "regset.h"
+#include "user-regs.h"
+
+#ifdef HAVE_ELF
+#include "elf-none-tdep.h"
+#endif
+
+/* Core file and register set support.  */
+#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
+
+/* Support VFP register format.  */
+#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
+
+/* The index to access CPSR in user_regs as defined in GLIBC.  */
+#define ARM_NONE_CPSR_GREGNUM 16
+
+/* Supply register REGNUM from buffer GREGS_BUF (length LEN bytes) into
+   REGCACHE.  If REGNUM is -1 then supply all registers.  The set of
+   registers that this function will supply is limited to the general
+   purpose registers.
+
+   The layout of the registers here is based on the ARM GNU/Linux
+   layout.  */
+
+static void
+arm_none_supply_gregset (const struct regset *regset,
+			 struct regcache *regcache,
+			 int regnum, const void *gregs_buf, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
+
+  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
+
+  if (regnum == ARM_PS_REGNUM || regnum == -1)
+    {
+      if (arm_apcs_32)
+	regcache->raw_supply (ARM_PS_REGNUM,
+			      gregs + ARM_INT_REGISTER_SIZE
+			      * ARM_NONE_CPSR_GREGNUM);
+      else
+	regcache->raw_supply (ARM_PS_REGNUM,
+			     gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
+    }
+
+  if (regnum == ARM_PC_REGNUM || regnum == -1)
+    {
+      gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
+
+      CORE_ADDR reg_pc
+	= extract_unsigned_integer (gregs + ARM_INT_REGISTER_SIZE
+				    * ARM_PC_REGNUM,
+				    ARM_INT_REGISTER_SIZE, byte_order);
+      reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
+      store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
+			      reg_pc);
+      regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
+    }
+}
+
+/* Collect register REGNUM from REGCACHE and place it into buffer GREGS_BUF
+   (length LEN bytes).  If REGNUM is -1 then collect all registers.  The
+   set of registers that this function will collect is limited to the
+   general purpose registers.
+
+   The layout of the registers here is based on the ARM GNU/Linux
+   layout.  */
+
+static void
+arm_none_collect_gregset (const struct regset *regset,
+			  const struct regcache *regcache,
+			  int regnum, void *gregs_buf, size_t len)
+{
+  gdb_byte *gregs = (gdb_byte *) gregs_buf;
+
+  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_collect (regno,
+			     gregs + ARM_INT_REGISTER_SIZE * regno);
+
+  if (regnum == ARM_PS_REGNUM || regnum == -1)
+    {
+      if (arm_apcs_32)
+	regcache->raw_collect (ARM_PS_REGNUM,
+			       gregs + ARM_INT_REGISTER_SIZE
+			       * ARM_NONE_CPSR_GREGNUM);
+      else
+	regcache->raw_collect (ARM_PS_REGNUM,
+			       gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
+    }
+
+  if (regnum == ARM_PC_REGNUM || regnum == -1)
+    regcache->raw_collect (ARM_PC_REGNUM,
+			   gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
+}
+
+/* Supply VFP registers from REGS_BUF into REGCACHE.  */
+
+static void
+arm_none_supply_vfp (const struct regset *regset,
+		     struct regcache *regcache,
+		     int regnum, const void *regs_buf, size_t len)
+{
+  const gdb_byte *regs = (const gdb_byte *) regs_buf;
+
+  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
+    regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
+
+  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
+}
+
+/* Collect VFP registers from REGCACHE into REGS_BUF.  */
+
+static void
+arm_none_collect_vfp (const struct regset *regset,
+		      const struct regcache *regcache,
+		      int regnum, void *regs_buf, size_t len)
+{
+  gdb_byte *regs = (gdb_byte *) regs_buf;
+
+  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
+    regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
+
+  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
+}
+
+/* The general purpose register set.  */
+
+static const struct regset arm_none_gregset =
+  {
+    nullptr, arm_none_supply_gregset, arm_none_collect_gregset
+  };
+
+/* The VFP register set.  */
+
+static const struct regset arm_none_vfpregset =
+  {
+    nullptr, arm_none_supply_vfp, arm_none_collect_vfp
+  };
+
+/* Iterate over core file register note sections.  */
+
+static void
+arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
+				       iterate_over_regset_sections_cb *cb,
+				       void *cb_data,
+				       const struct regcache *regcache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET,
+      &arm_none_gregset, nullptr, cb_data);
+
+  if (tdep->vfp_register_count > 0)
+    cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP,
+	&arm_none_vfpregset, "VFP floating-point", cb_data);
+}
+
+/* Initialize ARM bare-metal ABI info.  */
+
+static void
+arm_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+#ifdef HAVE_ELF
+  elf_none_init_abi (gdbarch);
+#endif
+
+  /* Iterate over registers for reading and writing bare metal ARM core
+     files.  */
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, arm_none_iterate_over_regset_sections);
+}
+
+/* Initialize ARM bare-metal target support.  */
+
+void _initialize_arm_none_tdep ();
+void
+_initialize_arm_none_tdep ()
+{
+  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NONE,
+			  arm_none_init_abi);
+}
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 91020678bf0..f81f03b96c9 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -65,7 +65,8 @@ arc*-*-*)
 
 arm*-*-*)
 	cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \
-		 arch/arm-get-next-pcs.o arm-tdep.o";;
+		 arch/arm-get-next-pcs.o arm-tdep.o arm-none-tdep.o"
+	;;
 
 hppa*-*-*)
 	# Target: HP PA-RISC
-- 
2.25.4


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv3 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code
  2021-02-15 17:29   ` [PATCHv3 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
@ 2021-02-15 22:56     ` Lancelot SIX
  2021-02-16 16:55       ` Andrew Burgess
  0 siblings, 1 reply; 57+ messages in thread
From: Lancelot SIX @ 2021-02-15 22:56 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, binutils

Le Mon, Feb 15, 2021 at 05:29:04PM +0000, Andrew Burgess a écrit :
> While reviewing the Linux and FreeBSD core dumping code within GDB for
> another patch series, I noticed that the code that collects the
> registers for each thread and writes these into ELF note format is
> basically identical between Linux and FreeBSD.
> 
> This commit merges this code and moves it into a new file gcore-elf.c.
> 
> The function find_signalled_thread is moved from linux-tdep.c to
> gcore.c despite not being shared.  A later commit will make use of
> this function.
> 
> I did merge, and then revert a previous version of this patch (commit
> 82a1fd3a4935 for the original patch and 03642b7189bc for the revert).
> The problem with the original patch is that it introduced a
> unconditional dependency between GDB and some ELF specific functions
> in the BFD library, e.g. elfcore_write_prstatus and
> elfcore_write_register_note.  It was pointed out in this mailing list
> post:
> 
>   https://sourceware.org/pipermail/gdb-patches/2021-February/175750.html
> 
> that this change was breaking any build of GDB for non-ELF targets.
> To confirm this breakage, and to test this new version of GDB I
> configured and built for the target x86_64-apple-darwin20.3.0.
> 
> Where the previous version of this patch placed all of the common code
> into gcore.c, which is included in all builds of GDB, this new patch
> only places non-ELF specific generic code (i.e. find_signalled_thread)
> into gcore.c, the ELF specific code is put into the new gcore-elf.c
> file, which is only included in GDB if BFD has ELF support.
> 
> The contents of gcore-elf.c are referenced unconditionally from
> linux-tdep.c and fbsd-tdep.c, this is fine, we previously always
> assumed that these two targets required ELF support, and we continue
> to make that assumption after this patch; nothing has changed there.
> 
> With my previous version of this patch the darwin target mentioned
> above failed to build, but with the new version, the target builds
> fine.
> 
> There are a couple of minor changes to the FreeBSD target after this
> commit, but I believe that these are changes for the better:
> 
> (1) For FreeBSD we always used to record the thread-id in the core
> file by using ptid_t.lwp ().  In contrast the Linux code did this:
> 
>     /* For remote targets the LWP may not be available, so use the TID.  */
>     long lwp = ptid.lwp ();
>     if (lwp == 0)
>       lwp = ptid.tid ();
> 
> Both target now do this:
> 
>     /* The LWP is often not available for bare metal target, in which case
>        use the tid instead.  */
>     if (ptid.lwp_p ())
>       lwp = ptid.lwp ();
>     else
>       lwp = ptid.tid ();
> 
> Which is equivalent for Linux, but is a change for FreeBSD.  I think
> that all this means is that in some cases where GDB might have
> previously recorded a thread-id of 0 for each thread, we might now get
> something more useful.
> 
> (2) When collecting the registers for Linux we collected into a zero
> initialised buffer.  By contrast on FreeBSD the buffer is left
> uninitialised.  In the new code the buffer is always zero initialised.
> I suspect once the registers are copied into the buffer there's
> probably no gaps left so this makes no difference, but if it does then
> using zeros rather than random bits of GDB's memory is probably a good
> thing.
> 
> Otherwise, there should be no other user visible changes after this
> commit.
> 
> Tested this on x86-64/GNU-Linux and x86-64/FreeBSD-12.2 with no
> regressions.
> 
> gdb/ChangeLog:
> 
> 	* Makefile.in (SFILES): Add gcore-elf.c.
> 	(HFILES_NO_SRCDIR): Add gcore-elf.h
> 	* configure: Regenerate.
> 	* configure.ac: Add gcore-elf.o to CONFIG_OBS if we have ELF
> 	support.
> 	* fbsd-tdep.c: Add 'gcore-elf.h' include.
> 	(struct fbsd_collect_regset_section_cb_data): Delete.
> 	(fbsd_collect_regset_section_cb): Delete.
> 	(fbsd_collect_thread_registers): Delete.
> 	(struct fbsd_corefile_thread_data): Delete.
> 	(fbsd_corefile_thread): Delete.
> 	(fbsd_make_corefile_notes): Call
> 	gcore_elf_build_thread_register_notes instead of the now deleted
> 	FreeBSD code.
> 	* gcore-elf.c: New file, the content was moved here from
> 	linux-tdep.c, functions were renamed and given minor cleanup.
> 	* gcore-elf.h: New file.
> 	* gcore.c (gcore_find_signalled_thread): Moved here from
> 	linux-tdep.c and given a new name.  Minor cleanups.
> 	* gcore.h (gcore_find_signalled_thread): Declare.
> 	* linux-tdep.c: Add 'gcore.h' and 'gcore-elf.h' includes.
> 	(struct linux_collect_regset_section_cb_data): Delete.
> 	(linux_collect_regset_section_cb): Delete.
> 	(linux_collect_thread_registers): Delete.
> 	(linux_corefile_thread): Call
> 	gcore_elf_build_thread_register_notes.
> 	(find_signalled_thread): Delete.
> 	(linux_make_corefile_notes): Call gcore_find_signalled_thread.
> ---
>  gdb/ChangeLog    |  31 ++++++++++
>  gdb/Makefile.in  |   2 +
>  gdb/configure    |   2 +-
>  gdb/configure.ac |   2 +-
>  gdb/fbsd-tdep.c  | 134 ++------------------------------------------
>  gdb/gcore-elf.c  | 136 ++++++++++++++++++++++++++++++++++++++++++++
>  gdb/gcore-elf.h  |  39 +++++++++++++
>  gdb/gcore.c      |  21 +++++++
>  gdb/gcore.h      |   9 +++
>  gdb/linux-tdep.c | 143 +++--------------------------------------------
>  10 files changed, 255 insertions(+), 264 deletions(-)
>  create mode 100644 gdb/gcore-elf.c
>  create mode 100644 gdb/gcore-elf.h
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index ae89b85eb56..cf5017e7f66 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1191,6 +1191,7 @@ SFILES = \
>  	dtrace-probe.c \
>  	elfread.c \
>  	f-exp.y \
> +	gcore-elf.c \
>  	gdb.c \
>  	go-exp.y \
>  	m2-exp.y \
> @@ -1292,6 +1293,7 @@ HFILES_NO_SRCDIR = \
>  	frame-unwind.h \
>  	frv-tdep.h \
>  	ft32-tdep.h \
> +	gcore-elf.h \
>  	gcore.h \
>  	gdb_bfd.h \
>  	gdb_curses.h \
> diff --git a/gdb/configure b/gdb/configure
> index 51b4d1921c5..4707fd01174 100755
> --- a/gdb/configure
> +++ b/gdb/configure
> @@ -17264,7 +17264,7 @@ $as_echo "$gdb_cv_var_elf" >&6; }
>    LDFLAGS=$OLD_LDFLAGS
>    LIBS=$OLD_LIBS
>  if test "$gdb_cv_var_elf" = yes; then
> -  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
> +  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
>  
>  $as_echo "#define HAVE_ELF 1" >>confdefs.h
>  
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index 618c59166e4..db765af0577 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -1882,7 +1882,7 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
>  GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
>                   [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
>  if test "$gdb_cv_var_elf" = yes; then
> -  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
> +  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
>    AC_DEFINE(HAVE_ELF, 1,
>  	    [Define if ELF support should be included.])
>    # -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
> diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
> index cc51e921ae2..dc4278cd644 100644
> --- a/gdb/fbsd-tdep.c
> +++ b/gdb/fbsd-tdep.c
> @@ -32,6 +32,7 @@
>  
>  #include "elf-bfd.h"
>  #include "fbsd-tdep.h"
> +#include "gcore-elf.h"
>  
>  /* This enum is derived from FreeBSD's <sys/signal.h>.  */
>  
> @@ -583,129 +584,6 @@ find_signalled_thread (struct thread_info *info, void *data)
>    return 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
> -{
> -  fbsd_collect_regset_section_cb_data (const struct regcache *regcache,
> -				       bfd *obfd,
> -				       gdb::unique_xmalloc_ptr<char> &note_data,
> -				       int *note_size,
> -				       unsigned long lwp,
> -				       gdb_signal stop_signal)
> -    : regcache (regcache),
> -      obfd (obfd),
> -      note_data (note_data),
> -      note_size (note_size),
> -      lwp (lwp),
> -      stop_signal (stop_signal)
> -  {}
> -
> -  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;
> -};
> -
> -static void
> -fbsd_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)
> -{
> -  char *buf;
> -  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 (collect_size);
> -  regset->collect_regset (regset, data->regcache, -1, buf, 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));
> -  else
> -    data->note_data.reset (elfcore_write_register_note
> -			     (data->obfd, data->note_data.release (),
> -			      data->note_size, sect_name, buf,
> -			      collect_size));
> -  xfree (buf);
> -
> -  if (data->note_data == NULL)
> -    data->abort_iteration = true;
> -}
> -
> -/* Records the thread's register state for the corefile note
> -   section.  */
> -
> -static void
> -fbsd_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)
> -{
> -  fbsd_collect_regset_section_cb_data data (regcache, obfd, note_data,
> -					    note_size, ptid.lwp (),
> -					    stop_signal);
> -
> -  gdbarch_iterate_over_regset_sections (regcache->arch (),
> -					fbsd_collect_regset_section_cb,
> -					&data, regcache);
> -}
> -
> -struct fbsd_corefile_thread_data
> -{
> -  fbsd_corefile_thread_data (struct gdbarch *gdbarch,
> -			     bfd *obfd,
> -			     gdb::unique_xmalloc_ptr<char> &note_data,
> -			     int *note_size,
> -			     gdb_signal stop_signal)
> -    : gdbarch (gdbarch),
> -      obfd (obfd),
> -      note_data (note_data),
> -      note_size (note_size),
> -      stop_signal (stop_signal)
> -  {}
> -
> -  struct gdbarch *gdbarch;
> -  bfd *obfd;
> -  gdb::unique_xmalloc_ptr<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 regcache *regcache;
> -
> -  regcache = get_thread_arch_regcache (info->inf->process_target (),
> -				       info->ptid, args->gdbarch);
> -
> -  target_fetch_registers (regcache, -1);
> -
> -  fbsd_collect_thread_registers (regcache, info->ptid, args->obfd,
> -				 args->note_data, args->note_size,
> -				 args->stop_signal);
> -}
> -
>  /* Return a byte_vector containing the contents of a core dump note
>     for the target object of type OBJECT.  If STRUCTSIZE is non-zero,
>     the data is prefixed with a 32-bit integer size to match the format
> @@ -782,16 +660,16 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
>  	signalled_thr = curr_thr;
>      }
>  
> -  fbsd_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
> -					 signalled_thr->suspend.stop_signal);
> -
> -  fbsd_corefile_thread (signalled_thr, &thread_args);
> +  enum gdb_signal stop_signal = signalled_thr->suspend.stop_signal;
> +  gcore_elf_build_thread_register_notes (gdbarch, signalled_thr, stop_signal,
> +					 obfd, &note_data, note_size);
>    for (thread_info *thr : current_inferior ()->non_exited_threads ())
>      {
>        if (thr == signalled_thr)
>  	continue;
>  
> -      fbsd_corefile_thread (thr, &thread_args);
> +      gcore_elf_build_thread_register_notes (gdbarch, thr, stop_signal,
> +					     obfd, &note_data, note_size);
>      }
>  
>    /* Auxiliary vector.  */
> diff --git a/gdb/gcore-elf.c b/gdb/gcore-elf.c
> new file mode 100644
> index 00000000000..ebc94277d35
> --- /dev/null
> +++ b/gdb/gcore-elf.c
> @@ -0,0 +1,136 @@
> +/* Copyright (C) 2021 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "gcore-elf.h"
> +#include "elf-bfd.h"
> +#include "target.h"
> +#include "regcache.h"
> +#include "gdbarch.h"
> +#include "gdbthread.h"
> +#include "inferior.h"
> +#include "regset.h"
> +
> +/* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS
> +   via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */
> +
> +struct gcore_elf_collect_regset_section_cb_data
> +{
> +  gcore_elf_collect_regset_section_cb_data
> +	(struct gdbarch *gdbarch, const struct regcache *regcache,
> +	 bfd *obfd, ptid_t ptid, gdb_signal stop_signal,
> +	 gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
> +    : gdbarch (gdbarch), regcache (regcache), obfd (obfd),
> +      note_data (note_data), note_size (note_size),
> +      stop_signal (stop_signal)
> +  {
> +    /* The LWP is often not available for bare metal target, in which case
> +       use the tid instead.  */
> +    if (ptid.lwp_p ())
> +      lwp = ptid.lwp ();
> +    else
> +      lwp = ptid.tid ();
> +  }
> +
> +  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 core file note section.  */
> +
> +static void
> +gcore_elf_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 gcore_elf_collect_regset_section_cb_data *data
> +    = (struct gcore_elf_collect_regset_section_cb_data *) cb_data;
> +  bool variable_size_section = (regset != NULL
> +				&& regset->flags & REGSET_VARIABLE_SIZE);
> +

Hi,

Maybe 'regset != nullptr'?

> +  gdb_assert (variable_size_section || supply_size == collect_size);
> +
> +  if (data->abort_iteration)
> +    return;
> +
> +  gdb_assert (regset != nullptr && regset->collect_regset != nullptr);
> +
> +  /* 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 == nullptr)
> +    data->abort_iteration = true;

I think you want '*data->note_data == nullptr' here.

data->note_data cannot be null (otherwise one of the
data->note_data->reset would have caused problem). It is the value
within the unique_ptr you are interested in.

Looks like this comes from a refactoring issue. In the original code,
note_data was a ref instead of a pointer (in both fbsd and linux side).
May ask why you changed it to a pointer? Is that to handle that param
similarly to other which are referred to by pointer?

Lancelot.

> +}
> +
> +/* Records the register state of thread PTID out of REGCACHE into the note
> +   buffer represented by *NOTE_DATA and NOTE_SIZE.  OBFD is the bfd into
> +   which the core file is being created, and STOP_SIGNAL is the signal that
> +   cause thread PTID to stop.  */
> +
> +static void
> +gcore_elf_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 ();
> +  gcore_elf_collect_regset_section_cb_data data (gdbarch, regcache, obfd,
> +						 ptid, stop_signal,
> +						 note_data, note_size);
> +  gdbarch_iterate_over_regset_sections
> +    (gdbarch, gcore_elf_collect_regset_section_cb, &data, regcache);
> +}
> +
> +/* See gcore-elf.h.  */
> +
> +void
> +gcore_elf_build_thread_register_notes
> +  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
> +   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
> +{
> +  struct regcache *regcache
> +    = get_thread_arch_regcache (info->inf->process_target (),
> +				info->ptid, gdbarch);
> +  target_fetch_registers (regcache, -1);
> +  gcore_elf_collect_thread_registers (regcache, info->ptid, obfd,
> +				      note_data, note_size, stop_signal);
> +}
> diff --git a/gdb/gcore-elf.h b/gdb/gcore-elf.h
> new file mode 100644
> index 00000000000..d667686adc7
> --- /dev/null
> +++ b/gdb/gcore-elf.h
> @@ -0,0 +1,39 @@
> +/* Copyright (C) 2021 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* This file contains generic functions for writing ELF based core files.  */
> +
> +#if !defined (GCORE_ELF_H)
> +#define GCORE_ELF_H 1
> +
> +#include "gdb_bfd.h"
> +#include "gdbsupport/gdb_signals.h"
> +#include "gcore.h"
> +
> +struct gdbarch;
> +struct thread_info;
> +
> +/* Add content to *NOTE_DATA (and update *NOTE_SIZE) to describe the
> +   registers of thread INFO.  Report the thread as having stopped with
> +   STOP_SIGNAL.  The core file is being written to OBFD, and GDBARCH is the
> +   architecture for which the core file is being generated.  */
> +
> +extern void gcore_elf_build_thread_register_notes
> +  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
> +   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size);
> +
> +#endif /* GCORE_ELF_H */
> diff --git a/gdb/gcore.c b/gdb/gcore.c
> index 73ac6b09c70..3b9025322f3 100644
> --- a/gdb/gcore.c
> +++ b/gdb/gcore.c
> @@ -579,6 +579,27 @@ gcore_memory_sections (bfd *obfd)
>    return 1;
>  }
>  
> +/* See gcore.h.  */
> +
> +thread_info *
> +gcore_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;
> +}
> +
>  void _initialize_gcore ();
>  void
>  _initialize_gcore ()
> diff --git a/gdb/gcore.h b/gdb/gcore.h
> index af37ff39b41..7e8e316926b 100644
> --- a/gdb/gcore.h
> +++ b/gdb/gcore.h
> @@ -22,10 +22,19 @@
>  
>  #include "gdb_bfd.h"
>  
> +struct thread_info;
> +
>  extern gdb_bfd_ref_ptr create_gcore_bfd (const char *filename);
>  extern void write_gcore_file (bfd *obfd);
>  extern int objfile_find_memory_regions (struct target_ops *self,
>  					find_memory_region_ftype func,
>  					void *obfd);
>  
> +/* 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.  */
> +
> +extern thread_info *gcore_find_signalled_thread ();
> +
>  #endif /* GCORE_H */
> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
> index e9f8e1b6133..5bfd82d1673 100644
> --- a/gdb/linux-tdep.c
> +++ b/gdb/linux-tdep.c
> @@ -39,6 +39,8 @@
>  #include "gdb_regex.h"
>  #include "gdbsupport/enum-flags.h"
>  #include "gdbsupport/gdb_optional.h"
> +#include "gcore.h"
> +#include "gcore-elf.h"
>  
>  #include <ctype.h>
>  
> @@ -1597,104 +1599,6 @@ 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.  */
> @@ -1746,22 +1650,17 @@ static void
>  linux_corefile_thread (struct thread_info *info,
>  		       struct linux_corefile_thread_data *args)
>  {
> -  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);
> +  gcore_elf_build_thread_register_notes (args->gdbarch, info,
> +					 args->stop_signal,
> +					 args->obfd, &args->note_data,
> +					 args->note_size);
>  
>    /* 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 (),
> @@ -1960,30 +1859,6 @@ 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.  */
>  
> @@ -2021,7 +1896,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 = find_signalled_thread ();
> +  thread_info *signalled_thr = gcore_find_signalled_thread ();
>    gdb_signal stop_signal;
>    if (signalled_thr != nullptr)
>      stop_signal = signalled_thr->suspend.stop_signal;
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv3 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code
  2021-02-15 22:56     ` Lancelot SIX
@ 2021-02-16 16:55       ` Andrew Burgess
  0 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-02-16 16:55 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches, binutils

* Lancelot SIX <lsix@lancelotsix.com> [2021-02-15 22:56:14 +0000]:

> Le Mon, Feb 15, 2021 at 05:29:04PM +0000, Andrew Burgess a écrit :
> > While reviewing the Linux and FreeBSD core dumping code within GDB for
> > another patch series, I noticed that the code that collects the
> > registers for each thread and writes these into ELF note format is
> > basically identical between Linux and FreeBSD.
> > 
> > This commit merges this code and moves it into a new file gcore-elf.c.
> > 
> > The function find_signalled_thread is moved from linux-tdep.c to
> > gcore.c despite not being shared.  A later commit will make use of
> > this function.
> > 
> > I did merge, and then revert a previous version of this patch (commit
> > 82a1fd3a4935 for the original patch and 03642b7189bc for the revert).
> > The problem with the original patch is that it introduced a
> > unconditional dependency between GDB and some ELF specific functions
> > in the BFD library, e.g. elfcore_write_prstatus and
> > elfcore_write_register_note.  It was pointed out in this mailing list
> > post:
> > 
> >   https://sourceware.org/pipermail/gdb-patches/2021-February/175750.html
> > 
> > that this change was breaking any build of GDB for non-ELF targets.
> > To confirm this breakage, and to test this new version of GDB I
> > configured and built for the target x86_64-apple-darwin20.3.0.
> > 
> > Where the previous version of this patch placed all of the common code
> > into gcore.c, which is included in all builds of GDB, this new patch
> > only places non-ELF specific generic code (i.e. find_signalled_thread)
> > into gcore.c, the ELF specific code is put into the new gcore-elf.c
> > file, which is only included in GDB if BFD has ELF support.
> > 
> > The contents of gcore-elf.c are referenced unconditionally from
> > linux-tdep.c and fbsd-tdep.c, this is fine, we previously always
> > assumed that these two targets required ELF support, and we continue
> > to make that assumption after this patch; nothing has changed there.
> > 
> > With my previous version of this patch the darwin target mentioned
> > above failed to build, but with the new version, the target builds
> > fine.
> > 
> > There are a couple of minor changes to the FreeBSD target after this
> > commit, but I believe that these are changes for the better:
> > 
> > (1) For FreeBSD we always used to record the thread-id in the core
> > file by using ptid_t.lwp ().  In contrast the Linux code did this:
> > 
> >     /* For remote targets the LWP may not be available, so use the TID.  */
> >     long lwp = ptid.lwp ();
> >     if (lwp == 0)
> >       lwp = ptid.tid ();
> > 
> > Both target now do this:
> > 
> >     /* The LWP is often not available for bare metal target, in which case
> >        use the tid instead.  */
> >     if (ptid.lwp_p ())
> >       lwp = ptid.lwp ();
> >     else
> >       lwp = ptid.tid ();
> > 
> > Which is equivalent for Linux, but is a change for FreeBSD.  I think
> > that all this means is that in some cases where GDB might have
> > previously recorded a thread-id of 0 for each thread, we might now get
> > something more useful.
> > 
> > (2) When collecting the registers for Linux we collected into a zero
> > initialised buffer.  By contrast on FreeBSD the buffer is left
> > uninitialised.  In the new code the buffer is always zero initialised.
> > I suspect once the registers are copied into the buffer there's
> > probably no gaps left so this makes no difference, but if it does then
> > using zeros rather than random bits of GDB's memory is probably a good
> > thing.
> > 
> > Otherwise, there should be no other user visible changes after this
> > commit.
> > 
> > Tested this on x86-64/GNU-Linux and x86-64/FreeBSD-12.2 with no
> > regressions.
> > 
> > gdb/ChangeLog:
> > 
> > 	* Makefile.in (SFILES): Add gcore-elf.c.
> > 	(HFILES_NO_SRCDIR): Add gcore-elf.h
> > 	* configure: Regenerate.
> > 	* configure.ac: Add gcore-elf.o to CONFIG_OBS if we have ELF
> > 	support.
> > 	* fbsd-tdep.c: Add 'gcore-elf.h' include.
> > 	(struct fbsd_collect_regset_section_cb_data): Delete.
> > 	(fbsd_collect_regset_section_cb): Delete.
> > 	(fbsd_collect_thread_registers): Delete.
> > 	(struct fbsd_corefile_thread_data): Delete.
> > 	(fbsd_corefile_thread): Delete.
> > 	(fbsd_make_corefile_notes): Call
> > 	gcore_elf_build_thread_register_notes instead of the now deleted
> > 	FreeBSD code.
> > 	* gcore-elf.c: New file, the content was moved here from
> > 	linux-tdep.c, functions were renamed and given minor cleanup.
> > 	* gcore-elf.h: New file.
> > 	* gcore.c (gcore_find_signalled_thread): Moved here from
> > 	linux-tdep.c and given a new name.  Minor cleanups.
> > 	* gcore.h (gcore_find_signalled_thread): Declare.
> > 	* linux-tdep.c: Add 'gcore.h' and 'gcore-elf.h' includes.
> > 	(struct linux_collect_regset_section_cb_data): Delete.
> > 	(linux_collect_regset_section_cb): Delete.
> > 	(linux_collect_thread_registers): Delete.
> > 	(linux_corefile_thread): Call
> > 	gcore_elf_build_thread_register_notes.
> > 	(find_signalled_thread): Delete.
> > 	(linux_make_corefile_notes): Call gcore_find_signalled_thread.
> > ---
> >  gdb/ChangeLog    |  31 ++++++++++
> >  gdb/Makefile.in  |   2 +
> >  gdb/configure    |   2 +-
> >  gdb/configure.ac |   2 +-
> >  gdb/fbsd-tdep.c  | 134 ++------------------------------------------
> >  gdb/gcore-elf.c  | 136 ++++++++++++++++++++++++++++++++++++++++++++
> >  gdb/gcore-elf.h  |  39 +++++++++++++
> >  gdb/gcore.c      |  21 +++++++
> >  gdb/gcore.h      |   9 +++
> >  gdb/linux-tdep.c | 143 +++--------------------------------------------
> >  10 files changed, 255 insertions(+), 264 deletions(-)
> >  create mode 100644 gdb/gcore-elf.c
> >  create mode 100644 gdb/gcore-elf.h
> > 
> > diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> > index ae89b85eb56..cf5017e7f66 100644
> > --- a/gdb/Makefile.in
> > +++ b/gdb/Makefile.in
> > @@ -1191,6 +1191,7 @@ SFILES = \
> >  	dtrace-probe.c \
> >  	elfread.c \
> >  	f-exp.y \
> > +	gcore-elf.c \
> >  	gdb.c \
> >  	go-exp.y \
> >  	m2-exp.y \
> > @@ -1292,6 +1293,7 @@ HFILES_NO_SRCDIR = \
> >  	frame-unwind.h \
> >  	frv-tdep.h \
> >  	ft32-tdep.h \
> > +	gcore-elf.h \
> >  	gcore.h \
> >  	gdb_bfd.h \
> >  	gdb_curses.h \
> > diff --git a/gdb/configure b/gdb/configure
> > index 51b4d1921c5..4707fd01174 100755
> > --- a/gdb/configure
> > +++ b/gdb/configure
> > @@ -17264,7 +17264,7 @@ $as_echo "$gdb_cv_var_elf" >&6; }
> >    LDFLAGS=$OLD_LDFLAGS
> >    LIBS=$OLD_LIBS
> >  if test "$gdb_cv_var_elf" = yes; then
> > -  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
> > +  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
> >  
> >  $as_echo "#define HAVE_ELF 1" >>confdefs.h
> >  
> > diff --git a/gdb/configure.ac b/gdb/configure.ac
> > index 618c59166e4..db765af0577 100644
> > --- a/gdb/configure.ac
> > +++ b/gdb/configure.ac
> > @@ -1882,7 +1882,7 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
> >  GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
> >                   [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
> >  if test "$gdb_cv_var_elf" = yes; then
> > -  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
> > +  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
> >    AC_DEFINE(HAVE_ELF, 1,
> >  	    [Define if ELF support should be included.])
> >    # -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
> > diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
> > index cc51e921ae2..dc4278cd644 100644
> > --- a/gdb/fbsd-tdep.c
> > +++ b/gdb/fbsd-tdep.c
> > @@ -32,6 +32,7 @@
> >  
> >  #include "elf-bfd.h"
> >  #include "fbsd-tdep.h"
> > +#include "gcore-elf.h"
> >  
> >  /* This enum is derived from FreeBSD's <sys/signal.h>.  */
> >  
> > @@ -583,129 +584,6 @@ find_signalled_thread (struct thread_info *info, void *data)
> >    return 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
> > -{
> > -  fbsd_collect_regset_section_cb_data (const struct regcache *regcache,
> > -				       bfd *obfd,
> > -				       gdb::unique_xmalloc_ptr<char> &note_data,
> > -				       int *note_size,
> > -				       unsigned long lwp,
> > -				       gdb_signal stop_signal)
> > -    : regcache (regcache),
> > -      obfd (obfd),
> > -      note_data (note_data),
> > -      note_size (note_size),
> > -      lwp (lwp),
> > -      stop_signal (stop_signal)
> > -  {}
> > -
> > -  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;
> > -};
> > -
> > -static void
> > -fbsd_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)
> > -{
> > -  char *buf;
> > -  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 (collect_size);
> > -  regset->collect_regset (regset, data->regcache, -1, buf, 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));
> > -  else
> > -    data->note_data.reset (elfcore_write_register_note
> > -			     (data->obfd, data->note_data.release (),
> > -			      data->note_size, sect_name, buf,
> > -			      collect_size));
> > -  xfree (buf);
> > -
> > -  if (data->note_data == NULL)
> > -    data->abort_iteration = true;
> > -}
> > -
> > -/* Records the thread's register state for the corefile note
> > -   section.  */
> > -
> > -static void
> > -fbsd_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)
> > -{
> > -  fbsd_collect_regset_section_cb_data data (regcache, obfd, note_data,
> > -					    note_size, ptid.lwp (),
> > -					    stop_signal);
> > -
> > -  gdbarch_iterate_over_regset_sections (regcache->arch (),
> > -					fbsd_collect_regset_section_cb,
> > -					&data, regcache);
> > -}
> > -
> > -struct fbsd_corefile_thread_data
> > -{
> > -  fbsd_corefile_thread_data (struct gdbarch *gdbarch,
> > -			     bfd *obfd,
> > -			     gdb::unique_xmalloc_ptr<char> &note_data,
> > -			     int *note_size,
> > -			     gdb_signal stop_signal)
> > -    : gdbarch (gdbarch),
> > -      obfd (obfd),
> > -      note_data (note_data),
> > -      note_size (note_size),
> > -      stop_signal (stop_signal)
> > -  {}
> > -
> > -  struct gdbarch *gdbarch;
> > -  bfd *obfd;
> > -  gdb::unique_xmalloc_ptr<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 regcache *regcache;
> > -
> > -  regcache = get_thread_arch_regcache (info->inf->process_target (),
> > -				       info->ptid, args->gdbarch);
> > -
> > -  target_fetch_registers (regcache, -1);
> > -
> > -  fbsd_collect_thread_registers (regcache, info->ptid, args->obfd,
> > -				 args->note_data, args->note_size,
> > -				 args->stop_signal);
> > -}
> > -
> >  /* Return a byte_vector containing the contents of a core dump note
> >     for the target object of type OBJECT.  If STRUCTSIZE is non-zero,
> >     the data is prefixed with a 32-bit integer size to match the format
> > @@ -782,16 +660,16 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
> >  	signalled_thr = curr_thr;
> >      }
> >  
> > -  fbsd_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
> > -					 signalled_thr->suspend.stop_signal);
> > -
> > -  fbsd_corefile_thread (signalled_thr, &thread_args);
> > +  enum gdb_signal stop_signal = signalled_thr->suspend.stop_signal;
> > +  gcore_elf_build_thread_register_notes (gdbarch, signalled_thr, stop_signal,
> > +					 obfd, &note_data, note_size);
> >    for (thread_info *thr : current_inferior ()->non_exited_threads ())
> >      {
> >        if (thr == signalled_thr)
> >  	continue;
> >  
> > -      fbsd_corefile_thread (thr, &thread_args);
> > +      gcore_elf_build_thread_register_notes (gdbarch, thr, stop_signal,
> > +					     obfd, &note_data, note_size);
> >      }
> >  
> >    /* Auxiliary vector.  */
> > diff --git a/gdb/gcore-elf.c b/gdb/gcore-elf.c
> > new file mode 100644
> > index 00000000000..ebc94277d35
> > --- /dev/null
> > +++ b/gdb/gcore-elf.c
> > @@ -0,0 +1,136 @@
> > +/* Copyright (C) 2021 Free Software Foundation, Inc.
> > +
> > +   This file is part of GDB.
> > +
> > +   This program is free software; you can redistribute it and/or modify
> > +   it under the terms of the GNU General Public License as published by
> > +   the Free Software Foundation; either version 3 of the License, or
> > +   (at your option) any later version.
> > +
> > +   This program is distributed in the hope that it will be useful,
> > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > +   GNU General Public License for more details.
> > +
> > +   You should have received a copy of the GNU General Public License
> > +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> > +
> > +#include "defs.h"
> > +#include "gcore-elf.h"
> > +#include "elf-bfd.h"
> > +#include "target.h"
> > +#include "regcache.h"
> > +#include "gdbarch.h"
> > +#include "gdbthread.h"
> > +#include "inferior.h"
> > +#include "regset.h"
> > +
> > +/* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS
> > +   via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */
> > +
> > +struct gcore_elf_collect_regset_section_cb_data
> > +{
> > +  gcore_elf_collect_regset_section_cb_data
> > +	(struct gdbarch *gdbarch, const struct regcache *regcache,
> > +	 bfd *obfd, ptid_t ptid, gdb_signal stop_signal,
> > +	 gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
> > +    : gdbarch (gdbarch), regcache (regcache), obfd (obfd),
> > +      note_data (note_data), note_size (note_size),
> > +      stop_signal (stop_signal)
> > +  {
> > +    /* The LWP is often not available for bare metal target, in which case
> > +       use the tid instead.  */
> > +    if (ptid.lwp_p ())
> > +      lwp = ptid.lwp ();
> > +    else
> > +      lwp = ptid.tid ();
> > +  }
> > +
> > +  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 core file note section.  */
> > +
> > +static void
> > +gcore_elf_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 gcore_elf_collect_regset_section_cb_data *data
> > +    = (struct gcore_elf_collect_regset_section_cb_data *) cb_data;
> > +  bool variable_size_section = (regset != NULL
> > +				&& regset->flags & REGSET_VARIABLE_SIZE);
> > +
> 
> Hi,
> 
> Maybe 'regset != nullptr'?
> 
> > +  gdb_assert (variable_size_section || supply_size == collect_size);
> > +
> > +  if (data->abort_iteration)
> > +    return;
> > +
> > +  gdb_assert (regset != nullptr && regset->collect_regset != nullptr);
> > +
> > +  /* 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 == nullptr)
> > +    data->abort_iteration = true;
> 
> I think you want '*data->note_data == nullptr' here.

Thanks for pointing out both of these issues.  I've addressed them in
the revised patch below.

> Looks like this comes from a refactoring issue. In the original code,
> note_data was a ref instead of a pointer (in both fbsd and linux side).
> May ask why you changed it to a pointer? Is that to handle that param
> similarly to other which are referred to by pointer?

I was pretty sure that the coding standard said references are OK for
read-only values, but parameters that can be modified should be passed
as pointer.

I went to look this up on the coding standard wiki and couldn't find
any mention of this rule.  But I'm sure I remember this being a thing
at one point.

Thanks,
Andrew

---

commit 17e785148f34bb0fef9ec87390a9d779a0efae1a
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Mon Jan 18 16:00:38 2021 +0000

    gdb: unify parts of the Linux and FreeBSD core dumping code
    
    While reviewing the Linux and FreeBSD core dumping code within GDB for
    another patch series, I noticed that the code that collects the
    registers for each thread and writes these into ELF note format is
    basically identical between Linux and FreeBSD.
    
    This commit merges this code and moves it into a new file gcore-elf.c.
    
    The function find_signalled_thread is moved from linux-tdep.c to
    gcore.c despite not being shared.  A later commit will make use of
    this function.
    
    I did merge, and then revert a previous version of this patch (commit
    82a1fd3a4935 for the original patch and 03642b7189bc for the revert).
    The problem with the original patch is that it introduced a
    unconditional dependency between GDB and some ELF specific functions
    in the BFD library, e.g. elfcore_write_prstatus and
    elfcore_write_register_note.  It was pointed out in this mailing list
    post:
    
      https://sourceware.org/pipermail/gdb-patches/2021-February/175750.html
    
    that this change was breaking any build of GDB for non-ELF targets.
    To confirm this breakage, and to test this new version of GDB I
    configured and built for the target x86_64-apple-darwin20.3.0.
    
    Where the previous version of this patch placed all of the common code
    into gcore.c, which is included in all builds of GDB, this new patch
    only places non-ELF specific generic code (i.e. find_signalled_thread)
    into gcore.c, the ELF specific code is put into the new gcore-elf.c
    file, which is only included in GDB if BFD has ELF support.
    
    The contents of gcore-elf.c are referenced unconditionally from
    linux-tdep.c and fbsd-tdep.c, this is fine, we previously always
    assumed that these two targets required ELF support, and we continue
    to make that assumption after this patch; nothing has changed there.
    
    With my previous version of this patch the darwin target mentioned
    above failed to build, but with the new version, the target builds
    fine.
    
    There are a couple of minor changes to the FreeBSD target after this
    commit, but I believe that these are changes for the better:
    
    (1) For FreeBSD we always used to record the thread-id in the core
    file by using ptid_t.lwp ().  In contrast the Linux code did this:
    
        /* For remote targets the LWP may not be available, so use the TID.  */
        long lwp = ptid.lwp ();
        if (lwp == 0)
          lwp = ptid.tid ();
    
    Both target now do this:
    
        /* The LWP is often not available for bare metal target, in which case
           use the tid instead.  */
        if (ptid.lwp_p ())
          lwp = ptid.lwp ();
        else
          lwp = ptid.tid ();
    
    Which is equivalent for Linux, but is a change for FreeBSD.  I think
    that all this means is that in some cases where GDB might have
    previously recorded a thread-id of 0 for each thread, we might now get
    something more useful.
    
    (2) When collecting the registers for Linux we collected into a zero
    initialised buffer.  By contrast on FreeBSD the buffer is left
    uninitialised.  In the new code the buffer is always zero initialised.
    I suspect once the registers are copied into the buffer there's
    probably no gaps left so this makes no difference, but if it does then
    using zeros rather than random bits of GDB's memory is probably a good
    thing.
    
    Otherwise, there should be no other user visible changes after this
    commit.
    
    Tested this on x86-64/GNU-Linux and x86-64/FreeBSD-12.2 with no
    regressions.
    
    gdb/ChangeLog:
    
            * Makefile.in (SFILES): Add gcore-elf.c.
            (HFILES_NO_SRCDIR): Add gcore-elf.h
            * configure: Regenerate.
            * configure.ac: Add gcore-elf.o to CONFIG_OBS if we have ELF
            support.
            * fbsd-tdep.c: Add 'gcore-elf.h' include.
            (struct fbsd_collect_regset_section_cb_data): Delete.
            (fbsd_collect_regset_section_cb): Delete.
            (fbsd_collect_thread_registers): Delete.
            (struct fbsd_corefile_thread_data): Delete.
            (fbsd_corefile_thread): Delete.
            (fbsd_make_corefile_notes): Call
            gcore_elf_build_thread_register_notes instead of the now deleted
            FreeBSD code.
            * gcore-elf.c: New file, the content was moved here from
            linux-tdep.c, functions were renamed and given minor cleanup.
            * gcore-elf.h: New file.
            * gcore.c (gcore_find_signalled_thread): Moved here from
            linux-tdep.c and given a new name.  Minor cleanups.
            * gcore.h (gcore_find_signalled_thread): Declare.
            * linux-tdep.c: Add 'gcore.h' and 'gcore-elf.h' includes.
            (struct linux_collect_regset_section_cb_data): Delete.
            (linux_collect_regset_section_cb): Delete.
            (linux_collect_thread_registers): Delete.
            (linux_corefile_thread): Call
            gcore_elf_build_thread_register_notes.
            (find_signalled_thread): Delete.
            (linux_make_corefile_notes): Call gcore_find_signalled_thread.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ae89b85eb56..cf5017e7f66 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1191,6 +1191,7 @@ SFILES = \
 	dtrace-probe.c \
 	elfread.c \
 	f-exp.y \
+	gcore-elf.c \
 	gdb.c \
 	go-exp.y \
 	m2-exp.y \
@@ -1292,6 +1293,7 @@ HFILES_NO_SRCDIR = \
 	frame-unwind.h \
 	frv-tdep.h \
 	ft32-tdep.h \
+	gcore-elf.h \
 	gcore.h \
 	gdb_bfd.h \
 	gdb_curses.h \
diff --git a/gdb/configure b/gdb/configure
index 51b4d1921c5..4707fd01174 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -17264,7 +17264,7 @@ $as_echo "$gdb_cv_var_elf" >&6; }
   LDFLAGS=$OLD_LDFLAGS
   LIBS=$OLD_LIBS
 if test "$gdb_cv_var_elf" = yes; then
-  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
+  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
 
 $as_echo "#define HAVE_ELF 1" >>confdefs.h
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 618c59166e4..db765af0577 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1882,7 +1882,7 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
 GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
                  [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
 if test "$gdb_cv_var_elf" = yes; then
-  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
+  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o gcore-elf.o"
   AC_DEFINE(HAVE_ELF, 1,
 	    [Define if ELF support should be included.])
   # -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index cc51e921ae2..dc4278cd644 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -32,6 +32,7 @@
 
 #include "elf-bfd.h"
 #include "fbsd-tdep.h"
+#include "gcore-elf.h"
 
 /* This enum is derived from FreeBSD's <sys/signal.h>.  */
 
@@ -583,129 +584,6 @@ find_signalled_thread (struct thread_info *info, void *data)
   return 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
-{
-  fbsd_collect_regset_section_cb_data (const struct regcache *regcache,
-				       bfd *obfd,
-				       gdb::unique_xmalloc_ptr<char> &note_data,
-				       int *note_size,
-				       unsigned long lwp,
-				       gdb_signal stop_signal)
-    : regcache (regcache),
-      obfd (obfd),
-      note_data (note_data),
-      note_size (note_size),
-      lwp (lwp),
-      stop_signal (stop_signal)
-  {}
-
-  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;
-};
-
-static void
-fbsd_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)
-{
-  char *buf;
-  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 (collect_size);
-  regset->collect_regset (regset, data->regcache, -1, buf, 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));
-  else
-    data->note_data.reset (elfcore_write_register_note
-			     (data->obfd, data->note_data.release (),
-			      data->note_size, sect_name, buf,
-			      collect_size));
-  xfree (buf);
-
-  if (data->note_data == NULL)
-    data->abort_iteration = true;
-}
-
-/* Records the thread's register state for the corefile note
-   section.  */
-
-static void
-fbsd_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)
-{
-  fbsd_collect_regset_section_cb_data data (regcache, obfd, note_data,
-					    note_size, ptid.lwp (),
-					    stop_signal);
-
-  gdbarch_iterate_over_regset_sections (regcache->arch (),
-					fbsd_collect_regset_section_cb,
-					&data, regcache);
-}
-
-struct fbsd_corefile_thread_data
-{
-  fbsd_corefile_thread_data (struct gdbarch *gdbarch,
-			     bfd *obfd,
-			     gdb::unique_xmalloc_ptr<char> &note_data,
-			     int *note_size,
-			     gdb_signal stop_signal)
-    : gdbarch (gdbarch),
-      obfd (obfd),
-      note_data (note_data),
-      note_size (note_size),
-      stop_signal (stop_signal)
-  {}
-
-  struct gdbarch *gdbarch;
-  bfd *obfd;
-  gdb::unique_xmalloc_ptr<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 regcache *regcache;
-
-  regcache = get_thread_arch_regcache (info->inf->process_target (),
-				       info->ptid, args->gdbarch);
-
-  target_fetch_registers (regcache, -1);
-
-  fbsd_collect_thread_registers (regcache, info->ptid, args->obfd,
-				 args->note_data, args->note_size,
-				 args->stop_signal);
-}
-
 /* Return a byte_vector containing the contents of a core dump note
    for the target object of type OBJECT.  If STRUCTSIZE is non-zero,
    the data is prefixed with a 32-bit integer size to match the format
@@ -782,16 +660,16 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
 	signalled_thr = curr_thr;
     }
 
-  fbsd_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
-					 signalled_thr->suspend.stop_signal);
-
-  fbsd_corefile_thread (signalled_thr, &thread_args);
+  enum gdb_signal stop_signal = signalled_thr->suspend.stop_signal;
+  gcore_elf_build_thread_register_notes (gdbarch, signalled_thr, stop_signal,
+					 obfd, &note_data, note_size);
   for (thread_info *thr : current_inferior ()->non_exited_threads ())
     {
       if (thr == signalled_thr)
 	continue;
 
-      fbsd_corefile_thread (thr, &thread_args);
+      gcore_elf_build_thread_register_notes (gdbarch, thr, stop_signal,
+					     obfd, &note_data, note_size);
     }
 
   /* Auxiliary vector.  */
diff --git a/gdb/gcore-elf.c b/gdb/gcore-elf.c
new file mode 100644
index 00000000000..b0fb808fae0
--- /dev/null
+++ b/gdb/gcore-elf.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "gcore-elf.h"
+#include "elf-bfd.h"
+#include "target.h"
+#include "regcache.h"
+#include "gdbarch.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "regset.h"
+
+/* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS
+   via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */
+
+struct gcore_elf_collect_regset_section_cb_data
+{
+  gcore_elf_collect_regset_section_cb_data
+	(struct gdbarch *gdbarch, const struct regcache *regcache,
+	 bfd *obfd, ptid_t ptid, gdb_signal stop_signal,
+	 gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
+    : gdbarch (gdbarch), regcache (regcache), obfd (obfd),
+      note_data (note_data), note_size (note_size),
+      stop_signal (stop_signal)
+  {
+    /* The LWP is often not available for bare metal target, in which case
+       use the tid instead.  */
+    if (ptid.lwp_p ())
+      lwp = ptid.lwp ();
+    else
+      lwp = ptid.tid ();
+  }
+
+  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 core file note section.  */
+
+static void
+gcore_elf_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 gcore_elf_collect_regset_section_cb_data *data
+    = (struct gcore_elf_collect_regset_section_cb_data *) cb_data;
+  bool variable_size_section = (regset != nullptr
+				&& regset->flags & REGSET_VARIABLE_SIZE);
+
+  gdb_assert (variable_size_section || supply_size == collect_size);
+
+  if (data->abort_iteration)
+    return;
+
+  gdb_assert (regset != nullptr && regset->collect_regset != nullptr);
+
+  /* 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 == nullptr)
+    data->abort_iteration = true;
+}
+
+/* Records the register state of thread PTID out of REGCACHE into the note
+   buffer represented by *NOTE_DATA and NOTE_SIZE.  OBFD is the bfd into
+   which the core file is being created, and STOP_SIGNAL is the signal that
+   cause thread PTID to stop.  */
+
+static void
+gcore_elf_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 ();
+  gcore_elf_collect_regset_section_cb_data data (gdbarch, regcache, obfd,
+						 ptid, stop_signal,
+						 note_data, note_size);
+  gdbarch_iterate_over_regset_sections
+    (gdbarch, gcore_elf_collect_regset_section_cb, &data, regcache);
+}
+
+/* See gcore-elf.h.  */
+
+void
+gcore_elf_build_thread_register_notes
+  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
+   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size)
+{
+  struct regcache *regcache
+    = get_thread_arch_regcache (info->inf->process_target (),
+				info->ptid, gdbarch);
+  target_fetch_registers (regcache, -1);
+  gcore_elf_collect_thread_registers (regcache, info->ptid, obfd,
+				      note_data, note_size, stop_signal);
+}
diff --git a/gdb/gcore-elf.h b/gdb/gcore-elf.h
new file mode 100644
index 00000000000..d667686adc7
--- /dev/null
+++ b/gdb/gcore-elf.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This file contains generic functions for writing ELF based core files.  */
+
+#if !defined (GCORE_ELF_H)
+#define GCORE_ELF_H 1
+
+#include "gdb_bfd.h"
+#include "gdbsupport/gdb_signals.h"
+#include "gcore.h"
+
+struct gdbarch;
+struct thread_info;
+
+/* Add content to *NOTE_DATA (and update *NOTE_SIZE) to describe the
+   registers of thread INFO.  Report the thread as having stopped with
+   STOP_SIGNAL.  The core file is being written to OBFD, and GDBARCH is the
+   architecture for which the core file is being generated.  */
+
+extern void gcore_elf_build_thread_register_notes
+  (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal,
+   bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size);
+
+#endif /* GCORE_ELF_H */
diff --git a/gdb/gcore.c b/gdb/gcore.c
index 73ac6b09c70..3b9025322f3 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -579,6 +579,27 @@ gcore_memory_sections (bfd *obfd)
   return 1;
 }
 
+/* See gcore.h.  */
+
+thread_info *
+gcore_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;
+}
+
 void _initialize_gcore ();
 void
 _initialize_gcore ()
diff --git a/gdb/gcore.h b/gdb/gcore.h
index af37ff39b41..7e8e316926b 100644
--- a/gdb/gcore.h
+++ b/gdb/gcore.h
@@ -22,10 +22,19 @@
 
 #include "gdb_bfd.h"
 
+struct thread_info;
+
 extern gdb_bfd_ref_ptr create_gcore_bfd (const char *filename);
 extern void write_gcore_file (bfd *obfd);
 extern int objfile_find_memory_regions (struct target_ops *self,
 					find_memory_region_ftype func,
 					void *obfd);
 
+/* 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.  */
+
+extern thread_info *gcore_find_signalled_thread ();
+
 #endif /* GCORE_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index e9f8e1b6133..5bfd82d1673 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -39,6 +39,8 @@
 #include "gdb_regex.h"
 #include "gdbsupport/enum-flags.h"
 #include "gdbsupport/gdb_optional.h"
+#include "gcore.h"
+#include "gcore-elf.h"
 
 #include <ctype.h>
 
@@ -1597,104 +1599,6 @@ 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.  */
@@ -1746,22 +1650,17 @@ static void
 linux_corefile_thread (struct thread_info *info,
 		       struct linux_corefile_thread_data *args)
 {
-  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);
+  gcore_elf_build_thread_register_notes (args->gdbarch, info,
+					 args->stop_signal,
+					 args->obfd, &args->note_data,
+					 args->note_size);
 
   /* 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 (),
@@ -1960,30 +1859,6 @@ 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.  */
 
@@ -2021,7 +1896,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 = find_signalled_thread ();
+  thread_info *signalled_thr = gcore_find_signalled_thread ();
   gdb_signal stop_signal;
   if (signalled_thr != nullptr)
     stop_signal = signalled_thr->suspend.stop_signal;

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv3 0/9] Bare-metal core dumps for RISC-V
  2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
                     ` (8 preceding siblings ...)
  2021-02-15 17:29   ` [PATCHv3 9/9] gdb/arm: add support for bare-metal " Andrew Burgess
@ 2021-03-01 10:32   ` Andrew Burgess
  2021-03-01 14:45     ` Nick Clifton
  2021-03-05 17:35     ` Andrew Burgess
  9 siblings, 2 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-03-01 10:32 UTC (permalink / raw)
  To: gdb-patches, binutils

Ping!

I'm planning to start merging this series later this week.  The code
was all reviewed in the v2 series.  The v3 mostly moves stuff around
to avoid adding dependencies on ELF support.

I still wonder if there's a better solution than the #ifdef block
added in patches 5 and 9, but these are pretty self-contained.  If
someone suggests a better approach later on then I'm happy to refactor
this code.

Thanks,
Andrew


* Andrew Burgess <andrew.burgess@embecosm.com> [2021-02-15 17:29:03 +0000]:

> After I pushed patch #1 from the v2 series it was pointed out that
> this broke any build of GDB for non-ELF targets.  I then reverted
> patch #1.  Now I'm back with an updated series.
> 
> For testing the build I have been using 'x86_64-apple-darwin20.3.0' as
> a non-ELF target.  I haven't done any actual functional testing on
> this target other than "it builds", but that's more than I did before
> (for non-ELF targets).
> 
> Between v2 and v3 then the changes are basically around the idea of
> not calling ELF specific functions from any generic code.  As far as
> possible I wanted to avoid just blocking code out with #ifdef, though
> I did use this trick in a limited way in patches #5 and #9, hopefully
> this is acceptable, though I'm open to suggestions for better ways to
> structure the code in these patches.
> 
> Here's a summary of which patches have changed:
> 
> (1) - Changed, common code from Linux and FreeBSD targets is now split
>       between gcore.c (for non-ELF code) and a new file gcore-elf.c
>       (for ELF specific code).  Changes to configure.ac ensure the ELF
>       specific file is only pulled in when needed.  This probably
>       needs a new review.
> 
> (2) - Minor updates to address Jim's review feedback.  Reviews are
>       welcome, but I'm considering this patch approved.
> 
> (3) - Code to add the target description note is moved to gcore-elf.c,
>       and each target must call this code (if the target is creating
>       an ELF based core file).  I don't like this as much as the
>       previous code where the target description note was added in one
>       place, but I can't see a good way to do this without adding a
>       #ifdef block to gcore.c.  This probably needs a new review.
> 
> (4) - Minor updates to address Jim's review feedback.  Reviews are
>       welcome, but I'm considering this patch approved.
> 
> (5) - The common bare metal core dump code is now in elf-none-tdep.c.
>       This is then called from the riscv-none-tdep.c code ONLY if we
>       have ELF support.  This is the use of '#ifdef HAVE_ELF' which is
>       a little yuck, but I can't see a better solution.  This probably
>       needs a new review.
> 
> (6) - Minor updates to address Jim's review feedback.  Reviews are
>       welcome, but I'm considering this patch approved.
> 
> (7) - No changes.  Reviews are welcome, but I'm considering this patch
>       approved.
> 
> (8) - No changes.  Reviews are welcome, but I'm considering this patch
>       approved.
> 
> (9) - No significant changes.  Like patch #5 it now includes a '#ifdef
>       HAVE_ELF' block in order to guard the call from arm-none-tdep.c
>       to elf-none-tdep.c.  I'd prefer reviews of this approach be
>       addressed to patch #5, I'll apply any feedback I get there to
>       this patch too.
> 
> ---
> 
> Andrew Burgess (9):
>   gdb: unify parts of the Linux and FreeBSD core dumping code
>   bfd/binutils: support for gdb target descriptions in the core file
>   gdb: write target description into core file
>   bfd/riscv: prepare to handle bare metal core dump creation
>   gdb/riscv: introduce bare metal core dump support
>   bfd/binutils: add support for RISC-V CSRs in core files
>   gdb/riscv: make riscv target description names global
>   gdb/riscv: write CSRs into baremetal core dumps
>   gdb/arm: add support for bare-metal core dumps
> 
>  bfd/ChangeLog         |  27 ++++++
>  bfd/elf-bfd.h         |   4 +
>  bfd/elf.c             |  70 ++++++++++++++
>  bfd/elfnn-riscv.c     |  84 ++++++++++++++++-
>  binutils/ChangeLog    |  10 ++
>  binutils/readelf.c    |   4 +
>  gdb/ChangeLog         |  88 +++++++++++++++++
>  gdb/Makefile.in       |   8 ++
>  gdb/arm-none-tdep.c   | 213 ++++++++++++++++++++++++++++++++++++++++++
>  gdb/configure         |   3 +-
>  gdb/configure.ac      |   3 +-
>  gdb/configure.tgt     |   5 +-
>  gdb/corelow.c         |  24 +++++
>  gdb/elf-none-tdep.c   | 126 +++++++++++++++++++++++++
>  gdb/elf-none-tdep.h   |  30 ++++++
>  gdb/fbsd-tdep.c       | 137 ++-------------------------
>  gdb/gcore-elf.c       | 166 ++++++++++++++++++++++++++++++++
>  gdb/gcore-elf.h       |  47 ++++++++++
>  gdb/gcore.c           |  21 +++++
>  gdb/gcore.h           |   9 ++
>  gdb/linux-tdep.c      | 146 +++--------------------------
>  gdb/riscv-none-tdep.c | 173 ++++++++++++++++++++++++++++++++++
>  gdb/riscv-tdep.c      |  14 ++-
>  gdb/riscv-tdep.h      |   3 +
>  include/ChangeLog     |  10 ++
>  include/elf/common.h  |   6 ++
>  26 files changed, 1159 insertions(+), 272 deletions(-)
>  create mode 100644 gdb/arm-none-tdep.c
>  create mode 100644 gdb/elf-none-tdep.c
>  create mode 100644 gdb/elf-none-tdep.h
>  create mode 100644 gdb/gcore-elf.c
>  create mode 100644 gdb/gcore-elf.h
>  create mode 100644 gdb/riscv-none-tdep.c
> 
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv3 0/9] Bare-metal core dumps for RISC-V
  2021-03-01 10:32   ` [PATCHv3 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
@ 2021-03-01 14:45     ` Nick Clifton
  2021-03-05 17:35     ` Andrew Burgess
  1 sibling, 0 replies; 57+ messages in thread
From: Nick Clifton @ 2021-03-01 14:45 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches, binutils

Hi Andrew,

> Ping!

Pong!

Approved - please apply.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv3 0/9] Bare-metal core dumps for RISC-V
  2021-03-01 10:32   ` [PATCHv3 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
  2021-03-01 14:45     ` Nick Clifton
@ 2021-03-05 17:35     ` Andrew Burgess
  1 sibling, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-03-05 17:35 UTC (permalink / raw)
  To: gdb-patches, binutils; +Cc: Fredrik Hederstierna

I have now pushed patches 1 to 8 of this series.  I have not merged
the ARM bare metal core dumping patch.

Fredrik,

Are you able to run any tests on the ARM patch and confirm that it
still does everything your original patch did?  Are you happy with my
variant?

Thanks,
Andrew



* Andrew Burgess <andrew.burgess@embecosm.com> [2021-03-01 10:32:41 +0000]:

> Ping!
> 
> I'm planning to start merging this series later this week.  The code
> was all reviewed in the v2 series.  The v3 mostly moves stuff around
> to avoid adding dependencies on ELF support.
> 
> I still wonder if there's a better solution than the #ifdef block
> added in patches 5 and 9, but these are pretty self-contained.  If
> someone suggests a better approach later on then I'm happy to refactor
> this code.
> 
> Thanks,
> Andrew
> 
> 
> * Andrew Burgess <andrew.burgess@embecosm.com> [2021-02-15 17:29:03 +0000]:
> 
> > After I pushed patch #1 from the v2 series it was pointed out that
> > this broke any build of GDB for non-ELF targets.  I then reverted
> > patch #1.  Now I'm back with an updated series.
> > 
> > For testing the build I have been using 'x86_64-apple-darwin20.3.0' as
> > a non-ELF target.  I haven't done any actual functional testing on
> > this target other than "it builds", but that's more than I did before
> > (for non-ELF targets).
> > 
> > Between v2 and v3 then the changes are basically around the idea of
> > not calling ELF specific functions from any generic code.  As far as
> > possible I wanted to avoid just blocking code out with #ifdef, though
> > I did use this trick in a limited way in patches #5 and #9, hopefully
> > this is acceptable, though I'm open to suggestions for better ways to
> > structure the code in these patches.
> > 
> > Here's a summary of which patches have changed:
> > 
> > (1) - Changed, common code from Linux and FreeBSD targets is now split
> >       between gcore.c (for non-ELF code) and a new file gcore-elf.c
> >       (for ELF specific code).  Changes to configure.ac ensure the ELF
> >       specific file is only pulled in when needed.  This probably
> >       needs a new review.
> > 
> > (2) - Minor updates to address Jim's review feedback.  Reviews are
> >       welcome, but I'm considering this patch approved.
> > 
> > (3) - Code to add the target description note is moved to gcore-elf.c,
> >       and each target must call this code (if the target is creating
> >       an ELF based core file).  I don't like this as much as the
> >       previous code where the target description note was added in one
> >       place, but I can't see a good way to do this without adding a
> >       #ifdef block to gcore.c.  This probably needs a new review.
> > 
> > (4) - Minor updates to address Jim's review feedback.  Reviews are
> >       welcome, but I'm considering this patch approved.
> > 
> > (5) - The common bare metal core dump code is now in elf-none-tdep.c.
> >       This is then called from the riscv-none-tdep.c code ONLY if we
> >       have ELF support.  This is the use of '#ifdef HAVE_ELF' which is
> >       a little yuck, but I can't see a better solution.  This probably
> >       needs a new review.
> > 
> > (6) - Minor updates to address Jim's review feedback.  Reviews are
> >       welcome, but I'm considering this patch approved.
> > 
> > (7) - No changes.  Reviews are welcome, but I'm considering this patch
> >       approved.
> > 
> > (8) - No changes.  Reviews are welcome, but I'm considering this patch
> >       approved.
> > 
> > (9) - No significant changes.  Like patch #5 it now includes a '#ifdef
> >       HAVE_ELF' block in order to guard the call from arm-none-tdep.c
> >       to elf-none-tdep.c.  I'd prefer reviews of this approach be
> >       addressed to patch #5, I'll apply any feedback I get there to
> >       this patch too.
> > 
> > ---
> > 
> > Andrew Burgess (9):
> >   gdb: unify parts of the Linux and FreeBSD core dumping code
> >   bfd/binutils: support for gdb target descriptions in the core file
> >   gdb: write target description into core file
> >   bfd/riscv: prepare to handle bare metal core dump creation
> >   gdb/riscv: introduce bare metal core dump support
> >   bfd/binutils: add support for RISC-V CSRs in core files
> >   gdb/riscv: make riscv target description names global
> >   gdb/riscv: write CSRs into baremetal core dumps
> >   gdb/arm: add support for bare-metal core dumps
> > 
> >  bfd/ChangeLog         |  27 ++++++
> >  bfd/elf-bfd.h         |   4 +
> >  bfd/elf.c             |  70 ++++++++++++++
> >  bfd/elfnn-riscv.c     |  84 ++++++++++++++++-
> >  binutils/ChangeLog    |  10 ++
> >  binutils/readelf.c    |   4 +
> >  gdb/ChangeLog         |  88 +++++++++++++++++
> >  gdb/Makefile.in       |   8 ++
> >  gdb/arm-none-tdep.c   | 213 ++++++++++++++++++++++++++++++++++++++++++
> >  gdb/configure         |   3 +-
> >  gdb/configure.ac      |   3 +-
> >  gdb/configure.tgt     |   5 +-
> >  gdb/corelow.c         |  24 +++++
> >  gdb/elf-none-tdep.c   | 126 +++++++++++++++++++++++++
> >  gdb/elf-none-tdep.h   |  30 ++++++
> >  gdb/fbsd-tdep.c       | 137 ++-------------------------
> >  gdb/gcore-elf.c       | 166 ++++++++++++++++++++++++++++++++
> >  gdb/gcore-elf.h       |  47 ++++++++++
> >  gdb/gcore.c           |  21 +++++
> >  gdb/gcore.h           |   9 ++
> >  gdb/linux-tdep.c      | 146 +++--------------------------
> >  gdb/riscv-none-tdep.c | 173 ++++++++++++++++++++++++++++++++++
> >  gdb/riscv-tdep.c      |  14 ++-
> >  gdb/riscv-tdep.h      |   3 +
> >  include/ChangeLog     |  10 ++
> >  include/elf/common.h  |   6 ++
> >  26 files changed, 1159 insertions(+), 272 deletions(-)
> >  create mode 100644 gdb/arm-none-tdep.c
> >  create mode 100644 gdb/elf-none-tdep.c
> >  create mode 100644 gdb/elf-none-tdep.h
> >  create mode 100644 gdb/gcore-elf.c
> >  create mode 100644 gdb/gcore-elf.h
> >  create mode 100644 gdb/riscv-none-tdep.c
> > 
> > -- 
> > 2.25.4
> > 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv3 9/9] gdb/arm: add support for bare-metal core dumps
  2021-02-15 17:29   ` [PATCHv3 9/9] gdb/arm: add support for bare-metal " Andrew Burgess
@ 2021-05-13 13:42     ` Andrew Burgess
  2021-05-13 13:51       ` Luis Machado
  0 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-05-13 13:42 UTC (permalink / raw)
  To: gdb-patches

When I merged the RISC-V bare-metal core file support I never merged
this patch (ARM bare-metal corefile support).

I've been in discussion with the author of the original patch
off-list, and this version of the patch does provide all of the
functionality that was present in their original work, and the
original author does have a copyright assignment in place.

I would like to propose merging this patch, even though I personally
have not tested it.

Thoughts?

Andrew



* Andrew Burgess <andrew.burgess@embecosm.com> [2021-02-15 17:29:12 +0000]:

>        **************** WARNING ********************
> 
> This commit is based off a patch from the mailing list, I don't know
> if the author of this patch has a copyright assignment in place.  As
> such this commit MUST NOT be pushed to upstream master until this has
> been cleared up.  A link to the original mailing list posting can be
> found in the patch description below.
> 
>        ************** END WARNING ******************
> 
> This commit adds support for bare metal core dumps on the ARM target,
> and is based off of this patch submitted to the mailing list:
> 
>   https://sourceware.org/pipermail/gdb-patches/2020-October/172845.html
> 
> Compared to the version linked above this version is updated to take
> account of recent changes to the core dump infrastructure in GDB,
> there is now more shared infrastructure for core dumping within GDB,
> and also some common bare metal core dumping infrastructure.  As a
> result this patch is smaller than the original proposed patch.
> 
> Further, the original patch included some unrelated changes to the
> simulator that have been removed from this version.
> 
> I have written a ChangeLog entry as the original patch was missing
> one.
> 
> I have done absolutely no testing of this patch.  It is based on the
> original submitted patch, which I assume was tested, but after my
> modifications things might have been broken.
> 
> The core dump format is based around generating an ELF containing
> sections for the writable regions of memory that a user could be
> using.  Which regions are dumped rely on GDB's existing common core
> dumping code, GDB will attempt to figure out the stack and heap as
> well as copying out writable data sections as identified by the
> original ELF.
> 
> Register information is added to the core dump using notes, just as it
> is for Linux of FreeBSD core dumps.  The note types used consist of
> the 2 basic types you would expect in a OS based core dump,
> NT_PRPSINFO, NT_PRSTATUS, along with the architecture specific
> NT_ARM_VFP note.
> 
> The data layouts for each note type are described below, in all cases,
> all padding fields should be set to zero.
> 
> Note NT_PRPSINFO is optional.  Its data layout is:
> 
>   struct prpsinfo_t
>   {
>     uint8_t padding[28];
>     char fname[16];
>     char psargs[80];
>   }
> 
> Field 'fname' - null terminated string consisting of the basename of
>     (up to the fist 15 characters of) the executable.  Any additional
>     space should be set to zero.  If there's no executable name then
>     this field can be set to all zero.
> 
> Field 'psargs' - a null terminated string up to 80 characters in
>     length.  Any additional space should be filled with zero.  This
>     field contains the full executable path and any arguments passed
>     to the executable.  If there's nothing sensible to write in this
>     field then fill it with zero.
> 
> Note NT_PRSTATUS is required, its data layout is:
> 
>   struct prstatus_t
>   {
>     uint8_t padding_1[12];
>     uint16_t sig;
>     uint8_t padding_2[10];
>     uint32_t thread_id;
>     uint8_t padding_3[44];
>     uint32_t gregs[18];
>   }
> 
> Field 'sig' - the signal that stopped this thread.  It's implementation
>     defined what this field actually means.  Within GDB this will be
>     the signal number that the remote target reports as the stop
>     reason for this thread.
> 
> Field 'thread_is' - the thread id for this thread.  It's implementation
>     defined what this field actually means.  Within GDB this will be
>     thread thread-id that is assigned to each remote thread.
> 
> Field 'gregs' - holds the general purpose registers $a1 through to $pc
>     at indices 0 to 15.  At index 16 the program status register.
>     Index 17 should be set to zero.
> 
> Note NT_ARM_VFP is optional, its data layout is:
> 
>   armvfp_t
>   {
>     uint64_t regs[32];
>     uint32_t fpscr;
>   }
> 
> Field 'regs' - holds the 32 d-registers 0 to 31 in order.
> 
> Field 'fpscr' - holds the fpscr register.
> 
> The rules for ordering the notes is the same as for Linux.  The
> NT_PRSTATUS note must come before any other notes about additional
> register sets.  And for multi-threaded targets all registers for a
> single thread should be grouped together.  This is because only
> NT_PRSTATUS includes a thread-id, all additional register notes after
> a NT_PRSTATUS are assumed to belong to the same thread until a
> different NT_PRSTATUS is seen.
> 
> gdb/ChangeLog:
> 
> 	PR gdb/14383
> 	* Makefile.in (ALL_TARGET_OBS): Add arm-none-tdep.o.
> 	(ALLDEPFILES): Add arm-none-tdep.c
> 	* arm-none-tdep.c: New file.
> 	* configure.tgt (arm*-*-*): Add arm-none-tdep.o to cpu_obs.
> ---
>  gdb/ChangeLog       |   9 ++
>  gdb/Makefile.in     |   2 +
>  gdb/arm-none-tdep.c | 213 ++++++++++++++++++++++++++++++++++++++++++++
>  gdb/configure.tgt   |   3 +-
>  4 files changed, 226 insertions(+), 1 deletion(-)
>  create mode 100644 gdb/arm-none-tdep.c
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index a6ca5a53655..77c2401e272 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -728,6 +728,7 @@ ALL_TARGET_OBS = \
>  	arm-fbsd-tdep.o \
>  	arm-linux-tdep.o \
>  	arm-netbsd-tdep.o \
> +	arm-none-tdep.o \
>  	arm-obsd-tdep.o \
>  	arm-pikeos-tdep.o \
>  	arm-tdep.o \
> @@ -2171,6 +2172,7 @@ ALLDEPFILES = \
>  	arm-linux-tdep.c \
>  	arm-netbsd-nat.c \
>  	arm-netbsd-tdep.c \
> +	arm-none-tdep.c \
>  	arm-obsd-tdep.c \
>  	arm-tdep.c \
>  	avr-tdep.c \
> diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
> new file mode 100644
> index 00000000000..2816c5954b3
> --- /dev/null
> +++ b/gdb/arm-none-tdep.c
> @@ -0,0 +1,213 @@
> +/* none on ARM target support.
> +
> +   Copyright (C) 2020-2021 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "arm-tdep.h"
> +#include "arch-utils.h"
> +#include "regcache.h"
> +#include "elf-bfd.h"
> +#include "regset.h"
> +#include "user-regs.h"
> +
> +#ifdef HAVE_ELF
> +#include "elf-none-tdep.h"
> +#endif
> +
> +/* Core file and register set support.  */
> +#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
> +
> +/* Support VFP register format.  */
> +#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
> +
> +/* The index to access CPSR in user_regs as defined in GLIBC.  */
> +#define ARM_NONE_CPSR_GREGNUM 16
> +
> +/* Supply register REGNUM from buffer GREGS_BUF (length LEN bytes) into
> +   REGCACHE.  If REGNUM is -1 then supply all registers.  The set of
> +   registers that this function will supply is limited to the general
> +   purpose registers.
> +
> +   The layout of the registers here is based on the ARM GNU/Linux
> +   layout.  */
> +
> +static void
> +arm_none_supply_gregset (const struct regset *regset,
> +			 struct regcache *regcache,
> +			 int regnum, const void *gregs_buf, size_t len)
> +{
> +  struct gdbarch *gdbarch = regcache->arch ();
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
> +
> +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
> +    if (regnum == -1 || regnum == regno)
> +      regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
> +
> +  if (regnum == ARM_PS_REGNUM || regnum == -1)
> +    {
> +      if (arm_apcs_32)
> +	regcache->raw_supply (ARM_PS_REGNUM,
> +			      gregs + ARM_INT_REGISTER_SIZE
> +			      * ARM_NONE_CPSR_GREGNUM);
> +      else
> +	regcache->raw_supply (ARM_PS_REGNUM,
> +			     gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> +    }
> +
> +  if (regnum == ARM_PC_REGNUM || regnum == -1)
> +    {
> +      gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
> +
> +      CORE_ADDR reg_pc
> +	= extract_unsigned_integer (gregs + ARM_INT_REGISTER_SIZE
> +				    * ARM_PC_REGNUM,
> +				    ARM_INT_REGISTER_SIZE, byte_order);
> +      reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
> +      store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
> +			      reg_pc);
> +      regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
> +    }
> +}
> +
> +/* Collect register REGNUM from REGCACHE and place it into buffer GREGS_BUF
> +   (length LEN bytes).  If REGNUM is -1 then collect all registers.  The
> +   set of registers that this function will collect is limited to the
> +   general purpose registers.
> +
> +   The layout of the registers here is based on the ARM GNU/Linux
> +   layout.  */
> +
> +static void
> +arm_none_collect_gregset (const struct regset *regset,
> +			  const struct regcache *regcache,
> +			  int regnum, void *gregs_buf, size_t len)
> +{
> +  gdb_byte *gregs = (gdb_byte *) gregs_buf;
> +
> +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
> +    if (regnum == -1 || regnum == regno)
> +      regcache->raw_collect (regno,
> +			     gregs + ARM_INT_REGISTER_SIZE * regno);
> +
> +  if (regnum == ARM_PS_REGNUM || regnum == -1)
> +    {
> +      if (arm_apcs_32)
> +	regcache->raw_collect (ARM_PS_REGNUM,
> +			       gregs + ARM_INT_REGISTER_SIZE
> +			       * ARM_NONE_CPSR_GREGNUM);
> +      else
> +	regcache->raw_collect (ARM_PS_REGNUM,
> +			       gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> +    }
> +
> +  if (regnum == ARM_PC_REGNUM || regnum == -1)
> +    regcache->raw_collect (ARM_PC_REGNUM,
> +			   gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> +}
> +
> +/* Supply VFP registers from REGS_BUF into REGCACHE.  */
> +
> +static void
> +arm_none_supply_vfp (const struct regset *regset,
> +		     struct regcache *regcache,
> +		     int regnum, const void *regs_buf, size_t len)
> +{
> +  const gdb_byte *regs = (const gdb_byte *) regs_buf;
> +
> +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
> +    regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
> +
> +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
> +    if (regnum == -1 || regnum == regno)
> +      regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
> +}
> +
> +/* Collect VFP registers from REGCACHE into REGS_BUF.  */
> +
> +static void
> +arm_none_collect_vfp (const struct regset *regset,
> +		      const struct regcache *regcache,
> +		      int regnum, void *regs_buf, size_t len)
> +{
> +  gdb_byte *regs = (gdb_byte *) regs_buf;
> +
> +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
> +    regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
> +
> +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
> +    if (regnum == -1 || regnum == regno)
> +      regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
> +}
> +
> +/* The general purpose register set.  */
> +
> +static const struct regset arm_none_gregset =
> +  {
> +    nullptr, arm_none_supply_gregset, arm_none_collect_gregset
> +  };
> +
> +/* The VFP register set.  */
> +
> +static const struct regset arm_none_vfpregset =
> +  {
> +    nullptr, arm_none_supply_vfp, arm_none_collect_vfp
> +  };
> +
> +/* Iterate over core file register note sections.  */
> +
> +static void
> +arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
> +				       iterate_over_regset_sections_cb *cb,
> +				       void *cb_data,
> +				       const struct regcache *regcache)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET,
> +      &arm_none_gregset, nullptr, cb_data);
> +
> +  if (tdep->vfp_register_count > 0)
> +    cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP,
> +	&arm_none_vfpregset, "VFP floating-point", cb_data);
> +}
> +
> +/* Initialize ARM bare-metal ABI info.  */
> +
> +static void
> +arm_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +#ifdef HAVE_ELF
> +  elf_none_init_abi (gdbarch);
> +#endif
> +
> +  /* Iterate over registers for reading and writing bare metal ARM core
> +     files.  */
> +  set_gdbarch_iterate_over_regset_sections
> +    (gdbarch, arm_none_iterate_over_regset_sections);
> +}
> +
> +/* Initialize ARM bare-metal target support.  */
> +
> +void _initialize_arm_none_tdep ();
> +void
> +_initialize_arm_none_tdep ()
> +{
> +  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NONE,
> +			  arm_none_init_abi);
> +}
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index 91020678bf0..f81f03b96c9 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -65,7 +65,8 @@ arc*-*-*)
>  
>  arm*-*-*)
>  	cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \
> -		 arch/arm-get-next-pcs.o arm-tdep.o";;
> +		 arch/arm-get-next-pcs.o arm-tdep.o arm-none-tdep.o"
> +	;;
>  
>  hppa*-*-*)
>  	# Target: HP PA-RISC
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv3 9/9] gdb/arm: add support for bare-metal core dumps
  2021-05-13 13:42     ` Andrew Burgess
@ 2021-05-13 13:51       ` Luis Machado
  2021-05-13 13:56         ` Andrew Burgess
  0 siblings, 1 reply; 57+ messages in thread
From: Luis Machado @ 2021-05-13 13:51 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 5/13/21 10:42 AM, Andrew Burgess wrote:
> When I merged the RISC-V bare-metal core file support I never merged
> this patch (ARM bare-metal corefile support).
> 
> I've been in discussion with the author of the original patch
> off-list, and this version of the patch does provide all of the
> functionality that was present in their original work, and the
> original author does have a copyright assignment in place.

It would be nice if the original author tested this on his end to make 
sure it works for his purpose.

> 
> I would like to propose merging this patch, even though I personally
> have not tested it.

I'm fine with that, but if the original author can test this, it would 
be better.

> 
> Thoughts?
> 
> Andrew
> 
> 
> 
> * Andrew Burgess <andrew.burgess@embecosm.com> [2021-02-15 17:29:12 +0000]:
> 
>>         **************** WARNING ********************
>>
>> This commit is based off a patch from the mailing list, I don't know
>> if the author of this patch has a copyright assignment in place.  As
>> such this commit MUST NOT be pushed to upstream master until this has
>> been cleared up.  A link to the original mailing list posting can be
>> found in the patch description below.
>>
>>         ************** END WARNING ******************
>>
>> This commit adds support for bare metal core dumps on the ARM target,
>> and is based off of this patch submitted to the mailing list:
>>
>>    https://sourceware.org/pipermail/gdb-patches/2020-October/172845.html
>>
>> Compared to the version linked above this version is updated to take
>> account of recent changes to the core dump infrastructure in GDB,
>> there is now more shared infrastructure for core dumping within GDB,
>> and also some common bare metal core dumping infrastructure.  As a
>> result this patch is smaller than the original proposed patch.
>>
>> Further, the original patch included some unrelated changes to the
>> simulator that have been removed from this version.
>>
>> I have written a ChangeLog entry as the original patch was missing
>> one.
>>
>> I have done absolutely no testing of this patch.  It is based on the
>> original submitted patch, which I assume was tested, but after my
>> modifications things might have been broken.
>>
>> The core dump format is based around generating an ELF containing
>> sections for the writable regions of memory that a user could be
>> using.  Which regions are dumped rely on GDB's existing common core
>> dumping code, GDB will attempt to figure out the stack and heap as
>> well as copying out writable data sections as identified by the
>> original ELF.
>>
>> Register information is added to the core dump using notes, just as it
>> is for Linux of FreeBSD core dumps.  The note types used consist of
>> the 2 basic types you would expect in a OS based core dump,
>> NT_PRPSINFO, NT_PRSTATUS, along with the architecture specific
>> NT_ARM_VFP note.
>>
>> The data layouts for each note type are described below, in all cases,
>> all padding fields should be set to zero.
>>
>> Note NT_PRPSINFO is optional.  Its data layout is:
>>
>>    struct prpsinfo_t
>>    {
>>      uint8_t padding[28];
>>      char fname[16];
>>      char psargs[80];
>>    }
>>
>> Field 'fname' - null terminated string consisting of the basename of
>>      (up to the fist 15 characters of) the executable.  Any additional
>>      space should be set to zero.  If there's no executable name then
>>      this field can be set to all zero.
>>
>> Field 'psargs' - a null terminated string up to 80 characters in
>>      length.  Any additional space should be filled with zero.  This
>>      field contains the full executable path and any arguments passed
>>      to the executable.  If there's nothing sensible to write in this
>>      field then fill it with zero.
>>
>> Note NT_PRSTATUS is required, its data layout is:
>>
>>    struct prstatus_t
>>    {
>>      uint8_t padding_1[12];
>>      uint16_t sig;
>>      uint8_t padding_2[10];
>>      uint32_t thread_id;
>>      uint8_t padding_3[44];
>>      uint32_t gregs[18];
>>    }
>>
>> Field 'sig' - the signal that stopped this thread.  It's implementation
>>      defined what this field actually means.  Within GDB this will be
>>      the signal number that the remote target reports as the stop
>>      reason for this thread.
>>
>> Field 'thread_is' - the thread id for this thread.  It's implementation
>>      defined what this field actually means.  Within GDB this will be
>>      thread thread-id that is assigned to each remote thread.
>>
>> Field 'gregs' - holds the general purpose registers $a1 through to $pc
>>      at indices 0 to 15.  At index 16 the program status register.
>>      Index 17 should be set to zero.
>>
>> Note NT_ARM_VFP is optional, its data layout is:
>>
>>    armvfp_t
>>    {
>>      uint64_t regs[32];
>>      uint32_t fpscr;
>>    }
>>
>> Field 'regs' - holds the 32 d-registers 0 to 31 in order.
>>
>> Field 'fpscr' - holds the fpscr register.
>>
>> The rules for ordering the notes is the same as for Linux.  The
>> NT_PRSTATUS note must come before any other notes about additional
>> register sets.  And for multi-threaded targets all registers for a
>> single thread should be grouped together.  This is because only
>> NT_PRSTATUS includes a thread-id, all additional register notes after
>> a NT_PRSTATUS are assumed to belong to the same thread until a
>> different NT_PRSTATUS is seen.
>>
>> gdb/ChangeLog:
>>
>> 	PR gdb/14383
>> 	* Makefile.in (ALL_TARGET_OBS): Add arm-none-tdep.o.
>> 	(ALLDEPFILES): Add arm-none-tdep.c
>> 	* arm-none-tdep.c: New file.
>> 	* configure.tgt (arm*-*-*): Add arm-none-tdep.o to cpu_obs.
>> ---
>>   gdb/ChangeLog       |   9 ++
>>   gdb/Makefile.in     |   2 +
>>   gdb/arm-none-tdep.c | 213 ++++++++++++++++++++++++++++++++++++++++++++
>>   gdb/configure.tgt   |   3 +-
>>   4 files changed, 226 insertions(+), 1 deletion(-)
>>   create mode 100644 gdb/arm-none-tdep.c
>>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index a6ca5a53655..77c2401e272 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -728,6 +728,7 @@ ALL_TARGET_OBS = \
>>   	arm-fbsd-tdep.o \
>>   	arm-linux-tdep.o \
>>   	arm-netbsd-tdep.o \
>> +	arm-none-tdep.o \
>>   	arm-obsd-tdep.o \
>>   	arm-pikeos-tdep.o \
>>   	arm-tdep.o \
>> @@ -2171,6 +2172,7 @@ ALLDEPFILES = \
>>   	arm-linux-tdep.c \
>>   	arm-netbsd-nat.c \
>>   	arm-netbsd-tdep.c \
>> +	arm-none-tdep.c \
>>   	arm-obsd-tdep.c \
>>   	arm-tdep.c \
>>   	avr-tdep.c \
>> diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
>> new file mode 100644
>> index 00000000000..2816c5954b3
>> --- /dev/null
>> +++ b/gdb/arm-none-tdep.c
>> @@ -0,0 +1,213 @@
>> +/* none on ARM target support.
>> +
>> +   Copyright (C) 2020-2021 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>> +
>> +#include "defs.h"
>> +#include "arm-tdep.h"
>> +#include "arch-utils.h"
>> +#include "regcache.h"
>> +#include "elf-bfd.h"
>> +#include "regset.h"
>> +#include "user-regs.h"
>> +
>> +#ifdef HAVE_ELF
>> +#include "elf-none-tdep.h"
>> +#endif
>> +
>> +/* Core file and register set support.  */
>> +#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
>> +
>> +/* Support VFP register format.  */
>> +#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
>> +
>> +/* The index to access CPSR in user_regs as defined in GLIBC.  */
>> +#define ARM_NONE_CPSR_GREGNUM 16
>> +
>> +/* Supply register REGNUM from buffer GREGS_BUF (length LEN bytes) into
>> +   REGCACHE.  If REGNUM is -1 then supply all registers.  The set of
>> +   registers that this function will supply is limited to the general
>> +   purpose registers.
>> +
>> +   The layout of the registers here is based on the ARM GNU/Linux
>> +   layout.  */
>> +
>> +static void
>> +arm_none_supply_gregset (const struct regset *regset,
>> +			 struct regcache *regcache,
>> +			 int regnum, const void *gregs_buf, size_t len)
>> +{
>> +  struct gdbarch *gdbarch = regcache->arch ();
>> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>> +  const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
>> +
>> +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
>> +    if (regnum == -1 || regnum == regno)
>> +      regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
>> +
>> +  if (regnum == ARM_PS_REGNUM || regnum == -1)
>> +    {
>> +      if (arm_apcs_32)
>> +	regcache->raw_supply (ARM_PS_REGNUM,
>> +			      gregs + ARM_INT_REGISTER_SIZE
>> +			      * ARM_NONE_CPSR_GREGNUM);
>> +      else
>> +	regcache->raw_supply (ARM_PS_REGNUM,
>> +			     gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
>> +    }
>> +
>> +  if (regnum == ARM_PC_REGNUM || regnum == -1)
>> +    {
>> +      gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
>> +
>> +      CORE_ADDR reg_pc
>> +	= extract_unsigned_integer (gregs + ARM_INT_REGISTER_SIZE
>> +				    * ARM_PC_REGNUM,
>> +				    ARM_INT_REGISTER_SIZE, byte_order);
>> +      reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
>> +      store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
>> +			      reg_pc);
>> +      regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
>> +    }
>> +}
>> +
>> +/* Collect register REGNUM from REGCACHE and place it into buffer GREGS_BUF
>> +   (length LEN bytes).  If REGNUM is -1 then collect all registers.  The
>> +   set of registers that this function will collect is limited to the
>> +   general purpose registers.
>> +
>> +   The layout of the registers here is based on the ARM GNU/Linux
>> +   layout.  */
>> +
>> +static void
>> +arm_none_collect_gregset (const struct regset *regset,
>> +			  const struct regcache *regcache,
>> +			  int regnum, void *gregs_buf, size_t len)
>> +{
>> +  gdb_byte *gregs = (gdb_byte *) gregs_buf;
>> +
>> +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
>> +    if (regnum == -1 || regnum == regno)
>> +      regcache->raw_collect (regno,
>> +			     gregs + ARM_INT_REGISTER_SIZE * regno);
>> +
>> +  if (regnum == ARM_PS_REGNUM || regnum == -1)
>> +    {
>> +      if (arm_apcs_32)
>> +	regcache->raw_collect (ARM_PS_REGNUM,
>> +			       gregs + ARM_INT_REGISTER_SIZE
>> +			       * ARM_NONE_CPSR_GREGNUM);
>> +      else
>> +	regcache->raw_collect (ARM_PS_REGNUM,
>> +			       gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
>> +    }
>> +
>> +  if (regnum == ARM_PC_REGNUM || regnum == -1)
>> +    regcache->raw_collect (ARM_PC_REGNUM,
>> +			   gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
>> +}
>> +
>> +/* Supply VFP registers from REGS_BUF into REGCACHE.  */
>> +
>> +static void
>> +arm_none_supply_vfp (const struct regset *regset,
>> +		     struct regcache *regcache,
>> +		     int regnum, const void *regs_buf, size_t len)
>> +{
>> +  const gdb_byte *regs = (const gdb_byte *) regs_buf;
>> +
>> +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
>> +    regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
>> +
>> +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
>> +    if (regnum == -1 || regnum == regno)
>> +      regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
>> +}
>> +
>> +/* Collect VFP registers from REGCACHE into REGS_BUF.  */
>> +
>> +static void
>> +arm_none_collect_vfp (const struct regset *regset,
>> +		      const struct regcache *regcache,
>> +		      int regnum, void *regs_buf, size_t len)
>> +{
>> +  gdb_byte *regs = (gdb_byte *) regs_buf;
>> +
>> +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
>> +    regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
>> +
>> +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
>> +    if (regnum == -1 || regnum == regno)
>> +      regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
>> +}
>> +
>> +/* The general purpose register set.  */
>> +
>> +static const struct regset arm_none_gregset =
>> +  {
>> +    nullptr, arm_none_supply_gregset, arm_none_collect_gregset
>> +  };
>> +
>> +/* The VFP register set.  */
>> +
>> +static const struct regset arm_none_vfpregset =
>> +  {
>> +    nullptr, arm_none_supply_vfp, arm_none_collect_vfp
>> +  };
>> +
>> +/* Iterate over core file register note sections.  */
>> +
>> +static void
>> +arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
>> +				       iterate_over_regset_sections_cb *cb,
>> +				       void *cb_data,
>> +				       const struct regcache *regcache)
>> +{
>> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>> +
>> +  cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET,
>> +      &arm_none_gregset, nullptr, cb_data);
>> +
>> +  if (tdep->vfp_register_count > 0)
>> +    cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP,
>> +	&arm_none_vfpregset, "VFP floating-point", cb_data);
>> +}
>> +
>> +/* Initialize ARM bare-metal ABI info.  */
>> +
>> +static void
>> +arm_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>> +{
>> +#ifdef HAVE_ELF
>> +  elf_none_init_abi (gdbarch);
>> +#endif
>> +
>> +  /* Iterate over registers for reading and writing bare metal ARM core
>> +     files.  */
>> +  set_gdbarch_iterate_over_regset_sections
>> +    (gdbarch, arm_none_iterate_over_regset_sections);
>> +}
>> +
>> +/* Initialize ARM bare-metal target support.  */
>> +
>> +void _initialize_arm_none_tdep ();
>> +void
>> +_initialize_arm_none_tdep ()
>> +{
>> +  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NONE,
>> +			  arm_none_init_abi);
>> +}
>> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
>> index 91020678bf0..f81f03b96c9 100644
>> --- a/gdb/configure.tgt
>> +++ b/gdb/configure.tgt
>> @@ -65,7 +65,8 @@ arc*-*-*)
>>   
>>   arm*-*-*)
>>   	cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \
>> -		 arch/arm-get-next-pcs.o arm-tdep.o";;
>> +		 arch/arm-get-next-pcs.o arm-tdep.o arm-none-tdep.o"
>> +	;;
>>   
>>   hppa*-*-*)
>>   	# Target: HP PA-RISC
>> -- 
>> 2.25.4
>>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCHv3 9/9] gdb/arm: add support for bare-metal core dumps
  2021-05-13 13:51       ` Luis Machado
@ 2021-05-13 13:56         ` Andrew Burgess
  2021-05-15 13:52           ` SV: " sarah@hederstierna.com
  0 siblings, 1 reply; 57+ messages in thread
From: Andrew Burgess @ 2021-05-13 13:56 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, Fredrik Hederstierna

* Luis Machado <luis.machado@linaro.org> [2021-05-13 10:51:47 -0300]:

> On 5/13/21 10:42 AM, Andrew Burgess wrote:
> > When I merged the RISC-V bare-metal core file support I never merged
> > this patch (ARM bare-metal corefile support).
> > 
> > I've been in discussion with the author of the original patch
> > off-list, and this version of the patch does provide all of the
> > functionality that was present in their original work, and the
> > original author does have a copyright assignment in place.
> 
> It would be nice if the original author tested this on his end to make sure
> it works for his purpose.
> 
> > 
> > I would like to propose merging this patch, even though I personally
> > have not tested it.
> 
> I'm fine with that, but if the original author can test this, it would be
> better.

Sorry, that was what I was (badly) trying to say before.  I'v CC'd
Fredrik, hopefully he can drop in and confirm this meets his needs.

Thanks,
Andrew


> 
> > 
> > Thoughts?
> > 
> > Andrew
> > 
> > 
> > 
> > * Andrew Burgess <andrew.burgess@embecosm.com> [2021-02-15 17:29:12 +0000]:
> > 
> > >         **************** WARNING ********************
> > > 
> > > This commit is based off a patch from the mailing list, I don't know
> > > if the author of this patch has a copyright assignment in place.  As
> > > such this commit MUST NOT be pushed to upstream master until this has
> > > been cleared up.  A link to the original mailing list posting can be
> > > found in the patch description below.
> > > 
> > >         ************** END WARNING ******************
> > > 
> > > This commit adds support for bare metal core dumps on the ARM target,
> > > and is based off of this patch submitted to the mailing list:
> > > 
> > >    https://sourceware.org/pipermail/gdb-patches/2020-October/172845.html
> > > 
> > > Compared to the version linked above this version is updated to take
> > > account of recent changes to the core dump infrastructure in GDB,
> > > there is now more shared infrastructure for core dumping within GDB,
> > > and also some common bare metal core dumping infrastructure.  As a
> > > result this patch is smaller than the original proposed patch.
> > > 
> > > Further, the original patch included some unrelated changes to the
> > > simulator that have been removed from this version.
> > > 
> > > I have written a ChangeLog entry as the original patch was missing
> > > one.
> > > 
> > > I have done absolutely no testing of this patch.  It is based on the
> > > original submitted patch, which I assume was tested, but after my
> > > modifications things might have been broken.
> > > 
> > > The core dump format is based around generating an ELF containing
> > > sections for the writable regions of memory that a user could be
> > > using.  Which regions are dumped rely on GDB's existing common core
> > > dumping code, GDB will attempt to figure out the stack and heap as
> > > well as copying out writable data sections as identified by the
> > > original ELF.
> > > 
> > > Register information is added to the core dump using notes, just as it
> > > is for Linux of FreeBSD core dumps.  The note types used consist of
> > > the 2 basic types you would expect in a OS based core dump,
> > > NT_PRPSINFO, NT_PRSTATUS, along with the architecture specific
> > > NT_ARM_VFP note.
> > > 
> > > The data layouts for each note type are described below, in all cases,
> > > all padding fields should be set to zero.
> > > 
> > > Note NT_PRPSINFO is optional.  Its data layout is:
> > > 
> > >    struct prpsinfo_t
> > >    {
> > >      uint8_t padding[28];
> > >      char fname[16];
> > >      char psargs[80];
> > >    }
> > > 
> > > Field 'fname' - null terminated string consisting of the basename of
> > >      (up to the fist 15 characters of) the executable.  Any additional
> > >      space should be set to zero.  If there's no executable name then
> > >      this field can be set to all zero.
> > > 
> > > Field 'psargs' - a null terminated string up to 80 characters in
> > >      length.  Any additional space should be filled with zero.  This
> > >      field contains the full executable path and any arguments passed
> > >      to the executable.  If there's nothing sensible to write in this
> > >      field then fill it with zero.
> > > 
> > > Note NT_PRSTATUS is required, its data layout is:
> > > 
> > >    struct prstatus_t
> > >    {
> > >      uint8_t padding_1[12];
> > >      uint16_t sig;
> > >      uint8_t padding_2[10];
> > >      uint32_t thread_id;
> > >      uint8_t padding_3[44];
> > >      uint32_t gregs[18];
> > >    }
> > > 
> > > Field 'sig' - the signal that stopped this thread.  It's implementation
> > >      defined what this field actually means.  Within GDB this will be
> > >      the signal number that the remote target reports as the stop
> > >      reason for this thread.
> > > 
> > > Field 'thread_is' - the thread id for this thread.  It's implementation
> > >      defined what this field actually means.  Within GDB this will be
> > >      thread thread-id that is assigned to each remote thread.
> > > 
> > > Field 'gregs' - holds the general purpose registers $a1 through to $pc
> > >      at indices 0 to 15.  At index 16 the program status register.
> > >      Index 17 should be set to zero.
> > > 
> > > Note NT_ARM_VFP is optional, its data layout is:
> > > 
> > >    armvfp_t
> > >    {
> > >      uint64_t regs[32];
> > >      uint32_t fpscr;
> > >    }
> > > 
> > > Field 'regs' - holds the 32 d-registers 0 to 31 in order.
> > > 
> > > Field 'fpscr' - holds the fpscr register.
> > > 
> > > The rules for ordering the notes is the same as for Linux.  The
> > > NT_PRSTATUS note must come before any other notes about additional
> > > register sets.  And for multi-threaded targets all registers for a
> > > single thread should be grouped together.  This is because only
> > > NT_PRSTATUS includes a thread-id, all additional register notes after
> > > a NT_PRSTATUS are assumed to belong to the same thread until a
> > > different NT_PRSTATUS is seen.
> > > 
> > > gdb/ChangeLog:
> > > 
> > > 	PR gdb/14383
> > > 	* Makefile.in (ALL_TARGET_OBS): Add arm-none-tdep.o.
> > > 	(ALLDEPFILES): Add arm-none-tdep.c
> > > 	* arm-none-tdep.c: New file.
> > > 	* configure.tgt (arm*-*-*): Add arm-none-tdep.o to cpu_obs.
> > > ---
> > >   gdb/ChangeLog       |   9 ++
> > >   gdb/Makefile.in     |   2 +
> > >   gdb/arm-none-tdep.c | 213 ++++++++++++++++++++++++++++++++++++++++++++
> > >   gdb/configure.tgt   |   3 +-
> > >   4 files changed, 226 insertions(+), 1 deletion(-)
> > >   create mode 100644 gdb/arm-none-tdep.c
> > > 
> > > diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> > > index a6ca5a53655..77c2401e272 100644
> > > --- a/gdb/Makefile.in
> > > +++ b/gdb/Makefile.in
> > > @@ -728,6 +728,7 @@ ALL_TARGET_OBS = \
> > >   	arm-fbsd-tdep.o \
> > >   	arm-linux-tdep.o \
> > >   	arm-netbsd-tdep.o \
> > > +	arm-none-tdep.o \
> > >   	arm-obsd-tdep.o \
> > >   	arm-pikeos-tdep.o \
> > >   	arm-tdep.o \
> > > @@ -2171,6 +2172,7 @@ ALLDEPFILES = \
> > >   	arm-linux-tdep.c \
> > >   	arm-netbsd-nat.c \
> > >   	arm-netbsd-tdep.c \
> > > +	arm-none-tdep.c \
> > >   	arm-obsd-tdep.c \
> > >   	arm-tdep.c \
> > >   	avr-tdep.c \
> > > diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
> > > new file mode 100644
> > > index 00000000000..2816c5954b3
> > > --- /dev/null
> > > +++ b/gdb/arm-none-tdep.c
> > > @@ -0,0 +1,213 @@
> > > +/* none on ARM target support.
> > > +
> > > +   Copyright (C) 2020-2021 Free Software Foundation, Inc.
> > > +
> > > +   This file is part of GDB.
> > > +
> > > +   This program is free software; you can redistribute it and/or modify
> > > +   it under the terms of the GNU General Public License as published by
> > > +   the Free Software Foundation; either version 3 of the License, or
> > > +   (at your option) any later version.
> > > +
> > > +   This program is distributed in the hope that it will be useful,
> > > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > > +   GNU General Public License for more details.
> > > +
> > > +   You should have received a copy of the GNU General Public License
> > > +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> > > +
> > > +#include "defs.h"
> > > +#include "arm-tdep.h"
> > > +#include "arch-utils.h"
> > > +#include "regcache.h"
> > > +#include "elf-bfd.h"
> > > +#include "regset.h"
> > > +#include "user-regs.h"
> > > +
> > > +#ifdef HAVE_ELF
> > > +#include "elf-none-tdep.h"
> > > +#endif
> > > +
> > > +/* Core file and register set support.  */
> > > +#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
> > > +
> > > +/* Support VFP register format.  */
> > > +#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
> > > +
> > > +/* The index to access CPSR in user_regs as defined in GLIBC.  */
> > > +#define ARM_NONE_CPSR_GREGNUM 16
> > > +
> > > +/* Supply register REGNUM from buffer GREGS_BUF (length LEN bytes) into
> > > +   REGCACHE.  If REGNUM is -1 then supply all registers.  The set of
> > > +   registers that this function will supply is limited to the general
> > > +   purpose registers.
> > > +
> > > +   The layout of the registers here is based on the ARM GNU/Linux
> > > +   layout.  */
> > > +
> > > +static void
> > > +arm_none_supply_gregset (const struct regset *regset,
> > > +			 struct regcache *regcache,
> > > +			 int regnum, const void *gregs_buf, size_t len)
> > > +{
> > > +  struct gdbarch *gdbarch = regcache->arch ();
> > > +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> > > +  const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
> > > +
> > > +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
> > > +    if (regnum == -1 || regnum == regno)
> > > +      regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
> > > +
> > > +  if (regnum == ARM_PS_REGNUM || regnum == -1)
> > > +    {
> > > +      if (arm_apcs_32)
> > > +	regcache->raw_supply (ARM_PS_REGNUM,
> > > +			      gregs + ARM_INT_REGISTER_SIZE
> > > +			      * ARM_NONE_CPSR_GREGNUM);
> > > +      else
> > > +	regcache->raw_supply (ARM_PS_REGNUM,
> > > +			     gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> > > +    }
> > > +
> > > +  if (regnum == ARM_PC_REGNUM || regnum == -1)
> > > +    {
> > > +      gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
> > > +
> > > +      CORE_ADDR reg_pc
> > > +	= extract_unsigned_integer (gregs + ARM_INT_REGISTER_SIZE
> > > +				    * ARM_PC_REGNUM,
> > > +				    ARM_INT_REGISTER_SIZE, byte_order);
> > > +      reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
> > > +      store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
> > > +			      reg_pc);
> > > +      regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
> > > +    }
> > > +}
> > > +
> > > +/* Collect register REGNUM from REGCACHE and place it into buffer GREGS_BUF
> > > +   (length LEN bytes).  If REGNUM is -1 then collect all registers.  The
> > > +   set of registers that this function will collect is limited to the
> > > +   general purpose registers.
> > > +
> > > +   The layout of the registers here is based on the ARM GNU/Linux
> > > +   layout.  */
> > > +
> > > +static void
> > > +arm_none_collect_gregset (const struct regset *regset,
> > > +			  const struct regcache *regcache,
> > > +			  int regnum, void *gregs_buf, size_t len)
> > > +{
> > > +  gdb_byte *gregs = (gdb_byte *) gregs_buf;
> > > +
> > > +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
> > > +    if (regnum == -1 || regnum == regno)
> > > +      regcache->raw_collect (regno,
> > > +			     gregs + ARM_INT_REGISTER_SIZE * regno);
> > > +
> > > +  if (regnum == ARM_PS_REGNUM || regnum == -1)
> > > +    {
> > > +      if (arm_apcs_32)
> > > +	regcache->raw_collect (ARM_PS_REGNUM,
> > > +			       gregs + ARM_INT_REGISTER_SIZE
> > > +			       * ARM_NONE_CPSR_GREGNUM);
> > > +      else
> > > +	regcache->raw_collect (ARM_PS_REGNUM,
> > > +			       gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> > > +    }
> > > +
> > > +  if (regnum == ARM_PC_REGNUM || regnum == -1)
> > > +    regcache->raw_collect (ARM_PC_REGNUM,
> > > +			   gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> > > +}
> > > +
> > > +/* Supply VFP registers from REGS_BUF into REGCACHE.  */
> > > +
> > > +static void
> > > +arm_none_supply_vfp (const struct regset *regset,
> > > +		     struct regcache *regcache,
> > > +		     int regnum, const void *regs_buf, size_t len)
> > > +{
> > > +  const gdb_byte *regs = (const gdb_byte *) regs_buf;
> > > +
> > > +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
> > > +    regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
> > > +
> > > +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
> > > +    if (regnum == -1 || regnum == regno)
> > > +      regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
> > > +}
> > > +
> > > +/* Collect VFP registers from REGCACHE into REGS_BUF.  */
> > > +
> > > +static void
> > > +arm_none_collect_vfp (const struct regset *regset,
> > > +		      const struct regcache *regcache,
> > > +		      int regnum, void *regs_buf, size_t len)
> > > +{
> > > +  gdb_byte *regs = (gdb_byte *) regs_buf;
> > > +
> > > +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
> > > +    regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
> > > +
> > > +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
> > > +    if (regnum == -1 || regnum == regno)
> > > +      regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
> > > +}
> > > +
> > > +/* The general purpose register set.  */
> > > +
> > > +static const struct regset arm_none_gregset =
> > > +  {
> > > +    nullptr, arm_none_supply_gregset, arm_none_collect_gregset
> > > +  };
> > > +
> > > +/* The VFP register set.  */
> > > +
> > > +static const struct regset arm_none_vfpregset =
> > > +  {
> > > +    nullptr, arm_none_supply_vfp, arm_none_collect_vfp
> > > +  };
> > > +
> > > +/* Iterate over core file register note sections.  */
> > > +
> > > +static void
> > > +arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
> > > +				       iterate_over_regset_sections_cb *cb,
> > > +				       void *cb_data,
> > > +				       const struct regcache *regcache)
> > > +{
> > > +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> > > +
> > > +  cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET,
> > > +      &arm_none_gregset, nullptr, cb_data);
> > > +
> > > +  if (tdep->vfp_register_count > 0)
> > > +    cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP,
> > > +	&arm_none_vfpregset, "VFP floating-point", cb_data);
> > > +}
> > > +
> > > +/* Initialize ARM bare-metal ABI info.  */
> > > +
> > > +static void
> > > +arm_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> > > +{
> > > +#ifdef HAVE_ELF
> > > +  elf_none_init_abi (gdbarch);
> > > +#endif
> > > +
> > > +  /* Iterate over registers for reading and writing bare metal ARM core
> > > +     files.  */
> > > +  set_gdbarch_iterate_over_regset_sections
> > > +    (gdbarch, arm_none_iterate_over_regset_sections);
> > > +}
> > > +
> > > +/* Initialize ARM bare-metal target support.  */
> > > +
> > > +void _initialize_arm_none_tdep ();
> > > +void
> > > +_initialize_arm_none_tdep ()
> > > +{
> > > +  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NONE,
> > > +			  arm_none_init_abi);
> > > +}
> > > diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> > > index 91020678bf0..f81f03b96c9 100644
> > > --- a/gdb/configure.tgt
> > > +++ b/gdb/configure.tgt
> > > @@ -65,7 +65,8 @@ arc*-*-*)
> > >   arm*-*-*)
> > >   	cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \
> > > -		 arch/arm-get-next-pcs.o arm-tdep.o";;
> > > +		 arch/arm-get-next-pcs.o arm-tdep.o arm-none-tdep.o"
> > > +	;;
> > >   hppa*-*-*)
> > >   	# Target: HP PA-RISC
> > > -- 
> > > 2.25.4
> > > 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* SV: [PATCHv3 9/9] gdb/arm: add support for bare-metal core dumps
  2021-05-13 13:56         ` Andrew Burgess
@ 2021-05-15 13:52           ` sarah@hederstierna.com
  2021-06-01  9:00             ` Andrew Burgess
  0 siblings, 1 reply; 57+ messages in thread
From: sarah@hederstierna.com @ 2021-05-15 13:52 UTC (permalink / raw)
  To: Andrew Burgess, Luis Machado; +Cc: gdb-patches


> > On 5/13/21 10:42 AM, Andrew Burgess wrote:
> > > When I merged the RISC-V bare-metal core file support I never merged
> > > this patch (ARM bare-metal corefile support).
> > >
> > > I've been in discussion with the author of the original patch
> > > off-list, and this version of the patch does provide all of the
> > > functionality that was present in their original work, and the
> > > original author does have a copyright assignment in place.
> >
> > It would be nice if the original author tested this on his end to make sure
> > it works for his purpose.
> >
> > >
> > > I would like to propose merging this patch, even though I personally
> > > have not tested it.
> >
> > I'm fine with that, but if the original author can test this, it would be
> > better.
>
> Sorry, that was what I was (badly) trying to say before.  I'v CC'd
> Fredrik, hopefully he can drop in and confirm this meets his needs.

Hi, I tested Andrews variant of the ARM corefile patch and it worked as expected in my tests.
I think it can be merged.
If you want to run it against the gdb ARM simulator, there may be some minor tweaks to be done, but that could be in an additional patch later I think.
Thanks! BR Fredrik

> Thanks,
> Andrew
>
>
>
> >
> > Thoughts?
> >
> > Andrew
> >
> >
> >
> > * Andrew Burgess <andrew.burgess@embecosm.com> [2021-02-15 17:29:12 +0000]:
> >
> > >         **************** WARNING ********************
> > >
> > > This commit is based off a patch from the mailing list, I don't know
> > > if the author of this patch has a copyright assignment in place.  As
> > > such this commit MUST NOT be pushed to upstream master until this has
> > > been cleared up.  A link to the original mailing list posting can be
> > > found in the patch description below.
> > >
> > >         ************** END WARNING ******************
> > >
> > > This commit adds support for bare metal core dumps on the ARM target,
> > > and is based off of this patch submitted to the mailing list:
> > >
> > >    https://sourceware.org/pipermail/gdb-patches/2020-October/172845.html
> > >
> > > Compared to the version linked above this version is updated to take
> > > account of recent changes to the core dump infrastructure in GDB,
> > > there is now more shared infrastructure for core dumping within GDB,
> > > and also some common bare metal core dumping infrastructure.  As a
> > > result this patch is smaller than the original proposed patch.
> > >
> > > Further, the original patch included some unrelated changes to the
> > > simulator that have been removed from this version.
> > >
> > > I have written a ChangeLog entry as the original patch was missing
> > > one.
> > >
> > > I have done absolutely no testing of this patch.  It is based on the
> > > original submitted patch, which I assume was tested, but after my
> > > modifications things might have been broken.
> > >
> > > The core dump format is based around generating an ELF containing
> > > sections for the writable regions of memory that a user could be
> > > using.  Which regions are dumped rely on GDB's existing common core
> > > dumping code, GDB will attempt to figure out the stack and heap as
> > > well as copying out writable data sections as identified by the
> > > original ELF.
> > >
> > > Register information is added to the core dump using notes, just as it
> > > is for Linux of FreeBSD core dumps.  The note types used consist of
> > > the 2 basic types you would expect in a OS based core dump,
> > > NT_PRPSINFO, NT_PRSTATUS, along with the architecture specific
> > > NT_ARM_VFP note.
> > >
> > > The data layouts for each note type are described below, in all cases,
> > > all padding fields should be set to zero.
> > >
> > > Note NT_PRPSINFO is optional.  Its data layout is:
> > >
> > >    struct prpsinfo_t
> > >    {
> > >      uint8_t padding[28];
> > >      char fname[16];
> > >      char psargs[80];
> > >    }
> > >
> > > Field 'fname' - null terminated string consisting of the basename of
> > >      (up to the fist 15 characters of) the executable.  Any additional
> > >      space should be set to zero.  If there's no executable name then
> > >      this field can be set to all zero.
> > >
> > > Field 'psargs' - a null terminated string up to 80 characters in
> > >      length.  Any additional space should be filled with zero.  This
> > >      field contains the full executable path and any arguments passed
> > >      to the executable.  If there's nothing sensible to write in this
> > >      field then fill it with zero.
> > >
> > > Note NT_PRSTATUS is required, its data layout is:
> > >
> > >    struct prstatus_t
> > >    {
> > >      uint8_t padding_1[12];
> > >      uint16_t sig;
> > >      uint8_t padding_2[10];
> > >      uint32_t thread_id;
> > >      uint8_t padding_3[44];
> > >      uint32_t gregs[18];
> > >    }
> > >
> > > Field 'sig' - the signal that stopped this thread.  It's implementation
> > >      defined what this field actually means.  Within GDB this will be
> > >      the signal number that the remote target reports as the stop
> > >      reason for this thread.
> > >
> > > Field 'thread_is' - the thread id for this thread.  It's implementation
> > >      defined what this field actually means.  Within GDB this will be
> > >      thread thread-id that is assigned to each remote thread.
> > >
> > > Field 'gregs' - holds the general purpose registers $a1 through to $pc
> > >      at indices 0 to 15.  At index 16 the program status register.
> > >      Index 17 should be set to zero.
> > >
> > > Note NT_ARM_VFP is optional, its data layout is:
> > >
> > >    armvfp_t
> > >    {
> > >      uint64_t regs[32];
> > >      uint32_t fpscr;
> > >    }
> > >
> > > Field 'regs' - holds the 32 d-registers 0 to 31 in order.
> > >
> > > Field 'fpscr' - holds the fpscr register.
> > >
> > > The rules for ordering the notes is the same as for Linux.  The
> > > NT_PRSTATUS note must come before any other notes about additional
> > > register sets.  And for multi-threaded targets all registers for a
> > > single thread should be grouped together.  This is because only
> > > NT_PRSTATUS includes a thread-id, all additional register notes after
> > > a NT_PRSTATUS are assumed to belong to the same thread until a
> > > different NT_PRSTATUS is seen.
> > >
> > > gdb/ChangeLog:
> > >
> > >   PR gdb/14383
> > >   * Makefile.in (ALL_TARGET_OBS): Add arm-none-tdep.o.
> > >   (ALLDEPFILES): Add arm-none-tdep.c
> > >   * arm-none-tdep.c: New file.
> > >   * configure.tgt (arm*-*-*): Add arm-none-tdep.o to cpu_obs.
> > > ---
> > >   gdb/ChangeLog       |   9 ++
> > >   gdb/Makefile.in     |   2 +
> > >   gdb/arm-none-tdep.c | 213 ++++++++++++++++++++++++++++++++++++++++++++
> > >   gdb/configure.tgt   |   3 +-
> > >   4 files changed, 226 insertions(+), 1 deletion(-)
> > >   create mode 100644 gdb/arm-none-tdep.c
> > >
> > > diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> > > index a6ca5a53655..77c2401e272 100644
> > > --- a/gdb/Makefile.in
> > > +++ b/gdb/Makefile.in
> > > @@ -728,6 +728,7 @@ ALL_TARGET_OBS = \
> > >           arm-fbsd-tdep.o \
> > >           arm-linux-tdep.o \
> > >           arm-netbsd-tdep.o \
> > > + arm-none-tdep.o \
> > >           arm-obsd-tdep.o \
> > >           arm-pikeos-tdep.o \
> > >           arm-tdep.o \
> > > @@ -2171,6 +2172,7 @@ ALLDEPFILES = \
> > >           arm-linux-tdep.c \
> > >           arm-netbsd-nat.c \
> > >           arm-netbsd-tdep.c \
> > > + arm-none-tdep.c \
> > >           arm-obsd-tdep.c \
> > >           arm-tdep.c \
> > >           avr-tdep.c \
> > > diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
> > > new file mode 100644
> > > index 00000000000..2816c5954b3
> > > --- /dev/null
> > > +++ b/gdb/arm-none-tdep.c
> > > @@ -0,0 +1,213 @@
> > > +/* none on ARM target support.
> > > +
> > > +   Copyright (C) 2020-2021 Free Software Foundation, Inc.
> > > +
> > > +   This file is part of GDB.
> > > +
> > > +   This program is free software; you can redistribute it and/or modify
> > > +   it under the terms of the GNU General Public License as published by
> > > +   the Free Software Foundation; either version 3 of the License, or
> > > +   (at your option) any later version.
> > > +
> > > +   This program is distributed in the hope that it will be useful,
> > > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > > +   GNU General Public License for more details.
> > > +
> > > +   You should have received a copy of the GNU General Public License
> > > +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> > > +
> > > +#include "defs.h"
> > > +#include "arm-tdep.h"
> > > +#include "arch-utils.h"
> > > +#include "regcache.h"
> > > +#include "elf-bfd.h"
> > > +#include "regset.h"
> > > +#include "user-regs.h"
> > > +
> > > +#ifdef HAVE_ELF
> > > +#include "elf-none-tdep.h"
> > > +#endif
> > > +
> > > +/* Core file and register set support.  */
> > > +#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
> > > +
> > > +/* Support VFP register format.  */
> > > +#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
> > > +
> > > +/* The index to access CPSR in user_regs as defined in GLIBC.  */
> > > +#define ARM_NONE_CPSR_GREGNUM 16
> > > +
> > > +/* Supply register REGNUM from buffer GREGS_BUF (length LEN bytes) into
> > > +   REGCACHE.  If REGNUM is -1 then supply all registers.  The set of
> > > +   registers that this function will supply is limited to the general
> > > +   purpose registers.
> > > +
> > > +   The layout of the registers here is based on the ARM GNU/Linux
> > > +   layout.  */
> > > +
> > > +static void
> > > +arm_none_supply_gregset (const struct regset *regset,
> > > +                  struct regcache *regcache,
> > > +                  int regnum, const void *gregs_buf, size_t len)
> > > +{
> > > +  struct gdbarch *gdbarch = regcache->arch ();
> > > +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> > > +  const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
> > > +
> > > +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
> > > +    if (regnum == -1 || regnum == regno)
> > > +      regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
> > > +
> > > +  if (regnum == ARM_PS_REGNUM || regnum == -1)
> > > +    {
> > > +      if (arm_apcs_32)
> > > + regcache->raw_supply (ARM_PS_REGNUM,
> > > +                       gregs + ARM_INT_REGISTER_SIZE
> > > +                       * ARM_NONE_CPSR_GREGNUM);
> > > +      else
> > > + regcache->raw_supply (ARM_PS_REGNUM,
> > > +                      gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> > > +    }
> > > +
> > > +  if (regnum == ARM_PC_REGNUM || regnum == -1)
> > > +    {
> > > +      gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
> > > +
> > > +      CORE_ADDR reg_pc
> > > + = extract_unsigned_integer (gregs + ARM_INT_REGISTER_SIZE
> > > +                             * ARM_PC_REGNUM,
> > > +                             ARM_INT_REGISTER_SIZE, byte_order);
> > > +      reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
> > > +      store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
> > > +                       reg_pc);
> > > +      regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
> > > +    }
> > > +}
> > > +
> > > +/* Collect register REGNUM from REGCACHE and place it into buffer GREGS_BUF
> > > +   (length LEN bytes).  If REGNUM is -1 then collect all registers.  The
> > > +   set of registers that this function will collect is limited to the
> > > +   general purpose registers.
> > > +
> > > +   The layout of the registers here is based on the ARM GNU/Linux
> > > +   layout.  */
> > > +
> > > +static void
> > > +arm_none_collect_gregset (const struct regset *regset,
> > > +                   const struct regcache *regcache,
> > > +                   int regnum, void *gregs_buf, size_t len)
> > > +{
> > > +  gdb_byte *gregs = (gdb_byte *) gregs_buf;
> > > +
> > > +  for (int regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
> > > +    if (regnum == -1 || regnum == regno)
> > > +      regcache->raw_collect (regno,
> > > +                      gregs + ARM_INT_REGISTER_SIZE * regno);
> > > +
> > > +  if (regnum == ARM_PS_REGNUM || regnum == -1)
> > > +    {
> > > +      if (arm_apcs_32)
> > > + regcache->raw_collect (ARM_PS_REGNUM,
> > > +                        gregs + ARM_INT_REGISTER_SIZE
> > > +                        * ARM_NONE_CPSR_GREGNUM);
> > > +      else
> > > + regcache->raw_collect (ARM_PS_REGNUM,
> > > +                        gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> > > +    }
> > > +
> > > +  if (regnum == ARM_PC_REGNUM || regnum == -1)
> > > +    regcache->raw_collect (ARM_PC_REGNUM,
> > > +                    gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
> > > +}
> > > +
> > > +/* Supply VFP registers from REGS_BUF into REGCACHE.  */
> > > +
> > > +static void
> > > +arm_none_supply_vfp (const struct regset *regset,
> > > +              struct regcache *regcache,
> > > +              int regnum, const void *regs_buf, size_t len)
> > > +{
> > > +  const gdb_byte *regs = (const gdb_byte *) regs_buf;
> > > +
> > > +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
> > > +    regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
> > > +
> > > +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
> > > +    if (regnum == -1 || regnum == regno)
> > > +      regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
> > > +}
> > > +
> > > +/* Collect VFP registers from REGCACHE into REGS_BUF.  */
> > > +
> > > +static void
> > > +arm_none_collect_vfp (const struct regset *regset,
> > > +               const struct regcache *regcache,
> > > +               int regnum, void *regs_buf, size_t len)
> > > +{
> > > +  gdb_byte *regs = (gdb_byte *) regs_buf;
> > > +
> > > +  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
> > > +    regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
> > > +
> > > +  for (int regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
> > > +    if (regnum == -1 || regnum == regno)
> > > +      regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
> > > +}
> > > +
> > > +/* The general purpose register set.  */
> > > +
> > > +static const struct regset arm_none_gregset =
> > > +  {
> > > +    nullptr, arm_none_supply_gregset, arm_none_collect_gregset
> > > +  };
> > > +
> > > +/* The VFP register set.  */
> > > +
> > > +static const struct regset arm_none_vfpregset =
> > > +  {
> > > +    nullptr, arm_none_supply_vfp, arm_none_collect_vfp
> > > +  };
> > > +
> > > +/* Iterate over core file register note sections.  */
> > > +
> > > +static void
> > > +arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
> > > +                                iterate_over_regset_sections_cb *cb,
> > > +                                void *cb_data,
> > > +                                const struct regcache *regcache)
> > > +{
> > > +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> > > +
> > > +  cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET,
> > > +      &arm_none_gregset, nullptr, cb_data);
> > > +
> > > +  if (tdep->vfp_register_count > 0)
> > > +    cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP,
> > > + &arm_none_vfpregset, "VFP floating-point", cb_data);
> > > +}
> > > +
> > > +/* Initialize ARM bare-metal ABI info.  */
> > > +
> > > +static void
> > > +arm_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> > > +{
> > > +#ifdef HAVE_ELF
> > > +  elf_none_init_abi (gdbarch);
> > > +#endif
> > > +
> > > +  /* Iterate over registers for reading and writing bare metal ARM core
> > > +     files.  */
> > > +  set_gdbarch_iterate_over_regset_sections
> > > +    (gdbarch, arm_none_iterate_over_regset_sections);
> > > +}
> > > +
> > > +/* Initialize ARM bare-metal target support.  */
> > > +
> > > +void _initialize_arm_none_tdep ();
> > > +void
> > > +_initialize_arm_none_tdep ()
> > > +{
> > > +  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NONE,
> > > +                   arm_none_init_abi);
> > > +}
> > > diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> > > index 91020678bf0..f81f03b96c9 100644
> > > --- a/gdb/configure.tgt
> > > +++ b/gdb/configure.tgt
> > > @@ -65,7 +65,8 @@ arc*-*-*)
> > >   arm*-*-*)
> > >           cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \
> > > -          arch/arm-get-next-pcs.o arm-tdep.o";;
> > > +          arch/arm-get-next-pcs.o arm-tdep.o arm-none-tdep.o"
> > > + ;;
> > >   hppa*-*-*)
> > >           # Target: HP PA-RISC
> > > --
> > > 2.25.4
> > >

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: SV: [PATCHv3 9/9] gdb/arm: add support for bare-metal core dumps
  2021-05-15 13:52           ` SV: " sarah@hederstierna.com
@ 2021-06-01  9:00             ` Andrew Burgess
  0 siblings, 0 replies; 57+ messages in thread
From: Andrew Burgess @ 2021-06-01  9:00 UTC (permalink / raw)
  To: sarah@hederstierna.com; +Cc: Luis Machado, gdb-patches

* sarah@hederstierna.com <hedersti@hederstierna.com> [2021-05-15 13:52:31 +0000]:

> 
> > > On 5/13/21 10:42 AM, Andrew Burgess wrote:
> > > > When I merged the RISC-V bare-metal core file support I never merged
> > > > this patch (ARM bare-metal corefile support).
> > > >
> > > > I've been in discussion with the author of the original patch
> > > > off-list, and this version of the patch does provide all of the
> > > > functionality that was present in their original work, and the
> > > > original author does have a copyright assignment in place.
> > >
> > > It would be nice if the original author tested this on his end to make sure
> > > it works for his purpose.
> > >
> > > >
> > > > I would like to propose merging this patch, even though I personally
> > > > have not tested it.
> > >
> > > I'm fine with that, but if the original author can test this, it would be
> > > better.
> >
> > Sorry, that was what I was (badly) trying to say before.  I'v CC'd
> > Fredrik, hopefully he can drop in and confirm this meets his needs.
> 
> Hi, I tested Andrews variant of the ARM corefile patch and it worked as expected in my tests.
> I think it can be merged.
> If you want to run it against the gdb ARM simulator, there may be some minor tweaks to be done, but that could be in an additional patch later I think.
> Thanks! BR Fredrik


I have now pushed this patch.

Please let me know if any issues crop up.

Thanks,
Andrew

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2021-06-01  9:00 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-20 20:23 [PATCHv2 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
2021-01-20 20:23 ` [PATCHv2 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
2021-01-22 12:01   ` Strasuns, Mihails
2021-01-22 18:50   ` Tom Tromey
2021-02-01 11:56   ` Andrew Burgess
2021-02-09 21:52     ` Andrew Burgess
2021-01-20 20:23 ` [PATCHv2 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
2021-01-22 10:47   ` Strasuns, Mihails
2021-01-22 19:30     ` Andrew Burgess
2021-01-25 10:11       ` Strasuns, Mihails
2021-01-25 11:20         ` Andrew Burgess
2021-02-01 12:05   ` PING: " Andrew Burgess
2021-02-01 15:10     ` Strasuns, Mihails
2021-02-01 13:29   ` Luis Machado
2021-02-10 20:45   ` Jim Wilson
2021-01-20 20:23 ` [PATCHv2 3/9] gdb: write target description into " Andrew Burgess
2021-01-22 19:15   ` Tom Tromey
2021-02-01 13:37   ` Luis Machado
2021-01-20 20:23 ` [PATCHv2 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
2021-02-01 12:03   ` PING: " Andrew Burgess
2021-02-01 13:48   ` Luis Machado
2021-02-01 14:44     ` Andrew Burgess
2021-02-10 20:57   ` Jim Wilson
2021-01-20 20:23 ` [PATCHv2 5/9] gdb/riscv: introduce bare metal core dump support Andrew Burgess
2021-02-01 14:05   ` Luis Machado
2021-02-03  3:04     ` Palmer Dabbelt
2021-01-20 20:23 ` [PATCHv2 6/9] bfd/binutils: add support for RISC-V CSRs in core files Andrew Burgess
2021-02-01 12:00   ` Andrew Burgess
2021-02-01 14:08     ` Luis Machado
2021-02-10 21:00     ` Jim Wilson
2021-01-20 20:23 ` [PATCHv2 7/9] gdb/riscv: make riscv target description names global Andrew Burgess
2021-02-01 14:22   ` Luis Machado
2021-01-20 20:23 ` [PATCHv2 8/9] gdb/riscv: write CSRs into baremetal core dumps Andrew Burgess
2021-02-01 14:33   ` Luis Machado
2021-01-20 20:23 ` [PATCHv2 9/9] gdb/arm: add support for bare-metal " Andrew Burgess
2021-02-01 14:51   ` Luis Machado
2021-01-22 19:28 ` [PATCHv2 0/9] Bare-metal core dumps for RISC-V Tom Tromey
2021-02-15 17:29 ` [PATCHv3 " Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 1/9] gdb: unify parts of the Linux and FreeBSD core dumping code Andrew Burgess
2021-02-15 22:56     ` Lancelot SIX
2021-02-16 16:55       ` Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 2/9] bfd/binutils: support for gdb target descriptions in the core file Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 3/9] gdb: write target description into " Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 4/9] bfd/riscv: prepare to handle bare metal core dump creation Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 5/9] gdb/riscv: introduce bare metal core dump support Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 6/9] bfd/binutils: add support for RISC-V CSRs in core files Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 7/9] gdb/riscv: make riscv target description names global Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 8/9] gdb/riscv: write CSRs into baremetal core dumps Andrew Burgess
2021-02-15 17:29   ` [PATCHv3 9/9] gdb/arm: add support for bare-metal " Andrew Burgess
2021-05-13 13:42     ` Andrew Burgess
2021-05-13 13:51       ` Luis Machado
2021-05-13 13:56         ` Andrew Burgess
2021-05-15 13:52           ` SV: " sarah@hederstierna.com
2021-06-01  9:00             ` Andrew Burgess
2021-03-01 10:32   ` [PATCHv3 0/9] Bare-metal core dumps for RISC-V Andrew Burgess
2021-03-01 14:45     ` Nick Clifton
2021-03-05 17:35     ` Andrew Burgess

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).