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

Luis Machado via Gdb-patches
2020-10-21T14:38:28Z

Hi,

Apologies for the delay in replying.

I think this still needs some more work to cut it down to the bare
essentials for a core file. I see quite a few things that are
linux-specific and that shouldn't be included in a potential all-arch
bare-metal core file format.

As Simon said, siginfo and auxv are *nix concepts. HWCAP_* constants
are also *nix/Linux concepts. So those should be dropped unless there is
good reason to include them.

If we require some of their data, then we should think of a way to make
that available. For example, AUXV's entry point information.

We should really discuss what the generic core file format for
bare-metal targets will look like before having a possible patch to
implement it. At least that's my take on it.

Otherwise we risk having an implementation without a formal definition.
And core files are already somewhat vaguely-defined anyway.

On 10/20/20 6:58 PM, Fredrik Hederstierna wrote:
> 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 */
>