From 8dccd430c9de0e6cf747ae4bb1bf9d944fe3397c Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Fri, 18 Mar 2011 18:42:41 +0000
Subject: 	gdb/ 	* dwarf2loc.c (read_pieced_value): Handle
 get_frame_register_bytes 	returning that the register piece is
 unavailable/optimized out. 	(write_pieced_value): Handle
 get_frame_register_bytes returning 	that the register piece is
 unavailable/optimized out when doing a 	read-modify write of a
 bitfield. 	* findvar.c (value_from_register): Handle
 get_frame_register_bytes 	returning that the register piece is
 unavailable/optimized out. 	* frame.c (get_frame_register_bytes): New
 parameters `optimizedp' 	and `unavailablep'.  Throw error on bad debug
 info.  Use 	frame_register instead of frame_register_read, to fill in the
 new 	arguments. 	* frame.h (get_frame_register_bytes): New parameters
 `optimizedp' 	and `unavailablep'. 	* valops.c: (value_assign): Adjust,
 and handle 	get_frame_register_bytes failing. 	* spu-tdep.c: Include
 exceptions.h. 	(spu_software_single_step): Adjust, and handle 
 get_frame_register_bytes failing. 	(spu_get_longjmp_target): Ditto. 
 * gdbarch.sh (register_to_value): Change to return int.  New 	parameters
 `optimizedp' and `unavailablep'. 	* gdbarch.h, gdbarch.c: Regenerate. 
 * i386-tdep.c (i386_register_to_value): Adjust to new 
 gdbarch_register_to_value interface. 	* i387-tdep.c
 (i387_register_to_value): Ditto. 	* i387-tdep.h
 (i387_register_to_value): Ditto. 	* alpha-tdep.c
 (alpha_register_to_value): Ditto. 	* ia64-tdep.c
 (ia64_register_to_value): Ditto. 	* m68k-tdep.c
 (m68k_register_to_value): Ditto. 	* mips-tdep.c
 (mips_register_to_value): Ditto. 	* rs6000-tdep.c
 (rs6000_register_to_value): Ditto.

---
 gdb/alpha-tdep.c        | 25 ++++++++++++++++---------
 gdb/dwarf2loc.c         | 34 ++++++++++++++++++++++++++++++----
 gdb/findvar.c           | 19 +++++++++++++++----
 gdb/frame.c             | 27 +++++++++++++++++++--------
 gdb/frame.h             |  7 +++++--
 gdb/gdbarch.c           |  6 +++---
 gdb/gdbarch.h           |  4 ++--
 gdb/gdbarch.sh          |  2 +-
 gdb/i386-tdep.c         | 23 +++++++++++++----------
 gdb/i387-tdep.c         | 15 +++++++++++----
 gdb/i387-tdep.h         |  5 +++--
 gdb/ia64-tdep.c         | 15 ++++++++++++---
 gdb/m68k-tdep.c         | 17 +++++++++++++----
 gdb/mips-tdep.c         | 28 ++++++++++++++++++++++------
 gdb/rs6000-tdep.c       | 13 ++++++++++---
 gdb/spu-tdep.c          | 25 +++++++++++++++++++++----
 gdb/testsuite/ChangeLog | 34 ++++++++++++++++++++++++++++++++++
 gdb/valops.c            | 12 ++++++++++--
 18 files changed, 240 insertions(+), 71 deletions(-)

diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c
index cc49a07..2f309a7 100644
--- a/gdb/alpha-tdep.c
+++ b/gdb/alpha-tdep.c
@@ -239,21 +239,28 @@ alpha_convert_register_p (struct gdbarch *gdbarch, int regno,
 	  && TYPE_LENGTH (type) != 8);
 }
 
-static void
+static int
 alpha_register_to_value (struct frame_info *frame, int regnum,
-			 struct type *valtype, gdb_byte *out)
+			 struct type *valtype, gdb_byte *out,
+			int *optimizedp, int *unavailablep)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
   gdb_byte in[MAX_REGISTER_SIZE];
 
