2003-06-14 Andrew Cagney <cagney@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Sat, 14 Jun 2003 22:35:25 +0000 (22:35 +0000)
committerAndrew Cagney <cagney@redhat.com>
Sat, 14 Jun 2003 22:35:25 +0000 (22:35 +0000)
            Mark Kettenis  <kettenis@gnu.org>

* gdbarch.sh (CONVERT_REGISTER_P): Add "type" parameter.
(REGISTER_TO_VALUE, VALUE_TO_REGISTER): Replace raw buffer
parameter with "frame".
* gdbarch.h, gdbarch.c: Re-generate.
* frame.h (put_frame_register): Declare.
* frame.c (put_frame_register): New function.
* arch-utils.c (legacy_convert_register_p): Add "type" parameter.
(legacy_register_to_value): Rewrite, use "frame" to get the
register value.
(legacy_value_to_register): Rewrite, use "frame" to find the
register's location before storing.
* arch-utils.h (legacy_convert_register_p): Update.
(legacy_register_to_value, legacy_value_to_register): Update.
* findvar.c (value_from_register): Rewrite, eliminate use of
REGISTER_CONVERT_TO_TYPE, pass "type" to CONVERT_REGISTER_P, pass
"frame" to REGISTER_TO_VALUE.
* valops.c (value_assign): Move the CONVERT_REGISTER code to the
lval_reg_frame_relative + lval_register branch of the switch.  Do
not use REGISTER_CONVERT_FROM_TYPE.  Use put_frame_register.
* i386-tdep.c (I386_EBX_REGNUM, I386_ECX_REGNUM, I386_ESI_REGNUM,
I386_EDI_REGNUM): New defines.
(i386_next_regnum, i386_convert_register_p,
i386_register_to_value, i386_value_to_register): New functions.
(i386_register_convertible, i386_register_convert_to_virtual,
i386_convert_to_raw): Remove functions.
(i386_gdbarch_init): Set convert_register_p, register_to_value and
value_to_register instead of register_convertible,
register_convert_to_virtual and register_convert_to_raw.
* mips-tdep.c (mips_convert_register_p): New function.
(mips_value_to_register): Replace mips_register_convert_from_type.
(mips_register_to_value): Replace mips_register_convert_to_type.
(mips_gdbarch_init): Set conver_register_p, value_to_register and
register_to_value.
* alpha-tdep.c (alpha_convert_register_p): Update.
(alpha_value_to_register): Update, store the register.
(alpha_register_to_value): Update, fetch the register.

13 files changed:
gdb/ChangeLog
gdb/alpha-tdep.c
gdb/arch-utils.c
gdb/arch-utils.h
gdb/findvar.c
gdb/frame.c
gdb/frame.h
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/i386-tdep.c
gdb/mips-tdep.c
gdb/valops.c

index c23420d..64d58e5 100644 (file)
@@ -1,3 +1,43 @@
+2003-06-14  Andrew Cagney  <cagney@redhat.com>
+            Mark Kettenis  <kettenis@gnu.org>
+
+       * gdbarch.sh (CONVERT_REGISTER_P): Add "type" parameter.
+       (REGISTER_TO_VALUE, VALUE_TO_REGISTER): Replace raw buffer
+       parameter with "frame".
+       * gdbarch.h, gdbarch.c: Re-generate.
+       * frame.h (put_frame_register): Declare.
+       * frame.c (put_frame_register): New function.
+       * arch-utils.c (legacy_convert_register_p): Add "type" parameter.
+       (legacy_register_to_value): Rewrite, use "frame" to get the
+       register value.
+       (legacy_value_to_register): Rewrite, use "frame" to find the
+       register's location before storing.
+       * arch-utils.h (legacy_convert_register_p): Update.
+       (legacy_register_to_value, legacy_value_to_register): Update.
+       * findvar.c (value_from_register): Rewrite, eliminate use of
+       REGISTER_CONVERT_TO_TYPE, pass "type" to CONVERT_REGISTER_P, pass
+       "frame" to REGISTER_TO_VALUE.
+       * valops.c (value_assign): Move the CONVERT_REGISTER code to the
+       lval_reg_frame_relative + lval_register branch of the switch.  Do
+       not use REGISTER_CONVERT_FROM_TYPE.  Use put_frame_register.
+       * i386-tdep.c (I386_EBX_REGNUM, I386_ECX_REGNUM, I386_ESI_REGNUM,
+       I386_EDI_REGNUM): New defines.
+       (i386_next_regnum, i386_convert_register_p,
+       i386_register_to_value, i386_value_to_register): New functions.
+       (i386_register_convertible, i386_register_convert_to_virtual,
+       i386_convert_to_raw): Remove functions.
+       (i386_gdbarch_init): Set convert_register_p, register_to_value and
+       value_to_register instead of register_convertible,
+       register_convert_to_virtual and register_convert_to_raw.
+       * mips-tdep.c (mips_convert_register_p): New function.
+       (mips_value_to_register): Replace mips_register_convert_from_type.
+       (mips_register_to_value): Replace mips_register_convert_to_type.
+       (mips_gdbarch_init): Set conver_register_p, value_to_register and
+       register_to_value.
+       * alpha-tdep.c (alpha_convert_register_p): Update.
+       (alpha_value_to_register): Update, store the register.
+       (alpha_register_to_value): Update, fetch the register.
+
 2003-06-14  Theodore A. Roth  <troth@openavr.org>
 
        * avr-tdep.c (avr_remote_translate_xfer_address): Delete function.
index d523577..fb2ca18 100644 (file)
@@ -206,14 +206,17 @@ alpha_sts (void *out, const void *in)
    registers is different. */
 
 static int
-alpha_convert_register_p (int regno)
+alpha_convert_register_p (int regno, struct type *type)
 {
   return (regno >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31);
 }
 
 static void
