]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
GDB: Add concept of variable-size registers to the regcache
authorThiago Jung Bauermann <thiago.bauermann@linaro.org>
Sat, 5 Oct 2024 02:48:11 +0000 (23:48 -0300)
committerThiago Jung Bauermann <thiago.bauermann@linaro.org>
Fri, 18 Apr 2025 01:49:16 +0000 (22:49 -0300)
The contents of variable-size registers are placed in a separate buffer,
because their size will only be known a while after the buffer is
created but some fixed-size registers (particularly the program counter)
need to be stored or fetched before then.  This is also why the state
related to variable-size registers is lazily initialised at the moment
it's first needed (by calling the initialize_variable_size_registers ()
method).

Simon suggested placing the variable-size registers at the end of the
existing contents buffer to avoid having to use a separate one.  I will
experiment with that idea and see if it simplifies the code.

The regcache now also stores the resolved type and size of the
variable-size registers.  Some places needed to be changed from calling
the register_size () function to calling the register_size () method
instead, because they may call them for variable-size registers.  The
frame-unwinding code doesn't have a regcache readily available, so the
register_size () function is changed to optionally accept a
frame_info_ptr which it uses to create a readonly_detached_regcache.

When debugging a remote target, if the regcache has variable-size
registers the maximum packet size may change with new values of
expedited registers.  Therefore, update the maximum packet size when
expedited registers are supplied, or load-early registers are fetched.

Finally, there are FIXMEs related to the const_casts needed to remove
the const from the "this" pointer when calling
reg_buffer::initialize_variable_size_registers ().  I'm still thinking
about what to do with them.  I tried the simple solution of changing the
calling methods to be non-const, but the change escalates quickly.

gdb/aarch64-tdep.c
gdb/eval.c
gdb/findvar.c
gdb/frame.c
gdb/record-full.c
gdb/regcache.c
gdb/regcache.h
gdb/remote.c
gdb/value.c