-  frame_register_read (frame, regnum, in);
-  switch (TYPE_LENGTH (valtype))
+  /* Convert to TYPE.  */
+  if (!get_frame_register_bytes (frame, regnum, 0,
+				 register_size (gdbarch, regnum),
+				 in, optimizedp, unavailablep))
+    return 0;
+
+  if (TYPE_LENGTH (valtype) == 4)
     {
-    case 4:
-      alpha_sts (get_frame_arch (frame), out, in);
-      break;
-    default:
-      error (_("Cannot retrieve value from floating point register"));
+      alpha_sts (gdbarch, out, in);
+      *optimizedp = *unavailablep = 0;
+      return 1;
     }
+
+  error (_("Cannot retrieve value from floating point register"));
 }
 
 static void
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index f90ee71..285081e 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -591,8 +591,20 @@ read_pieced_value (struct value *v)
 
 	    if (gdb_regnum != -1)
 	      {
-		get_frame_register_bytes (frame, gdb_regnum, reg_offset, 
-					  this_size, buffer);
+		int optim, unavail;
+
+		if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
+					       this_size, buffer,
+					       &optim, &unavail))
+		  {
+		    /* Just so garbage doesn't ever shine through.  */
+		    memset (buffer, 0, this_size);
+
+		    if (optim)
+		      set_value_optimized_out (v, 1);
+		    if (unavail)
+		      mark_value_bytes_unavailable (v, offset, this_size);
+		  }
 	      }
 	    else
 	      {
@@ -776,8 +788,22 @@ write_pieced_value (struct value *to, struct value *from)
 	      {
 		if (need_bitwise)
 		  {
-		    get_frame_register_bytes (frame, gdb_regnum, reg_offset,
-					      this_size, buffer);
+		    int optim, unavail;
+
+		    if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
+						   this_size, buffer,
+						   &optim, &unavail))
+		      {
+			if (optim)
+			  error (_("Can't do read-modify-write to "
+				   "update bitfield; containing word has been "
+				   "optimized out"));
+			if (unavail)
+			  throw_error (NOT_AVAILABLE_ERROR,
+				       _("Can't do read-modify-write to update "
+					 "bitfield; containing word "
+					 "is unavailable"));
+		      }
 		    copy_bitwise (buffer, dest_offset_bits,
 				  contents, source_offset_bits,
 				  this_size_bits,
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 809a99e..2b361efe 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -628,6 +628,7 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct type *type1 = check_typedef (type);
   struct value *v;
+  int optim, unavail, ok;
 
   if (gdbarch_convert_register_p (gdbarch, regnum, type1))
     {
@@ -642,8 +643,9 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
       VALUE_LVAL (v) = lval_register;
       VALUE_FRAME_ID (v) = get_frame_id (frame);
       VALUE_REGNUM (v) = regnum;
-      gdbarch_register_to_value (gdbarch,
-				 frame, regnum, type1, value_contents_raw (v));
+      ok = gdbarch_register_to_value (gdbarch, frame, regnum, type1,
+				      value_contents_raw (v), &optim,
+				      &unavail);
     }
   else
     {
@@ -653,10 +655,19 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
       v = gdbarch_value_from_register (gdbarch, type, regnum, frame);
 
       /* Get the data.  */
-      if (!get_frame_register_bytes (frame, regnum, value_offset (v), len,
-				     value_contents_raw (v)))
+      ok = get_frame_register_bytes (frame, regnum, value_offset (v), len,
+				     value_contents_raw (v),
+				     &optim, &unavail);
+    }
+
+  if (!ok)
+    {
+      if (optim)
 	set_value_optimized_out (v, 1);
+      if (unavail)
+	mark_value_bytes_unavailable (v, 0, TYPE_LENGTH (type));
     }
+
   return v;
 }
 
diff --git a/gdb/frame.c b/gdb/frame.c
index 42380eb..5bd1b03 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1001,7 +1001,8 @@ frame_register_read (struct frame_info *frame, int regnum,
 
 int
 get_frame_register_bytes (struct frame_info *frame, int regnum,
-			  CORE_ADDR offset, int len, gdb_byte *myaddr)
+			  CORE_ADDR offset, int len, gdb_byte *myaddr,
+			  int *optimizedp, int *unavailablep)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   int i;
@@ -1028,11 +1029,8 @@ get_frame_register_bytes (struct frame_info *frame, int regnum,
       maxsize += thissize;
     }
   if (len > maxsize)
-    {
-      warning (_("Bad debug information detected: "
-		 "Attempt to read %d bytes from registers."), len);
-      return 0;
-    }
+    error (_("Bad debug information detected: "
+	     "Attempt to read %d bytes from registers."), len);
 
   /* Copy the data.  */
   while (len > 0)
@@ -1044,14 +1042,25 @@ get_frame_register_bytes (struct frame_info *frame, int regnum,
 
       if (curr_len == register_size (gdbarch, regnum))
 	{
-	  if (!frame_register_read (frame, regnum, myaddr))
+	  enum lval_type lval;
+	  CORE_ADDR addr;
+	  int realnum;
+
+	  frame_register (frame, regnum, optimizedp, unavailablep,
+			  &lval, &addr, &realnum, myaddr);
+	  if (*optimizedp || *unavailablep)
 	    return 0;
 	}
       else
 	{
 	  gdb_byte buf[MAX_REGISTER_SIZE];
+	  enum lval_type lval;
+	  CORE_ADDR addr;
+	  int realnum;
 
-	  if (!frame_register_read (frame, regnum, buf))
+	  frame_register (frame, regnum, optimizedp, unavailablep,
+			  &lval, &addr, &realnum, buf);
+	  if (*optimizedp || *unavailablep)
 	    return 0;
 	  memcpy (myaddr, buf + offset, curr_len);
 	}
@@ -1062,6 +1071,8 @@ get_frame_register_bytes (struct frame_info *frame, int regnum,
       regnum++;
     }
 
+  *optimizedp = 0;
+  *unavailablep = 0;
   return 1;
 }
 
diff --git a/gdb/frame.h b/gdb/frame.h
index 605528c..e7053a8 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -520,10 +520,13 @@ extern void put_frame_register (struct frame_info *frame, int regnum,
 				const gdb_byte *buf);
 
 /* Read LEN bytes from one or multiple registers starting with REGNUM
-   in frame FRAME, starting at OFFSET, into BUF.  */
+   in frame FRAME, starting at OFFSET, into BUF.  If the register
+   contents are optimized out or unavailable, set *OPTIMIZEDP,
+   *UNAVAILABLEP accordingly.  */
 extern int get_frame_register_bytes (struct frame_info *frame, int regnum,
 				     CORE_ADDR offset, int len,
-				     gdb_byte *myaddr);
+				     gdb_byte *myaddr,
+				     int *optimizedp, int *unavailablep);
 
 /* Write LEN bytes to one or multiple registers starting with REGNUM
    in frame FRAME, starting at OFFSET, into BUF.  */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 8b97f20..7f98306 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -2262,14 +2262,14 @@ set_gdbarch_convert_register_p (struct gdbarch *gdbarch,
   gdbarch->convert_register_p = convert_register_p;
 }
 
