diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index d555465c2f96..12ec8294e4ee 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -349,19 +349,15 @@ amd64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
 
 static struct value *
 amd64_pseudo_register_read_value (struct gdbarch *gdbarch,
-				  readable_regcache *regcache,
+				  frame_info *next_frame,
 				  int regnum)
 {
   gdb_byte *raw_buf = (gdb_byte *) alloca (register_size (gdbarch, regnum));
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  enum register_status status;
-  struct value *result_value;
-  gdb_byte *buf;
-
-  result_value = allocate_value (register_type (gdbarch, regnum));
-  VALUE_LVAL (result_value) = lval_register;
-  VALUE_REGNUM (result_value) = regnum;
-  buf = value_contents_raw (result_value);
+  value *result_value
+    = allocate_register_value (gdbarch, regnum, next_frame);
+  gdb_byte *buf = value_contents_raw (result_value);
+  set_value_lazy (result_value, 0);
 
   if (i386_byte_regnum_p (gdbarch, regnum))
     {
@@ -371,37 +367,25 @@ amd64_pseudo_register_read_value (struct gdbarch *gdbarch,
       if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
 	{
 	  /* Special handling for AH, BH, CH, DH.  */
-	  status = regcache->raw_read (gpnum - AMD64_NUM_LOWER_BYTE_REGS,
-				       raw_buf);
-	  if (status == REG_VALID)
-	    memcpy (buf, raw_buf + 1, 1);
-	  else
-	    mark_value_bytes_unavailable (result_value, 0,
-					  TYPE_LENGTH (value_type (result_value)));
+	  frame_unwind_register (next_frame, gpnum - AMD64_NUM_LOWER_BYTE_REGS,
+				 raw_buf);
+	  memcpy (buf, raw_buf + 1, 1);
 	}
       else
 	{
-	  status = regcache->raw_read (gpnum, raw_buf);
-	  if (status == REG_VALID)
-	    memcpy (buf, raw_buf, 1);
-	  else
-	    mark_value_bytes_unavailable (result_value, 0,
-					  TYPE_LENGTH (value_type (result_value)));
+	  frame_unwind_register (next_frame, gpnum, raw_buf);
+	  memcpy (buf, raw_buf, 1);
 	}
     }
   else if (i386_dword_regnum_p (gdbarch, regnum))
     {
       int gpnum = regnum - tdep->eax_regnum;
       /* Extract (always little endian).  */
-      status = regcache->raw_read (gpnum, raw_buf);
-      if (status == REG_VALID)
-	memcpy (buf, raw_buf, 4);
-      else
-	mark_value_bytes_unavailable (result_value, 0,
-				      TYPE_LENGTH (value_type (result_value)));
+      frame_unwind_register (next_frame, gpnum, raw_buf);
+      memcpy (buf, raw_buf, 4);
     }
   else
-    i386_pseudo_register_read_into_value (gdbarch, regcache, regnum,
+    i386_pseudo_register_read_into_value (gdbarch, next_frame, regnum,
 					  result_value);
 
   return result_value;
@@ -409,7 +393,7 @@ amd64_pseudo_register_read_value (struct gdbarch *gdbarch,
 
 static void
 amd64_pseudo_register_write (struct gdbarch *gdbarch,
-			     struct regcache *regcache,
+			     frame_info *this_frame,
 			     int regnum, const gdb_byte *buf)
 {
   gdb_byte *raw_buf = (gdb_byte *) alloca (register_size (gdbarch, regnum));
@@ -422,22 +406,20 @@ amd64_pseudo_register_write (struct gdbarch *gdbarch,
       if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
 	{
 	  /* Read ... AH, BH, CH, DH.  */
-	  regcache_raw_read (regcache,
-			     gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf);
+	  get_frame_register (this_frame, gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf);
 	  /* ... Modify ... (always little endian).  */
 	  memcpy (raw_buf + 1, buf, 1);
 	  /* ... Write.  */
-	  regcache_raw_write (regcache,
-			      gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf);
+	  put_frame_register (this_frame, gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf);
 	}
       else
 	{
 	  /* Read ...  */
-	  regcache_raw_read (regcache, gpnum, raw_buf);
+	  get_frame_register (this_frame, gpnum, raw_buf);
 	  /* ... Modify ... (always little endian).  */
 	  memcpy (raw_buf, buf, 1);
 	  /* ... Write.  */
-	  regcache_raw_write (regcache, gpnum, raw_buf);
+	  put_frame_register (this_frame, gpnum, raw_buf);
 	}
     }
   else if (i386_dword_regnum_p (gdbarch, regnum))
@@ -445,14 +427,14 @@ amd64_pseudo_register_write (struct gdbarch *gdbarch,
       int gpnum = regnum - tdep->eax_regnum;
 
       /* Read ...  */
-      regcache_raw_read (regcache, gpnum, raw_buf);
+      get_frame_register (this_frame, gpnum, raw_buf);
       /* ... Modify ... (always little endian).  */
       memcpy (raw_buf, buf, 4);
       /* ... Write.  */
-      regcache_raw_write (regcache, gpnum, raw_buf);
+      put_frame_register (this_frame, gpnum, raw_buf);
     }
   else
-    i386_pseudo_register_write (gdbarch, regcache, regnum, buf);
+    i386_pseudo_register_write (gdbarch, this_frame, regnum, buf);
 }
 
 /* Implement the 'ax_pseudo_register_collect' gdbarch method.  */
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 382080a714b6..123ab9e2a03d 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -230,7 +230,7 @@ static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch,
 						readable_regcache *regcache,
 						int regnum, gdb_byte *buf);
 static void arm_neon_quad_write (struct gdbarch *gdbarch,
-				 struct regcache *regcache,
+				 frame_info *this_frame,
 				 int regnum, const gdb_byte *buf);
 
 static CORE_ADDR
@@ -3796,7 +3796,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 		  char name_buf[4];
 		  int regnum;
 		  if (reg_char == 'q')
-		    arm_neon_quad_write (gdbarch, regcache, reg_scaled + i,
+		    arm_neon_quad_write (gdbarch, get_current_frame (), reg_scaled + i,
 					 val + i * unit_length);
 		  else
 		    {
@@ -8198,7 +8198,7 @@ arm_return_value (struct gdbarch *gdbarch, struct value *function,
 	  if (reg_char == 'q')
 	    {
 	      if (writebuf)
-		arm_neon_quad_write (gdbarch, regcache, i,
+		arm_neon_quad_write (gdbarch, get_current_frame (), i,
 				     writebuf + i * unit_length);
 
 	      if (readbuf)
@@ -8749,7 +8749,7 @@ arm_pseudo_read (struct gdbarch *gdbarch, readable_regcache *regcache,
    of the quad register, in [0, 15].  */
 
 static void
-arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache,
+arm_neon_quad_write (struct gdbarch *gdbarch, frame_info *this_frame,
 		     int regnum, const gdb_byte *buf)
 {
   char name_buf[4];
@@ -8765,13 +8765,13 @@ arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache,
   else
     offset = 0;
 
-  regcache_raw_write (regcache, double_regnum, buf + offset);
+  put_frame_register (this_frame, double_regnum, buf + offset);
   offset = 8 - offset;
-  regcache_raw_write (regcache, double_regnum + 1, buf + offset);
+  put_frame_register (this_frame, double_regnum + 1, buf + offset);
 }
 
 static void
-arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
+arm_pseudo_write (struct gdbarch *gdbarch, frame_info *this_frame,
 		  int regnum, const gdb_byte *buf)
 {
   const int num_regs = gdbarch_num_regs (gdbarch);
@@ -8784,7 +8784,7 @@ arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
 
   if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
     /* Quad-precision register.  */
-    arm_neon_quad_write (gdbarch, regcache, regnum - 32, buf);
+    arm_neon_quad_write (gdbarch, this_frame, regnum - 32, buf);
   else
     {
       /* Single-precision register.  */
@@ -8800,9 +8800,9 @@ arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
       double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
 						   strlen (name_buf));
 
-      regcache_raw_read (regcache, double_regnum, reg_buf);
+      get_frame_register (this_frame, double_regnum, reg_buf);
       memcpy (reg_buf + offset, buf, 4);
-      regcache_raw_write (regcache, double_regnum, reg_buf);
+      put_frame_register (this_frame, double_regnum, reg_buf);
     }
 }
 
diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c
index 5aa61ba2d9e7..d1addbad72b3 100644
--- a/gdb/avr-tdep.c
+++ b/gdb/avr-tdep.c
@@ -404,18 +404,23 @@ avr_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache,
 }
 
 static void
-avr_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+avr_pseudo_register_write (struct gdbarch *gdbarch, frame_info *this_frame,
                            int regnum, const gdb_byte *buf)
 {
-  ULONGEST val;
-
   switch (regnum)
     {
     case AVR_PSEUDO_PC_REGNUM:
-      val = extract_unsigned_integer (buf, 4, gdbarch_byte_order (gdbarch));
-      val <<= 1;
-      regcache_raw_write_unsigned (regcache, AVR_PC_REGNUM, val);
-      break;
+      {
+	bfd_endian endianness = gdbarch_byte_order (gdbarch);
+	ULONGEST val = extract_unsigned_integer (buf, 4, endianness);
+	val <<= 1;
+
+	int pc_size = register_size (gdbarch, AVR_PC_REGNUM);
+	gdb_byte pc_buf[pc_size];
+	store_unsigned_integer (pc_buf, pc_size, endianness, val);
+	put_frame_register (this_frame, AVR_PC_REGNUM, pc_buf);
+	break;
+      }
     default:
       internal_error (__FILE__, __LINE__, _("invalid regnum"));
     }
diff --git a/gdb/frame.c b/gdb/frame.c
index c0f6e64dfc25..0181655b2d60 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1183,29 +1183,48 @@ get_frame_register (struct frame_info *frame,
 }
 
 struct value *
-frame_unwind_register_value (struct frame_info *frame, int regnum)
+frame_unwind_register_value (struct frame_info *next_frame, int regnum)
 {
-  struct gdbarch *gdbarch;
-  struct value *value;
+  gdb_assert (next_frame != NULL);
 
-  gdb_assert (frame != NULL);
-  gdbarch = frame_unwind_arch (frame);
+  struct gdbarch *gdbarch = frame_unwind_arch (next_frame);
+
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch)));
 
   if (frame_debug)
     {
       fprintf_unfiltered (gdb_stdlog,
 			  "{ frame_unwind_register_value "
 			  "(frame=%d,regnum=%d(%s),...) ",
-			  frame->level, regnum,
+			  next_frame->level, regnum,
 			  user_reg_map_regnum_to_name (gdbarch, regnum));
     }
 
   /* Find the unwinder.  */
-  if (frame->unwind == NULL)
-    frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+  if (next_frame->unwind == NULL)
+    frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache);
 
-  /* Ask this frame to unwind its register.  */
-  value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum);
+  struct value *value;
+  if (regnum < gdbarch_num_regs (gdbarch))
+    {
+      /* This is a raw register, we can directly ask the next frame to unwind
+         the register.  */
+      value = next_frame->unwind->prev_register (next_frame,
+						 &next_frame->prologue_cache,
+						 regnum);
+    }
+  else if (gdbarch_pseudo_register_read_value_p (gdbarch))
+    {
+      /* This is a pseudo register, we don't know how how what raw registers
+         this pseudo register is made of.  Ask the gdbarch to read the value,
+         it will itself ask the next frame to unwind the values of the raw
+         registers it needs to compose the value of the pseudo register.  */
+      value = gdbarch_pseudo_register_read_value (gdbarch, next_frame, regnum);
+    }
+  else
+    error (_("Can't unwind value of register %d (%s)"), regnum,
+	   user_reg_map_regnum_to_name (gdbarch, regnum));
 
   if (frame_debug)
     {
@@ -1353,22 +1372,36 @@ put_frame_register (struct frame_info *frame, int regnum,
   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."));
-  switch (lval)
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch)));
+
+  if (regnum < gdbarch_num_regs (gdbarch))
     {
-    case lval_memory:
-      {
-	write_memory (addr, buf, register_size (gdbarch, regnum));
-	break;
-      }
-    case lval_register:
-      regcache_cooked_write (get_current_regcache (), realnum, buf);
-      break;
-    default:
-      error (_("Attempt to assign to an unmodifiable value."));
+      /* This is a raw register, we can find directly where it is saved
+         currently and update it.  */
+      frame_register (frame, regnum, &optim, &unavail,
+		      &lval, &addr, &realnum, NULL);
+      if (optim)
+	error (_("Attempt to assign to a register that was not saved."));
+      switch (lval)
+	{
+	case lval_memory:
+	  {
+	    write_memory (addr, buf, register_size (gdbarch, regnum));
+	    break;
+	  }
+	case lval_register:
+	  regcache_cooked_write (get_current_regcache (), realnum, buf);
+	  break;
+	default:
+	  error (_("Attempt to assign to an unmodifiable value."));
+	}
+    }
+  else
+    {
+      /* This is a pseudo-register, the arch will find out which raw registers
+         to modify and update them.  */
+      gdbarch_pseudo_register_write (gdbarch, frame, regnum, buf);
     }
 }
 
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index c430ebe52a4f..a284a4bfc298 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -1979,13 +1979,13 @@ gdbarch_pseudo_register_read_value_p (struct gdbarch *gdbarch)
 }
 
 struct value *
-gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum)
+gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->pseudo_register_read_value != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_pseudo_register_read_value called\n");
-  return gdbarch->pseudo_register_read_value (gdbarch, regcache, cookednum);
+  return gdbarch->pseudo_register_read_value (gdbarch, this_frame, cookednum);
 }
 
 void
