public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] gdbserver: Add GNU/Linux support for ARC
@ 2020-08-26 16:56 Shahab Vahedi
  2020-09-07  9:12 ` Shahab Vahedi
                   ` (5 more replies)
  0 siblings, 6 replies; 17+ messages in thread
From: Shahab Vahedi @ 2020-08-26 16:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Shahab Vahedi, Shahab Vahedi, Francois Bedard, Anton Kolesov

From: Anton Kolesov <Anton.Kolesov@synopsys.com>

This gdbserver implementation supports ARC ABI v3 and v4 (older ARC ABI
versions are not supported by other modern GNU tools or Linux itself).
Gdbserver supports inspection of ARC HS registers R30, R58 and R59 - feature
that has been added to Linux 4.12.  Whether gdbserver build will actually
support this feature depends on the version of Linux headers used to build
the server.

gdbserver/ChangeLog:

2020-08-26  Anton Kolesov  <anton.kolesov@synopsys.com>

	* configure.srv: Support ARC architecture.
	* Makefile.in: Add linux-arc-low.cc and arch-arc.o.
	* linux-arc-low.cc: New file.
---
 gdbserver/Makefile.in      |   6 +
 gdbserver/configure.srv    |  11 +
 gdbserver/linux-arc-low.cc | 398 +++++++++++++++++++++++++++++++++++++
 3 files changed, 415 insertions(+)
 create mode 100644 gdbserver/linux-arc-low.cc

diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
index 9d7687be534..df1b4d16da0 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -179,6 +179,7 @@ SFILES = \
 	$(srcdir)/i387-fp.cc \
 	$(srcdir)/inferiors.cc \
 	$(srcdir)/linux-aarch64-low.cc \
+	$(srcdir)/linux-arc-low.cc \
 	$(srcdir)/linux-arm-low.cc \
 	$(srcdir)/linux-ia64-low.cc \
 	$(srcdir)/linux-low.cc \
@@ -206,6 +207,7 @@ SFILES = \
 	$(srcdir)/win32-low.cc \
 	$(srcdir)/x86-low.cc \
 	$(srcdir)/../gdb/alloc.c \
+	$(srcdir)/../gdb/arch/arc.c \
 	$(srcdir)/../gdb/arch/arm.c \
 	$(srcdir)/../gdb/arch/arm-get-next-pcs.c \
 	$(srcdir)/../gdb/arch/arm-linux.c \
@@ -490,6 +492,10 @@ ax.o: ax.cc
 	$(COMPILE) $(WARN_CFLAGS_NO_FORMAT) $<
 	$(POSTCOMPILE)
 
+arch-arc.o: ../gdb/arch/arc.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
 # Rules for objects that go in the in-process agent.
 
 arch/%-ipa.o: ../gdb/arch/%.c
diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
index 5e33bd9c54d..d764753baaa 100644
--- a/gdbserver/configure.srv
+++ b/gdbserver/configure.srv
@@ -61,6 +61,17 @@ case "${gdbserver_host}" in
 			ipa_obj="${ipa_obj} linux-aarch64-tdesc-ipa.o"
 			ipa_obj="${ipa_obj} arch/aarch64-ipa.o"
 			;;
+  arc*-*-linux*)
+			srv_regobj=""
+			srv_tgtobj="linux-arc-low.o arch-arc.o $srv_linux_obj"
+			srv_xmlfiles="arc/v1-core.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v1-aux.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v2-core.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v2-aux.xml"
+			srv_linux_regsets=yes
+			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
+			;;
   arm*-*-linux*)	srv_tgtobj="$srv_linux_obj linux-arm-low.o"
 			srv_tgtobj="$srv_tgtobj linux-arm-tdesc.o"
 			srv_tgtobj="$srv_tgtobj linux-aarch32-low.o"
diff --git a/gdbserver/linux-arc-low.cc b/gdbserver/linux-arc-low.cc
new file mode 100644
index 00000000000..d28b3452321
--- /dev/null
+++ b/gdbserver/linux-arc-low.cc
@@ -0,0 +1,398 @@
+/* Target dependent code for the remote server for GNU/Linux ARC.
+
+   Copyright 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 "server.h"
+#include "regdef.h"
+#include "linux-low.h"
+#include "tdesc.h"
+#include "arch/arc.h"
+
+#include <linux/elf.h>
+#include <arpa/inet.h>
+
+/* Linux starting with 4.12 supports NT_ARC_V2 note type, which adds R30,
+   R58 and R59 registers.  */
+#ifdef NT_ARC_V2
+#define ARC_HAS_V2_REGSET
+#endif
+
+#define TRAP_S_1_OPCODE	0x3e78
+#define TRAP_S_1_SIZE	2
+
+/* Linux target op definitions for the ARC architecture.
+   Note for future: in case of adding the protected method low_get_next_pcs(),
+   the public method supports_software_single_step() should be added to return
+   "true".  */
+
+class arc_target : public linux_process_target
+{
+public:
+
+  const regs_info *get_regs_info () override;
+
+  const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
+
+protected:
+
+  void low_arch_setup () override;
+
+  bool low_cannot_fetch_register (int regno) override;
+
+  bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
+
+  bool low_breakpoint_at (CORE_ADDR where) override;
+};
+
+/* The singleton target ops object.  */
+
+static arc_target the_arc_target;
+
+bool
+arc_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+arc_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+arc_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
+static const struct target_desc *
+arc_linux_read_description (void)
+{
+#ifdef __ARC700__
+  arc_gdbarch_features features (4, ARC_ISA_ARCV1);
+#else
+  arc_gdbarch_features features (4, ARC_ISA_ARCV2);
+#endif
+  struct target_desc *tdesc = arc_create_target_description (features);
+
+  static const char *expedite_regs[] = { "sp", "status32", nullptr };
+  init_target_desc (tdesc, expedite_regs);
+
+  return tdesc;
+}
+
+void
+arc_target::low_arch_setup ()
+{
+  current_process ()->tdesc = arc_linux_read_description ();
+}
+
+bool
+arc_target::low_cannot_fetch_register (int regno)
+{
+  return (regno >= current_process ()->tdesc->reg_defs.size());
+}
+
+bool
+arc_target::low_cannot_store_register (int regno)
+{
+  return (regno >= current_process ()->tdesc->reg_defs.size());
+}
+
+/* The breakpoint instruction is TRAP_S 1, network function ntohs can be
+   used to convert its little-endian form (0x3e78) to the host
+   representation, which may be little-endian or big-endian (network
+   representation is defined to be little-endian).  */
+
+bool
+arc_target::low_breakpoint_at (CORE_ADDR where)
+{
+  uint16_t insn;
+  uint16_t breakpoint = ntohs (TRAP_S_1_OPCODE);
+
+  the_target->read_memory (where, (gdb_byte *) &insn, TRAP_S_1_SIZE);
+  return (insn == breakpoint);
+}
+
+/* PTRACE_GETREGSET/NT_PRSTATUS and PTRACE_SETREGSET/NT_PRSTATUS work with
+   regsets in a struct, "user_regs_struct", defined in the
+   linux/arch/arc/include/uapi/asm/ptrace.h header.  This code supports
+   ARC Linux ABI v3 and v4.  */
+
+/* Populate a ptrace NT_PRSTATUS regset from a regcache.
+
+   This appears to be a unique approach to populating the buffer, but
+   being name, rather than offset based, it is robust to future API
+   changes, as there is no need to create a regmap of registers in the
+   user_regs_struct.  */
+
+static void
+arc_fill_gregset (struct regcache *regcache, void *buf)
+{
+  struct user_regs_struct *regbuf = (struct user_regs_struct *) buf;
+
+  /* Core registers.  */
+  collect_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
+  collect_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
+  collect_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
+  collect_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
+  collect_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
+  collect_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
+  collect_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
+  collect_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
+  collect_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
+  collect_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
+  collect_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
+  collect_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
+  collect_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
+  collect_register_by_name (regcache, "r13", &(regbuf->callee.r13));
+  collect_register_by_name (regcache, "r14", &(regbuf->callee.r14));
+  collect_register_by_name (regcache, "r15", &(regbuf->callee.r15));
+  collect_register_by_name (regcache, "r16", &(regbuf->callee.r16));
+  collect_register_by_name (regcache, "r17", &(regbuf->callee.r17));
+  collect_register_by_name (regcache, "r18", &(regbuf->callee.r18));
+  collect_register_by_name (regcache, "r19", &(regbuf->callee.r19));
+  collect_register_by_name (regcache, "r20", &(regbuf->callee.r20));
+  collect_register_by_name (regcache, "r21", &(regbuf->callee.r21));
+  collect_register_by_name (regcache, "r22", &(regbuf->callee.r22));
+  collect_register_by_name (regcache, "r23", &(regbuf->callee.r23));
+  collect_register_by_name (regcache, "r24", &(regbuf->callee.r24));
+  collect_register_by_name (regcache, "r25", &(regbuf->callee.r25));
+  collect_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
+  collect_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
+  collect_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
+  collect_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
+
+  /* Loop registers.  */
+  collect_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
+  collect_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
+  collect_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
+
+  /* PC should be written to "return address", instead of stop address.  */
+  collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));
+
+  /* Currently ARC Linux ptrace doesn't allow writes to status32 because
+     some of it's bits are kernel mode-only and shoudn't be writable from
+     user-space.  Writing status32 from debugger could be useful, though,
+     so ability to write non-priviliged bits will be added to kernel
+     sooner or later.  */
+
+  /* BTA.  */
+  collect_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
+}
+
+/* Populate a regcache from a ptrace NT_PRSTATUS regset.  */
+
+static void
+arc_store_gregset (struct regcache *regcache, const void *buf)
+{
+  const struct user_regs_struct *regbuf = (const struct user_regs_struct *) buf;
+
+  /* Core registers.  */
+  supply_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
+  supply_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
+  supply_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
+  supply_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
+  supply_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
+  supply_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
+  supply_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
+  supply_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
+  supply_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
+  supply_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
+  supply_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
+  supply_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
+  supply_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
+  supply_register_by_name (regcache, "r13", &(regbuf->callee.r13));
+  supply_register_by_name (regcache, "r14", &(regbuf->callee.r14));
+  supply_register_by_name (regcache, "r15", &(regbuf->callee.r15));
+  supply_register_by_name (regcache, "r16", &(regbuf->callee.r16));
+  supply_register_by_name (regcache, "r17", &(regbuf->callee.r17));
+  supply_register_by_name (regcache, "r18", &(regbuf->callee.r18));
+  supply_register_by_name (regcache, "r19", &(regbuf->callee.r19));
+  supply_register_by_name (regcache, "r20", &(regbuf->callee.r20));
+  supply_register_by_name (regcache, "r21", &(regbuf->callee.r21));
+  supply_register_by_name (regcache, "r22", &(regbuf->callee.r22));
+  supply_register_by_name (regcache, "r23", &(regbuf->callee.r23));
+  supply_register_by_name (regcache, "r24", &(regbuf->callee.r24));
+  supply_register_by_name (regcache, "r25", &(regbuf->callee.r25));
+  supply_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
+  supply_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
+  supply_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
+  supply_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
+
+  /* Loop registers.  */
+  supply_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
+  supply_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
+  supply_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
+
+  /* PC value is read from stop address.  */
+  supply_register_by_name (regcache, "pc", &(regbuf->stop_pc));
+  unsigned long pcl = regbuf->stop_pc & ~3L;
+  supply_register_by_name (regcache, "pcl", &pcl);
+
+  /* Other auxilliary registers.  */
+  supply_register_by_name (regcache, "status32", &(regbuf->scratch.status32));
+
+  /* BTA.  */
+  supply_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
+}
+
+#ifdef ARC_HAS_V2_REGSET
+
+/* Look through a regcache's TDESC for a register named NAME.
+   If found, return true. False otherwise.  */
+
+static bool
+is_reg_name_available_p (const struct target_desc *tdesc,
+			 const char *name)
+{
+  for (int i = 0; i < tdesc->reg_defs.size (); ++i)
+    if (strcmp (name, tdesc->reg_defs[i].name) == 0)
+      return true;
+  return false;
+}
+
+/* Copy registers from regcache to user_regs_arcv2.  */
+
+static void
+arc_fill_v2_regset (struct regcache *regcache, void *buf)
+{
+  struct user_regs_arcv2 *regbuf = (struct user_regs_arcv2 *) buf;
+
+  if (is_reg_name_available_p (regcache->tdesc, "r30"))
+    collect_register_by_name (regcache, "r30", &(regbuf->r30));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r58"))
+    collect_register_by_name (regcache, "r58", &(regbuf->r58));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r59"))
+    collect_register_by_name (regcache, "r59", &(regbuf->r59));
+}
+
+/* Copy registers from user_regs_arcv2 to regcache.  */
+
+static void
+arc_store_v2_regset (struct regcache *regcache, const void *buf)
+{
+  struct user_regs_arcv2 *regbuf = (struct user_regs_arcv2 *) buf;
+
+  if (is_reg_name_available_p (regcache->tdesc, "r30"))
+    supply_register_by_name (regcache, "r30", &(regbuf->r30));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r58"))
+    supply_register_by_name (regcache, "r58", &(regbuf->r58));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r59"))
+    supply_register_by_name (regcache, "r59", &(regbuf->r59));
+}
+
+#endif
+
+/* Fetch the thread-local storage pointer for libthread_db.  Note that
+   this function is not called from GDB, but is called from libthread_db.
+
+   This is the same function as for other architectures, for example in
+   linux-arm-low.c.  */
+
+ps_err_e
+ps_get_thread_area (struct ps_prochandle *ph, lwpid_t lwpid,
+		    int idx, void **base)
+{
+  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, nullptr, base) != 0)
+    return PS_ERR;
+
+  /* IDX is the bias from the thread pointer to the beginning of the
+     thread descriptor.  It has to be subtracted due to implementation
+     quirks in libthread_db.  */
+  *base = (void *) ((char *) *base - idx);
+
+  return PS_OK;
+}
+
+static struct regset_info arc_regsets[] =
+{
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
+    sizeof (struct user_regs_struct), GENERAL_REGS,
+    arc_fill_gregset, arc_store_gregset
+  },
+#ifdef ARC_HAS_V2_REGSET
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARC_V2,
+    sizeof (struct user_regs_arcv2), GENERAL_REGS,
+    arc_fill_v2_regset, arc_store_v2_regset
+  },
+#endif
+  NULL_REGSET
+};
+
+static struct regsets_info arc_regsets_info =
+{
+  arc_regsets,	/* regsets */
+  0,		/* num_regsets */
+  nullptr,	/* disabled regsets */
+};
+
+static struct regs_info arc_regs_info =
+{
+  nullptr,	/* regset_bitmap */
+  nullptr,	/* usrregs */
+  &arc_regsets_info
+};
+
+const regs_info *
+arc_target::get_regs_info ()
+{
+  return &arc_regs_info;
+}
+
+/* One of the methods necessary for Z0 packet support.
+   See issue #35 for further details.  */
+
+const gdb_byte *
+arc_target::sw_breakpoint_from_kind (int kind, int *size)
+{
+  static bool initialized = false;
+  static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE] = { 0, };
+
+  if (!initialized)
+    {
+      uint16_t breakpoint = ntohs (TRAP_S_1_OPCODE);
+      *((uint16_t *) arc_linux_trap_s) = breakpoint;
+      initialized = true;
+    }
+
+  gdb_assert (kind == TRAP_S_1_SIZE);
+  *size = kind;
+  return arc_linux_trap_s;
+}
+
+/* The linux target ops object.  */
+
+linux_process_target *the_linux_target = &the_arc_target;
+
+void
+initialize_low_arch (void)
+{
+  initialize_regsets_info (&arc_regsets_info);
+}
-- 
2.28.0


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

