]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Support assignment of capabilities to C registers
authorLuis Machado <luis.machado@linaro.org>
Wed, 29 Dec 2021 11:20:53 +0000 (08:20 -0300)
committerLuis Machado <luis.machado@linaro.org>
Fri, 14 Jan 2022 14:30:12 +0000 (11:30 -0300)
Enable assignment of capabilities to C registers while preserving
the capability tag. This enables operations like the following:

set $c0=$c1
set $c0=p, where "p" is a capability (pointer) in AARCH64-CAP

Due to the X/C register overlap, we also force a re-read of register
data after every register write. So any 'G' packets are immediately
followed by a 'g' packet.

gdb/aarch64-linux-tdep.c
gdb/aarch64-tdep.c
gdb/arch-utils.c
gdb/arch-utils.h
gdb/frame.c
gdb/frame.h
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/remote.c
gdb/valops.c

index 356f20342e5ea8638ac060245266aa3bd136beaa..dd92b31fd5903aff6c1af16e0c82404c18057b79 100644 (file)
@@ -1637,6 +1637,24 @@ aarch64_linux_get_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr)
   return cap[0] != 0;
 }
 
+/* AArch64 Linux implementation of the set_cap_tag_from_address gdbarch
+   hook.  Sets the tag from the capability located at ADDR to TAG.  */
+
+static void
+aarch64_linux_set_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr,
+                                       bool tag)
+{
+  gdb::byte_vector cap;
+
+  /* Read original capability at ADDR.  */
+  cap = target_read_capability (addr);
+
+  cap[0] = tag? 1 : 0;
+
+  /* Write back the same contents but with a custom tag.  */
+  target_write_capability (addr, cap);
+}
+
 /* Return the number of Morello memory tag granules contained in the memory
    range [addr, addr + len).  */
 
@@ -2115,6 +2133,8 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
                                      aarch64_linux_report_signal_info);
       set_gdbarch_get_cap_tag_from_address (gdbarch,
                                            aarch64_linux_get_cap_tag_from_address);
+      set_gdbarch_set_cap_tag_from_address (gdbarch,
+                                           aarch64_linux_set_cap_tag_from_address);
 
       /* Core file helpers.  */
 
index 2928bc6d44bf27dbd3fbfd289f979966fbb7df07..c1ab29094ec576005396f46d8cc7353ba27f742e 100644 (file)
@@ -1984,11 +1984,11 @@ struct aarch64_call_info
   std::vector<stack_item_t> si;
 };
 
-/* Helper function to set a TAG for a particular register REGNUM.  */
+/* Implementation of the gdbarch_register_set_tag hook.  */
 
 static void
-set_register_tag (struct gdbarch *gdbarch, struct regcache *regcache,
-                 int regnum, bool tag)
+aarch64_register_set_tag (struct gdbarch *gdbarch, struct regcache *regcache,
+                         int regnum, bool tag)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
@@ -2069,7 +2069,7 @@ pass_in_c (struct gdbarch *gdbarch, struct regcache *regcache,
          /* We need to read the tags from memory.  */
          gdb::byte_vector cap = target_read_capability (address);
          bool tag = cap[0] == 0 ? false : true;
-         set_register_tag (gdbarch, regcache, regnum, tag);
+         aarch64_register_set_tag (gdbarch, regcache, regnum, tag);
 
          if (aarch64_debug)
            debug_printf ("aarch64: %s Read tag %s from address %s\n",
@@ -2570,7 +2570,7 @@ morello_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
         capability.  */
       struct value *clr = regcache->cooked_read_value (regnum);
       regcache->cooked_write (regnum, value_contents (clr));
-      set_register_tag (gdbarch, regcache, regnum, value_tag (clr));
+      aarch64_register_set_tag (gdbarch, regcache, regnum, value_tag (clr));
     }
 
   if (aarch64_debug)
@@ -2601,7 +2601,7 @@ morello_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
             capability.  */
          struct value *csp = regcache->cooked_read_value (regnum);
          regcache->cooked_write (regnum, value_contents (csp));
-         set_register_tag (gdbarch, regcache, regnum, value_tag (csp));
+         aarch64_register_set_tag (gdbarch, regcache, regnum, value_tag (csp));
        }
 
       if (aarch64_debug)
@@ -2799,7 +2799,7 @@ morello_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
       struct value *csp = regcache->cooked_read_value (regnum);
       regcache->cooked_write (regnum, value_contents (csp));
-      set_register_tag (gdbarch, regcache, regnum, value_tag (csp));
+      aarch64_register_set_tag (gdbarch, regcache, regnum, value_tag (csp));
     }
 
     if (aarch64_debug)
