@@ -83,6 +83,10 @@
* Support for native Thread Local Storage (TLS) variables on Windows.
+* Support for Intel APX registers on amd64 GNU/Linux.
+ Support displaying and modifying Intel APX registers (Extended GPRs
+ $r16 - $r31) including byte, word and dword pseudo registers.
+
* Configure changes
** --with-babeltrace has been removed. The babeltrace library was
@@ -113,6 +113,8 @@ int amd64_linux_gregset_reg_offset[] =
-1, -1, -1, -1, -1, -1, -1, -1,
-1, /* PKEYS register pkru */
-1, /* CET user mode register PL3_SSP. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* r16 ... r31. */
+ -1, -1, -1, -1, -1, -1, -1, -1,
/* End of hardware registers */
21 * 8, 22 * 8, /* fs_base and gs_base. */
@@ -61,6 +61,36 @@
/* Register information. */
+/* Number of general purpose registers without APX. */
+#define AMD64_NUM_GPRS 16
+
+/* Number of lower byte registers without APX. */
+#define AMD64_NUM_LOWER_BYTE_REGS AMD64_NUM_GPRS
+
+/* Number of byte registers without APX. */
+#define AMD64_NUM_BYTE_REGS (AMD64_NUM_LOWER_BYTE_REGS + 4)
+
+/* Number of word registers without APX. */
+#define AMD64_NUM_WORD_REGS AMD64_NUM_GPRS
+
+/* Number of dword registers without APX. */
+#define AMD64_NUM_DWORD_REGS AMD64_NUM_GPRS
+
+/* Number of general purpose registers with APX. */
+#define AMD64_APX_NUM_GPRS 32
+
+/* Number of APX lower byte registers. */
+#define AMD64_APX_NUM_LOWER_BYTE_REGS AMD64_APX_NUM_GPRS
+
+/* Number of APX byte registers. */
+#define AMD64_APX_NUM_BYTE_REGS (AMD64_APX_NUM_LOWER_BYTE_REGS + 4)
+
+/* Number of APX word registers. */
+#define AMD64_APX_NUM_WORD_REGS AMD64_APX_NUM_GPRS
+
+/* Number of APX dword registers. */
+#define AMD64_APX_NUM_DWORD_REGS AMD64_APX_NUM_GPRS
+
static const char * const amd64_register_names[] =
{
"rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp",
@@ -87,6 +117,12 @@ static const char * const amd64_ymm_names[] =
"ymm12", "ymm13", "ymm14", "ymm15"
};
+static const char * const amd64_apx_names[] =
+{
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
static const char * const amd64_ymm_avx512_names[] =
{
"ymm16", "ymm17", "ymm18", "ymm19",
@@ -252,7 +288,20 @@ static int amd64_dwarf_regmap[] =
AMD64_K0_REGNUM + 0, AMD64_K0_REGNUM + 1,
AMD64_K0_REGNUM + 2, AMD64_K0_REGNUM + 3,
AMD64_K0_REGNUM + 4, AMD64_K0_REGNUM + 5,
- AMD64_K0_REGNUM + 6, AMD64_K0_REGNUM + 7
+ AMD64_K0_REGNUM + 6, AMD64_K0_REGNUM + 7,
+
+ /* Reserved. */
+ -1, -1, -1, -1,
+
+ /* r16-r31. */
+ AMD64_R16_REGNUM + 0, AMD64_R16_REGNUM + 1,
+ AMD64_R16_REGNUM + 2, AMD64_R16_REGNUM + 3,
+ AMD64_R16_REGNUM + 4, AMD64_R16_REGNUM + 5,
+ AMD64_R16_REGNUM + 6, AMD64_R16_REGNUM + 7,
+ AMD64_R16_REGNUM + 8, AMD64_R16_REGNUM + 9,
+ AMD64_R16_REGNUM + 10, AMD64_R16_REGNUM + 11,
+ AMD64_R16_REGNUM + 12, AMD64_R16_REGNUM + 13,
+ AMD64_R16_REGNUM + 14, AMD64_R16_REGNUM + 15
};
static const int amd64_dwarf_regmap_len =
@@ -322,8 +371,19 @@ static const char * const amd64_byte_names[] =
"ah", "bh", "ch", "dh"
};
-/* Number of lower byte registers. */
-#define AMD64_NUM_LOWER_BYTE_REGS 16
+static_assert (ARRAY_SIZE (amd64_byte_names) == AMD64_NUM_BYTE_REGS);
+
+static const char * const amd64_apx_byte_names[] =
+{
+ "al", "bl", "cl", "dl", "sil", "dil", "bpl", "spl",
+ "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l",
+ "r16l", "r17l", "r18l", "r19l", "r20l", "r21l", "r22l", "r23l",
+ "r24l", "r25l", "r26l", "r27l", "r28l", "r29l", "r30l", "r31l",
+ "ah", "bh", "ch", "dh"
+};
+
+static_assert (ARRAY_SIZE (amd64_apx_byte_names)
+ == AMD64_APX_NUM_BYTE_REGS);
/* Register names for word pseudo-registers. */
@@ -333,6 +393,19 @@ static const char * const amd64_word_names[] =
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
};
+static_assert (ARRAY_SIZE (amd64_word_names) == AMD64_NUM_WORD_REGS);
+
+static const char * const amd64_apx_word_names[] =
+{
+ "ax", "bx", "cx", "dx", "si", "di", "bp", "",
+ "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w",
+ "r16w", "r17w", "r18w", "r19w", "r20w", "r21w", "r22w", "r23w",
+ "r24w", "r25w", "r26w", "r27w", "r28w", "r29w", "r30w", "r31w"
+};
+
+static_assert (ARRAY_SIZE (amd64_apx_word_names)
+ == AMD64_APX_NUM_WORD_REGS);
+
/* Register names for dword pseudo-registers. */
static const char * const amd64_dword_names[] =
@@ -342,28 +415,90 @@ static const char * const amd64_dword_names[] =
"eip"
};
+static_assert (ARRAY_SIZE (amd64_dword_names) == AMD64_NUM_DWORD_REGS + 1);
+
+static const char * const amd64_apx_dword_names[] =
+{
+ "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
+ "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
+ "r16d", "r17d", "r18d", "r19d", "r20d", "r21d", "r22d", "r23d",
+ "r24d", "r25d", "r26d", "r27d", "r28d", "r29d", "r30d", "r31d",
+ "eip"
+};
+
+static_assert (ARRAY_SIZE (amd64_apx_dword_names)
+ == AMD64_APX_NUM_DWORD_REGS + 1);
+
/* Return the name of register REGNUM. */
static const char *
amd64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
{
i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
- if (i386_byte_regnum_p (gdbarch, regnum))
- return amd64_byte_names[regnum - tdep->al_regnum];
- else if (i386_zmm_regnum_p (gdbarch, regnum))
+ if (i386_zmm_regnum_p (gdbarch, regnum))
return amd64_zmm_names[regnum - tdep->zmm0_regnum];
else if (i386_ymm_regnum_p (gdbarch, regnum))
return amd64_ymm_names[regnum - tdep->ymm0_regnum];
else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
return amd64_ymm_avx512_names[regnum - tdep->ymm16_regnum];
- else if (i386_word_regnum_p (gdbarch, regnum))
- return amd64_word_names[regnum - tdep->ax_regnum];
else if (i386_dword_regnum_p (gdbarch, regnum))
- return amd64_dword_names[regnum - tdep->eax_regnum];
+ return tdep->dword_names[regnum - tdep->eax_regnum];
else
return i386_pseudo_register_name (gdbarch, regnum);
}
+/* Return the raw byte register number. *PART is set to 1 for high
+ byte register and 0 otherwise. */
+
+static int
+amd64_raw_byte_register (i386_gdbarch_tdep *tdep, int regnum, int *part)
+{
+ int gpnum = regnum - tdep->al_regnum;
+
+ /* Extract (always little endian). */
+ if (gpnum >= tdep->num_lower_byte_regs)
+ {
+ /* Special handling for AH, BH, CH, DH. */
+ *part = 1;
+ gpnum -= tdep->num_lower_byte_regs;
+ }
+ else
+ {
+ *part = 0;
+ if (gpnum >= AMD64_NUM_GPRS)
+ {
+ gdb_assert (tdep->r16_regnum != -1);
+ gpnum += tdep->r16_regnum - 16;
+ }
+ }
+ return gpnum;
+}
+
+/* Return the raw word register number. */
+
+static int
+amd64_raw_word_register (i386_gdbarch_tdep *tdep, int regnum)
+{
+ int gpnum = regnum - tdep->ax_regnum;
+ if (gpnum >= 16)
+ gpnum += tdep->r16_regnum - 16;
+ return gpnum;
+}
+
+/* Return the raw dword register number. For x32, the last dword
+ register is EIP. */
+
+static int
+amd64_raw_dword_register (i386_gdbarch_tdep *tdep, int regnum)
+{
+ int gpnum = regnum - tdep->eax_regnum;
+ if (tdep->eip_regnum == gpnum)
+ return AMD64_RIP_REGNUM;
+ if (gpnum >= 16)
+ gpnum += tdep->r16_regnum - 16;
+ return gpnum;
+}
+
static value *
amd64_pseudo_register_read_value (gdbarch *gdbarch, const frame_info_ptr &next_frame,
int regnum)
@@ -372,23 +507,18 @@ amd64_pseudo_register_read_value (gdbarch *gdbarch, const frame_info_ptr &next_f
if (i386_byte_regnum_p (gdbarch, regnum))
{
- int gpnum = regnum - tdep->al_regnum;
-
- /* Extract (always little endian). */
- if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
- {
- gpnum -= AMD64_NUM_LOWER_BYTE_REGS;
-
- /* Special handling for AH, BH, CH, DH. */
- return pseudo_from_raw_part (next_frame, regnum, gpnum, 1);
- }
- else
- return pseudo_from_raw_part (next_frame, regnum, gpnum, 0);
+ int part;
+ const int gpnum = amd64_raw_byte_register (tdep, regnum, &part);
+ return pseudo_from_raw_part (next_frame, regnum, gpnum, part);
+ }
+ else if (i386_word_regnum_p (gdbarch, regnum))
+ {
+ const int gpnum = amd64_raw_word_register (tdep, regnum);
+ return pseudo_from_raw_part (next_frame, regnum, gpnum, 0);
}
else if (i386_dword_regnum_p (gdbarch, regnum))
{
- int gpnum = regnum - tdep->eax_regnum;
-
+ const int gpnum = amd64_raw_dword_register (tdep, regnum);
return pseudo_from_raw_part (next_frame, regnum, gpnum, 0);
}
else
@@ -403,19 +533,18 @@ amd64_pseudo_register_write (gdbarch *gdbarch, const frame_info_ptr &next_frame,
if (i386_byte_regnum_p (gdbarch, regnum))
{
- int gpnum = regnum - tdep->al_regnum;
-
- if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
- {
- gpnum -= AMD64_NUM_LOWER_BYTE_REGS;
- pseudo_to_raw_part (next_frame, buf, gpnum, 1);
- }
- else
- pseudo_to_raw_part (next_frame, buf, gpnum, 0);
+ int part;
+ const int gpnum = amd64_raw_byte_register (tdep, regnum, &part);
+ pseudo_to_raw_part (next_frame, buf, gpnum, part);
+ }
+ else if (i386_word_regnum_p (gdbarch, regnum))
+ {
+ const int gpnum = amd64_raw_word_register (tdep, regnum);
+ pseudo_to_raw_part (next_frame, buf, gpnum, 0);
}
else if (i386_dword_regnum_p (gdbarch, regnum))
{
- int gpnum = regnum - tdep->eax_regnum;
+ const int gpnum = amd64_raw_dword_register (tdep, regnum);
pseudo_to_raw_part (next_frame, buf, gpnum, 0);
}
else
@@ -432,17 +561,18 @@ amd64_ax_pseudo_register_collect (struct gdbarch *gdbarch,
if (i386_byte_regnum_p (gdbarch, regnum))
{
- int gpnum = regnum - tdep->al_regnum;
-
- if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
- ax_reg_mask (ax, gpnum - AMD64_NUM_LOWER_BYTE_REGS);
- else
- ax_reg_mask (ax, gpnum);
+ int part;
+ const int gpnum = amd64_raw_byte_register (tdep, regnum, &part);
+ ax_reg_mask (ax, gpnum);
+ }
+ else if (i386_word_regnum_p (gdbarch, regnum))
+ {
+ const int gpnum = amd64_raw_word_register (tdep, regnum);
+ ax_reg_mask (ax, gpnum);
}
else if (i386_dword_regnum_p (gdbarch, regnum))
{
- int gpnum = regnum - tdep->eax_regnum;
-
+ const int gpnum = amd64_raw_dword_register (tdep, regnum);
ax_reg_mask (ax, gpnum);
}
else
@@ -3552,9 +3682,30 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pl3_ssp") != nullptr)
tdep->ssp_regnum = AMD64_PL3_SSP_REGNUM;
- tdep->num_byte_regs = 20;
- tdep->num_word_regs = 16;
- tdep->num_dword_regs = 16;
+ if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.apx") != nullptr)
+ {
+ tdep->apx_register_names = amd64_apx_names;
+ tdep->num_apx_regs = 16;
+ tdep->r16_regnum = AMD64_R16_REGNUM;
+ tdep->byte_names = amd64_apx_byte_names;
+ tdep->word_names = amd64_apx_word_names;
+ tdep->dword_names = amd64_apx_dword_names;
+ tdep->num_lower_byte_regs = AMD64_APX_NUM_LOWER_BYTE_REGS;
+ tdep->num_byte_regs = AMD64_APX_NUM_BYTE_REGS;
+ tdep->num_word_regs = AMD64_APX_NUM_WORD_REGS;
+ tdep->num_dword_regs = AMD64_APX_NUM_DWORD_REGS;
+ }
+ else
+ {
+ tdep->byte_names = amd64_byte_names;
+ tdep->word_names = amd64_word_names;
+ tdep->dword_names = amd64_dword_names;
+ tdep->num_lower_byte_regs = AMD64_NUM_LOWER_BYTE_REGS;
+ tdep->num_byte_regs = AMD64_NUM_BYTE_REGS;
+ tdep->num_word_regs = AMD64_NUM_WORD_REGS;
+ tdep->num_dword_regs = AMD64_NUM_DWORD_REGS;
+ }
+
/* Avoid wiring in the MMX registers for now. */
tdep->num_mmx_regs = 0;
@@ -3663,15 +3814,13 @@ static struct type *
amd64_x32_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
{
i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+ const int gpnum = regnum - tdep->eax_regnum;
- switch (regnum - tdep->eax_regnum)
- {
- case AMD64_RBP_REGNUM: /* %ebp */
- case AMD64_RSP_REGNUM: /* %esp */
- return builtin_type (gdbarch)->builtin_data_ptr;
- case AMD64_RIP_REGNUM: /* %eip */
- return builtin_type (gdbarch)->builtin_func_ptr;
- }
+ if (gpnum == tdep->eip_regnum) /* %eip. */
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else if (gpnum == AMD64_RBP_REGNUM /* %ebp. */
+ || gpnum == AMD64_RSP_REGNUM) /* %esp. */
+ return builtin_type (gdbarch)->builtin_data_ptr;
return i386_pseudo_register_type (gdbarch, regnum);
}
@@ -3684,7 +3833,10 @@ amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
amd64_init_abi (info, gdbarch, default_tdesc);
- tdep->num_dword_regs = 17;
+ /* Set %eip to the last dword register. */
+ tdep->eip_regnum = tdep->num_dword_regs;
+ /* Increment 1 for %eip. */
+ tdep->num_dword_regs += 1;
set_tdesc_pseudo_register_type (gdbarch, amd64_x32_pseudo_register_type);
set_gdbarch_long_bit (gdbarch, 32);
@@ -3706,12 +3858,14 @@ const struct target_desc *
amd64_target_description (uint64_t xstate_bv, bool segments)
{
static const_target_desc_up amd64_tdescs \
- [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*CET_U*/][2/*segments*/] = {};
+ [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*CET_U*/][2/*APX*/] \
+ [2/*segments*/] = {};
const_target_desc_up &tdesc
= amd64_tdescs[(xstate_bv & X86_XSTATE_AVX) ? 1 : 0]
[(xstate_bv & X86_XSTATE_AVX512) ? 1 : 0]
[(xstate_bv & X86_XSTATE_PKRU) ? 1 : 0]
[(xstate_bv & X86_XSTATE_CET_U) ? 1 : 0]
+ [(xstate_bv & X86_XSTATE_APX_F) ? 1 : 0]
[segments ? 1 : 0];
if (tdesc == nullptr)
@@ -82,6 +82,8 @@ enum amd64_regnum
AMD64_ZMM31H_REGNUM = AMD64_ZMM0H_REGNUM + 31,
AMD64_PKRU_REGNUM,
AMD64_PL3_SSP_REGNUM,
+ AMD64_R16_REGNUM,
+ AMD64_R31_REGNUM = AMD64_R16_REGNUM + 15,
AMD64_FSBASE_REGNUM,
AMD64_GSBASE_REGNUM
};
@@ -23,6 +23,7 @@
#include "../features/i386/64bit-avx.c"
#include "../features/i386/64bit-avx512.c"
#include "../features/i386/64bit-core.c"
+#include "../features/i386/64bit-apx.c"
#include "../features/i386/64bit-linux.c"
#include "../features/i386/64bit-segments.c"
#include "../features/i386/64bit-sse.c"
@@ -78,5 +79,8 @@ amd64_create_target_description (uint64_t xstate_bv, bool is_x32,
regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum);
}
+ if (xstate_bv & X86_XSTATE_APX_F)
+ regnum = create_feature_i386_64bit_apx (tdesc.get (), regnum);
+
return tdesc;
}
@@ -65,6 +65,7 @@ struct x86_xstate_feature {
static constexpr x86_xstate_feature x86_linux_all_xstate_features[] = {
/* Feature, i386, amd64, x32. */
+ { X86_XSTATE_APX_F, false, true, true },
{ X86_XSTATE_CET_U, false, true, true },
{ X86_XSTATE_PKRU, true, true, true },
{ X86_XSTATE_AVX512, true, true, true },
@@ -50709,6 +50709,10 @@ amd64, 32 bits on amd64 with 32-bit pointer size (X32) and 32 bits on i386.
Following the restriction of the Linux kernel, only @value{GDBN} for amd64
targets makes use of this feature for now.
+The @samp{org.gnu.gdb.i386.apx} feature is optional. It should describe
+16 Extended General Purpose registers (EGPRs) @samp{r16} - @samp{r31} with
+64 bits each. All APX registers are valid only on amd64.
+
@node LoongArch Features
@subsection LoongArch Features
@cindex target descriptions, LoongArch Features
@@ -231,6 +231,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
i386/32bit-avx512.xml \
i386/32bit-segments.xml \
i386/32bit-ssp.xml \
+ i386/64bit-apx.xml \
i386/64bit-avx512.xml \
i386/64bit-core.xml \
i386/64bit-segments.xml \
new file mode 100644
@@ -0,0 +1,29 @@
+/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro:
+ Original: 64bit-apx.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_i386_64bit_apx (struct target_desc *result, long regnum)
+{
+ struct tdesc_feature *feature;
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.i386.apx");
+ tdesc_create_reg (feature, "r16", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r17", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r18", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r19", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r20", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r21", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r22", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r23", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r24", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r25", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r26", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r27", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r28", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r29", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r30", regnum++, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "r31", regnum++, 1, NULL, 64, "int64");
+ return regnum;
+}
new file mode 100644
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2024 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.apx">
+ <reg name="r16" bitsize="64" type="int64"/>
+ <reg name="r17" bitsize="64" type="int64"/>
+ <reg name="r18" bitsize="64" type="int64"/>
+ <reg name="r19" bitsize="64" type="int64"/>
+ <reg name="r20" bitsize="64" type="int64"/>
+ <reg name="r21" bitsize="64" type="int64"/>
+ <reg name="r22" bitsize="64" type="int64"/>
+ <reg name="r23" bitsize="64" type="int64"/>
+ <reg name="r24" bitsize="64" type="int64"/>
+ <reg name="r25" bitsize="64" type="int64"/>
+ <reg name="r26" bitsize="64" type="int64"/>
+ <reg name="r27" bitsize="64" type="int64"/>
+ <reg name="r28" bitsize="64" type="int64"/>
+ <reg name="r29" bitsize="64" type="int64"/>
+ <reg name="r30" bitsize="64" type="int64"/>
+ <reg name="r31" bitsize="64" type="int64"/>
+</feature>
@@ -412,9 +412,9 @@ i386_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
else if (i386_zmm_regnum_p (gdbarch, regnum))
return i386_zmm_names[regnum - tdep->zmm0_regnum];
else if (i386_byte_regnum_p (gdbarch, regnum))
- return i386_byte_names[regnum - tdep->al_regnum];
+ return tdep->byte_names[regnum - tdep->al_regnum];
else if (i386_word_regnum_p (gdbarch, regnum))
- return i386_word_names[regnum - tdep->ax_regnum];
+ return tdep->word_names[regnum - tdep->ax_regnum];
internal_error (_("invalid regnum"));
}
@@ -8479,7 +8479,8 @@ i386_xcr0_from_tdesc (const struct target_desc *tdesc)
const struct tdesc_feature *feature_core;
const struct tdesc_feature *feature_sse, *feature_avx,
- *feature_avx512, *feature_pkeys;
+ *feature_avx512, *feature_pkeys,
+ *feature_apx;
/* Get core registers. */
feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.core");
@@ -8495,6 +8496,9 @@ i386_xcr0_from_tdesc (const struct target_desc *tdesc)
/* Try AVX512 registers. */
feature_avx512 = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx512");
+ /* Try APX registers. */
+ feature_apx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.apx");
+
/* Try PKEYS */
feature_pkeys = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys");
@@ -8522,6 +8526,9 @@ i386_xcr0_from_tdesc (const struct target_desc *tdesc)
xcr0 |= X86_XSTATE_AVX512;
}
+ if (feature_apx)
+ xcr0 |= X86_XSTATE_APX_F;
+
if (feature_pkeys)
xcr0 |= X86_XSTATE_PKRU;
@@ -8537,7 +8544,7 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
const struct tdesc_feature *feature_sse, *feature_avx, *feature_avx512,
*feature_pkeys, *feature_segments,
- *feature_pl3_ssp;
+ *feature_pl3_ssp, *feature_apx;
int i, num_regs, valid_p;
if (! tdesc_has_registers (tdesc))
@@ -8557,6 +8564,9 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
/* Try AVX512 registers. */
feature_avx512 = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx512");
+ /* Try APX registers. */
+ feature_apx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.apx");
+
/* Try segment base registers. */
feature_segments = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.segments");
@@ -8641,6 +8651,18 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
tdep->num_xmm_regs = 0;
}
+ if (feature_apx
+ && tdep->r16_regnum != -1
+ && tdep->apx_register_names != nullptr
+ && tdep->num_apx_regs > 0)
+ {
+ tdep->xcr0 |= X86_XSTATE_APX_F;
+ for (i = 0; i < tdep->num_apx_regs; i++)
+ valid_p &= tdesc_numbered_register (feature_apx, tdesc_data,
+ tdep->r16_regnum + i,
+ tdep->apx_register_names[i]);
+ }
+
num_regs = tdep->num_core_regs;
for (i = 0; i < num_regs; i++)
valid_p &= tdesc_numbered_register (feature_core, tdesc_data, i,
@@ -8908,6 +8930,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep->num_core_regs = I386_NUM_GREGS + I387_NUM_REGS;
tdep->register_names = i386_register_names;
+ tdep->byte_names = i386_byte_names;
+ tdep->word_names = i386_word_names;
tdep->num_byte_regs = 8;
tdep->num_word_regs = 8;
@@ -108,6 +108,9 @@ struct i386_gdbarch_tdep : gdbarch_tdep_base
value >= 0. */
int al_regnum = -1;
+ /* Number of pseudo lower byte registers. Only used for AMD64. */
+ int num_lower_byte_regs = 0;
+
/* Number of pseudo word registers. */
int num_word_regs = 0;
@@ -121,9 +124,16 @@ struct i386_gdbarch_tdep : gdbarch_tdep_base
registers are supported. */
int eax_regnum = -1;
+ /* Register number for %eip. Set this to a value >= 0 in case of %eip
+ support. Only used for AMD64. */
+ int eip_regnum = -1;
+
/* Number of core registers. */
int num_core_regs = 0;
+ /* Number of registers added in APX. Only used for AMD64. */
+ int num_apx_regs = 0;
+
/* Number of SSE registers. */
int num_xmm_regs = 0;
@@ -159,6 +169,15 @@ struct i386_gdbarch_tdep : gdbarch_tdep_base
supported. */
int ymm0h_regnum = -1;
+ /* Byte register names. */
+ const char * const *byte_names = nullptr;
+
+ /* Word register names. */
+ const char * const *word_names = nullptr;
+
+ /* Dword register names. Only used for AMD64. */
+ const char * const *dword_names = nullptr;
+
/* Upper YMM register names. Only used for tdesc_numbered_register. */
const char * const *ymmh_register_names = nullptr;
@@ -173,6 +192,13 @@ struct i386_gdbarch_tdep : gdbarch_tdep_base
registers are supported. */
int zmm0h_regnum = -1;
+ /* Register number for %r16. Set this to a value >= 0 if r16-r31
+ registers are supported. Only used for AMD64. */
+ int r16_regnum = -1;
+
+ /* r16-r31 register names. Only used for tdesc_numbered_register. */
+ const char * const *apx_register_names = nullptr;
+
/* OpMask register names. */
const char * const *k_register_names = nullptr;
@@ -818,6 +818,34 @@ static int xsave_xmm_avx512_offset[] =
(xsave + (tdep)->xsave_layout.zmm_offset \
+ xsave_xmm_avx512_offset[regnum - I387_XMM16_REGNUM (tdep)])
+/* At xsave_apx_egpr_offset[REGNUM] you'll find the relative offset
+ within the APX region of the XSAVE extended state where the GDB
+ registers r16 - r31 is stored. */
+
+static int xsave_apx_egpr_offset[] =
+{
+ 0 * 8, /* r16...r31 registers. */
+ 1 * 8,
+ 2 * 8,
+ 3 * 8,
+ 4 * 8,
+ 5 * 8,
+ 6 * 8,
+ 7 * 8,
+ 8 * 8,
+ 9 * 8,
+ 10 * 8,
+ 11 * 8,
+ 12 * 8,
+ 13 * 8,
+ 14 * 8,
+ 15 * 8
+};
+
+#define XSAVE_APX_EGPR_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.apx_offset \
+ + xsave_apx_egpr_offset[regnum - I387_R16_REGNUM (tdep)])
+
/* At xsave_avx512_k_offset[REGNUM] you'll find the relative offset
within the K region of the XSAVE extended state where the AVX512
opmask register K0 + REGNUM is stored. */
@@ -920,6 +948,7 @@ i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
{
/* Intel CPUs supporting PKRU. */
layout.avx_offset = 576;
+ layout.apx_offset = 960;
layout.k_offset = 1088;
layout.zmm_h_offset = 1152;
layout.zmm_offset = 1664;
@@ -938,6 +967,7 @@ i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
{
/* Intel CPUs supporting AVX512. */
layout.avx_offset = 576;
+ layout.apx_offset = 960;
layout.k_offset = 1088;
layout.zmm_h_offset = 1152;
layout.zmm_offset = 1664;
@@ -968,6 +998,7 @@ i387_fallback_xsave_layout (uint64_t xcr0)
{
/* Intel CPUs supporting PKRU. */
layout.avx_offset = 576;
+ layout.apx_offset = 960;
layout.k_offset = 1088;
layout.zmm_h_offset = 1152;
layout.zmm_offset = 1664;
@@ -978,6 +1009,7 @@ i387_fallback_xsave_layout (uint64_t xcr0)
{
/* Intel CPUs supporting AVX512. */
layout.avx_offset = 576;
+ layout.apx_offset = 960;
layout.k_offset = 1088;
layout.zmm_h_offset = 1152;
layout.zmm_offset = 1664;
@@ -1043,8 +1075,9 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
avx512_ymmh_avx512 = 0x40,
avx512_xmm_avx512 = 0x80,
pkeys = 0x100,
+ apx = 0x200,
all = x87 | sse | avxh | avx512_k | avx512_zmm0_h | avx512_zmm16_h
- | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
+ | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys | apx
} regclass;
gdb_assert (regs != NULL);
@@ -1053,6 +1086,9 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
if (regnum == -1)
regclass = all;
+ else if (regnum >= I387_R16_REGNUM (tdep)
+ && regnum < I387_APX_END_REGNUM (tdep))
+ regclass = apx;
else if (regnum >= I387_PKRU_REGNUM (tdep)
&& regnum < I387_PKEYSEND_REGNUM (tdep))
regclass = pkeys;
@@ -1099,6 +1135,13 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
case none:
break;
+ case apx:
+ if ((clear_bv & X86_XSTATE_APX_F))
+ regcache->raw_supply_zeroed (regnum);
+ else
+ regcache->raw_supply (regnum, XSAVE_APX_EGPR_ADDR (tdep, regs, regnum));
+ return;
+
case pkeys:
if ((clear_bv & X86_XSTATE_PKRU))
regcache->raw_supply_zeroed (regnum);
@@ -1274,6 +1317,25 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
}
}
+ /* Handle the APX register. */
+ if ((tdep->xcr0 & X86_XSTATE_APX_F) != 0)
+ {
+ if ((clear_bv & X86_XSTATE_APX_F) != 0)
+ {
+ for (i = I387_R16_REGNUM (tdep);
+ i < I387_APX_END_REGNUM (tdep);
+ i++)
+ regcache->raw_supply_zeroed (i);
+ }
+ else
+ {
+ for (i = I387_R16_REGNUM (tdep);
+ i < I387_APX_END_REGNUM (tdep);
+ i++)
+ regcache->raw_supply (i, XSAVE_APX_EGPR_ADDR (tdep, regs, i));
+ }
+ }
+
/* Handle the XMM registers. */
if ((tdep->xcr0 & X86_XSTATE_SSE))
{
@@ -1432,8 +1494,9 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
avx512_ymmh_avx512 = 0x80,
avx512_xmm_avx512 = 0x100,
pkeys = 0x200,
+ apx = 0x400,
all = x87 | sse | avxh | avx512_k | avx512_zmm0_h | avx512_zmm16_h
- | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
+ | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys | apx
} regclass;
gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
@@ -1441,6 +1504,9 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
if (regnum == -1)
regclass = all;
+ else if (regnum >= I387_R16_REGNUM (tdep)
+ && regnum < I387_APX_END_REGNUM (tdep))
+ regclass = apx;
else if (regnum >= I387_PKRU_REGNUM (tdep)
&& regnum < I387_PKEYSEND_REGNUM (tdep))
regclass = pkeys;
@@ -1505,6 +1571,14 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
seem justified at this point. */
if (clear_bv)
{
+ if ((clear_bv & X86_XSTATE_APX_F))
+ {
+ for (i = I387_R16_REGNUM (tdep);
+ i < I387_APX_END_REGNUM (tdep);
+ i++)
+ memset (XSAVE_APX_EGPR_ADDR (tdep, regs, i), 0, 8);
+ }
+
if ((clear_bv & X86_XSTATE_PKRU))
for (i = I387_PKRU_REGNUM (tdep);
i < I387_PKEYSEND_REGNUM (tdep); i++)
@@ -1571,6 +1645,23 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
if (regclass == all)
{
+ /* Check if any APX registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_APX_F))
+ {
+ for (i = I387_R16_REGNUM (tdep);
+ i < I387_APX_END_REGNUM (tdep);
+ i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_APX_EGPR_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 8) != 0)
+ {
+ xstate_bv |= X86_XSTATE_APX_F;
+ memcpy (p, raw, 8);
+ }
+ }
+ }
+
/* Check if any PKEYS registers are changed. */
if ((tdep->xcr0 & X86_XSTATE_PKRU))
for (i = I387_PKRU_REGNUM (tdep);
@@ -1723,6 +1814,16 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
default:
internal_error (_("invalid i387 regclass"));
+ case apx:
+ regcache->raw_collect (regnum, raw);
+ p = XSAVE_APX_EGPR_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 8))
+ {
+ xstate_bv |= X86_XSTATE_APX_F;
+ memcpy (p, raw, 8);
+ }
+ break;
+
case pkeys:
/* This is a PKEYS register. */
p = XSAVE_PKEYS_ADDR (tdep, regs, regnum);
@@ -37,6 +37,9 @@ struct x86_xsave_layout;
#define I387_NUM_YMM_REGS(tdep) ((tdep)->num_ymm_regs)
#define I387_YMM0H_REGNUM(tdep) ((tdep)->ymm0h_regnum)
+#define I387_R16_REGNUM(tdep) ((tdep)->r16_regnum)
+#define I387_NUM_APX_REGS(tdep) ((tdep)->num_apx_regs)
+
/* Set of constants used for 32 and 64-bit. */
#define I387_NUM_K_REGS 8
#define I387_NUM_PKEYS_REGS 1
@@ -75,6 +78,9 @@ struct x86_xsave_layout;
#define I387_XMM_AVX512_END_REGNUM(tdep) \
(I387_XMM16_REGNUM (tdep) + I387_NUM_XMM_AVX512_REGS (tdep))
+#define I387_APX_END_REGNUM(tdep) \
+ (I387_R16_REGNUM (tdep) + I387_NUM_APX_REGS (tdep))
+
#define I387_PKEYSEND_REGNUM(tdep) \
(I387_PKRU_REGNUM (tdep) + I387_NUM_PKEYS_REGS)
@@ -56,6 +56,7 @@ x86_fetch_xsave_layout (uint64_t xcr0, int len)
x86_xsave_layout layout;
layout.sizeof_xsave = len;
layout.avx_offset = xsave_feature_offset (xcr0, X86_XSTATE_AVX_ID);
+ layout.apx_offset = xsave_feature_offset (xcr0, X86_XSTATE_APX_F_ID);
layout.k_offset = xsave_feature_offset (xcr0, X86_XSTATE_K_ID);
layout.zmm_h_offset = xsave_feature_offset (xcr0, X86_XSTATE_ZMM_H_ID);
layout.zmm_offset = xsave_feature_offset (xcr0, X86_XSTATE_ZMM_ID);
@@ -380,6 +380,7 @@ target_debug_print_x86_xsave_layout (const x86_xsave_layout &layout)
POFFS(zmm_h);
POFFS(zmm);
POFFS(pkru);
+ POFFS(apx);
#undef POFFS
new file mode 100644
@@ -0,0 +1,87 @@
+# Copyright 2024 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/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# Test apx corefiles.
+
+require allow_apx_tests
+
+standard_testfile amd64-apx.c
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ {debug additional_flags=-mapxf}] } {
+ return -1
+}
+
+set nr_regs 16
+set egpr(1) r16
+set egpr(2) r17
+set egpr(3) r18
+set egpr(4) r19
+set egpr(5) r20
+set egpr(6) r21
+set egpr(7) r22
+set egpr(8) r23
+set egpr(9) r24
+set egpr(10) r25
+set egpr(11) r26
+set egpr(12) r27
+set egpr(13) r28
+set egpr(14) r29
+set egpr(15) r30
+set egpr(16) r31
+
+proc test_apx_corefiles {setting} {
+ global egpr nr_regs
+
+ clean_restart "$::testfile"
+ if { ![runto_main] } {
+ continue
+ }
+
+ set line [gdb_get_line_number "break here"]
+ gdb_breakpoint $line
+ gdb_continue_to_breakpoint "break here" ".*$::srcfile:$line.*"
+
+ gdb_test_no_output "maint set gcore xml-target-description ${setting}"
+
+ set gcorefile "${::binfile}_${setting}.gcore"
+ if { ![gdb_gcore_cmd $gcorefile "save a corefile"] } {
+ return -1
+ }
+
+ # Now restart gdb and load the corefile.
+ clean_restart "$::testfile"
+
+ gdb_test "core ${gcorefile}" \
+ "Core was generated by .*" "re-load generated corefile"
+
+ with_test_prefix "test egpr after corefile load" {
+ for { set r 1 } { $r <= $nr_regs } { incr r } {
+ set hexr [format %x [expr $r-1]]
+ gdb_test "print/z \$$egpr($r)" \
+ "= 0x00000000${hexr}4${hexr}3${hexr}2${hexr}1"
+ }
+ }
+}
+
+test_apx_corefiles "on"
+
+# Test the code path without the NT_GDB_TDESC note
+with_test_prefix "no NT_GDB_TDESC" {
+ test_apx_corefiles "off"
+}
new file mode 100644
@@ -0,0 +1,83 @@
+/* Copyright 2024 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>.
+
+ Test program for APX Extended GPRs (EGPRs). */
+
+long data[] = {
+ 0x0000000004030201,
+ 0x0000000014131211,
+ 0x0000000024232221,
+ 0x0000000034333231,
+ 0x0000000044434241,
+ 0x0000000054535251,
+ 0x0000000064636261,
+ 0x0000000074737271,
+ 0x0000000084838281,
+ 0x0000000094939291,
+ 0x00000000a4a3a2a1,
+ 0x00000000b4b3b2b1,
+ 0x00000000c4c3c2c1,
+ 0x00000000d4d3d2d1,
+ 0x00000000e4e3e2e1,
+ 0x00000000f4f3f2f1,
+};
+
+int
+main (int argc, char **argv)
+{
+ register long r16 asm ("r16");
+ register long r17 asm ("r17");
+ register long r18 asm ("r18");
+ register long r19 asm ("r19");
+ register long r20 asm ("r20");
+ register long r21 asm ("r21");
+ register long r22 asm ("r22");
+ register long r23 asm ("r23");
+ register long r24 asm ("r24");
+ register long r25 asm ("r25");
+ register long r26 asm ("r26");
+ register long r27 asm ("r27");
+ register long r28 asm ("r28");
+ register long r29 asm ("r29");
+ register long r30 asm ("r30");
+ register long r31 asm ("r31");
+
+ asm ("mov 0(%0), %%r16\n\t"
+ "mov 8(%0), %%r17\n\t"
+ "mov 16(%0), %%r18\n\t"
+ "mov 24(%0), %%r19\n\t"
+ "mov 32(%0), %%r20\n\t"
+ "mov 40(%0), %%r21\n\t"
+ "mov 48(%0), %%r22\n\t"
+ "mov 56(%0), %%r23\n\t"
+ "mov 64(%0), %%r24\n\t"
+ "mov 72(%0), %%r25\n\t"
+ "mov 80(%0), %%r26\n\t"
+ "mov 88(%0), %%r27\n\t"
+ "mov 96(%0), %%r28\n\t"
+ "mov 104(%0), %%r29\n\t"
+ "mov 112(%0), %%r30\n\t"
+ "mov 120(%0), %%r31\n\t"
+ : /* no output operands */
+ : "r" (data)
+ : "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31");
+
+ asm ("nop"); /* break here */
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,106 @@
+# Copyright 2024 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/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# Test apx dword, word, byte and raw registers.
+
+set nr_regs 16
+set regs(1) r16
+set regs(2) r17
+set regs(3) r18
+set regs(4) r19
+set regs(5) r20
+set regs(6) r21
+set regs(7) r22
+set regs(8) r23
+set regs(9) r24
+set regs(10) r25
+set regs(11) r26
+set regs(12) r27
+set regs(13) r28
+set regs(14) r29
+set regs(15) r30
+set regs(16) r31
+
+proc get_reg_val { type r } {
+ set hexr [format %x [expr $r-1]]
+ if { $type == "d"} {
+ return 0x${hexr}4${hexr}3${hexr}2${hexr}1
+ }
+ if { $type == "w" } {
+ return 0x${hexr}2${hexr}1
+ }
+ if { $type == "l" } {
+ return 0x${hexr}1
+ }
+ if { $type == "" } {
+ return 0x00000000${hexr}4${hexr}3${hexr}2${hexr}1
+ }
+}
+
+proc check_reg_content { type } {
+ global nr_regs
+ global regs
+
+ for { set r 1 } { $r <= $nr_regs } { incr r } {
+ set regval [get_reg_val $type $r]
+ gdb_test "print/z \$$regs($r)$type" "= $regval"
+ }
+}
+
+require allow_apx_tests
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ {debug additional_flags=-mapxf}] } {
+ return
+}
+
+if { ![runto_main] } {
+ return
+}
+
+set line [gdb_get_line_number "break here"]
+gdb_breakpoint $line
+gdb_continue_to_breakpoint "break here" ".*$srcfile:$line.*"
+
+# Run test for dword, word, byte pseudo registers, as well as raw registers.
+set regtypes [list "d" "w" "l" ""]
+set regtype_names [list "dword" "word" "byte" "raw"]
+
+# Check initial register content written by testprogram.
+for { set i 0 } { $i < [llength $regtypes] } { incr i } {
+ set type [lindex $regtypes $i]
+ set type_name [lindex $regtype_names $i]
+ with_test_prefix "$type_name register" {
+ check_reg_content $type
+ }
+}
+
+# Check writing registers with GDB.
+for { set i 0 } { $i < [llength $regtypes] } { incr i } {
+ set type [lindex $regtypes $i]
+ set type_name [lindex $regtype_names $i]
+ with_test_prefix "$type_name register" {
+ for { set r 1 } { $r <= $nr_regs } { incr r } {
+ set val [expr $r + $i]
+ gdb_test_no_output "set var \$$regs($r)$type = $val"
+ gdb_test "print \$$regs($r)$type" "= $val"
+ }
+ }
+}
@@ -4730,6 +4730,65 @@ gdb_caching_proc allow_lam_tests {} {
return $allow_lam_tests
}
+# Run a test on the target to see if it supports APX. Return 1 if so,
+# 0 if it does not.
+
+gdb_caching_proc allow_apx_tests {} {
+ global srcdir subdir gdb_prompt inferior_exited_re
+
+ set me "allow_apx_tests"
+ if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } {
+ verbose "$me: target does not support apx, returning 0" 2
+ return 0
+ }
+
+ # Compile a test program.
+ set src {
+ int data[] = {12345};
+
+ int
+ main (int argc, char **argv)
+ {
+ asm ("mov 0(%0), %%r30\n\t"
+ : /* no output operands */
+ : "r" (data));
+ return 0;
+ }
+ }
+ set compile_flags "{additional_flags=-mapxf}"
+ if { ![gdb_simple_compile $me $src executable $compile_flags] } {
+ return 0
+ }
+
+ # No error message, compilation succeeded so now run it via gdb.
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load "$obj"
+ gdb_run_cmd
+ gdb_expect {
+ -re ".*Illegal instruction.*${gdb_prompt} $" {
+ verbose -log "$me: apx hardware not detected."
+ set allow_apx_tests 0
+ }
+ -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+ verbose -log "$me: apx hardware detected."
+ set allow_apx_tests 1
+ }
+ default {
+ warning "\n$me: default case taken."
+ set allow_apx_tests 0
+ }
+ }
+ gdb_exit
+ remote_file build delete $obj
+
+ verbose "$me: returning $allow_apx_tests" 2
+ return $allow_apx_tests
+}
+
+
# Run a test on the target to see if it supports btrace hardware. Return 1 if so,
# 0 if it does not. Based on 'check_vmx_hw_available' from the GCC testsuite.
@@ -23,6 +23,7 @@
/* Default to SSE. */
static uint64_t x86_xstate_bv = X86_XSTATE_SSE_MASK;
+static const int num_apx_registers = 16;
static const int num_avx512_k_registers = 8;
static const int num_pkeys_registers = 1;
@@ -116,6 +117,10 @@ public:
unsigned char *ymmh_space ()
{ return xsave () + xsave_layout.avx_offset; }
+ /* Memory address of 16 EGPR register values of 64 bits. */
+ unsigned char *apx_space ()
+ { return xsave () + xsave_layout.apx_offset; }
+
/* Memory address of 8 OpMask register values of 64 bits. */
unsigned char *k_space ()
{ return xsave () + xsave_layout.k_offset; }
@@ -312,6 +317,10 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
if ((clear_bv & X86_XSTATE_PKRU))
for (i = 0; i < num_pkeys_registers; i++)
memset (fp->pkru_space () + i * 4, 0, 4);
+
+ if (amd64 && (clear_bv & X86_XSTATE_APX_F) != 0)
+ for (i = 0; i < num_apx_registers; i++)
+ memset (fp->apx_space () + i * 8, 0, 8);
}
/* Check if any x87 registers are changed. */
@@ -465,6 +474,23 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
}
+ /* Check if any APX registers are changed. */
+ if (amd64 && (x86_xstate_bv & X86_XSTATE_APX_F)!= 0)
+ {
+ int r16_regnum = find_regno (regcache->tdesc, "r16");
+
+ for (i = 0; i < num_apx_registers; i++)
+ {
+ collect_register (regcache, i + r16_regnum, raw);
+ p = fp->apx_space () + i * 8;
+ if (memcmp (raw, p, 8) != 0)
+ {
+ xstate_bv |= X86_XSTATE_APX_F;
+ memcpy (p, raw, 8);
+ }
+ }
+ }
+
if (x86_xstate_bv & X86_XSTATE_X87)
{
collect_register_by_name (regcache, "fioff", raw);
@@ -790,6 +816,23 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
+ if (amd64 && (x86_xstate_bv & X86_XSTATE_APX_F) != 0)
+ {
+ int r16_regnum = find_regno (regcache->tdesc, "r16");
+
+ if ((clear_bv & X86_XSTATE_APX_F) != 0)
+ {
+ for (i = 0; i < num_apx_registers; i++)
+ supply_register_zeroed (regcache, i + r16_regnum);
+ }
+ else
+ {
+ p = fp->apx_space ();
+ for (i = 0; i < num_apx_registers; i++)
+ supply_register (regcache, i + r16_regnum, p + i * 8);
+ }
+ }
+
if ((clear_bv & (X86_XSTATE_SSE | X86_XSTATE_AVX))
== (X86_XSTATE_SSE | X86_XSTATE_AVX))
{
@@ -260,7 +260,9 @@ static const int x86_64_regmap[] =
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, /* pkru */
- -1 /* CET user mode register PL3_SSP. */
+ -1, /* CET user mode register PL3_SSP. */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* r16...r31 (APX). */
+ -1, -1, -1, -1, -1, -1, -1, -1,
};
#define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0]))
@@ -29,11 +29,13 @@
#define X86_XSTATE_ZMM_ID 7
#define X86_XSTATE_PKRU_ID 9
#define X86_XSTATE_CET_U_ID 11
+#define X86_XSTATE_APX_F_ID 19
/* The extended state feature bits. */
#define X86_XSTATE_X87 (1ULL << X86_XSTATE_X87_ID)
#define X86_XSTATE_SSE (1ULL << X86_XSTATE_SSE_ID)
#define X86_XSTATE_AVX (1ULL << X86_XSTATE_AVX_ID)
+#define X86_XSTATE_APX_F (1ULL << X86_XSTATE_APX_F_ID)
/* AVX 512 adds three feature bits. All three must be enabled. */
#define X86_XSTATE_K (1ULL << X86_XSTATE_K_ID)
@@ -53,6 +55,7 @@ struct x86_xsave_layout
{
int sizeof_xsave = 0;
int avx_offset = 0;
+ int apx_offset = 0;
int k_offset = 0;
int zmm_h_offset = 0;
int zmm_offset = 0;
@@ -64,6 +67,7 @@ constexpr bool operator== (const x86_xsave_layout &lhs,
{
return lhs.sizeof_xsave == rhs.sizeof_xsave
&& lhs.avx_offset == rhs.avx_offset
+ && lhs.apx_offset == rhs.apx_offset
&& lhs.k_offset == rhs.k_offset
&& lhs.zmm_h_offset == rhs.zmm_h_offset
&& lhs.zmm_offset == rhs.zmm_offset
@@ -81,14 +85,19 @@ constexpr bool operator!= (const x86_xsave_layout &lhs,
#define X86_XSTATE_X87_MASK X86_XSTATE_X87
#define X86_XSTATE_SSE_MASK (X86_XSTATE_X87 | X86_XSTATE_SSE)
#define X86_XSTATE_AVX_MASK (X86_XSTATE_SSE_MASK | X86_XSTATE_AVX)
+#define X86_XSTATE_AVX_APX_MASK (X86_XSTATE_AVX_MASK | X86_XSTATE_APX_F)
#define X86_XSTATE_AVX_AVX512_MASK (X86_XSTATE_AVX_MASK | X86_XSTATE_AVX512)
+#define X86_XSTATE_AVX_AVX512_APX_MASK\
+ (X86_XSTATE_AVX_AVX512_MASK | X86_XSTATE_APX_F)
#define X86_XSTATE_AVX_AVX512_PKU_MASK (X86_XSTATE_AVX_MASK\
| X86_XSTATE_AVX512 | X86_XSTATE_PKRU)
+#define X86_XSTATE_AVX_AVX512_PKU_APX_MASK\
+ (X86_XSTATE_AVX_AVX512_PKU_MASK | X86_XSTATE_APX_F)
/* Supported mask of state-component bitmap xstate_bv. The SDM defines
xstate_bv as XCR0 | IA32_XSS. */
-#define X86_XSTATE_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_MASK\
+#define X86_XSTATE_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_APX_MASK\
| X86_XSTATE_CET_U)
#define X86_XSTATE_SSE_SIZE 576
@@ -97,6 +106,7 @@ constexpr bool operator!= (const x86_xsave_layout &lhs,
#define HAS_AVX(XCR0) (((XCR0) & X86_XSTATE_AVX) != 0)
#define HAS_AVX512(XCR0) (((XCR0) & X86_XSTATE_AVX512) != 0)
+#define HAS_APX(XCR0) (((XCR0) & X86_XSTATE_APX_F) != 0)
#define HAS_PKRU(XCR0) (((XCR0) & X86_XSTATE_PKRU) != 0)
/* Initial value for fctrl register, as defined in the X86 manual, and