-alpha_register_to_value (int regnum, struct type *valtype, char *in, char *out)
+alpha_register_to_value (struct frame_info *frame, int regnum,
+                        struct type *valtype, void *out)
 {
+  char in[MAX_REGISTER_SIZE];
+  frame_register_read (frame, regnum, in);
   switch (TYPE_LENGTH (valtype))
     {
     case 4:
@@ -228,8 +231,10 @@ alpha_register_to_value (int regnum, struct type *valtype, char *in, char *out)
 }
 
 static void
-alpha_value_to_register (struct type *valtype, int regnum, char *in, char *out)
+alpha_value_to_register (struct frame_info *frame, int regnum,
+                        struct type *valtype, const void *in)
 {
+  char out[MAX_REGISTER_SIZE];
   switch (TYPE_LENGTH (valtype))
     {
     case 4:
@@ -241,6 +246,7 @@ alpha_value_to_register (struct type *valtype, int regnum, char *in, char *out)
     default:
       error ("Cannot store value in floating point register");
     }
+  put_frame_register (frame, regnum, out);
 }
 
 \f
index 9fa9cea..f3be320 100644 (file)
@@ -440,23 +440,29 @@ legacy_pc_in_sigtramp (CORE_ADDR pc, char *name)
 }
 
 int
-legacy_convert_register_p (int regnum)
+legacy_convert_register_p (int regnum, struct type *type)
 {
   return DEPRECATED_REGISTER_CONVERTIBLE (regnum);
 }
 
 void
-legacy_register_to_value (int regnum, struct type *type,
-                         char *from, char *to)
+legacy_register_to_value (struct frame_info *frame, int regnum,
+                         struct type *type, void *to)
 {
+  char from[MAX_REGISTER_SIZE];
+  frame_read_register (frame, regnum, from);
   DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL (regnum, type, from, to);
 }
 
 void
-legacy_value_to_register (struct type *type, int regnum,
-                         char *from, char *to)
+legacy_value_to_register (struct frame_info *frame, int regnum,
+                         struct type *type, const void *tmp)
 {
+  char to[MAX_REGISTER_SIZE];
+  char *from = alloca (TYPE_LENGTH (type));
+  memcpy (from, from, TYPE_LENGTH (type));
   DEPRECATED_REGISTER_CONVERT_TO_RAW (type, regnum, from, to);
+  put_frame_register (frame, regnum, to);
 }
 
 \f
index 8fce252..8952ed3 100644 (file)
@@ -160,9 +160,11 @@ extern int legacy_pc_in_sigtramp (CORE_ADDR pc, char *name);
    (something that is discouraged); and to convert a register to the
    type of a corresponding variable.  These legacy functions preserve
    that overloaded behavour in existing targets.  */