@@ -3743,7 +3743,7 @@ morello_store_return_value (struct value *value, struct regcache *regs,
 
       /* Also store the tag if we are dealing with a capability.  */
       if (aapcs64_cap || type->code () == TYPE_CODE_CAPABILITY)
-       set_register_tag (gdbarch, regs, regno, value_tag (value));
+       aarch64_register_set_tag (gdbarch, regs, regno, value_tag (value));
     }
   else if (type->code () == TYPE_CODE_INT
           || type->code () == TYPE_CODE_CHAR
@@ -3821,7 +3821,7 @@ morello_store_return_value (struct value *value, struct regcache *regs,
              /* We need to read the tags from memory.  */
              gdb::byte_vector cap = target_read_capability (address);
              bool tag = cap[0] == 0 ? false : true;
-             set_register_tag (gdbarch, regs, regno, tag);
+             aarch64_register_set_tag (gdbarch, regs, regno, tag);
 
              if (aarch64_debug)
                debug_printf ("aarch64: %s Read tag %s from address %s\n",
@@ -4399,8 +4399,8 @@ aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
       regcache->raw_write_part (c_real_regnum, 0, 8, lower_bytes);
       regcache->raw_write_part (c_real_regnum, 8, 8, upper_bytes);
 
-      set_register_tag (gdbarch, regcache, c_real_regnum,
-                       (tag != 0)? true : false);
+      aarch64_register_set_tag (gdbarch, regcache, c_real_regnum,
+                               (tag != 0)? true : false);
       return;
     }
 
@@ -5673,6 +5673,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       /* For fetching register tag information.  */
       set_gdbarch_register_has_tag (gdbarch, aarch64_register_has_tag);
       set_gdbarch_register_tag (gdbarch, aarch64_register_tag);
+      set_gdbarch_register_set_tag (gdbarch, aarch64_register_set_tag);
 
       /* Create the Morello register aliases.  */
       /* cip0 and cip1 */
index 2136e8a22257be25c32e95b80eda32d76677ae62..79d36cadc0d177e37a308be3c995af19c9576b3c 100644 (file)
@@ -1070,6 +1070,15 @@ default_register_tag (struct gdbarch *gdbarch,
   return false;
 }
 
+/* See arch-utils.h.  */
+void
+default_register_set_tag (struct gdbarch *gdbarch,
+                         regcache *regcache,
+                         int cookednum, bool tag)
+{
+  return;
+}
+
 /* See arch-utils.h.  */
 bool default_get_cap_tag_from_address (struct gdbarch *gdbarch,
                                       CORE_ADDR addr)
@@ -1077,6 +1086,14 @@ bool default_get_cap_tag_from_address (struct gdbarch *gdbarch,
   return false;
 }
 
+/* See arch-utils.h.  */
+void
+default_set_cap_tag_from_address (struct gdbarch *gdbarch,
+                                 CORE_ADDR addr, bool tag)
+{
+  return;
+}
+
 void _initialize_gdbarch_utils ();
 void
 _initialize_gdbarch_utils ()
index fb35d731a428206a23ceaaff20859a69e0371b81..e6dd69962c495ac9734a27a8dd9eceb1642c6b3c 100644 (file)
@@ -303,7 +303,16 @@ extern bool default_register_tag (struct gdbarch *gdbarch,
                                  readable_regcache *regcache,
                                  int cookednum);
 
+/* Default implementation of gdbarch_register_set_tag.  */
+extern void default_register_set_tag (struct gdbarch *gdbarch,
+                                     regcache *regcache,
+                                     int cookednum, bool tag);
+
 /* Default implementation of gdbarch_cap_tag_from_address.  */
 extern bool default_get_cap_tag_from_address (struct gdbarch *gdbarch,
                                              CORE_ADDR addr);
+
+/* Default implementation of gdbarch_set_cap_tag_from_address.  */
+extern void default_set_cap_tag_from_address (struct gdbarch *gdbarch,
+                                             CORE_ADDR addr, bool tag);
 #endif /* ARCH_UTILS_H */
index 6bfa31e630e44d9c3efcb1243fcb5b1db220d951..9609fcd07a69f107bb5dde4e183096803c48f58b 100644 (file)
@@ -1415,6 +1415,59 @@ read_frame_register_unsigned (frame_info *frame, int regnum,
   return false;
 }
 
+void
+put_frame_register (struct frame_info *frame, int regnum,
+                   const gdb_byte *buf, struct value *fromval)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int realnum;
+  int optim;
+  int unavail;
+  enum lval_type lval;
+  CORE_ADDR addr;
+
+  frame_register (frame, regnum, &optim, &unavail,
+                 &lval, &addr, &realnum, NULL);
+  if (optim)
+    error (_("Attempt to assign to a register that was not saved."));
+
+  struct type *val_type = value_type (fromval);
+
+  switch (lval)
+    {
+    case lval_memory:
+      {
+       write_memory (addr, buf, register_size (gdbarch, regnum));
+
+       /* If this value is a capability, we need to handle the capability tag
+          as well.  */
+       if ((val_type->code () == TYPE_CODE_CAPABILITY
+           || (val_type->code () == TYPE_CODE_PTR
+               && TYPE_CAPABILITY (val_type)))
+           && value_tagged (fromval))
+         gdbarch_set_cap_tag_from_address (gdbarch, addr, value_tag (fromval));
+       break;
+      }
+    case lval_register:
+      {
+       get_current_regcache ()->cooked_write (realnum, buf);
+       /* If this value is a capability, we need to handle the capability tag
+          as well.  */
+       if ((val_type->code () == TYPE_CODE_CAPABILITY
+           || (val_type->code () == TYPE_CODE_PTR
+               && TYPE_CAPABILITY (val_type)))
+           && value_tagged (fromval))
+         {
+           gdbarch_register_set_tag (gdbarch, get_current_regcache (),
+                                     regnum, value_tag (fromval));
+         }
+      }
+      break;
+    default:
+      error (_("Attempt to assign to an unmodifiable value."));
+    }
+}
+
 void
 put_frame_register (struct frame_info *frame, int regnum,
                    const gdb_byte *buf)
@@ -1551,6 +1604,53 @@ get_frame_register_bytes (frame_info *frame, int regnum,
   return true;
 }
 
+void
+put_frame_register_value (struct frame_info *frame, int regnum,
+                         CORE_ADDR offset, struct value *fromval)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int len = TYPE_LENGTH (value_type (fromval));
+  const gdb_byte *myaddr = value_contents (fromval);
+
+  /* Skip registers wholly inside of OFFSET.  */
+  while (offset >= register_size (gdbarch, regnum))
+    {
+      offset -= register_size (gdbarch, regnum);
+      regnum++;
+    }
+
+  /* Copy the data.  */
+  while (len > 0)
+    {
+      int curr_len = register_size (gdbarch, regnum) - offset;
+
+      if (curr_len > len)
+       curr_len = len;
+
+      if (curr_len == register_size (gdbarch, regnum))
+       {
+         put_frame_register (frame, regnum, myaddr, fromval);
+       }
+      else
+       {
+         struct value *value = frame_unwind_register_value (frame->next,
+                                                            regnum);
+         gdb_assert (value != NULL);
+
+         memcpy ((char *) value_contents_writeable (value) + offset, myaddr,
+                 curr_len);
+         put_frame_register (frame, regnum, value_contents_raw (value),
+                             fromval);
+         release_value (value);
+       }
+
+      myaddr += curr_len;
+      len -= curr_len;
+      offset = 0;
+      regnum++;
+    }
+}
+
 void
 put_frame_register_bytes (struct frame_info *frame, int regnum,
                          CORE_ADDR offset, int len, const gdb_byte *myaddr)