-void
-gdbarch_register_to_value (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf)
+int
+gdbarch_register_to_value (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf, int *optimizedp, int *unavailablep)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->register_to_value != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_register_to_value called\n");
-  gdbarch->register_to_value (frame, regnum, type, buf);
+  return gdbarch->register_to_value (frame, regnum, type, buf, optimizedp, unavailablep);
 }
 
 void
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 7284f76..50221d7 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -384,8 +384,8 @@ typedef int (gdbarch_convert_register_p_ftype) (struct gdbarch *gdbarch, int reg
 extern int gdbarch_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type);
 extern void set_gdbarch_convert_register_p (struct gdbarch *gdbarch, gdbarch_convert_register_p_ftype *convert_register_p);
 
-typedef void (gdbarch_register_to_value_ftype) (struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf);
-extern void gdbarch_register_to_value (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf);
+typedef int (gdbarch_register_to_value_ftype) (struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf, int *optimizedp, int *unavailablep);
+extern int gdbarch_register_to_value (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf, int *optimizedp, int *unavailablep);
 extern void set_gdbarch_register_to_value (struct gdbarch *gdbarch, gdbarch_register_to_value_ftype *register_to_value);
 
 typedef void (gdbarch_value_to_register_ftype) (struct frame_info *frame, int regnum, struct type *type, const gdb_byte *buf);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 2f987ae..3112f44 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -484,7 +484,7 @@ F:int:get_longjmp_target:struct frame_info *frame, CORE_ADDR *pc:frame, pc
 v:int:believe_pcc_promotion:::::::
 #
 m:int:convert_register_p:int regnum, struct type *type:regnum, type:0:generic_convert_register_p::0
