diff --git a/gdb/NEWS b/gdb/NEWS
index 8f40ca5cb11..5b3ba152188 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,10 @@
 
 *** Changes since GDB 17
 
+* 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.
+
 * Support for the Common Trace Format (CTF) has been removed.  GDB now
   saves trace information exclusively in its own "tfile" format.
 
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 9b23db72bbe..81e66be75c1 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -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.  */
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index a982e610642..18b8f2a4c0b 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -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 - AMD64_NUM_GPRS;
+	}
+    }
+  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 >= AMD64_NUM_GPRS)
+    gpnum += tdep->r16_regnum - AMD64_NUM_GPRS;
+  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 >= AMD64_NUM_GPRS)
+    gpnum += tdep->r16_regnum - AMD64_NUM_GPRS;
+  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)
diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
index 3de28952cca..93b3cb61b17 100644
--- a/gdb/amd64-tdep.h
+++ b/gdb/amd64-tdep.h
@@ -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
 };
diff --git a/gdb/arch/amd64.c b/gdb/arch/amd64.c
index d1a871dd6cb..3992bbf512e 100644
--- a/gdb/arch/amd64.c
+++ b/gdb/arch/amd64.c
@@ -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;
 }
diff --git a/gdb/arch/x86-linux-tdesc-features.c b/gdb/arch/x86-linux-tdesc-features.c
index 5d6ea7cc701..0191f326834 100644
--- a/gdb/arch/x86-linux-tdesc-features.c
+++ b/gdb/arch/x86-linux-tdesc-features.c
@@ -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 },
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0030698dcee..69a2d714299 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -50753,6 +50753,11 @@ 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 (@acronym{EGPRs})
+@samp{r16} - @samp{r31} with 64 bits each.  All @acronym{Intel APX}
+registers are valid only on amd64.
+
 @node LoongArch Features
 @subsection LoongArch Features
 @cindex target descriptions, LoongArch Features
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 161a7453d66..df716ab6c5e 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -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 \
diff --git a/gdb/features/i386/64bit-apx.c b/gdb/features/i386/64bit-apx.c
new file mode 100644
index 00000000000..34cd47131d1
--- /dev/null
+++ b/gdb/features/i386/64bit-apx.c
@@ -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;
+}
diff --git a/gdb/features/i386/64bit-apx.xml b/gdb/features/i386/64bit-apx.xml
new file mode 100644
index 00000000000..11a4ec67cae
--- /dev/null
+++ b/gdb/features/i386/64bit-apx.xml
@@ -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>
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index f69cc2dcc01..76d1b0c9531 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -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"));
 }
@@ -8519,7 +8519,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");
@@ -8535,6 +8536,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");
 
@@ -8562,6 +8566,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;
 
@@ -8577,7 +8584,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))
@@ -8597,6 +8604,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");
 
@@ -8681,6 +8691,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,
@@ -8948,6 +8970,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;
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index d64d5241754..bdafd523834 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -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;
 
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
index f22a5e02bbb..ea3f3f15a5d 100644
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -820,6 +820,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.  */
@@ -922,6 +950,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;
@@ -940,6 +969,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;
@@ -970,6 +1000,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;
@@ -980,6 +1011,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;
@@ -1045,8 +1077,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);
@@ -1055,6 +1088,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;
@@ -1101,6 +1137,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);
@@ -1276,6 +1319,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))
 	{
@@ -1434,8 +1496,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);
@@ -1443,6 +1506,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;
@@ -1507,6 +1573,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++)
@@ -1573,6 +1647,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);
@@ -1725,6 +1816,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);
diff --git a/gdb/i387-tdep.h b/gdb/i387-tdep.h
index 5d063502bce..f029c1e5119 100644
--- a/gdb/i387-tdep.h
+++ b/gdb/i387-tdep.h
@@ -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)
 
diff --git a/gdb/nat/x86-xstate.c b/gdb/nat/x86-xstate.c
index c45570179a6..f0f0b00e859 100644
--- a/gdb/nat/x86-xstate.c
+++ b/gdb/nat/x86-xstate.c
@@ -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);
diff --git a/gdb/target-debug.h b/gdb/target-debug.h
index c86affbc838..949847b181c 100644
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -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
 