index 3ceb7b32effaf9c7cc12905e67af2a6100bb2736..acf63851086ca00f1b128dcbdf0fa7a4d1d7b014 100644 (file)
@@ -617,6 +617,10 @@ extern void frame_register (struct frame_info *frame, int regnum,
 extern void put_frame_register (struct frame_info *frame, int regnum,
                                const gdb_byte *buf);
 
+/* Same as put_frame_register, but passing a struct value *.  */
+extern void put_frame_register (struct frame_info *frame, int regnum,
+                               const gdb_byte *buf, struct value *fromval);
+
 /* Read LEN bytes from one or multiple registers starting with REGNUM
    in frame FRAME, starting at OFFSET, into BUF.  If the register
    contents are optimized out or unavailable, set *OPTIMIZEDP,
@@ -632,6 +636,10 @@ extern void put_frame_register_bytes (struct frame_info *frame, int regnum,
                                      CORE_ADDR offset, int len,
                                      const gdb_byte *myaddr);
 
+/* Same as put_frame_register_bytes, but passing a struct value *.  */
+extern void put_frame_register_value (struct frame_info *frame, int regnum,
+                                     CORE_ADDR offset, struct value *fromval);
+
 /* Unwind the PC.  Strictly speaking return the resume address of the
    calling frame.  For GDB, `pc' is the resume address and not a
    specific register.  */
index a79d9bdfcf32b8046c113015f4bacf0f4a681f83..bc6c125b4142f8202b0a544db25194e0ec07b866 100644 (file)
@@ -243,6 +243,7 @@ struct gdbarch
   CORE_ADDR deprecated_function_start_offset;
   gdbarch_remote_register_number_ftype *remote_register_number;
   gdbarch_get_cap_tag_from_address_ftype *get_cap_tag_from_address;
+  gdbarch_set_cap_tag_from_address_ftype *set_cap_tag_from_address;
   gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address;
   gdbarch_get_thread_local_address_ftype *get_thread_local_address;
   CORE_ADDR frame_args_skip;
@@ -357,6 +358,7 @@ struct gdbarch
   gdbarch_read_core_file_mappings_ftype *read_core_file_mappings;
   gdbarch_register_has_tag_ftype *register_has_tag;
   gdbarch_register_tag_ftype *register_tag;
+  gdbarch_register_set_tag_ftype *register_set_tag;
 };
 
 /* Create a new ``struct gdbarch'' based on information provided by
@@ -432,6 +434,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint;
   gdbarch->remote_register_number = default_remote_register_number;
   gdbarch->get_cap_tag_from_address = default_get_cap_tag_from_address;
+  gdbarch->set_cap_tag_from_address = default_set_cap_tag_from_address;
   gdbarch->unwind_pc = default_unwind_pc;
   gdbarch->unwind_sp = default_unwind_sp;
   gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
@@ -478,6 +481,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->read_core_file_mappings = default_read_core_file_mappings;
   gdbarch->register_has_tag = default_register_has_tag;
   gdbarch->register_tag = default_register_tag;
+  gdbarch->register_set_tag = default_register_set_tag;
   /* gdbarch_alloc() */
 
   return gdbarch;