* Re: [PATCH] gdbserver: Add GNU/Linux support for ARC
  2020-08-26 16:56 [PATCH] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
@ 2020-09-07  9:12 ` Shahab Vahedi
  2020-09-16  2:29 ` [PING^2][PATCH] " Shahab Vahedi
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Shahab Vahedi @ 2020-09-07  9:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Shahab Vahedi, Francois Bedard, Anton Kolesov

A gentle reminder for reviewing this patch [1].

Thank you in advance,
Shahab

[1] gdbserver: Add GNU/Linux support for ARC
https://sourceware.org/pipermail/gdb-patches/2020-August/171499.html

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

* [PING^2][PATCH] gdbserver: Add GNU/Linux support for ARC
  2020-08-26 16:56 [PATCH] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
  2020-09-07  9:12 ` Shahab Vahedi
@ 2020-09-16  2:29 ` Shahab Vahedi
  2020-09-16 19:59 ` [PATCH] " Simon Marchi
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Shahab Vahedi @ 2020-09-16  2:29 UTC (permalink / raw)
  To: gdb-patches; +Cc: Shahab Vahedi, Francois Bedard, Anton Kolesov

A gentle reminder for gdbserver: Add GNU/Linux support for ARC [1].

[1]
https://sourceware.org/pipermail/gdb-patches/2020-August/171499.html

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

* Re: [PATCH] gdbserver: Add GNU/Linux support for ARC
  2020-08-26 16:56 [PATCH] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
  2020-09-07  9:12 ` Shahab Vahedi
  2020-09-16  2:29 ` [PING^2][PATCH] " Shahab Vahedi
@ 2020-09-16 19:59 ` Simon Marchi
  2020-10-06 16:21   ` Shahab Vahedi
  2020-10-06 16:42 ` [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 17+ messages in thread
From: Simon Marchi @ 2020-09-16 19:59 UTC (permalink / raw)
  To: Shahab Vahedi, gdb-patches; +Cc: Shahab Vahedi, Anton Kolesov, Francois Bedard


Hi Shahab,

I've noted a few comments below.  Otherwise, it looks good to me.  I
don't know all the gdbserver quirks by heart, but I've looked at other
implementations (which is probably what you did too :)) and it all
seemed reasonable.  I also don't know the specific details of the
various ARC variants, so I trust you for that.

Once the nits are fixed, you can merge this to master and the
gdb-10-branch.

On 2020-08-26 12:56 p.m., Shahab Vahedi via Gdb-patches wrote:
> From: Anton Kolesov <Anton.Kolesov@synopsys.com>
>
> This gdbserver implementation supports ARC ABI v3 and v4 (older ARC ABI
> versions are not supported by other modern GNU tools or Linux itself).
> Gdbserver supports inspection of ARC HS registers R30, R58 and R59 - feature
> that has been added to Linux 4.12.  Whether gdbserver build will actually
> support this feature depends on the version of Linux headers used to build
> the server.
>
> gdbserver/ChangeLog:
>
> 2020-08-26  Anton Kolesov  <anton.kolesov@synopsys.com>
>
> 	* configure.srv: Support ARC architecture.
> 	* Makefile.in: Add linux-arc-low.cc and arch-arc.o.
> 	* linux-arc-low.cc: New file.
> ---
>  gdbserver/Makefile.in      |   6 +
>  gdbserver/configure.srv    |  11 +
>  gdbserver/linux-arc-low.cc | 398 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 415 insertions(+)
>  create mode 100644 gdbserver/linux-arc-low.cc
>
> diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
> index 9d7687be534..df1b4d16da0 100644
> --- a/gdbserver/Makefile.in
> +++ b/gdbserver/Makefile.in
> @@ -179,6 +179,7 @@ SFILES = \
>  	$(srcdir)/i387-fp.cc \
>  	$(srcdir)/inferiors.cc \
>  	$(srcdir)/linux-aarch64-low.cc \
> +	$(srcdir)/linux-arc-low.cc \
>  	$(srcdir)/linux-arm-low.cc \
>  	$(srcdir)/linux-ia64-low.cc \
>  	$(srcdir)/linux-low.cc \
> @@ -206,6 +207,7 @@ SFILES = \
>  	$(srcdir)/win32-low.cc \
>  	$(srcdir)/x86-low.cc \
>  	$(srcdir)/../gdb/alloc.c \
> +	$(srcdir)/../gdb/arch/arc.c \
>  	$(srcdir)/../gdb/arch/arm.c \
>  	$(srcdir)/../gdb/arch/arm-get-next-pcs.c \
>  	$(srcdir)/../gdb/arch/arm-linux.c \
> @@ -490,6 +492,10 @@ ax.o: ax.cc
>  	$(COMPILE) $(WARN_CFLAGS_NO_FORMAT) $<
>  	$(POSTCOMPILE)
>
> +arch-arc.o: ../gdb/arch/arc.c
> +	$(COMPILE) $<
> +	$(POSTCOMPILE)
> +

I think that's not needed.  This file can use the

  arch/%.o: ../gdb/arch/%.c

pattern rule and get compiled to arch/arc.o.

> +static const struct target_desc *
> +arc_linux_read_description (void)
> +{
> +#ifdef __ARC700__
> +  arc_gdbarch_features features (4, ARC_ISA_ARCV1);
> +#else
> +  arc_gdbarch_features features (4, ARC_ISA_ARCV2);
> +#endif

I should have mentionned this in an earlier review, but
"arc_gdbarch_features" is a bit mis-named.  "gdbarch" specifically
refers to the type/interface in GDB, but arc_gdbarch_features is not
related to that.  "arc_arch_features" would be a bit better, if you want
to change it in an obvious patch.

> +  struct target_desc *tdesc = arc_create_target_description (features);
> +
> +  static const char *expedite_regs[] = { "sp", "status32", nullptr };
> +  init_target_desc (tdesc, expedite_regs);
> +
> +  return tdesc;
> +}
> +
> +void
> +arc_target::low_arch_setup ()
> +{
> +  current_process ()->tdesc = arc_linux_read_description ();
> +}
> +
> +bool
> +arc_target::low_cannot_fetch_register (int regno)
> +{
> +  return (regno >= current_process ()->tdesc->reg_defs.size());

Space before parenthesis.

> +}
> +
> +bool
> +arc_target::low_cannot_store_register (int regno)
> +{
> +  return (regno >= current_process ()->tdesc->reg_defs.size());

Space before parenthesis.

> +}
> +
> +/* The breakpoint instruction is TRAP_S 1, network function ntohs can be
> +   used to convert its little-endian form (0x3e78) to the host
> +   representation, which may be little-endian or big-endian (network
> +   representation is defined to be little-endian).  */

Isn't network byte order big endian?
> +static void
> +arc_fill_gregset (struct regcache *regcache, void *buf)
> +{
> +  struct user_regs_struct *regbuf = (struct user_regs_struct *) buf;
> +
> +  /* Core registers.  */
> +  collect_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
> +  collect_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
> +  collect_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
> +  collect_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
> +  collect_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
> +  collect_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
> +  collect_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
> +  collect_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
> +  collect_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
> +  collect_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
> +  collect_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
> +  collect_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
> +  collect_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
> +  collect_register_by_name (regcache, "r13", &(regbuf->callee.r13));
> +  collect_register_by_name (regcache, "r14", &(regbuf->callee.r14));
> +  collect_register_by_name (regcache, "r15", &(regbuf->callee.r15));
> +  collect_register_by_name (regcache, "r16", &(regbuf->callee.r16));
> +  collect_register_by_name (regcache, "r17", &(regbuf->callee.r17));
> +  collect_register_by_name (regcache, "r18", &(regbuf->callee.r18));
> +  collect_register_by_name (regcache, "r19", &(regbuf->callee.r19));
> +  collect_register_by_name (regcache, "r20", &(regbuf->callee.r20));
> +  collect_register_by_name (regcache, "r21", &(regbuf->callee.r21));
> +  collect_register_by_name (regcache, "r22", &(regbuf->callee.r22));
> +  collect_register_by_name (regcache, "r23", &(regbuf->callee.r23));
> +  collect_register_by_name (regcache, "r24", &(regbuf->callee.r24));
> +  collect_register_by_name (regcache, "r25", &(regbuf->callee.r25));
> +  collect_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
> +  collect_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
> +  collect_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
> +  collect_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
> +
> +  /* Loop registers.  */
> +  collect_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
> +  collect_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
> +  collect_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
> +
> +  /* PC should be written to "return address", instead of stop address.  */
> +  collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));

Can you explain why the PC is written to "ret", whereas when going the
other way we take the value from the "stop_pc" field?

> +
> +  /* Currently ARC Linux ptrace doesn't allow writes to status32 because
> +     some of it's bits are kernel mode-only and shoudn't be writable from

"its bits"

> +/* Look through a regcache's TDESC for a register named NAME.
> +   If found, return true. False otherwise.  */
> +
> +static bool
> +is_reg_name_available_p (const struct target_desc *tdesc,
> +			 const char *name)
> +{
> +  for (int i = 0; i < tdesc->reg_defs.size (); ++i)
> +    if (strcmp (name, tdesc->reg_defs[i].name) == 0)

It looks like this could be a range based iteration:

  for (const gdb::reg &reg : tdesc->reg_defs)

> +const regs_info *
> +arc_target::get_regs_info ()
> +{
> +  return &arc_regs_info;
> +}
> +
> +/* One of the methods necessary for Z0 packet support.
> +   See issue #35 for further details.  */

"issue #35" isn't relevant in upstream code.

> +
> +const gdb_byte *
> +arc_target::sw_breakpoint_from_kind (int kind, int *size)
> +{
> +  static bool initialized = false;
> +  static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE] = { 0, };
> +
> +  if (!initialized)
> +    {
> +      uint16_t breakpoint = ntohs (TRAP_S_1_OPCODE);
> +      *((uint16_t *) arc_linux_trap_s) = breakpoint;
> +      initialized = true;
> +    }
> +
> +  gdb_assert (kind == TRAP_S_1_SIZE);

I always find it a little odd that we choose the breakpoint size as the
kind, instead of just an arbitrary number (first one 0, second one 1,
etc).   What if we want to use another breakpoint instruction that is
two bytes long?  Anyway, not really a problem, just something I wonder
about.

Simon

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

* Re: [PATCH] gdbserver: Add GNU/Linux support for ARC
  2020-09-16 19:59 ` [PATCH] " Simon Marchi
@ 2020-10-06 16:21   ` Shahab Vahedi
  0 siblings, 0 replies; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-06 16:21 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches, Shahab Vahedi, Anton Kolesov, Francois Bedard

Hi Simon,

On Wed, Sep 16, 2020 at 03:59:42PM -0400, Simon Marchi wrote:
> On 2020-08-26 12:56 p.m., Shahab Vahedi via Gdb-patches wrote:
> > +static const struct target_desc *
> > +arc_linux_read_description (void)
> > +{
> > +#ifdef __ARC700__
> > +  arc_gdbarch_features features (4, ARC_ISA_ARCV1);
> > +#else
> > +  arc_gdbarch_features features (4, ARC_ISA_ARCV2);
> > +#endif
> 
> I should have mentionned this in an earlier review, but
> "arc_gdbarch_features" is a bit mis-named.  "gdbarch" specifically
> refers to the type/interface in GDB, but arc_gdbarch_features is not
> related to that.  "arc_arch_features" would be a bit better, if you want
> to change it in an obvious patch.

I renamed it in the next version.  Therefore, v2 is a patch series and
not a single patch anymore.

> > +/* The breakpoint instruction is TRAP_S 1, network function ntohs can be
> > +   used to convert its little-endian form (0x3e78) to the host
> > +   representation, which may be little-endian or big-endian (network
> > +   representation is defined to be little-endian).  */
> 
> Isn't network byte order big endian?

Got rid of it.

> > +static void
> > +arc_fill_gregset (struct regcache *regcache, void *buf)
> > +{
> > +  struct user_regs_struct *regbuf = (struct user_regs_struct *) buf;
> > +
> > +  /* Core registers.  */
> > +  collect_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
> >    ...
> > +  /* PC should be written to "return address", instead of stop address.  */
> > +  collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));
> 
> Can you explain why the PC is written to "ret", whereas when going the
> other way we take the value from the "stop_pc" field?

I've added the following comments in the code in v2.  I hope it is
helpful.

  /* The current "pc" value must be written to "eret" (exception return
     address) register, because that is the address that the kernel code
     will jump back to after a breakpoint exception has been raised.
     The "pc_stop" value is ignored by the genregs_set() in
     linux/arch/arc/kernel/ptrace.c.  */
  collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));

  /* The genregs_get() in linux/arch/arc/kernel/ptrace.c populates the
     pseudo register "stop_pc" with the "efa" (exception fault address)
     register.  This was deemed necessary, because the breakpoint
     instruction, "trap_s 1", is a committing one; i.e. the "eret"
     (excpetion return address) register will be pointing to the next
     instruction, while "efa" points to the address that raised the
     breakpoint.  */
  supply_register_by_name (regcache, "pc", &(regbuf->stop_pc));

