Add OpenBSD/arm native support.

Index: gdb/arm-obsd-nat.c
--- gdb/arm-obsd-nat.c.orig
+++ gdb/arm-obsd-nat.c
@@ -0,0 +1,427 @@
+/* Native-dependent code for BSD Unix running on ARM's, for GDB.
+
+   Copyright (C) 1988-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 "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "target.h"
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+
+#include "arm-tdep.h"
+#include "inf-ptrace.h"
+#include "obsd-nat.h"
+
+class arm_openbsd_nat_target final : public obsd_nat_target
+{
+public:
+  /* Add our register access methods.  */
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+
+  const struct target_desc *read_description () override;
+};
+
+static arm_openbsd_nat_target the_arm_openbsd_nat_target;
+
+static void
+arm_supply_gregset (struct regcache *regcache, struct reg *gregset)
+{
+  int regno;
+  CORE_ADDR r_pc;
+
+  /* Integer registers.  */
+  for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
+    regcache->raw_supply (regno, (char *) &gregset->r[regno]);
+
+  regcache->raw_supply (ARM_SP_REGNUM, (char *) &gregset->r_sp);
+  regcache->raw_supply (ARM_LR_REGNUM, (char *) &gregset->r_lr);
+  /* This is ok: we're running native...  */
+  r_pc = gdbarch_addr_bits_remove (regcache->arch (), gregset->r_pc);
+  regcache->raw_supply (ARM_PC_REGNUM, (char *) &r_pc);
+
+  if (arm_apcs_32)
+    regcache->raw_supply (ARM_PS_REGNUM, (char *) &gregset->r_cpsr);
+  else
+    regcache->raw_supply (ARM_PS_REGNUM, (char *) &gregset->r_pc);
+}
+
+static void
+arm_supply_fparegset (struct regcache *regcache, struct fpreg *fparegset)
+{
+  int regno;
+
+  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
+    regcache->raw_supply (regno,
+			  (char *) &fparegset->fp_reg[regno - ARM_F0_REGNUM]);
+
+  regcache->raw_supply (ARM_FPS_REGNUM, (char *) &fparegset->fp_scr);
+}
+
+static void
+fetch_register (struct regcache *regcache, int regno)
+{
+  struct reg inferior_registers;
+  int ret;
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  ret = ptrace (PT_GETREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
+
+  if (ret < 0)
+    {
+      warning (_("unable to fetch general register"));
+      return;
+    }
+
+  switch (regno)
+    {
+    case ARM_SP_REGNUM:
+      regcache->raw_supply (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
+      break;
+
+    case ARM_LR_REGNUM:
+      regcache->raw_supply (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
+      break;
+
+    case ARM_PC_REGNUM:
+      /* This is ok: we're running native...  */
+      inferior_registers.r_pc = gdbarch_addr_bits_remove
+				  (regcache->arch (),
+				   inferior_registers.r_pc);
+      regcache->raw_supply (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
+      break;
+
+    case ARM_PS_REGNUM:
+      if (arm_apcs_32)
+	regcache->raw_supply (ARM_PS_REGNUM,
+			      (char *) &inferior_registers.r_cpsr);
+      else
+	regcache->raw_supply (ARM_PS_REGNUM,
+			      (char *) &inferior_registers.r_pc);
+      break;
+
+    default:
+      regcache->raw_supply (regno, (char *) &inferior_registers.r[regno]);
+      break;
+    }
+}
+
+static void
+fetch_regs (struct regcache *regcache)
+{
+  struct reg inferior_registers;
+  int ret;
+  int regno;
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  ret = ptrace (PT_GETREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
+
+  if (ret < 0)
+    {
+      warning (_("unable to fetch general registers"));
+      return;
+    }
+
+  arm_supply_gregset (regcache, &inferior_registers);
+}
+
+static void
+fetch_fp_register (struct regcache *regcache, int regno)
+{
+  struct fpreg inferior_fp_registers;
+  int ret;
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  ret = ptrace (PT_GETFPREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
+
+  if (ret < 0)
+    {
+      warning (_("unable to fetch floating-point register"));
+      return;
+    }
+
+  switch (regno)
+    {
+    case ARM_FPS_REGNUM:
+      regcache->raw_supply (ARM_FPS_REGNUM,
+			    (char *) &inferior_fp_registers.fp_scr);
+      break;
+
+    default:
+      regcache->raw_supply
+	(regno, (char *) &inferior_fp_registers.fp_reg[regno - ARM_F0_REGNUM]);
+      break;
+    }
+}
+
+static void
+fetch_fp_regs (struct regcache *regcache)
+{
+  struct fpreg inferior_fp_registers;
+  int ret;
+  int regno;
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  ret = ptrace (PT_GETFPREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
+
+  if (ret < 0)
+    {
+      warning (_("unable to fetch general registers"));
+      return;
+    }
+
+  arm_supply_fparegset (regcache, &inferior_fp_registers);
+}
+
+void
+arm_openbsd_nat_target::fetch_registers (struct regcache *regcache, int regno)
+{
+  if (regno >= 0)
+    {
+      if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
+	fetch_register (regcache, regno);
+      else
+	fetch_fp_register (regcache, regno);
+    }
+  else
+    {
+      fetch_regs (regcache);
+      fetch_fp_regs (regcache);
+    }
+}
+
+
+static void
+store_register (const struct regcache *regcache, int regno)
+{
+  gdbarch *gdbarch = regcache->arch ();
+  struct reg inferior_registers;
+  int ret;
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  ret = ptrace (PT_GETREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
+
+  if (ret < 0)
+    {
+      warning (_("unable to fetch general registers"));
+      return;
+    }
+
+  switch (regno)
+    {
+    case ARM_SP_REGNUM:
+      regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
+      break;
+
+    case ARM_LR_REGNUM:
+      regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
+      break;
+
+    case ARM_PC_REGNUM:
+      if (arm_apcs_32)
+	regcache->raw_collect (ARM_PC_REGNUM,
+			       (char *) &inferior_registers.r_pc);
+      else
+	{
+	  unsigned pc_val;
+
+	  regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val);
+	  
+	  pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val);
+	  inferior_registers.r_pc ^= gdbarch_addr_bits_remove
+				       (gdbarch, inferior_registers.r_pc);
+	  inferior_registers.r_pc |= pc_val;
+	}
+      break;
+
+    case ARM_PS_REGNUM:
+      if (arm_apcs_32)
+	regcache->raw_collect (ARM_PS_REGNUM,
+			       (char *) &inferior_registers.r_cpsr);
+      else
+	{
+	  unsigned psr_val;
+
+	  regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val);
+
+	  psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val);
+	  inferior_registers.r_pc = gdbarch_addr_bits_remove
+				      (gdbarch, inferior_registers.r_pc);
+	  inferior_registers.r_pc |= psr_val;
+	}
+      break;
+
+    default:
+      regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]);
+      break;
+    }
+
+  ret = ptrace (PT_SETREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
+
+  if (ret < 0)
+    warning (_("unable to write register %d to inferior"), regno);
+}
+
+static void
+store_regs (const struct regcache *regcache)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  struct reg inferior_registers;
+  int ret;
+  int regno;
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
+    regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]);
+
+  regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
+  regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
+
+  if (arm_apcs_32)
+    {
+      regcache->raw_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
+      regcache->raw_collect (ARM_PS_REGNUM,
+			     (char *) &inferior_registers.r_cpsr);
+    }
+  else
+    {
+      unsigned pc_val;
+      unsigned psr_val;
+
+      regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val);
+      regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val);
+	  
+      pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val);
+      psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val);
+
+      inferior_registers.r_pc = pc_val | psr_val;
+    }
+
+  ret = ptrace (PT_SETREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
+
+  if (ret < 0)
+    warning (_("unable to store general registers"));
+}
+
+static void
+store_fp_register (const struct regcache *regcache, int regno)
+{
+  struct fpreg inferior_fp_registers;
+  int ret;
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  ret = ptrace (PT_GETFPREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
+
+  if (ret < 0)
+    {
+      warning (_("unable to fetch floating-point registers"));
+      return;
+    }
+
+  switch (regno)
+    {
+    case ARM_FPS_REGNUM:
+      regcache->raw_collect (ARM_FPS_REGNUM,
+			     (char *) &inferior_fp_registers.fp_scr);
+      break;
+
+    default:
+      regcache->raw_collect
+	(regno, (char *) &inferior_fp_registers.fp_reg[regno - ARM_F0_REGNUM]);
+      break;
+    }
+
+  ret = ptrace (PT_SETFPREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
+
+  if (ret < 0)
+    warning (_("unable to write register %d to inferior"), regno);
+}
+
+static void
+store_fp_regs (const struct regcache *regcache)
+{
+  struct fpreg inferior_fp_registers;
+  int ret;
+  int regno;
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
+    regcache->raw_collect
+      (regno, (char *) &inferior_fp_registers.fp_reg[regno - ARM_F0_REGNUM]);
+
+  regcache->raw_collect (ARM_FPS_REGNUM,
+			 (char *) &inferior_fp_registers.fp_scr);
+
+  ret = ptrace (PT_SETFPREGS, pid,
+		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
+
+  if (ret < 0)
+    warning (_("unable to store floating-point registers"));
+}
+
+void
+arm_openbsd_nat_target::store_registers (struct regcache *regcache, int regno)
+{
+  if (regno >= 0)
+    {
+      if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
+	store_register (regcache, regno);
+      else
+	store_fp_register (regcache, regno);
+    }
+  else
+    {
+      store_regs (regcache);
+      store_fp_regs (regcache);
+    }
+}
+
+const struct target_desc *
+arm_openbsd_nat_target::read_description ()
+{
+#ifdef notyet
+/*
+ * XXX clang on OpenBSD/arm enables NEON by default
+ * Should we try to use that code path?
+ */
+  if (neon)
+    return aarch32_read_description ();
+#endif
+
+  return arm_read_description (ARM_FP_TYPE_VFPV3, false);
+}
+
+void _initialize_arm_openbsd_nat ();
+void
+_initialize_arm_openbsd_nat ()
+{
+  add_inf_child_target (&the_arm_openbsd_nat_target);
+}