@@ -624,6 +628,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of deprecated_function_start_offset, invalid_p == 0 */
   /* Skip verify of remote_register_number, invalid_p == 0 */
   /* Skip verify of get_cap_tag_from_address, invalid_p == 0 */
+  /* Skip verify of set_cap_tag_from_address, invalid_p == 0 */
   /* Skip verify of fetch_tls_load_module_address, has predicate.  */
   /* Skip verify of get_thread_local_address, has predicate.  */
   /* Skip verify of frame_args_skip, invalid_p == 0 */
@@ -737,6 +742,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of read_core_file_mappings, invalid_p == 0 */
   /* Skip verify of register_has_tag, invalid_p == 0 */
   /* Skip verify of register_tag, invalid_p == 0 */
+  /* Skip verify of register_set_tag, invalid_p == 0 */
   if (!log.empty ())
     internal_error (__FILE__, __LINE__,
                     _("verify_gdbarch: the following are invalid ...%s"),
@@ -1348,6 +1354,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: register_reggroup_p = <%s>\n",
                       host_address_to_string (gdbarch->register_reggroup_p));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: register_set_tag = <%s>\n",
+                      host_address_to_string (gdbarch->register_set_tag));
   fprintf_unfiltered (file,
                       "gdbarch_dump: register_sim_regno = <%s>\n",
                       host_address_to_string (gdbarch->register_sim_regno));
@@ -1390,6 +1399,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: sdb_reg_to_regnum = <%s>\n",
                       host_address_to_string (gdbarch->sdb_reg_to_regnum));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: set_cap_tag_from_address = <%s>\n",
+                      host_address_to_string (gdbarch->set_cap_tag_from_address));
   fprintf_unfiltered (file,
                       "gdbarch_dump: short_bit = %s\n",
                       plongest (gdbarch->short_bit));
@@ -3107,6 +3119,23 @@ set_gdbarch_get_cap_tag_from_address (struct gdbarch *gdbarch,
   gdbarch->get_cap_tag_from_address = get_cap_tag_from_address;
 }
 
