[PATCH v2] Support for corefiles for arm-none-eabi target.

Fredrik Hederstierna fredrik@hederstierna.com
Tue Oct 20 21:58:17 GMT 2020


From: fredrikhederstierna <fredrik@hederstierna.com>

---
 gdb/arm-none-tdep.c | 368 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/arm-none-tdep.h |  60 ++++++++
 gdb/arm-tdep.c      |   8 +
 gdb/configure.tgt   |   6 +-
 gdb/none-tdep.c     | 335 ++++++++++++++++++++++++++++++++++++++++
 gdb/none-tdep.h     |  39 +++++
 6 files changed, 815 insertions(+), 1 deletion(-)
 create mode 100644 gdb/arm-none-tdep.c
 create mode 100644 gdb/arm-none-tdep.h
 create mode 100644 gdb/none-tdep.c
 create mode 100644 gdb/none-tdep.h

diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
new file mode 100644
index 0000000000..9d83a8b913
--- /dev/null
+++ b/gdb/arm-none-tdep.c
@@ -0,0 +1,368 @@
+/* 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 "target.h"
+#include "value.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "regcache.h"
+#include "solib-svr4.h"
+#include "osabi.h"
+#include "regset.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+#include "breakpoint.h"
+#include "auxv.h"
+
+#include "aarch32-tdep.h"
+#include "arch/arm.h"
+#include "arm-tdep.h"
+#include "arm-none-tdep.h"
+#include "glibc-tdep.h"
+#include "arch-utils.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include "symfile.h"
+
+#include "cli/cli-utils.h"
+#include "stap-probe.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
+#include "elf-bfd.h"
+#include "coff/internal.h"
+#include "elf/arm.h"
+
+#include "elf/common.h"
+
+/* ---- based on arm-linux-tdep.h ---- */
+
+#define ARM_NONE_SIZEOF_NWFPE (8 * ARM_FP_REGISTER_SIZE \
+				+ 2 * ARM_INT_REGISTER_SIZE \
+				+ 8 + ARM_INT_REGISTER_SIZE)
+
+/* The index to access CSPR in user_regs defined in GLIBC.  */
+#define ARM_CPSR_GREGNUM 16
+
+/* Support for register format used by the NWFPE FPA emulator.  Each
+   register takes three words, where either the first one, two, or
+   three hold a single, double, or extended precision value (depending
+   on the corresponding tag).  The register set is eight registers,
+   followed by the fpsr and fpcr, followed by eight tag bytes, and a
+   final word flag which indicates whether NWFPE has been
+   initialized.  */
+
+#define NWFPE_FPSR_OFFSET (8 * ARM_FP_REGISTER_SIZE)
+#define NWFPE_FPCR_OFFSET (NWFPE_FPSR_OFFSET + ARM_INT_REGISTER_SIZE)
+#define NWFPE_TAGS_OFFSET (NWFPE_FPCR_OFFSET + ARM_INT_REGISTER_SIZE)
+#define NWFPE_INITFLAG_OFFSET (NWFPE_TAGS_OFFSET + 8)
+
+/* Reuse ARM GNU/Linux HWCAP values for none.  These are in defined in
+   <asm/elf.h> in current kernels.  */
+#define HWCAP_VFP       64
+#define HWCAP_IWMMXT    512
+#define HWCAP_NEON      4096
+#define HWCAP_VFPv3     8192
+#define HWCAP_VFPv3D16  16384
+
+/* Core file and register set support.  */
+
+#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
+
+/* ---- based on arm-linux-tdep.c ---- */
+
+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;
+  int regno;
+  CORE_ADDR reg_pc;
+  gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
+
+  for (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_CPSR_GREGNUM);
+      else
+	regcache->raw_supply (ARM_PS_REGNUM,
+			     gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
+    }
+
+  if (regnum == ARM_PC_REGNUM || regnum == -1)
+    {
+      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);
+    }
+}
+
+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;
+  int regno;
+
+  for (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_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);
+}
+
+/* Support for register format used by the NWFPE FPA emulator.  */
+
+#define typeNone		0x00
+#define typeSingle		0x01
+#define typeDouble		0x02
+#define typeExtended		0x03
+
+void
+arm_none_supply_nwfpe_register (struct regcache *regcache, int regno,
+				const gdb_byte *regs)
+{
+  const gdb_byte *reg_data;
+  gdb_byte reg_tag;
+  gdb_byte buf[ARM_FP_REGISTER_SIZE];
+
+  reg_data = regs + (regno - ARM_F0_REGNUM) * ARM_FP_REGISTER_SIZE;
+  reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET];
+  memset (buf, 0, ARM_FP_REGISTER_SIZE);
+
+  switch (reg_tag)
+    {
+    case typeSingle:
+      memcpy (buf, reg_data, 4);
+      break;
+    case typeDouble:
+      memcpy (buf, reg_data + 4, 4);
+      memcpy (buf + 4, reg_data, 4);
+      break;
+    case typeExtended:
+      /* We want sign and exponent, then least significant bits,
+	 then most significant.  NWFPE does sign, most, least.  */
+      memcpy (buf, reg_data, 4);
+      memcpy (buf + 4, reg_data + 8, 4);
+      memcpy (buf + 8, reg_data + 4, 4);
+      break;
+    default:
+      break;
+    }
+
+  regcache->raw_supply (regno, buf);
+}
+
+void
+arm_none_collect_nwfpe_register (const struct regcache *regcache, int regno,
+				 gdb_byte *regs)
+{
+  gdb_byte *reg_data;
+  gdb_byte reg_tag;
+  gdb_byte buf[ARM_FP_REGISTER_SIZE];
+
+  regcache->raw_collect (regno, buf);
+
+  /* NOTE drow/2006-06-07: This code uses the tag already in the
+     register buffer.  I've preserved that when moving the code
+     from the native file to the target file.  But this doesn't
+     always make sense.  */
+
+  reg_data = regs + (regno - ARM_F0_REGNUM) * ARM_FP_REGISTER_SIZE;
+  reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET];
+
+  switch (reg_tag)
+    {
+    case typeSingle:
+      memcpy (reg_data, buf, 4);
+      break;
+    case typeDouble:
+      memcpy (reg_data, buf + 4, 4);
+      memcpy (reg_data + 4, buf, 4);
+      break;
+    case typeExtended:
+      memcpy (reg_data, buf, 4);
+      memcpy (reg_data + 4, buf + 8, 4);
+      memcpy (reg_data + 8, buf + 4, 4);
+      break;
+    default:
+      break;
+    }
+}
+
+void
+arm_none_supply_nwfpe (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;
+  int regno;
+
+  if (regnum == ARM_FPS_REGNUM || regnum == -1)
+    regcache->raw_supply (ARM_FPS_REGNUM,
+			 regs + NWFPE_FPSR_OFFSET);
+
+  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      arm_none_supply_nwfpe_register (regcache, regno, regs);
+}
+
+void
+arm_none_collect_nwfpe (const struct regset *regset,
+			 const struct regcache *regcache,
+			 int regnum, void *regs_buf, size_t len)
+{
+  gdb_byte *regs = (gdb_byte *) regs_buf;
+  int regno;
+
+  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      arm_none_collect_nwfpe_register (regcache, regno, regs);
+
+  if (regnum == ARM_FPS_REGNUM || regnum == -1)
+    regcache->raw_collect (ARM_FPS_REGNUM,
+			   regs + ARM_INT_REGISTER_SIZE * ARM_FPS_REGNUM);
+}
+
+/* Support VFP register format.  */
+
+#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
+
+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;
+  int regno;
+
+  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
+    regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
+
+  for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
+}
+
+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;
+  int regno;
+
+  if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
+    regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
+
+  for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
+}
+
+static const struct regset arm_none_gregset =
+  {
+    NULL, arm_none_supply_gregset, arm_none_collect_gregset
+  };
+
+static const struct regset arm_none_fpregset =
+  {
+    NULL, arm_none_supply_nwfpe, arm_none_collect_nwfpe
+  };
+
+static const struct regset arm_none_vfpregset =
+  {
+    NULL, arm_none_supply_vfp, arm_none_collect_vfp
+  };
+
+/* Iterate over core file register note sections.  */
+
+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, NULL, 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);
+  else if (tdep->have_fpa_registers)
+    cb (".reg2", ARM_NONE_SIZEOF_NWFPE, ARM_NONE_SIZEOF_NWFPE,
+	&arm_none_fpregset, "FPA floating-point", cb_data);
+}
+
+/* Determine target description from core file.  */
+
+const struct target_desc *
+arm_none_core_read_description (struct gdbarch *gdbarch,
+				struct target_ops *target,
+				bfd *abfd)
+{
+  CORE_ADDR arm_hwcap = 0;
+  if (target_auxv_search (target, AT_HWCAP, &arm_hwcap) != 1)
+    return nullptr;
+
+  if (arm_hwcap & HWCAP_VFP)
+    {
+      /* NEON implies VFPv3-D32 or no-VFP unit.  Say that we only support
+         Neon with VFPv3-D32.  */
+      if (arm_hwcap & HWCAP_NEON)
+	return aarch32_read_description ();
+      else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+	return arm_read_description (ARM_FP_TYPE_VFPV3);
+
+      return arm_read_description (ARM_FP_TYPE_VFPV2);
+    }
+
+  return nullptr;
+}
diff --git a/gdb/arm-none-tdep.h b/gdb/arm-none-tdep.h
new file mode 100644
index 0000000000..7927c0aff3
--- /dev/null
+++ b/gdb/arm-none-tdep.h
@@ -0,0 +1,60 @@
+/* none on ARM target support, prototypes.
+
+   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/>.  */
+
+#ifndef ARM_NONE_TDEP_H
+#define ARM_NONE_TDEP_H
+
+#include "gdbarch.h"
+#include "target.h"
+#include "bfd.h"
+
+struct regset;
+struct regcache;
+
+void arm_none_supply_gregset (const struct regset *regset,
+			       struct regcache *regcache,
+			       int regnum, const void *gregs_buf, size_t len);
+void arm_none_collect_gregset (const struct regset *regset,
+				const struct regcache *regcache,
+				int regnum, void *gregs_buf, size_t len);
+
+void arm_none_supply_nwfpe_register (struct regcache *regcache, int regno,
+				     const gdb_byte *regs);
+void arm_none_collect_nwfpe_register (const struct regcache *regcache, int regno,
+				      gdb_byte *regs);
+
+void arm_none_supply_nwfpe (const struct regset *regset,
+			     struct regcache *regcache,
+			     int regnum, const void *regs_buf, size_t len);
+void arm_none_collect_nwfpe (const struct regset *regset,
+			      const struct regcache *regcache,
+			      int regnum, void *regs_buf, size_t len);
+
+void
+arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                       iterate_over_regset_sections_cb *cb,
+                                       void *cb_data,
+                                       const struct regcache *regcache);
+
+const struct target_desc *
+arm_none_core_read_description (struct gdbarch *gdbarch,
+				struct target_ops *target,
+				bfd *abfd);
+
+#endif /* ARM_NONE_TDEP_H */
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index a214f22d7a..be47cc2228 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -50,6 +50,8 @@
 #include "arch/arm.h"
 #include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