index bf5b5d3bcf62eb05bcf189535bfa251039e7ff62..19d9f1d745c7d8cc104f0f8959b89bc7eb8f3e68 100644 (file)
@@ -1728,7 +1728,7 @@ pass_in_v (struct gdbarch *gdbarch,
     {
       int regnum = AARCH64_V0_REGNUM + info->nsrn;
       /* Enough space for a full vector register.  */
-      gdb::byte_vector reg (register_size (gdbarch, regnum), 0);
+      gdb::byte_vector reg (regcache->register_size (regnum), 0);
       gdb_assert (len <= reg.size ());
 
       info->argnum++;
@@ -2543,7 +2543,7 @@ aarch64_extract_return_value (struct type *type, struct regcache *regs,
        {
          int regno = AARCH64_V0_REGNUM + i;
          /* Enough space for a full vector register.  */
-         gdb::byte_vector buf (register_size (gdbarch, regno));
+         gdb::byte_vector buf (regs->register_size (regno));
          gdb_assert (len <= buf.size ());
 
          aarch64_debug_printf
@@ -2657,7 +2657,7 @@ aarch64_store_return_value (struct type *type, struct regcache *regs,
        {
          int regno = AARCH64_V0_REGNUM + i;
          /* Enough space for a full vector register.  */
-         gdb::byte_vector tmpbuf (register_size (gdbarch, regno));
+         gdb::byte_vector tmpbuf (regs->register_size (regno));
          gdb_assert (len <= tmpbuf.size ());
 
          aarch64_debug_printf
@@ -3311,7 +3311,8 @@ aarch64_pseudo_write_1 (gdbarch *gdbarch, const frame_info_ptr &next_frame,
      various 'scalar' pseudo registers to behavior like architectural
      writes, register width bytes are written the remainder are set to
      zero.  */
-  gdb::byte_vector raw_buf (register_size (gdbarch, raw_regnum), 0);
+  int raw_reg_size = register_size (gdbarch, raw_regnum, &next_frame);
+  gdb::byte_vector raw_buf (raw_reg_size, 0);
   static_assert (AARCH64_V0_REGNUM == AARCH64_SVE_Z0_REGNUM);
 
   gdb::array_view<gdb_byte> raw_view (raw_buf);
index 95d2532af8f5a49e9cd1a4681083259adc599ffa..984515a12c11464bcc6cfec6ad042c63162cc4a0 100644 (file)
@@ -1137,13 +1137,14 @@ eval_op_register (struct type *expect_type, struct expression *exp,
   if (regno == -1)
     error (_("Register $%s not available."), name);
 
-  /* In EVAL_AVOID_SIDE_EFFECTS mode, we only need to return
-     a value with the appropriate register type.  Unfortunately,
-     we don't have easy access to the type of user registers.
-     So for these registers, we fetch the register value regardless
-     of the evaluation mode.  */
+  /* In EVAL_AVOID_SIDE_EFFECTS mode, we only need to return a value with
+     the appropriate register type.  Unfortunately, we don't have easy
+     access to the type of user registers and variable-size registers.  So
+     for these registers, we fetch the register value regardless of the
+     evaluation mode.  */
   if (noside == EVAL_AVOID_SIDE_EFFECTS
-      && regno < gdbarch_num_cooked_regs (exp->gdbarch))
+      && regno < gdbarch_num_cooked_regs (exp->gdbarch)
+      && !register_is_variable_size (exp->gdbarch, regno))
     val = value::zero (register_type (exp->gdbarch, regno), not_lval);
   else
     val = value_of_register
index 29389313f943daac6ff00c0c6d8a974551744f72..94da6ded6e2a75cf4a0022c5cf83a7f53bedbfee 100644 (file)
@@ -580,11 +580,12 @@ read_frame_register_value (value *value)
   LONGEST reg_offset = value->offset ();
   int regnum = value->regnum ();
   int len = type_length_units (check_typedef (value->type ()));
+  int reg_size = register_size (gdbarch, regnum, &next_frame);
 
   /* Skip registers wholly inside of REG_OFFSET.  */
-  while (reg_offset >= register_size (gdbarch, regnum))
+  while (reg_offset >= reg_size)
     {
-      reg_offset -= register_size (gdbarch, regnum);
+      reg_offset -= reg_size;
       regnum++;
     }
 
index fe5336f24012ad7a8790cd9f69b90648e04cc3d7..95151da6120bf828365542f4259a51e2c27ec0fa 100644 (file)
@@ -1318,12 +1318,24 @@ frame_unwind_register_value (const frame_info_ptr &next_frame, int regnum)
            gdb_printf (&debug_file, " lazy");
          else if (value->entirely_available ())
            {
-             int i;
+             int i, reg_size;
              gdb::array_view<const gdb_byte> buf = value->contents ();
 
              gdb_printf (&debug_file, " bytes=");
              gdb_printf (&debug_file, "[");
-             for (i = 0; i < register_size (gdbarch, regnum); i++)
+
+             if (register_is_variable_size (gdbarch, regnum))
+               /* To get the size of a variable-size register, we need to
+                  call frame_save_as_regcache () so that we can call
+                  regcache::register_size ().  Unfortunatlly the former
+                  ends up calling this function so we enter into an
+                  infinite recursion.  So just assume that the value has
+                  the correct size.  */
+               reg_size = buf.size ();
+             else
+               reg_size = register_size (gdbarch, regnum);
+
+             for (i = 0; i < reg_size; i++)
                gdb_printf (&debug_file, "%02x", buf[i]);
              gdb_printf (&debug_file, "]");
            }
@@ -1442,7 +1454,7 @@ put_frame_register (const frame_info_ptr &next_frame, int regnum,
   int unavail;
   enum lval_type lval;
   CORE_ADDR addr;
-  int size = register_size (gdbarch, regnum);
+  int size = register_size (gdbarch, regnum, &next_frame);
 
   gdb_assert (buf.size () == size);
 
@@ -1458,8 +1470,9 @@ put_frame_register (const frame_info_ptr &next_frame, int regnum,
        break;
       }
     case lval_register:
-      /* Not sure if that's always true... but we have a problem if not.  */
-      gdb_assert (size == register_size (gdbarch, realnum));
+      if (regnum != realnum)
+       /* Not sure if that's always true... but we have a problem if not.  */
+       gdb_assert (size == register_size (gdbarch, realnum));
 
       if (realnum < gdbarch_num_regs (gdbarch)
          || !gdbarch_pseudo_register_write_p (gdbarch))
@@ -1505,9 +1518,9 @@ get_frame_register_bytes (const frame_info_ptr &next_frame, int regnum,
   gdbarch *gdbarch = frame_unwind_arch (next_frame);
 
   /* Skip registers wholly inside of OFFSET.  */
-  while (offset >= register_size (gdbarch, regnum))
+  while (offset >= register_size (gdbarch, regnum, &next_frame))
     {
-      offset -= register_size (gdbarch, regnum);
+      offset -= register_size (gdbarch, regnum, &next_frame);
       regnum++;
     }
 
@@ -1517,7 +1530,7 @@ get_frame_register_bytes (const frame_info_ptr &next_frame, int regnum,
   int numregs = gdbarch_num_cooked_regs (gdbarch);
   for (int i = regnum; i < numregs; i++)
     {
-      int thissize = register_size (gdbarch, i);
+      int thissize = register_size (gdbarch, i, &next_frame);
 
       if (thissize == 0)
        break;  /* This register is not available on this architecture.  */
@@ -1531,10 +1544,10 @@ get_frame_register_bytes (const frame_info_ptr &next_frame, int regnum,
   /* Copy the data.  */
   while (!buffer.empty ())
     {
-      int curr_len = std::min<int> (register_size (gdbarch, regnum) - offset,
-                                   buffer.size ());
+      int reg_size = register_size (gdbarch, regnum, &next_frame);
+      int curr_len = std::min<int> (reg_size - offset, buffer.size ());
 
-      if (curr_len == register_size (gdbarch, regnum))
+      if (curr_len == reg_size)
        {
          enum lval_type lval;
          CORE_ADDR addr;
@@ -1582,19 +1595,19 @@ put_frame_register_bytes (const frame_info_ptr &next_frame, int regnum,
   gdbarch *gdbarch = frame_unwind_arch (next_frame);
 
   /* Skip registers wholly inside of OFFSET.  */
-  while (offset >= register_size (gdbarch, regnum))
+  while (offset >= register_size (gdbarch, regnum, &next_frame))
     {
-      offset -= register_size (gdbarch, regnum);
+      offset -= register_size (gdbarch, regnum, &next_frame);
       regnum++;
     }
 
   /* Copy the data.  */
   while (!buffer.empty ())
     {
-      int curr_len = std::min<int> (register_size (gdbarch, regnum) - offset,
-                                   buffer.size ());
+      int reg_size = register_size (gdbarch, regnum, &next_frame);
+      int curr_len = std::min<int> (reg_size - offset, buffer.size ());
 
-      if (curr_len == register_size (gdbarch, regnum))
+      if (curr_len == reg_size)
        put_frame_register (next_frame, regnum, buffer.slice (0, curr_len));
       else
        {
index b52fb062d80187d399059211ad5708e6dd453061..ffedafbbede531725f54fed763ec9a9e01b47005 100644 (file)
@@ -401,12 +401,11 @@ static inline struct record_full_entry *
 record_full_reg_alloc (struct regcache *regcache, int regnum)
 {
   struct record_full_entry *rec;
-  struct gdbarch *gdbarch = regcache->arch ();
 
   rec = XCNEW (struct record_full_entry);
   rec->type = record_full_reg;
   rec->u.reg.num = regnum;
-  rec->u.reg.len = register_size (gdbarch, regnum);
+  rec->u.reg.len = regcache->register_size (regnum);
   if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
     rec->u.reg.u.ptr = (gdb_byte *) xmalloc (rec->u.reg.len);
 
index e3d435f90d52796c3f500d7fe4fa91394e99231c..2a65be67382face287b8ea52d858993d4dfc966e 100644 (file)
@@ -51,7 +51,7 @@ struct regcache_descr
      redundant information - if the PC is constructed from two
      registers then those registers and not the PC lives in the raw
      cache.  */
-  long sizeof_raw_registers = 0;
+  long sizeof_fixed_size_raw_registers = 0;
 
   /* The cooked register space.  Each cooked register in the range
      [0..NR_RAW_REGISTERS) is direct-mapped onto the corresponding raw
@@ -60,7 +60,7 @@ struct regcache_descr
      both raw registers and memory by the architecture methods
      gdbarch_pseudo_register_read and gdbarch_pseudo_register_write.  */
   int nr_cooked_registers = 0;
-  long sizeof_cooked_registers = 0;
+  long sizeof_fixed_size_cooked_registers = 0;
 
   /* Offset and size (in 8 bit bytes), of each register in the
      register cache.  All registers (including those in the range
@@ -69,6 +69,12 @@ struct regcache_descr
   long *register_offset = nullptr;
   long *sizeof_register = nullptr;
 
+  /* Vector indicating whether a given register is variable-size.  */
+  bool *register_is_variable_size = nullptr;
+
+  /* Does the regcache contains any variable-size register?  */
+  bool has_variable_size_registers = false;
+
   /* Cached table containing the type of each register.  */
   struct type **register_type = nullptr;
 };
@@ -116,23 +122,49 @@ init_regcache_descr (struct gdbarch *gdbarch)
       = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
     descr->register_offset
       = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
+    descr->register_is_variable_size
+      = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, bool);
+
     for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
       {
-       descr->sizeof_register[i] = descr->register_type[i]->length ();
-       descr->register_offset[i] = offset;
-       offset += descr->sizeof_register[i];
+       descr->register_is_variable_size[i]
+         = is_dynamic_type (descr->register_type[i]);
+       if (descr->register_is_variable_size[i])
+         {
+           descr->sizeof_register[i] = -1;
+           descr->register_offset[i] = -1;
+           descr->has_variable_size_registers = true;
+         }
+       else
+         {
+           descr->sizeof_register[i] = descr->register_type[i]->length ();
+           descr->register_offset[i] = offset;
+           offset += descr->sizeof_register[i];
+         }
       }
+
     /* Set the real size of the raw register cache buffer.  */
-    descr->sizeof_raw_registers = offset;
+    descr->sizeof_fixed_size_raw_registers = offset;
 
     for (; i < descr->nr_cooked_registers; i++)
       {
-       descr->sizeof_register[i] = descr->register_type[i]->length ();
-       descr->register_offset[i] = offset;
-       offset += descr->sizeof_register[i];
+       descr->register_is_variable_size[i]
+         = is_dynamic_type (descr->register_type[i]);
+       if (descr->register_is_variable_size[i])
+         {
+           descr->sizeof_register[i] = -1;
+           descr->register_offset[i] = -1;
+           descr->has_variable_size_registers = true;
+         }
+       else
+         {
+           descr->sizeof_register[i] = descr->register_type[i]->length ();
+           descr->register_offset[i] = offset;
+           offset += descr->sizeof_register[i];
+         }
       }
     /* Set the real size of the readonly register cache buffer.  */
-    descr->sizeof_cooked_registers = offset;
+    descr->sizeof_fixed_size_cooked_registers = offset;
   }
 
   return descr;
@@ -154,27 +186,60 @@ regcache_descr (struct gdbarch *gdbarch)
 /* Utility functions returning useful register attributes stored in
    the regcache descr.  */
 
+/* See gdb/regcache.h.  */
+
 struct type *
 register_type (struct gdbarch *gdbarch, int regnum)
 {
   struct regcache_descr *descr = regcache_descr (gdbarch);
 
   gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
-  return descr->register_type[regnum];
+
+  struct type *type = descr->register_type[regnum];
+
+  if (descr->register_is_variable_size[regnum])
+    {
+      frame_info_ptr current_frame = get_current_frame ();
+      type = resolve_dynamic_type (type, {}, 0, &current_frame);
+    }
+
+  return type;
 }
 
-/* Utility functions returning useful register attributes stored in
-   the regcache descr.  */
+/* See gdb/regcache.h.  */
 
 int
-register_size (struct gdbarch *gdbarch, int regnum)
+register_size (struct gdbarch *gdbarch, int regnum,
+              const frame_info_ptr *next_frame)
 {
   struct regcache_descr *descr = regcache_descr (gdbarch);
-  int size;
 
-  gdb_assert (regnum >= 0 && regnum < gdbarch_num_cooked_regs (gdbarch));
-  size = descr->sizeof_register[regnum];
-  return size;
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < descr->nr_cooked_registers);
+
+  if (descr->register_is_variable_size[regnum])
+    {
+      gdb_assert (next_frame != nullptr);
+
+      std::unique_ptr<readonly_detached_regcache> regcache =
+       frame_save_as_regcache (get_prev_frame (*next_frame));
+      return regcache->register_size (regnum);
+    }
+
+  return descr->sizeof_register[regnum];
+}
+
+/* See gdb/regcache.h.  */
+
+bool
+register_is_variable_size (struct gdbarch *gdbarch, int regnum)
+{
+  struct regcache_descr *descr = regcache_descr (gdbarch);
+
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < descr->nr_cooked_registers);
+
+  return descr->register_is_variable_size[regnum];
 }
 
 /* See gdbsupport/common-regcache.h.  */
@@ -182,7 +247,47 @@ register_size (struct gdbarch *gdbarch, int regnum)
 int
 reg_buffer::register_size (int regnum) const
 {
-  return ::register_size (this->arch (), regnum);
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < m_descr->nr_cooked_registers);
+
+  int size;
+
+  if (m_descr->register_is_variable_size[regnum])
+    {
+      if (!m_variable_size_registers)
+       const_cast<reg_buffer *> (this)
+         ->initialize_variable_size_registers (); // FIXME: Remove cast.
+
+      size = m_variable_size_register_sizeof[regnum];
+    }
+  else
+    size = m_descr->sizeof_register[regnum];
+
+  return size;
+}
+
+/* See gdb/regcache.h.  */
+
+struct type *
+reg_buffer::register_type (int regnum) const
+{
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < m_descr->nr_cooked_registers);
+
+  struct type *type;
+
+  if (m_descr->register_is_variable_size[regnum])
+    {
+      if (!m_variable_size_registers)
+       const_cast<reg_buffer *> (this)
+         ->initialize_variable_size_registers (); // FIXME: Remove cast.
+
+      type = m_variable_size_register_type[regnum];
+    }
+  else
+    type = m_descr->register_type[regnum];
+
+  return type;
 }
 
 reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo)
@@ -196,13 +301,13 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo)
      REG_VALID.  */
   if (has_pseudo)
     {
-      m_registers.reset (new gdb_byte[m_descr->sizeof_cooked_registers]);
+      m_fixed_size_registers.reset (new gdb_byte[m_descr->sizeof_fixed_size_cooked_registers]);
       m_register_status.reset
        (new register_status[m_descr->nr_cooked_registers] ());
     }
   else
     {
-      m_registers.reset (new gdb_byte[m_descr->sizeof_raw_registers]);
+      m_fixed_size_registers.reset (new gdb_byte[m_descr->sizeof_fixed_size_raw_registers]);
       m_register_status.reset
        (new register_status[gdbarch_num_regs (gdbarch)] ());
     }
@@ -231,6 +336,50 @@ reg_buffer::arch () const
   return m_descr->gdbarch;
 }
 
+/* See regcache.h.  */
+
+void
+reg_buffer::initialize_variable_size_registers ()
+{
+  unsigned long total_size = 0;
+
+  m_variable_size_register_type.resize (m_descr->nr_cooked_registers);
+  m_variable_size_register_sizeof.resize (m_descr->nr_cooked_registers);
+  m_variable_size_register_offset.resize (m_descr->nr_cooked_registers);
+
+  for (unsigned int i = 0; i < m_descr->nr_cooked_registers; i++)
+    {
+      if (!m_descr->register_is_variable_size[i])
+       {
+         m_variable_size_register_type[i] = nullptr;
+         m_variable_size_register_sizeof[i] = -1;
+         m_variable_size_register_offset[i] = -1;
+         continue;
+       }
+
+      m_variable_size_register_type[i]
+       = resolve_dynamic_type (m_descr->register_type[i], {},
+                               /* Unused address.  */ 0, nullptr);
+
+      ULONGEST size = m_variable_size_register_type[i]->length ();
+      gdb_assert (size != 0);
+      m_variable_size_register_sizeof[i] = size;
+      m_variable_size_register_offset[i] = total_size;
+      m_register_status[i] = REG_UNKNOWN;
+      total_size += size;
+    }
+
+  m_variable_size_registers.reset (new gdb_byte[total_size]);
+}
+
+/* See regcache.h.  */
+
+bool
+reg_buffer::has_variable_size_registers ()
+{
+  return m_descr->has_variable_size_registers;
+}
+
 /* Helper for reg_buffer::register_buffer.  */
 
 template<typename ElemType>
@@ -238,8 +387,19 @@ gdb::array_view<ElemType>
 reg_buffer::register_buffer (int regnum) const
 {
   assert_regnum (regnum);
-  ElemType *start = &m_registers[m_descr->register_offset[regnum]];
-  int size = m_descr->sizeof_register[regnum];
+  ElemType *start;
+
+  if (m_descr->register_is_variable_size[regnum])
+    {
+      if (!m_variable_size_registers)
+       const_cast<reg_buffer *>(this)->initialize_variable_size_registers (); // FIXME: Remove cast.
+
+      start = &m_variable_size_registers[m_variable_size_register_offset[regnum]];
+    }
+  else
+    start = &m_fixed_size_registers[m_descr->register_offset[regnum]];
+
+  int size = register_size (regnum);
   return gdb::array_view<ElemType> (start, size);
 }
 
@@ -267,8 +427,14 @@ reg_buffer::save (register_read_ftype cooked_read)
   /* It should have pseudo registers.  */
   gdb_assert (m_has_pseudo);
   /* Clear the dest.  */
-  memset (m_registers.get (), 0, m_descr->sizeof_cooked_registers);
+  memset (m_fixed_size_registers.get (), 0, m_descr->sizeof_fixed_size_cooked_registers);
   memset (m_register_status.get (), REG_UNKNOWN, m_descr->nr_cooked_registers);
+
+  /* For data related to variable-size registers, we only need to reset
+     their buffer at this point.  Other data will be resized/re-set by
+     initialize_variable_size_registers ().  */
+  m_variable_size_registers.reset ();
+
   /* Copy over any registers (identified by their membership in the
      save_reggroup) and mark them as valid.  The full [0 .. gdbarch_num_regs +
      gdbarch_num_pseudo_regs) range is checked since some architectures need
@@ -615,7 +781,7 @@ register_status
 readable_regcache::raw_read (int regnum, gdb::array_view<gdb_byte> dst)
 {
   assert_regnum (regnum);
-  gdb_assert (dst.size () == m_descr->sizeof_register[regnum]);
+  gdb_assert (dst.size () == register_size (regnum));
 
   raw_update (regnum);
 
@@ -631,7 +797,7 @@ register_status
 readable_regcache::raw_read (int regnum, gdb_byte *dst)
 {
   assert_regnum (regnum);
-  int size = m_descr->sizeof_register[regnum];
+  int size = register_size (regnum);
   return raw_read (regnum, gdb::make_array_view (dst, size));
 }
 
@@ -647,7 +813,7 @@ enum register_status
 readable_regcache::raw_read (int regnum, T *val)
 {
   assert_regnum (regnum);
-  size_t size = m_descr->sizeof_register[regnum];
+  size_t size = register_size (regnum);
   gdb_byte *buf = (gdb_byte *) alloca (size);
   auto view = gdb::make_array_view (buf, size);
   register_status status = raw_read (regnum, view);
@@ -682,7 +848,7 @@ regcache::raw_write (int regnum, T val)
 {
   assert_regnum (regnum);
 
-  int size = m_descr->sizeof_register[regnum];
+  int size = register_size (regnum);
   gdb_byte *buf = (gdb_byte *) alloca (size);
   auto view = gdb::make_array_view (buf, size);
   store_integer (view, gdbarch_byte_order (m_descr->gdbarch), val);
@@ -721,7 +887,7 @@ readable_regcache::cooked_read (int regnum, gdb::array_view<gdb_byte> dst)
   if (regnum < num_raw_registers ())
     return raw_read (regnum, dst);
 
-  gdb_assert (dst.size () == m_descr->sizeof_register[regnum]);
+  gdb_assert (dst.size () == register_size (regnum));
 
   if (m_has_pseudo && m_register_status[regnum] != REG_UNKNOWN)
     {
@@ -763,7 +929,7 @@ readable_regcache::cooked_read (int regnum, gdb_byte *dst)
   gdb_assert (regnum >= 0);
   gdb_assert (regnum < m_descr->nr_cooked_registers);
 
-  int size = m_descr->sizeof_register[regnum];
+  int size = register_size (regnum);
   return cooked_read (regnum, gdb::make_array_view (dst, size));
 }
 
@@ -777,8 +943,12 @@ readable_regcache::cooked_read_value (int regnum)
       || (m_has_pseudo && m_register_status[regnum] != REG_UNKNOWN)
       || !gdbarch_pseudo_register_read_value_p (m_descr->gdbarch))
     {
+      /* Provide the register type if its size is fixed to avoid infinite
+        recursion in the case of variable-size registers.  */
+      struct type *type = (m_descr->register_is_variable_size[regnum] ?
+                          nullptr : m_descr->register_type[regnum]);
       value *result = value::allocate_register
-       (get_next_frame_sentinel_okay (get_current_frame ()), regnum);
+       (get_next_frame_sentinel_okay (get_current_frame ()), regnum, type);
 
       /* It is more efficient in general to do this delegation in this
         direction than in the other one, even though the value-based
@@ -808,7 +978,7 @@ enum register_status
 readable_regcache::cooked_read (int regnum, T *val)
 {
   gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers);
-  size_t size = m_descr->sizeof_register[regnum];
+  size_t size = register_size (regnum);
   gdb_byte *buf = (gdb_byte *) alloca (size);
   auto view = gdb::make_array_view (buf, size);
   register_status status = cooked_read (regnum, view);
@@ -842,7 +1012,7 @@ regcache::cooked_write (int regnum, T val)
   gdb_assert (regnum >= 0);
   gdb_assert (regnum < m_descr->nr_cooked_registers);
 
-  int size = m_descr->sizeof_register[regnum];
+  int size = register_size (regnum);
   gdb_byte *buf = (gdb_byte *) alloca (size);
   auto view = gdb::make_array_view (buf, size);
   store_integer (view, gdbarch_byte_order (m_descr->gdbarch), val);
@@ -861,7 +1031,7 @@ void
 regcache::raw_write (int regnum, gdb::array_view<const gdb_byte> src)
 {
   assert_regnum (regnum);
-  gdb_assert (src.size () == m_descr->sizeof_register[regnum]);
+  gdb_assert (src.size () == register_size (regnum));
 
   /* On the sparc, writing %g0 is a no-op, so we don't even want to
      change the registers array if something writes to this register.  */
@@ -898,7 +1068,7 @@ regcache::raw_write (int regnum, const gdb_byte *src)
 {
   assert_regnum (regnum);
 
-  int size = m_descr->sizeof_register[regnum];
+  int size = register_size (regnum);
   raw_write (regnum, gdb::make_array_view (src, size));
 }
 
@@ -929,7 +1099,7 @@ regcache::cooked_write (int regnum, const gdb_byte *src)
   gdb_assert (regnum >= 0);
   gdb_assert (regnum < m_descr->nr_cooked_registers);
 
-  int size = m_descr->sizeof_register[regnum];
+  int size = register_size (regnum);
   return cooked_write (regnum, gdb::make_array_view (src, size));
 }
 
@@ -1159,7 +1329,7 @@ reg_buffer::raw_supply (int regnum, const void *src)
 {
   assert_regnum (regnum);
 
-  int size = m_descr->sizeof_register[regnum];
+  int size = register_size (regnum);
   raw_supply (regnum, gdb::make_array_view ((const gdb_byte *) src, size));
 }
 
@@ -1213,7 +1383,7 @@ reg_buffer::raw_collect (int regnum, void *dst) const
 {
   assert_regnum (regnum);
 
-  int size = m_descr->sizeof_register[regnum];
+  int size = register_size (regnum);
   return raw_collect (regnum, gdb::make_array_view ((gdb_byte *) dst, size));
 }
 
@@ -1288,7 +1458,7 @@ regcache::transfer_regset (const struct regset *regset, int regbase,
        regno += regbase;
 
       if (slot_size == 0 && regno != REGCACHE_MAP_SKIP)
-       slot_size = m_descr->sizeof_register[regno];
+       slot_size = register_size (regnum);
 
       if (regno == REGCACHE_MAP_SKIP
          || (regnum != -1
index 7eb49b3ae662af9ae901b189a1ad130f79d05807..1da162f2f7493fcebcc42d615c749e6b87bfebce 100644 (file)
@@ -165,10 +165,15 @@ extern bool regcache_map_supplies (const struct regcache_map_entry *map,
 extern struct type *register_type (struct gdbarch *gdbarch, int regnum);
 
 
-/* Return the size of register REGNUM.  All registers should have only
-   one size.  */
+/* Return the size of register REGNUM.  FRAME is needed in case regnum is a
+   variable-size register.  */
    
-extern int register_size (struct gdbarch *gdbarch, int regnum);
+extern int register_size (struct gdbarch *gdbarch, int regnum,
+                         const frame_info_ptr *next_frame = nullptr);
+
+/* Return whether REGNUM  is a variable-size register.  */
+
+extern bool register_is_variable_size (struct gdbarch *gdbarch, int regnum);
 
 using register_read_ftype
   = gdb::function_view<register_status (int, gdb::array_view<gdb_byte>)>;
@@ -257,6 +262,12 @@ public:
   /* See gdbsupport/common-regcache.h.  */
   bool raw_compare (int regnum, const void *buf, int offset) const override;
 
+  /* Whether any register in this regcache has a dynamic type.  */
+  bool has_variable_size_registers ();
+
+  /* Return type of register REGNUM.  */
+  struct type *register_type (int regnum) const;
+
   /* See gdbsupport/common-regcache.h.  */
   int register_size (int regnum) const override;
 
@@ -266,6 +277,10 @@ protected:
 
   int num_raw_registers () const;
 
+  /* Initialize (or reset) information about variable-size registers in this
+     reg_buffer.  */
+  void initialize_variable_size_registers ();
+
   /* Return a view on register REGNUM's buffer cache.  */
   template <typename ElemType>
   gdb::array_view<ElemType> register_buffer (int regnum) const;
@@ -280,11 +295,25 @@ protected:
   struct regcache_descr *m_descr;
 
   bool m_has_pseudo;
-  /* The register buffers.  */
-  std::unique_ptr<gdb_byte[]> m_registers;
+
+  /* The fixed-size register buffers.  */
+  std::unique_ptr<gdb_byte[]> m_fixed_size_registers;
+
+  /* The variable-size register buffers (if any).  */
+  std::unique_ptr<gdb_byte[]> m_variable_size_registers;
+
   /* Register cache status.  */
   std::unique_ptr<register_status[]> m_register_status;
 
+  /* The resolved types for variable-size registers (if any).  */
+  std::vector<struct type *> m_variable_size_register_type;
+
+  /* The size of resolved types for variable-size registers (if any).  */
+  std::vector<long> m_variable_size_register_sizeof;
+
+  /* The offset of resolved types for variable-size registers (if any).  */
+  std::vector<long> m_variable_size_register_offset;
+
   friend class regcache;
   friend class detached_regcache;
 };
index 7dc057c056884ad5f42242b66757b4d871f1de3d..ea3c254a7707803b01c173a55c7ce68110171cdd 100644 (file)
@@ -472,6 +472,8 @@ struct packet_reg
      at present.  */
 };
 
+struct remote_state;
+
 struct remote_arch_state
 {
   explicit remote_arch_state (struct gdbarch *gdbarch);
@@ -494,6 +496,10 @@ struct remote_arch_state
   /* This is the maximum size (in chars) of a non read/write packet.
      It is also used as a cap on the size of read/write packets.  */
   long remote_packet_size;
+
+  /* Make sure the maximum packet size reflects current size of variable-size
+     registers.  */
+  void update_packet_size (const struct regcache *regcache, remote_state *rs);
 };
 
 /* Description of the remote protocol state for the currently
@@ -1894,7 +1900,8 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
 }
 
 static int
-map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs)
+map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs,
+                          const struct regcache *regcache = nullptr)
 {
   int regnum, num_remote_regs, offset;
   struct packet_reg **remote_regs;
@@ -1902,8 +1909,15 @@ map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs)
   for (regnum = 0; regnum < gdbarch_num_regs (gdbarch); regnum++)
     {
       struct packet_reg *r = &regs[regnum];
+      bool skip_register;
 
-      if (register_size (gdbarch, regnum) == 0)
+      if (regcache == nullptr)
+       skip_register = (register_is_variable_size (gdbarch, regnum)
+                        || register_size (gdbarch, regnum) == 0);
+      else
+       skip_register = regcache->register_size (regnum) == 0;
+
+      if (skip_register)
        /* Do not try to fetch zero-sized (placeholder) registers.  */
        r->pnum = -1;
       else
@@ -1931,7 +1945,10 @@ map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs)
     {
       remote_regs[regnum]->in_g_packet = true;
       remote_regs[regnum]->offset = offset;
-      offset += register_size (gdbarch, remote_regs[regnum]->regnum);
+      if (regcache == nullptr)
+       offset += register_size (gdbarch, remote_regs[regnum]->regnum);
+      else
+       offset += regcache->register_size (remote_regs[regnum]->regnum);
     }
 
   return offset;
@@ -1992,6 +2009,29 @@ remote_arch_state::remote_arch_state (struct gdbarch *gdbarch)
     this->remote_packet_size = (this->sizeof_g_packet * 2 + 32);
 }
 
+/* See remote_arch_state class declaration.  */
+
+void
+remote_arch_state::update_packet_size (const struct regcache *regcache,
+                                      remote_state *rs)
+{
+  /* Record the maximum possible size of the g packet - it may turn out
+     to be smaller.  */
+  this->sizeof_g_packet
+    = map_regcache_remote_table (regcache->arch (), this->regs.get (),
+                                regcache);
+
+  this->remote_packet_size = 400 - 1;
+
+  if (this->sizeof_g_packet > (this->remote_packet_size - 32) / 2)
+    this->remote_packet_size = this->sizeof_g_packet * 2 + 32;
+
+  /* Make sure that the packet buffer is plenty big enough for
+     this architecture.  */
+  if (rs->buf.size () < this->remote_packet_size)
+    rs->buf.resize (2 * this->remote_packet_size);
+}
+
 /* Get a pointer to the current remote target.  If not connected to a
    remote target, return NULL.  */
 
@@ -9006,7 +9046,7 @@ remote_target::process_g_packet (struct regcache *regcache)
       for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
        {
          long offset = rsa->regs[i].offset;
-         long reg_size = register_size (gdbarch, i);
+         long reg_size = regcache->register_size (i);
 
          if (rsa->regs[i].pnum == -1)
            continue;
@@ -9054,7 +9094,7 @@ remote_target::process_g_packet (struct regcache *regcache)
   for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
     {
       struct packet_reg *r = &rsa->regs[i];
-      long reg_size = register_size (gdbarch, i);
+      long reg_size = regcache->register_size (i);
 
       if (r->in_g_packet)
        {
@@ -9189,7 +9229,8 @@ remote_target::store_register_using_P (const struct regcache *regcache,
   struct remote_state *rs = get_remote_state ();
   /* Try storing a single register.  */
   char *buf = rs->buf.data ();
-  gdb_byte *regp = (gdb_byte *) alloca (register_size (gdbarch, reg->regnum));
+  int reg_size = regcache->register_size (reg->regnum);
+  gdb_byte *regp = (gdb_byte *) alloca (reg_size);
   char *p;
 
   if (m_features.packet_support (PACKET_P) == PACKET_DISABLE)
@@ -9201,7 +9242,7 @@ remote_target::store_register_using_P (const struct regcache *regcache,
   xsnprintf (buf, get_remote_packet_size (), "P%s=", phex_nz (reg->pnum, 0));
   p = buf + strlen (buf);
   regcache->raw_collect (reg->regnum, regp);
-  bin2hex (regp, p, register_size (gdbarch, reg->regnum));
+  bin2hex (regp, p, reg_size);
   putpkt (rs->buf);
   getpkt (&rs->buf);
 
index 0f1be2e5d122ca09e5e29708e2689ed89ebbc717..5c0e5d83518c032d83b2eff76ca4b1a688fd3dea 100644 (file)
@@ -4083,12 +4083,24 @@ value::fetch_lazy_register ()
 
          if (new_val->entirely_available ())
            {
-             int i;
+             int i, reg_size;
              gdb::array_view<const gdb_byte> buf = new_val->contents ();
 
              gdb_printf (&debug_file, " bytes=");
              gdb_printf (&debug_file, "[");
-             for (i = 0; i < register_size (gdbarch, regnum); i++)
+
+             if (register_is_variable_size (gdbarch, regnum))
+               /* To get the size of a variable-size register, we need to
+                  call frame_save_as_regcache () so that we can call
+                  regcache::register_size ().  Unfortunatlly the former
+                  ends up calling this function so we enter into an
+                  infinite recursion.  So just assume that the value has
+                  the correct size.  */
+               reg_size = buf.size ();
+             else
+               reg_size = register_size (gdbarch, regnum);
+
+             for (i = 0; i < reg_size; i++)
                gdb_printf (&debug_file, "%02x", buf[i]);
              gdb_printf (&debug_file, "]");
            }