> > +
> > +const gdb_byte *
> > +arc_target::sw_breakpoint_from_kind (int kind, int *size)
> > +{
> > +  static bool initialized = false;
> > +  static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE] = { 0, };
> > +
> > +  if (!initialized)
> > +    {
> > +      uint16_t breakpoint = ntohs (TRAP_S_1_OPCODE);
> > +      *((uint16_t *) arc_linux_trap_s) = breakpoint;
> > +      initialized = true;
> > +    }
> > +
> > +  gdb_assert (kind == TRAP_S_1_SIZE);
> 
> I always find it a little odd that we choose the breakpoint size as the
> kind, instead of just an arbitrary number (first one 0, second one 1,
> etc).   What if we want to use another breakpoint instruction that is
> two bytes long?  Anyway, not really a problem, just something I wonder
> about.

I agree.  I rather use an enum that acts like a key in a map that returns
the size.  I see this pattern in "gdb" code as well.  I plan to tackle
this in a separate patch.  So I can focus on sharing the code base as
much as possible.


Cheers,
Shahab

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

* [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct
  2020-08-26 16:56 [PATCH] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
                   ` (2 preceding siblings ...)
  2020-09-16 19:59 ` [PATCH] " Simon Marchi
@ 2020-10-06 16:42 ` Shahab Vahedi
  2020-10-06 16:42   ` [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
  2020-10-07  1:27   ` [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct Simon Marchi
  2020-10-07 15:58 ` [PUSHED master] " Shahab Vahedi
  2020-10-07 16:03 ` [PUSHED gdb-10-branch] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
  5 siblings, 2 replies; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-06 16:42 UTC (permalink / raw)
  To: gdb-patches
  Cc: Shahab Vahedi, Shahab Vahedi, Simon Marchi, Baris Aktemur,
	Francois Bedard

From: Shahab Vahedi <shahab@synopsys.com>

"arc_gdbarch_features" is a data structure containing information
about the ARC architecture: ISA version, register size, etc.
This name is misleading, because although it carries the phrase
"gdbarch", it has nothing to do with the type/interface in GDB.
Traditionaly, "gdbarch" structures are only used for that purpose.
To rectify this, this patch changes the name to "arc_arch_features".

gdb/ChangeLog:

	* arch/arc.h: Rename "arc_gdbarch_features" to
	"arc_arch_features".
	* arc-tdep.h: Likewise.
	* arc-tdep.c: Likewise.
---
 gdb/arc-tdep.c | 14 +++++++-------
 gdb/arch/arc.c | 12 ++++++------
 gdb/arch/arc.h | 12 ++++++------
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 6f544bff78d..60c76af3352 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1883,11 +1883,11 @@ mach_type_to_arc_isa (const unsigned long mach)
     }
 }
 
-/* Common construction code for ARC_GDBARCH_FEATURES struct.  If there
+/* Common construction code for ARC_ARCH_FEATURES struct.  If there
    is no ABFD, then a FEATURE with default values is returned.  */
 
-static arc_gdbarch_features
-arc_gdbarch_features_create (const bfd *abfd, const unsigned long mach)
+static arc_arch_features
+arc_arch_features_create (const bfd *abfd, const unsigned long mach)
 {
   /* Use 4 as a fallback value.  */
   int reg_size = 4;
@@ -1915,7 +1915,7 @@ arc_gdbarch_features_create (const bfd *abfd, const unsigned long mach)
      case).  */
   arc_isa isa = mach_type_to_arc_isa (mach);
 
-  return arc_gdbarch_features (reg_size, isa);
+  return arc_arch_features (reg_size, isa);
 }
 
 /* Look for obsolete core feature names in TDESC.  */
@@ -2085,9 +2085,9 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
   /* If target doesn't provide a description, use the default ones.  */
   if (!tdesc_has_registers (tdesc_loc))
     {
-      arc_gdbarch_features features
-	= arc_gdbarch_features_create (info.abfd,
-				       info.bfd_arch_info->mach);
+      arc_arch_features features
+	= arc_arch_features_create (info.abfd,
+				    info.bfd_arch_info->mach);
       tdesc_loc = arc_lookup_target_description (features);
     }
   gdb_assert (tdesc_loc != nullptr);
diff --git a/gdb/arch/arc.c b/gdb/arch/arc.c
index 8e126ca5a82..3808f9fe292 100644
--- a/gdb/arch/arc.c
+++ b/gdb/arch/arc.c
@@ -35,7 +35,7 @@
 #endif
 
 STATIC_IN_GDB target_desc *
-arc_create_target_description (const struct arc_gdbarch_features &features)
+arc_create_target_description (const struct arc_arch_features &features)
 {
   /* Create a new target description.  */
   target_desc *tdesc = allocate_target_description ();
@@ -84,10 +84,10 @@ arc_create_target_description (const struct arc_gdbarch_features &features)
 #ifndef GDBSERVER
 
 /* Wrapper used by std::unordered_map to generate hash for features set.  */
-struct arc_gdbarch_features_hasher
+struct arc_arch_features_hasher
 {
   std::size_t
-  operator() (const arc_gdbarch_features &features) const noexcept
+  operator() (const arc_arch_features &features) const noexcept
   {
     return features.hash ();
   }
@@ -95,14 +95,14 @@ struct arc_gdbarch_features_hasher
 
 /* Cache of previously created target descriptions, indexed by the hash
    of the features set used to create them.  */
-static std::unordered_map<arc_gdbarch_features,
+static std::unordered_map<arc_arch_features,
 			  const target_desc_up,
-			  arc_gdbarch_features_hasher> arc_tdesc_cache;
+			  arc_arch_features_hasher> arc_tdesc_cache;
 
 /* See arch/arc.h.  */
 
 const target_desc *
-arc_lookup_target_description (const struct arc_gdbarch_features &features)
+arc_lookup_target_description (const struct arc_arch_features &features)
 {
   /* Lookup in the cache first.  If found, return the pointer from the
      "target_desc_up" type which is a "unique_ptr".  This should be fine
diff --git a/gdb/arch/arc.h b/gdb/arch/arc.h
index a5313b1fee6..16257596748 100644
--- a/gdb/arch/arc.h
+++ b/gdb/arch/arc.h
@@ -27,9 +27,9 @@ enum arc_isa
   ARC_ISA_ARCV2	      /* such as ARC EM and ARC HS  */
 };
 
-struct arc_gdbarch_features
+struct arc_arch_features
 {
-  arc_gdbarch_features (int reg_size, arc_isa isa)
+  arc_arch_features (int reg_size, arc_isa isa)
     : reg_size (reg_size), isa (isa)
   {}
 
@@ -41,13 +41,13 @@ struct arc_gdbarch_features
   const arc_isa isa;
 
   /* Equality operator.  */
-  bool operator== (const struct arc_gdbarch_features &rhs) const
+  bool operator== (const struct arc_arch_features &rhs) const
   {
     return (reg_size == rhs.reg_size && isa == rhs.isa);
   }
 
   /* Inequality operator.  */
-  bool operator!= (const struct arc_gdbarch_features &rhs) const
+  bool operator!= (const struct arc_arch_features &rhs) const
   {
     return !(*this == rhs);
   }
@@ -71,7 +71,7 @@ struct arc_gdbarch_features
    the returned data.  */
 
 target_desc *arc_create_target_description
-	(const struct arc_gdbarch_features &features);
+	(const struct arc_arch_features &features);
 
 #else
 
@@ -79,7 +79,7 @@ target_desc *arc_create_target_description
    If nothing is found, then create one and return it.  */
 
 const target_desc *arc_lookup_target_description
-	(const struct arc_gdbarch_features &features);
+	(const struct arc_arch_features &features);
 
 #endif /* GDBSERVER */
 
-- 
2.28.0


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

* [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC
  2020-10-06 16:42 ` [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
@ 2020-10-06 16:42   ` Shahab Vahedi
  2020-10-07  2:28     ` Simon Marchi
  2020-10-07  1:27   ` [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct Simon Marchi
  1 sibling, 1 reply; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-06 16:42 UTC (permalink / raw)
  To: gdb-patches
  Cc: Shahab Vahedi, Shahab Vahedi, Simon Marchi, Baris Aktemur,
	Francois Bedard, Anton Kolesov

From: Anton Kolesov <Anton.Kolesov@synopsys.com>

This gdbserver implementation supports ARC ABI v3 and v4 (older ARC ABI
versions are not supported by other modern GNU tools or Linux itself).
Gdbserver supports inspection of ARC HS registers R30, R58 and R59 - feature
that has been added to Linux 4.12.  Whether gdbserver build will actually
support this feature depends on the version of Linux headers used to build
the server.

v2 [1]:
- Use "this->read_memory ()" instead of "the_target->read_memory ()".
- Remove the unnecessary "arch-arc.o:" target from the "Makefile.in".
- Got rid of "ntohs()" function and added lots of comments about
  endianness.
- Clarify why "pc" value is read from and saved to different fields
  in user regs struct.
- In function "is_reg_name_available_p()", use a range-based iterator
  to loop over the registers.
- Removed mentioning of issue number that was not related to sourceware.
- A few typo's fixed.

[1] Remarks
https://sourceware.org/pipermail/gdb-patches/2020-September/171911.html
https://sourceware.org/pipermail/gdb-patches/2020-September/171919.html

gdbserver/ChangeLog:

	* configure.srv: Support ARC architecture.
	* Makefile.in: Add linux-arc-low.cc and arch/arc.o.
	* linux-arc-low.cc: New file.
---
 gdbserver/Makefile.in      |   2 +
 gdbserver/configure.srv    |  11 +
 gdbserver/linux-arc-low.cc | 420 +++++++++++++++++++++++++++++++++++++
 3 files changed, 433 insertions(+)
 create mode 100644 gdbserver/linux-arc-low.cc

diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
index 9d7687be534..09a652a3354 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -179,6 +179,7 @@ SFILES = \
 	$(srcdir)/i387-fp.cc \
 	$(srcdir)/inferiors.cc \
 	$(srcdir)/linux-aarch64-low.cc \
+	$(srcdir)/linux-arc-low.cc \
 	$(srcdir)/linux-arm-low.cc \
 	$(srcdir)/linux-ia64-low.cc \
 	$(srcdir)/linux-low.cc \
@@ -206,6 +207,7 @@ SFILES = \
 	$(srcdir)/win32-low.cc \
 	$(srcdir)/x86-low.cc \
 	$(srcdir)/../gdb/alloc.c \
+	$(srcdir)/../gdb/arch/arc.c \
 	$(srcdir)/../gdb/arch/arm.c \
 	$(srcdir)/../gdb/arch/arm-get-next-pcs.c \
 	$(srcdir)/../gdb/arch/arm-linux.c \
diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
index 5e33bd9c54d..029ddabc4b8 100644
--- a/gdbserver/configure.srv
+++ b/gdbserver/configure.srv
@@ -61,6 +61,17 @@ case "${gdbserver_host}" in
 			ipa_obj="${ipa_obj} linux-aarch64-tdesc-ipa.o"
 			ipa_obj="${ipa_obj} arch/aarch64-ipa.o"
 			;;
+  arc*-*-linux*)
+			srv_regobj=""
+			srv_tgtobj="linux-arc-low.o arch/arc.o $srv_linux_obj"
+			srv_xmlfiles="arc/v1-core.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v1-aux.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v2-core.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v2-aux.xml"
+			srv_linux_regsets=yes
+			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
+			;;
   arm*-*-linux*)	srv_tgtobj="$srv_linux_obj linux-arm-low.o"
 			srv_tgtobj="$srv_tgtobj linux-arm-tdesc.o"
 			srv_tgtobj="$srv_tgtobj linux-aarch32-low.o"
diff --git a/gdbserver/linux-arc-low.cc b/gdbserver/linux-arc-low.cc
new file mode 100644
index 00000000000..605277ff9be
--- /dev/null
+++ b/gdbserver/linux-arc-low.cc
@@ -0,0 +1,420 @@
+/* Target dependent code for the remote server for GNU/Linux ARC.
+
+   Copyright 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 "server.h"
+#include "regdef.h"
+#include "linux-low.h"
+#include "tdesc.h"
+#include "arch/arc.h"
+
+#include <linux/elf.h>
+#include <arpa/inet.h>
+
+/* Linux starting with 4.12 supports NT_ARC_V2 note type, which adds R30,
+   R58 and R59 registers.  */
+#ifdef NT_ARC_V2
+#define ARC_HAS_V2_REGSET
+#endif
+
+/* The encoding of the instruction "TRAP_S 1" (endianness agnostic).  */
+#define TRAP_S_1_OPCODE	0x783e
+#define TRAP_S_1_SIZE	2
+
+/* Using a mere "uint16_t arc_linux_traps_s = TRAP_S_1_OPCODE" would
+   work as well, because the endianness will end up correctly when
+   the code is compiled for the same endianness as the target (see
+   the notes for "low_breakpoint_at" in this file).  However, this
+   illustrates how the __BIG_ENDIAN__ macro can be used to make
+   easy-to-understand codes.  */
+#if defined(__BIG_ENDIAN__)
+/* 0x78, 0x3e.  */
+static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE]
+	= {TRAP_S_1_OPCODE >> 8, TRAP_S_1_OPCODE & 0xFF};
+#else
+/* 0x3e, 0x78.  */
+static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE]
+	= {TRAP_S_1_OPCODE && 0xFF, TRAP_S_1_OPCODE >> 8};
+#endif
+
+/* Linux target op definitions for the ARC architecture.
+   Note for future: in case of adding the protected method low_get_next_pcs(),
+   the public method supports_software_single_step() should be added to return
+   "true".  */
+
+class arc_target : public linux_process_target
+{
+public:
+
+  const regs_info *get_regs_info () override;
+
+  const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
+
+protected:
+
+  void low_arch_setup () override;
+
+  bool low_cannot_fetch_register (int regno) override;
+
+  bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
+
+  bool low_breakpoint_at (CORE_ADDR where) override;
+};
+
+/* The singleton target ops object.  */
+
+static arc_target the_arc_target;
+
+bool
+arc_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+arc_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+arc_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
+static const struct target_desc *
+arc_linux_read_description (void)
+{
+#ifdef __ARC700__
+  arc_arch_features features (4, ARC_ISA_ARCV1);
+#else
+  arc_arch_features features (4, ARC_ISA_ARCV2);
+#endif
+  struct target_desc *tdesc = arc_create_target_description (features);
+
+  static const char *expedite_regs[] = { "sp", "status32", nullptr };
+  init_target_desc (tdesc, expedite_regs);
+
+  return tdesc;
+}
+
+void
+arc_target::low_arch_setup ()
+{
+  current_process ()->tdesc = arc_linux_read_description ();
+}
+
+bool
+arc_target::low_cannot_fetch_register (int regno)
+{
+  return (regno >= current_process ()->tdesc->reg_defs.size ());
+}
+
+bool
+arc_target::low_cannot_store_register (int regno)
+{
+  return (regno >= current_process ()->tdesc->reg_defs.size ());
+}
+
+/* This works for both endianness.  Below you see an illustration of how
+   the "trap_s 1" instruction encoded for both endianness in the memory
+   will end up as the TRAP_S_1_OPCODE constant:
+
+   BE: 0x78 0x3e --> at INSN addr: 0x78 0x3e --> INSN = 0x783e
+   LE: 0x3e 0x78 --> at INSN addr: 0x3e 0x78 --> INSN = 0x783e
+
+   One can employ "memcmp()" for comparing the arrays too.
+   A big shout-out to Simon Marchi (simark) for clearing this up.
+   */
+
+bool
+arc_target::low_breakpoint_at (CORE_ADDR where)
+{
+  uint16_t insn;
+
+  /* Since "this" is "the_target", no point in using the latter.  */
+  this->read_memory (where, (gdb_byte *) &insn, TRAP_S_1_SIZE);
+  return (insn == TRAP_S_1_OPCODE);
+}
+
+/* PTRACE_GETREGSET/NT_PRSTATUS and PTRACE_SETREGSET/NT_PRSTATUS work with
+   regsets in a struct, "user_regs_struct", defined in the
+   linux/arch/arc/include/uapi/asm/ptrace.h header.  This code supports
+   ARC Linux ABI v3 and v4.  */
+
+/* Populate a ptrace NT_PRSTATUS regset from a regcache.
+
+   This appears to be a unique approach to populating the buffer, but
+   being name, rather than offset based, it is robust to future API
+   changes, as there is no need to create a regmap of registers in the
+   user_regs_struct.  */
+
+static void
+arc_fill_gregset (struct regcache *regcache, void *buf)
+{
+  struct user_regs_struct *regbuf = (struct user_regs_struct *) buf;
+
+  /* Core registers.  */
+  collect_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
+  collect_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
+  collect_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
+  collect_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
+  collect_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
+  collect_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
+  collect_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
+  collect_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
+  collect_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
+  collect_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
+  collect_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
+  collect_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
+  collect_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
+  collect_register_by_name (regcache, "r13", &(regbuf->callee.r13));
+  collect_register_by_name (regcache, "r14", &(regbuf->callee.r14));
+  collect_register_by_name (regcache, "r15", &(regbuf->callee.r15));
+  collect_register_by_name (regcache, "r16", &(regbuf->callee.r16));
+  collect_register_by_name (regcache, "r17", &(regbuf->callee.r17));
+  collect_register_by_name (regcache, "r18", &(regbuf->callee.r18));
+  collect_register_by_name (regcache, "r19", &(regbuf->callee.r19));
+  collect_register_by_name (regcache, "r20", &(regbuf->callee.r20));
+  collect_register_by_name (regcache, "r21", &(regbuf->callee.r21));
+  collect_register_by_name (regcache, "r22", &(regbuf->callee.r22));
+  collect_register_by_name (regcache, "r23", &(regbuf->callee.r23));
+  collect_register_by_name (regcache, "r24", &(regbuf->callee.r24));
+  collect_register_by_name (regcache, "r25", &(regbuf->callee.r25));
+  collect_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
+  collect_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
+  collect_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
+  collect_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
+
+  /* Loop registers.  */
+  collect_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
+  collect_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
+  collect_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
+
+  /* The current "pc" value must be written to "eret" (exception return
+     address) register, because that is the address that the kernel code
+     will jump back to after a breakpoint exception has been raised.
+     The "pc_stop" value is ignored by the genregs_set() in
+     linux/arch/arc/kernel/ptrace.c.  */
+  collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));
+
+  /* Currently ARC Linux ptrace doesn't allow writes to status32 because
+     some of its bits are kernel mode-only and shoudn't be writable from
+     user-space.  Writing status32 from debugger could be useful, though,
+     so ability to write non-priviliged bits will be added to kernel
+     sooner or later.  */
+
+  /* BTA.  */
+  collect_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
+}
+
+/* Populate a regcache from a ptrace NT_PRSTATUS regset.  */
+
+static void
+arc_store_gregset (struct regcache *regcache, const void *buf)
+{
+  const struct user_regs_struct *regbuf = (const struct user_regs_struct *) buf;
+
+  /* Core registers.  */
+  supply_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
+  supply_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
+  supply_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
+  supply_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
+  supply_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
+  supply_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
+  supply_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
+  supply_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
+  supply_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
+  supply_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
+  supply_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
+  supply_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
+  supply_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
+  supply_register_by_name (regcache, "r13", &(regbuf->callee.r13));
+  supply_register_by_name (regcache, "r14", &(regbuf->callee.r14));
+  supply_register_by_name (regcache, "r15", &(regbuf->callee.r15));
+  supply_register_by_name (regcache, "r16", &(regbuf->callee.r16));
+  supply_register_by_name (regcache, "r17", &(regbuf->callee.r17));
+  supply_register_by_name (regcache, "r18", &(regbuf->callee.r18));
+  supply_register_by_name (regcache, "r19", &(regbuf->callee.r19));
+  supply_register_by_name (regcache, "r20", &(regbuf->callee.r20));
+  supply_register_by_name (regcache, "r21", &(regbuf->callee.r21));
+  supply_register_by_name (regcache, "r22", &(regbuf->callee.r22));
+  supply_register_by_name (regcache, "r23", &(regbuf->callee.r23));
+  supply_register_by_name (regcache, "r24", &(regbuf->callee.r24));
+  supply_register_by_name (regcache, "r25", &(regbuf->callee.r25));
+  supply_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
+  supply_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
+  supply_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
+  supply_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
+
+  /* Loop registers.  */
+  supply_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
+  supply_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
+  supply_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
+
+  /* The genregs_get() in linux/arch/arc/kernel/ptrace.c populates the
+     pseudo register "stop_pc" with the "efa" (exception fault address)
+     register.  This was deemed necessary, because the breakpoint
+     instruction, "trap_s 1", is a committing one; i.e. the "eret"
+     (excpetion return address) register will be pointing to the next
+     instruction, while "efa" points to the address that raised the
+     breakpoint.  */
+  supply_register_by_name (regcache, "pc", &(regbuf->stop_pc));
+  unsigned long pcl = regbuf->stop_pc & ~3L;
+  supply_register_by_name (regcache, "pcl", &pcl);
+
+  /* Other auxilliary registers.  */
+  supply_register_by_name (regcache, "status32", &(regbuf->scratch.status32));
+
+  /* BTA.  */
+  supply_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
+}
+
+#ifdef ARC_HAS_V2_REGSET
+
+/* Look through a regcache's TDESC for a register named NAME.
+   If found, return true; false, otherwise.  */
+
+static bool
+is_reg_name_available_p (const struct target_desc *tdesc,
+			 const char *name)
+{
+  for (const gdb::reg &reg : tdesc->reg_defs)
+    if (strcmp (name, reg.name) == 0)
+      return true;
+  return false;
+}
+
+/* Copy registers from regcache to user_regs_arcv2.  */
+
+static void
+arc_fill_v2_regset (struct regcache *regcache, void *buf)
+{
+  struct user_regs_arcv2 *regbuf = (struct user_regs_arcv2 *) buf;
+
+  if (is_reg_name_available_p (regcache->tdesc, "r30"))
+    collect_register_by_name (regcache, "r30", &(regbuf->r30));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r58"))
+    collect_register_by_name (regcache, "r58", &(regbuf->r58));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r59"))
+    collect_register_by_name (regcache, "r59", &(regbuf->r59));
+}
+
+/* Copy registers from user_regs_arcv2 to regcache.  */
+
+static void
+arc_store_v2_regset (struct regcache *regcache, const void *buf)
+{
+  struct user_regs_arcv2 *regbuf = (struct user_regs_arcv2 *) buf;
+
+  if (is_reg_name_available_p (regcache->tdesc, "r30"))
+    supply_register_by_name (regcache, "r30", &(regbuf->r30));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r58"))
+    supply_register_by_name (regcache, "r58", &(regbuf->r58));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r59"))
+    supply_register_by_name (regcache, "r59", &(regbuf->r59));
+}
+
+#endif
+
+/* Fetch the thread-local storage pointer for libthread_db.  Note that
+   this function is not called from GDB, but is called from libthread_db.
+
+   This is the same function as for other architectures, for example in
+   linux-arm-low.c.  */
+
+ps_err_e
+ps_get_thread_area (struct ps_prochandle *ph, lwpid_t lwpid,
+		    int idx, void **base)
+{
+  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, nullptr, base) != 0)
+    return PS_ERR;
+
+  /* IDX is the bias from the thread pointer to the beginning of the
+     thread descriptor.  It has to be subtracted due to implementation
+     quirks in libthread_db.  */
+  *base = (void *) ((char *) *base - idx);
+
+  return PS_OK;
+}
+
+static struct regset_info arc_regsets[] =
+{
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
+    sizeof (struct user_regs_struct), GENERAL_REGS,
+    arc_fill_gregset, arc_store_gregset
+  },
+#ifdef ARC_HAS_V2_REGSET
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARC_V2,
+    sizeof (struct user_regs_arcv2), GENERAL_REGS,
+    arc_fill_v2_regset, arc_store_v2_regset
+  },
+#endif
+  NULL_REGSET
+};
+
+static struct regsets_info arc_regsets_info =
+{
+  arc_regsets,	/* regsets */
+  0,		/* num_regsets */
+  nullptr,	/* disabled regsets */
+};
+
+static struct regs_info arc_regs_info =
+{
+  nullptr,	/* regset_bitmap */
+  nullptr,	/* usrregs */
+  &arc_regsets_info
+};
+
+const regs_info *
+arc_target::get_regs_info ()
+{
+  return &arc_regs_info;
+}
+
+/* One of the methods necessary for Z0 packet support.  */
+
+const gdb_byte *
+arc_target::sw_breakpoint_from_kind (int kind, int *size)
+{
+  gdb_assert (kind == TRAP_S_1_SIZE);
+  *size = kind;
+  return arc_linux_trap_s;
+}
+
+/* The linux target ops object.  */
+
+linux_process_target *the_linux_target = &the_arc_target;
+
+void
+initialize_low_arch (void)
+{
+  initialize_regsets_info (&arc_regsets_info);
+}
-- 
2.28.0


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

* Re: [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct
  2020-10-06 16:42 ` [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
  2020-10-06 16:42   ` [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
@ 2020-10-07  1:27   ` Simon Marchi
  1 sibling, 0 replies; 17+ messages in thread
From: Simon Marchi @ 2020-10-07  1:27 UTC (permalink / raw)
  To: Shahab Vahedi, gdb-patches; +Cc: Shahab Vahedi, Francois Bedard

On 2020-10-06 12:42 p.m., Shahab Vahedi via Gdb-patches wrote:
> From: Shahab Vahedi <shahab@synopsys.com>
>
> "arc_gdbarch_features" is a data structure containing information
> about the ARC architecture: ISA version, register size, etc.
> This name is misleading, because although it carries the phrase
> "gdbarch", it has nothing to do with the type/interface in GDB.
> Traditionaly, "gdbarch" structures are only used for that purpose.
> To rectify this, this patch changes the name to "arc_arch_features".

Thanks, this is OK.

Simon

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

* Re: [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC
  2020-10-06 16:42   ` [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
@ 2020-10-07  2:28     ` Simon Marchi
  2020-10-07  2:30       ` Simon Marchi
  2020-10-07  7:20       ` Shahab Vahedi
  0 siblings, 2 replies; 17+ messages in thread
From: Simon Marchi @ 2020-10-07  2:28 UTC (permalink / raw)
  To: Shahab Vahedi, gdb-patches
  Cc: Shahab Vahedi, Baris Aktemur, Francois Bedard, Anton Kolesov


Some minor comments, but otherwise this is fine.  Please merge after
going through the comments.

On 2020-10-06 12:42 p.m., Shahab Vahedi wrote:
> +/* Using a mere "uint16_t arc_linux_traps_s = TRAP_S_1_OPCODE" would
> +   work as well, because the endianness will end up correctly when
> +   the code is compiled for the same endianness as the target (see
> +   the notes for "low_breakpoint_at" in this file).  However, this
> +   illustrates how the __BIG_ENDIAN__ macro can be used to make
> +   easy-to-understand codes.  */

If you have a simpler way that  doesn't use __BIG_ENDIAN__, that's fine
too.  Don't feel forced to use it only because I suggested it.

> +bool
> +arc_target::low_cannot_store_register (int regno)
> +{
> +  return (regno >= current_process ()->tdesc->reg_defs.size ());
> +}
> +
> +/* This works for both endianness.  Below you see an illustration of how
> +   the "trap_s 1" instruction encoded for both endianness in the memory
> +   will end up as the TRAP_S_1_OPCODE constant:
> +
> +   BE: 0x78 0x3e --> at INSN addr: 0x78 0x3e --> INSN = 0x783e
> +   LE: 0x3e 0x78 --> at INSN addr: 0x3e 0x78 --> INSN = 0x783e
> +
> +   One can employ "memcmp()" for comparing the arrays too.
> +   A big shout-out to Simon Marchi (simark) for clearing this up.

Heh, please don't mention this :).

> +   */
> +
> +bool
> +arc_target::low_breakpoint_at (CORE_ADDR where)
> +{
> +  uint16_t insn;
> +
> +  /* Since "this" is "the_target", no point in using the latter.  */

This is not a very useful comment IMO.  "this" is the "current"
arc_target object, which is obvious to anybody familiar with C++.

> +  this->read_memory (where, (gdb_byte *) &insn, TRAP_S_1_SIZE);
> +  return (insn == TRAP_S_1_OPCODE);
> +}
> +
> +/* PTRACE_GETREGSET/NT_PRSTATUS and PTRACE_SETREGSET/NT_PRSTATUS work with
> +   regsets in a struct, "user_regs_struct", defined in the
> +   linux/arch/arc/include/uapi/asm/ptrace.h header.  This code supports
> +   ARC Linux ABI v3 and v4.  */
> +
> +/* Populate a ptrace NT_PRSTATUS regset from a regcache.
> +
> +   This appears to be a unique approach to populating the buffer, but
> +   being name, rather than offset based, it is robust to future API
> +   changes, as there is no need to create a regmap of registers in the
> +   user_regs_struct.  */
> +
> +static void
> +arc_fill_gregset (struct regcache *regcache, void *buf)
> +{
> +  struct user_regs_struct *regbuf = (struct user_regs_struct *) buf;
> +
> +  /* Core registers.  */
> +  collect_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
> +  collect_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
> +  collect_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
> +  collect_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
> +  collect_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
> +  collect_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
> +  collect_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
> +  collect_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
> +  collect_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
> +  collect_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
> +  collect_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
> +  collect_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
> +  collect_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
> +  collect_register_by_name (regcache, "r13", &(regbuf->callee.r13));
> +  collect_register_by_name (regcache, "r14", &(regbuf->callee.r14));
> +  collect_register_by_name (regcache, "r15", &(regbuf->callee.r15));
> +  collect_register_by_name (regcache, "r16", &(regbuf->callee.r16));
> +  collect_register_by_name (regcache, "r17", &(regbuf->callee.r17));
> +  collect_register_by_name (regcache, "r18", &(regbuf->callee.r18));
> +  collect_register_by_name (regcache, "r19", &(regbuf->callee.r19));
> +  collect_register_by_name (regcache, "r20", &(regbuf->callee.r20));
> +  collect_register_by_name (regcache, "r21", &(regbuf->callee.r21));
> +  collect_register_by_name (regcache, "r22", &(regbuf->callee.r22));
> +  collect_register_by_name (regcache, "r23", &(regbuf->callee.r23));
> +  collect_register_by_name (regcache, "r24", &(regbuf->callee.r24));
> +  collect_register_by_name (regcache, "r25", &(regbuf->callee.r25));
> +  collect_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
> +  collect_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
> +  collect_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
> +  collect_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
> +
> +  /* Loop registers.  */
> +  collect_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
> +  collect_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
> +  collect_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
> +
> +  /* The current "pc" value must be written to "eret" (exception return
> +     address) register, because that is the address that the kernel code
> +     will jump back to after a breakpoint exception has been raised.
> +     The "pc_stop" value is ignored by the genregs_set() in
> +     linux/arch/arc/kernel/ptrace.c.  */
> +  collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));
> +
> +  /* Currently ARC Linux ptrace doesn't allow writes to status32 because
> +     some of its bits are kernel mode-only and shoudn't be writable from
> +     user-space.  Writing status32 from debugger could be useful, though,
> +     so ability to write non-priviliged bits will be added to kernel
> +     sooner or later.  */
> +
> +  /* BTA.  */
> +  collect_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
> +}
> +
> +/* Populate a regcache from a ptrace NT_PRSTATUS regset.  */
> +
> +static void
> +arc_store_gregset (struct regcache *regcache, const void *buf)
> +{
> +  const struct user_regs_struct *regbuf = (const struct user_regs_struct *) buf;
> +
> +  /* Core registers.  */
> +  supply_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
> +  supply_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
> +  supply_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
> +  supply_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
> +  supply_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
> +  supply_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
> +  supply_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
> +  supply_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
> +  supply_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
> +  supply_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
> +  supply_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
> +  supply_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
> +  supply_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
> +  supply_register_by_name (regcache, "r13", &(regbuf->callee.r13));
> +  supply_register_by_name (regcache, "r14", &(regbuf->callee.r14));
> +  supply_register_by_name (regcache, "r15", &(regbuf->callee.r15));
> +  supply_register_by_name (regcache, "r16", &(regbuf->callee.r16));
> +  supply_register_by_name (regcache, "r17", &(regbuf->callee.r17));
> +  supply_register_by_name (regcache, "r18", &(regbuf->callee.r18));
> +  supply_register_by_name (regcache, "r19", &(regbuf->callee.r19));
> +  supply_register_by_name (regcache, "r20", &(regbuf->callee.r20));
> +  supply_register_by_name (regcache, "r21", &(regbuf->callee.r21));
> +  supply_register_by_name (regcache, "r22", &(regbuf->callee.r22));
> +  supply_register_by_name (regcache, "r23", &(regbuf->callee.r23));
> +  supply_register_by_name (regcache, "r24", &(regbuf->callee.r24));
> +  supply_register_by_name (regcache, "r25", &(regbuf->callee.r25));
> +  supply_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
> +  supply_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
> +  supply_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
> +  supply_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
> +
> +  /* Loop registers.  */
> +  supply_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
> +  supply_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
> +  supply_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
> +
> +  /* The genregs_get() in linux/arch/arc/kernel/ptrace.c populates the
> +     pseudo register "stop_pc" with the "efa" (exception fault address)
> +     register.  This was deemed necessary, because the breakpoint
> +     instruction, "trap_s 1", is a committing one; i.e. the "eret"
> +     (excpetion return address) register will be pointing to the next

excpetion -> exception

Simon

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

* Re: [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC
  2020-10-07  2:28     ` Simon Marchi
@ 2020-10-07  2:30       ` Simon Marchi
  2020-10-07  7:33         ` Shahab Vahedi
  2020-10-07  7:20       ` Shahab Vahedi
  1 sibling, 1 reply; 17+ messages in thread
From: Simon Marchi @ 2020-10-07  2:30 UTC (permalink / raw)
  To: Shahab Vahedi, gdb-patches; +Cc: Anton Kolesov, Shahab Vahedi, Francois Bedard

On 2020-10-06 10:28 p.m., Simon Marchi wrote:
> Some minor comments, but otherwise this is fine.  Please merge after
> going through the comments.

Oh, also it seems like we announce new gdbserver ports in gdb/NEWS, so
can you please prepare a separate patch for that?

Simon

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

* Re: [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC
  2020-10-07  2:28     ` Simon Marchi
  2020-10-07  2:30       ` Simon Marchi
@ 2020-10-07  7:20       ` Shahab Vahedi
  1 sibling, 0 replies; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-07  7:20 UTC (permalink / raw)
  To: Simon Marchi
  Cc: gdb-patches, Shahab Vahedi, Baris Aktemur, Francois Bedard,
	Anton Kolesov

Hi Simon,

On Tue, Oct 06, 2020 at 10:28:54PM -0400, Simon Marchi wrote:
> On 2020-10-06 12:42 p.m., Shahab Vahedi wrote:
> > +/* Using a mere "uint16_t arc_linux_traps_s = TRAP_S_1_OPCODE" would
> > +   work as well, because the endianness will end up correctly when
> > +   the code is compiled for the same endianness as the target (see
> > +   the notes for "low_breakpoint_at" in this file).  However, this
> > +   illustrates how the __BIG_ENDIAN__ macro can be used to make
> > +   easy-to-understand codes.  */
> 
> If you have a simpler way that  doesn't use __BIG_ENDIAN__, that's fine
> too.  Don't feel forced to use it only because I suggested it.

Actually I am grateful that you did.  It keeps my options open.  If in
the future, I run into a problem related to endianness that cannot be
solved easily or it makes more sense to have it "if" guarded, then this
will be a good hint for me.

> > +  /* Since "this" is "the_target", no point in using the latter.  */
> 
> This is not a very useful comment IMO.  "this" is the "current"
> arc_target object, which is obvious to anybody familiar with C++.

This is not about the "this" keyword being the current object in C++.
The previous code was using "the_target->...".  To me, it was not
clear that the "the_target" global variable is actually the current
object.  Maybe I should change the comment to what I just said to have
it less confusing for the people reading it.


Cheers,
Shahab

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

* Re: [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC
  2020-10-07  2:30       ` Simon Marchi
@ 2020-10-07  7:33         ` Shahab Vahedi
  2020-10-07 11:17           ` Simon Marchi
  0 siblings, 1 reply; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-07  7:33 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches, Anton Kolesov, Shahab Vahedi, Francois Bedard

Hi Simon,

On Tue, Oct 06, 2020 at 10:30:13PM -0400, Simon Marchi wrote:
> Oh, also it seems like we announce new gdbserver ports in gdb/NEWS, so
> can you please prepare a separate patch for that?

Sure! Does it really need to be a _separate_ patch?

On a different topic, can I still push my changes to "gdb-10-branch"?


Cheers,
Shahab

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

* Re: [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC
  2020-10-07  7:33         ` Shahab Vahedi
@ 2020-10-07 11:17           ` Simon Marchi
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Marchi @ 2020-10-07 11:17 UTC (permalink / raw)
  To: Shahab Vahedi; +Cc: gdb-patches, Anton Kolesov, Shahab Vahedi, Francois Bedard

On 2020-10-07 3:33 a.m., Shahab Vahedi wrote:
> Sure! Does it really need to be a _separate_ patch?

No, but since this patch is ok, I think you can push it and send a
separate small patch for the NEWS, instead of rolling a new version of
the big patch.

> On a different topic, can I still push my changes to "gdb-10-branch"?

Yes, since it's a new gdbserver implementation we agreed that it was ok,
there is no risk of breaking existing features.

Simon

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

* [PUSHED master] arc: Rename "arc_gdbarch_features" struct
  2020-08-26 16:56 [PATCH] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
                   ` (3 preceding siblings ...)
  2020-10-06 16:42 ` [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
@ 2020-10-07 15:58 ` Shahab Vahedi
  2020-10-07 15:58   ` [PUSHED master] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
  2020-10-07 16:03 ` [PUSHED gdb-10-branch] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
  5 siblings, 1 reply; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-07 15:58 UTC (permalink / raw)
  To: gdb-patches
  Cc: Shahab Vahedi, Shahab Vahedi, Simon Marchi, Baris Aktemur,
	Francois Bedard

From: Shahab Vahedi <shahab@synopsys.com>

"arc_gdbarch_features" is a data structure containing information
about the ARC architecture: ISA version, register size, etc.
This name is misleading, because although it carries the phrase
"gdbarch", it has nothing to do with the type/interface in GDB.
Traditionaly, "gdbarch" structures are only used for that purpose.
To rectify this, this patch changes the name to "arc_arch_features".

gdb/ChangeLog:

	* arch/arc.h: Rename "arc_gdbarch_features" to
	"arc_arch_features".
	* arc-tdep.h: Likewise.
	* arc-tdep.c: Likewise.
---
 gdb/arc-tdep.c | 14 +++++++-------
 gdb/arch/arc.c | 12 ++++++------
 gdb/arch/arc.h | 12 ++++++------
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 6f544bff78d..60c76af3352 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1883,11 +1883,11 @@ mach_type_to_arc_isa (const unsigned long mach)
     }
 }
 
-/* Common construction code for ARC_GDBARCH_FEATURES struct.  If there
+/* Common construction code for ARC_ARCH_FEATURES struct.  If there
    is no ABFD, then a FEATURE with default values is returned.  */
 
-static arc_gdbarch_features
-arc_gdbarch_features_create (const bfd *abfd, const unsigned long mach)
+static arc_arch_features
+arc_arch_features_create (const bfd *abfd, const unsigned long mach)
 {
   /* Use 4 as a fallback value.  */
   int reg_size = 4;
@@ -1915,7 +1915,7 @@ arc_gdbarch_features_create (const bfd *abfd, const unsigned long mach)
      case).  */
   arc_isa isa = mach_type_to_arc_isa (mach);
 
-  return arc_gdbarch_features (reg_size, isa);
+  return arc_arch_features (reg_size, isa);
 }
 
 /* Look for obsolete core feature names in TDESC.  */
@@ -2085,9 +2085,9 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
   /* If target doesn't provide a description, use the default ones.  */
   if (!tdesc_has_registers (tdesc_loc))
     {
-      arc_gdbarch_features features
-	= arc_gdbarch_features_create (info.abfd,
-				       info.bfd_arch_info->mach);
+      arc_arch_features features
+	= arc_arch_features_create (info.abfd,
+				    info.bfd_arch_info->mach);
       tdesc_loc = arc_lookup_target_description (features);
     }
   gdb_assert (tdesc_loc != nullptr);
diff --git a/gdb/arch/arc.c b/gdb/arch/arc.c
index 8e126ca5a82..3808f9fe292 100644
--- a/gdb/arch/arc.c
+++ b/gdb/arch/arc.c
@@ -35,7 +35,7 @@
 #endif
 
 STATIC_IN_GDB target_desc *
-arc_create_target_description (const struct arc_gdbarch_features &features)
+arc_create_target_description (const struct arc_arch_features &features)
 {
   /* Create a new target description.  */
   target_desc *tdesc = allocate_target_description ();
@@ -84,10 +84,10 @@ arc_create_target_description (const struct arc_gdbarch_features &features)
 #ifndef GDBSERVER
 
 /* Wrapper used by std::unordered_map to generate hash for features set.  */
-struct arc_gdbarch_features_hasher
+struct arc_arch_features_hasher
 {
   std::size_t
-  operator() (const arc_gdbarch_features &features) const noexcept
+  operator() (const arc_arch_features &features) const noexcept
   {
     return features.hash ();
   }
@@ -95,14 +95,14 @@ struct arc_gdbarch_features_hasher
 
 /* Cache of previously created target descriptions, indexed by the hash
    of the features set used to create them.  */
-static std::unordered_map<arc_gdbarch_features,
+static std::unordered_map<arc_arch_features,
 			  const target_desc_up,
-			  arc_gdbarch_features_hasher> arc_tdesc_cache;
+			  arc_arch_features_hasher> arc_tdesc_cache;
 
 /* See arch/arc.h.  */
 
 const target_desc *
-arc_lookup_target_description (const struct arc_gdbarch_features &features)
+arc_lookup_target_description (const struct arc_arch_features &features)
 {
   /* Lookup in the cache first.  If found, return the pointer from the
      "target_desc_up" type which is a "unique_ptr".  This should be fine
diff --git a/gdb/arch/arc.h b/gdb/arch/arc.h
index a5313b1fee6..16257596748 100644
--- a/gdb/arch/arc.h
+++ b/gdb/arch/arc.h
@@ -27,9 +27,9 @@ enum arc_isa
   ARC_ISA_ARCV2	      /* such as ARC EM and ARC HS  */
 };
 
-struct arc_gdbarch_features
+struct arc_arch_features
 {
-  arc_gdbarch_features (int reg_size, arc_isa isa)
+  arc_arch_features (int reg_size, arc_isa isa)
     : reg_size (reg_size), isa (isa)
   {}
 
@@ -41,13 +41,13 @@ struct arc_gdbarch_features
   const arc_isa isa;
 
   /* Equality operator.  */
-  bool operator== (const struct arc_gdbarch_features &rhs) const
+  bool operator== (const struct arc_arch_features &rhs) const
   {
     return (reg_size == rhs.reg_size && isa == rhs.isa);
   }
 
   /* Inequality operator.  */
-  bool operator!= (const struct arc_gdbarch_features &rhs) const
+  bool operator!= (const struct arc_arch_features &rhs) const
   {
     return !(*this == rhs);
   }
@@ -71,7 +71,7 @@ struct arc_gdbarch_features
    the returned data.  */
 
 target_desc *arc_create_target_description
-	(const struct arc_gdbarch_features &features);
+	(const struct arc_arch_features &features);
 
 #else
 
@@ -79,7 +79,7 @@ target_desc *arc_create_target_description
    If nothing is found, then create one and return it.  */
 
 const target_desc *arc_lookup_target_description
-	(const struct arc_gdbarch_features &features);
+	(const struct arc_arch_features &features);
 
 #endif /* GDBSERVER */
 
-- 
2.28.0


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

* [PUSHED master] gdbserver: Add GNU/Linux support for ARC
  2020-10-07 15:58 ` [PUSHED master] " Shahab Vahedi
@ 2020-10-07 15:58   ` Shahab Vahedi
  0 siblings, 0 replies; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-07 15:58 UTC (permalink / raw)
  To: gdb-patches
  Cc: Shahab Vahedi, Shahab Vahedi, Simon Marchi, Baris Aktemur,
	Francois Bedard, Anton Kolesov

From: Anton Kolesov <Anton.Kolesov@synopsys.com>

This gdbserver implementation supports ARC ABI v3 and v4 (older ARC ABI
versions are not supported by other modern GNU tools or Linux itself).
Gdbserver supports inspection of ARC HS registers R30, R58 and R59 - feature
that has been added to Linux 4.12.  Whether gdbserver build will actually
support this feature depends on the version of Linux headers used to build
the server.

v2 [1]:
- Use "this->read_memory ()" instead of "the_target->read_memory ()".
- Remove the unnecessary "arch-arc.o:" target from the "Makefile.in".
- Got rid of "ntohs()" function and added lots of comments about
  endianness.
- Clarify why "pc" value is read from and saved to different fields
  in user regs struct.
- In function "is_reg_name_available_p()", use a range-based iterator
  to loop over the registers.
- Removed mentioning of issue number that was not related to sourceware.
- A few typo's fixed.

[1] Remarks
https://sourceware.org/pipermail/gdb-patches/2020-September/171911.html
https://sourceware.org/pipermail/gdb-patches/2020-September/171919.html

gdbserver/ChangeLog:

	* configure.srv: Support ARC architecture.
	* Makefile.in: Add linux-arc-low.cc and arch/arc.o.
	* linux-arc-low.cc: New file.
---
 gdbserver/Makefile.in      |   2 +
 gdbserver/configure.srv    |  11 +
 gdbserver/linux-arc-low.cc | 418 +++++++++++++++++++++++++++++++++++++
 3 files changed, 431 insertions(+)
 create mode 100644 gdbserver/linux-arc-low.cc

diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
index 9d7687be534..09a652a3354 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -179,6 +179,7 @@ SFILES = \
 	$(srcdir)/i387-fp.cc \
 	$(srcdir)/inferiors.cc \
 	$(srcdir)/linux-aarch64-low.cc \
+	$(srcdir)/linux-arc-low.cc \
 	$(srcdir)/linux-arm-low.cc \
 	$(srcdir)/linux-ia64-low.cc \
 	$(srcdir)/linux-low.cc \
@@ -206,6 +207,7 @@ SFILES = \
 	$(srcdir)/win32-low.cc \
 	$(srcdir)/x86-low.cc \
 	$(srcdir)/../gdb/alloc.c \
+	$(srcdir)/../gdb/arch/arc.c \
 	$(srcdir)/../gdb/arch/arm.c \
 	$(srcdir)/../gdb/arch/arm-get-next-pcs.c \
 	$(srcdir)/../gdb/arch/arm-linux.c \
diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
index 5e33bd9c54d..029ddabc4b8 100644
--- a/gdbserver/configure.srv
+++ b/gdbserver/configure.srv
@@ -61,6 +61,17 @@ case "${gdbserver_host}" in
 			ipa_obj="${ipa_obj} linux-aarch64-tdesc-ipa.o"
 			ipa_obj="${ipa_obj} arch/aarch64-ipa.o"
 			;;
+  arc*-*-linux*)
+			srv_regobj=""
+			srv_tgtobj="linux-arc-low.o arch/arc.o $srv_linux_obj"
+			srv_xmlfiles="arc/v1-core.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v1-aux.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v2-core.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v2-aux.xml"
+			srv_linux_regsets=yes
+			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
+			;;
   arm*-*-linux*)	srv_tgtobj="$srv_linux_obj linux-arm-low.o"
 			srv_tgtobj="$srv_tgtobj linux-arm-tdesc.o"
 			srv_tgtobj="$srv_tgtobj linux-aarch32-low.o"
diff --git a/gdbserver/linux-arc-low.cc b/gdbserver/linux-arc-low.cc
new file mode 100644
index 00000000000..1f370ef7964
--- /dev/null
+++ b/gdbserver/linux-arc-low.cc
@@ -0,0 +1,418 @@
+/* Target dependent code for the remote server for GNU/Linux ARC.
+
+   Copyright 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 "server.h"
+#include "regdef.h"
+#include "linux-low.h"
+#include "tdesc.h"
+#include "arch/arc.h"
+
+#include <linux/elf.h>
+#include <arpa/inet.h>
+
+/* Linux starting with 4.12 supports NT_ARC_V2 note type, which adds R30,
+   R58 and R59 registers.  */
+#ifdef NT_ARC_V2
+#define ARC_HAS_V2_REGSET
+#endif
+
+/* The encoding of the instruction "TRAP_S 1" (endianness agnostic).  */
+#define TRAP_S_1_OPCODE	0x783e
+#define TRAP_S_1_SIZE	2
+
+/* Using a mere "uint16_t arc_linux_traps_s = TRAP_S_1_OPCODE" would
+   work as well, because the endianness will end up correctly when
+   the code is compiled for the same endianness as the target (see
+   the notes for "low_breakpoint_at" in this file).  However, this
+   illustrates how the __BIG_ENDIAN__ macro can be used to make
+   easy-to-understand codes.  */
+#if defined(__BIG_ENDIAN__)
+/* 0x78, 0x3e.  */
+static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE]
+	= {TRAP_S_1_OPCODE >> 8, TRAP_S_1_OPCODE & 0xFF};
+#else
+/* 0x3e, 0x78.  */
+static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE]
+	= {TRAP_S_1_OPCODE && 0xFF, TRAP_S_1_OPCODE >> 8};
+#endif
+
+/* Linux target op definitions for the ARC architecture.
+   Note for future: in case of adding the protected method low_get_next_pcs(),
+   the public method supports_software_single_step() should be added to return
+   "true".  */
+
+class arc_target : public linux_process_target
+{
+public:
+
+  const regs_info *get_regs_info () override;
+
+  const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
+
+protected:
+
+  void low_arch_setup () override;
+
+  bool low_cannot_fetch_register (int regno) override;
+
+  bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
+
+  bool low_breakpoint_at (CORE_ADDR where) override;
+};
+
+/* The singleton target ops object.  */
+
+static arc_target the_arc_target;
+
+bool
+arc_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+arc_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+arc_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
+static const struct target_desc *
+arc_linux_read_description (void)
+{
+#ifdef __ARC700__
+  arc_arch_features features (4, ARC_ISA_ARCV1);
+#else
+  arc_arch_features features (4, ARC_ISA_ARCV2);
+#endif
+  struct target_desc *tdesc = arc_create_target_description (features);
+
+  static const char *expedite_regs[] = { "sp", "status32", nullptr };
+  init_target_desc (tdesc, expedite_regs);
+
+  return tdesc;
+}
+
+void
+arc_target::low_arch_setup ()
+{
+  current_process ()->tdesc = arc_linux_read_description ();
+}
+
+bool
+arc_target::low_cannot_fetch_register (int regno)
+{
+  return (regno >= current_process ()->tdesc->reg_defs.size ());
+}
+
+bool
+arc_target::low_cannot_store_register (int regno)
+{
+  return (regno >= current_process ()->tdesc->reg_defs.size ());
+}
+
+/* This works for both endianness.  Below you see an illustration of how
+   the "trap_s 1" instruction encoded for both endianness in the memory
+   will end up as the TRAP_S_1_OPCODE constant:
+
+   BE: 0x78 0x3e --> at INSN addr: 0x78 0x3e --> INSN = 0x783e
+   LE: 0x3e 0x78 --> at INSN addr: 0x3e 0x78 --> INSN = 0x783e
+
+   One can employ "memcmp()" for comparing the arrays too.  */
+
+bool
+arc_target::low_breakpoint_at (CORE_ADDR where)
+{
+  uint16_t insn;
+
+  /* "the_target" global variable is the current object at hand.  */
+  this->read_memory (where, (gdb_byte *) &insn, TRAP_S_1_SIZE);
+  return (insn == TRAP_S_1_OPCODE);
+}
+
+/* PTRACE_GETREGSET/NT_PRSTATUS and PTRACE_SETREGSET/NT_PRSTATUS work with
+   regsets in a struct, "user_regs_struct", defined in the
+   linux/arch/arc/include/uapi/asm/ptrace.h header.  This code supports
+   ARC Linux ABI v3 and v4.  */
+
+/* Populate a ptrace NT_PRSTATUS regset from a regcache.
+
+   This appears to be a unique approach to populating the buffer, but
+   being name, rather than offset based, it is robust to future API
+   changes, as there is no need to create a regmap of registers in the
+   user_regs_struct.  */
+
+static void
+arc_fill_gregset (struct regcache *regcache, void *buf)
+{
+  struct user_regs_struct *regbuf = (struct user_regs_struct *) buf;
+
+  /* Core registers.  */
+  collect_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
+  collect_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
+  collect_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
+  collect_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
+  collect_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
+  collect_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
+  collect_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
+  collect_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
+  collect_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
+  collect_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
+  collect_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
+  collect_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
+  collect_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
+  collect_register_by_name (regcache, "r13", &(regbuf->callee.r13));
+  collect_register_by_name (regcache, "r14", &(regbuf->callee.r14));
+  collect_register_by_name (regcache, "r15", &(regbuf->callee.r15));
+  collect_register_by_name (regcache, "r16", &(regbuf->callee.r16));
+  collect_register_by_name (regcache, "r17", &(regbuf->callee.r17));
+  collect_register_by_name (regcache, "r18", &(regbuf->callee.r18));
+  collect_register_by_name (regcache, "r19", &(regbuf->callee.r19));
+  collect_register_by_name (regcache, "r20", &(regbuf->callee.r20));
+  collect_register_by_name (regcache, "r21", &(regbuf->callee.r21));
+  collect_register_by_name (regcache, "r22", &(regbuf->callee.r22));
+  collect_register_by_name (regcache, "r23", &(regbuf->callee.r23));
+  collect_register_by_name (regcache, "r24", &(regbuf->callee.r24));
+  collect_register_by_name (regcache, "r25", &(regbuf->callee.r25));
+  collect_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
+  collect_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
+  collect_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
+  collect_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
+
+  /* Loop registers.  */
+  collect_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
+  collect_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
+  collect_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
+
+  /* The current "pc" value must be written to "eret" (exception return
+     address) register, because that is the address that the kernel code
+     will jump back to after a breakpoint exception has been raised.
+     The "pc_stop" value is ignored by the genregs_set() in
+     linux/arch/arc/kernel/ptrace.c.  */
+  collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));
+
+  /* Currently ARC Linux ptrace doesn't allow writes to status32 because
+     some of its bits are kernel mode-only and shoudn't be writable from
+     user-space.  Writing status32 from debugger could be useful, though,
+     so ability to write non-priviliged bits will be added to kernel
+     sooner or later.  */
+
+  /* BTA.  */
+  collect_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
+}
+
+/* Populate a regcache from a ptrace NT_PRSTATUS regset.  */
+
+static void
+arc_store_gregset (struct regcache *regcache, const void *buf)
+{
+  const struct user_regs_struct *regbuf = (const struct user_regs_struct *) buf;
+
+  /* Core registers.  */
+  supply_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
+  supply_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
+  supply_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
+  supply_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
+  supply_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
+  supply_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
+  supply_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
+  supply_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
+  supply_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
+  supply_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
+  supply_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
+  supply_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
+  supply_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
+  supply_register_by_name (regcache, "r13", &(regbuf->callee.r13));
+  supply_register_by_name (regcache, "r14", &(regbuf->callee.r14));
+  supply_register_by_name (regcache, "r15", &(regbuf->callee.r15));
+  supply_register_by_name (regcache, "r16", &(regbuf->callee.r16));
+  supply_register_by_name (regcache, "r17", &(regbuf->callee.r17));
+  supply_register_by_name (regcache, "r18", &(regbuf->callee.r18));
+  supply_register_by_name (regcache, "r19", &(regbuf->callee.r19));
+  supply_register_by_name (regcache, "r20", &(regbuf->callee.r20));
+  supply_register_by_name (regcache, "r21", &(regbuf->callee.r21));
+  supply_register_by_name (regcache, "r22", &(regbuf->callee.r22));
+  supply_register_by_name (regcache, "r23", &(regbuf->callee.r23));
+  supply_register_by_name (regcache, "r24", &(regbuf->callee.r24));
+  supply_register_by_name (regcache, "r25", &(regbuf->callee.r25));
+  supply_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
+  supply_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
+  supply_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
+  supply_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
+
+  /* Loop registers.  */
+  supply_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
+  supply_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
+  supply_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
+
+  /* The genregs_get() in linux/arch/arc/kernel/ptrace.c populates the
+     pseudo register "stop_pc" with the "efa" (exception fault address)
+     register.  This was deemed necessary, because the breakpoint
+     instruction, "trap_s 1", is a committing one; i.e. the "eret"
+     (exception return address) register will be pointing to the next
+     instruction, while "efa" points to the address that raised the
+     breakpoint.  */
+  supply_register_by_name (regcache, "pc", &(regbuf->stop_pc));
+  unsigned long pcl = regbuf->stop_pc & ~3L;
+  supply_register_by_name (regcache, "pcl", &pcl);
+
+  /* Other auxilliary registers.  */
+  supply_register_by_name (regcache, "status32", &(regbuf->scratch.status32));
+
+  /* BTA.  */
+  supply_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
+}
+
+#ifdef ARC_HAS_V2_REGSET
+
+/* Look through a regcache's TDESC for a register named NAME.
+   If found, return true; false, otherwise.  */
+
+static bool
+is_reg_name_available_p (const struct target_desc *tdesc,
+			 const char *name)
+{
+  for (const gdb::reg &reg : tdesc->reg_defs)
+    if (strcmp (name, reg.name) == 0)
+      return true;
+  return false;
+}
+
+/* Copy registers from regcache to user_regs_arcv2.  */
+
+static void
+arc_fill_v2_regset (struct regcache *regcache, void *buf)
+{
+  struct user_regs_arcv2 *regbuf = (struct user_regs_arcv2 *) buf;
+
+  if (is_reg_name_available_p (regcache->tdesc, "r30"))
+    collect_register_by_name (regcache, "r30", &(regbuf->r30));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r58"))
+    collect_register_by_name (regcache, "r58", &(regbuf->r58));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r59"))
+    collect_register_by_name (regcache, "r59", &(regbuf->r59));
+}
+
+/* Copy registers from user_regs_arcv2 to regcache.  */
+
+static void
+arc_store_v2_regset (struct regcache *regcache, const void *buf)
+{
+  struct user_regs_arcv2 *regbuf = (struct user_regs_arcv2 *) buf;
+
+  if (is_reg_name_available_p (regcache->tdesc, "r30"))
+    supply_register_by_name (regcache, "r30", &(regbuf->r30));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r58"))
+    supply_register_by_name (regcache, "r58", &(regbuf->r58));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r59"))
+    supply_register_by_name (regcache, "r59", &(regbuf->r59));
+}
+
+#endif
+
+/* Fetch the thread-local storage pointer for libthread_db.  Note that
+   this function is not called from GDB, but is called from libthread_db.
+
+   This is the same function as for other architectures, for example in
+   linux-arm-low.c.  */
+
+ps_err_e
+ps_get_thread_area (struct ps_prochandle *ph, lwpid_t lwpid,
+		    int idx, void **base)
+{
+  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, nullptr, base) != 0)
+    return PS_ERR;
+
+  /* IDX is the bias from the thread pointer to the beginning of the
+     thread descriptor.  It has to be subtracted due to implementation
+     quirks in libthread_db.  */
+  *base = (void *) ((char *) *base - idx);
+
+  return PS_OK;
+}
+
+static struct regset_info arc_regsets[] =
+{
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
+    sizeof (struct user_regs_struct), GENERAL_REGS,
+    arc_fill_gregset, arc_store_gregset
+  },
+#ifdef ARC_HAS_V2_REGSET
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARC_V2,
+    sizeof (struct user_regs_arcv2), GENERAL_REGS,
+    arc_fill_v2_regset, arc_store_v2_regset
+  },
+#endif
+  NULL_REGSET
+};
+
+static struct regsets_info arc_regsets_info =
+{
+  arc_regsets,	/* regsets */
+  0,		/* num_regsets */
+  nullptr,	/* disabled regsets */
+};
+
+static struct regs_info arc_regs_info =
+{
+  nullptr,	/* regset_bitmap */
+  nullptr,	/* usrregs */
+  &arc_regsets_info
+};
+
+const regs_info *
+arc_target::get_regs_info ()
+{
+  return &arc_regs_info;
+}
+
+/* One of the methods necessary for Z0 packet support.  */
+
+const gdb_byte *
+arc_target::sw_breakpoint_from_kind (int kind, int *size)
+{
+  gdb_assert (kind == TRAP_S_1_SIZE);
+  *size = kind;
+  return arc_linux_trap_s;
+}
+
+/* The linux target ops object.  */
+
+linux_process_target *the_linux_target = &the_arc_target;
+
+void
+initialize_low_arch (void)
+{
+  initialize_regsets_info (&arc_regsets_info);
+}
-- 
2.28.0


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

