public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Ravenscar simplification + FPU feature
@ 2022-05-31 12:57 Tom Tromey
  2022-05-31 12:57 ` [PATCH 1/3] Fix bugs in aarch64-ravenscar-thread.c Tom Tromey
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Tom Tromey @ 2022-05-31 12:57 UTC (permalink / raw)
  To: gdb-patches

This series simplifies the Ravenscar layer in gdb, making it more
table-based and not code-based.  It also fixes a bug, and adds support
for a missing feature -- some Ravenscar targets manage the FPU state
on demand, and so the runtime has to be queried to decide where to
find FP registers.

Tested using the internal AdaCore test suite.  I've never gotten cross
testing working using qemu with the gdb test suite, and would
Ravenscar need extra setup on top of that.

Tom



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

* [PATCH 1/3] Fix bugs in aarch64-ravenscar-thread.c
  2022-05-31 12:57 [PATCH 0/3] Ravenscar simplification + FPU feature Tom Tromey
@ 2022-05-31 12:57 ` Tom Tromey
  2022-05-31 12:57 ` [PATCH 2/3] Reimplement ravenscar registers using tables Tom Tromey
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Tom Tromey @ 2022-05-31 12:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

We found a few bugs in aarch64-ravenscar-thread.c.

First, some of the register offsets were incorrect.  The "bb-runtimes"
file for this runtime had the wrong offsets in comments, which GDB
took to be correct.  However, those comments didn't account for
alignment.  This patch adjusts the offsets.

Next, the "FPU Saved field" is not a register -- it is an
implementation detail of the runtime.  This is removed.

Finally, I think the FP registers are actually named V0-V31, and the
"Q" names are pseudo-registers.  This patch fixes the comment.
---
 gdb/aarch64-ravenscar-thread.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/gdb/aarch64-ravenscar-thread.c b/gdb/aarch64-ravenscar-thread.c
index a60471d7275..dc35537e3d5 100644
--- a/gdb/aarch64-ravenscar-thread.c
+++ b/gdb/aarch64-ravenscar-thread.c
@@ -47,21 +47,18 @@ static const int aarch64_context_offsets[] =
   80,        88,        96,        88,
   NO_OFFSET,
 
-  /* Q0 - Q31 */
-  112,       128,       144,       160,
-  176,       192,       208,       224,
-  240,       256,       272,       288,
-  304,       320,       336,       352,
-  368,       384,       400,       416,
-  432,       448,       464,       480,
-  496,       512,       528,       544,
-  560,       576,       592,       608,
+  /* V0 - V31 */
+  128,       144,       160,       176,
+  192,       208,       224,       240,
+  256,       272,       288,       304,
+  320,       336,       352,       368,
+  384,       400,       416,       432,
+  448,       464,       480,       496,
+  512,       528,       544,       560,
+  576,       592,       608,       624,
 
   /* FPSR, FPCR */
-  104,       108,
-
-  /* FPU Saved field */
-  624
+  112,       116,
 };
 
 /* The register layout info.  */
-- 
2.34.1


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

* [PATCH 2/3] Reimplement ravenscar registers using tables
  2022-05-31 12:57 [PATCH 0/3] Ravenscar simplification + FPU feature Tom Tromey
  2022-05-31 12:57 ` [PATCH 1/3] Fix bugs in aarch64-ravenscar-thread.c Tom Tromey
