#include "record-full.h"
#include "linux-record.h"
-#include "features/i386/i386-linux.c"
-#include "features/i386/i386-mmx-linux.c"
-#include "features/i386/i386-mpx-linux.c"
-#include "features/i386/i386-avx-mpx-linux.c"
-#include "features/i386/i386-avx-linux.c"
-#include "features/i386/i386-avx-avx512-linux.c"
-#include "features/i386/i386-avx-mpx-avx512-pku-linux.c"
+
+#include "features/i386/32bit-core.c"
+#include "features/i386/32bit-sse.c"
+#include "features/i386/32bit-linux.c"
+#include "features/i386/32bit-avx.c"
+#include "features/i386/32bit-mpx.c"
+#include "features/i386/32bit-avx512.c"
+#include "features/i386/32bit-pkeys.c"
/* Return non-zero, when the register is in the corresponding register
group. Put the LINUX_ORIG_EAX register in the system group. */
const struct target_desc *
i386_linux_read_description (uint64_t xcr0)
{
- switch ((xcr0 & X86_XSTATE_ALL_MASK))
+ if (xcr0 == 0)
+ return NULL;
+
+ static struct target_desc *i386_linux_tdescs \
+ [2/*X87*/][2/*SSE*/][2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/] = {};
+ struct target_desc **tdesc;
+
+ tdesc = &i386_linux_tdescs[(xcr0 & X86_XSTATE_X87) ? 1 : 0]
+ [(xcr0 & X86_XSTATE_SSE) ? 1 : 0]
+ [(xcr0 & X86_XSTATE_AVX) ? 1 : 0]
+ [(xcr0 & X86_XSTATE_MPX) ? 1 : 0]
+ [(xcr0 & X86_XSTATE_AVX512) ? 1 : 0]
+ [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0];
+
+ if (*tdesc == NULL)
{
- case X86_XSTATE_AVX_MPX_AVX512_PKU_MASK:
- return tdesc_i386_avx_mpx_avx512_pku_linux;
- case X86_XSTATE_AVX_AVX512_MASK:
- return tdesc_i386_avx_avx512_linux;
- case X86_XSTATE_MPX_MASK:
- return tdesc_i386_mpx_linux;
- case X86_XSTATE_AVX_MPX_MASK:
- return tdesc_i386_avx_mpx_linux;
- case X86_XSTATE_AVX_MASK:
- return tdesc_i386_avx_linux;
- case X86_XSTATE_SSE_MASK:
- return tdesc_i386_linux;
- case X86_XSTATE_X87_MASK:
- return tdesc_i386_mmx_linux;
- default:
- break;
+ *tdesc = allocate_target_description ();
+ set_tdesc_architecture (*tdesc, bfd_scan_arch ("i386"));
+ set_tdesc_osabi (*tdesc, osabi_from_tdesc_string ("GNU/Linux"));
+
+ long regnum = 0;
+
+ if (xcr0 & X86_XSTATE_X87)
+ regnum = create_feature_i386_32bit_core (*tdesc, regnum);
+
+ if (xcr0 & X86_XSTATE_SSE)
+ regnum = create_feature_i386_32bit_sse (*tdesc, regnum);
+
+ regnum = create_feature_i386_32bit_linux (*tdesc, regnum);
+
+ if (xcr0 & X86_XSTATE_AVX)
+ regnum = create_feature_i386_32bit_avx (*tdesc, regnum);
+
+ if (xcr0 & X86_XSTATE_MPX)
+ regnum = create_feature_i386_32bit_mpx (*tdesc, regnum);
+
+ if (xcr0 & X86_XSTATE_AVX512)
+ regnum = create_feature_i386_32bit_avx512 (*tdesc, regnum);
+
+ if (xcr0 & X86_XSTATE_PKRU)
+ regnum = create_feature_i386_32bit_pkeys (*tdesc, regnum);
}
- return NULL;
+ return *tdesc;
}
/* Get Linux/x86 target description from core dump. */
{
gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX,
i386_linux_init_abi);
-
- /* Initialize the Linux target description. */
- initialize_tdesc_i386_linux ();
- initialize_tdesc_i386_mmx_linux ();
- initialize_tdesc_i386_avx_linux ();
- initialize_tdesc_i386_mpx_linux ();
- initialize_tdesc_i386_avx_mpx_linux ();
- initialize_tdesc_i386_avx_avx512_linux ();
- initialize_tdesc_i386_avx_mpx_avx512_pku_linux ();
}
void visit (const tdesc_reg *reg) override
{
+ /* Most "reg" in XML target descriptions don't have "regnum"
+ attribute, so the register number is allocated sequentially.
+ In case that reg has "regnum" attribute, register number
+ should be set by that explicitly. */
+
+ if (reg->target_regnum < m_next_regnum)
+ {
+ /* The integrity check, it can catch some errors on register
+ number collision, like this,
+
+ <reg name="x0" bitsize="32"/>
+ <reg name="x1" bitsize="32"/>
+ <reg name="x2" bitsize="32"/>
+ <reg name="x3" bitsize="32"/>
+ <reg name="ps" bitsize="32" regnum="3"/>
+
+ but it also has false negatives. The target description
+ below is correct,
+
+ <reg name="x1" bitsize="32" regnum="1"/>
+ <reg name="x3" bitsize="32" regnum="3"/>
+ <reg name="x2" bitsize="32" regnum="2"/>
+ <reg name="x4" bitsize="32" regnum="4"/>
+
+ but it is not a good practice, so still error on this,
+ and also print the message so that it can be saved in the
+ generated c file. */
+
+ printf_unfiltered ("ERROR: \"regnum\" attribute %ld ",
+ reg->target_regnum);
+ printf_unfiltered ("is not the largest number (%d).\n",
+ m_next_regnum);
+ error (_("\"regnum\" attribute %ld is not the largest number (%d)."),
+ reg->target_regnum, m_next_regnum);
+ }
+
+ if (reg->target_regnum > m_next_regnum)
+ {
+ printf_unfiltered (" regnum = %ld;\n", reg->target_regnum);
+ m_next_regnum = reg->target_regnum;
+ }
+
printf_unfiltered (" tdesc_create_reg (feature, \"%s\", regnum++, %d, ",
reg->name, reg->save_restore);
if (reg->group)
else
printf_unfiltered ("NULL, ");
printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type);
+
+ m_next_regnum++;
}
+private:
+ /* The register number to use for the next register we see. */
+ int m_next_regnum = 0;
};
static void