* [PUSHED gdb-10-branch] arc: Rename "arc_gdbarch_features" struct
  2020-08-26 16:56 [PATCH] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
                   ` (4 preceding siblings ...)
  2020-10-07 15:58 ` [PUSHED master] " Shahab Vahedi
@ 2020-10-07 16:03 ` Shahab Vahedi
  2020-10-07 16:03   ` [PUSHED gdb-10-branch] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
  5 siblings, 1 reply; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-07 16:03 UTC (permalink / raw)
  To: gdb-patches
  Cc: Shahab Vahedi, Shahab Vahedi, Simon Marchi, Baris Aktemur,
	Francois Bedard

From: Shahab Vahedi <shahab@synopsys.com>

"arc_gdbarch_features" is a data structure containing information
about the ARC architecture: ISA version, register size, etc.
This name is misleading, because although it carries the phrase
"gdbarch", it has nothing to do with the type/interface in GDB.
Traditionaly, "gdbarch" structures are only used for that purpose.
To rectify this, this patch changes the name to "arc_arch_features".

gdb/ChangeLog:

	* arch/arc.h: Rename "arc_gdbarch_features" to
	"arc_arch_features".
	* arc-tdep.h: Likewise.
	* arc-tdep.c: Likewise.
---
 gdb/arc-tdep.c | 14 +++++++-------
 gdb/arch/arc.c | 12 ++++++------
 gdb/arch/arc.h | 12 ++++++------
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 6f544bff78d..60c76af3352 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1883,11 +1883,11 @@ mach_type_to_arc_isa (const unsigned long mach)
     }
 }
 