@ 2022-05-31 12:57 ` Tom Tromey
  2022-05-31 12:57 ` [PATCH 3/3] Implement lazy FPU initialization for ravenscar Tom Tromey
  2022-06-14 15:08 ` [PATCH 0/3] Ravenscar simplification + FPU feature Tom Tromey
  3 siblings, 0 replies; 5+ messages in thread
From: Tom Tromey @ 2022-05-31 12:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

Currently, the ravenscar-thread implementation for each architecture
is written by hand.  However, these are actually written by
copy-paste.  It seems better to switch to a table-driven approach.

The previous code also fetched all registers whenever any register was
requested.  This is corrected in the new implementation.
---
 gdb/aarch64-ravenscar-thread.c | 121 +-------------------------
 gdb/amd64-ravenscar-thread.c   | 112 ++++--------------------
 gdb/ppc-ravenscar-thread.c     | 154 +--------------------------------
 gdb/ravenscar-thread.c         | 113 +++++++++++++++++++++++-
 gdb/ravenscar-thread.h         |  42 ++++++++-
 gdb/riscv-ravenscar-thread.c   | 120 ++++++-------------------
 gdb/sparc-ravenscar-thread.c   | 124 +-------------------------
 7 files changed, 206 insertions(+), 580 deletions(-)

diff --git a/gdb/aarch64-ravenscar-thread.c b/gdb/aarch64-ravenscar-thread.c
index dc35537e3d5..045d022fc23 100644
--- a/gdb/aarch64-ravenscar-thread.c
+++ b/gdb/aarch64-ravenscar-thread.c
@@ -61,127 +61,10 @@ static const int aarch64_context_offsets[] =
   112,       116,
 };
 
-/* The register layout info.  */
-
-struct ravenscar_reg_info
-{
-  /* A table providing the offset relative to the context structure
-     where each register is saved.  */
-  const int *context_offsets;
-
-  /* The number of elements in the context_offsets table above.  */
-  int context_offsets_size;
-};
-
-/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the
-   regcache.  */
-
-static void
-supply_register_at_address (struct regcache *regcache, int regnum,
-			    CORE_ADDR register_addr)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte *buf;
-
-  buf = (gdb_byte *) alloca (buf_size);
-  read_memory (register_addr, buf, buf_size);
-  regcache->raw_supply (regnum, buf);
-}
-
-/* Return true if, for a non-running thread, REGNUM has been saved on the
-   Thread_Descriptor.  */
-
-static int
-register_in_thread_descriptor_p (const struct ravenscar_reg_info *reg_info,
-				 int regnum)
-{
-  /* Check FPU registers */
-  return (regnum < reg_info->context_offsets_size
-	  && reg_info->context_offsets[regnum] != NO_OFFSET);
-}
-
-/* to_fetch_registers when inferior_ptid is different from the running
-   thread.  */
-
-static void
-aarch64_ravenscar_generic_fetch_registers
-  (const struct ravenscar_reg_info *reg_info,
-   struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  const int num_regs = gdbarch_num_regs (gdbarch);
-  int current_regnum;
-  CORE_ADDR current_address;
-  CORE_ADDR thread_descriptor_address;
-
-  /* The tid is the thread_id field, which is a pointer to the thread.  */
-  thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
-
-  /* Read registers.  */
-  for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
-    {
-      if (register_in_thread_descriptor_p (reg_info, current_regnum))
-	{
-	  current_address = thread_descriptor_address
-	    + reg_info->context_offsets[current_regnum];
-	  supply_register_at_address (regcache, current_regnum,
-				      current_address);
-	}
-    }
-}
-
-/* to_store_registers when inferior_ptid is different from the running
-   thread.  */
-
-static void
-aarch64_ravenscar_generic_store_registers
-  (const struct ravenscar_reg_info *reg_info,
-   struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte buf[buf_size];
-  ULONGEST register_address;
-
-  if (register_in_thread_descriptor_p (reg_info, regnum))
-    register_address
-      = inferior_ptid.tid () + reg_info->context_offsets [regnum];
-  else
-    return;
-
-  regcache->raw_collect (regnum, buf);
-  write_memory (register_address,
-		buf,
-		buf_size);
-}
-
-/* The ravenscar_reg_info for most Aarch64 targets.  */
-
-static const struct ravenscar_reg_info aarch64_reg_info =
-{
-  aarch64_context_offsets,
-  ARRAY_SIZE (aarch64_context_offsets),
-};
-
-struct aarch64_ravenscar_ops : public ravenscar_arch_ops
-{
-  void fetch_registers (struct regcache *regcache, int regnum) override
-  {
-    aarch64_ravenscar_generic_fetch_registers
-      (&aarch64_reg_info, regcache, regnum);
-  }
-
-  void store_registers (struct regcache *regcache, int regnum) override
-  {
-    aarch64_ravenscar_generic_store_registers
-      (&aarch64_reg_info, regcache, regnum);
-  }
-};
-
 /* The ravenscar_arch_ops vector for most Aarch64 targets.  */
 
-static struct aarch64_ravenscar_ops aarch64_ravenscar_ops;
+static struct ravenscar_arch_ops aarch64_ravenscar_ops
+     (aarch64_context_offsets);
 
 /* Register aarch64_ravenscar_ops in GDBARCH.  */
 
diff --git a/gdb/amd64-ravenscar-thread.c b/gdb/amd64-ravenscar-thread.c
index d06cdf8b7a2..18c000dc988 100644
--- a/gdb/amd64-ravenscar-thread.c
+++ b/gdb/amd64-ravenscar-thread.c
@@ -26,17 +26,6 @@
 #include "ravenscar-thread.h"
 #include "amd64-ravenscar-thread.h"
 
-struct amd64_ravenscar_ops : public ravenscar_arch_ops
-{
-  void fetch_registers (struct regcache *regcache, int regnum) override;
-  void store_registers (struct regcache *regcache, int regnum) override;
-
-private:
-
-  /* Return the offset of the register in the context buffer.  */
-  int register_offset (struct gdbarch *arch, int regnum);
-};
-
 /* x86-64 Ravenscar stores registers as:
 
    type Context_Buffer is record
@@ -54,92 +43,29 @@ struct amd64_ravenscar_ops : public ravenscar_arch_ops
 */
 static const int register_layout[] =
 {
-  AMD64_RIP_REGNUM,
-  AMD64_EFLAGS_REGNUM,
-  AMD64_RSP_REGNUM,
-  AMD64_RBX_REGNUM,
-  AMD64_RBP_REGNUM,
-  AMD64_R12_REGNUM,
-  AMD64_R13_REGNUM,
-  AMD64_R14_REGNUM,
-  AMD64_R15_REGNUM,
+  /* RAX */ -1,
+  /* RBX */ 3 * 8,
+  /* RCX */ -1,
+  /* RDX */ -1,
+  /* RSI */ -1,
+  /* RDI */ -1,
+  /* RBP */ 4 * 8,
+  /* RSP */ 2 * 8,
+  /* R8 */ -1,
+  /* R9 */ -1,
+  /* R10 */ -1,
+  /* R11 */ -1,
+  /* R12 */ 5 * 8,
+  /* R13 */ 6 * 8,
+  /* R14 */ 7 * 8,
+  /* R15 */ 8 * 8,
+  /* RIP */ 0 * 8,
+  /* EFLAGS */ 1 * 8,
 };
 
-int
-amd64_ravenscar_ops::register_offset (struct gdbarch *arch, int regnum)
-{
-  for (int i = 0; i < ARRAY_SIZE (register_layout); ++i)
-    if (register_layout[i] == regnum)
-      return i * 8;
-  /* Not saved.  */
-  return -1;
-}
-
-/* Supply register REGNUM, which has been saved at REGISTER_ADDR, to
-   the regcache.  */
-
-static void
-supply_register_at_address (struct regcache *regcache, int regnum,
-                            CORE_ADDR register_addr)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte *buf;
-
-  buf = (gdb_byte *) alloca (buf_size);
-  read_memory (register_addr, buf, buf_size);
-  regcache->raw_supply (regnum, buf);
-}
-
-void
-amd64_ravenscar_ops::fetch_registers (struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  const int num_regs = gdbarch_num_regs (gdbarch);
-  int current_regnum;
-  CORE_ADDR current_address;
-  CORE_ADDR thread_descriptor_address;
-
-  /* The tid is the thread_id field, which is a pointer to the thread.  */
-  thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
-
-  /* Read registers.  */
-  for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
-    {
-      int offset = register_offset (gdbarch, current_regnum);
-
-      if (offset != -1)
-        {
-          current_address = thread_descriptor_address + offset;
-          supply_register_at_address (regcache, current_regnum,
-                                      current_address);
-        }
-    }
-}
-
-void
-amd64_ravenscar_ops::store_registers (struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte buf[buf_size];
-  CORE_ADDR register_address;
-
-  int offset = register_offset (gdbarch, regnum);
-  if (offset != -1)
-    {
-      register_address = inferior_ptid.tid () + offset;
-
-      regcache->raw_collect (regnum, buf);
-      write_memory (register_address,
-		    buf,
-		    buf_size);
-    }
-}
-
 /* The ravenscar_arch_ops vector for AMD64 targets.  */
 
-static struct amd64_ravenscar_ops amd64_ravenscar_ops;
+static struct ravenscar_arch_ops amd64_ravenscar_ops (register_layout);
 
 /* Register amd64_ravenscar_ops in GDBARCH.  */
 
diff --git a/gdb/ppc-ravenscar-thread.c b/gdb/ppc-ravenscar-thread.c
index 42d7334b93f..0691a6317d5 100644
--- a/gdb/ppc-ravenscar-thread.c
+++ b/gdb/ppc-ravenscar-thread.c
@@ -100,129 +100,10 @@ static const int e500_context_offsets[] =
   NO_OFFSET, 176
 };
 
-/* The register layout info.  */
-
-struct ravenscar_reg_info
-{
-  /* A table providing the offset relative to the context structure
-     where each register is saved.  */
-  const int *context_offsets;
-
-  /* The number of elements in the context_offsets table above.  */
-  int context_offsets_size;
-};
-
-/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the
-   regcache.  */
-
-static void
-supply_register_at_address (struct regcache *regcache, int regnum,
-			    CORE_ADDR register_addr)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte *buf;
-
-  buf = (gdb_byte *) alloca (buf_size);
-  read_memory (register_addr, buf, buf_size);
-  regcache->raw_supply (regnum, buf);
-}
-
-/* Return true if, for a non-running thread, REGNUM has been saved on the
-   Thread_Descriptor.  */
-
-static int
-register_in_thread_descriptor_p (const struct ravenscar_reg_info *reg_info,
-				 int regnum)
-{
-  return (regnum < reg_info->context_offsets_size
-	  && reg_info->context_offsets[regnum] != NO_OFFSET);
-}
-
-/* to_fetch_registers when inferior_ptid is different from the running
-   thread.  */
-
-static void
-ppc_ravenscar_generic_fetch_registers
-  (const struct ravenscar_reg_info *reg_info,
-   struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  const int num_regs = gdbarch_num_regs (gdbarch);
-  int current_regnum;
-  CORE_ADDR current_address;
-  CORE_ADDR thread_descriptor_address;
-
-  /* The tid is the thread_id field, which is a pointer to the thread.  */
-  thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
-
-  /* Read registers.  */
-  for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
-    {
-      if (register_in_thread_descriptor_p (reg_info, current_regnum))
-	{
-	  current_address = thread_descriptor_address
-	    + reg_info->context_offsets[current_regnum];
-	  supply_register_at_address (regcache, current_regnum,
-				      current_address);
-	}
-    }
-}
-
-/* to_store_registers when inferior_ptid is different from the running
-   thread.  */
-
-static void
-ppc_ravenscar_generic_store_registers
-  (const struct ravenscar_reg_info *reg_info,
-   struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte buf[buf_size];
-  ULONGEST register_address;
-
-  if (register_in_thread_descriptor_p (reg_info, regnum))
-    register_address
-      = inferior_ptid.tid () + reg_info->context_offsets [regnum];
-  else
-    return;
-
-  regcache->raw_collect (regnum, buf);
-  write_memory (register_address,
-		buf,
-		buf_size);
-}
-
-/* The ravenscar_reg_info for most PowerPC targets.  */
-
-static const struct ravenscar_reg_info ppc_reg_info =
-{
-  powerpc_context_offsets,
-  ARRAY_SIZE (powerpc_context_offsets),
-};
-
-struct ppc_ravenscar_powerpc_ops : public ravenscar_arch_ops
-{
-  void fetch_registers (struct regcache *, int) override;
-  void store_registers (struct regcache *, int) override;
-};
-
-void
-ppc_ravenscar_powerpc_ops::fetch_registers (struct regcache *regcache, int regnum)
-{
-  ppc_ravenscar_generic_fetch_registers (&ppc_reg_info, regcache, regnum);
-}
-
-void
-ppc_ravenscar_powerpc_ops::store_registers (struct regcache *regcache, int regnum)
-{
-  ppc_ravenscar_generic_store_registers (&ppc_reg_info, regcache, regnum);
-}
-
 /* The ravenscar_arch_ops vector for most PowerPC targets.  */
 
-static struct ppc_ravenscar_powerpc_ops ppc_ravenscar_powerpc_ops;
+static struct ravenscar_arch_ops ppc_ravenscar_powerpc_ops
+     (powerpc_context_offsets);
 
 /* Register ppc_ravenscar_powerpc_ops in GDBARCH.  */
 
@@ -232,38 +113,9 @@ register_ppc_ravenscar_ops (struct gdbarch *gdbarch)
   set_gdbarch_ravenscar_ops (gdbarch, &ppc_ravenscar_powerpc_ops);
 }
 
-/* The ravenscar_reg_info for E500 targets.  */
-
-static const struct ravenscar_reg_info e500_reg_info =
-{
-  e500_context_offsets,
-  ARRAY_SIZE (e500_context_offsets),
-};
-
-struct ppc_ravenscar_e500_ops : public ravenscar_arch_ops
-{
-  void fetch_registers (struct regcache *, int) override;
-  void store_registers (struct regcache *, int) override;
-};
-
-void
-ppc_ravenscar_e500_ops::fetch_registers (struct regcache *regcache, int regnum)
-{
-  ppc_ravenscar_generic_fetch_registers (&e500_reg_info, regcache, regnum);
-}
-
-/* Implement the to_store_registers ravenscar_arch_ops method
-   for E500 targets.  */
-
-void
-ppc_ravenscar_e500_ops::store_registers (struct regcache *regcache, int regnum)
-{
-  ppc_ravenscar_generic_store_registers (&e500_reg_info, regcache, regnum);
-}
-
 /* The ravenscar_arch_ops vector for E500 targets.  */
 
-static struct ppc_ravenscar_e500_ops ppc_ravenscar_e500_ops;
+static struct ravenscar_arch_ops ppc_ravenscar_e500_ops (e500_context_offsets);
 
 /* Register ppc_ravenscar_e500_ops in GDBARCH.  */
 
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c
index aae6e397327..e300095b53f 100644
--- a/gdb/ravenscar-thread.c
+++ b/gdb/ravenscar-thread.c
@@ -477,6 +477,116 @@ ravenscar_thread_target::pid_to_str (ptid_t ptid)
 			phex_nz (ptid.tid (), sizeof (ULONGEST)));
 }
 
+CORE_ADDR
+ravenscar_arch_ops::get_stack_base (struct regcache *regcache) const
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const int sp_regnum = gdbarch_sp_regnum (gdbarch);
+  ULONGEST stack_address;
+  regcache_cooked_read_unsigned (regcache, sp_regnum, &stack_address);
+  return (CORE_ADDR) stack_address;
+}
+
+void
+ravenscar_arch_ops::supply_one_register (struct regcache *regcache,
+					 int regnum,
+					 CORE_ADDR descriptor,
+					 CORE_ADDR stack_base) const
+{
+  CORE_ADDR addr;
+  if (regnum >= first_stack_register && regnum <= last_stack_register)
+    addr = stack_base;
+  else
+    addr = descriptor;
+  addr += offsets[regnum];
+
+  struct gdbarch *gdbarch = regcache->arch ();
+  int size = register_size (gdbarch, regnum);
+  gdb_byte *buf = (gdb_byte *) alloca (size);
+  read_memory (addr, buf, size);
+  regcache->raw_supply (regnum, buf);
+}
+
+void
+ravenscar_arch_ops::fetch_registers (struct regcache *regcache,
+				     int regnum) const
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  /* The tid is the thread_id field, which is a pointer to the thread.  */
+  CORE_ADDR thread_descriptor_address
+    = (CORE_ADDR) regcache->ptid ().tid ();
+
+  int sp_regno = -1;
+  CORE_ADDR stack_address = 0;
+  if (regnum == -1
+      || (regnum >= first_stack_register && regnum <= last_stack_register))
+    {
+      /* We must supply SP for get_stack_base, so recurse.  */
+      sp_regno = gdbarch_sp_regnum (gdbarch);
+      gdb_assert (!(sp_regno >= first_stack_register
+		    && sp_regno <= last_stack_register));
+      fetch_registers (regcache, sp_regno);
+      stack_address = get_stack_base (regcache);
+    }
+
+  if (regnum == -1)
+    {
+      /* Fetch all registers.  */
+      for (int reg = 0; reg < offsets.size (); ++reg)
+	if (reg != sp_regno && offsets[reg] != -1)
+	  supply_one_register (regcache, reg, thread_descriptor_address,
+			       stack_address);
+    }
+  else if (regnum < offsets.size () && offsets[regnum] != -1)
+    supply_one_register (regcache, regnum, thread_descriptor_address,
+			 stack_address);
+}
+
+void
+ravenscar_arch_ops::store_one_register (struct regcache *regcache, int regnum,
+					CORE_ADDR descriptor,
+					CORE_ADDR stack_base) const
+{
+  CORE_ADDR addr;
+  if (regnum >= first_stack_register && regnum <= last_stack_register)
+    addr = stack_base;
+  else
+    addr = descriptor;
+  addr += offsets[regnum];
+
+  struct gdbarch *gdbarch = regcache->arch ();
+  int size = register_size (gdbarch, regnum);
+  gdb_byte *buf = (gdb_byte *) alloca (size);
+  regcache->raw_collect (regnum, buf);
+  write_memory (addr, buf, size);
+}
+
+void
+ravenscar_arch_ops::store_registers (struct regcache *regcache,
+				     int regnum) const
+{
+  /* The tid is the thread_id field, which is a pointer to the thread.  */
+  CORE_ADDR thread_descriptor_address
+    = (CORE_ADDR) regcache->ptid ().tid ();
+
+  CORE_ADDR stack_address = 0;
+  if (regnum == -1
+      || (regnum >= first_stack_register && regnum <= last_stack_register))
+    stack_address = get_stack_base (regcache);
+
+  if (regnum == -1)
+    {
+      /* Store all registers.  */
+      for (int reg = 0; reg < offsets.size (); ++reg)
+	if (offsets[reg] != -1)
+	  store_one_register (regcache, reg, thread_descriptor_address,
+			      stack_address);
+    }
+  else if (regnum < offsets.size () && offsets[regnum] != -1)
+    store_one_register (regcache, regnum, thread_descriptor_address,
+			stack_address);
+}
+
 /* Temporarily set the ptid of a regcache to some other value.  When
    this object is destroyed, the regcache's original ptid is
    restored.  */
@@ -506,7 +616,8 @@ class temporarily_change_regcache_ptid
 };
 
 void
-ravenscar_thread_target::fetch_registers (struct regcache *regcache, int regnum)
+ravenscar_thread_target::fetch_registers (struct regcache *regcache,
+					  int regnum)
 {
   ptid_t ptid = regcache->ptid ();
 
diff --git a/gdb/ravenscar-thread.h b/gdb/ravenscar-thread.h
index df750667ab9..5d5661f48df 100644
--- a/gdb/ravenscar-thread.h
+++ b/gdb/ravenscar-thread.h
@@ -24,12 +24,48 @@
 
 struct ravenscar_arch_ops
 {
-  virtual ~ravenscar_arch_ops ()
+  ravenscar_arch_ops (gdb::array_view<const int> offsets_,
+		      int first_stack = -1,
+		      int last_stack = -1)
+    : offsets (offsets_),
+      first_stack_register (first_stack),
+      last_stack_register (last_stack)
   {
+    /* These must either both be -1 or both be valid.  */
+    gdb_assert ((first_stack_register == -1) == (last_stack_register == -1));
+    /* They must also be ordered.  */
+    gdb_assert (last_stack_register >= first_stack_register);
   }
 
-  virtual void fetch_registers (struct regcache *, int) = 0;
-  virtual void store_registers (struct regcache *, int) = 0;
+  void fetch_registers (struct regcache *, int) const;
+  void store_registers (struct regcache *, int) const;
+
+private:
+
+  /* An array where the indices are register numbers and the contents
+     are offsets.  The offsets are either in the thread descriptor or
+     the stack, depending on the other fields.  An offset of -1 means
+     that the corresponding register is not stored.  */
+  const gdb::array_view<const int> offsets;
+
+  /* If these are -1, then all registers for this architecture are
+     stored in the thread descriptor.  Otherwise, these mark a range
+     of registers that are stored on the stack.  */
+  const int first_stack_register;
+  const int last_stack_register;
+
+  /* Helper function to supply one register.  */
+  void supply_one_register (struct regcache *regcache, int regnum,
+			    CORE_ADDR descriptor,
+			    CORE_ADDR stack_base) const;
+  /* Helper function to store one register.  */
+  void store_one_register (struct regcache *regcache, int regnum,
+			   CORE_ADDR descriptor,
+			   CORE_ADDR stack_base) const;
+  /* Helper function to find stack address where registers are stored.
+     This must be called with the stack pointer already supplied in
+     the register cache.  */
+  CORE_ADDR get_stack_base (struct regcache *) const;
 };
 
 #endif /* !defined (RAVENSCAR_THREAD_H) */
diff --git a/gdb/riscv-ravenscar-thread.c b/gdb/riscv-ravenscar-thread.c
index b2a7b6e0096..e28e17878c3 100644
--- a/gdb/riscv-ravenscar-thread.c
+++ b/gdb/riscv-ravenscar-thread.c
@@ -26,115 +26,51 @@
 #include "ravenscar-thread.h"
 #include "riscv-ravenscar-thread.h"
 
+#define LAST_REGISTER (RISCV_FIRST_FP_REGNUM + 14)
+
 struct riscv_ravenscar_ops : public ravenscar_arch_ops
 {
-  void fetch_registers (struct regcache *regcache, int regnum) override;
-  void store_registers (struct regcache *regcache, int regnum) override;
-
-private:
+  int reg_offsets[LAST_REGISTER + 1];
 
-  /* Return the offset of the register in the context buffer.  */
-  int register_offset (struct gdbarch *arch, int regnum);
+  riscv_ravenscar_ops (struct gdbarch *arch);
 };
 
-int
-riscv_ravenscar_ops::register_offset (struct gdbarch *arch, int regnum)
-{
-  int offset;
-  if (regnum == RISCV_RA_REGNUM || regnum == RISCV_PC_REGNUM)
-    offset = 0;
-  else if (regnum == RISCV_SP_REGNUM)
-    offset = 1;
-  else if (regnum == RISCV_ZERO_REGNUM + 8) /* S0 */
-    offset = 2;
-  else if (regnum == RISCV_ZERO_REGNUM + 9) /* S1 */
-    offset = 3;
-  else if (regnum >= RISCV_ZERO_REGNUM + 19
-	   && regnum <= RISCV_ZERO_REGNUM + 27) /* S2..S11 */
-    offset = regnum - (RISCV_ZERO_REGNUM + 19) + 4;
-  else if (regnum >= RISCV_FIRST_FP_REGNUM
-	   && regnum <= RISCV_FIRST_FP_REGNUM + 11)
-    offset = regnum - RISCV_FIRST_FP_REGNUM + 14; /* FS0..FS11 */
-  else
-    {
-      /* Not saved.  */
-      return -1;
-    }
-
-  int size = register_size (arch, regnum);
-  return offset * size;
-}
-
-/* Supply register REGNUM, which has been saved on REGISTER_ADDR, to the
-   regcache.  */
-
-static void
-supply_register_at_address (struct regcache *regcache, int regnum,
-			    CORE_ADDR register_addr)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte *buf;
-
-  buf = (gdb_byte *) alloca (buf_size);
-  read_memory (register_addr, buf, buf_size);
-  regcache->raw_supply (regnum, buf);
-}
-
-void
-riscv_ravenscar_ops::fetch_registers (struct regcache *regcache, int regnum)
+riscv_ravenscar_ops::riscv_ravenscar_ops (struct gdbarch *arch)
+  : ravenscar_arch_ops (gdb::make_array_view (reg_offsets, LAST_REGISTER + 1))
 {
-  struct gdbarch *gdbarch = regcache->arch ();
-  const int num_regs = gdbarch_num_regs (gdbarch);
-  int current_regnum;
-  CORE_ADDR current_address;
-  CORE_ADDR thread_descriptor_address;
-
-  /* The tid is the thread_id field, which is a pointer to the thread.  */
-  thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
+  int reg_size = riscv_isa_xlen (arch);
 
-  /* Read registers.  */
-  for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
+  for (int regnum = 0; regnum <= LAST_REGISTER; ++regnum)
     {
-      int offset = register_offset (gdbarch, current_regnum);
+      int offset;
+      if (regnum == RISCV_RA_REGNUM || regnum == RISCV_PC_REGNUM)
+	offset = 0;
+      else if (regnum == RISCV_SP_REGNUM)
+	offset = 1;
+      else if (regnum == RISCV_ZERO_REGNUM + 8) /* S0 */
+	offset = 2;
+      else if (regnum == RISCV_ZERO_REGNUM + 9) /* S1 */
+	offset = 3;
+      else if (regnum >= RISCV_ZERO_REGNUM + 19
+	       && regnum <= RISCV_ZERO_REGNUM + 27) /* S2..S11 */
+	offset = regnum - (RISCV_ZERO_REGNUM + 19) + 4;
+      else if (regnum >= RISCV_FIRST_FP_REGNUM
+	       && regnum <= RISCV_FIRST_FP_REGNUM + 11)
+	offset = regnum - RISCV_FIRST_FP_REGNUM + 14; /* FS0..FS11 */
+      else
+	offset = -1;
 
       if (offset != -1)
-	{
-	  current_address = thread_descriptor_address + offset;
-	  supply_register_at_address (regcache, current_regnum,
-				      current_address);
-	}
-    }
-}
-
-void
-riscv_ravenscar_ops::store_registers (struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte buf[buf_size];
-  CORE_ADDR register_address;
-
-  int offset = register_offset (gdbarch, regnum);
-  if (offset != -1)
-    {
-      register_address = inferior_ptid.tid () + offset;
+	offset *= reg_size;
 
-      regcache->raw_collect (regnum, buf);
-      write_memory (register_address,
-		    buf,
-		    buf_size);
+      reg_offsets[regnum] = offset;
     }
 }
 
-/* The ravenscar_arch_ops vector for most RISC-V targets.  */
-
-static struct riscv_ravenscar_ops riscv_ravenscar_ops;
-
 /* Register riscv_ravenscar_ops in GDBARCH.  */
 
 void
 register_riscv_ravenscar_ops (struct gdbarch *gdbarch)
 {
-  set_gdbarch_ravenscar_ops (gdbarch, &riscv_ravenscar_ops);
+  set_gdbarch_ravenscar_ops (gdbarch, new riscv_ravenscar_ops (gdbarch));
 }
diff --git a/gdb/sparc-ravenscar-thread.c b/gdb/sparc-ravenscar-thread.c
index 014d8981d7b..b199afb99c0 100644
--- a/gdb/sparc-ravenscar-thread.c
+++ b/gdb/sparc-ravenscar-thread.c
@@ -26,12 +26,6 @@
 #include "sparc-ravenscar-thread.h"
 #include "gdbarch.h"
 
-struct sparc_ravenscar_ops : public ravenscar_arch_ops
-{
-  void fetch_registers (struct regcache *, int) override;
-  void store_registers (struct regcache *, int) override;
-};
-
 /* Register offsets from a referenced address (exempli gratia the
    Thread_Descriptor).  The referenced address depends on the register
    number.  The Thread_Descriptor layout and the stack layout are documented
@@ -56,121 +50,9 @@ static const int sparc_register_offsets[] =
   0x40, 0x20, 0x44, -1,   0x1C, -1,   0x4C, -1
 };
 
-/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the
-   regcache.  */
-
-static void
-supply_register_at_address (struct regcache *regcache, int regnum,
-			    CORE_ADDR register_addr)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte *buf;
-
-  buf = (gdb_byte *) alloca (buf_size);
-  read_memory (register_addr, buf, buf_size);
-  regcache->raw_supply (regnum, buf);
-}
-
-/* Return true if, for a non-running thread, REGNUM has been saved on the
-   stack.  */
-
-static int
-register_on_stack_p (int regnum)
-{
-  return (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
-    || (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM);
-}
-
-/* Return true if, for a non-running thread, REGNUM has been saved on the
-   Thread_Descriptor.  */
-
-static int
-register_in_thread_descriptor_p (int regnum)
-{
-  return (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
-    || (regnum == SPARC32_PSR_REGNUM)
-    || (regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
-    || (regnum == SPARC32_Y_REGNUM)
-    || (regnum == SPARC32_WIM_REGNUM)
-    || (regnum == SPARC32_FSR_REGNUM)
-    || (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F0_REGNUM + 31)
-    || (regnum == SPARC32_PC_REGNUM);
-}
-
-/* to_fetch_registers when inferior_ptid is different from the running
-   thread.  */
-
-void
-sparc_ravenscar_ops::fetch_registers (struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  const int sp_regnum = gdbarch_sp_regnum (gdbarch);
-  const int num_regs = gdbarch_num_regs (gdbarch);
-  int current_regnum;
-  CORE_ADDR current_address;
-  CORE_ADDR thread_descriptor_address;
-  ULONGEST stack_address;
-
-  /* The tid is the thread_id field, which is a pointer to the thread.  */
-  thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
-
-  /* Read the saved SP in the context buffer.  */
-  current_address = thread_descriptor_address
-    + sparc_register_offsets [sp_regnum];
-  supply_register_at_address (regcache, sp_regnum, current_address);
-  regcache_cooked_read_unsigned (regcache, sp_regnum, &stack_address);
-
-  /* Read registers.  */
-  for (current_regnum = 0; current_regnum < num_regs; current_regnum ++)
-    {
-      if (register_in_thread_descriptor_p (current_regnum))
-	{
-	  current_address = thread_descriptor_address
-	    + sparc_register_offsets [current_regnum];
-	  supply_register_at_address (regcache, current_regnum,
-				      current_address);
-	}
-      else if (register_on_stack_p (current_regnum))
-	{
-	  current_address = stack_address
-	    + sparc_register_offsets [current_regnum];
-	  supply_register_at_address (regcache, current_regnum,
-				      current_address);
-	}
-    }
-}
-
-/* to_store_registers when inferior_ptid is different from the running
-   thread.  */
-
-void
-sparc_ravenscar_ops::store_registers (struct regcache *regcache, int regnum)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  int buf_size = register_size (gdbarch, regnum);
-  gdb_byte buf[buf_size];
-  ULONGEST register_address;
-
-  if (register_in_thread_descriptor_p (regnum))
-    register_address =
-      inferior_ptid.tid () + sparc_register_offsets [regnum];
-  else if (register_on_stack_p (regnum))
-    {
-      regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM,
-				     &register_address);
-      register_address += sparc_register_offsets [regnum];
-    }
-  else
-    return;
-
-  regcache->raw_collect (regnum, buf);
-  write_memory (register_address,
-		buf,
-		buf_size);
-}
-
-static struct sparc_ravenscar_ops sparc_ravenscar_ops;
+static struct ravenscar_arch_ops sparc_ravenscar_ops (sparc_register_offsets,
+						      SPARC_L0_REGNUM,
+						      SPARC_I7_REGNUM);
 
 /* Register ravenscar_arch_ops in GDBARCH.  */
 
-- 
2.34.1


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

* [PATCH 3/3] Implement lazy FPU initialization for ravenscar
  2022-05-31 12:57 [PATCH 0/3] Ravenscar simplification + FPU feature Tom Tromey
  2022-05-31 12:57 ` [PATCH 1/3] Fix bugs in aarch64-ravenscar-thread.c Tom Tromey
  2022-05-31 12:57 ` [PATCH 2/3] Reimplement ravenscar registers using tables Tom Tromey
@ 2022-05-31 12:57 ` Tom Tromey
  2022-06-14 15:08 ` [PATCH 0/3] Ravenscar simplification + FPU feature Tom Tromey
  3 siblings, 0 replies; 5+ messages in thread
From: Tom Tromey @ 2022-05-31 12:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

Some ravenscar runtimes implement lazy FPU handling.  On these
runtimes, the FPU is only initialized when a task tries to use it.
Furthermore, the FP registers aren't automatically saved on a task
switch -- instead, the save is deferred until the new task tries to
use the FPU.  Furthermore, each task's context area has a flag
indicating whether the FPU has been initialized for this task.

This patch teaches GDB to understand this implementation.  When
fetching or storing registers, GDB now checks to see whether the live
FP registers should be used.  If not, the task's saved FP registers
will be used if the task has caused FPU initialization.

Currently only AArch64 uses this code.  bb-runtimes implements this
for ARM as well, but GDB doesn't yet have an arm-ravenscar-thread.c.
---
 gdb/aarch64-ravenscar-thread.c |   9 +-
 gdb/ravenscar-thread.c         | 194 ++++++++++++++++++++++++---------
 gdb/ravenscar-thread.h         |  70 +++++++++++-
 3 files changed, 217 insertions(+), 56 deletions(-)

diff --git a/gdb/aarch64-ravenscar-thread.c b/gdb/aarch64-ravenscar-thread.c
index 045d022fc23..eb7bda88d5d 100644
--- a/gdb/aarch64-ravenscar-thread.c
+++ b/gdb/aarch64-ravenscar-thread.c
@@ -61,10 +61,17 @@ static const int aarch64_context_offsets[] =
   112,       116,
 };
 
+#define V_INIT_OFFSET 640
+
 /* The ravenscar_arch_ops vector for most Aarch64 targets.  */
 
 static struct ravenscar_arch_ops aarch64_ravenscar_ops
-     (aarch64_context_offsets);
+     (aarch64_context_offsets,
+      -1, -1,
+      V_INIT_OFFSET,
+      /* The FPU context buffer starts with the FPSR register.  */
+      aarch64_context_offsets[AARCH64_FPSR_REGNUM],
+      AARCH64_V0_REGNUM, AARCH64_FPCR_REGNUM);
 
 /* Register aarch64_ravenscar_ops in GDBARCH.  */
 
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c
index e300095b53f..1718c367ff6 100644
--- a/gdb/ravenscar-thread.c
+++ b/gdb/ravenscar-thread.c
@@ -164,6 +164,32 @@ struct ravenscar_thread_target final : public target_ops
     switch_to_thread (find_thread_ptid (proc_target, underlying));
   }
 
+  /* Some targets use lazy FPU initialization.  On these, the FP
+     registers for a given task might be uninitialized, or stored in
+     the per-task context, or simply be the live registers on the CPU.
+     This enum is used to encode this information.  */
+  enum fpu_state
+  {
+    /* This target doesn't do anything special for FP registers -- if
+       any exist, they are treated just identical to non-FP
+       registers.  */
+    NOTHING_SPECIAL,
+    /* This target uses the lazy FP scheme, and the FP registers are
+       taken from the CPU.  This can happen for any task, because if a
+       task switch occurs, the registers aren't immediately written to
+       the per-task context -- this is deferred until the current task
+       causes an FPU trap.  */
+    LIVE_FP_REGISTERS,
+    /* This target uses the lazy FP scheme, and the FP registers are
+       not available.  Maybe this task never initialized the FPU, or
+       maybe GDB couldn't find the required symbol.  */
+    NO_FP_REGISTERS
+  };
+
+  /* Return the FPU state.  */
+  fpu_state get_fpu_state (struct regcache *regcache,
+			   const ravenscar_arch_ops *arch_ops);
+
   /* This maps a TID to the CPU on which it was running.  This is
      needed because sometimes the runtime will report an active task
      that hasn't yet been put on the list of tasks that is read by
@@ -508,9 +534,11 @@ ravenscar_arch_ops::supply_one_register (struct regcache *regcache,
 }
 
 void
-ravenscar_arch_ops::fetch_registers (struct regcache *regcache,
-				     int regnum) const
+ravenscar_arch_ops::fetch_register (struct regcache *regcache,
+				    int regnum) const
 {
+  gdb_assert (regnum != -1);
+
   struct gdbarch *gdbarch = regcache->arch ();
   /* The tid is the thread_id field, which is a pointer to the thread.  */
   CORE_ADDR thread_descriptor_address
@@ -518,26 +546,17 @@ ravenscar_arch_ops::fetch_registers (struct regcache *regcache,
 
   int sp_regno = -1;
   CORE_ADDR stack_address = 0;
-  if (regnum == -1
-      || (regnum >= first_stack_register && regnum <= last_stack_register))
+  if (regnum >= first_stack_register && regnum <= last_stack_register)
     {
       /* We must supply SP for get_stack_base, so recurse.  */
       sp_regno = gdbarch_sp_regnum (gdbarch);
       gdb_assert (!(sp_regno >= first_stack_register
 		    && sp_regno <= last_stack_register));
-      fetch_registers (regcache, sp_regno);
+      fetch_register (regcache, sp_regno);
       stack_address = get_stack_base (regcache);
     }
 
-  if (regnum == -1)
-    {
-      /* Fetch all registers.  */
-      for (int reg = 0; reg < offsets.size (); ++reg)
-	if (reg != sp_regno && offsets[reg] != -1)
-	  supply_one_register (regcache, reg, thread_descriptor_address,
-			       stack_address);
-    }
-  else if (regnum < offsets.size () && offsets[regnum] != -1)
+  if (regnum < offsets.size () && offsets[regnum] != -1)
     supply_one_register (regcache, regnum, thread_descriptor_address,
 			 stack_address);
 }
@@ -562,27 +581,20 @@ ravenscar_arch_ops::store_one_register (struct regcache *regcache, int regnum,
 }
 
 void
-ravenscar_arch_ops::store_registers (struct regcache *regcache,
-				     int regnum) const
+ravenscar_arch_ops::store_register (struct regcache *regcache,
+				    int regnum) const
 {
+  gdb_assert (regnum != -1);
+
   /* The tid is the thread_id field, which is a pointer to the thread.  */
   CORE_ADDR thread_descriptor_address
     = (CORE_ADDR) regcache->ptid ().tid ();
 
   CORE_ADDR stack_address = 0;
-  if (regnum == -1
-      || (regnum >= first_stack_register && regnum <= last_stack_register))
+  if (regnum >= first_stack_register && regnum <= last_stack_register)
     stack_address = get_stack_base (regcache);
 
-  if (regnum == -1)
-    {
-      /* Store all registers.  */
-      for (int reg = 0; reg < offsets.size (); ++reg)
-	if (offsets[reg] != -1)
-	  store_one_register (regcache, reg, thread_descriptor_address,
-			      stack_address);
-    }
-  else if (regnum < offsets.size () && offsets[regnum] != -1)
+  if (regnum < offsets.size () && offsets[regnum] != -1)
     store_one_register (regcache, regnum, thread_descriptor_address,
 			stack_address);
 }
@@ -615,6 +627,48 @@ class temporarily_change_regcache_ptid
   ptid_t m_save_ptid;
 };
 
+ravenscar_thread_target::fpu_state
+ravenscar_thread_target::get_fpu_state (struct regcache *regcache,
+					const ravenscar_arch_ops *arch_ops)
+{
+  /* We want to return true if the special FP register handling is
+     needed.  If this target doesn't have lazy FP, then no special
+     treatment is ever needed.  */
+  if (!arch_ops->on_demand_fp ())
+    return NOTHING_SPECIAL;
+
+  bound_minimal_symbol fpu_context
+    = lookup_minimal_symbol ("system__bb__cpu_primitives__current_fpu_context",
+			     nullptr, nullptr);
+  /* If the symbol can't be found, just fall back.  */
+  if (fpu_context.minsym == nullptr)
+    return NO_FP_REGISTERS;
+
+  struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
+  ptr_type = lookup_pointer_type (ptr_type);
+  value *val = value_from_pointer (ptr_type, fpu_context.value_address ());
+
+  int cpu = get_thread_base_cpu (regcache->ptid ());
+  /* The array index type has a lower bound of 1 -- it is Ada code --
+     so subtract 1 here.  */
+  val = value_ptradd (val, cpu - 1);
+
+  val = value_ind (val);
+  CORE_ADDR fpu_task = value_as_long (val);
+
+  /* The tid is the thread_id field, which is a pointer to the thread.  */
+  CORE_ADDR thread_descriptor_address
+    = (CORE_ADDR) regcache->ptid ().tid ();
+  if (fpu_task == (thread_descriptor_address
+		   + arch_ops->get_fpu_context_offset ()))
+    return LIVE_FP_REGISTERS;
+
+  int v_init_offset = arch_ops->get_v_init_offset ();
+  gdb_byte init = 0;
+  read_memory (thread_descriptor_address + v_init_offset, &init, 1);
+  return init ? NOTHING_SPECIAL : NO_FP_REGISTERS;
+}
+
 void
 ravenscar_thread_target::fetch_registers (struct regcache *regcache,
 					  int regnum)
@@ -623,19 +677,38 @@ ravenscar_thread_target::fetch_registers (struct regcache *regcache,
 
   if (runtime_initialized () && is_ravenscar_task (ptid))
     {
-      if (task_is_currently_active (ptid))
-	{
-	  ptid_t base = get_base_thread_from_ravenscar_task (ptid);
-	  temporarily_change_regcache_ptid changer (regcache, base);
-	  beneath ()->fetch_registers (regcache, regnum);
-	}
-      else
-	{
-	  struct gdbarch *gdbarch = regcache->arch ();
-	  struct ravenscar_arch_ops *arch_ops
-	    = gdbarch_ravenscar_ops (gdbarch);
+      struct gdbarch *gdbarch = regcache->arch ();
+      bool is_active = task_is_currently_active (ptid);
+      struct ravenscar_arch_ops *arch_ops = gdbarch_ravenscar_ops (gdbarch);
+      gdb::optional<fpu_state> fp_state;
+
+      int low_reg = regnum == -1 ? 0 : regnum;
+      int high_reg = regnum == -1 ? gdbarch_num_regs (gdbarch) : regnum + 1;
 
-	  arch_ops->fetch_registers (regcache, regnum);
+      ptid_t base = get_base_thread_from_ravenscar_task (ptid);
+      for (int i = low_reg; i < high_reg; ++i)
+	{
+	  bool use_beneath = false;
+	  if (arch_ops->is_fp_register (i))
+	    {
+	      if (!fp_state.has_value ())
+		fp_state = get_fpu_state (regcache, arch_ops);
+	      if (*fp_state == NO_FP_REGISTERS)
+		continue;
+	      if (*fp_state == LIVE_FP_REGISTERS
+		  || (is_active && *fp_state == NOTHING_SPECIAL))
+		use_beneath = true;
+	    }
+	  else
+	    use_beneath = is_active;
+
+	  if (use_beneath)
+	    {
+	      temporarily_change_regcache_ptid changer (regcache, base);
+	      beneath ()->fetch_registers (regcache, i);
+	    }
+	  else
+	    arch_ops->fetch_register (regcache, i);
 	}
     }
   else
@@ -650,19 +723,38 @@ ravenscar_thread_target::store_registers (struct regcache *regcache,
 
   if (runtime_initialized () && is_ravenscar_task (ptid))
     {
-      if (task_is_currently_active (ptid))
-	{
-	  ptid_t base = get_base_thread_from_ravenscar_task (ptid);
-	  temporarily_change_regcache_ptid changer (regcache, base);
-	  beneath ()->store_registers (regcache, regnum);
-	}
-      else
-	{
-	  struct gdbarch *gdbarch = regcache->arch ();
-	  struct ravenscar_arch_ops *arch_ops
-	    = gdbarch_ravenscar_ops (gdbarch);
+      struct gdbarch *gdbarch = regcache->arch ();
+      bool is_active = task_is_currently_active (ptid);
+      struct ravenscar_arch_ops *arch_ops = gdbarch_ravenscar_ops (gdbarch);
+      gdb::optional<fpu_state> fp_state;
 
-	  arch_ops->store_registers (regcache, regnum);
+      int low_reg = regnum == -1 ? 0 : regnum;
+      int high_reg = regnum == -1 ? gdbarch_num_regs (gdbarch) : regnum + 1;
+
+      ptid_t base = get_base_thread_from_ravenscar_task (ptid);
+      for (int i = low_reg; i < high_reg; ++i)
+	{
+	  bool use_beneath = false;
+	  if (arch_ops->is_fp_register (i))
+	    {
+	      if (!fp_state.has_value ())
+		fp_state = get_fpu_state (regcache, arch_ops);
+	      if (*fp_state == NO_FP_REGISTERS)
+		continue;
+	      if (*fp_state == LIVE_FP_REGISTERS
+		  || (is_active && *fp_state == NOTHING_SPECIAL))
+		use_beneath = true;
+	    }
+	  else
+	    use_beneath = is_active;
+
+	  if (use_beneath)
+	    {
+	      temporarily_change_regcache_ptid changer (regcache, base);
+	      beneath ()->store_registers (regcache, i);
+	    }
+	  else
+	    arch_ops->store_register (regcache, i);
 	}
     }
   else
diff --git a/gdb/ravenscar-thread.h b/gdb/ravenscar-thread.h
index 5d5661f48df..eda7ab1026d 100644
--- a/gdb/ravenscar-thread.h
+++ b/gdb/ravenscar-thread.h
@@ -26,19 +26,63 @@ struct ravenscar_arch_ops
 {
   ravenscar_arch_ops (gdb::array_view<const int> offsets_,
 		      int first_stack = -1,
-		      int last_stack = -1)
+		      int last_stack = -1,
+		      int v_init = -1,
+		      int fpu_offset = -1,
+		      int first_fp = -1,
+		      int last_fp = -1)
     : offsets (offsets_),
       first_stack_register (first_stack),
-      last_stack_register (last_stack)
+      last_stack_register (last_stack),
+      v_init_offset (v_init),
+      fpu_context_offset (fpu_offset),
+      first_fp_register (first_fp),
+      last_fp_register (last_fp)
   {
     /* These must either both be -1 or both be valid.  */
     gdb_assert ((first_stack_register == -1) == (last_stack_register == -1));
     /* They must also be ordered.  */
     gdb_assert (last_stack_register >= first_stack_register);
+    /* These must either all be -1 or all be valid.  */
+    gdb_assert ((v_init_offset == -1) == (fpu_context_offset == -1)
+		&& (fpu_context_offset == -1) == (first_fp_register == -1)
+		&& (first_fp_register == -1) == (last_fp_register == -1));
   }
 
-  void fetch_registers (struct regcache *, int) const;
-  void store_registers (struct regcache *, int) const;
+  /* Return true if this architecture implements on-demand floating
+     point.  */
+  bool on_demand_fp () const
+  { return v_init_offset != -1; }
+
+  /* Return true if REGNUM is a floating-point register for this
+     target.  If this target does not use the on-demand FP scheme,
+     this will always return false.  */
+  bool is_fp_register (int regnum) const
+  {
+    return regnum >= first_fp_register && regnum <= last_fp_register;
+  }
+
+  /* Return the offset, in the current task context, of the byte
+     indicating whether the FPU has been initialized for the task.
+     This can only be called when the architecture implements
+     on-demand floating-point.  */
+  int get_v_init_offset () const
+  {
+    gdb_assert (on_demand_fp ());
+    return v_init_offset;
+  }
+
+  /* Return the offset, in the current task context, of the FPU
+     context.  This can only be called when the architecture
+     implements on-demand floating-point.  */
+  int get_fpu_context_offset () const
+  {
+    gdb_assert (on_demand_fp ());
+    return fpu_context_offset;
+  }
+
+  void fetch_register (struct regcache *recache, int regnum) const;
+  void store_register (struct regcache *recache, int regnum) const;
 
 private:
 
@@ -54,6 +98,24 @@ struct ravenscar_arch_ops
   const int first_stack_register;
   const int last_stack_register;
 
+  /* If these are -1, there is no special treatment for floating-point
+     registers -- they are handled, or not, just like all other
+     registers.
+
+     Otherwise, they must all not be -1, and the target is one that
+     uses on-demand FP initialization.  V_INIT_OFFSET is the offset of
+     a boolean field in the context that indicates whether the FP
+     registers have been initialized for this task.
+     FPU_CONTEXT_OFFSET is the offset of the FPU context from the task
+     context.  (This is needed to check whether the FPU registers have
+     been saved.)  FIRST_FP_REGISTER and LAST_FP_REGISTER are the
+     register numbers of the first and last (inclusive) floating point
+     registers.  */
+  const int v_init_offset;
+  const int fpu_context_offset;
+  const int first_fp_register;
+  const int last_fp_register;
+
   /* Helper function to supply one register.  */
   void supply_one_register (struct regcache *regcache, int regnum,
 			    CORE_ADDR descriptor,
-- 
2.34.1


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

* Re: [PATCH 0/3] Ravenscar simplification + FPU feature
  2022-05-31 12:57 [PATCH 0/3] Ravenscar simplification + FPU feature Tom Tromey
                   ` (2 preceding siblings ...)
  2022-05-31 12:57 ` [PATCH 3/3] Implement lazy FPU initialization for ravenscar Tom Tromey
@ 2022-06-14 15:08 ` Tom Tromey
  3 siblings, 0 replies; 5+ messages in thread
