aboutsummaryrefslogtreecommitdiff
path: root/gdb/i386-tdep.c
diff options
context:
space:
mode:
authorWalfred Tedeschi <walfred.tedeschi@intel.com>2013-11-20 13:02:00 +0100
committerWalfred Tedeschi <walfred.tedeschi@intel.com>2013-11-20 14:42:50 +0100
commit1dbcd68cf12168c359df2da36b5b612100310a30 (patch)
tree7ff900d7ed9b933c214ef9c686bc509e884b9e85 /gdb/i386-tdep.c
parentccc42043f7a34784560e08553bbf51ce3044785e (diff)
downloadgdb-1dbcd68cf12168c359df2da36b5b612100310a30.zip
gdb-1dbcd68cf12168c359df2da36b5b612100310a30.tar.gz
gdb-1dbcd68cf12168c359df2da36b5b612100310a30.tar.bz2
Add MPX support for i386
2013-11-20 Walfred Tedeschi <walfred.tedeschi@intel.com> * i386-linux-nat.c (GETXSTATEREGS_SUPPLIES): Add MPX registers on the range of registers to be read from xsave buffer. (i386_linux_read_description): Add case for MPX. * i386-linux-tdep.c: Include features/i386/i386-mpx-linux.c. (i386_linux_gregset_reg_offset): Add MPX registers. (i386_linux_core_read_description): Initialize also MPX. (_initialize_i386_linux_tdep): Add mpx initialization. * i386-tdep.h (gdbarch_tdep): Add fields bnd0r_regnum, bnd0_regnum, mpx_register_names. (i386_regnum): Add MPX registers. (I386_MPX_NUM_REGS): New macro. (i386_bnd_regnum_p): New function. * i386-linux-tdep.h (I386_LINUX_NUM_REGS): Set number of registers to be the number of BNDSTATUS. (tdesc_i386_mpx_linux): Add description for MPX Linux registers. * i386-tdep.c: Include features/i386/i386-mpx.c. (i386_mpx_names): Add MPX register names array. (i386_bnd_names): Add bnd pseudo register names array. (i386_bndr_regnum_p): Lookup register numbers for bnd raw registers. (i386_bndr_regnum_p): Lookup register numbers for bnd raw registers. (386_mpx_ctrl_regnum_p): Lookup register numbers for MPX control registers. (i386_bnd_type): New function. (i386_pseudo_register_type): Use i386_bnd_type for bnd pseudo register types. (i386_pseudo_register_read_into_value): Add bnd case. (i386_pseudo_register_write): Add bnd pseudo registers. (i386_register_reggroup_p): Add MPX register to the group all. (i386_validate_tdesc_p): Add MPX to the target description validation. (i386_pseudo_register_name): Add bnd pseudo registers. (i386_gdbarch_init): Add MPX for architecture initialization. (_initia_initialize_i386_tdep): Add mpx initialization. * i387-tdep.c (xsave_mpx_offset): New vector for MPX offsets on XSAVE buffer. (XSAVE_MPX_ADDR): New macro. (i387_supply_xsave): Add MPX case. (i387_collect_xsave): Add MPX case. * i387-tdep.h (I387_BND0R_REGNUM): New macro. (I387_BNDCFGU_REGNUM): New macro. (I387_NUM_MPX_REGS): New macro. (I387_NUM_BND_REGS): New macro. (I387_NUM_MPX_CTRL_REGS): New macro. (I387_MPXEND_REGNUM): New macro. * common/i386-xstate.h (I386_XSTATE_BNDREGS): New macro. (I386_XSTATE_BNDCFG): Likewise. (I386_XSTATE_MPX_MASK): Likewise. (I386_XSTATE_ALL_MASK): New macro represents flags for all states. (I386_XSTATE_BNDREGS_SIZE): New macro. (I386_XSTATE_BNDCFG_SIZE): Likewise. (I386_XSTATE_SIZE): Adapt for MPX. (I386_XSTATE_MAX_SIZE): Likewise. Change-Id: I9ddb7d49434d86fa18eb6b99515203d7c567aefd Signed-off-by: Walfred Tedeschi <walfred.tedeschi@intel.com> Conflicts: gdb/ChangeLog
Diffstat (limited to 'gdb/i386-tdep.c')
-rw-r--r--gdb/i386-tdep.c219
1 files changed, 211 insertions, 8 deletions
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 9529dcc..597d672 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -57,6 +57,7 @@
#include "features/i386/i386.c"
#include "features/i386/i386-avx.c"
+#include "features/i386/i386-mpx.c"
#include "features/i386/i386-mmx.c"
#include "ax.h"
@@ -98,6 +99,18 @@ static const char *i386_ymmh_names[] =
"ymm4h", "ymm5h", "ymm6h", "ymm7h",
};
+static const char *i386_mpx_names[] =
+{
+ "bnd0raw", "bnd1raw", "bnd2raw", "bnd3raw", "bndcfgu", "bndstatus"
+};
+
+/* Register names for MPX pseudo-registers. */
+
+static const char *i386_bnd_names[] =
+{
+ "bnd0", "bnd1", "bnd2", "bnd3"
+};
+
/* Register names for MMX pseudo-registers. */
static const char *i386_mmx_names[] =
@@ -202,6 +215,21 @@ i386_ymm_regnum_p (struct gdbarch *gdbarch, int regnum)
return regnum >= 0 && regnum < tdep->num_ymm_regs;
}
+/* BND register? */
+
+int
+i386_bnd_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int bnd0_regnum = tdep->bnd0_regnum;
+
+ if (bnd0_regnum < 0)
+ return 0;
+
+ regnum -= bnd0_regnum;
+ return regnum >= 0 && regnum < I387_NUM_BND_REGS;
+}
+
/* SSE register? */
int
@@ -254,6 +282,34 @@ i386_fpc_regnum_p (struct gdbarch *gdbarch, int regnum)
&& regnum < I387_XMM0_REGNUM (tdep));
}
+/* BNDr (raw) register? */
+
+static int
+i386_bndr_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (I387_BND0R_REGNUM (tdep) < 0)
+ return 0;
+
+ regnum -= tdep->bnd0r_regnum;
+ return regnum >= 0 && regnum < I387_NUM_BND_REGS;
+}
+
+/* BND control register? */
+
+static int
+i386_mpx_ctrl_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (I387_BNDCFGU_REGNUM (tdep) < 0)
+ return 0;
+
+ regnum -= I387_BNDCFGU_REGNUM (tdep);
+ return regnum >= 0 && regnum < I387_NUM_MPX_CTRL_REGS;
+}
+
/* Return the name of register REGNUM, or the empty string if it is
an anonymous register. */
@@ -273,6 +329,8 @@ const char *
i386_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ if (i386_bnd_regnum_p (gdbarch, regnum))
+ return i386_bnd_names[regnum - tdep->bnd0_regnum];
if (i386_mmx_regnum_p (gdbarch, regnum))
return i386_mmx_names[regnum - I387_MM0_REGNUM (tdep)];
else if (i386_ymm_regnum_p (gdbarch, regnum))
@@ -2750,6 +2808,43 @@ i387_ext_type (struct gdbarch *gdbarch)
return tdep->i387_ext_type;
}
+/* Construct type for pseudo BND registers. We can't use
+ tdesc_find_type since a complement of one value has to be used
+ to describe the upper bound. */
+
+static struct type *
+i386_bnd_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+
+ if (!tdep->i386_bnd_type)
+ {
+ struct type *t, *bound_t;
+ const struct builtin_type *bt = builtin_type (gdbarch);
+
+ /* The type we're building is described bellow: */
+#if 0
+ struct __bound128
+ {
+ void *lbound;
+ void *ubound; /* One complement of raw ubound field. */
+ };
+#endif
+
+ t = arch_composite_type (gdbarch,
+ "__gdb_builtin_type_bound128", TYPE_CODE_STRUCT);
+
+ append_composite_type_field (t, "lbound", bt->builtin_data_ptr);
+ append_composite_type_field (t, "ubound", bt->builtin_data_ptr);
+
+ TYPE_NAME (t) = "builtin_type_bound128";
+ tdep->i386_bnd_type = t;
+ }
+
+ return tdep->i386_bnd_type;
+}
+
/* Construct vector type for pseudo YMM registers. We can't use
tdesc_find_type since YMM isn't described in target description. */
@@ -2851,6 +2946,8 @@ i386_mmx_type (struct gdbarch *gdbarch)
struct type *
i386_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
{
+ if (i386_bnd_regnum_p (gdbarch, regnum))
+ return i386_bnd_type (gdbarch);
if (i386_mmx_regnum_p (gdbarch, regnum))
return i386_mmx_type (gdbarch);
else if (i386_ymm_regnum_p (gdbarch, regnum))
@@ -2917,8 +3014,31 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
else
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ if (i386_bnd_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->bnd0_regnum;
- if (i386_ymm_regnum_p (gdbarch, regnum))
+ /* Extract (always little endian). Read lower 128bits. */
+ status = regcache_raw_read (regcache,
+ I387_BND0R_REGNUM (tdep) + regnum,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 0, 16);
+ else
+ {
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+ LONGEST upper, lower;
+ int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);
+
+ lower = extract_unsigned_integer (raw_buf, 8, byte_order);
+ upper = extract_unsigned_integer (raw_buf + 8, 8, byte_order);
+ upper = ~upper;
+
+ memcpy (buf, &lower, size);
+ memcpy (buf + size, &upper, size);
+ }
+ }
+ else if (i386_ymm_regnum_p (gdbarch, regnum))
{
regnum -= tdep->ymm0_regnum;
@@ -3011,7 +3131,34 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (i386_ymm_regnum_p (gdbarch, regnum))
+ if (i386_bnd_regnum_p (gdbarch, regnum))
+ {
+ ULONGEST upper, lower;
+ int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+
+ /* New values from input value. */
+ regnum -= tdep->bnd0_regnum;
+ lower = extract_unsigned_integer (buf, size, byte_order);
+ upper = extract_unsigned_integer (buf + size, size, byte_order);
+
+ /* Fetching register buffer. */
+ regcache_raw_read (regcache,
+ I387_BND0R_REGNUM (tdep) + regnum,
+ raw_buf);
+
+ upper = ~upper;
+
+ /* Set register bits. */
+ memcpy (raw_buf, &lower, 8);
+ memcpy (raw_buf + 8, &upper, 8);
+
+
+ regcache_raw_write (regcache,
+ I387_BND0R_REGNUM (tdep) + regnum,
+ raw_buf);
+ }
+ else if (i386_ymm_regnum_p (gdbarch, regnum))
{
regnum -= tdep->ymm0_regnum;
@@ -3866,7 +4013,8 @@ i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
{
const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int fp_regnum_p, mmx_regnum_p, xmm_regnum_p, mxcsr_regnum_p,
- ymm_regnum_p, ymmh_regnum_p;
+ ymm_regnum_p, ymmh_regnum_p, bndr_regnum_p, bnd_regnum_p,
+ mpx_ctrl_regnum_p;
/* Don't include pseudo registers, except for MMX, in any register
groups. */
@@ -3911,13 +4059,31 @@ i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
|| ymmh_regnum_p))
return 0;
+ bnd_regnum_p = i386_bnd_regnum_p (gdbarch, regnum);
+ if (group == all_reggroup
+ && ((bnd_regnum_p && (tdep->xcr0 & I386_XSTATE_MPX_MASK))))
+ return bnd_regnum_p;
+
+ bndr_regnum_p = i386_bndr_regnum_p (gdbarch, regnum);
+ if (group == all_reggroup
+ && ((bndr_regnum_p && (tdep->xcr0 & I386_XSTATE_MPX_MASK))))
+ return 0;
+
+ mpx_ctrl_regnum_p = i386_mpx_ctrl_regnum_p (gdbarch, regnum);
+ if (group == all_reggroup
+ && ((mpx_ctrl_regnum_p && (tdep->xcr0 & I386_XSTATE_MPX_MASK))))
+ return mpx_ctrl_regnum_p;
+
if (group == general_reggroup)
return (!fp_regnum_p
&& !mmx_regnum_p
&& !mxcsr_regnum_p
&& !xmm_regnum_p
&& !ymm_regnum_p
- && !ymmh_regnum_p);
+ && !ymmh_regnum_p
+ && !bndr_regnum_p
+ && !bnd_regnum_p
+ && !mpx_ctrl_regnum_p);
return default_register_reggroup_p (gdbarch, regnum, group);
}
@@ -7496,7 +7662,7 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
{
const struct target_desc *tdesc = tdep->tdesc;
const struct tdesc_feature *feature_core;
- const struct tdesc_feature *feature_sse, *feature_avx;
+ const struct tdesc_feature *feature_sse, *feature_avx, *feature_mpx;
int i, num_regs, valid_p;
if (! tdesc_has_registers (tdesc))
@@ -7513,6 +7679,9 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
/* Try AVX registers. */
feature_avx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx");
+ /* Try MPX registers. */
+ feature_mpx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.mpx");
+
valid_p = 1;
/* The XCR0 bits. */
@@ -7559,6 +7728,23 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
tdep->register_names[i]);
}
+ if (feature_mpx)
+ {
+ tdep->xcr0 = I386_XSTATE_MPX_MASK;
+
+ if (tdep->bnd0r_regnum < 0)
+ {
+ tdep->mpx_register_names = i386_mpx_names;
+ tdep->bnd0r_regnum = I386_BND0R_REGNUM;
+ tdep->bndcfgu_regnum = I386_BNDCFGU_REGNUM;
+ }
+
+ for (i = 0; i < I387_NUM_MPX_REGS; i++)
+ valid_p &= tdesc_numbered_register (feature_mpx, tdesc_data,
+ I387_BND0R_REGNUM (tdep) + i,
+ tdep->mpx_register_names[i]);
+ }
+
return valid_p;
}
@@ -7572,6 +7758,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
const struct target_desc *tdesc;
int mm0_regnum;
int ymm0_regnum;
+ int bnd0_regnum;
+ int num_bnd_cooked;
/* If there is already a candidate, use it. */
arches = gdbarch_list_lookup_by_info (arches, &info);
@@ -7745,8 +7933,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Even though the default ABI only includes general-purpose registers,
floating-point registers and the SSE registers, we have to leave a
- gap for the upper AVX registers. */
- set_gdbarch_num_regs (gdbarch, I386_AVX_NUM_REGS);
+ gap for the upper AVX registers and the MPX registers. */
+ set_gdbarch_num_regs (gdbarch, I386_MPX_NUM_REGS);
/* Get the x86 target description from INFO. */
tdesc = info.target_desc;
@@ -7767,6 +7955,10 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep->num_mmx_regs = 8;
tdep->num_ymm_regs = 0;
+ /* No MPX registers. */
+ tdep->bnd0r_regnum = -1;
+ tdep->bndcfgu_regnum = -1;
+
tdesc_data = tdesc_data_alloc ();
set_gdbarch_relocate_instruction (gdbarch, i386_relocate_instruction);
@@ -7785,13 +7977,16 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
return NULL;
}
+ num_bnd_cooked = (tdep->bnd0r_regnum > 0 ? I387_NUM_BND_REGS : 0);
+
/* Wire in pseudo registers. Number of pseudo registers may be
changed. */
set_gdbarch_num_pseudo_regs (gdbarch, (tdep->num_byte_regs
+ tdep->num_word_regs
+ tdep->num_dword_regs
+ tdep->num_mmx_regs
- + tdep->num_ymm_regs));
+ + tdep->num_ymm_regs
+ + num_bnd_cooked));
/* Target description may be changed. */
tdesc = tdep->tdesc;
@@ -7825,14 +8020,21 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
else
tdep->ymm0_regnum = -1;
+ bnd0_regnum = mm0_regnum;
if (tdep->num_mmx_regs != 0)
{
/* Support MMX pseudo-register if MMX hasn't been disabled. */
tdep->mm0_regnum = mm0_regnum;
+ bnd0_regnum += tdep->num_mmx_regs;
}
else
tdep->mm0_regnum = -1;
+ if (tdep->bnd0r_regnum > 0)
+ tdep->bnd0_regnum = bnd0_regnum;
+ else
+ tdep-> bnd0_regnum = -1;
+
/* Hook in the legacy prologue-based unwinders last (fallback). */
frame_unwind_append_unwinder (gdbarch, &i386_stack_tramp_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &i386_sigtramp_frame_unwind);
@@ -7910,6 +8112,7 @@ is \"default\"."),
initialize_tdesc_i386 ();
initialize_tdesc_i386_mmx ();
initialize_tdesc_i386_avx ();
+ initialize_tdesc_i386_mpx ();
/* Tell remote stub that we support XML target description. */
register_remote_support_xml ("i386");