-/* Common construction code for ARC_GDBARCH_FEATURES struct.  If there
+/* Common construction code for ARC_ARCH_FEATURES struct.  If there
    is no ABFD, then a FEATURE with default values is returned.  */
 
-static arc_gdbarch_features
-arc_gdbarch_features_create (const bfd *abfd, const unsigned long mach)
+static arc_arch_features
+arc_arch_features_create (const bfd *abfd, const unsigned long mach)
 {
   /* Use 4 as a fallback value.  */
   int reg_size = 4;
@@ -1915,7 +1915,7 @@ arc_gdbarch_features_create (const bfd *abfd, const unsigned long mach)
      case).  */
   arc_isa isa = mach_type_to_arc_isa (mach);
 
-  return arc_gdbarch_features (reg_size, isa);
+  return arc_arch_features (reg_size, isa);
 }
 
 /* Look for obsolete core feature names in TDESC.  */
@@ -2085,9 +2085,9 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
   /* If target doesn't provide a description, use the default ones.  */
   if (!tdesc_has_registers (tdesc_loc))
     {
-      arc_gdbarch_features features
-	= arc_gdbarch_features_create (info.abfd,
-				       info.bfd_arch_info->mach);
+      arc_arch_features features
+	= arc_arch_features_create (info.abfd,
+				    info.bfd_arch_info->mach);
       tdesc_loc = arc_lookup_target_description (features);
     }
   gdb_assert (tdesc_loc != nullptr);
