diff options
Diffstat (limited to 'gdb/valops.c')
-rw-r--r-- | gdb/valops.c | 199 |
1 files changed, 104 insertions, 95 deletions
diff --git a/gdb/valops.c b/gdb/valops.c index 91b97b4..61688c4 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -632,132 +632,120 @@ value_assign (struct value *toval, struct value *fromval) } break; - case lval_register: - if (VALUE_BITSIZE (toval)) - { - char buffer[sizeof (LONGEST)]; - int len = - REGISTER_RAW_SIZE (VALUE_REGNO (toval)) - VALUE_OFFSET (toval); - - if (len > (int) sizeof (LONGEST)) - error ("Can't handle bitfields in registers larger than %d bits.", - (int) sizeof (LONGEST) * HOST_CHAR_BIT); - - if (VALUE_BITPOS (toval) + VALUE_BITSIZE (toval) - > len * HOST_CHAR_BIT) - /* Getting this right would involve being very careful about - byte order. */ - error ("Can't assign to bitfields that cross register " - "boundaries."); - - read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), - buffer, len); - modify_field (buffer, value_as_long (fromval), - VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); - write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), - buffer, len); - } - else if (use_buffer) - write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), - raw_buffer, use_buffer); - else - { - /* Do any conversion necessary when storing this type to more - than one register. */ -#ifdef REGISTER_CONVERT_FROM_TYPE - memcpy (raw_buffer, VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); - REGISTER_CONVERT_FROM_TYPE (VALUE_REGNO (toval), type, raw_buffer); - write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), - raw_buffer, TYPE_LENGTH (type)); -#else - write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), - VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); -#endif - } - - target_changed_event (); - - /* Assigning to the stack pointer, frame pointer, and other - (architecture and calling convention specific) registers may - cause the frame cache to be out of date. We just do this - on all assignments to registers for simplicity; I doubt the slowdown - matters. */ - reinit_frame_cache (); - break; - case lval_reg_frame_relative: + case lval_register: { + struct frame_id old_frame; /* 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_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type)); - int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval)); - int byte_offset = VALUE_OFFSET (toval) % reg_size; - int reg_offset = VALUE_OFFSET (toval) / reg_size; int amount_copied; - - /* Make the buffer large enough in all cases. */ - /* FIXME (alloca): Not safe for very large data types. */ - char *buffer = (char *) alloca (amount_to_copy - + sizeof (LONGEST) - + MAX_REGISTER_RAW_SIZE); - + int amount_to_copy; + char *buffer; + int value_reg; + int reg_offset; + int byte_offset; int regno; struct frame_info *frame; + /* Since modifying a register can trash the frame chain, we + save the old frame and then restore the new frame + afterwards. */ + get_frame_id (selected_frame, &old_frame); + /* Figure out which frame this is in currently. */ - for (frame = get_current_frame (); - frame && FRAME_FP (frame) != VALUE_FRAME (toval); - frame = get_prev_frame (frame)) - ; + if (VALUE_LVAL (toval) == lval_register) + { + frame = get_current_frame (); + value_reg = VALUE_REGNO (toval); + } + else + { + for (frame = get_current_frame (); + frame && FRAME_FP (frame) != VALUE_FRAME (toval); + frame = get_prev_frame (frame)) + ; + value_reg = VALUE_FRAME_REGNUM (toval); + } if (!frame) error ("Value being assigned to is no longer active."); - amount_to_copy += (reg_size - amount_to_copy % reg_size); + /* 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 = VALUE_FRAME_REGNUM (toval) + reg_offset, - amount_copied = 0); + /* 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_RAW_SIZE); + + /* Copy it in. */ + for (regno = reg_offset, amount_copied = 0; amount_copied < amount_to_copy; - amount_copied += reg_size, regno++) + amount_copied += REGISTER_RAW_SIZE (regno), regno++) { - get_saved_register (buffer + amount_copied, - (int *) NULL, (CORE_ADDR *) NULL, - frame, regno, (enum lval_type *) NULL); + 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)); + { + modify_field (buffer + byte_offset, + value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + } else if (use_buffer) - memcpy (buffer + byte_offset, raw_buffer, use_buffer); + { + memcpy (buffer + VALUE_OFFSET (toval), raw_buffer, use_buffer); + } else - memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval), - TYPE_LENGTH (type)); + { + 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 + } - /* Copy it back. */ - for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset, - amount_copied = 0); + /* Copy it out. */ + for (regno = reg_offset, amount_copied = 0; amount_copied < amount_to_copy; - amount_copied += reg_size, regno++) + amount_copied += REGISTER_RAW_SIZE (regno), regno++) { enum lval_type lval; CORE_ADDR addr; int optim; - + int realnum; + /* Just find out where to put it. */ - get_saved_register ((char *) NULL, - &optim, &addr, frame, regno, &lval); - + frame_register (frame, regno, &optim, &lval, &addr, &realnum, + NULL); + if (optim) error ("Attempt to assign to a value that was optimized out."); if (lval == lval_memory) - write_memory (addr, buffer + amount_copied, reg_size); + write_memory (addr, buffer + amount_copied, + REGISTER_RAW_SIZE (regno)); else if (lval == lval_register) - write_register_bytes (addr, buffer + amount_copied, reg_size); + regcache_cooked_write (current_regcache, realnum, + (buffer + amount_copied)); else error ("Attempt to assign to an unmodifiable value."); } @@ -765,10 +753,31 @@ value_assign (struct value *toval, struct value *fromval) if (register_changed_hook) register_changed_hook (-1); target_changed_event (); + + /* Assigning to the stack pointer, frame pointer, and other + (architecture and calling convention specific) registers + may cause the frame cache to be out of date. We just do + this on all assignments to registers for simplicity; I + doubt the slowdown matters. */ + reinit_frame_cache (); + + /* Having destoroyed the frame cache, restore the selected + frame. */ + /* FIXME: cagney/2002-11-02: There has to be a better way of + doing this. Instead of constantly saving/restoring the + frame. Why not create a get_selected_frame() function + that, having saved the selected frame's ID can + automatically re-find the previously selected frame + automatically. */ + { + struct frame_info *fi = frame_find_by_id (old_frame); + if (fi != NULL) + select_frame (fi); + } } break; - - + + default: error ("Left operand of assignment is not an lvalue."); } |