{"fp", AARCH64_FP_REGNUM},
{"lr", AARCH64_LR_REGNUM},
{"sp", AARCH64_SP_REGNUM},
-
- /* 32-bit register names. */
- {"w0", AARCH64_X0_REGNUM + 0},
- {"w1", AARCH64_X0_REGNUM + 1},
- {"w2", AARCH64_X0_REGNUM + 2},
- {"w3", AARCH64_X0_REGNUM + 3},
- {"w4", AARCH64_X0_REGNUM + 4},
- {"w5", AARCH64_X0_REGNUM + 5},
- {"w6", AARCH64_X0_REGNUM + 6},
- {"w7", AARCH64_X0_REGNUM + 7},
- {"w8", AARCH64_X0_REGNUM + 8},
- {"w9", AARCH64_X0_REGNUM + 9},
- {"w10", AARCH64_X0_REGNUM + 10},
- {"w11", AARCH64_X0_REGNUM + 11},
- {"w12", AARCH64_X0_REGNUM + 12},
- {"w13", AARCH64_X0_REGNUM + 13},
- {"w14", AARCH64_X0_REGNUM + 14},
- {"w15", AARCH64_X0_REGNUM + 15},
- {"w16", AARCH64_X0_REGNUM + 16},
- {"w17", AARCH64_X0_REGNUM + 17},
- {"w18", AARCH64_X0_REGNUM + 18},
- {"w19", AARCH64_X0_REGNUM + 19},
- {"w20", AARCH64_X0_REGNUM + 20},
- {"w21", AARCH64_X0_REGNUM + 21},
- {"w22", AARCH64_X0_REGNUM + 22},
- {"w23", AARCH64_X0_REGNUM + 23},
- {"w24", AARCH64_X0_REGNUM + 24},
- {"w25", AARCH64_X0_REGNUM + 25},
- {"w26", AARCH64_X0_REGNUM + 26},
- {"w27", AARCH64_X0_REGNUM + 27},
- {"w28", AARCH64_X0_REGNUM + 28},
- {"w29", AARCH64_X0_REGNUM + 29},
- {"w30", AARCH64_X0_REGNUM + 30},
-
/* specials */
{"ip0", AARCH64_X0_REGNUM + 16},
{"ip1", AARCH64_X0_REGNUM + 17}
}
\f
+/* Return TRUE if REGNUM is a W pseudo-register number. Return FALSE
+ otherwise. */
+
+static bool
+is_w_pseudo_register (struct gdbarch *gdbarch, int regnum)
+{
+ aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+
+ if (tdep->w_pseudo_base <= regnum
+ && regnum < tdep->w_pseudo_base + tdep->w_pseudo_count)
+ return true;
+
+ return false;
+}
+
/* Return the pseudo register name corresponding to register regnum. */
static const char *
{
aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+ /* W pseudo-registers. Bottom halves of the X registers. */
+ static const char *const w_name[] =
+ {
+ "w0", "w1", "w2", "w3",
+ "w4", "w5", "w6", "w7",
+ "w8", "w9", "w10", "w11",
+ "w12", "w13", "w14", "w15",
+ "w16", "w17", "w18", "w19",
+ "w20", "w21", "w22", "w23",
+ "w24", "w25", "w26", "w27",
+ "w28", "w29", "w30",
+ };
+
static const char *const q_name[] =
{
"q0", "q1", "q2", "q3",
if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
return b_name[p_regnum - AARCH64_B0_REGNUM];
+ /* W pseudo-registers? */
+ if (is_w_pseudo_register (gdbarch, regnum))
+ return w_name[regnum - tdep->w_pseudo_base];
+
if (tdep->has_sve ())
{
static const char *const sve_v_name[] =
&& p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
return aarch64_vnv_type (gdbarch);
+ /* W pseudo-registers are 32-bit. */
+ if (is_w_pseudo_register (gdbarch, regnum))
+ return builtin_type (gdbarch)->builtin_uint32;
+
if (tdep->has_pauth () && regnum == tdep->ra_sign_state_regnum)
return builtin_type (gdbarch)->builtin_uint64;
VALUE_LVAL (result_value) = lval_register;
VALUE_REGNUM (result_value) = regnum;
+ if (is_w_pseudo_register (gdbarch, regnum))
+ {
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ /* Default offset for little endian. */
+ int offset = 0;
+
+ if (byte_order == BFD_ENDIAN_BIG)
+ 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];
+
+ /* Read the bottom 4 bytes of X. */
+ if (regcache->raw_read_part (x_regnum, offset, 4, data) != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 0, 4);
+ else
+ memcpy (value_contents_raw (result_value).data (), data, 4);
+
+ return result_value;
+ }
+
regnum -= gdbarch_num_regs (gdbarch);
if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
int regnum, const gdb_byte *buf)
{
aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+
+ if (is_w_pseudo_register (gdbarch, regnum))
+ {
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ /* Default offset for little endian. */
+ int offset = 0;
+
+ if (byte_order == BFD_ENDIAN_BIG)
+ offset = 4;
+
+ /* Find the correct X register to extract the data from. */
+ int x_regnum = AARCH64_X0_REGNUM + (regnum - tdep->w_pseudo_base);
+
+ /* First zero-out the contents of X. */
+ ULONGEST zero = 0;
+ regcache->raw_write (x_regnum, zero);
+ /* Write to the bottom 4 bytes of X. */
+ regcache->raw_write_part (x_regnum, offset, 4, buf);
+ return;
+ }
+
regnum -= gdbarch_num_regs (gdbarch);
if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
num_regs += i;
}
+ /* W pseudo-registers */
+ int first_w_regnum = num_pseudo_regs;
+ num_pseudo_regs += 31;
if (!valid_p)
return nullptr;
/* With the number of real registers updated, setup the pseudo-registers and
record their numbers. */
+ /* Setup W pseudo-register numbers. */
+ tdep->w_pseudo_base = first_w_regnum + num_regs;
+ tdep->w_pseudo_count = 31;
+
/* Pointer authentication pseudo-registers. */
if (tdep->has_pauth ())
tdep->ra_sign_state_regnum = ra_sign_state_offset + num_regs;
--- /dev/null
+# Copyright (C) 2022 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Check if the W registers have the expected size and if setting/fetching
+# values from W registers works correctly for both big and little endian.
+
+if {![is_aarch64_target]} {
+ verbose "Skipping ${gdb_test_file_name}."
+ return
+}
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile {nodebug}]} {
+ return -1
+}
+
+if ![runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+array set w_values {
+ 0 0x0
+ 1 0x10
+ 2 0x2010
+ 3 0x302010
+ 4 0x40302010
+ 5 0x40302010
+ 6 0x40302010
+ 7 0x40302010
+ 8 0x40302010
+}
+
+array set x_values {
+ 0 0x0
+ 1 0x10
+ 2 0x2010
+ 3 0x302010
+ 4 0x40302010
+ 5 0x5040302010
+ 6 0x605040302010
+ 7 0x70605040302010
+ 8 0x8070605040302010
+}
+
+# Exercise various things for register w<rn>
+
+proc test_register { rn } {
+ gdb_test "ptype \$w${rn}" "type = uint32_t"
+ gdb_test "p sizeof(\$w${rn})" " = 4"
+
+ # Set all bits of x<rn>
+ gdb_test_no_output "set \$x${rn}=0xffffffffffffffff" \
+ "set all bits of x${rn}"
+
+ # Test setting/fetching values
+ for {set i 0} {$i < 9} {incr i} {
+ global w_values
+ global x_values
+
+ with_test_prefix "set w${rn} to $x_values($i)" {
+ # Set value of W and see the effects on W and X.
+ gdb_test_no_output "set \$w${rn}=$x_values($i)"
+ gdb_test "p/x \$w${rn}" "= $w_values($i)"
+ gdb_test "p/x \$x${rn}" "= $w_values($i)"
+ }
+
+ with_test_prefix "set x${rn} to $x_values($i)" {
+ # Set value of X and see the effects on W and X.
+ gdb_test_no_output "set \$x${rn}=$x_values($i)"
+ gdb_test "p/x \$w${rn}" "= $w_values($i)"
+ gdb_test "p/x \$x${rn}" "= $x_values($i)"
+
+ # Set all bits of x<rn>
+ gdb_test_no_output "set \$x${rn}=0xffffffffffffffff" \
+ "set all bits of x${rn}"
+ }
+ }
+}
+
+# Run tests
+foreach_with_prefix endian {"little" "big"} {
+ gdb_test "set endian ${endian}" "The target is set to ${endian} endian\."
+
+ for {set i 0} {$i < 31} {incr i} {
+ test_register $i
+ }
+}