+void
+gdbarch_set_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr, bool tag)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->set_cap_tag_from_address != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_set_cap_tag_from_address called\n");
+  gdbarch->set_cap_tag_from_address (gdbarch, addr, tag);
+}
+
+void
+set_gdbarch_set_cap_tag_from_address (struct gdbarch *gdbarch,
+                                      gdbarch_set_cap_tag_from_address_ftype set_cap_tag_from_address)
+{
+  gdbarch->set_cap_tag_from_address = set_cap_tag_from_address;
+}
+
 int
 gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch)
 {
@@ -5362,6 +5391,23 @@ set_gdbarch_register_tag (struct gdbarch *gdbarch,
   gdbarch->register_tag = register_tag;
 }
 
+void
+gdbarch_register_set_tag (struct gdbarch *gdbarch, regcache *regcache, int cookednum, bool tag)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->register_set_tag != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_register_set_tag called\n");
+  gdbarch->register_set_tag (gdbarch, regcache, cookednum, tag);
+}
+
+void
+set_gdbarch_register_set_tag (struct gdbarch *gdbarch,
+                              gdbarch_register_set_tag_ftype register_set_tag)
+{
+  gdbarch->register_set_tag = register_set_tag;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules.  */
index 49c7f1c7a8d82f70e02c2b46e6b1f0ef9c9f0845..bbf1fe4e890ba2032239103296757bb4c22377d3 100644 (file)
@@ -645,6 +645,12 @@ typedef bool (gdbarch_get_cap_tag_from_address_ftype) (struct gdbarch *gdbarch,
 extern bool gdbarch_get_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr);
 extern void set_gdbarch_get_cap_tag_from_address (struct gdbarch *gdbarch, gdbarch_get_cap_tag_from_address_ftype *get_cap_tag_from_address);
 
+/* Set the tag from a capability stored at address ADDR to TAG. */
+
+typedef void (gdbarch_set_cap_tag_from_address_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr, bool tag);
+extern void gdbarch_set_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr, bool tag);
+extern void set_gdbarch_set_cap_tag_from_address (struct gdbarch *gdbarch, gdbarch_set_cap_tag_from_address_ftype *set_cap_tag_from_address);
+
 /* Fetch the target specific address used to represent a load module. */
 
 extern int gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch);
@@ -1683,6 +1689,12 @@ typedef bool (gdbarch_register_tag_ftype) (struct gdbarch *gdbarch, readable_reg
 extern bool gdbarch_register_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
 extern void set_gdbarch_register_tag (struct gdbarch *gdbarch, gdbarch_register_tag_ftype *register_tag);
 
+/* Sets the register tag to TAG. */
+
+typedef void (gdbarch_register_set_tag_ftype) (struct gdbarch *gdbarch, regcache *regcache, int cookednum, bool tag);
+extern void gdbarch_register_set_tag (struct gdbarch *gdbarch, regcache *regcache, int cookednum, bool tag);
+extern void set_gdbarch_register_set_tag (struct gdbarch *gdbarch, gdbarch_register_set_tag_ftype *register_set_tag);
+
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 
 
index 01d1a6972b2556241da422b931bdf59b48ba7463..2ce7c18d87f507e76f98e8de96ee2021fff56174 100755 (executable)
@@ -574,6 +574,9 @@ m;int;remote_register_number;int regno;regno;;default_remote_register_number;;0
 # Return the tag from a capability stored at address ADDR.
 m;bool;get_cap_tag_from_address;CORE_ADDR addr;addr;0;default_get_cap_tag_from_address;;0
 
+# Set the tag from a capability stored at address ADDR to TAG.
+m;void;set_cap_tag_from_address;CORE_ADDR addr, bool tag;addr, tag;0;default_set_cap_tag_from_address;;0
+
 # Fetch the target specific address used to represent a load module.
 F;CORE_ADDR;fetch_tls_load_module_address;struct objfile *objfile;objfile
 
@@ -1202,6 +1205,8 @@ m;bool;register_has_tag;readable_regcache *regcache, int cookednum;regcache, coo
 # Returns true if the register tag bit is 1 and false otherwise.
 # The default is to always return false.
 m;bool;register_tag;readable_regcache *regcache, int cookednum;regcache, cookednum;;default_register_tag;;0
+# Sets the register tag to TAG.
+m;void;register_set_tag;regcache *regcache, int cookednum, bool tag;regcache, cookednum, tag;;default_register_set_tag;;0
 
 EOF
 }
index 5fff3520e0db5970133199b5ba5b3aeb9a746490..80c287de8ef283b5f89b4324305a7b894addcc5c 100644 (file)
@@ -8451,6 +8451,7 @@ remote_target::store_registers (struct regcache *regcache, int regnum)
        return;
 
       store_registers_using_G (regcache);
+      fetch_registers_using_g (regcache);
       return;
     }
 
index d0f1a1ed60441c8cd32f74cbd325b446f1429ca3..d3339712e9f0578c92103adba665180dbedb97d6 100644 (file)
@@ -1175,10 +1175,9 @@ value_assign (struct value *toval, struct value *fromval)
              }
            else
              {
-               put_frame_register_bytes (frame, value_reg,
+               put_frame_register_value (frame, value_reg,
                                          value_offset (toval),
-                                         TYPE_LENGTH (type),
-                                         value_contents (fromval));
+                                         fromval);
              }
          }