-extern int legacy_convert_register_p (int regnum);
-extern void legacy_register_to_value (int regnum, struct type *type, char *from, char *to);
-extern void legacy_value_to_register (struct type *type, int regnum, char *from, char *to);
+extern int legacy_convert_register_p (int regnum, struct type *type);
+extern void legacy_register_to_value (struct frame_info *frame, int regnum,
+                                     struct type *type, void *to);
+extern void legacy_value_to_register (struct frame_info *frame, int regnum,
+                                     struct type *type, const void *from);
 
 /* For compatibility with older architectures, returns
    (LEGACY_SIM_REGNO_IGNORE) when the register doesn't have a valid
index 3155697..933146a 100644 (file)
@@ -624,145 +624,75 @@ addresses have not been bound by the dynamic loader. Try again when executable i
 struct value *
 value_from_register (struct type *type, int regnum, struct frame_info *frame)
 {
-  char raw_buffer[MAX_REGISTER_SIZE];
-  CORE_ADDR addr;
-  int optim;
+  struct gdbarch *gdbarch = get_frame_arch (frame);
   struct value *v = allocate_value (type);
-  char *value_bytes = 0;
-  int value_bytes_copied = 0;
-  int num_storage_locs;
-  enum lval_type lval;
-  int len;
-
   CHECK_TYPEDEF (type);
-  len = TYPE_LENGTH (type);
 
-  VALUE_REGNO (v) = regnum;
-
-  num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ?
-                     ((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 :
-                     1);
-
-  if (num_storage_locs > 1
-#if 0
-      // OBSOLETE #ifdef GDB_TARGET_IS_H8500
-      // OBSOLETE       || TYPE_CODE (type) == TYPE_CODE_PTR
-      // OBSOLETE #endif
-#endif
-    )
+  if (CONVERT_REGISTER_P (regnum, type))
+    {
+      /* The ISA/ABI need to something weird when obtaining the
+         specified value from this register.  It might need to
+         re-order non-adjacent, starting with REGNUM (see MIPS and
+         i386).  It might need to convert the [float] register into
+         the corresponding [integer] type (see Alpha).  The assumption
+         is that REGISTER_TO_VALUE populates the entire value
+         including the location.  */
+      REGISTER_TO_VALUE (frame, regnum, type, VALUE_CONTENTS_RAW (v));
+      VALUE_LVAL (v) = lval_reg_frame_relative;
+      VALUE_FRAME_ID (v) = get_frame_id (frame);
+      VALUE_FRAME_REGNUM (v) = regnum;
+    }
+  else
     {
-      /* Value spread across multiple storage locations.  */
-
       int local_regnum;
       int mem_stor = 0, reg_stor = 0;
       int mem_tracking = 1;
       CORE_ADDR last_addr = 0;
       CORE_ADDR first_addr = 0;
-
-      value_bytes = (char *) alloca (len + MAX_REGISTER_SIZE);
+      int first_realnum = regnum;
+      int len = TYPE_LENGTH (type);
+      int value_bytes_copied;
+      int optimized = 0;
+      char *value_bytes = (char *) alloca (len + MAX_REGISTER_SIZE);
 
       /* Copy all of the data out, whereever it may be.  */
-
-#if 0
-      // OBSOLETE #ifdef GDB_TARGET_IS_H8500
-      // OBSOLETE /* This piece of hideosity is required because the H8500 treats registers
-      // OBSOLETE    differently depending upon whether they are used as pointers or not.  As a
-      // OBSOLETE    pointer, a register needs to have a page register tacked onto the front.
-      // OBSOLETE    An alternate way to do this would be to have gcc output different register
-      // OBSOLETE    numbers for the pointer & non-pointer form of the register.  But, it
-      // OBSOLETE    doesn't, so we're stuck with this.  */
-      // OBSOLETE 
-      // OBSOLETE       if (TYPE_CODE (type) == TYPE_CODE_PTR
-      // OBSOLETE        && len > 2)
-      // OBSOLETE      {
-      // OBSOLETE        int page_regnum;
-      // OBSOLETE 
-      // OBSOLETE        switch (regnum)
-      // OBSOLETE          {
-      // OBSOLETE          case R0_REGNUM:
-      // OBSOLETE          case R1_REGNUM:
-      // OBSOLETE          case R2_REGNUM:
-      // OBSOLETE          case R3_REGNUM:
-      // OBSOLETE            page_regnum = SEG_D_REGNUM;
-      // OBSOLETE            break;
-      // OBSOLETE          case R4_REGNUM:
-      // OBSOLETE          case R5_REGNUM:
-      // OBSOLETE            page_regnum = SEG_E_REGNUM;
-      // OBSOLETE            break;
-      // OBSOLETE          case R6_REGNUM:
-      // OBSOLETE          case R7_REGNUM:
-      // OBSOLETE            page_regnum = SEG_T_REGNUM;
-      // OBSOLETE            break;
-      // OBSOLETE          }
-      // OBSOLETE 
-      // OBSOLETE        value_bytes[0] = 0;
-      // OBSOLETE        get_saved_register (value_bytes + 1,
-      // OBSOLETE                            &optim,
-      // OBSOLETE                            &addr,
-      // OBSOLETE                            frame,
-      // OBSOLETE                            page_regnum,
-      // OBSOLETE                            &lval);
-      // OBSOLETE 
-      // OBSOLETE        if (register_cached (page_regnum) == -1)
-      // OBSOLETE          return NULL;        /* register value not available */
-      // OBSOLETE 
-      // OBSOLETE        if (lval == lval_register)
-      // OBSOLETE          reg_stor++;
-      // OBSOLETE        else
-      // OBSOLETE          mem_stor++;
-      // OBSOLETE        first_addr = addr;
-      // OBSOLETE        last_addr = addr;
-      // OBSOLETE 
-      // OBSOLETE        get_saved_register (value_bytes + 2,
-      // OBSOLETE                            &optim,
-      // OBSOLETE                            &addr,
-      // OBSOLETE                            frame,
-      // OBSOLETE                            regnum,
-      // OBSOLETE                            &lval);
-      // OBSOLETE 
-      // OBSOLETE        if (register_cached (regnum) == -1)
-      // OBSOLETE          return NULL;        /* register value not available */
-      // OBSOLETE 
-      // OBSOLETE        if (lval == lval_register)
-      // OBSOLETE          reg_stor++;
-      // OBSOLETE        else
-      // OBSOLETE          {
-      // OBSOLETE            mem_stor++;
-      // OBSOLETE            mem_tracking = mem_tracking && (addr == last_addr);
-      // OBSOLETE          }
-      // OBSOLETE        last_addr = addr;
-      // OBSOLETE      }
-      // OBSOLETE       else
-      // OBSOLETE #endif /* GDB_TARGET_IS_H8500 */
-#endif
-       for (local_regnum = regnum;
-            value_bytes_copied < len;
-            (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
-             ++local_regnum))
-         {
-           int realnum;
-           frame_register (frame, local_regnum, &optim, &lval, &addr,
-                           &realnum, value_bytes + value_bytes_copied);
-
-           if (register_cached (local_regnum) == -1)
-             return NULL;      /* register value not available */
-
-           if (regnum == local_regnum)
+      for (local_regnum = regnum, value_bytes_copied = 0;
+          value_bytes_copied < len;
+          (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
+           ++local_regnum))
+       {
+         int realnum;
+         int optim;
+         enum lval_type lval;
+         CORE_ADDR addr;
+         frame_register (frame, local_regnum, &optim, &lval, &addr,
+                         &realnum, value_bytes + value_bytes_copied);
+         optimized += optim;
+         if (register_cached (local_regnum) == -1)
+           return NULL;        /* register value not available */
+         
+         if (regnum == local_regnum)
+           {
              first_addr = addr;
-           if (lval == lval_register)
-             reg_stor++;
-           else
-             {
-               mem_stor++;
-
-               mem_tracking =
-                 (mem_tracking
-                  && (regnum == local_regnum
-                      || addr == last_addr));
-             }
-           last_addr = addr;
-         }
-
+             first_realnum = realnum;
+           }
+         if (lval == lval_register)
+           reg_stor++;
+         else
+           {
+             mem_stor++;
+             
+             mem_tracking = (mem_tracking
+                             && (regnum == local_regnum
+                                 || addr == last_addr));
+           }
+         last_addr = addr;
+       }
+      
+      /* FIXME: cagney/2003-06-04: Shouldn't this always use
+         lval_reg_frame_relative?  If it doesn't and the register's
+         location changes (say after a resume) then this value is
+         going to have wrong information.  */
       if ((reg_stor && mem_stor)
          || (mem_stor && !mem_tracking))
        /* Mixed storage; all of the hassle we just went through was
@@ -781,67 +711,29 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
        {
          VALUE_LVAL (v) = lval_register;
          VALUE_ADDRESS (v) = first_addr;
+         VALUE_REGNO (v) = first_realnum;
        }
       else
        internal_error (__FILE__, __LINE__,
                        "value_from_register: Value not stored anywhere!");
-
-      VALUE_OPTIMIZED_OUT (v) = optim;
-
+      
+      VALUE_OPTIMIZED_OUT (v) = optimized;
+      
       /* Any structure stored in more than one register will always be
-         an integral number of registers.  Otherwise, you'd need to do
+         an integral number of registers.  Otherwise, you need to do
          some fiddling with the last register copied here for little
          endian machines.  */
-
-      /* Copy into the contents section of the value.  */
-      memcpy (VALUE_CONTENTS_RAW (v), value_bytes, len);
-
-      /* Finally do any conversion necessary when extracting this
-         type from more than one register.  */
-#ifdef REGISTER_CONVERT_TO_TYPE
-      REGISTER_CONVERT_TO_TYPE (regnum, type, VALUE_CONTENTS_RAW (v));
-#endif
-      return v;
-    }
-
-  /* Data is completely contained within a single register.  Locate the
-     register's contents in a real register or in core;
-     read the data in raw format.  */
-
-  {
-    int realnum;
-    frame_register (frame, regnum, &optim, &lval, &addr, &realnum, raw_buffer);
-  }
-
-  if (register_cached (regnum) == -1)
-    return NULL;               /* register value not available */
-
-  VALUE_OPTIMIZED_OUT (v) = optim;
-  VALUE_LVAL (v) = lval;
-  VALUE_ADDRESS (v) = addr;
-
-  /* Convert the raw register to the corresponding data value's memory
-     format, if necessary.  */
-
-  if (CONVERT_REGISTER_P (regnum))
-    {
-      REGISTER_TO_VALUE (regnum, type, raw_buffer, VALUE_CONTENTS_RAW (v));
-    }
-  else
-    {
-      /* Raw and virtual formats are the same for this register.  */
-
-      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG && len < REGISTER_RAW_SIZE (regnum))
-       {
-         /* Big-endian, and we want less than full size.  */
-         VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len;
-       }
-
-      memcpy (VALUE_CONTENTS_RAW (v), raw_buffer + VALUE_OFFSET (v), len);
+      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+         && len < REGISTER_RAW_SIZE (regnum))
+       /* Big-endian, and we want less than full size.  */
+       VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len;
+      else
+       VALUE_OFFSET (v) = 0;
+      memcpy (VALUE_CONTENTS_RAW (v), value_bytes + VALUE_OFFSET (v), len);
     }
