diff options
author | Luis Machado <luis.machado@linaro.org> | 2020-03-18 13:06:05 -0300 |
---|---|---|
committer | Luis Machado <luis.machado@linaro.org> | 2020-12-10 11:45:08 -0300 |
commit | 6afcd2d4161165fd976c55a9792dbcccd2d5d106 (patch) | |
tree | fb937c4e5014dfc25d5b05162d78f5e13af25f4c /gdb/trad-frame.c | |
parent | 15cc148fb817bc1eb91aa16e5d94e39ebafc11ee (diff) | |
download | gdb-6afcd2d4161165fd976c55a9792dbcccd2d5d106.zip gdb-6afcd2d4161165fd976c55a9792dbcccd2d5d106.tar.gz gdb-6afcd2d4161165fd976c55a9792dbcccd2d5d106.tar.bz2 |
[AArch64] SVE/FPSIMD fixup for big endian
The FPSIMD dump in signal frames and ptrace FPSIMD dump in the SVE context
structure follows the target endianness, whereas the SVE dumps are
endianness-independent (LE).
Therefore, when the system is in BE mode, we need to reverse the bytes
for the FPSIMD data.
Given the V registers are larger than 64-bit, I've added a way for value
bytes to be set, as opposed to passing a 64-bit fixed quantity. This fits
nicely with the unwinding *_got_bytes function and makes the trad-frame
more flexible and capable of saving larger registers.
The memory for the bytes is allocated via the frame obstack, so it gets freed
after we're done inspecting the frame.
gdb/ChangeLog:
2020-12-10 Luis Machado <luis.machado@linaro.org>
* aarch64-linux-tdep.c (aarch64_linux_restore_vreg) New function.
(aarch64_linux_sigframe_init): Call aarch64_linux_restore_vreg.
* aarch64-tdep.h (V_REGISTER_SIZE): Move to ...
* arch/aarch64.h: ... here.
* nat/aarch64-sve-linux-ptrace.c: Include endian.h.
(aarch64_maybe_swab128): New function.
(aarch64_sve_regs_copy_to_reg_buf)
(aarch64_sve_regs_copy_from_reg_buf): Adjust FPSIMD entries.
* trad-frame.c (trad_frame_reset_saved_regs): Initialize
the data field.
(TF_REG_VALUE_BYTES): New enum value.
(trad_frame_value_bytes_p): New function.
(trad_frame_set_value_bytes): New function.
(trad_frame_set_reg_value_bytes): New function.
(trad_frame_get_prev_register): Handle register values saved as bytes.
* trad-frame.h (trad_frame_set_reg_value_bytes): New prototype.
(struct trad_frame_saved_reg) <data>: New field.
(trad_frame_set_value_bytes): New prototype.
(trad_frame_value_bytes_p): New prototype.
Diffstat (limited to 'gdb/trad-frame.c')
-rw-r--r-- | gdb/trad-frame.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/gdb/trad-frame.c b/gdb/trad-frame.c index a6a8479..8a1aa81 100644 --- a/gdb/trad-frame.c +++ b/gdb/trad-frame.c @@ -56,6 +56,7 @@ trad_frame_reset_saved_regs (struct gdbarch *gdbarch, { regs[regnum].realreg = regnum; regs[regnum].addr = -1; + regs[regnum].data = nullptr; } } @@ -83,7 +84,7 @@ trad_frame_alloc_saved_regs (struct frame_info *this_frame) return trad_frame_alloc_saved_regs (gdbarch); } -enum { TF_REG_VALUE = -1, TF_REG_UNKNOWN = -2 }; +enum { TF_REG_VALUE = -1, TF_REG_UNKNOWN = -2, TF_REG_VALUE_BYTES = -3 }; int trad_frame_value_p (struct trad_frame_saved_reg this_saved_regs[], int regnum) @@ -106,6 +107,16 @@ trad_frame_realreg_p (struct trad_frame_saved_reg this_saved_regs[], && this_saved_regs[regnum].addr == -1); } +/* See trad-frame.h. */ + +bool +trad_frame_value_bytes_p (struct trad_frame_saved_reg this_saved_regs[], + int regnum) +{ + return (this_saved_regs[regnum].realreg == TF_REG_VALUE_BYTES + && this_saved_regs[regnum].data != nullptr); +} + void trad_frame_set_value (struct trad_frame_saved_reg this_saved_regs[], int regnum, LONGEST val) @@ -224,6 +235,35 @@ trad_frame_set_unknown (struct trad_frame_saved_reg this_saved_regs[], this_saved_regs[regnum].addr = -1; } +/* See trad-frame.h. */ + +void +trad_frame_set_value_bytes (struct trad_frame_saved_reg this_saved_regs[], + int regnum, const gdb_byte *bytes, + size_t size) +{ + this_saved_regs[regnum].realreg = TF_REG_VALUE_BYTES; + + /* Allocate the space and copy the data bytes. */ + this_saved_regs[regnum].data = FRAME_OBSTACK_CALLOC (size, gdb_byte); + memcpy (this_saved_regs[regnum].data, bytes, size); +} + +/* See trad-frame.h. */ + +void +trad_frame_set_reg_value_bytes (struct trad_frame_cache *this_trad_cache, + int regnum, const gdb_byte *bytes, + size_t size) +{ + /* External interface for users of trad_frame_cache + (who cannot access the prev_regs object directly). */ + trad_frame_set_value_bytes (this_trad_cache->prev_regs, regnum, bytes, + size); +} + + + struct value * trad_frame_get_prev_register (struct frame_info *this_frame, struct trad_frame_saved_reg this_saved_regs[], @@ -240,6 +280,10 @@ trad_frame_get_prev_register (struct frame_info *this_frame, /* The register's value is available. */ return frame_unwind_got_constant (this_frame, regnum, this_saved_regs[regnum].addr); + else if (trad_frame_value_bytes_p (this_saved_regs, regnum)) + /* The register's value is available as a sequence of bytes. */ + return frame_unwind_got_bytes (this_frame, regnum, + this_saved_regs[regnum].data); else return frame_unwind_got_optimized (this_frame, regnum); } |