diff --git a/gdb/arch/arc.c b/gdb/arch/arc.c
index 8e126ca5a82..3808f9fe292 100644
--- a/gdb/arch/arc.c
+++ b/gdb/arch/arc.c
@@ -35,7 +35,7 @@
 #endif
 
 STATIC_IN_GDB target_desc *
-arc_create_target_description (const struct arc_gdbarch_features &features)
+arc_create_target_description (const struct arc_arch_features &features)
 {
   /* Create a new target description.  */
   target_desc *tdesc = allocate_target_description ();
@@ -84,10 +84,10 @@ arc_create_target_description (const struct arc_gdbarch_features &features)
 #ifndef GDBSERVER
 
 /* Wrapper used by std::unordered_map to generate hash for features set.  */
-struct arc_gdbarch_features_hasher
+struct arc_arch_features_hasher
 {
   std::size_t
-  operator() (const arc_gdbarch_features &features) const noexcept
+  operator() (const arc_arch_features &features) const noexcept
   {
     return features.hash ();
   }
@@ -95,14 +95,14 @@ struct arc_gdbarch_features_hasher
 
 /* Cache of previously created target descriptions, indexed by the hash
    of the features set used to create them.  */
-static std::unordered_map<arc_gdbarch_features,
+static std::unordered_map<arc_arch_features,
 			  const target_desc_up,
-			  arc_gdbarch_features_hasher> arc_tdesc_cache;
+			  arc_arch_features_hasher> arc_tdesc_cache;
 
 /* See arch/arc.h.  */
 
 const target_desc *
-arc_lookup_target_description (const struct arc_gdbarch_features &features)
+arc_lookup_target_description (const struct arc_arch_features &features)
 {
   /* Lookup in the cache first.  If found, return the pointer from the
      "target_desc_up" type which is a "unique_ptr".  This should be fine
diff --git a/gdb/arch/arc.h b/gdb/arch/arc.h
index a5313b1fee6..16257596748 100644
--- a/gdb/arch/arc.h
+++ b/gdb/arch/arc.h
@@ -27,9 +27,9 @@ enum arc_isa
   ARC_ISA_ARCV2	      /* such as ARC EM and ARC HS  */
 };
 
-struct arc_gdbarch_features
+struct arc_arch_features
 {
-  arc_gdbarch_features (int reg_size, arc_isa isa)
+  arc_arch_features (int reg_size, arc_isa isa)
     : reg_size (reg_size), isa (isa)
   {}
 
@@ -41,13 +41,13 @@ struct arc_gdbarch_features
   const arc_isa isa;
 
   /* Equality operator.  */
-  bool operator== (const struct arc_gdbarch_features &rhs) const
+  bool operator== (const struct arc_arch_features &rhs) const
   {
     return (reg_size == rhs.reg_size && isa == rhs.isa);
   }
 
   /* Inequality operator.  */
-  bool operator!= (const struct arc_gdbarch_features &rhs) const
+  bool operator!= (const struct arc_arch_features &rhs) const
   {
     return !(*this == rhs);
   }
@@ -71,7 +71,7 @@ struct arc_gdbarch_features
    the returned data.  */
 
 target_desc *arc_create_target_description
-	(const struct arc_gdbarch_features &features);
+	(const struct arc_arch_features &features);
 
 #else
 
@@ -79,7 +79,7 @@ target_desc *arc_create_target_description
    If nothing is found, then create one and return it.  */
 
 const target_desc *arc_lookup_target_description
-	(const struct arc_gdbarch_features &features);
+	(const struct arc_arch_features &features);
 
 #endif /* GDBSERVER */
 
-- 
2.28.0


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

* [PUSHED gdb-10-branch] gdbserver: Add GNU/Linux support for ARC
  2020-10-07 16:03 ` [PUSHED gdb-10-branch] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
@ 2020-10-07 16:03   ` Shahab Vahedi
  0 siblings, 0 replies; 17+ messages in thread
From: Shahab Vahedi @ 2020-10-07 16:03 UTC (permalink / raw)
  To: gdb-patches
  Cc: Shahab Vahedi, Shahab Vahedi, Simon Marchi, Baris Aktemur,
	Francois Bedard, Anton Kolesov

From: Anton Kolesov <Anton.Kolesov@synopsys.com>

This gdbserver implementation supports ARC ABI v3 and v4 (older ARC ABI
versions are not supported by other modern GNU tools or Linux itself).
Gdbserver supports inspection of ARC HS registers R30, R58 and R59 - feature
that has been added to Linux 4.12.  Whether gdbserver build will actually
support this feature depends on the version of Linux headers used to build
the server.

v2 [1]:
- Use "this->read_memory ()" instead of "the_target->read_memory ()".
- Remove the unnecessary "arch-arc.o:" target from the "Makefile.in".
- Got rid of "ntohs()" function and added lots of comments about
  endianness.
- Clarify why "pc" value is read from and saved to different fields
  in user regs struct.
- In function "is_reg_name_available_p()", use a range-based iterator
  to loop over the registers.
- Removed mentioning of issue number that was not related to sourceware.
- A few typo's fixed.

[1] Remarks
https://sourceware.org/pipermail/gdb-patches/2020-September/171911.html
https://sourceware.org/pipermail/gdb-patches/2020-September/171919.html

gdbserver/ChangeLog:

	* configure.srv: Support ARC architecture.
	* Makefile.in: Add linux-arc-low.cc and arch/arc.o.
	* linux-arc-low.cc: New file.
---
 gdbserver/Makefile.in      |   2 +
 gdbserver/configure.srv    |  11 +
 gdbserver/linux-arc-low.cc | 418 +++++++++++++++++++++++++++++++++++++
 3 files changed, 431 insertions(+)
 create mode 100644 gdbserver/linux-arc-low.cc

diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
index 9d7687be534..09a652a3354 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -179,6 +179,7 @@ SFILES = \
 	$(srcdir)/i387-fp.cc \
 	$(srcdir)/inferiors.cc \
 	$(srcdir)/linux-aarch64-low.cc \
+	$(srcdir)/linux-arc-low.cc \
 	$(srcdir)/linux-arm-low.cc \
 	$(srcdir)/linux-ia64-low.cc \
 	$(srcdir)/linux-low.cc \
@@ -206,6 +207,7 @@ SFILES = \
 	$(srcdir)/win32-low.cc \
 	$(srcdir)/x86-low.cc \
 	$(srcdir)/../gdb/alloc.c \
+	$(srcdir)/../gdb/arch/arc.c \
 	$(srcdir)/../gdb/arch/arm.c \
 	$(srcdir)/../gdb/arch/arm-get-next-pcs.c \
 	$(srcdir)/../gdb/arch/arm-linux.c \
diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
index 5e33bd9c54d..029ddabc4b8 100644
--- a/gdbserver/configure.srv
+++ b/gdbserver/configure.srv
@@ -61,6 +61,17 @@ case "${gdbserver_host}" in
 			ipa_obj="${ipa_obj} linux-aarch64-tdesc-ipa.o"
 			ipa_obj="${ipa_obj} arch/aarch64-ipa.o"
 			;;
+  arc*-*-linux*)
+			srv_regobj=""
+			srv_tgtobj="linux-arc-low.o arch/arc.o $srv_linux_obj"
+			srv_xmlfiles="arc/v1-core.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v1-aux.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v2-core.xml"
+			srv_xmlfiles="${srv_xmlfiles} arc/v2-aux.xml"
+			srv_linux_regsets=yes
+			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
+			;;
   arm*-*-linux*)	srv_tgtobj="$srv_linux_obj linux-arm-low.o"
 			srv_tgtobj="$srv_tgtobj linux-arm-tdesc.o"
 			srv_tgtobj="$srv_tgtobj linux-aarch32-low.o"
diff --git a/gdbserver/linux-arc-low.cc b/gdbserver/linux-arc-low.cc
new file mode 100644
index 00000000000..1f370ef7964
--- /dev/null
+++ b/gdbserver/linux-arc-low.cc
@@ -0,0 +1,418 @@
+/* Target dependent code for the remote server for GNU/Linux ARC.
+
+   Copyright 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 "server.h"
+#include "regdef.h"
+#include "linux-low.h"
+#include "tdesc.h"
+#include "arch/arc.h"
+
+#include <linux/elf.h>
+#include <arpa/inet.h>
+
+/* Linux starting with 4.12 supports NT_ARC_V2 note type, which adds R30,
+   R58 and R59 registers.  */
+#ifdef NT_ARC_V2
+#define ARC_HAS_V2_REGSET
+#endif
+
+/* The encoding of the instruction "TRAP_S 1" (endianness agnostic).  */
+#define TRAP_S_1_OPCODE	0x783e
+#define TRAP_S_1_SIZE	2
+
+/* Using a mere "uint16_t arc_linux_traps_s = TRAP_S_1_OPCODE" would
+   work as well, because the endianness will end up correctly when
+   the code is compiled for the same endianness as the target (see
+   the notes for "low_breakpoint_at" in this file).  However, this
+   illustrates how the __BIG_ENDIAN__ macro can be used to make
+   easy-to-understand codes.  */
+#if defined(__BIG_ENDIAN__)
+/* 0x78, 0x3e.  */
+static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE]
+	= {TRAP_S_1_OPCODE >> 8, TRAP_S_1_OPCODE & 0xFF};
+#else
+/* 0x3e, 0x78.  */
+static gdb_byte arc_linux_trap_s[TRAP_S_1_SIZE]
+	= {TRAP_S_1_OPCODE && 0xFF, TRAP_S_1_OPCODE >> 8};
+#endif
+
+/* Linux target op definitions for the ARC architecture.
+   Note for future: in case of adding the protected method low_get_next_pcs(),
+   the public method supports_software_single_step() should be added to return
+   "true".  */
+
+class arc_target : public linux_process_target
+{
+public:
+
+  const regs_info *get_regs_info () override;
+
+  const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
+
+protected:
+
+  void low_arch_setup () override;
+
+  bool low_cannot_fetch_register (int regno) override;
+
+  bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
+
+  bool low_breakpoint_at (CORE_ADDR where) override;
+};
+
+/* The singleton target ops object.  */
+
+static arc_target the_arc_target;
+
+bool
+arc_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+arc_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+arc_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
+static const struct target_desc *
+arc_linux_read_description (void)
+{
+#ifdef __ARC700__
+  arc_arch_features features (4, ARC_ISA_ARCV1);
+#else
+  arc_arch_features features (4, ARC_ISA_ARCV2);
+#endif
+  struct target_desc *tdesc = arc_create_target_description (features);
+
+  static const char *expedite_regs[] = { "sp", "status32", nullptr };
+  init_target_desc (tdesc, expedite_regs);
+
+  return tdesc;
+}
+
+void
+arc_target::low_arch_setup ()
+{
+  current_process ()->tdesc = arc_linux_read_description ();
+}
+
+bool
+arc_target::low_cannot_fetch_register (int regno)
+{
+  return (regno >= current_process ()->tdesc->reg_defs.size ());
+}
+
+bool
+arc_target::low_cannot_store_register (int regno)
+{
+  return (regno >= current_process ()->tdesc->reg_defs.size ());
+}
+
+/* This works for both endianness.  Below you see an illustration of how
+   the "trap_s 1" instruction encoded for both endianness in the memory
+   will end up as the TRAP_S_1_OPCODE constant:
+
+   BE: 0x78 0x3e --> at INSN addr: 0x78 0x3e --> INSN = 0x783e
+   LE: 0x3e 0x78 --> at INSN addr: 0x3e 0x78 --> INSN = 0x783e
+
+   One can employ "memcmp()" for comparing the arrays too.  */
+
+bool
+arc_target::low_breakpoint_at (CORE_ADDR where)
+{
+  uint16_t insn;
+
+  /* "the_target" global variable is the current object at hand.  */
+  this->read_memory (where, (gdb_byte *) &insn, TRAP_S_1_SIZE);
+  return (insn == TRAP_S_1_OPCODE);
+}
+
+/* PTRACE_GETREGSET/NT_PRSTATUS and PTRACE_SETREGSET/NT_PRSTATUS work with
+   regsets in a struct, "user_regs_struct", defined in the
+   linux/arch/arc/include/uapi/asm/ptrace.h header.  This code supports
+   ARC Linux ABI v3 and v4.  */
+
+/* Populate a ptrace NT_PRSTATUS regset from a regcache.
+
+   This appears to be a unique approach to populating the buffer, but
+   being name, rather than offset based, it is robust to future API
+   changes, as there is no need to create a regmap of registers in the
+   user_regs_struct.  */
+
+static void
+arc_fill_gregset (struct regcache *regcache, void *buf)
+{
+  struct user_regs_struct *regbuf = (struct user_regs_struct *) buf;
+
+  /* Core registers.  */
+  collect_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
+  collect_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
+  collect_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
+  collect_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
+  collect_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
+  collect_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
+  collect_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
+  collect_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
+  collect_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
+  collect_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
+  collect_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
+  collect_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
+  collect_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
+  collect_register_by_name (regcache, "r13", &(regbuf->callee.r13));
+  collect_register_by_name (regcache, "r14", &(regbuf->callee.r14));
+  collect_register_by_name (regcache, "r15", &(regbuf->callee.r15));
+  collect_register_by_name (regcache, "r16", &(regbuf->callee.r16));
+  collect_register_by_name (regcache, "r17", &(regbuf->callee.r17));
+  collect_register_by_name (regcache, "r18", &(regbuf->callee.r18));
+  collect_register_by_name (regcache, "r19", &(regbuf->callee.r19));
+  collect_register_by_name (regcache, "r20", &(regbuf->callee.r20));
+  collect_register_by_name (regcache, "r21", &(regbuf->callee.r21));
+  collect_register_by_name (regcache, "r22", &(regbuf->callee.r22));
+  collect_register_by_name (regcache, "r23", &(regbuf->callee.r23));
+  collect_register_by_name (regcache, "r24", &(regbuf->callee.r24));
+  collect_register_by_name (regcache, "r25", &(regbuf->callee.r25));
+  collect_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
+  collect_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
+  collect_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
+  collect_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
+
+  /* Loop registers.  */
+  collect_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
+  collect_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
+  collect_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
+
+  /* The current "pc" value must be written to "eret" (exception return
+     address) register, because that is the address that the kernel code
+     will jump back to after a breakpoint exception has been raised.
+     The "pc_stop" value is ignored by the genregs_set() in
+     linux/arch/arc/kernel/ptrace.c.  */
+  collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));
+
+  /* Currently ARC Linux ptrace doesn't allow writes to status32 because
+     some of its bits are kernel mode-only and shoudn't be writable from
+     user-space.  Writing status32 from debugger could be useful, though,
+     so ability to write non-priviliged bits will be added to kernel
+     sooner or later.  */
+
+  /* BTA.  */
+  collect_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
+}
+
+/* Populate a regcache from a ptrace NT_PRSTATUS regset.  */
+
+static void
+arc_store_gregset (struct regcache *regcache, const void *buf)
+{
+  const struct user_regs_struct *regbuf = (const struct user_regs_struct *) buf;
+
+  /* Core registers.  */
+  supply_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
+  supply_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
+  supply_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
+  supply_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
+  supply_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
+  supply_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
+  supply_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
+  supply_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
+  supply_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
+  supply_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
+  supply_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
+  supply_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
+  supply_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
+  supply_register_by_name (regcache, "r13", &(regbuf->callee.r13));
+  supply_register_by_name (regcache, "r14", &(regbuf->callee.r14));
+  supply_register_by_name (regcache, "r15", &(regbuf->callee.r15));
+  supply_register_by_name (regcache, "r16", &(regbuf->callee.r16));
+  supply_register_by_name (regcache, "r17", &(regbuf->callee.r17));
+  supply_register_by_name (regcache, "r18", &(regbuf->callee.r18));
+  supply_register_by_name (regcache, "r19", &(regbuf->callee.r19));
+  supply_register_by_name (regcache, "r20", &(regbuf->callee.r20));
+  supply_register_by_name (regcache, "r21", &(regbuf->callee.r21));
+  supply_register_by_name (regcache, "r22", &(regbuf->callee.r22));
+  supply_register_by_name (regcache, "r23", &(regbuf->callee.r23));
+  supply_register_by_name (regcache, "r24", &(regbuf->callee.r24));
+  supply_register_by_name (regcache, "r25", &(regbuf->callee.r25));
+  supply_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
+  supply_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
+  supply_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
+  supply_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
+
+  /* Loop registers.  */
+  supply_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
+  supply_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
+  supply_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
+
+  /* The genregs_get() in linux/arch/arc/kernel/ptrace.c populates the
+     pseudo register "stop_pc" with the "efa" (exception fault address)
+     register.  This was deemed necessary, because the breakpoint
+     instruction, "trap_s 1", is a committing one; i.e. the "eret"
+     (exception return address) register will be pointing to the next
+     instruction, while "efa" points to the address that raised the
+     breakpoint.  */
+  supply_register_by_name (regcache, "pc", &(regbuf->stop_pc));
+  unsigned long pcl = regbuf->stop_pc & ~3L;
+  supply_register_by_name (regcache, "pcl", &pcl);
+
+  /* Other auxilliary registers.  */
+  supply_register_by_name (regcache, "status32", &(regbuf->scratch.status32));
+
+  /* BTA.  */
+  supply_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
+}
+
+#ifdef ARC_HAS_V2_REGSET
+
+/* Look through a regcache's TDESC for a register named NAME.
+   If found, return true; false, otherwise.  */
+
+static bool
+is_reg_name_available_p (const struct target_desc *tdesc,
+			 const char *name)
+{
+  for (const gdb::reg &reg : tdesc->reg_defs)
+    if (strcmp (name, reg.name) == 0)
+      return true;
+  return false;
+}
+
+/* Copy registers from regcache to user_regs_arcv2.  */
+
+static void
+arc_fill_v2_regset (struct regcache *regcache, void *buf)
+{
+  struct user_regs_arcv2 *regbuf = (struct user_regs_arcv2 *) buf;
+
+  if (is_reg_name_available_p (regcache->tdesc, "r30"))
+    collect_register_by_name (regcache, "r30", &(regbuf->r30));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r58"))
+    collect_register_by_name (regcache, "r58", &(regbuf->r58));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r59"))
+    collect_register_by_name (regcache, "r59", &(regbuf->r59));
+}
+
+/* Copy registers from user_regs_arcv2 to regcache.  */
+
+static void
+arc_store_v2_regset (struct regcache *regcache, const void *buf)
+{
+  struct user_regs_arcv2 *regbuf = (struct user_regs_arcv2 *) buf;
+
+  if (is_reg_name_available_p (regcache->tdesc, "r30"))
+    supply_register_by_name (regcache, "r30", &(regbuf->r30));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r58"))
+    supply_register_by_name (regcache, "r58", &(regbuf->r58));
+
+  if (is_reg_name_available_p (regcache->tdesc, "r59"))
+    supply_register_by_name (regcache, "r59", &(regbuf->r59));
+}
+
+#endif
+
+/* Fetch the thread-local storage pointer for libthread_db.  Note that
+   this function is not called from GDB, but is called from libthread_db.
+
+   This is the same function as for other architectures, for example in
+   linux-arm-low.c.  */
+
+ps_err_e
+ps_get_thread_area (struct ps_prochandle *ph, lwpid_t lwpid,
+		    int idx, void **base)
+{
+  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, nullptr, base) != 0)
+    return PS_ERR;
+
+  /* IDX is the bias from the thread pointer to the beginning of the
+     thread descriptor.  It has to be subtracted due to implementation
+     quirks in libthread_db.  */
+  *base = (void *) ((char *) *base - idx);
+
+  return PS_OK;
+}
+
+static struct regset_info arc_regsets[] =
+{
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
+    sizeof (struct user_regs_struct), GENERAL_REGS,
+    arc_fill_gregset, arc_store_gregset
+  },
+#ifdef ARC_HAS_V2_REGSET
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARC_V2,
+    sizeof (struct user_regs_arcv2), GENERAL_REGS,
+    arc_fill_v2_regset, arc_store_v2_regset
+  },
+#endif
+  NULL_REGSET
+};
+
+static struct regsets_info arc_regsets_info =
+{
+  arc_regsets,	/* regsets */
+  0,		/* num_regsets */
+  nullptr,	/* disabled regsets */
+};
+
+static struct regs_info arc_regs_info =
+{
+  nullptr,	/* regset_bitmap */
+  nullptr,	/* usrregs */
+  &arc_regsets_info
+};
+
+const regs_info *
+arc_target::get_regs_info ()
+{
+  return &arc_regs_info;
+}
+
+/* One of the methods necessary for Z0 packet support.  */
+
+const gdb_byte *
+arc_target::sw_breakpoint_from_kind (int kind, int *size)
+{
+  gdb_assert (kind == TRAP_S_1_SIZE);
+  *size = kind;
+  return arc_linux_trap_s;
+}
+
+/* The linux target ops object.  */
+
+linux_process_target *the_linux_target = &the_arc_target;
+
+void
+initialize_low_arch (void)
+{
+  initialize_regsets_info (&arc_regsets_info);
+}
-- 
2.28.0


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