-
   return v;
 }
+
 \f
 /* Given a struct symbol for a variable or function,
    and a stack frame id, 
index 18f9561..7c82941 100644 (file)
@@ -674,6 +674,36 @@ frame_read_signed_register (struct frame_info *frame, int regnum,
 }
 
 void
+put_frame_register (struct frame_info *frame, int regnum, const void *buf)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int realnum;
+  int optim;
+  enum lval_type lval;
+  CORE_ADDR addr;
+  frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
+  if (optim)
+    error ("Attempt to assign to a value that was optimized out.");
+  switch (lval)
+    {
+    case lval_memory:
+      {
+       /* FIXME: write_memory doesn't yet take constant buffers.
+           Arrrg!  */
+       char tmp[MAX_REGISTER_SIZE];
+       memcpy (tmp, buf, register_size (gdbarch, regnum));
+       write_memory (addr, tmp, register_size (gdbarch, regnum));
+       break;
+      }
+    case lval_register:
+      regcache_cooked_write (current_regcache, realnum, buf);
+      break;
+    default:
+      error ("Attempt to assign to an unmodifiable value.");
+    }
+}
+
+void
 deprecated_unwind_get_saved_register (char *raw_buffer,
                                      int *optimizedp,
                                      CORE_ADDR *addrp,
index 4dc7560..ecca9f1 100644 (file)
@@ -332,6 +332,12 @@ extern void frame_read_signed_register (struct frame_info *frame,
 extern void frame_read_unsigned_register (struct frame_info *frame,
                                          int regnum, ULONGEST *val);
 
+/* The reverse.  Store a register value relative to the specified
+   frame.  Note: this call makes the frame's state undefined.  The
+   register and frame caches must be flushed.  */
+extern void put_frame_register (struct frame_info *frame, int regnum,
+                               const void *buf);
+
 /* Map between a frame register number and its name.  A frame register
    space is a superset of the cooked register space --- it also
    includes builtin registers.  If NAMELEN is negative, use the NAME's
index 47a5355..98afade 100644 (file)
@@ -989,8 +989,8 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
 #ifdef CONVERT_REGISTER_P
   fprintf_unfiltered (file,
                       "gdbarch_dump: %s # %s\n",
-                      "CONVERT_REGISTER_P(regnum)",
-                      XSTRING (CONVERT_REGISTER_P (regnum)));
+                      "CONVERT_REGISTER_P(regnum, type)",
+                      XSTRING (CONVERT_REGISTER_P (regnum, type)));
   if (GDB_MULTI_ARCH)
     fprintf_unfiltered (file,
                         "gdbarch_dump: CONVERT_REGISTER_P = <0x%08lx>\n",
@@ -2148,8 +2148,8 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   /* Macro might contain `[{}]' when not multi-arch */
   fprintf_unfiltered (file,
                       "gdbarch_dump: %s # %s\n",
-                      "REGISTER_TO_VALUE(regnum, type, from, to)",
-                      XSTRING (REGISTER_TO_VALUE (regnum, type, from, to)));
+                      "REGISTER_TO_VALUE(frame, regnum, type, buf)",
+                      XSTRING (REGISTER_TO_VALUE (frame, regnum, type, buf)));
 #endif
   if (GDB_MULTI_ARCH)
     fprintf_unfiltered (file,
@@ -2670,8 +2670,8 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   /* Macro might contain `[{}]' when not multi-arch */
   fprintf_unfiltered (file,
                       "gdbarch_dump: %s # %s\n",
-                      "VALUE_TO_REGISTER(type, regnum, from, to)",
-                      XSTRING (VALUE_TO_REGISTER (type, regnum, from, to)));
+                      "VALUE_TO_REGISTER(frame, regnum, type, buf)",
+                      XSTRING (VALUE_TO_REGISTER (frame, regnum, type, buf)));
 #endif
   if (GDB_MULTI_ARCH)
     fprintf_unfiltered (file,
@@ -4335,7 +4335,7 @@ set_gdbarch_deprecated_register_convert_to_raw (struct gdbarch *gdbarch,
 }
 
 int
-gdbarch_convert_register_p (struct gdbarch *gdbarch, int regnum)
+gdbarch_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type)
 {
   gdb_assert (gdbarch != NULL);
   if (gdbarch->convert_register_p == 0)
@@ -4343,7 +4343,7 @@ gdbarch_convert_register_p (struct gdbarch *gdbarch, int regnum)
                     "gdbarch: gdbarch_convert_register_p invalid");
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_convert_register_p called\n");
-  return gdbarch->convert_register_p (regnum);
+  return gdbarch->convert_register_p (regnum, type);
 }
 
 void
@@ -4354,7 +4354,7 @@ set_gdbarch_convert_register_p (struct gdbarch *gdbarch,
 }
 
 void
-gdbarch_register_to_value (struct gdbarch *gdbarch, int regnum, struct type *type, char *from, char *to)
+gdbarch_register_to_value (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, void *buf)
 {
   gdb_assert (gdbarch != NULL);
   if (gdbarch->register_to_value == 0)
@@ -4362,7 +4362,7 @@ gdbarch_register_to_value (struct gdbarch *gdbarch, int regnum, struct type *typ
                     "gdbarch: gdbarch_register_to_value invalid");
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_register_to_value called\n");
-  gdbarch->register_to_value (regnum, type, from, to);
+  gdbarch->register_to_value (frame, regnum, type, buf);
 }
 
 void