diff --git a/gdb/testsuite/gdb.arch/amd64-apx-core.c b/gdb/testsuite/gdb.arch/amd64-apx-core.c
new file mode 100644
index 00000000000..34f4dac8851
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-apx-core.c
@@ -0,0 +1,88 @@
+/* Copyright 2024-2026 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).  */
+
+#include <stdlib.h>
+
+volatile int should_dump_core_p = 1;
+
+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");
+
+  if (should_dump_core_p) /* break here for gcore, or crash for OS corefile. */
+    abort ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-apx-corefile.c b/gdb/testsuite/gdb.arch/amd64-apx-corefile.c
new file mode 100644
index 00000000000..90c90e27992
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-apx-corefile.c
@@ -0,0 +1,71 @@
+/* Copyright 2024-2026 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 Intel APX Extended GPRs (EGPRs) in corefiles.  */
+
+#include <stdlib.h>
+
+volatile int should_dump_core_p = 1;
+
+long data[] = {
+  0x0000000004030201,
+  0x0000000014131211,
+  0x0000000024232221,
+  0x0000000034333231,
+  0x0000000044434241,
+  0x0000000054535251,
+  0x0000000064636261,
+  0x0000000074737271,
+  0x0000000084838281,
+  0x0000000094939291,
+  0x00000000a4a3a2a1,
+  0x00000000b4b3b2b1,
+  0x00000000c4c3c2c1,
+  0x00000000d4d3d2d1,
+  0x00000000e4e3e2e1,
+  0x00000000f4f3f2f1,
+};
+
+int
+main (int argc, char **argv)
+{
+  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");
+
+  if (should_dump_core_p) /* break here for gcore, or crash for OS corefile. */
+    abort ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-apx-corefile.exp b/gdb/testsuite/gdb.arch/amd64-apx-corefile.exp
new file mode 100644
index 00000000000..ed1b4bc142b
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-apx-corefile.exp
@@ -0,0 +1,67 @@
+# Copyright 2024-2026 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 Intel APX corefiles.
+
+require allow_apx_tests
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+	{debug additional_flags=-mapxf}] } {
+    return
+}
+
+proc test_apx_corefiles {core_filename} {
+    # Restart gdb and load the corefile.
+    clean_restart $::testfile
+
+    gdb_test "core $core_filename" "Core was generated by .*" \
+	"load corefile"
+
+    for { set r 16 } { $r <= 31  } { incr r } {
+	set hexr [format %x [expr {$r-16}]]
+	gdb_test "print/z \$r$r" \
+	    "= 0x00000000${hexr}4${hexr}3${hexr}2${hexr}1"
+    }
+}
+
+with_test_prefix "gcore corefile" {
+    if { ![runto_main] } {
+	return
+    }
+    gdb_test_no_output "set should_dump_core_p=0"
+
+    set line [gdb_get_line_number "break here"]
+    gdb_breakpoint $line
+    gdb_continue_to_breakpoint "break here" ".*$srcfile:$line.*"
+
+    set gcorefile $binfile.gcore
+    if { [gdb_gcore_cmd $gcorefile "save a corefile"] } {
+	test_apx_corefiles $gcorefile
+    }
+}
+
+with_test_prefix "OS generated corefile" {
+    set corefile [core_find $binfile]
+    if { $corefile eq "" } {
+	unsupported "unable to generate core file"
+	return
+    }
+    test_apx_corefiles $corefile
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-apx.c b/gdb/testsuite/gdb.arch/amd64-apx.c
new file mode 100644
index 00000000000..c9539d16cf1
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-apx.c
@@ -0,0 +1,66 @@
+/* Copyright 2024-2026 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 Intel 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)
+{
+  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;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-apx.exp b/gdb/testsuite/gdb.arch/amd64-apx.exp
new file mode 100644
index 00000000000..77d831ba786
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-apx.exp
@@ -0,0 +1,77 @@
+# Copyright 2024-2026 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 Intel APX dword, word, byte and raw registers.
+
+proc get_reg_val { type r } {
+    set hexr [format %x [expr {$r - 16}]]
+    switch $type {
+	"d"  { return 0x${hexr}4${hexr}3${hexr}2${hexr}1 }
+	"w"  { return 0x${hexr}2${hexr}1 }
+	"l"  { return 0x${hexr}1 }
+	""   { return 0x00000000${hexr}4${hexr}3${hexr}2${hexr}1 }
+    }
+}
+
+proc check_reg_content { type } {
+    for { set r 16 } { $r <= 31  } { incr r } {
+	set regval [get_reg_val $type $r]
+	gdb_test "print/z \$r$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.
+foreach type $regtypes type_name $regtype_names {
+    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 16 } { $r <= 31  } { incr r } {
+	    set val [expr {($r - 16) + $i}]
+	    gdb_test_no_output "set var \$r$r$type = $val"
+	    gdb_test "print \$r$r$type" "= $val"
+	}
+    }
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 41e9a8c721e..2825b1a71f7 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4765,6 +4765,64 @@ 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.
 
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
index 164b666979f..90f146a74d2 100644
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -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))
     {
diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
index 906191e04f4..f893821fa48 100644
--- a/gdbserver/linux-x86-low.cc
+++ b/gdbserver/linux-x86-low.cc
@@ -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]))
diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h
index ee8660f8cb4..3602fa40cd9 100644
--- a/gdbsupport/x86-xstate.h
+++ b/gdbsupport/x86-xstate.h
@@ -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