From: Tom Tromey @ 2022-06-14 15:08 UTC (permalink / raw)
  To: Tom Tromey via Gdb-patches; +Cc: Tom Tromey

>>>>> "Tom" == Tom Tromey via Gdb-patches <gdb-patches@sourceware.org> writes:

Tom> This series simplifies the Ravenscar layer in gdb, making it more
Tom> table-based and not code-based.  It also fixes a bug, and adds support
Tom> for a missing feature -- some Ravenscar targets manage the FPU state
Tom> on demand, and so the runtime has to be queried to decide where to
Tom> find FP registers.

Tom> Tested using the internal AdaCore test suite.  I've never gotten cross
Tom> testing working using qemu with the gdb test suite, and would
Tom> Ravenscar need extra setup on top of that.

I'm checking these in now.

Tom

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

end of thread, other threads:[~2022-06-14 15:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-31 12:57 [PATCH 0/3] Ravenscar simplification + FPU feature Tom Tromey
2022-05-31 12:57 ` [PATCH 1/3] Fix bugs in aarch64-ravenscar-thread.c Tom Tromey
2022-05-31 12:57 ` [PATCH 2/3] Reimplement ravenscar registers using tables Tom Tromey
2022-05-31 12:57 ` [PATCH 3/3] Implement lazy FPU initialization for ravenscar Tom Tromey
2022-06-14 15:08 ` [PATCH 0/3] Ravenscar simplification + FPU feature Tom Tromey

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