@@ -4373,7 +4373,7 @@ set_gdbarch_register_to_value (struct gdbarch *gdbarch,
 }
 
 void
-gdbarch_value_to_register (struct gdbarch *gdbarch, struct type *type, int regnum, char *from, char *to)
+gdbarch_value_to_register (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, const void *buf)
 {
   gdb_assert (gdbarch != NULL);
   if (gdbarch->value_to_register == 0)
@@ -4381,7 +4381,7 @@ gdbarch_value_to_register (struct gdbarch *gdbarch, struct type *type, int regnu
                     "gdbarch: gdbarch_value_to_register invalid");
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_value_to_register called\n");
-  gdbarch->value_to_register (type, regnum, from, to);
+  gdbarch->value_to_register (frame, regnum, type, buf);
 }
 
 void
index e5800ad..53f3181 100644 (file)
@@ -1688,47 +1688,47 @@ extern void set_gdbarch_deprecated_register_convert_to_raw (struct gdbarch *gdba
 
 /* Default (function) for non- multi-arch platforms. */
 #if (!GDB_MULTI_ARCH) && !defined (CONVERT_REGISTER_P)
-#define CONVERT_REGISTER_P(regnum) (legacy_convert_register_p (regnum))
+#define CONVERT_REGISTER_P(regnum, type) (legacy_convert_register_p (regnum, type))
 #endif
 
-typedef int (gdbarch_convert_register_p_ftype) (int regnum);
-extern int gdbarch_convert_register_p (struct gdbarch *gdbarch, int regnum);
+typedef int (gdbarch_convert_register_p_ftype) (int regnum, struct type *type);
+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);
 #if (GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PARTIAL) && defined (CONVERT_REGISTER_P)
 #error "Non multi-arch definition of CONVERT_REGISTER_P"
 #endif
 #if !defined (CONVERT_REGISTER_P)
-#define CONVERT_REGISTER_P(regnum) (gdbarch_convert_register_p (current_gdbarch, regnum))
+#define CONVERT_REGISTER_P(regnum, type) (gdbarch_convert_register_p (current_gdbarch, regnum, type))
 #endif
 
 /* Default (function) for non- multi-arch platforms. */
 #if (!GDB_MULTI_ARCH) && !defined (REGISTER_TO_VALUE)
-#define REGISTER_TO_VALUE(regnum, type, from, to) (legacy_register_to_value (regnum, type, from, to))
+#define REGISTER_TO_VALUE(frame, regnum, type, buf) (legacy_register_to_value (frame, regnum, type, buf))
 #endif
 
-typedef void (gdbarch_register_to_value_ftype) (int regnum, struct type *type, char *from, char *to);
-extern void gdbarch_register_to_value (struct gdbarch *gdbarch, int regnum, struct type *type, char *from, char *to);
+typedef void (gdbarch_register_to_value_ftype) (struct frame_info *frame, int regnum, struct type *type, void *buf);
+extern void gdbarch_register_to_value (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, void *buf);
 extern void set_gdbarch_register_to_value (struct gdbarch *gdbarch, gdbarch_register_to_value_ftype *register_to_value);
 #if (GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PARTIAL) && defined (REGISTER_TO_VALUE)
 #error "Non multi-arch definition of REGISTER_TO_VALUE"
 #endif
 #if !defined (REGISTER_TO_VALUE)
-#define REGISTER_TO_VALUE(regnum, type, from, to) (gdbarch_register_to_value (current_gdbarch, regnum, type, from, to))
+#define REGISTER_TO_VALUE(frame, regnum, type, buf) (gdbarch_register_to_value (current_gdbarch, frame, regnum, type, buf))
 #endif
 
 /* Default (function) for non- multi-arch platforms. */
 #if (!GDB_MULTI_ARCH) && !defined (VALUE_TO_REGISTER)
-#define VALUE_TO_REGISTER(type, regnum, from, to) (legacy_value_to_register (type, regnum, from, to))
+#define VALUE_TO_REGISTER(frame, regnum, type, buf) (legacy_value_to_register (frame, regnum, type, buf))
 #endif
 
-typedef void (gdbarch_value_to_register_ftype) (struct type *type, int regnum, char *from, char *to);
-extern void gdbarch_value_to_register (struct gdbarch *gdbarch, struct type *type, int regnum, char *from, char *to);
+typedef void (gdbarch_value_to_register_ftype) (struct frame_info *frame, int regnum, struct type *type, const void *buf);
+extern void gdbarch_value_to_register (struct gdbarch *gdbarch, struct frame_info *frame, int regnum, struct type *type, const void *buf);
 extern void set_gdbarch_value_to_register (struct gdbarch *gdbarch, gdbarch_value_to_register_ftype *value_to_register);
 #if (GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PARTIAL) && defined (VALUE_TO_REGISTER)
 #error "Non multi-arch definition of VALUE_TO_REGISTER"
 #endif
 #if !defined (VALUE_TO_REGISTER)
-#define VALUE_TO_REGISTER(type, regnum, from, to) (gdbarch_value_to_register (current_gdbarch, type, regnum, from, to))
+#define VALUE_TO_REGISTER(frame, regnum, type, buf) (gdbarch_value_to_register (current_gdbarch, frame, regnum, type, buf))
 #endif
 
 /* Default (function) for non- multi-arch platforms. */
index aee39b4..2e007a0 100755 (executable)
@@ -585,9 +585,9 @@ f:2:DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL:void:deprecated_register_convert_to_v
 # For raw <-> cooked register conversions, replaced by pseudo registers.
 f:2:DEPRECATED_REGISTER_CONVERT_TO_RAW:void:deprecated_register_convert_to_raw:struct type *type, int regnum, const char *from, char *to:type, regnum, from, to:::0::0
 #