-f:void:register_to_value:struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf:frame, regnum, type, buf:0
+f:int:register_to_value:struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf, int *optimizedp, int *unavailablep:frame, regnum, type, buf, optimizedp, unavailablep:0
 f:void:value_to_register:struct frame_info *frame, int regnum, struct type *type, const gdb_byte *buf:frame, regnum, type, buf:0
 # Construct a value representing the contents of register REGNUM in
 # frame FRAME, interpreted as type TYPE.  The routine needs to
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 6330ceb..62df614 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -2746,21 +2746,17 @@ i386_convert_register_p (struct gdbarch *gdbarch,
 /* Read a value of type TYPE from register REGNUM in frame FRAME, and
    return its contents in TO.  */
 
-static void
+static int
 i386_register_to_value (struct frame_info *frame, int regnum,
-			struct type *type, gdb_byte *to)
+			struct type *type, gdb_byte *to,
+			int *optimizedp, int *unavailablep)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   int len = TYPE_LENGTH (type);
 
-  /* FIXME: kettenis/20030609: What should we do if REGNUM isn't
-     available in FRAME (i.e. if it wasn't saved)?  */
-
   if (i386_fp_regnum_p (gdbarch, regnum))
-    {
-      i387_register_to_value (frame, regnum, type, to);
-      return;
-    }
+    return i387_register_to_value (frame, regnum, type, to,
+				   optimizedp, unavailablep);
 
   /* Read a value spread across multiple registers.  */
 
@@ -2771,11 +2767,18 @@ i386_register_to_value (struct frame_info *frame, int regnum,
       gdb_assert (regnum != -1);
       gdb_assert (register_size (gdbarch, regnum) == 4);
 
-      get_frame_register (frame, regnum, to);
+      if (!get_frame_register_bytes (frame, regnum, 0,
+				     register_size (gdbarch, regnum),
+				     to, optimizedp, unavailablep))
+	return 0;
+
       regnum = i386_next_regnum (regnum);
       len -= 4;
       to += 4;
     }
+
+  *optimizedp = *unavailablep = 0;
+  return 1;
 }
 
 /* Write the contents FROM of a value of type TYPE into register
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
index 122bd83..9eece41 100644
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -307,9 +307,10 @@ i387_convert_register_p (struct gdbarch *gdbarch, int regnum,
 /* Read a value of type TYPE from register REGNUM in frame FRAME, and
    return its contents in TO.  */
 