@@ -2003,13 +2003,13 @@ gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch)
 }
 
 void
-gdbarch_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const gdb_byte *buf)
+gdbarch_pseudo_register_write (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum, const gdb_byte *buf)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->pseudo_register_write != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_pseudo_register_write called\n");
-  gdbarch->pseudo_register_write (gdbarch, regcache, cookednum, buf);
+  gdbarch->pseudo_register_write (gdbarch, this_frame, cookednum, buf);
 }
 
 void
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 09edcd5eb282..4a315bb8eb24 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -271,14 +271,14 @@ extern void set_gdbarch_pseudo_register_read (struct gdbarch *gdbarch, gdbarch_p
 
 extern int gdbarch_pseudo_register_read_value_p (struct gdbarch *gdbarch);
 
-typedef struct value * (gdbarch_pseudo_register_read_value_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
-extern struct value * gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+typedef struct value * (gdbarch_pseudo_register_read_value_ftype) (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum);
+extern struct value * gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum);
 extern void set_gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, gdbarch_pseudo_register_read_value_ftype *pseudo_register_read_value);
 
 extern int gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch);
 
-typedef void (gdbarch_pseudo_register_write_ftype) (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const gdb_byte *buf);
-extern void gdbarch_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const gdb_byte *buf);
+typedef void (gdbarch_pseudo_register_write_ftype) (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum, const gdb_byte *buf);
+extern void gdbarch_pseudo_register_write (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum, const gdb_byte *buf);
 extern void set_gdbarch_pseudo_register_write (struct gdbarch *gdbarch, gdbarch_pseudo_register_write_ftype *pseudo_register_write);
 
 extern int gdbarch_num_regs (struct gdbarch *gdbarch);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 733043093742..5a1b53ee9d1b 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -431,8 +431,8 @@ M;enum register_status;pseudo_register_read;readable_regcache *regcache, int coo
 # or partly unavailable, this should call mark_value_bytes_unavailable
 # as appropriate.  If this is defined, then pseudo_register_read will
 # never be called.