-f:1:CONVERT_REGISTER_P:int:convert_register_p:int regnum:regnum::0:legacy_convert_register_p::0
-f:1:REGISTER_TO_VALUE:void:register_to_value:int regnum, struct type *type, char *from, char *to:regnum, type, from, to::0:legacy_register_to_value::0
-f:1:VALUE_TO_REGISTER:void:value_to_register:struct type *type, int regnum, char *from, char *to:type, regnum, from, to::0:legacy_value_to_register::0
+f:1:CONVERT_REGISTER_P:int:convert_register_p:int regnum, struct type *type:regnum, type::0:legacy_convert_register_p::0
+f:1:REGISTER_TO_VALUE:void:register_to_value:struct frame_info *frame, int regnum, struct type *type, void *buf:frame, regnum, type, buf::0:legacy_register_to_value::0
+f:1:VALUE_TO_REGISTER:void:value_to_register:struct frame_info *frame, int regnum, struct type *type, const void *buf:frame, regnum, type, buf::0:legacy_value_to_register::0
 #
 f:2:POINTER_TO_ADDRESS:CORE_ADDR:pointer_to_address:struct type *type, const void *buf:type, buf:::unsigned_pointer_to_address::0
 f:2:ADDRESS_TO_POINTER:void:address_to_pointer:struct type *type, void *buf, CORE_ADDR addr:type, buf, addr:::unsigned_address_to_pointer::0
index 467f686..8309ef5 100644 (file)
@@ -1324,65 +1324,148 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
   else
     regcache_raw_write (regcache, regnum, buf);
 }
+\f
+
+/* These registers don't have pervasive standard uses.  Move them to
+   i386-tdep.h if necessary.  */
+
+#define I386_EBX_REGNUM                3 /* %ebx */
+#define I386_ECX_REGNUM                1 /* %ecx */
+#define I386_ESI_REGNUM                6 /* %esi */
+#define I386_EDI_REGNUM                7 /* %edi */
+
+/* Return the register number of the register allocated by GCC after
+   REGNUM, or -1 if there is no such register.  */
+
+static int
+i386_next_regnum (int regnum)
+{
+  /* GCC allocates the registers in the order:
+
+     %eax, %edx, %ecx, %ebx, %esi, %edi, %ebp, %esp, ...
+
+     Since storing a variable in %esp doesn't make any sense we return
+     -1 for %ebp and for %esp itself.  */
+  static int next_regnum[] =
+  {
+    I386_EDX_REGNUM,           /* Slot for %eax.  */
+    I386_EBX_REGNUM,           /* Slot for %ecx.  */
+    I386_ECX_REGNUM,           /* Slot for %edx.  */
+    I386_ESI_REGNUM,           /* Slot for %ebx.  */
+    -1, -1,                    /* Slots for %esp and %ebp.  */
+    I386_EDI_REGNUM,           /* Slot for %esi.  */
+    I386_EBP_REGNUM            /* Slot for %edi.  */
+  };
+
+  if (regnum < sizeof (next_regnum) / sizeof (next_regnum[0]))
+    return next_regnum[regnum];
 
-/* Return true iff register REGNUM's virtual format is different from
-   its raw format.  Note that this definition assumes that the host
-   supports IEEE 32-bit floats, since it doesn't say that SSE
-   registers need conversion.  Even if we can't find a counterexample,
-   this is still sloppy.  */
+  return -1;
+}
+
+/* Return nonzero if a value of type TYPE stored in register REGNUM
+   needs any special handling.  */
 
 static int
-i386_register_convertible (int regnum)
+i386_convert_register_p (int regnum, struct type *type)
 {
+  /* Values may be spread across multiple registers.  Most debugging
+     formats aren't expressive enough to specify the locations, so
+     some heuristics is involved.  Right now we only handle types that
+     are exactly 8 bytes long as GCC doesn't seem to put any other
+     types into registers.  */
+  if (TYPE_LENGTH (type) == 8 && i386_next_regnum (regnum) != -1)
+    return 1;
+
   return i386_fp_regnum_p (regnum);
 }
 
-/* Convert data from raw format for register REGNUM in buffer FROM to
-   virtual format with type TYPE in buffer TO.  */
+/* Read a value of type TYPE from register REGNUM in frame FRAME, and
+   return its contents in TO.  */
 
 static void
-i386_register_convert_to_virtual (int regnum, struct type *type,
-                                 char *from, char *to)
+i386_register_to_value (struct frame_info *frame, int regnum,
+                       struct type *type, void *to)
 {
-  gdb_assert (i386_fp_regnum_p (regnum));
+  /* FIXME: kettenis/20030609: What should we do if REGNUM isn't
+     available in FRAME (i.e. if it wasn't saved)?  */
 
-  /* We only support floating-point values.  */
-  if (TYPE_CODE (type) != TYPE_CODE_FLT)
+  if (i386_fp_regnum_p (regnum))
     {
-      warning ("Cannot convert floating-point register value "
-              "to non-floating-point type.");
-      memset (to, 0, TYPE_LENGTH (type));
-      return;
+      char from[I386_MAX_REGISTER_SIZE];
+
+      /* We only support floating-point values.  */
+      if (TYPE_CODE (type) != TYPE_CODE_FLT)
+       {
+         warning ("Cannot convert floating-point register value "
+                  "to non-floating-point type.");
+         return;
+       }
+
+      /* Convert to TYPE.  This should be a no-op if TYPE is
+        equivalent to the extended floating-point format used by the
+        FPU.  */
+      frame_read_register (frame, regnum, from);
+      convert_typed_floating (from, builtin_type_i387_ext, to, type);
     }
+  else
+    {
+      gdb_assert (TYPE_LENGTH (type) == 8);
+
+      /* Read the first part.  */
+      gdb_assert (register_size (current_gdbarch, regnum) == 4);
+      frame_read_register (frame, regnum, (char *) to + 0);
 
-  /* Convert to TYPE.  This should be a no-op if TYPE is equivalent to
-     the extended floating-point format used by the FPU.  */
-  convert_typed_floating (from, builtin_type_i387_ext, to, type);
+      /* Read the second part.  */
+      regnum = i386_next_regnum (regnum);
+      gdb_assert (regnum != -1);
+      gdb_assert (register_size (current_gdbarch, regnum));
+      frame_read_register (frame, regnum, (char *) to + 4);
+    }
 }
 
-/* Convert data from virtual format with type TYPE in buffer FROM to
-   raw format for register REGNUM in buffer TO.  */
+/* Write the contents FROM of a value of type TYPE into register
+   REGNUM in frame FRAME.  */
 
 static void