-void
+int
 i387_register_to_value (struct frame_info *frame, int regnum,
-			struct type *type, gdb_byte *to)
+			struct type *type, gdb_byte *to,
+			int *optimizedp, int *unavailablep)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   gdb_byte from[I386_MAX_REGISTER_SIZE];
@@ -321,12 +322,18 @@ i387_register_to_value (struct frame_info *frame, int regnum,
     {
       warning (_("Cannot convert floating-point register value "
 	       "to non-floating-point type."));
-      return;
+      *optimizedp = *unavailablep = 0;
+      return 0;
     }
 
   /* Convert to TYPE.  */
-  get_frame_register (frame, regnum, from);
+  if (!get_frame_register_bytes (frame, regnum, 0, TYPE_LENGTH (type),
+				 from, optimizedp, unavailablep))
+    return 0;
+
   convert_typed_floating (from, i387_ext_type (gdbarch), to, type);
+  *optimizedp = *unavailablep = 0;
+  return 1;
 }
 
 /* Write the contents FROM of a value of type TYPE into register
diff --git a/gdb/i387-tdep.h b/gdb/i387-tdep.h
index bd592ba..b876549 100644
--- a/gdb/i387-tdep.h
+++ b/gdb/i387-tdep.h
@@ -66,8 +66,9 @@ extern int i387_convert_register_p (struct gdbarch *gdbarch, int regnum,
 /* Read a value of type TYPE from register REGNUM in frame FRAME, and
    return its contents in TO.  */
 
-extern void i387_register_to_value (struct frame_info *frame, int regnum,
-				    struct type *type, gdb_byte *to);
+extern int i387_register_to_value (struct frame_info *frame, int regnum,
+				   struct type *type, gdb_byte *to,
+				   int *optimizedp, int *unavailablep);
 
 /* Write the contents FROM of a value of type TYPE into register
    REGNUM in frame FRAME.  */
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index cbd8514..363800d 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -1223,14 +1223,23 @@ ia64_convert_register_p (struct gdbarch *gdbarch, int regno, struct type *type)
 	  && type != ia64_ext_type (gdbarch));
 }
 
-static void
+static int
 ia64_register_to_value (struct frame_info *frame, int regnum,
-                         struct type *valtype, gdb_byte *out)
+			struct type *valtype, gdb_byte *out,
+			int *optimizedp, int *unavailablep)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   char in[MAX_REGISTER_SIZE];
-  frame_register_read (frame, regnum, in);
+
+  /* Convert to TYPE.  */
+  if (!get_frame_register_bytes (frame, regnum, 0,
+				 register_size (gdbarch, regnum),
+				 in, optimizedp, unavailablep))
+    return 0;
+
   convert_typed_floating (in, ia64_ext_type (gdbarch), out, valtype);
+  *optimizedp = *unavailablep = 0;
+  return 1;
 }
 
 static void
diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c
index 082cb84..2706969 100644
--- a/gdb/m68k-tdep.c
+++ b/gdb/m68k-tdep.c
@@ -203,9 +203,10 @@ m68k_convert_register_p (struct gdbarch *gdbarch,
 /* Read a value of type TYPE from register REGNUM in frame FRAME, and
    return its contents in TO.  */
 
-static void
+static int
 m68k_register_to_value (struct frame_info *frame, int regnum,
-			struct type *type, gdb_byte *to)
+			struct type *type, gdb_byte *to,
+			int *optimizedp, int *unavailablep)
 {
   gdb_byte from[M68K_MAX_REGISTER_SIZE];
   struct type *fpreg_type = register_type (get_frame_arch (frame),
@@ -216,12 +217,20 @@ m68k_register_to_value (struct frame_info *frame, int regnum,
     {
       warning (_("Cannot convert floating-point register value "
 	       "to non-floating-point type."));
-      return;
+      *optimizedp = *unavailablep = 0;
+      return 0;
     }
 
   /* Convert to TYPE.  */
-  get_frame_register (frame, regnum, from);
+
+  /* Convert to TYPE.  */
+  if (!get_frame_register_bytes (frame, regnum, 0, TYPE_LENGTH (type),
+				 from, optimizedp, unavailablep))
+    return 0;
+
   convert_typed_floating (from, fpreg_type, to, type);
+  *optimizedp = *unavailablep = 0;
+  return 1;
 }
 
 /* Write the contents FROM of a value of type TYPE into register
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 04ce30a..e5aed94 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -737,9 +737,10 @@ mips_convert_register_p (struct gdbarch *gdbarch,
       || mips_convert_register_gpreg_case_p (gdbarch, regnum, type);
 }
 
-static void
+static int
 mips_register_to_value (struct frame_info *frame, int regnum,
-			struct type *type, gdb_byte *to)
+			struct type *type, gdb_byte *to,
+			int *optimizedp, int *unavailablep)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
 
@@ -747,14 +748,29 @@ mips_register_to_value (struct frame_info *frame, int regnum,
     {
       get_frame_register (frame, regnum + 0, to + 4);
       get_frame_register (frame, regnum + 1, to + 0);
+
+      if (!get_frame_register_bytes (frame, regnum + 0, 0, 4, to + 4,
+				     optimizedp, unavailablep))
+	return 0;
+
+      if (!get_frame_register_bytes (frame, regnum + 1, 0, 4, to + 0,
+				     optimizedp, unavailablep))
+	return 0;
+      *optimizedp = *unavailablep = 0;
+      return 1;
     }
   else if (mips_convert_register_gpreg_case_p (gdbarch, regnum, type))
     {
       int len = TYPE_LENGTH (type);
-      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
-	get_frame_register_bytes (frame, regnum, 8 - len, len, to);
-      else
-	get_frame_register_bytes (frame, regnum, 0, len, to);
+      CORE_ADDR offset;
+
+      offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 - len : 0;
+      if (!get_frame_register_bytes (frame, regnum, offset, len, to,
+				     optimizedp, unavailablep))
+	return 0;
+
+      *optimizedp = *unavailablep = 0;
+      return 1;
     }
   else
     {
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index b8c87fb..23fe9e3 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -2504,20 +2504,27 @@ rs6000_convert_register_p (struct gdbarch *gdbarch, int regnum,
 	     != TYPE_LENGTH (builtin_type (gdbarch)->builtin_double));
 }
 
-static void
+static int
 rs6000_register_to_value (struct frame_info *frame,
                           int regnum,
                           struct type *type,
-                          gdb_byte *to)
+                          gdb_byte *to,
+			  int *optimizedp, int *unavailablep)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   gdb_byte from[MAX_REGISTER_SIZE];
   
   gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
 
-  get_frame_register (frame, regnum, from);
+  if (!get_frame_register_bytes (frame, regnum, 0,
+				 register_size (gdbarch, regnum),
+				 from, optimizedp, unavailablep))
+    return 0;
+
   convert_typed_floating (from, builtin_type (gdbarch)->builtin_double,
 			  to, type);
+  *optimizedp = *unavailablep = 0;
+  return 1;
 }
 
 static void
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 7f0cd7d..da7024a 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -45,7 +45,7 @@
 #include "observer.h"
 #include "infcall.h"
 #include "dwarf2.h"
-
+#include "exceptions.h"
 #include "spu-tdep.h"
 
 
@@ -1594,8 +1594,21 @@ spu_software_single_step (struct frame_info *frame)
 	target += SPUADDR_ADDR (pc);
       else if (reg != -1)
 	{
-	  get_frame_register_bytes (frame, reg, 0, 4, buf);
-	  target += extract_unsigned_integer (buf, 4, byte_order) & -4;
+	  int optim, unavail;
+
+	  if (get_frame_register_bytes (frame, reg, 0, 4, buf,
+					 &optim, &unavail))
+	    target += extract_unsigned_integer (buf, 4, byte_order) & -4;
+	  else
+	    {
+	      if (optim)
+		error (_("Could not determine address of "
+			 "single-step breakpoint."));
+	      if (unavail)
+		throw_error (NOT_AVAILABLE_ERROR,
+			     _("Could not determine address of "
+			       "single-step breakpoint."));
+	    }
 	}
 
       target = target & lslr;
@@ -1618,9 +1631,13 @@ spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   gdb_byte buf[4];
   CORE_ADDR jb_addr;
+  int optim, unavail;
 
   /* Jump buffer is pointed to by the argument register $r3.  */
-  get_frame_register_bytes (frame, SPU_ARG1_REGNUM, 0, 4, buf);
+  if (!get_frame_register_bytes (frame, SPU_ARG1_REGNUM, 0, 4, buf,
+				 &optim, &unavail))
+    return 0;
+
   jb_addr = extract_unsigned_integer (buf, 4, byte_order);
   if (target_read_memory (SPUADDR (tdep->id, jb_addr), buf, 4))
     return 0;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 77bad9f..5984d2d 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,39 @@
 2011-03-18  Pedro Alves  <pedro@codesourcery.com>
 
+	* dwarf2loc.c (read_pieced_value): Handle get_frame_register_bytes
+	returning that the register piece is unavailable/optimized out.
+	(write_pieced_value): Handle get_frame_register_bytes returning
+	that the register piece is unavailable/optimized out when doing a
+	read-modify write of a bitfield.
+	* findvar.c (value_from_register): Handle get_frame_register_bytes
+	returning that the register piece is unavailable/optimized out.
+	* frame.c (get_frame_register_bytes): New parameters `optimizedp'
+	and `unavailablep'.  Throw error on bad debug info.  Use
+	frame_register instead of frame_register_read, to fill in the new
+	arguments.
+	* frame.h (get_frame_register_bytes): New parameters `optimizedp'
+	and `unavailablep'.
+	* valops.c: (value_assign): Adjust, and handle
+	get_frame_register_bytes failing.
+	* spu-tdep.c: Include exceptions.h.
+	(spu_software_single_step): Adjust, and handle
+	get_frame_register_bytes failing.
+	(spu_get_longjmp_target): Ditto.
+	* gdbarch.sh (register_to_value): Change to return int.  New
+	parameters `optimizedp' and `unavailablep'.
+	* gdbarch.h, gdbarch.c: Regenerate.
+	* i386-tdep.c (i386_register_to_value): Adjust to new
+	gdbarch_register_to_value interface.
+	* i387-tdep.c (i387_register_to_value): Ditto.
+	* i387-tdep.h (i387_register_to_value): Ditto.
+	* alpha-tdep.c (alpha_register_to_value): Ditto.
+	* ia64-tdep.c (ia64_register_to_value): Ditto.
+	* m68k-tdep.c (m68k_register_to_value): Ditto.
+	* mips-tdep.c (mips_register_to_value): Ditto.
+	* rs6000-tdep.c (rs6000_register_to_value): Ditto.
+
+2011-03-18  Pedro Alves  <pedro@codesourcery.com>
+
 	* gdb.trace/unavailable.exp (fpreg, spreg, pcreg): Define.
 	(test_register, test_register_unavailable): New procedures.
 	(gdb_unavailable_registers_test): New procedure.
diff --git a/gdb/valops.c b/gdb/valops.c
index 0c07e5c..b9f5508 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1343,8 +1343,16 @@ value_assign (struct value *toval, struct value *fromval)
 			   "don't fit in a %d bit word."),
 			 (int) sizeof (LONGEST) * HOST_CHAR_BIT);
 
-		get_frame_register_bytes (frame, value_reg, offset,
-					  changed_len, buffer);
+		if (!get_frame_register_bytes (frame, value_reg, offset,
+					       changed_len, buffer,
+					       &optim, &unavail))
+		  {
+		    if (optim)
+		      error (_("value has been optimized out"));
+		    if (unavail)
+		      throw_error (NOT_AVAILABLE_ERROR,
+				   _("value is not available"));
+		  }
 
 		modify_field (type, buffer, value_as_long (fromval),
 			      value_bitpos (toval), value_bitsize (toval));
-- 
cgit v1.1