-M;struct value *;pseudo_register_read_value;readable_regcache *regcache, int cookednum;regcache, cookednum
-M;void;pseudo_register_write;struct regcache *regcache, int cookednum, const gdb_byte *buf;regcache, cookednum, buf
+M;struct value *;pseudo_register_read_value;frame_info *next_frame, int cookednum;next_frame, cookednum
+M;void;pseudo_register_write;frame_info *this_frame, int cookednum, const gdb_byte *buf;this_frame, cookednum, buf
 #
 v;int;num_regs;;;0;-1
 # This macro gives the number of pseudo-registers that live in the
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 646f305edc51..73a87a613f7d 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -3249,17 +3249,14 @@ i386_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
    the MMX registers need to be mapped onto floating point registers.  */
 
 static int
-i386_mmx_regnum_to_fp_regnum (readable_regcache *regcache, int regnum)
+i386_mmx_regnum_to_fp_regnum (frame_info *next_frame, int regnum)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
-  int mmxreg, fpreg;
-  ULONGEST fstat;
-  int tos;
-
-  mmxreg = regnum - tdep->mm0_regnum;
-  regcache->raw_read (I387_FSTAT_REGNUM (tdep), &fstat);
-  tos = (fstat >> 11) & 0x7;
-  fpreg = (mmxreg + tos) % 8;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+  int mmxreg = regnum - tdep->mm0_regnum;
+  ULONGEST fstat
+    = frame_unwind_register_unsigned (next_frame, I387_FSTAT_REGNUM (tdep));
+  int tos = (fstat >> 11) & 0x7;
+  int fpreg = (mmxreg + tos) % 8;
 
   return (I387_ST0_REGNUM (tdep) + fpreg);
 }