end of thread, other threads:[~2020-10-07 16:03 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-26 16:56 [PATCH] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
2020-09-07  9:12 ` Shahab Vahedi
2020-09-16  2:29 ` [PING^2][PATCH] " Shahab Vahedi
2020-09-16 19:59 ` [PATCH] " Simon Marchi
2020-10-06 16:21   ` Shahab Vahedi
2020-10-06 16:42 ` [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
2020-10-06 16:42   ` [PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
2020-10-07  2:28     ` Simon Marchi
2020-10-07  2:30       ` Simon Marchi
2020-10-07  7:33         ` Shahab Vahedi
2020-10-07 11:17           ` Simon Marchi
2020-10-07  7:20       ` Shahab Vahedi
2020-10-07  1:27   ` [PATCH v2 1/2] arc: Rename "arc_gdbarch_features" struct Simon Marchi
2020-10-07 15:58 ` [PUSHED master] " Shahab Vahedi
2020-10-07 15:58   ` [PUSHED master] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi
2020-10-07 16:03 ` [PUSHED gdb-10-branch] arc: Rename "arc_gdbarch_features" struct Shahab Vahedi
2020-10-07 16:03   ` [PUSHED gdb-10-branch] gdbserver: Add GNU/Linux support for ARC Shahab Vahedi

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).