-i386_register_convert_to_raw (struct type *type, int regnum,
-                             const char *from, char *to)
+i386_value_to_register (struct frame_info *frame, int regnum,
+                       struct type *type, const void *from)
 {
-  gdb_assert (i386_fp_regnum_p (regnum));
-
-  /* We only support floating-point values.  */
-  if (TYPE_CODE (type) != TYPE_CODE_FLT)
+  if (i386_fp_regnum_p (regnum))
     {
-      warning ("Cannot convert non-floating-point type "
-              "to floating-point register value.");
-      memset (to, 0, TYPE_LENGTH (type));
-      return;
-    }
+      char to[I386_MAX_REGISTER_SIZE];
 
-  /* Convert from TYPE.  This should be a no-op if TYPE is equivalent
-     to the extended floating-point format used by the FPU.  */
-  convert_typed_floating (from, type, to, builtin_type_i387_ext);
+      /* We only support floating-point values.  */
+      if (TYPE_CODE (type) != TYPE_CODE_FLT)
+       {
+         warning ("Cannot convert non-floating-point type "
+                  "to floating-point register value.");
+         return;
+       }
+
+      /* Convert from TYPE.  This should be a no-op if TYPE is
+        equivalent to the extended floating-point format used by the
+        FPU.  */
+      convert_typed_floating (from, type, to, builtin_type_i387_ext);
+      put_frame_register (frame, regnum, to);
+    }
+  else
+    {
+      gdb_assert (TYPE_LENGTH (type) == 8);
+
+      /* Write the first part.  */
+      gdb_assert (register_size (current_gdbarch, regnum) == 4);
+      put_frame_register (frame, regnum, (const char *) from + 0);
+
+      /* Write the second part.  */
+      regnum = i386_next_regnum (regnum);
+      gdb_assert (regnum != -1);
+      gdb_assert (register_size (current_gdbarch, regnum) == 4);
+      put_frame_register (frame, regnum, (const char *) from + 4);
+   }
 }
-\f     
+\f
+
 
 #ifdef STATIC_TRANSFORM_NAME
 /* SunPRO encodes the static variables.  This is not related to C++
@@ -1692,9 +1775,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Call dummy code.  */
   set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
 
-  set_gdbarch_deprecated_register_convertible (gdbarch, i386_register_convertible);
-  set_gdbarch_deprecated_register_convert_to_virtual (gdbarch, i386_register_convert_to_virtual);
-  set_gdbarch_deprecated_register_convert_to_raw (gdbarch, i386_register_convert_to_raw);
+  set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
+  set_gdbarch_register_to_value (gdbarch,  i386_register_to_value);
+  set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
 
   set_gdbarch_extract_return_value (gdbarch, i386_extract_return_value);
   set_gdbarch_store_return_value (gdbarch, i386_store_return_value);
index 70bb92b..dd0b176 100644 (file)
@@ -634,36 +634,30 @@ mips_register_convert_to_raw (struct type *virtual_type, int n,
            TYPE_LENGTH (virtual_type));
 }
 
+static int
+mips_convert_register_p (int regnum, struct type *type)
+{
+  return (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+         && REGISTER_RAW_SIZE (regnum) == 4
+         && (regnum) >= FP0_REGNUM && (regnum) < FP0_REGNUM + 32
+         && TYPE_CODE(type) == TYPE_CODE_FLT
+         && TYPE_LENGTH(type) == 8);
+}
+
 void
-mips_register_convert_to_type (int regnum, struct type *type, char *buffer)
+mips_register_to_value (struct frame_info *frame, int regnum,
+                       struct type *type, void *to)
 {
-  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
-      && REGISTER_RAW_SIZE (regnum) == 4
-      && (regnum) >= FP0_REGNUM && (regnum) < FP0_REGNUM + 32
-      && TYPE_CODE(type) == TYPE_CODE_FLT
-      && TYPE_LENGTH(type) == 8) 
-    {
-      char temp[4];
-      memcpy (temp, ((char *)(buffer))+4, 4);
-      memcpy (((char *)(buffer))+4, (buffer), 4);
-      memcpy (((char *)(buffer)), temp, 4); 
-    }
+  frame_read_register (frame, regnum + 0, (char *) to + 4);
+  frame_read_register (frame, regnum + 1, (char *) to + 0);
 }
 
 void
-mips_register_convert_from_type (int regnum, struct type *type, char *buffer)
+mips_value_to_register (struct frame_info *frame, int regnum,
+                       struct type *type, const void *from)
 {
-if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
-    && REGISTER_RAW_SIZE (regnum) == 4
-    && (regnum) >= FP0_REGNUM && (regnum) < FP0_REGNUM + 32
-    && TYPE_CODE(type) == TYPE_CODE_FLT
-    && TYPE_LENGTH(type) == 8) 
-  {
-    char temp[4];
-    memcpy (temp, ((char *)(buffer))+4, 4);
-    memcpy (((char *)(buffer))+4, (buffer), 4);
-    memcpy (((char *)(buffer)), temp, 4);
-  }
+  put_frame_register (frame, regnum + 0, (const char *) from + 4);
+  put_frame_register (frame, regnum + 1, (const char *) from + 0);
 }
 
 /* Return the GDB type object for the "standard" data type
index 2767630..9d02a35 100644 (file)
@@ -498,22 +498,6 @@ value_assign (struct value *toval, struct value *fromval)
     COERCE_ARRAY (fromval);
   CHECK_TYPEDEF (type);
 
-  /* If TOVAL is a special machine register requiring conversion
-     of program values to a special raw format,
-     convert FROMVAL's contents now, with result in `raw_buffer',
-     and set USE_BUFFER to the number of bytes to write.  */
-
-  if (VALUE_REGNO (toval) >= 0)
-    {
-      int regno = VALUE_REGNO (toval);
-      if (CONVERT_REGISTER_P (regno))
-       {
-         struct type *fromtype = check_typedef (VALUE_TYPE (fromval));
-         VALUE_TO_REGISTER (fromtype, regno, VALUE_CONTENTS (fromval), raw_buffer);
-         use_buffer = REGISTER_RAW_SIZE (regno);
-       }
-    }
-
   /* Since modifying a register can trash the frame chain, and modifying memory
      can trash the frame cache, we save the old frame and then restore the new
      frame afterwards.  */
