]> 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)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:59:24 +0000 (15:59 -0700)
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-components.py
gdb/gdbarch-gen.h
gdb/gdbarch.c
gdb/remote.c
gdb/valops.c

index e5fdaa13d7157196fc1c9d797d4791017f84dba0..7e3a239e616302b2a7815659c70a4092e1a6e8a3 100644 (file)
@@ -2130,6 +2130,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);
+}
+
 /* Implement the maintenance print capability tag command.  */
 
 static void
@@ -2520,6 +2538,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);
 
       add_cmd ("cap_from_addr", class_maintenance,
               maint_print_cap_from_addr_cmd,
index 5e29e72169ff7e609a4f51f672494a0f21dcd828..14fbe1491fafb27c2d1aee21692be4ea7b2cf67c 100644 (file)
@@ -2025,11 +2025,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)
 {
   aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
 
@@ -2110,7 +2110,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",
@@ -2603,7 +2603,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).data ());
-      set_register_tag (gdbarch, regcache, regnum, value_tag (clr));
+      aarch64_register_set_tag (gdbarch, regcache, regnum, value_tag (clr));
     }
 
   if (aarch64_debug)
@@ -2634,7 +2634,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).data ());
-         set_register_tag (gdbarch, regcache, regnum, value_tag (csp));
+         aarch64_register_set_tag (gdbarch, regcache, regnum, value_tag (csp));
        }
 
       if (aarch64_debug)
@@ -2832,7 +2832,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).data ());
-      set_register_tag (gdbarch, regcache, regnum, value_tag (csp));
+      aarch64_register_set_tag (gdbarch, regcache, regnum, value_tag (csp));
     }
 
     if (aarch64_debug)
@@ -3777,7 +3777,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
@@ -3855,7 +3855,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",
@@ -4444,8 +4444,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;
     }
 
@@ -5780,6 +5780,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 66c19059db2fae6354a2886528d55c18f4810a13..f80384220330e0640868a1dd5b9a45c2a82647ba 100644 (file)
@@ -1110,6 +1110,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)
@@ -1117,6 +1126,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;
+}
+
 /* Static function declarations */
 
 static void alloc_gdbarch_data (struct gdbarch *);
index 90469d2cb6af6c5a72838e813f833870965d5494..53c8a8d77cf2d3ee11e923a1f034e744c128876f 100644 (file)
@@ -311,7 +311,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 ce95cf8343bc172d8242cda21e931fb02c211da0..d33ac9260a03c069e2073b55d78856daabe4f1ca 100644 (file)
@@ -1370,6 +1370,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)
@@ -1512,6 +1565,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).data ();
+
+  /* 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).data () + offset,
+                 myaddr, curr_len);
+         put_frame_register (frame, regnum, value_contents_raw (value).data (),
+                             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,
index b9a3793cc2330cad9c00cdfa936e3f7bd5644ede..b33b716abfff87f4e85edd7b23ec4c21c2cc4f68 100644 (file)
@@ -653,6 +653,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,
@@ -668,6 +672,10 @@ extern void put_frame_register_bytes (struct frame_info *frame, int regnum,
                                      CORE_ADDR offset,
                                      gdb::array_view<const gdb_byte> buffer);
 
+/* 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 663e056b0fd015fdf353ccc5e64d41b7ec31ea58..825a48e2f972a730304c4dd87bb693e5ddc2af45 100644 (file)
@@ -1034,6 +1034,17 @@ Return the tag from a capability stored at address ADDR.
     invalid=False,
 )
 
+Method(
+    comment="""
+Set the tag from a capability stored at address ADDR to TAG.
+""",
+    type="void",
+    name="set_cap_tag_from_address",
+    params=[("CORE_ADDR", "addr"), ("bool", "tag")],
+    predefault="default_set_cap_tag_from_address",
+    invalid=False,
+)
+
 Function(
     comment="""
 Fetch the target specific address used to represent a load module.
@@ -2710,3 +2721,18 @@ The default is to always return false.
     predefault="default_register_tag",
     invalid=False,
 )
+
+Method(
+    comment="""
+Sets the register tag to TAG.
+""",
+    type="void",
+    name="register_set_tag",
+    params=[
+        ("regcache *", "regcache"),
+        ("int", "cookednum"),
+        ("bool", "tag"),
+    ],
+    predefault="default_register_set_tag",
+    invalid=False,
+)
index 64f887e4dd65466f8cac17b638eb489fa582d353..4498bfcc84bc7da7a9cc74f422d0e8e996d2c410 100644 (file)
@@ -553,6 +553,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 bool gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch);
@@ -1661,3 +1667,9 @@ extern void set_gdbarch_register_has_tag (struct gdbarch *gdbarch, gdbarch_regis
 typedef bool (gdbarch_register_tag_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
 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);
index db62dd682a90e66dfab472c4bc1acd466c66ea2d..59e830e543dc8312a0806fbf5bf773c6e2988d9f 100644 (file)
@@ -131,6 +131,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;
@@ -255,6 +256,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
@@ -330,6 +332,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;
@@ -381,6 +384,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;
@@ -498,6 +502,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 */
@@ -623,6 +628,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"),
@@ -952,6 +958,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_filtered (file,
                       "gdbarch_dump: get_cap_tag_from_address = <%s>\n",
                       host_address_to_string (gdbarch->get_cap_tag_from_address));
+  fprintf_filtered (file,
+                      "gdbarch_dump: set_cap_tag_from_address = <%s>\n",
+                      host_address_to_string (gdbarch->set_cap_tag_from_address));
   fprintf_filtered (file,
                       "gdbarch_dump: gdbarch_fetch_tls_load_module_address_p() = %d\n",
                       gdbarch_fetch_tls_load_module_address_p (gdbarch));
@@ -1468,6 +1477,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_filtered (file,
                       "gdbarch_dump: register_tag = <%s>\n",
                       host_address_to_string (gdbarch->register_tag));
+  fprintf_filtered (file,
+                      "gdbarch_dump: register_set_tag = <%s>\n",
+                      host_address_to_string (gdbarch->register_set_tag));
   if (gdbarch->dump_tdep != NULL)
     gdbarch->dump_tdep (gdbarch, file);
 }
@@ -3015,6 +3027,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;
+}
+
 bool
 gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch)
 {
@@ -5462,3 +5491,20 @@ 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;
+}
index b941fbfdca47c90042553a81c3ea0485b00d9ae5..53208a89038347165a9952fcd5ce1c580ababc10 100644 (file)
@@ -8782,6 +8782,7 @@ remote_target::store_registers (struct regcache *regcache, int regnum)
        return;
 
       store_registers_using_G (regcache);
+      fetch_registers_using_g (regcache);
       return;
     }
 
index d1fe6d1024d359ef52f3e80e113b9d625cafd4aa..a0f2c31f34e8c34944b17c037f1d643d121ffcdd 100644 (file)
@@ -1268,9 +1268,9 @@ value_assign (struct value *toval, struct value *fromval)
                                           value_contents (fromval).data ());
              }
            else
-             put_frame_register_bytes (frame, value_reg,
+             put_frame_register_value (frame, value_reg,
                                        value_offset (toval),
-                                       value_contents (fromval));
+                                       fromval);
          }
 
        gdb::observers::register_changed.notify (frame, value_reg);