@@ -1453,7 +1453,14 @@ put_frame_register (frame_info_ptr next_frame, int regnum,
break;
}
case lval_register:
- get_thread_regcache (inferior_thread ())->cooked_write (realnum, buf);
+ /* Not sure if that's always true... but we have a problem if not. */
+ gdb_assert (size == register_size (gdbarch, realnum));
+
+ if (realnum < gdbarch_num_regs (gdbarch)
+ || !gdbarch_pseudo_register_write_p (gdbarch))
+ get_thread_regcache (inferior_thread ())->cooked_write (realnum, buf);
+ else
+ gdbarch_pseudo_register_write (gdbarch, next_frame, realnum, buf);
break;
default:
error (_("Attempt to assign to an unmodifiable value."));
@@ -200,12 +200,25 @@ typedef struct value * (gdbarch_pseudo_register_read_value_ftype) (struct gdbarc
extern struct value * gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, frame_info_ptr next_frame, int cookednum);
extern void set_gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, gdbarch_pseudo_register_read_value_ftype *pseudo_register_read_value);
+/* Write bytes in BUF to pseudo register with number PSEUDO_REG_NUM.
+
+ Raw registers backing the pseudo register should be written to using
+ NEXT_FRAME. */
+
+extern bool gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_pseudo_register_write_ftype) (struct gdbarch *gdbarch, frame_info_ptr next_frame, int pseudo_reg_num, gdb::array_view<const gdb_byte> buf);
+extern void gdbarch_pseudo_register_write (struct gdbarch *gdbarch, frame_info_ptr next_frame, int pseudo_reg_num, gdb::array_view<const gdb_byte> buf);
+extern void set_gdbarch_pseudo_register_write (struct gdbarch *gdbarch, gdbarch_pseudo_register_write_ftype *pseudo_register_write);
+
/* Write bytes to a pseudo register.
This is marked as deprecated because it gets passed a regcache for
implementations to write raw registers in. This doesn't work for unwound
frames, where the raw registers backing the pseudo registers may have been
- saved elsewhere. */
+ saved elsewhere.
+
+ Implementations should be migrated to implement pseudo_register_write instead. */
extern bool gdbarch_deprecated_pseudo_register_write_p (struct gdbarch *gdbarch);
@@ -74,6 +74,7 @@ struct gdbarch
gdbarch_virtual_frame_pointer_ftype *virtual_frame_pointer = legacy_virtual_frame_pointer;
gdbarch_pseudo_register_read_ftype *pseudo_register_read = nullptr;
gdbarch_pseudo_register_read_value_ftype *pseudo_register_read_value = nullptr;
+ gdbarch_pseudo_register_write_ftype *pseudo_register_write = nullptr;
gdbarch_deprecated_pseudo_register_write_ftype *deprecated_pseudo_register_write = nullptr;
int num_regs = -1;
int num_pseudo_regs = 0;
@@ -330,6 +331,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of virtual_frame_pointer, invalid_p == 0 */
/* Skip verify of pseudo_register_read, has predicate. */
/* Skip verify of pseudo_register_read_value, has predicate. */
+ /* Skip verify of pseudo_register_write, has predicate. */
/* Skip verify of deprecated_pseudo_register_write, has predicate. */
if (gdbarch->num_regs == -1)
log.puts ("\n\tnum_regs");
@@ -649,6 +651,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
gdb_printf (file,
"gdbarch_dump: pseudo_register_read_value = <%s>\n",
host_address_to_string (gdbarch->pseudo_register_read_value));
+ gdb_printf (file,
+ "gdbarch_dump: gdbarch_pseudo_register_write_p() = %d\n",
+ gdbarch_pseudo_register_write_p (gdbarch));
+ gdb_printf (file,
+ "gdbarch_dump: pseudo_register_write = <%s>\n",
+ host_address_to_string (gdbarch->pseudo_register_write));
gdb_printf (file,
"gdbarch_dump: gdbarch_deprecated_pseudo_register_write_p() = %d\n",
gdbarch_deprecated_pseudo_register_write_p (gdbarch));
@@ -1902,6 +1910,30 @@ set_gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch,
gdbarch->pseudo_register_read_value = pseudo_register_read_value;
}
+bool
+gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->pseudo_register_write != NULL;
+}
+
+void
+gdbarch_pseudo_register_write (struct gdbarch *gdbarch, frame_info_ptr next_frame, int pseudo_reg_num, gdb::array_view<const gdb_byte> buf)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->pseudo_register_write != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_pseudo_register_write called\n");
+ gdbarch->pseudo_register_write (gdbarch, next_frame, pseudo_reg_num, buf);
+}
+
+void
+set_gdbarch_pseudo_register_write (struct gdbarch *gdbarch,
+ gdbarch_pseudo_register_write_ftype pseudo_register_write)
+{
+ gdbarch->pseudo_register_write = pseudo_register_write;
+}
+
bool
gdbarch_deprecated_pseudo_register_write_p (struct gdbarch *gdbarch)
{
@@ -418,6 +418,23 @@ never be called.
predicate=True,
)
+Method(
+ comment="""
+Write bytes in BUF to pseudo register with number PSEUDO_REG_NUM.
+
+Raw registers backing the pseudo register should be written to using
+NEXT_FRAME.
+""",
+ type="void",
+ name="pseudo_register_write",
+ params=[
+ ("frame_info_ptr", "next_frame"),
+ ("int", "pseudo_reg_num"),
+ ("gdb::array_view<const gdb_byte>", "buf"),
+ ],
+ predicate=True,
+)
+
Method(
comment="""
Write bytes to a pseudo register.
@@ -426,6 +443,8 @@ This is marked as deprecated because it gets passed a regcache for
implementations to write raw registers in. This doesn't work for unwound
frames, where the raw registers backing the pseudo registers may have been
saved elsewhere.
+
+Implementations should be migrated to implement pseudo_register_write instead.
""",
type="void",
name="deprecated_pseudo_register_write",
@@ -911,6 +911,10 @@ regcache::cooked_write (int regnum, gdb::array_view<const gdb_byte> src)
if (regnum < num_raw_registers ())
raw_write (regnum, src);
+ else if (gdbarch_pseudo_register_write_p (m_descr->gdbarch))
+ gdbarch_pseudo_register_write
+ (m_descr->gdbarch, get_next_frame_sentinel_okay (get_current_frame ()),
+ regnum, src);
else
gdbarch_deprecated_pseudo_register_write (m_descr->gdbarch, this, regnum,
src.data ());
@@ -4057,6 +4057,23 @@ pseudo_from_raw_part (frame_info_ptr next_frame, int pseudo_reg_num,
/* See value.h. */
+void
+pseudo_to_raw_part (frame_info_ptr next_frame,
+ gdb::array_view<const gdb_byte> pseudo_buf,
+ int raw_reg_num, int raw_offset)
+{
+ int raw_reg_size
+ = register_size (frame_unwind_arch (next_frame), raw_reg_num);
+
+ /* When overflowing a register, put_frame_register_bytes writes to the
+ subsequent registers. We don't want that behavior here, so make sure
+ the write is wholly within register RAW_REG_NUM. */
+ gdb_assert (raw_offset + pseudo_buf.size () <= raw_reg_size);
+ put_frame_register_bytes (next_frame, raw_reg_num, raw_offset, pseudo_buf);
+}
+
+/* See value.h. */
+
value *
pseudo_from_concat_raw (frame_info_ptr next_frame, int pseudo_reg_num,
int raw_reg_1_num, int raw_reg_2_num)
@@ -4080,6 +4097,29 @@ pseudo_from_concat_raw (frame_info_ptr next_frame, int pseudo_reg_num,
return pseudo_reg_val;
}
+/* See value.h. */
+
+void
+pseudo_to_concat_raw (frame_info_ptr next_frame,
+ gdb::array_view<const gdb_byte> pseudo_buf,
+ int raw_reg_1_num, int raw_reg_2_num)
+{
+ int src_offset = 0;
+ gdbarch *arch = frame_unwind_arch (next_frame);
+
+ int raw_reg_1_size = register_size (arch, raw_reg_1_num);
+ put_frame_register_bytes (next_frame, raw_reg_1_num, 0,
+ pseudo_buf.slice (src_offset, raw_reg_1_size));
+ src_offset += raw_reg_1_size;
+
+ int raw_reg_2_size = register_size (arch, raw_reg_2_num);
+ put_frame_register_bytes (next_frame, raw_reg_2_num, 0,
+ pseudo_buf.slice (src_offset, raw_reg_2_size));
+ src_offset += raw_reg_2_size;
+
+ gdb_assert (src_offset == pseudo_buf.size ());
+}
+
/* See value.h. */
value *
@@ -4111,6 +4151,34 @@ pseudo_from_concat_raw (frame_info_ptr next_frame, int pseudo_reg_num,
return pseudo_reg_val;
}
+/* See value.h. */
+
+void
+pseudo_to_concat_raw (frame_info_ptr next_frame,
+ gdb::array_view<const gdb_byte> pseudo_buf,
+ int raw_reg_1_num, int raw_reg_2_num, int raw_reg_3_num)
+{
+ int src_offset = 0;
+ gdbarch *arch = frame_unwind_arch (next_frame);
+
+ int raw_reg_1_size = register_size (arch, raw_reg_1_num);
+ put_frame_register_bytes (next_frame, raw_reg_1_num, 0,
+ pseudo_buf.slice (src_offset, raw_reg_1_size));
+ src_offset += raw_reg_1_size;
+
+ int raw_reg_2_size = register_size (arch, raw_reg_2_num);
+ put_frame_register_bytes (next_frame, raw_reg_2_num, 0,
+ pseudo_buf.slice (src_offset, raw_reg_2_size));
+ src_offset += raw_reg_2_size;
+
+ int raw_reg_3_size = register_size (arch, raw_reg_3_num);
+ put_frame_register_bytes (next_frame, raw_reg_3_num, 0,
+ pseudo_buf.slice (src_offset, raw_reg_3_size));
+ src_offset += raw_reg_3_size;
+
+ gdb_assert (src_offset == pseudo_buf.size ());
+}
+
/* Implementation of the convenience function $_isvoid. */
static struct value *
@@ -1661,6 +1661,13 @@ struct scoped_array_length_limiting
value *pseudo_from_raw_part (frame_info_ptr next_frame, int pseudo_reg_num,
int raw_reg_num, int raw_offset);
+/* Write PSEUDO_BUF, the contents of a pseudo register, to part of raw register
+ RAW_REG_NUM starting at RAW_OFFSET. */
+
+void pseudo_to_raw_part (frame_info_ptr next_frame,
+ gdb::array_view<const gdb_byte> pseudo_buf,
+ int raw_reg_num, int raw_offset);
+
/* Create a value for pseudo register PSEUDO_REG_NUM by concatenating raw
registers RAW_REG_1_NUM and RAW_REG_2_NUM.
@@ -1670,10 +1677,25 @@ value *pseudo_from_raw_part (frame_info_ptr next_frame, int pseudo_reg_num,
value *pseudo_from_concat_raw (frame_info_ptr next_frame, int pseudo_reg_num,
int raw_reg_1_num, int raw_reg_2_num);
+/* Write PSEUDO_BUF, the contents of a pseudo register, to the two raw registers
+ RAW_REG_1_NUM and RAW_REG_2_NUM. */
+
+void pseudo_to_concat_raw (frame_info_ptr next_frame,
+ gdb::array_view<const gdb_byte> pseudo_buf,
+ int raw_reg_1_num, int raw_reg_2_num);
+
/* Same as the above, but with three raw registers. */
value *pseudo_from_concat_raw (frame_info_ptr next_frame, int pseudo_reg_num,
int raw_reg_1_num, int raw_reg_2_num,
int raw_reg_3_num);
+/* Write PSEUDO_BUF, the contents of a pseudo register, to the three raw
+ registers RAW_REG_1_NUM, RAW_REG_2_NUM and RAW_REG_3_NUM. */
+
+void pseudo_to_concat_raw (frame_info_ptr next_frame,
+ gdb::array_view<const gdb_byte> pseudo_buf,
+ int raw_reg_1_num, int raw_reg_2_num,
+ int raw_reg_3_num);
+
#endif /* !defined (VALUE_H) */