@@ -3270,25 +3267,20 @@ i386_mmx_regnum_to_fp_regnum (readable_regcache *regcache, int regnum)
 
 void
 i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
-				      readable_regcache *regcache,
+				      frame_info *next_frame,
 				      int regnum,
 				      struct value *result_value)
 {
   gdb_byte raw_buf[I386_MAX_REGISTER_SIZE];
-  enum register_status status;
   gdb_byte *buf = value_contents_raw (result_value);
 
   if (i386_mmx_regnum_p (gdbarch, regnum))
     {
-      int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
+      int fpnum = i386_mmx_regnum_to_fp_regnum (next_frame, regnum);
 
       /* Extract (always little endian).  */
-      status = regcache->raw_read (fpnum, raw_buf);
-      if (status != REG_VALID)
-	mark_value_bytes_unavailable (result_value, 0,
-				      TYPE_LENGTH (value_type (result_value)));
-      else
-	memcpy (buf, raw_buf, register_size (gdbarch, regnum));
+      frame_unwind_register (next_frame, fpnum, raw_buf);
+      memcpy (buf, raw_buf, register_size (gdbarch, regnum));
     }
   else
     {
@@ -3298,34 +3290,26 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
 	  regnum -= tdep->bnd0_regnum;
 
 	  /* Extract (always little endian).  Read lower 128bits.  */
-	  status = regcache->raw_read (I387_BND0R_REGNUM (tdep) + regnum,
-				       raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 0, 16);
-	  else
-	    {
-	      enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
-	      LONGEST upper, lower;
-	      int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);
+	  frame_unwind_register (next_frame, I387_BND0R_REGNUM (tdep) + regnum, raw_buf);
 
-	      lower = extract_unsigned_integer (raw_buf, 8, byte_order);
-	      upper = extract_unsigned_integer (raw_buf + 8, 8, byte_order);
-	      upper = ~upper;
+	  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+	  LONGEST upper, lower;
+	  int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);
 
-	      memcpy (buf, &lower, size);
-	      memcpy (buf + size, &upper, size);
-	    }
+	  lower = extract_unsigned_integer (raw_buf, 8, byte_order);
+	  upper = extract_unsigned_integer (raw_buf + 8, 8, byte_order);
+	  upper = ~upper;
+
+	  memcpy (buf, &lower, size);
+	  memcpy (buf + size, &upper, size);
 	}
       else if (i386_k_regnum_p (gdbarch, regnum))
 	{
 	  regnum -= tdep->k0_regnum;
 
 	  /* Extract (always little endian).  */
-	  status = regcache->raw_read (tdep->k0_regnum + regnum, raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 0, 8);
-	  else
-	    memcpy (buf, raw_buf, 8);
+	  frame_unwind_register (next_frame, tdep->k0_regnum + regnum, raw_buf);
+	  memcpy (buf, raw_buf, 8);
 	}
       else if (i386_zmm_regnum_p (gdbarch, regnum))
 	{
@@ -3334,98 +3318,57 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
 	  if (regnum < num_lower_zmm_regs)
 	    {
 	      /* Extract (always little endian).  Read lower 128bits.  */
-	      status = regcache->raw_read (I387_XMM0_REGNUM (tdep) + regnum,
-					   raw_buf);
-	      if (status != REG_VALID)
-		mark_value_bytes_unavailable (result_value, 0, 16);
-	      else
-		memcpy (buf, raw_buf, 16);
+	      frame_unwind_register (next_frame, I387_XMM0_REGNUM (tdep) + regnum, raw_buf);
+	      memcpy (buf, raw_buf, 16);
 
 	      /* Extract (always little endian).  Read upper 128bits.  */
-	      status = regcache->raw_read (tdep->ymm0h_regnum + regnum,
-					   raw_buf);
-	      if (status != REG_VALID)
-		mark_value_bytes_unavailable (result_value, 16, 16);
-	      else
-		memcpy (buf + 16, raw_buf, 16);
+	      frame_unwind_register (next_frame, tdep->ymm0h_regnum + regnum, raw_buf);
+	      memcpy (buf + 16, raw_buf, 16);
 	    }
 	  else
 	    {
 	      /* Extract (always little endian).  Read lower 128bits.  */
-	      status = regcache->raw_read (I387_XMM16_REGNUM (tdep) + regnum
-					   - num_lower_zmm_regs,
-					   raw_buf);
-	      if (status != REG_VALID)
-		mark_value_bytes_unavailable (result_value, 0, 16);
-	      else
-		memcpy (buf, raw_buf, 16);
+	      frame_unwind_register (next_frame, I387_XMM16_REGNUM (tdep) + regnum, raw_buf);
+	      memcpy (buf, raw_buf, 16);
 
 	      /* Extract (always little endian).  Read upper 128bits.  */
-	      status = regcache->raw_read (I387_YMM16H_REGNUM (tdep) + regnum
-					   - num_lower_zmm_regs,
-					   raw_buf);
-	      if (status != REG_VALID)
-		mark_value_bytes_unavailable (result_value, 16, 16);
-	      else
-		memcpy (buf + 16, raw_buf, 16);
+	      frame_unwind_register (next_frame, I387_YMM16H_REGNUM (tdep) + regnum, raw_buf);
+	      memcpy (buf + 16, raw_buf, 16);
 	    }
 
 	  /* Read upper 256bits.  */
-	  status = regcache->raw_read (tdep->zmm0h_regnum + regnum,
-				       raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 32, 32);
-	  else
-	    memcpy (buf + 32, raw_buf, 32);
+	  frame_unwind_register (next_frame, tdep->zmm0h_regnum + regnum, raw_buf);
+	  memcpy (buf + 32, raw_buf, 32);
 	}
       else if (i386_ymm_regnum_p (gdbarch, regnum))
 	{
 	  regnum -= tdep->ymm0_regnum;
 
 	  /* Extract (always little endian).  Read lower 128bits.  */
-	  status = regcache->raw_read (I387_XMM0_REGNUM (tdep) + regnum,
-				       raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 0, 16);
-	  else
-	    memcpy (buf, raw_buf, 16);
+	  frame_unwind_register (next_frame, I387_XMM0_REGNUM (tdep) + regnum, raw_buf);
+	  memcpy (buf, raw_buf, 16);
+
 	  /* Read upper 128bits.  */
-	  status = regcache->raw_read (tdep->ymm0h_regnum + regnum,
-				       raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 16, 32);
-	  else
-	    memcpy (buf + 16, raw_buf, 16);
+	  frame_unwind_register (next_frame, tdep->ymm0h_regnum + regnum, raw_buf);
+	  memcpy (buf + 16, raw_buf, 16);
 	}
       else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
 	{
 	  regnum -= tdep->ymm16_regnum;
 	  /* Extract (always little endian).  Read lower 128bits.  */
-	  status = regcache->raw_read (I387_XMM16_REGNUM (tdep) + regnum,
-				       raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 0, 16);
-	  else
-	    memcpy (buf, raw_buf, 16);
+	  frame_unwind_register (next_frame, I387_XMM16_REGNUM (tdep) + regnum, raw_buf);
+	  memcpy (buf, raw_buf, 16);
 	  /* Read upper 128bits.  */
-	  status = regcache->raw_read (tdep->ymm16h_regnum + regnum,
-				       raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 16, 16);
-	  else
-	    memcpy (buf + 16, raw_buf, 16);
+	  frame_unwind_register (next_frame, tdep->ymm16h_regnum + regnum, raw_buf);
+	  memcpy (buf + 16, raw_buf, 16);
 	}
       else if (i386_word_regnum_p (gdbarch, regnum))
 	{
 	  int gpnum = regnum - tdep->ax_regnum;
 
 	  /* Extract (always little endian).  */
-	  status = regcache->raw_read (gpnum, raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 0,
-					  TYPE_LENGTH (value_type (result_value)));
-	  else
-	    memcpy (buf, raw_buf, 2);
+	  frame_unwind_register (next_frame, gpnum, raw_buf);
+	  memcpy (buf, raw_buf, 2);
 	}
       else if (i386_byte_regnum_p (gdbarch, regnum))
 	{
@@ -3433,11 +3376,8 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
 
 	  /* Extract (always little endian).  We read both lower and
 	     upper registers.  */
-	  status = regcache->raw_read (gpnum % 4, raw_buf);
-	  if (status != REG_VALID)
-	    mark_value_bytes_unavailable (result_value, 0,
-					  TYPE_LENGTH (value_type (result_value)));
-	  else if (gpnum >= 4)
+	  frame_unwind_register (next_frame, gpnum % 4, raw_buf);
+	  if (gpnum >= 4)
 	    memcpy (buf, raw_buf + 1, 1);
 	  else
 	    memcpy (buf, raw_buf, 1);
@@ -3449,36 +3389,34 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
 
 static struct value *
 i386_pseudo_register_read_value (struct gdbarch *gdbarch,
-				 readable_regcache *regcache,
+				 frame_info *next_frame,
 				 int regnum)
 {
-  struct value *result;
-
-  result = allocate_value (register_type (gdbarch, regnum));
-  VALUE_LVAL (result) = lval_register;
-  VALUE_REGNUM (result) = regnum;
+  struct value *result = allocate_register_value (gdbarch, regnum, next_frame);
+  set_value_lazy (result, 0);
 
-  i386_pseudo_register_read_into_value (gdbarch, regcache, regnum, result);
+  i386_pseudo_register_read_into_value (gdbarch, next_frame, regnum, result);
 
   return result;
 }
 
 void
-i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+i386_pseudo_register_write (struct gdbarch *gdbarch, frame_info *this_frame,
 			    int regnum, const gdb_byte *buf)
 {
   gdb_byte raw_buf[I386_MAX_REGISTER_SIZE];
 
   if (i386_mmx_regnum_p (gdbarch, regnum))
     {
-      int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
+      frame_info *next_frame = get_next_frame_sentinel_okay (this_frame);
+      int fpnum = i386_mmx_regnum_to_fp_regnum (next_frame, regnum);
 
       /* Read ...  */
-      regcache_raw_read (regcache, fpnum, raw_buf);
+      get_frame_register (this_frame, fpnum, raw_buf);
       /* ... Modify ... (always little endian).  */
       memcpy (raw_buf, buf, register_size (gdbarch, regnum));
       /* ... Write.  */
-      regcache_raw_write (regcache, fpnum, raw_buf);
+      put_frame_register (this_frame, fpnum, raw_buf);
     }
   else
     {
@@ -3496,9 +3434,9 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
 	  upper = extract_unsigned_integer (buf + size, size, byte_order);
 
 	  /* Fetching register buffer.  */
-	  regcache_raw_read (regcache,
-			     I387_BND0R_REGNUM (tdep) + regnum,
-			     raw_buf);
+	  get_frame_register (this_frame,
+			      I387_BND0R_REGNUM (tdep) + regnum,
+			      raw_buf);
 
 	  upper = ~upper;
 
@@ -3506,8 +3444,7 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
 	  memcpy (raw_buf, &lower, 8);
 	  memcpy (raw_buf + 8, &upper, 8);
 
-
-	  regcache_raw_write (regcache,
+	  put_frame_register (this_frame,
 			      I387_BND0R_REGNUM (tdep) + regnum,
 			      raw_buf);
 	}
@@ -3515,7 +3452,7 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
 	{
 	  regnum -= tdep->k0_regnum;
 
-	  regcache_raw_write (regcache,
+	  put_frame_register (this_frame,
 			      tdep->k0_regnum + regnum,
 			      buf);
 	}
@@ -3526,29 +3463,29 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
 	  if (regnum < num_lower_zmm_regs)
 	    {
 	      /* Write lower 128bits.  */
-	      regcache_raw_write (regcache,
+	      put_frame_register (this_frame,
 				  I387_XMM0_REGNUM (tdep) + regnum,
 				  buf);
 	      /* Write upper 128bits.  */
-	      regcache_raw_write (regcache,
+	      put_frame_register (this_frame,
 				  I387_YMM0_REGNUM (tdep) + regnum,
 				  buf + 16);
 	    }
 	  else
 	    {
 	      /* Write lower 128bits.  */
-	      regcache_raw_write (regcache,
+	      put_frame_register (this_frame,
 				  I387_XMM16_REGNUM (tdep) + regnum
 				  - num_lower_zmm_regs,
 				  buf);
 	      /* Write upper 128bits.  */
-	      regcache_raw_write (regcache,
+	      put_frame_register (this_frame,
 				  I387_YMM16H_REGNUM (tdep) + regnum
 				  - num_lower_zmm_regs,
 				  buf + 16);
 	    }
 	  /* Write upper 256bits.  */
-	  regcache_raw_write (regcache,
+	  put_frame_register (this_frame,
 			      tdep->zmm0h_regnum + regnum,
 			      buf + 32);
 	}
@@ -3557,11 +3494,11 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
 	  regnum -= tdep->ymm0_regnum;
 
 	  /* ... Write lower 128bits.  */
-	  regcache_raw_write (regcache,
+	  put_frame_register (this_frame,
 			     I387_XMM0_REGNUM (tdep) + regnum,
 			     buf);
 	  /* ... Write upper 128bits.  */
-	  regcache_raw_write (regcache,
+	  put_frame_register (this_frame,
 			     tdep->ymm0h_regnum + regnum,
 			     buf + 16);
 	}
@@ -3570,11 +3507,11 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
 	  regnum -= tdep->ymm16_regnum;
 
 	  /* ... Write lower 128bits.  */
-	  regcache_raw_write (regcache,
+	  put_frame_register (this_frame,
 			      I387_XMM16_REGNUM (tdep) + regnum,
 			      buf);
 	  /* ... Write upper 128bits.  */
-	  regcache_raw_write (regcache,
+	  put_frame_register (this_frame,
 			      tdep->ymm16h_regnum + regnum,
 			      buf + 16);
 	}
@@ -3583,25 +3520,25 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
 	  int gpnum = regnum - tdep->ax_regnum;
 
 	  /* Read ...  */
-	  regcache_raw_read (regcache, gpnum, raw_buf);
+	  get_frame_register (this_frame, gpnum, raw_buf);
 	  /* ... Modify ... (always little endian).  */
 	  memcpy (raw_buf, buf, 2);
 	  /* ... Write.  */
-	  regcache_raw_write (regcache, gpnum, raw_buf);
+	  put_frame_register (this_frame, gpnum, raw_buf);
 	}
       else if (i386_byte_regnum_p (gdbarch, regnum))
 	{
 	  int gpnum = regnum - tdep->al_regnum;
 
 	  /* Read ...  We read both lower and upper registers.  */
-	  regcache_raw_read (regcache, gpnum % 4, raw_buf);
+	  get_frame_register (this_frame, gpnum % 4, raw_buf);
 	  /* ... Modify ... (always little endian).  */
 	  if (gpnum >= 4)
 	    memcpy (raw_buf + 1, buf, 1);
 	  else
 	    memcpy (raw_buf, buf, 1);
 	  /* ... Write.  */
-	  regcache_raw_write (regcache, gpnum % 4, raw_buf);
+	  put_frame_register (this_frame, gpnum % 4, raw_buf);
 	}
       else
 	internal_error (__FILE__, __LINE__, _("invalid regnum"));
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 81a93f11af5a..238bb1f533cd 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -364,12 +364,12 @@ extern struct type *i386_pseudo_register_type (struct gdbarch *gdbarch,
 					       int regnum);
 
 extern void i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
-						  readable_regcache *regcache,
+						  frame_info *next_frame,
 						  int regnum,
 						  struct value *result);
 
 extern void i386_pseudo_register_write (struct gdbarch *gdbarch,
-					struct regcache *regcache,
+					frame_info *this_frame,
 					int regnum, const gdb_byte *buf);
 
 extern int i386_ax_pseudo_register_collect (struct gdbarch *gdbarch,
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 83bcbd22a374..c6c6330bcec6 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -663,7 +663,7 @@ readable_regcache::cooked_read (int regnum, gdb_byte *buf)
       mark = value_mark ();
 
       computed = gdbarch_pseudo_register_read_value (m_descr->gdbarch,
-						     this, regnum);
+						     frame_find_by_id (sentinel_frame_id), regnum);
       if (value_entirely_available (computed))
 	memcpy (buf, value_contents_raw (computed),
 		m_descr->sizeof_register[regnum]);
@@ -716,7 +716,7 @@ readable_regcache::cooked_read_value (int regnum)
     }
   else
     return gdbarch_pseudo_register_read_value (m_descr->gdbarch,
-					       this, regnum);
+					       frame_find_by_id (sentinel_frame_id), regnum);
 }
 
 enum register_status
@@ -838,7 +838,7 @@ regcache::cooked_write (int regnum, const gdb_byte *buf)
   if (regnum < num_raw_registers ())
     raw_write (regnum, buf);
   else
-    gdbarch_pseudo_register_write (m_descr->gdbarch, this,
+    gdbarch_pseudo_register_write (m_descr->gdbarch, get_current_frame (),
 				   regnum, buf);
 }
 
@@ -1598,6 +1598,8 @@ cooked_read_test (struct gdbarch *gdbarch)
   scoped_restore restore_inferior_ptid
     = make_scoped_restore (&inferior_ptid, mock_ptid);
 
+  frame_info *f = get_current_frame ();
+
   /* Test that read one raw register from regcache_no_target will go
      to the target layer.  */
   int regnum;
@@ -1609,7 +1611,9 @@ cooked_read_test (struct gdbarch *gdbarch)
 	break;
     }
 
-  readwrite_regcache readwrite (gdbarch);
+  //readwrite_regcache readwrite (gdbarch);
+  regcache *r = get_thread_regcache (mock_ptid);
+  regcache &readwrite = *r;
   gdb::def_vector<gdb_byte> buf (register_size (gdbarch, regnum));
 
   readwrite.raw_read (regnum, buf.data ());
@@ -1731,12 +1735,29 @@ cooked_write_test (struct gdbarch *gdbarch)
   if (target_stack->to_stratum >= process_stratum)
     error (_("target already pushed"));
 
-  /* Create a mock environment.  A process_stratum target pushed.  */
-
   target_ops_no_register mock_target;
+  ptid_t mock_ptid (1, 1);
+  inferior mock_inferior (mock_ptid.pid ());
+  address_space mock_aspace
+    { };
+  mock_inferior.gdbarch = gdbarch;
+  mock_inferior.aspace = &mock_aspace;
+  thread_info mock_thread (&mock_inferior, mock_ptid);
+
+  scoped_restore restore_thread_list = make_scoped_restore (&thread_list,
+							    &mock_thread);
+
+  /* Add the mock inferior to the inferior list so that look ups by
+   target+ptid can find it.  */
+  scoped_restore restore_inferior_list = make_scoped_restore (&inferior_list);
+  inferior_list = &mock_inferior;
+
+  /* Switch to the mock inferior.  */
+  scoped_restore_current_inferior restore_current_inferior;
+  set_current_inferior (&mock_inferior);
 
   /* Push the process_stratum target so we can mock accessing
-     registers.  */
+   registers.  */
   push_target (&mock_target);
 
   /* Pop it again on exit (return/exception).  */
@@ -1748,7 +1769,15 @@ cooked_write_test (struct gdbarch *gdbarch)
     }
   } pop_targets;
 
-  readwrite_regcache readwrite (gdbarch);
+  /* Switch to the mock thread.  */
+  scoped_restore restore_inferior_ptid = make_scoped_restore (&inferior_ptid,
+							      mock_ptid);
+
+  frame_info *f = get_current_frame ();
+
+
+  regcache *r = get_thread_regcache (mock_ptid);
+  regcache &readwrite = *r;
 
   const int num_regs = (gdbarch_num_regs (gdbarch)
 			+ gdbarch_num_pseudo_regs (gdbarch));
diff --git a/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S
new file mode 100644
index 000000000000..390de7c32692
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S
@@ -0,0 +1,43 @@
+.global callee
+callee:
+.cfi_startproc
+	push %rbp
+.cfi_def_cfa rbp, 16
+	mov %rsp, %rbp
+
+	# Save caller's rbx value on the stack.
+.cfi_offset rbx, -24
+	push %rbx
+
+	# Put our own rbx value.
+	mov $0x2021222324252627, %rbx
+break_here_asm:
+
+	pop %rbx
+	pop %rbp	
+	ret
+.cfi_endproc
+
+
+.global caller
+caller:
+.cfi_startproc
+	push %rbp
+.cfi_def_cfa_offset 16
+	mov %rsp, %rbp
+
+	# Save caller's rbx value on the stack.
+.cfi_offset rbx, -24
+	push %rbx
+
+	# Put our own rbx value.
+	mov $0x1011121314151617, %rbx
+	call callee
+	
+	# Return the value we put in rbx.
+	mov %rbx, %rax
+
+	pop %rbx
+	pop %rbp
+	ret
+.cfi_endproc
diff --git a/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.c b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.c
new file mode 100644
index 000000000000..c4553f844e9f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.c
@@ -0,0 +1,33 @@
+/* Copyright 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+
+uint64_t caller (void);
+
+static void
+break_here_c (uint64_t value)
+{
+}
+
+int
+main (void)
+{
+  uint64_t value = caller ();
+  break_here_c (value);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.exp b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.exp
new file mode 100644
index 000000000000..619f44405e82
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.exp
@@ -0,0 +1,81 @@
+# Copyright 2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping amd64 pseudo register unwind."
+    return
+}
+
+standard_testfile amd64-pseudo-unwind.c amd64-pseudo-unwind-asm.S
+
+if { [prepare_for_testing "failed to prepare" ${testfile} "${srcfile} ${srcfile2}" {debug}] } {
+    return -1
+}
+
+clean_restart ${binfile}
+
+if ![runto_main] then {
+    fail "could not run to main"
+}
+
+gdb_breakpoint break_here_asm temporary
+gdb_continue_to_breakpoint "continue to callee"
+
+# Verify the value of rbx/ebx in the inner frame (callee)
+with_test_prefix "callee, before change" {
+    gdb_test "p/x \$rbx" " = 0x2021222324252627"
+    gdb_test "p/x \$ebx" " = 0x24252627"
+}
+
+# Verify that we can change the value of the pseudo register (ebx) in the inner frame (callee)
+gdb_test_no_output "set \$ebx = 0x34353637"
+
+with_test_prefix "callee, after change" {
+    # Verify the value of rbx/ebx in the inner frame (callee) after the change
+    gdb_test "p/x \$rbx" " = 0x2021222334353637"
+    gdb_test "p/x \$ebx" " = 0x34353637"
+}
+
+# Go up one frame, and do the same
+gdb_test "up"
+
+# Verify the value of rbx/ebx in the outer frame (caller)
+with_test_prefix "caller, before change" {
+    gdb_test "p/x \$rbx" " = 0x1011121314151617"
+    gdb_test "p/x \$ebx" " = 0x14151617"
+}
+
+# Verify that we can change the value of the pseudo register (ebx) in the outer frame (caller)
+gdb_test_no_output "set \$ebx = 0x44454647"
+
+# Verify the value of rbx/ebx in the outer frame (caller) after the change
+with_test_prefix "caller, after change" {
+    gdb_test "p/x \$rbx" " = 0x1011121344454647"
+    gdb_test "p/x \$ebx" " = 0x44454647"
+}
+
+# Go back to frame 0, check that the change to the outer frame didn't mess up anything there.
+gdb_test "down"
+
+with_test_prefix "callee, after change in caller" {
+    gdb_test "p/x \$rbx" " = 0x2021222334353637"
+    gdb_test "p/x \$ebx" " = 0x34353637"
+}
+
+# Verify that the value of the saved rbx we changed is correctly seen by the inferior.
+gdb_breakpoint break_here_c temporary
+gdb_continue_to_breakpoint "continue to break_here_c"
+
+gdb_test "p/x value" " = 0x1011121344454647"
diff --git a/gdb/value.c b/gdb/value.c
index 89ccac7cfc6e..6ea7c200af41 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1049,6 +1049,19 @@ allocate_repeat_value (struct type *type, int count)
   return allocate_value (array_type);
 }
 
+struct value *
+allocate_register_value (struct gdbarch *gdbarch, int regnum, frame_info *next_frame)
+{
+  struct type *type = register_type (gdbarch, regnum);
+  value *v = allocate_value_lazy (type);
+
+  VALUE_LVAL (v) = lval_register;
+  v->location.reg.regnum = regnum;
+  v->location.reg.next_frame_id = get_frame_id (next_frame);
+
+  return v;
+}
+
 struct value *
 allocate_computed_value (struct type *type,
                          const struct lval_funcs *funcs,
@@ -3758,7 +3771,6 @@ value_fetch_lazy_memory (struct value *val)
 static void
 value_fetch_lazy_register (struct value *val)
 {
-  struct frame_info *next_frame;
   int regnum;
   struct type *type = check_typedef (value_type (val));
   struct value *new_val = val, *mark = value_mark ();
@@ -3771,7 +3783,7 @@ value_fetch_lazy_register (struct value *val)
     {
       struct frame_id next_frame_id = VALUE_NEXT_FRAME_ID (new_val);
 
-      next_frame = frame_find_by_id (next_frame_id);
+      frame_info *next_frame = frame_find_by_id (next_frame_id);
       regnum = VALUE_REGNUM (new_val);
 
       gdb_assert (next_frame != NULL);
diff --git a/gdb/value.h b/gdb/value.h
index 4d75c966edd6..2335edb0f5eb 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -238,6 +238,9 @@ extern void set_value_pointed_to_offset (struct value *value, LONGEST val);
 extern LONGEST value_embedded_offset (const struct value *value);
 extern void set_value_embedded_offset (struct value *value, LONGEST val);
 
+extern struct value *allocate_register_value (struct gdbarch *gdbarch,
+					      int regnum, frame_info *frame);
+
 /* For lval_computed values, this structure holds functions used to
    retrieve and set the value (or portions of the value).
 