+#include "none-tdep.h"
+#include "arm-none-tdep.h"
 #include "gdb/sim-arm.h"
 
 #include "elf-bfd.h"
@@ -9453,6 +9455,12 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Virtual tables.  */
   set_gdbarch_vbit_in_delta (gdbarch, 1);
 
+  /* Default none core file support, can be overridden by osabi. */
+  none_init_corefile (info, gdbarch);
+  set_gdbarch_iterate_over_regset_sections (gdbarch,
+                                            arm_none_iterate_over_regset_sections);
+  set_gdbarch_core_read_description (gdbarch, arm_none_core_read_description);
+
   /* Hook in the ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
 
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index d865ecdcb6..f4a1540464 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -64,7 +64,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 \
+		 none-tdep.o arm-none-tdep.o";;
 
 hppa*-*-*)
 	# Target: HP PA-RISC
@@ -798,4 +799,7 @@ for t in x ${gdb_target_obs}; do
   if test "$t" = linux-tdep.o; then
     gdb_have_gcore=true
   fi
+  if test "$t" = arm-none-tdep.o; then
+    gdb_have_gcore=true
+  fi
 done
diff --git a/gdb/none-tdep.c b/gdb/none-tdep.c
new file mode 100644
index 0000000000..5ac5c6c707
--- /dev/null
+++ b/gdb/none-tdep.c
@@ -0,0 +1,335 @@
+/* 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 "gdbtypes.h"
+#include "none-tdep.h"
+#include "auxv.h"
+#include "target.h"
+#include "gdbthread.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "regset.h"
+#include "elf/common.h"
+#include "elf-bfd.h"            /* for elfcore_write_* */
+#include "inferior.h"
+#include "cli/cli-utils.h"
+#include "arch-utils.h"
+#include "gdb_obstack.h"
+#include "observable.h"
+#include "objfiles.h"
+#include "infcall.h"
+#include "gdbcmd.h"
+#include "gdb_regex.h"
+#include "gdbsupport/enum-flags.h"
+#include "gdbsupport/gdb_optional.h"
+
+#include <ctype.h>
+
+/* ---- based on linux-tdep.c ---- */
+
+/* Structure for passing information from
+   none_collect_thread_registers via an iterator to
+   none_collect_regset_section_cb. */
+
+struct none_collect_regset_section_cb_data
+{
+  struct gdbarch *gdbarch;
+  const struct regcache *regcache;
+  bfd *obfd;
+  char *note_data;
+  int *note_size;
+  unsigned long lwp;
+  enum gdb_signal stop_signal;
+  int abort_iteration;
+};
+
+/* Callback for iterate_over_regset_sections that records a single
+   regset in the corefile note section.  */
+
+static void
+none_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 none_collect_regset_section_cb_data *data
+    = (struct none_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 = (char *) elfcore_write_prstatus
+      (data->obfd, data->note_data, data->note_size, data->lwp,
+       gdb_signal_to_host (data->stop_signal), buf.data ());
+  else
+    data->note_data = (char *) elfcore_write_register_note
+      (data->obfd, data->note_data, data->note_size,
+       sect_name, buf.data (), collect_size);
+
+  if (data->note_data == NULL)
+    data->abort_iteration = 1;
+}
+
+/* Records the thread's register state for the corefile note
+   section.  */
+
+static char *
+none_collect_thread_registers (const struct regcache *regcache,
+                               ptid_t ptid, bfd *obfd,
+                               char *note_data, int *note_size,
+                               enum gdb_signal stop_signal)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  struct none_collect_regset_section_cb_data data;
+
+  data.gdbarch = gdbarch;
+  data.regcache = regcache;
+  data.obfd = obfd;
+  data.note_data = note_data;
+  data.note_size = note_size;
+  data.stop_signal = stop_signal;
+  data.abort_iteration = 0;
+
+  /* For remote targets the LWP may not be available, so use the TID.  */
+  data.lwp = ptid.lwp ();
+  if (!data.lwp)
+    data.lwp = ptid.tid ();
+
+  gdbarch_iterate_over_regset_sections (gdbarch,
+					none_collect_regset_section_cb,
+					&data, regcache);
+  return data.note_data;
+}
+
+/* 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.  */
+
+static gdb::byte_vector
+none_get_siginfo_data (thread_info *thread, struct gdbarch *gdbarch)
+{
+  struct type *siginfo_type;
+  LONGEST bytes_read;
+
+  if (!gdbarch_get_siginfo_type_p (gdbarch))
+    return gdb::byte_vector ();
+
+  scoped_restore_current_thread save_current_thread;
+  switch_to_thread (thread);
+
+  siginfo_type = gdbarch_get_siginfo_type (gdbarch);
+
+  gdb::byte_vector buf (TYPE_LENGTH (siginfo_type));
+
+  bytes_read = target_read (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL,
+			    buf.data (), 0, TYPE_LENGTH (siginfo_type));
+  if (bytes_read != TYPE_LENGTH (siginfo_type))
+    buf.clear ();
+
+  return buf;
+}
+
+struct none_corefile_thread_data
+{
+  struct gdbarch *gdbarch;
+  bfd *obfd;
+  char *note_data;
+  int *note_size;
+  enum gdb_signal stop_signal;
+};
+
+/* Records the thread's register state for the corefile note
+   section.  */
+
+static void
+none_corefile_thread (struct thread_info *info,
+                      struct none_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 = none_get_siginfo_data (info, args->gdbarch);
+
+  args->note_data = none_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)
+    if (!siginfo_data.empty ())
+      args->note_data = elfcore_write_note (args->obfd,
+					    args->note_data,
+					    args->note_size,
+					    "CORE", NT_SIGINFO,
+					    siginfo_data.data (),
+					    siginfo_data.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.  */
+
+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;
+}
+
+/* Fills the "to_make_corefile_note" target vector.  Builds the note
+   section for a corefile, and returns it in a malloc buffer.  */
+
+char *
+none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size,
+                          none_collect_thread_registers_ftype collect)
+{
+  struct none_corefile_thread_data thread_args;
+  char *note_data = NULL;
+
+  /* Process information.  */
+  if (get_exec_file (0))
+    {
+      const char *fname = lbasename (get_exec_file (0));
+      char *psargs = xstrdup (fname);
+
+      if (get_inferior_args ())
+        psargs = reconcat (psargs, psargs, " ", get_inferior_args (),
+			   (char *) NULL);
+
+      note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
+                                          fname, psargs);
+      xfree (psargs);
+    }
+
+  if (!note_data)
+    return NULL;
+
+  /* Thread register information.  */
+  try
+    {
+      update_thread_list ();
+    }
+  catch (const gdb_exception_error &e)
+    {
+      exception_print (gdb_stderr, e);
+    }
+
+  /* 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_args.gdbarch = gdbarch;
+  thread_args.obfd = obfd;
+  thread_args.note_data = note_data;
+  thread_args.note_size = note_size;
+  if (signalled_thr != nullptr)
+    thread_args.stop_signal = signalled_thr->suspend.stop_signal;
+  else
+    thread_args.stop_signal = GDB_SIGNAL_0;
+
+  if (signalled_thr != nullptr)
+    none_corefile_thread (signalled_thr, &thread_args);
+  for (thread_info *thr : current_inferior ()->non_exited_threads ())
+    {
+      if (thr == signalled_thr)
+	continue;
+
+      none_corefile_thread (thr, &thread_args);
+    }
+
+  note_data = thread_args.note_data;
+  if (!note_data)
+    return NULL;
+
+  /* Auxillary vector.  */
+  gdb::optional<gdb::byte_vector> auxv =
+    target_read_alloc (current_top_target (), TARGET_OBJECT_AUXV, NULL);
+  if (auxv && !auxv->empty ())
+    {
+      note_data = elfcore_write_note (obfd, note_data, note_size,
+                                      "CORE", NT_AUXV, auxv->data (),
+                                      auxv->size ());
+      if (!note_data)
+        return NULL;
+    }
+
+  /* make_cleanup (xfree, note_data); */
+  return note_data;
+}
+
+static char *
+none_make_corefile_notes_1 (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
+{
+  return none_make_corefile_notes (gdbarch, obfd, note_size,
+                                   none_collect_thread_registers);
+}
+
+/* Setup default core file support for none targets.
+   Can be overridden later by OSABI.  */
+
+void
+none_init_corefile (struct gdbarch_info info,
+                    struct gdbarch *gdbarch)
+{
+  /* Default core file support.  */
+  set_gdbarch_make_corefile_notes (gdbarch, none_make_corefile_notes_1);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_none_tdep;
+
+void
+_initialize_none_tdep (void)
+{
+  /* No special actions.  */
+}
diff --git a/gdb/none-tdep.h b/gdb/none-tdep.h
new file mode 100644
index 0000000000..4aea7004d8
--- /dev/null
+++ b/gdb/none-tdep.h
@@ -0,0 +1,39 @@
+/* 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/>.  */
+
+#ifndef NONE_TDEP_H
+#define NONE_TDEP_H
+
+#include "bfd.h"
+
+struct regcache;
+
+typedef char *(*none_collect_thread_registers_ftype) (const struct regcache *,
+                                                      ptid_t,
+                                                      bfd *, char *, int *,
+                                                      enum gdb_signal);
+char *
+none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size,
+                          none_collect_thread_registers_ftype collect);
+
+void
+none_init_corefile (struct gdbarch_info info,
+                    struct gdbarch *gdbarch);
+
+#endif /* none-tdep.h */
-- 
2.17.1



More information about the Gdb-patches mailing list