aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/aarch64-tdep.c148
-rw-r--r--gdb/amd64-tdep.c43
-rw-r--r--gdb/dwarf2/frame.c5
-rw-r--r--gdb/frame.c36
-rw-r--r--gdb/gdbarch-gen.h4
-rw-r--r--gdb/gdbarch.c4
-rw-r--r--gdb/gdbarch_components.py2
-rw-r--r--gdb/i386-tdep.c224
-rw-r--r--gdb/i386-tdep.h7
-rw-r--r--gdb/regcache.c38
-rw-r--r--gdb/value.c70
-rw-r--r--gdb/value.h26
12 files changed, 322 insertions, 285 deletions
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index b0aee19..d901b69 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -3104,25 +3104,14 @@ aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
/* Helper for aarch64_pseudo_read_value. */
-static struct value *
-aarch64_pseudo_read_value_1 (struct gdbarch *gdbarch,
- readable_regcache *regcache, int regnum_offset,
- int regsize, struct value *result_value)
+static value *
+aarch64_pseudo_read_value_1 (frame_info_ptr next_frame,
+ const int pseudo_reg_num, int raw_regnum_offset)
{
- unsigned v_regnum = AARCH64_V0_REGNUM + regnum_offset;
-
- /* Enough space for a full vector register. */
- gdb_byte reg_buf[register_size (gdbarch, AARCH64_V0_REGNUM)];
- static_assert (AARCH64_V0_REGNUM == AARCH64_SVE_Z0_REGNUM);
+ unsigned v_regnum = AARCH64_V0_REGNUM + raw_regnum_offset;
- if (regcache->raw_read (v_regnum, reg_buf) != REG_VALID)
- result_value->mark_bytes_unavailable (0,
- result_value->type ()->length ());
- else
- memcpy (result_value->contents_raw ().data (), reg_buf, regsize);
-
- return result_value;
- }
+ return pseudo_from_raw_part (next_frame, pseudo_reg_num, v_regnum, 0);
+}
/* Helper function for reading/writing ZA pseudo-registers. Given REGNUM,
a ZA pseudo-register number, return, in OFFSETS, the information on positioning
@@ -3205,54 +3194,47 @@ aarch64_za_offsets_from_regnum (struct gdbarch *gdbarch, int regnum,
/* Given REGNUM, a SME pseudo-register number, return its value in RESULT. */
-static struct value *
-aarch64_sme_pseudo_register_read (struct gdbarch *gdbarch,
- readable_regcache *regcache, int regnum,
- struct value *result)
+static value *
+aarch64_sme_pseudo_register_read (gdbarch *gdbarch, frame_info_ptr next_frame,
+ const int pseudo_reg_num)
{
aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
gdb_assert (tdep->has_sme ());
gdb_assert (tdep->sme_svq > 0);
- gdb_assert (tdep->sme_pseudo_base <= regnum);
- gdb_assert (regnum < tdep->sme_pseudo_base + tdep->sme_pseudo_count);
+ gdb_assert (tdep->sme_pseudo_base <= pseudo_reg_num);
+ gdb_assert (pseudo_reg_num < tdep->sme_pseudo_base + tdep->sme_pseudo_count);
/* Fetch the offsets that we need in order to read from the correct blocks
of ZA. */
struct za_offsets offsets;
- aarch64_za_offsets_from_regnum (gdbarch, regnum, offsets);
+ aarch64_za_offsets_from_regnum (gdbarch, pseudo_reg_num, offsets);
/* Fetch the contents of ZA. */
- size_t svl = sve_vl_from_vq (tdep->sme_svq);
- gdb::byte_vector za (std::pow (svl, 2));
- regcache->raw_read (tdep->sme_za_regnum, za.data ());
+ value *za_value = value_of_register (tdep->sme_za_regnum, next_frame);
+ value *result = value::allocate_register (next_frame, pseudo_reg_num);
/* Copy the requested data. */
for (int chunks = 0; chunks < offsets.chunks; chunks++)
{
- const gdb_byte *source
- = za.data () + offsets.starting_offset + chunks * offsets.stride_size;
- gdb_byte *destination
- = result->contents_raw ().data () + chunks * offsets.chunk_size;
-
- memcpy (destination, source, offsets.chunk_size);
+ int src_offset = offsets.starting_offset + chunks * offsets.stride_size;
+ int dst_offset = chunks * offsets.chunk_size;
+ za_value->contents_copy (result, dst_offset, src_offset,
+ offsets.chunk_size);
}
+
return result;
}
/* Implement the "pseudo_register_read_value" gdbarch method. */
-static struct value *
-aarch64_pseudo_read_value (struct gdbarch *gdbarch, readable_regcache *regcache,
- int regnum)
+static value *
+aarch64_pseudo_read_value (gdbarch *gdbarch, frame_info_ptr next_frame,
+ const int pseudo_reg_num)
{
aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
- struct value *result_value = value::allocate (register_type (gdbarch, regnum));
- result_value->set_lval (lval_register);
- VALUE_REGNUM (result_value) = regnum;
-
- if (is_w_pseudo_register (gdbarch, regnum))
+ if (is_w_pseudo_register (gdbarch, pseudo_reg_num))
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* Default offset for little endian. */
@@ -3262,53 +3244,49 @@ aarch64_pseudo_read_value (struct gdbarch *gdbarch, readable_regcache *regcache,
offset = 4;
/* Find the correct X register to extract the data from. */
- int x_regnum = AARCH64_X0_REGNUM + (regnum - tdep->w_pseudo_base);
- gdb_byte data[4];
+ int x_regnum
+ = AARCH64_X0_REGNUM + (pseudo_reg_num - tdep->w_pseudo_base);
/* Read the bottom 4 bytes of X. */
- if (regcache->raw_read_part (x_regnum, offset, 4, data) != REG_VALID)
- result_value->mark_bytes_unavailable (0, 4);
- else
- memcpy (result_value->contents_raw ().data (), data, 4);
-
- return result_value;
+ return pseudo_from_raw_part (next_frame, pseudo_reg_num, x_regnum,
+ offset);
}
- else if (is_sme_pseudo_register (gdbarch, regnum))
- return aarch64_sme_pseudo_register_read (gdbarch, regcache, regnum,
- result_value);
-
- regnum -= gdbarch_num_regs (gdbarch);
-
- if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_Q0_REGNUM,
- Q_REGISTER_SIZE, result_value);
-
- if (regnum >= AARCH64_D0_REGNUM && regnum < AARCH64_D0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_D0_REGNUM,
- D_REGISTER_SIZE, result_value);
-
- if (regnum >= AARCH64_S0_REGNUM && regnum < AARCH64_S0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_S0_REGNUM,
- S_REGISTER_SIZE, result_value);
-
- if (regnum >= AARCH64_H0_REGNUM && regnum < AARCH64_H0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_H0_REGNUM,
- H_REGISTER_SIZE, result_value);
-
- if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_B0_REGNUM,
- B_REGISTER_SIZE, result_value);
-
- if (tdep->has_sve () && regnum >= AARCH64_SVE_V0_REGNUM
- && regnum < AARCH64_SVE_V0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_SVE_V0_REGNUM,
- V_REGISTER_SIZE, result_value);
+ else if (is_sme_pseudo_register (gdbarch, pseudo_reg_num))
+ return aarch64_sme_pseudo_register_read (gdbarch, next_frame,
+ pseudo_reg_num);
+
+ /* Offset in the "pseudo-register space". */
+ int pseudo_offset = pseudo_reg_num - gdbarch_num_regs (gdbarch);
+
+ if (pseudo_offset >= AARCH64_Q0_REGNUM
+ && pseudo_offset < AARCH64_Q0_REGNUM + 32)
+ return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num,
+ pseudo_offset - AARCH64_Q0_REGNUM);
+
+ if (pseudo_offset >= AARCH64_D0_REGNUM
+ && pseudo_offset < AARCH64_D0_REGNUM + 32)
+ return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num,
+ pseudo_offset - AARCH64_D0_REGNUM);
+
+ if (pseudo_offset >= AARCH64_S0_REGNUM
+ && pseudo_offset < AARCH64_S0_REGNUM + 32)
+ return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num,
+ pseudo_offset - AARCH64_S0_REGNUM);
+
+ if (pseudo_offset >= AARCH64_H0_REGNUM
+ && pseudo_offset < AARCH64_H0_REGNUM + 32)
+ return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num,
+ pseudo_offset - AARCH64_H0_REGNUM);
+
+ if (pseudo_offset >= AARCH64_B0_REGNUM
+ && pseudo_offset < AARCH64_B0_REGNUM + 32)
+ return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num,
+ pseudo_offset - AARCH64_B0_REGNUM);
+
+ if (tdep->has_sve () && pseudo_offset >= AARCH64_SVE_V0_REGNUM
+ && pseudo_offset < AARCH64_SVE_V0_REGNUM + 32)
+ return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num,
+ pseudo_offset - AARCH64_SVE_V0_REGNUM);
gdb_assert_not_reached ("regnum out of bound");
}
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index e6feee6..955a686 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -348,18 +348,12 @@ amd64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
return i386_pseudo_register_name (gdbarch, regnum);
}
-static struct value *
-amd64_pseudo_register_read_value (struct gdbarch *gdbarch,
- readable_regcache *regcache,
+static value *
+amd64_pseudo_register_read_value (gdbarch *gdbarch, frame_info_ptr next_frame,
int regnum)
{
i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
- value *result_value = value::allocate (register_type (gdbarch, regnum));
- result_value->set_lval (lval_register);
- VALUE_REGNUM (result_value) = regnum;
- gdb_byte *buf = result_value->contents_raw ().data ();
-
if (i386_byte_regnum_p (gdbarch, regnum))
{
int gpnum = regnum - tdep->al_regnum;
@@ -368,44 +362,21 @@ amd64_pseudo_register_read_value (struct gdbarch *gdbarch,
if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
{
gpnum -= AMD64_NUM_LOWER_BYTE_REGS;
- gdb_byte raw_buf[register_size (gdbarch, gpnum)];
/* Special handling for AH, BH, CH, DH. */
- register_status status = regcache->raw_read (gpnum, raw_buf);
- if (status == REG_VALID)
- memcpy (buf, raw_buf + 1, 1);
- else
- result_value->mark_bytes_unavailable (0,
- result_value->type ()->length ());
+ return pseudo_from_raw_part (next_frame, regnum, gpnum, 1);
}
else
- {
- gdb_byte raw_buf[register_size (gdbarch, gpnum)];
- register_status status = regcache->raw_read (gpnum, raw_buf);
- if (status == REG_VALID)
- memcpy (buf, raw_buf, 1);
- else
- result_value->mark_bytes_unavailable (0,
- result_value->type ()->length ());
- }
+ return pseudo_from_raw_part (next_frame, regnum, gpnum, 0);
}
else if (i386_dword_regnum_p (gdbarch, regnum))
{
int gpnum = regnum - tdep->eax_regnum;
- gdb_byte raw_buf[register_size (gdbarch, gpnum)];
- /* Extract (always little endian). */
- register_status status = regcache->raw_read (gpnum, raw_buf);
- if (status == REG_VALID)
- memcpy (buf, raw_buf, 4);
- else
- result_value->mark_bytes_unavailable (0,
- result_value->type ()->length ());
+
+ return pseudo_from_raw_part (next_frame, regnum, gpnum, 0);
}
else
- i386_pseudo_register_read_into_value (gdbarch, regcache, regnum,
- result_value);
-
- return result_value;
+ return i386_pseudo_register_read_value (gdbarch, next_frame, regnum);
}
static void
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index d72dd0a..d3d1ecd 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -1220,7 +1220,10 @@ dwarf2_frame_prev_register (frame_info_ptr this_frame, void **this_cache,
"undefined"). Code above issues a complaint about this.
Here just fudge the books, assume GCC, and that the value is
more inner on the stack. */
- return frame_unwind_got_register (this_frame, regnum, regnum);
+ if (regnum < gdbarch_num_regs (gdbarch))
+ return frame_unwind_got_register (this_frame, regnum, regnum);
+ else
+ return nullptr;
case DWARF2_FRAME_REG_SAME_VALUE:
return frame_unwind_got_register (this_frame, regnum, regnum);
diff --git a/gdb/frame.c b/gdb/frame.c
index d260e8c..a9cad1d 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1257,9 +1257,39 @@ frame_unwind_register_value (frame_info_ptr next_frame, int regnum)
frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache);
/* Ask this frame to unwind its register. */
- value *value = next_frame->unwind->prev_register (next_frame,
- &next_frame->prologue_cache,
- regnum);
+ value *value
+ = next_frame->unwind->prev_register (next_frame,
+ &next_frame->prologue_cache, regnum);
+ if (value == nullptr)
+ {
+ 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 if (gdbarch_pseudo_register_read_p (gdbarch))
+ {
+ value = value::allocate_register (next_frame, regnum);
+
+ /* Passing the current regcache is known to be broken, the pseudo
+ register value will be constructed using the current raw registers,
+ rather than reading them using NEXT_FRAME. Architectures should be
+ migrated to gdbarch_pseudo_register_read_value. */
+ register_status status = gdbarch_pseudo_register_read
+ (gdbarch, get_thread_regcache (inferior_thread ()), regnum,
+ value->contents_writeable ().data ());
+ if (status == REG_UNAVAILABLE)
+ value->mark_bytes_unavailable (0, value->type ()->length ());
+ }
+ else
+ error (_("Can't unwind value of register %d (%s)"), regnum,
+ user_reg_map_regnum_to_name (gdbarch, regnum));
+ }
if (frame_debug)
{
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index 9f468bd..c70bfc9 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -196,8 +196,8 @@ extern void set_gdbarch_pseudo_register_read (struct gdbarch *gdbarch, gdbarch_p
extern bool 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_ptr next_frame, int cookednum);
+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);
extern bool gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch);
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index ea6e4c6..06ff5257 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -1886,13 +1886,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_ptr next_frame, int cookednum)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->pseudo_register_read_value != NULL);
if (gdbarch_debug >= 2)
gdb_printf (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, next_frame, cookednum);
}
void
diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
index 694ac36..c597b38 100644
--- a/gdb/gdbarch_components.py
+++ b/gdb/gdbarch_components.py
@@ -414,7 +414,7 @@ never be called.
""",
type="struct value *",
name="pseudo_register_read_value",
- params=[("readable_regcache *", "regcache"), ("int", "cookednum")],
+ params=[("frame_info_ptr", "next_frame"), ("int", "cookednum")],
predicate=True,
)
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 7a13a41..cb24a73 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -3411,195 +3411,131 @@ i386_mmx_regnum_to_fp_regnum (readable_regcache *regcache, int regnum)
return (I387_ST0_REGNUM (tdep) + fpreg);
}
+/* Map a cooked register onto a raw register or memory. For the i386,
+ the MMX registers need to be mapped onto floating point registers. */
+
+static int
+i386_mmx_regnum_to_fp_regnum (frame_info_ptr next_frame, int regnum)
+{
+ gdbarch *arch = frame_unwind_arch (next_frame);
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (arch);
+ ULONGEST fstat
+ = frame_unwind_register_unsigned (next_frame, I387_FSTAT_REGNUM (tdep));
+ int tos = (fstat >> 11) & 0x7;
+ int mmxreg = regnum - tdep->mm0_regnum;
+ int fpreg = (mmxreg + tos) % 8;
+
+ return (I387_ST0_REGNUM (tdep) + fpreg);
+}
+
/* A helper function for us by i386_pseudo_register_read_value and
amd64_pseudo_register_read_value. It does all the work but reads
the data into an already-allocated value. */
-void
-i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
- readable_regcache *regcache,
- int regnum,
- struct value *result_value)
+value *
+i386_pseudo_register_read_value (gdbarch *gdbarch, frame_info_ptr next_frame,
+ const int pseudo_reg_num)
{
- gdb_byte raw_buf[I386_MAX_REGISTER_SIZE];
- enum register_status status;
- gdb_byte *buf = result_value->contents_raw ().data ();
-
- if (i386_mmx_regnum_p (gdbarch, regnum))
+ if (i386_mmx_regnum_p (gdbarch, pseudo_reg_num))
{
- int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
+ int fpnum = i386_mmx_regnum_to_fp_regnum (next_frame, pseudo_reg_num);
/* Extract (always little endian). */
- status = regcache->raw_read (fpnum, raw_buf);
- if (status != REG_VALID)
- result_value->mark_bytes_unavailable (0,
- result_value->type ()->length ());
- else
- memcpy (buf, raw_buf, register_size (gdbarch, regnum));
+ return pseudo_from_raw_part (next_frame, pseudo_reg_num, fpnum, 0);
}
else
{
i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
- if (i386_bnd_regnum_p (gdbarch, regnum))
+ if (i386_bnd_regnum_p (gdbarch, pseudo_reg_num))
{
- regnum -= tdep->bnd0_regnum;
+ int i = pseudo_reg_num - 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)
- result_value->mark_bytes_unavailable (0, 16);
- else
+ value *bndr_value
+ = value_of_register (I387_BND0R_REGNUM (tdep) + i, next_frame);
+ int size = builtin_type (gdbarch)->builtin_data_ptr->length ();
+ value *result
+ = value::allocate_register (next_frame, pseudo_reg_num);
+
+ /* Copy the lower. */
+ bndr_value->contents_copy (result, 0, 0, size);
+
+ /* Copy the upper. */
+ bndr_value->contents_copy (result, size, 8, size);
+
+ /* If upper bytes are available, compute ones' complement. */
+ if (result->bytes_available (size, size))
{
bfd_endian byte_order
- = gdbarch_byte_order (current_inferior ()->arch ());
- LONGEST upper, lower;
- int size = builtin_type (gdbarch)->builtin_data_ptr->length ();
-
- lower = extract_unsigned_integer (raw_buf, 8, byte_order);
- upper = extract_unsigned_integer (raw_buf + 8, 8, byte_order);
+ = gdbarch_byte_order (frame_unwind_arch (next_frame));
+ gdb::array_view<gdb_byte> upper_bytes
+ = result->contents_raw ().slice (size, size);
+ ULONGEST upper
+ = extract_unsigned_integer (upper_bytes, byte_order);
upper = ~upper;
-
- memcpy (buf, &lower, size);
- memcpy (buf + size, &upper, size);
+ store_unsigned_integer (upper_bytes, byte_order, upper);
}
+
+ return result;
}
- else if (i386_zmm_regnum_p (gdbarch, regnum))
+ else if (i386_zmm_regnum_p (gdbarch, pseudo_reg_num))
{
- regnum -= tdep->zmm0_regnum;
-
- 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)
- result_value->mark_bytes_unavailable (0, 16);
- else
- memcpy (buf, raw_buf, 16);
+ /* Which register is it, relative to zmm0. */
+ int i_0 = pseudo_reg_num - tdep->zmm0_regnum;
- /* Extract (always little endian). Read upper 128bits. */
- status = regcache->raw_read (tdep->ymm0h_regnum + regnum,
- raw_buf);
- if (status != REG_VALID)
- result_value->mark_bytes_unavailable (16, 16);
- else
- memcpy (buf + 16, raw_buf, 16);
- }
+ if (i_0 < num_lower_zmm_regs)
+ return pseudo_from_concat_raw (next_frame, pseudo_reg_num,
+ I387_XMM0_REGNUM (tdep) + i_0,
+ tdep->ymm0h_regnum + i_0,
+ tdep->zmm0h_regnum + i_0);
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)
- result_value->mark_bytes_unavailable (0, 16);
- else
- 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)
- result_value->mark_bytes_unavailable (16, 16);
- else
- memcpy (buf + 16, raw_buf, 16);
- }
+ /* Which register is it, relative to zmm16. */
+ int i_16 = i_0 - num_lower_zmm_regs;
- /* Read upper 256bits. */
- status = regcache->raw_read (tdep->zmm0h_regnum + regnum,
- raw_buf);
- if (status != REG_VALID)
- result_value->mark_bytes_unavailable (32, 32);
- else
- memcpy (buf + 32, raw_buf, 32);
+ return pseudo_from_concat_raw (next_frame, pseudo_reg_num,
+ I387_XMM16_REGNUM (tdep) + i_16,
+ I387_YMM16H_REGNUM (tdep) + i_16,
+ tdep->zmm0h_regnum + i_0);
+ }
}
- else if (i386_ymm_regnum_p (gdbarch, regnum))
+ else if (i386_ymm_regnum_p (gdbarch, pseudo_reg_num))
{
- regnum -= tdep->ymm0_regnum;
+ int i = pseudo_reg_num - 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)
- result_value->mark_bytes_unavailable (0, 16);
- else
- memcpy (buf, raw_buf, 16);
- /* Read upper 128bits. */
- status = regcache->raw_read (tdep->ymm0h_regnum + regnum,
- raw_buf);
- if (status != REG_VALID)
- result_value->mark_bytes_unavailable (16, 32);
- else
- memcpy (buf + 16, raw_buf, 16);
+ return pseudo_from_concat_raw (next_frame, pseudo_reg_num,
+ I387_XMM0_REGNUM (tdep) + i,
+ tdep->ymm0h_regnum + i);
}
- else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
+ else if (i386_ymm_avx512_regnum_p (gdbarch, pseudo_reg_num))
{
- 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)
- result_value->mark_bytes_unavailable (0, 16);
- else
- memcpy (buf, raw_buf, 16);
- /* Read upper 128bits. */
- status = regcache->raw_read (tdep->ymm16h_regnum + regnum,
- raw_buf);
- if (status != REG_VALID)
- result_value->mark_bytes_unavailable (16, 16);
- else
- memcpy (buf + 16, raw_buf, 16);
+ int i = pseudo_reg_num - tdep->ymm16_regnum;
+
+ return pseudo_from_concat_raw (next_frame, pseudo_reg_num,
+ I387_XMM16_REGNUM (tdep) + i,
+ tdep->ymm16h_regnum + i);
}
- else if (i386_word_regnum_p (gdbarch, regnum))
+ else if (i386_word_regnum_p (gdbarch, pseudo_reg_num))
{
- int gpnum = regnum - tdep->ax_regnum;
+ int gpnum = pseudo_reg_num - tdep->ax_regnum;
/* Extract (always little endian). */
- status = regcache->raw_read (gpnum, raw_buf);
- if (status != REG_VALID)
- result_value->mark_bytes_unavailable (0,
- result_value->type ()->length ());
- else
- memcpy (buf, raw_buf, 2);
+ return pseudo_from_raw_part (next_frame, pseudo_reg_num, gpnum, 0);
}
- else if (i386_byte_regnum_p (gdbarch, regnum))
+ else if (i386_byte_regnum_p (gdbarch, pseudo_reg_num))
{
- int gpnum = regnum - tdep->al_regnum;
+ int gpnum = pseudo_reg_num - tdep->al_regnum;
/* Extract (always little endian). We read both lower and
upper registers. */
- status = regcache->raw_read (gpnum % 4, raw_buf);
- if (status != REG_VALID)
- result_value->mark_bytes_unavailable (0,
- result_value->type ()->length ());
- else if (gpnum >= 4)
- memcpy (buf, raw_buf + 1, 1);
- else
- memcpy (buf, raw_buf, 1);
+ return pseudo_from_raw_part (next_frame, pseudo_reg_num, gpnum % 4,
+ gpnum >= 4 ? 1 : 0);
}
else
internal_error (_("invalid regnum"));
}
}
-static struct value *
-i386_pseudo_register_read_value (struct gdbarch *gdbarch,
- readable_regcache *regcache,
- int regnum)
-{
- struct value *result;
-
- result = value::allocate (register_type (gdbarch, regnum));
- result->set_lval (lval_register);
- VALUE_REGNUM (result) = regnum;
-
- i386_pseudo_register_read_into_value (gdbarch, regcache, regnum, result);
-
- return result;
-}
-
void
i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, const gdb_byte *buf)
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 4283a52..970dc89 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -376,10 +376,9 @@ extern const char *i386_pseudo_register_name (struct gdbarch *gdbarch,
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,
- int regnum,
- struct value *result);
+extern value *i386_pseudo_register_read_value (gdbarch *gdbarch,
+ frame_info_ptr next_frame,
+ int regnum);
extern void i386_pseudo_register_write (struct gdbarch *gdbarch,
struct regcache *regcache,
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 9b3fd4f..9575988 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -735,8 +735,9 @@ readable_regcache::cooked_read (int regnum, gdb::array_view<gdb_byte> dst)
{
register_status result = REG_VALID;
scoped_value_mark mark;
- value *computed
- = gdbarch_pseudo_register_read_value (m_descr->gdbarch, this, regnum);
+ value *computed = gdbarch_pseudo_register_read_value
+ (m_descr->gdbarch, get_next_frame_sentinel_okay (get_current_frame ()),
+ regnum);
if (computed->entirely_available ())
copy (computed->contents_raw (), dst);
@@ -788,8 +789,9 @@ readable_regcache::cooked_read_value (int regnum)
return result;
}
else
- return gdbarch_pseudo_register_read_value (m_descr->gdbarch,
- this, regnum);
+ return gdbarch_pseudo_register_read_value
+ (m_descr->gdbarch, get_next_frame_sentinel_okay (get_current_frame ()),
+ regnum);
}
enum register_status
@@ -1952,10 +1954,18 @@ cooked_read_test (struct gdbarch *gdbarch)
break;
}
- readwrite_regcache readwrite (&mockctx.mock_inferior, gdbarch);
+ /* Install this regcache in the regcaches global structure, so that. */
+ pid_ptid_regcache_map &x = regcaches[&mockctx.mock_target];
+ ptid_regcache_map &y = x[mockctx.mock_ptid.pid ()];
+ regcache &readwrite
+ = *y.emplace (std::make_pair (mockctx.mock_ptid,
+ std::make_unique<readwrite_regcache> (
+ &mockctx.mock_inferior, gdbarch)))
+ ->second;
+
readwrite.set_ptid (mockctx.mock_ptid);
- gdb::byte_vector buf (register_size (gdbarch, nonzero_regnum));
+ gdb::byte_vector buf (register_size (gdbarch, nonzero_regnum));
readwrite.raw_read (nonzero_regnum, buf);
/* raw_read calls target_fetch_registers. */
@@ -2053,6 +2063,8 @@ cooked_read_test (struct gdbarch *gdbarch)
mockctx.mock_target.reset ();
}
+
+ regcaches.erase (&mockctx.mock_target);
}
/* Test regcache::cooked_write by writing some expected contents to
@@ -2067,7 +2079,17 @@ cooked_write_test (struct gdbarch *gdbarch)
/* Create a mock environment. A process_stratum target pushed. */
scoped_mock_context<target_ops_no_register> ctx (gdbarch);
- readwrite_regcache readwrite (&ctx.mock_inferior, gdbarch);
+
+
+ /* Install this regcache in the regcaches global structure, so that. */
+ pid_ptid_regcache_map &x = regcaches[&ctx.mock_target];
+ ptid_regcache_map &y = x[ctx.mock_ptid.pid ()];
+ regcache &readwrite
+ = *y.emplace (std::make_pair (ctx.mock_ptid,
+ std::make_unique<readwrite_regcache> (
+ &ctx.mock_inferior, gdbarch)))
+ ->second;
+
readwrite.set_ptid (ctx.mock_ptid);
const int num_regs = gdbarch_num_cooked_regs (gdbarch);
@@ -2148,6 +2170,8 @@ cooked_write_test (struct gdbarch *gdbarch)
SELF_CHECK (readwrite.cooked_read (regnum, buf) == REG_VALID);
SELF_CHECK (expected == buf);
}
+
+ regcaches.erase (&ctx.mock_target);
}
/* Verify that when two threads with the same ptid exist (from two different
diff --git a/gdb/value.c b/gdb/value.c
index 5e48a4c..20f8dcc 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -4056,6 +4056,76 @@ value::fetch_lazy ()
set_lazy (false);
}
+/* See value.h. */
+
+value *
+pseudo_from_raw_part (frame_info_ptr next_frame, int pseudo_reg_num,
+ int raw_reg_num, int raw_offset)
+{
+ value *pseudo_reg_val
+ = value::allocate_register (next_frame, pseudo_reg_num);
+ value *raw_reg_val = value_of_register (raw_reg_num, next_frame);
+ raw_reg_val->contents_copy (pseudo_reg_val, 0, raw_offset,
+ pseudo_reg_val->type ()->length ());
+ return pseudo_reg_val;
+}
+
+/* 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)
+{
+ value *pseudo_reg_val
+ = value::allocate_register (next_frame, pseudo_reg_num);
+ int dst_offset = 0;
+
+ value *raw_reg_1_val = value_of_register (raw_reg_1_num, next_frame);
+ raw_reg_1_val->contents_copy (pseudo_reg_val, dst_offset, 0,
+ raw_reg_1_val->type ()->length ());
+ dst_offset += raw_reg_1_val->type ()->length ();
+
+ value *raw_reg_2_val = value_of_register (raw_reg_2_num, next_frame);
+ raw_reg_2_val->contents_copy (pseudo_reg_val, dst_offset, 0,
+ raw_reg_2_val->type ()->length ());
+ dst_offset += raw_reg_2_val->type ()->length ();
+
+ gdb_assert (dst_offset == pseudo_reg_val->type ()->length ());
+
+ return pseudo_reg_val;
+}
+
+/* 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,
+ int raw_reg_3_num)
+{
+ value *pseudo_reg_val
+ = value::allocate_register (next_frame, pseudo_reg_num);
+ int dst_offset = 0;
+
+ value *raw_reg_1_val = value_of_register (raw_reg_1_num, next_frame);
+ raw_reg_1_val->contents_copy (pseudo_reg_val, dst_offset, 0,
+ raw_reg_1_val->type ()->length ());
+ dst_offset += raw_reg_1_val->type ()->length ();
+
+ value *raw_reg_2_val = value_of_register (raw_reg_2_num, next_frame);
+ raw_reg_2_val->contents_copy (pseudo_reg_val, dst_offset, 0,
+ raw_reg_2_val->type ()->length ());
+ dst_offset += raw_reg_2_val->type ()->length ();
+
+ value *raw_reg_3_val = value_of_register (raw_reg_3_num, next_frame);
+ raw_reg_3_val->contents_copy (pseudo_reg_val, dst_offset, 0,
+ raw_reg_3_val->type ()->length ());
+ dst_offset += raw_reg_3_val->type ()->length ();
+
+ gdb_assert (dst_offset == pseudo_reg_val->type ()->length ());
+
+ return pseudo_reg_val;
+}
+
/* Implementation of the convenience function $_isvoid. */
static struct value *
diff --git a/gdb/value.h b/gdb/value.h
index 2f3b41e..935d9eb 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1650,4 +1650,30 @@ private:
std::optional<int> m_old_value;
};
+/* Helpers for building pseudo register values from raw registers. */
+
+/* Create a value for pseudo register PSEUDO_REG_NUM by using bytes from
+ raw register RAW_REG_NUM starting at RAW_OFFSET.
+
+ The size of the pseudo register specifies how many bytes to use. The
+ offset plus the size must not overflow the raw register's size. */
+
+value *pseudo_from_raw_part (frame_info_ptr next_frame, int pseudo_reg_num,
+ 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.
+
+ The sum of the sizes of raw registers must be equal to the size of the
+ pseudo register. */
+
+value *pseudo_from_concat_raw (frame_info_ptr next_frame, int pseudo_reg_num,
+ 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);
+
#endif /* !defined (VALUE_H) */