@@ -587,17 +571,8 @@ value_assign (struct value *toval, struct value *fromval)
     case lval_reg_frame_relative:
     case lval_register:
       {
-       /* value is stored in a series of registers in the frame
-          specified by the structure.  Copy that value out, modify
-          it, and copy it back in.  */
-       int amount_copied;
-       int amount_to_copy;
-       char *buffer;
-       int value_reg;
-       int reg_offset;
-       int byte_offset;
-       int regno;
        struct frame_info *frame;
+       int value_reg;
 
        /* Figure out which frame this is in currently.  */
        if (VALUE_LVAL (toval) == lval_register)
@@ -613,92 +588,77 @@ value_assign (struct value *toval, struct value *fromval)
 
        if (!frame)
          error ("Value being assigned to is no longer active.");
-
-       /* Locate the first register that falls in the value that
-           needs to be transfered.  Compute the offset of the value in
-           that register.  */
-       {
-         int offset;
-         for (reg_offset = value_reg, offset = 0;
-              offset + REGISTER_RAW_SIZE (reg_offset) <= VALUE_OFFSET (toval);
-              reg_offset++);
-         byte_offset = VALUE_OFFSET (toval) - offset;
-       }
-
-       /* Compute the number of register aligned values that need to
-           be copied.  */
-       if (VALUE_BITSIZE (toval))
-         amount_to_copy = byte_offset + 1;
-       else
-         amount_to_copy = byte_offset + TYPE_LENGTH (type);
-
-       /* And a bounce buffer.  Be slightly over generous.  */
-       buffer = (char *) alloca (amount_to_copy + MAX_REGISTER_SIZE);
-
-       /* Copy it in.  */
-       for (regno = reg_offset, amount_copied = 0;
-            amount_copied < amount_to_copy;
-            amount_copied += REGISTER_RAW_SIZE (regno), regno++)
-         {
-           frame_register_read (frame, regno, buffer + amount_copied);
-         }
        
-       /* Modify what needs to be modified.  */
-       if (VALUE_BITSIZE (toval))
-         {
-           modify_field (buffer + byte_offset,
-                         value_as_long (fromval),
-                         VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
-         }
-       else if (use_buffer)
+       if (VALUE_LVAL (toval) == lval_reg_frame_relative
+           && CONVERT_REGISTER_P (VALUE_FRAME_REGNUM (toval), type))
          {
-           memcpy (buffer + VALUE_OFFSET (toval), raw_buffer, use_buffer);
+           /* If TOVAL is a special machine register requiring
+              conversion of program values to a special raw format.  */
+           VALUE_TO_REGISTER (frame, VALUE_FRAME_REGNUM (toval),
+                              type, VALUE_CONTENTS (fromval));
          }
        else
          {
-           memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval),
-                   TYPE_LENGTH (type));
-           /* Do any conversion necessary when storing this type to
-              more than one register.  */
-#ifdef REGISTER_CONVERT_FROM_TYPE
-           REGISTER_CONVERT_FROM_TYPE (value_reg, type,
-                                       (buffer + byte_offset));
-#endif
-         }
+           /* TOVAL is stored in a series of registers in the frame
+              specified by the structure.  Copy that value out,
+              modify it, and copy it back in.  */
+           int amount_copied;
+           int amount_to_copy;
+           char *buffer;
+           int reg_offset;
+           int byte_offset;
+           int regno;
+
+           /* Locate the first register that falls in the value that
+              needs to be transfered.  Compute the offset of the
+              value in that register.  */
+           {
+             int offset;
+             for (reg_offset = value_reg, offset = 0;
+                  offset + REGISTER_RAW_SIZE (reg_offset) <= VALUE_OFFSET (toval);
+                  reg_offset++);
+             byte_offset = VALUE_OFFSET (toval) - offset;
+           }
 
-       /* Copy it out.  */
-       for (regno = reg_offset, amount_copied = 0;
-            amount_copied < amount_to_copy;
-            amount_copied += REGISTER_RAW_SIZE (regno), regno++)
-         {
-           enum lval_type lval;
-           CORE_ADDR addr;
-           int optim;
-           int realnum;
+           /* Compute the number of register aligned values that need
+              to be copied.  */
+           if (VALUE_BITSIZE (toval))
+             amount_to_copy = byte_offset + 1;
+           else
+             amount_to_copy = byte_offset + TYPE_LENGTH (type);
            
-           /* Just find out where to put it.  */
-           frame_register (frame, regno, &optim, &lval, &addr, &realnum,
-                           NULL);
+           /* And a bounce buffer.  Be slightly over generous.  */
+           buffer = (char *) alloca (amount_to_copy + MAX_REGISTER_SIZE);
+
+           /* Copy it in.  */
+           for (regno = reg_offset, amount_copied = 0;
+                amount_copied < amount_to_copy;
+                amount_copied += REGISTER_RAW_SIZE (regno), regno++)
+             frame_register_read (frame, regno, buffer + amount_copied);
            
-           if (optim)
-             error ("Attempt to assign to a value that was optimized out.");
-           if (lval == lval_memory)
-             write_memory (addr, buffer + amount_copied,
-                           REGISTER_RAW_SIZE (regno));
-           else if (lval == lval_register)
-             regcache_cooked_write (current_regcache, realnum,
-                                    (buffer + amount_copied));
+           /* Modify what needs to be modified.  */
+           if (VALUE_BITSIZE (toval))
+             modify_field (buffer + byte_offset,
+                           value_as_long (fromval),
+                           VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+           else if (use_buffer)
+             memcpy (buffer + VALUE_OFFSET (toval), raw_buffer, use_buffer);
            else
-             error ("Attempt to assign to an unmodifiable value.");
-         }
+             memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval),
+                     TYPE_LENGTH (type));
 
+           /* Copy it out.  */
+           for (regno = reg_offset, amount_copied = 0;
+                amount_copied < amount_to_copy;
+                amount_copied += REGISTER_RAW_SIZE (regno), regno++)
+             put_frame_register (frame, regno, buffer + amount_copied);
+
+         }
        if (register_changed_hook)
          register_changed_hook (-1);
        target_changed_event ();
-
+       break;
       }
-      break;
-      
       
     default:
       error ("Left operand of assignment is not an lvalue.");