/* Intel 386 target-dependent stuff.
- Copyright (C) 1988-2013 Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include "frame-base.h"
#include "frame-unwind.h"
#include "inferior.h"
+#include "infrun.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdbtypes.h"
#include "dis-asm.h"
#include "disasm.h"
#include "remote.h"
-#include "exceptions.h"
-#include "gdb_assert.h"
-#include <string.h>
-
#include "i386-tdep.h"
#include "i387-tdep.h"
-#include "i386-xstate.h"
+#include "x86-xstate.h"
#include "record.h"
#include "record-full.h"
-#include <stdint.h>
-
#include "features/i386/i386.c"
#include "features/i386/i386-avx.c"
#include "features/i386/i386-mpx.c"
+#include "features/i386/i386-avx512.c"
#include "features/i386/i386-mmx.c"
#include "ax.h"
"mxcsr"
};
+static const char *i386_zmm_names[] =
+{
+ "zmm0", "zmm1", "zmm2", "zmm3",
+ "zmm4", "zmm5", "zmm6", "zmm7"
+};
+
+static const char *i386_zmmh_names[] =
+{
+ "zmm0h", "zmm1h", "zmm2h", "zmm3h",
+ "zmm4h", "zmm5h", "zmm6h", "zmm7h"
+};
+
+static const char *i386_k_names[] =
+{
+ "k0", "k1", "k2", "k3",
+ "k4", "k5", "k6", "k7"
+};
+
static const char *i386_ymm_names[] =
{
"ymm0", "ymm1", "ymm2", "ymm3",
"", "bp", "si", "di"
};
+/* Constant used for reading/writing pseudo registers. In 64-bit mode, we have
+ 16 lower ZMM regs that extend corresponding xmm/ymm registers. In addition,
+ we have 16 upper ZMM regs that have to be handled differently. */
+
+const int num_lower_zmm_regs = 16;
+
/* MMX register? */
static int
return regnum >= 0 && regnum < tdep->num_dword_regs;
}
+/* AVX512 register? */
+
+int
+i386_zmmh_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int zmm0h_regnum = tdep->zmm0h_regnum;
+
+ if (zmm0h_regnum < 0)
+ return 0;
+
+ regnum -= zmm0h_regnum;
+ return regnum >= 0 && regnum < tdep->num_zmm_regs;
+}
+
+int
+i386_zmm_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int zmm0_regnum = tdep->zmm0_regnum;
+
+ if (zmm0_regnum < 0)
+ return 0;
+
+ regnum -= zmm0_regnum;
+ return regnum >= 0 && regnum < tdep->num_zmm_regs;
+}
+
+int
+i386_k_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int k0_regnum = tdep->k0_regnum;
+
+ if (k0_regnum < 0)
+ return 0;
+
+ regnum -= k0_regnum;
+ return regnum >= 0 && regnum < I387_NUM_K_REGS;
+}
+
static int
i386_ymmh_regnum_p (struct gdbarch *gdbarch, int regnum)
{
return regnum >= 0 && regnum < tdep->num_ymm_regs;
}
+static int
+i386_ymmh_avx512_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int ymm16h_regnum = tdep->ymm16h_regnum;
+
+ if (ymm16h_regnum < 0)
+ return 0;
+
+ regnum -= ymm16h_regnum;
+ return regnum >= 0 && regnum < tdep->num_ymm_avx512_regs;
+}
+
+int
+i386_ymm_avx512_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int ymm16_regnum = tdep->ymm16_regnum;
+
+ if (ymm16_regnum < 0)
+ return 0;
+
+ regnum -= ymm16_regnum;
+ return regnum >= 0 && regnum < tdep->num_ymm_avx512_regs;
+}
+
/* BND register? */
int
return regnum >= 0 && regnum < num_xmm_regs;
}
+/* XMM_512 register? */
+
+int
+i386_xmm_avx512_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int num_xmm_avx512_regs = I387_NUM_XMM_AVX512_REGS (tdep);
+
+ if (num_xmm_avx512_regs == 0)
+ return 0;
+
+ regnum -= I387_XMM16_REGNUM (tdep);
+ return regnum >= 0 && regnum < num_xmm_avx512_regs;
+}
+
static int
i386_mxcsr_regnum_p (struct gdbarch *gdbarch, int regnum)
{
if (i386_ymmh_regnum_p (gdbarch, regnum))
return "";
+ /* Hide the upper YMM16-31 registers. */
+ if (i386_ymmh_avx512_regnum_p (gdbarch, regnum))
+ return "";
+
+ /* Hide the upper ZMM registers. */
+ if (i386_zmmh_regnum_p (gdbarch, regnum))
+ return "";
+
return tdesc_register_name (gdbarch, regnum);
}
return i386_mmx_names[regnum - I387_MM0_REGNUM (tdep)];
else if (i386_ymm_regnum_p (gdbarch, regnum))
return i386_ymm_names[regnum - tdep->ymm0_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];
else if (i386_word_regnum_p (gdbarch, regnum))
return 0;
}
+/* Return non-zero if INSN is a jump, zero otherwise. */
+
+static int
+i386_jmp_p (const gdb_byte *insn)
+{
+ /* jump short, relative. */
+ if (insn[0] == 0xeb)
+ return 1;
+
+ /* jump near, relative. */
+ if (insn[0] == 0xe9)
+ return 1;
+
+ return i386_absolute_jmp_p (insn);
+}
+
static int
i386_absolute_call_p (const gdb_byte *insn)
{
return 0;
}
+/* The gdbarch insn_is_call method. */
+
+static int
+i386_insn_is_call (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[I386_MAX_INSN_LEN], *insn;
+
+ read_code (addr, buf, I386_MAX_INSN_LEN);
+ insn = i386_skip_prefixes (buf, I386_MAX_INSN_LEN);
+
+ return i386_call_p (insn);
+}
+
+/* The gdbarch insn_is_ret method. */
+
+static int
+i386_insn_is_ret (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[I386_MAX_INSN_LEN], *insn;
+
+ read_code (addr, buf, I386_MAX_INSN_LEN);
+ insn = i386_skip_prefixes (buf, I386_MAX_INSN_LEN);
+
+ return i386_ret_p (insn);
+}
+
+/* The gdbarch insn_is_jump method. */
+
+static int
+i386_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[I386_MAX_INSN_LEN], *insn;
+
+ read_code (addr, buf, I386_MAX_INSN_LEN);
+ insn = i386_skip_prefixes (buf, I386_MAX_INSN_LEN);
+
+ return i386_jmp_p (insn);
+}
+
/* Some kernels may run one past a syscall insn, so we have to cope.
Otherwise this is just simple_displaced_step_copy_insn. */
{
CORE_ADDR post_prologue_pc
= skip_prologue_using_sal (gdbarch, func_addr);
- struct symtab *s = find_pc_symtab (func_addr);
+ struct compunit_symtab *cust = find_pc_compunit_symtab (func_addr);
/* Clang always emits a line note before the prologue and another
one after. We trust clang to emit usable line notes. */
if (post_prologue_pc
- && (s != NULL
- && s->producer != NULL
- && strncmp (s->producer, "clang ", sizeof ("clang ") - 1) == 0))
+ && (cust != NULL
+ && COMPUNIT_PRODUCER (cust) != NULL
+ && startswith (COMPUNIT_PRODUCER (cust), "clang ")))
return max (start_pc, post_prologue_pc);
}
call_dest = call_dest & 0xffffffffU;
s = lookup_minimal_symbol_by_pc (call_dest);
if (s.minsym != NULL
- && SYMBOL_LINKAGE_NAME (s.minsym) != NULL
- && strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "__main") == 0)
+ && MSYMBOL_LINKAGE_NAME (s.minsym) != NULL
+ && strcmp (MSYMBOL_LINKAGE_NAME (s.minsym), "__main") == 0)
pc += 5;
}
}
static struct i386_frame_cache *
i386_frame_cache (struct frame_info *this_frame, void **this_cache)
{
- volatile struct gdb_exception ex;
struct i386_frame_cache *cache;
if (*this_cache)
cache = i386_alloc_frame_cache ();
*this_cache = cache;
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY
{
i386_frame_cache_1 (this_frame, cache);
}
- if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
+ }
+ END_CATCH
return cache;
}
/* Normal frames, but in a function epilogue. */
-/* The epilogue is defined here as the 'ret' instruction, which will
+/* Implement the stack_frame_destroyed_p gdbarch method.
+
+ The epilogue is defined here as the 'ret' instruction, which will
follow any instruction such as 'leave' or 'pop %ebp' that destroys
the function's stack frame. */
static int
-i386_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+i386_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
gdb_byte insn;
- struct symtab *symtab;
+ struct compunit_symtab *cust;
- symtab = find_pc_symtab (pc);
- if (symtab && symtab->epilogue_unwind_valid)
+ cust = find_pc_compunit_symtab (pc);
+ if (cust != NULL && COMPUNIT_EPILOGUE_UNWIND_VALID (cust))
return 0;
if (target_read_memory (pc, &insn, 1))
void **this_prologue_cache)
{
if (frame_relative_level (this_frame) == 0)
- return i386_in_function_epilogue_p (get_frame_arch (this_frame),
- get_frame_pc (this_frame));
+ return i386_stack_frame_destroyed_p (get_frame_arch (this_frame),
+ get_frame_pc (this_frame));
else
return 0;
}
static struct i386_frame_cache *
i386_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache)
{
- volatile struct gdb_exception ex;
struct i386_frame_cache *cache;
CORE_ADDR sp;
cache = i386_alloc_frame_cache ();
*this_cache = cache;
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY
{
cache->pc = get_frame_func (this_frame);
cache->base_p = 1;
}
- if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
+ }
+ END_CATCH
return cache;
}
struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- volatile struct gdb_exception ex;
struct i386_frame_cache *cache;
CORE_ADDR addr;
gdb_byte buf[4];
cache = i386_alloc_frame_cache ();
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY
{
get_frame_register (this_frame, I386_ESP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 4, byte_order) - 4;
cache->base_p = 1;
}
- if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
+ }
+ END_CATCH
*this_cache = cache;
return cache;
return tdep->i386_bnd_type;
}
+/* Construct vector type for pseudo ZMM registers. We can't use
+ tdesc_find_type since ZMM isn't described in target description. */
+
+static struct type *
+i386_zmm_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->i386_zmm_type)
+ {
+ const struct builtin_type *bt = builtin_type (gdbarch);
+
+ /* The type we're building is this: */
+#if 0
+ union __gdb_builtin_type_vec512i
+ {
+ int128_t uint128[4];
+ int64_t v4_int64[8];
+ int32_t v8_int32[16];
+ int16_t v16_int16[32];
+ int8_t v32_int8[64];
+ double v4_double[8];
+ float v8_float[16];
+ };
+#endif
+
+ struct type *t;
+
+ t = arch_composite_type (gdbarch,
+ "__gdb_builtin_type_vec512i", TYPE_CODE_UNION);
+ append_composite_type_field (t, "v16_float",
+ init_vector_type (bt->builtin_float, 16));
+ append_composite_type_field (t, "v8_double",
+ init_vector_type (bt->builtin_double, 8));
+ append_composite_type_field (t, "v64_int8",
+ init_vector_type (bt->builtin_int8, 64));
+ append_composite_type_field (t, "v32_int16",
+ init_vector_type (bt->builtin_int16, 32));
+ append_composite_type_field (t, "v16_int32",
+ init_vector_type (bt->builtin_int32, 16));
+ append_composite_type_field (t, "v8_int64",
+ init_vector_type (bt->builtin_int64, 8));
+ append_composite_type_field (t, "v4_int128",
+ init_vector_type (bt->builtin_int128, 4));
+
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "builtin_type_vec512i";
+ tdep->i386_zmm_type = t;
+ }
+
+ return tdep->i386_zmm_type;
+}
+
/* Construct vector type for pseudo YMM registers. We can't use
tdesc_find_type since YMM isn't described in target description. */
return i386_mmx_type (gdbarch);
else if (i386_ymm_regnum_p (gdbarch, regnum))
return i386_ymm_type (gdbarch);
+ else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
+ return i386_ymm_type (gdbarch);
+ else if (i386_zmm_regnum_p (gdbarch, regnum))
+ return i386_zmm_type (gdbarch);
else
{
const struct builtin_type *bt = builtin_type (gdbarch);
return bt->builtin_int16;
else if (i386_dword_regnum_p (gdbarch, regnum))
return bt->builtin_int32;
+ else if (i386_k_regnum_p (gdbarch, regnum))
+ return bt->builtin_int64;
}
internal_error (__FILE__, __LINE__, _("invalid regnum"));
memcpy (buf + size, &upper, size);
}
}
+ else if (i386_k_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->k0_regnum;
+
+ /* Extract (always little endian). */
+ status = regcache_raw_read (regcache,
+ tdep->k0_regnum + regnum,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 0, 8);
+ else
+ memcpy (buf, raw_buf, 8);
+ }
+ else if (i386_zmm_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->zmm0_regnum;
+
+ if (regnum < num_lower_zmm_regs)
+ {
+ /* Extract (always little endian). Read lower 128bits. */
+ status = regcache_raw_read (regcache,
+ I387_XMM0_REGNUM (tdep) + regnum,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 0, 16);
+ else
+ memcpy (buf, raw_buf, 16);
+
+ /* Extract (always little endian). Read upper 128bits. */
+ status = regcache_raw_read (regcache,
+ tdep->ymm0h_regnum + regnum,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 16, 16);
+ else
+ memcpy (buf + 16, raw_buf, 16);
+ }
+ else
+ {
+ /* Extract (always little endian). Read lower 128bits. */
+ status = regcache_raw_read (regcache,
+ I387_XMM16_REGNUM (tdep) + regnum
+ - num_lower_zmm_regs,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 0, 16);
+ else
+ memcpy (buf, raw_buf, 16);
+
+ /* Extract (always little endian). Read upper 128bits. */
+ status = regcache_raw_read (regcache,
+ I387_YMM16H_REGNUM (tdep) + regnum
+ - num_lower_zmm_regs,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 16, 16);
+ else
+ memcpy (buf + 16, raw_buf, 16);
+ }
+
+ /* Read upper 256bits. */
+ status = regcache_raw_read (regcache,
+ tdep->zmm0h_regnum + regnum,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 32, 32);
+ else
+ memcpy (buf + 32, raw_buf, 32);
+ }
else if (i386_ymm_regnum_p (gdbarch, regnum))
{
regnum -= tdep->ymm0_regnum;
else
memcpy (buf + 16, raw_buf, 16);
}
+ else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->ymm16_regnum;
+ /* Extract (always little endian). Read lower 128bits. */
+ status = regcache_raw_read (regcache,
+ I387_XMM16_REGNUM (tdep) + regnum,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 0, 16);
+ else
+ memcpy (buf, raw_buf, 16);
+ /* Read upper 128bits. */
+ status = regcache_raw_read (regcache,
+ tdep->ymm16h_regnum + regnum,
+ raw_buf);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 16, 16);
+ else
+ memcpy (buf + 16, raw_buf, 16);
+ }
else if (i386_word_regnum_p (gdbarch, regnum))
{
int gpnum = regnum - tdep->ax_regnum;
I387_BND0R_REGNUM (tdep) + regnum,
raw_buf);
}
+ else if (i386_k_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->k0_regnum;
+
+ regcache_raw_write (regcache,
+ tdep->k0_regnum + regnum,
+ buf);
+ }
+ else if (i386_zmm_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->zmm0_regnum;
+
+ if (regnum < num_lower_zmm_regs)
+ {
+ /* Write lower 128bits. */
+ regcache_raw_write (regcache,
+ I387_XMM0_REGNUM (tdep) + regnum,
+ buf);
+ /* Write upper 128bits. */
+ regcache_raw_write (regcache,
+ I387_YMM0_REGNUM (tdep) + regnum,
+ buf + 16);
+ }
+ else
+ {
+ /* Write lower 128bits. */
+ regcache_raw_write (regcache,
+ I387_XMM16_REGNUM (tdep) + regnum
+ - num_lower_zmm_regs,
+ buf);
+ /* Write upper 128bits. */
+ regcache_raw_write (regcache,
+ I387_YMM16H_REGNUM (tdep) + regnum
+ - num_lower_zmm_regs,
+ buf + 16);
+ }
+ /* Write upper 256bits. */
+ regcache_raw_write (regcache,
+ tdep->zmm0h_regnum + regnum,
+ buf + 32);
+ }
else if (i386_ymm_regnum_p (gdbarch, regnum))
{
regnum -= tdep->ymm0_regnum;
tdep->ymm0h_regnum + regnum,
buf + 16);
}
+ else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->ymm16_regnum;
+
+ /* ... Write lower 128bits. */
+ regcache_raw_write (regcache,
+ I387_XMM16_REGNUM (tdep) + regnum,
+ buf);
+ /* ... Write upper 128bits. */
+ regcache_raw_write (regcache,
+ tdep->ymm16h_regnum + regnum,
+ buf + 16);
+ }
else if (i386_word_regnum_p (gdbarch, regnum))
{
int gpnum = regnum - tdep->ax_regnum;
i386_supply_gregset (const struct regset *regset, struct regcache *regcache,
int regnum, const void *gregs, size_t len)
{
- const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
const gdb_byte *regs = gregs;
int i;
- gdb_assert (len == tdep->sizeof_gregset);
+ gdb_assert (len >= tdep->sizeof_gregset);
for (i = 0; i < tdep->gregset_num_regs; i++)
{
general-purpose register set REGSET. If REGNUM is -1, do this for
all registers in REGSET. */
-void
+static void
i386_collect_gregset (const struct regset *regset,
const struct regcache *regcache,
int regnum, void *gregs, size_t len)
{
- const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_byte *regs = gregs;
int i;
- gdb_assert (len == tdep->sizeof_gregset);
+ gdb_assert (len >= tdep->sizeof_gregset);
for (i = 0; i < tdep->gregset_num_regs; i++)
{
i386_supply_fpregset (const struct regset *regset, struct regcache *regcache,
int regnum, const void *fpregs, size_t len)
{
- const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (len == I387_SIZEOF_FXSAVE)
{
return;
}
- gdb_assert (len == tdep->sizeof_fpregset);
+ gdb_assert (len >= tdep->sizeof_fpregset);
i387_supply_fsave (regcache, regnum, fpregs);
}
const struct regcache *regcache,
int regnum, void *fpregs, size_t len)
{
- const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (len == I387_SIZEOF_FXSAVE)
{
return;
}
- gdb_assert (len == tdep->sizeof_fpregset);
+ gdb_assert (len >= tdep->sizeof_fpregset);
i387_collect_fsave (regcache, regnum, fpregs);
}
-/* Similar to i386_supply_fpregset, but use XSAVE extended state. */
-
-static void
-i386_supply_xstateregset (const struct regset *regset,
- struct regcache *regcache, int regnum,
- const void *xstateregs, size_t len)
-{
- i387_supply_xsave (regcache, regnum, xstateregs);
-}
+/* Register set definitions. */
-/* Similar to i386_collect_fpregset , but use XSAVE extended state. */
+const struct regset i386_gregset =
+ {
+ NULL, i386_supply_gregset, i386_collect_gregset
+ };
-static void
-i386_collect_xstateregset (const struct regset *regset,
- const struct regcache *regcache,
- int regnum, void *xstateregs, size_t len)
-{
- i387_collect_xsave (regcache, regnum, xstateregs, 1);
-}
+const struct regset i386_fpregset =
+ {
+ NULL, i386_supply_fpregset, i386_collect_fpregset
+ };
-/* Return the appropriate register set for the core section identified
- by SECT_NAME and SECT_SIZE. */
+/* Default iterator over core file register note sections. */
-const struct regset *
-i386_regset_from_core_section (struct gdbarch *gdbarch,
- const char *sect_name, size_t sect_size)
+void
+i386_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (strcmp (sect_name, ".reg") == 0 && sect_size == tdep->sizeof_gregset)
- {
- if (tdep->gregset == NULL)
- tdep->gregset = regset_alloc (gdbarch, i386_supply_gregset,
- i386_collect_gregset);
- return tdep->gregset;
- }
-
- if ((strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
- || (strcmp (sect_name, ".reg-xfp") == 0
- && sect_size == I387_SIZEOF_FXSAVE))
- {
- if (tdep->fpregset == NULL)
- tdep->fpregset = regset_alloc (gdbarch, i386_supply_fpregset,
- i386_collect_fpregset);
- return tdep->fpregset;
- }
-
- if (strcmp (sect_name, ".reg-xstate") == 0)
- {
- if (tdep->xstateregset == NULL)
- tdep->xstateregset = regset_alloc (gdbarch,
- i386_supply_xstateregset,
- i386_collect_xstateregset);
-
- return tdep->xstateregset;
- }
-
- return NULL;
+ cb (".reg", tdep->sizeof_gregset, &i386_gregset, NULL, cb_data);
+ if (tdep->sizeof_fpregset)
+ cb (".reg2", tdep->sizeof_fpregset, tdep->fpregset, NULL, cb_data);
}
\f
read_memory_unsigned_integer (pc + 2, 4, byte_order);
struct minimal_symbol *indsym =
indirect ? lookup_minimal_symbol_by_pc (indirect).minsym : 0;
- const char *symname = indsym ? SYMBOL_LINKAGE_NAME (indsym) : 0;
+ const char *symname = indsym ? MSYMBOL_LINKAGE_NAME (indsym) : 0;
if (symname)
{
- if (strncmp (symname, "__imp_", 6) == 0
- || strncmp (symname, "_imp_", 5) == 0)
+ if (startswith (symname, "__imp_")
+ || startswith (symname, "_imp_"))
return name ? 1 :
read_memory_unsigned_integer (indirect, 4, byte_order);
}
|| (*s == '%' && isalpha (s[1]))); /* Register access. */
}
-/* Implementation of `gdbarch_stap_parse_special_token', as defined in
- gdbarch.h. */
+/* Helper function for i386_stap_parse_special_token.
-int
-i386_stap_parse_special_token (struct gdbarch *gdbarch,
- struct stap_parse_info *p)
+ This function parses operands of the form `-8+3+1(%rbp)', which
+ must be interpreted as `*(-8 + 3 - 1 + (void *) $eax)'.
+
+ Return 1 if the operand was parsed successfully, zero
+ otherwise. */
+
+static int
+i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
{
- /* In order to parse special tokens, we use a state-machine that go
- through every known token and try to get a match. */
- enum
+ const char *s = p->arg;
+
+ if (isdigit (*s) || *s == '-' || *s == '+')
{
- TRIPLET,
- THREE_ARG_DISPLACEMENT,
- DONE
- } current_state;
+ int got_minus[3];
+ int i;
+ long displacements[3];
+ const char *start;
+ char *regname;
+ int len;
+ struct stoken str;
+ char *endp;
+
+ got_minus[0] = 0;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ got_minus[0] = 1;
+ }
- current_state = TRIPLET;
+ if (!isdigit ((unsigned char) *s))
+ return 0;
- /* The special tokens to be parsed here are:
+ displacements[0] = strtol (s, &endp, 10);
+ s = endp;
- - `register base + (register index * size) + offset', as represented
- in `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
+ if (*s != '+' && *s != '-')
+ {
+ /* We are not dealing with a triplet. */
+ return 0;
+ }
- - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
- `*(-8 + 3 - 1 + (void *) $eax)'. */
+ got_minus[1] = 0;
+ if (*s == '+')
+ ++s;
+ else
+ {
+ ++s;
+ got_minus[1] = 1;
+ }
+
+ if (!isdigit ((unsigned char) *s))
+ return 0;
+
+ displacements[1] = strtol (s, &endp, 10);
+ s = endp;
+
+ if (*s != '+' && *s != '-')
+ {
+ /* We are not dealing with a triplet. */
+ return 0;
+ }
+
+ got_minus[2] = 0;
+ if (*s == '+')
+ ++s;
+ else
+ {
+ ++s;
+ got_minus[2] = 1;
+ }
+
+ if (!isdigit ((unsigned char) *s))
+ return 0;
+
+ displacements[2] = strtol (s, &endp, 10);
+ s = endp;
+
+ if (*s != '(' || s[1] != '%')
+ return 0;
+
+ s += 2;
+ start = s;
+
+ while (isalnum (*s))
+ ++s;
+
+ if (*s++ != ')')
+ return 0;
+
+ len = s - start - 1;
+ regname = alloca (len + 1);
- while (current_state != DONE)
- {
- const char *s = p->arg;
+ strncpy (regname, start, len);
+ regname[len] = '\0';
- switch (current_state)
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
+
+ for (i = 0; i < 3; i++)
{
- case TRIPLET:
- {
- if (isdigit (*s) || *s == '-' || *s == '+')
- {
- int got_minus[3];
- int i;
- long displacements[3];
- const char *start;
- char *regname;
- int len;
- struct stoken str;
- char *endp;
-
- got_minus[0] = 0;
- if (*s == '+')
- ++s;
- else if (*s == '-')
- {
- ++s;
- got_minus[0] = 1;
- }
+ write_exp_elt_opcode (&p->pstate, OP_LONG);
+ write_exp_elt_type
+ (&p->pstate, builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (&p->pstate, displacements[i]);
+ write_exp_elt_opcode (&p->pstate, OP_LONG);
+ if (got_minus[i])
+ write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+ }
- displacements[0] = strtol (s, &endp, 10);
- s = endp;
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (&p->pstate, str);
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
- if (*s != '+' && *s != '-')
- {
- /* We are not dealing with a triplet. */
- break;
- }
+ write_exp_elt_opcode (&p->pstate, UNOP_CAST);
+ write_exp_elt_type (&p->pstate,
+ builtin_type (gdbarch)->builtin_data_ptr);
+ write_exp_elt_opcode (&p->pstate, UNOP_CAST);
- got_minus[1] = 0;
- if (*s == '+')
- ++s;
- else
- {
- ++s;
- got_minus[1] = 1;
- }
+ write_exp_elt_opcode (&p->pstate, BINOP_ADD);
+ write_exp_elt_opcode (&p->pstate, BINOP_ADD);
+ write_exp_elt_opcode (&p->pstate, BINOP_ADD);
- displacements[1] = strtol (s, &endp, 10);
- s = endp;
+ write_exp_elt_opcode (&p->pstate, UNOP_CAST);
+ write_exp_elt_type (&p->pstate,
+ lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (&p->pstate, UNOP_CAST);
- if (*s != '+' && *s != '-')
- {
- /* We are not dealing with a triplet. */
- break;
- }
+ write_exp_elt_opcode (&p->pstate, UNOP_IND);
- got_minus[2] = 0;
- if (*s == '+')
- ++s;
- else
- {
- ++s;
- got_minus[2] = 1;
- }
+ p->arg = s;
- displacements[2] = strtol (s, &endp, 10);
- s = endp;
+ return 1;
+ }
- if (*s != '(' || s[1] != '%')
- break;
+ return 0;
+}
- s += 2;
- start = s;
+/* Helper function for i386_stap_parse_special_token.
- while (isalnum (*s))
- ++s;
+ This function parses operands of the form `register base +
+ (register index * size) + offset', as represented in
+ `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
- if (*s++ != ')')
- break;
+ Return 1 if the operand was parsed successfully, zero
+ otherwise. */
- len = s - start;
- regname = alloca (len + 1);
+static int
+i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ const char *s = p->arg;
- strncpy (regname, start, len);
- regname[len] = '\0';
+ if (isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
+ {
+ int offset_minus = 0;
+ long offset = 0;
+ int size_minus = 0;
+ long size = 0;
+ const char *start;
+ char *base;
+ int len_base;
+ char *index;
+ int len_index;
+ struct stoken base_token, index_token;
+
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ offset_minus = 1;
+ }
- if (user_reg_map_name_to_regnum (gdbarch,
- regname, len) == -1)
- error (_("Invalid register name `%s' "
- "on expression `%s'."),
- regname, p->saved_arg);
+ if (offset_minus && !isdigit (*s))
+ return 0;
- for (i = 0; i < 3; i++)
- {
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type
- (builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (displacements[i]);
- write_exp_elt_opcode (OP_LONG);
- if (got_minus[i])
- write_exp_elt_opcode (UNOP_NEG);
- }
+ if (isdigit (*s))
+ {
+ char *endp;
- write_exp_elt_opcode (OP_REGISTER);
- str.ptr = regname;
- str.length = len;
- write_exp_string (str);
- write_exp_elt_opcode (OP_REGISTER);
+ offset = strtol (s, &endp, 10);
+ s = endp;
+ }
- write_exp_elt_opcode (UNOP_CAST);
- write_exp_elt_type (builtin_type (gdbarch)->builtin_data_ptr);
- write_exp_elt_opcode (UNOP_CAST);
+ if (*s != '(' || s[1] != '%')
+ return 0;
- write_exp_elt_opcode (BINOP_ADD);
- write_exp_elt_opcode (BINOP_ADD);
- write_exp_elt_opcode (BINOP_ADD);
+ s += 2;
+ start = s;
- write_exp_elt_opcode (UNOP_CAST);
- write_exp_elt_type (lookup_pointer_type (p->arg_type));
- write_exp_elt_opcode (UNOP_CAST);
+ while (isalnum (*s))
+ ++s;
- write_exp_elt_opcode (UNOP_IND);
+ if (*s != ',' || s[1] != '%')
+ return 0;
- p->arg = s;
+ len_base = s - start;
+ base = alloca (len_base + 1);
+ strncpy (base, start, len_base);
+ base[len_base] = '\0';
- return 1;
- }
- break;
- }
- case THREE_ARG_DISPLACEMENT:
- {
- if (isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
- {
- int offset_minus = 0;
- long offset = 0;
- int size_minus = 0;
- long size = 0;
- const char *start;
- char *base;
- int len_base;
- char *index;
- int len_index;
- struct stoken base_token, index_token;
-
- if (*s == '+')
- ++s;
- else if (*s == '-')
- {
- ++s;
- offset_minus = 1;
- }
+ if (user_reg_map_name_to_regnum (gdbarch, base, len_base) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ base, p->saved_arg);
- if (offset_minus && !isdigit (*s))
- break;
+ s += 2;
+ start = s;
- if (isdigit (*s))
- {
- char *endp;
+ while (isalnum (*s))
+ ++s;
- offset = strtol (s, &endp, 10);
- s = endp;
- }
+ len_index = s - start;
+ index = alloca (len_index + 1);
+ strncpy (index, start, len_index);
+ index[len_index] = '\0';
- if (*s != '(' || s[1] != '%')
- break;
+ if (user_reg_map_name_to_regnum (gdbarch, index, len_index) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ index, p->saved_arg);
- s += 2;
- start = s;
+ if (*s != ',' && *s != ')')
+ return 0;
- while (isalnum (*s))
- ++s;
+ if (*s == ',')
+ {
+ char *endp;
- if (*s != ',' || s[1] != '%')
- break;
+ ++s;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ size_minus = 1;
+ }
- len_base = s - start;
- base = alloca (len_base + 1);
- strncpy (base, start, len_base);
- base[len_base] = '\0';
+ size = strtol (s, &endp, 10);
+ s = endp;
- if (user_reg_map_name_to_regnum (gdbarch,
- base, len_base) == -1)
- error (_("Invalid register name `%s' "
- "on expression `%s'."),
- base, p->saved_arg);
+ if (*s != ')')
+ return 0;
+ }
- s += 2;
- start = s;
+ ++s;
- while (isalnum (*s))
- ++s;
+ if (offset)
+ {
+ write_exp_elt_opcode (&p->pstate, OP_LONG);
+ write_exp_elt_type (&p->pstate,
+ builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (&p->pstate, offset);
+ write_exp_elt_opcode (&p->pstate, OP_LONG);
+ if (offset_minus)
+ write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+ }
- len_index = s - start;
- index = alloca (len_index + 1);
- strncpy (index, start, len_index);
- index[len_index] = '\0';
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+ base_token.ptr = base;
+ base_token.length = len_base;
+ write_exp_string (&p->pstate, base_token);
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
- if (user_reg_map_name_to_regnum (gdbarch,
- index, len_index) == -1)
- error (_("Invalid register name `%s' "
- "on expression `%s'."),
- index, p->saved_arg);
+ if (offset)
+ write_exp_elt_opcode (&p->pstate, BINOP_ADD);
- if (*s != ',' && *s != ')')
- break;
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+ index_token.ptr = index;
+ index_token.length = len_index;
+ write_exp_string (&p->pstate, index_token);
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
- if (*s == ',')
- {
- char *endp;
+ if (size)
+ {
+ write_exp_elt_opcode (&p->pstate, OP_LONG);
+ write_exp_elt_type (&p->pstate,
+ builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (&p->pstate, size);
+ write_exp_elt_opcode (&p->pstate, OP_LONG);
+ if (size_minus)
+ write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+ write_exp_elt_opcode (&p->pstate, BINOP_MUL);
+ }
- ++s;
- if (*s == '+')
- ++s;
- else if (*s == '-')
- {
- ++s;
- size_minus = 1;
- }
+ write_exp_elt_opcode (&p->pstate, BINOP_ADD);
- size = strtol (s, &endp, 10);
- s = endp;
+ write_exp_elt_opcode (&p->pstate, UNOP_CAST);
+ write_exp_elt_type (&p->pstate,
+ lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (&p->pstate, UNOP_CAST);
- if (*s != ')')
- break;
- }
+ write_exp_elt_opcode (&p->pstate, UNOP_IND);
- ++s;
+ p->arg = s;
- if (offset)
- {
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type
- (builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (offset);
- write_exp_elt_opcode (OP_LONG);
- if (offset_minus)
- write_exp_elt_opcode (UNOP_NEG);
- }
+ return 1;
+ }
- write_exp_elt_opcode (OP_REGISTER);
- base_token.ptr = base;
- base_token.length = len_base;
- write_exp_string (base_token);
- write_exp_elt_opcode (OP_REGISTER);
+ return 0;
+}
- if (offset)
- write_exp_elt_opcode (BINOP_ADD);
+/* Implementation of `gdbarch_stap_parse_special_token', as defined in
+ gdbarch.h. */
- write_exp_elt_opcode (OP_REGISTER);
- index_token.ptr = index;
- index_token.length = len_index;
- write_exp_string (index_token);
- write_exp_elt_opcode (OP_REGISTER);
+int
+i386_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ /* In order to parse special tokens, we use a state-machine that go
+ through every known token and try to get a match. */
+ enum
+ {
+ TRIPLET,
+ THREE_ARG_DISPLACEMENT,
+ DONE
+ };
+ int current_state;
- if (size)
- {
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type
- (builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (size);
- write_exp_elt_opcode (OP_LONG);
- if (size_minus)
- write_exp_elt_opcode (UNOP_NEG);
- write_exp_elt_opcode (BINOP_MUL);
- }
+ current_state = TRIPLET;
- write_exp_elt_opcode (BINOP_ADD);
+ /* The special tokens to be parsed here are:
- write_exp_elt_opcode (UNOP_CAST);
- write_exp_elt_type (lookup_pointer_type (p->arg_type));
- write_exp_elt_opcode (UNOP_CAST);
+ - `register base + (register index * size) + offset', as represented
+ in `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
- write_exp_elt_opcode (UNOP_IND);
+ - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
+ `*(-8 + 3 - 1 + (void *) $eax)'. */
- p->arg = s;
+ while (current_state != DONE)
+ {
+ switch (current_state)
+ {
+ case TRIPLET:
+ if (i386_stap_parse_special_token_triplet (gdbarch, p))
+ return 1;
+ break;
- return 1;
- }
- break;
- }
+ case THREE_ARG_DISPLACEMENT:
+ if (i386_stap_parse_special_token_three_arg_disp (gdbarch, p))
+ return 1;
+ break;
}
/* Advancing to the next state. */
\f
+/* gdbarch gnu_triplet_regexp method. Both arches are acceptable as GDB always
+ also supplies -m64 or -m32 by gdbarch_gcc_target_options. */
+
+static const char *
+i386_gnu_triplet_regexp (struct gdbarch *gdbarch)
+{
+ return "(x86_64|i.86)";
+}
+
+\f
+
/* Generic ELF. */
void
i386_stap_is_single_operand);
set_gdbarch_stap_parse_special_token (gdbarch,
i386_stap_parse_special_token);
+
+ set_gdbarch_gnu_triplet_regexp (gdbarch, i386_gnu_triplet_regexp);
}
/* System V Release 4 (SVR4). */
set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
set_gdbarch_has_dos_based_file_system (gdbarch, 1);
+
+ set_gdbarch_gnu_triplet_regexp (gdbarch, i386_gnu_triplet_regexp);
}
\f
{
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, bndr_regnum_p, bnd_regnum_p,
- mpx_ctrl_regnum_p;
+ ymm_regnum_p, ymmh_regnum_p, ymm_avx512_regnum_p, ymmh_avx512_regnum_p,
+ bndr_regnum_p, bnd_regnum_p, k_regnum_p, zmm_regnum_p, zmmh_regnum_p,
+ zmm_avx512_regnum_p, mpx_ctrl_regnum_p, xmm_avx512_regnum_p,
+ avx512_p, avx_p, sse_p;
/* Don't include pseudo registers, except for MMX, in any register
groups. */
return mmx_regnum_p;
xmm_regnum_p = i386_xmm_regnum_p (gdbarch, regnum);
+ xmm_avx512_regnum_p = i386_xmm_avx512_regnum_p (gdbarch, regnum);
mxcsr_regnum_p = i386_mxcsr_regnum_p (gdbarch, regnum);
if (group == i386_sse_reggroup)
- return xmm_regnum_p || mxcsr_regnum_p;
+ return xmm_regnum_p || xmm_avx512_regnum_p || mxcsr_regnum_p;
ymm_regnum_p = i386_ymm_regnum_p (gdbarch, regnum);
+ ymm_avx512_regnum_p = i386_ymm_avx512_regnum_p (gdbarch, regnum);
+ zmm_regnum_p = i386_zmm_regnum_p (gdbarch, regnum);
+
+ avx512_p = ((tdep->xcr0 & X86_XSTATE_AVX512_MASK)
+ == X86_XSTATE_AVX512_MASK);
+ avx_p = ((tdep->xcr0 & X86_XSTATE_AVX512_MASK)
+ == X86_XSTATE_AVX_MASK) && !avx512_p;
+ sse_p = ((tdep->xcr0 & X86_XSTATE_AVX512_MASK)
+ == X86_XSTATE_SSE_MASK) && !avx512_p && ! avx_p;
+
if (group == vector_reggroup)
return (mmx_regnum_p
- || ymm_regnum_p
- || mxcsr_regnum_p
- || (xmm_regnum_p
- && ((tdep->xcr0 & I386_XSTATE_AVX_MASK)
- == I386_XSTATE_SSE_MASK)));
+ || (zmm_regnum_p && avx512_p)
+ || ((ymm_regnum_p || ymm_avx512_regnum_p) && avx_p)
+ || ((xmm_regnum_p || xmm_avx512_regnum_p) && sse_p)
+ || mxcsr_regnum_p);
fp_regnum_p = (i386_fp_regnum_p (gdbarch, regnum)
|| i386_fpc_regnum_p (gdbarch, regnum));
/* For "info reg all", don't include upper YMM registers nor XMM
registers when AVX is supported. */
ymmh_regnum_p = i386_ymmh_regnum_p (gdbarch, regnum);
+ ymmh_avx512_regnum_p = i386_ymmh_avx512_regnum_p (gdbarch, regnum);
+ zmmh_regnum_p = i386_zmmh_regnum_p (gdbarch, regnum);
if (group == all_reggroup
- && ((xmm_regnum_p
- && (tdep->xcr0 & I386_XSTATE_AVX))
- || ymmh_regnum_p))
+ && (((xmm_regnum_p || xmm_avx512_regnum_p) && !sse_p)
+ || ((ymm_regnum_p || ymm_avx512_regnum_p) && !avx_p)
+ || ymmh_regnum_p
+ || ymmh_avx512_regnum_p
+ || zmmh_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))))
+ && ((bnd_regnum_p && (tdep->xcr0 & X86_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))))
+ && ((bndr_regnum_p && (tdep->xcr0 & X86_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))))
+ && ((mpx_ctrl_regnum_p && (tdep->xcr0 & X86_XSTATE_MPX_MASK))))
return mpx_ctrl_regnum_p;
if (group == general_reggroup)
&& !mmx_regnum_p
&& !mxcsr_regnum_p
&& !xmm_regnum_p
+ && !xmm_avx512_regnum_p
&& !ymm_regnum_p
&& !ymmh_regnum_p
+ && !ymm_avx512_regnum_p
+ && !ymmh_avx512_regnum_p
&& !bndr_regnum_p
&& !bnd_regnum_p
- && !mpx_ctrl_regnum_p);
+ && !mpx_ctrl_regnum_p
+ && !zmm_regnum_p
+ && !zmmh_regnum_p);
return default_register_reggroup_p (gdbarch, regnum, group);
}
return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4, byte_order);
}
-static void
-i386_skip_permanent_breakpoint (struct regcache *regcache)
-{
- CORE_ADDR current_pc = regcache_read_pc (regcache);
-
- /* On i386, breakpoint is exactly 1 byte long, so we just
- adjust the PC in the regcache. */
- current_pc += 1;
- regcache_write_pc (regcache, current_pc);
-}
-
-
#define PREFIX_REPZ 0x01
#define PREFIX_REPNZ 0x02
#define PREFIX_LOCK 0x04
case 0x0ffc:
case 0x0ffd:
case 0x0ffe:
- switch (prefixes)
+ /* Mask out PREFIX_ADDR. */
+ switch ((prefixes & ~PREFIX_ADDR))
{
case PREFIX_REPNZ:
opcode |= 0xf20000;
string. */
static int
-i386_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
- CORE_ADDR addr, int *isize, char **msg)
+i386_fast_tracepoint_valid_at (struct gdbarch *gdbarch, CORE_ADDR addr,
+ char **msg)
{
int len, jumplen;
static struct ui_file *gdb_null = NULL;
/* Check for fit. */
len = gdb_print_insn (gdbarch, addr, gdb_null, NULL);
- if (isize)
- *isize = len;
if (len < jumplen)
{
{
const struct target_desc *tdesc = tdep->tdesc;
const struct tdesc_feature *feature_core;
- const struct tdesc_feature *feature_sse, *feature_avx, *feature_mpx;
+
+ const struct tdesc_feature *feature_sse, *feature_avx, *feature_mpx,
+ *feature_avx512;
int i, num_regs, valid_p;
if (! tdesc_has_registers (tdesc))
/* Try MPX registers. */
feature_mpx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.mpx");
+ /* Try AVX512 registers. */
+ feature_avx512 = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx512");
+
valid_p = 1;
/* The XCR0 bits. */
+ if (feature_avx512)
+ {
+ /* AVX512 register description requires AVX register description. */
+ if (!feature_avx)
+ return 0;
+
+ tdep->xcr0 = X86_XSTATE_MPX_AVX512_MASK;
+
+ /* It may have been set by OSABI initialization function. */
+ if (tdep->k0_regnum < 0)
+ {
+ tdep->k_register_names = i386_k_names;
+ tdep->k0_regnum = I386_K0_REGNUM;
+ }
+
+ for (i = 0; i < I387_NUM_K_REGS; i++)
+ valid_p &= tdesc_numbered_register (feature_avx512, tdesc_data,
+ tdep->k0_regnum + i,
+ i386_k_names[i]);
+
+ if (tdep->num_zmm_regs == 0)
+ {
+ tdep->zmmh_register_names = i386_zmmh_names;
+ tdep->num_zmm_regs = 8;
+ tdep->zmm0h_regnum = I386_ZMM0H_REGNUM;
+ }
+
+ for (i = 0; i < tdep->num_zmm_regs; i++)
+ valid_p &= tdesc_numbered_register (feature_avx512, tdesc_data,
+ tdep->zmm0h_regnum + i,
+ tdep->zmmh_register_names[i]);
+
+ for (i = 0; i < tdep->num_xmm_avx512_regs; i++)
+ valid_p &= tdesc_numbered_register (feature_avx512, tdesc_data,
+ tdep->xmm16_regnum + i,
+ tdep->xmm_avx512_register_names[i]);
+
+ for (i = 0; i < tdep->num_ymm_avx512_regs; i++)
+ valid_p &= tdesc_numbered_register (feature_avx512, tdesc_data,
+ tdep->ymm16h_regnum + i,
+ tdep->ymm16h_register_names[i]);
+ }
if (feature_avx)
{
/* AVX register description requires SSE register description. */
if (!feature_sse)
return 0;
- tdep->xcr0 = I386_XSTATE_AVX_MASK;
+ if (!feature_avx512)
+ tdep->xcr0 = X86_XSTATE_AVX_MASK;
/* It may have been set by OSABI initialization function. */
if (tdep->num_ymm_regs == 0)
tdep->ymmh_register_names[i]);
}
else if (feature_sse)
- tdep->xcr0 = I386_XSTATE_SSE_MASK;
+ tdep->xcr0 = X86_XSTATE_SSE_MASK;
else
{
- tdep->xcr0 = I386_XSTATE_X87_MASK;
+ tdep->xcr0 = X86_XSTATE_X87_MASK;
tdep->num_xmm_regs = 0;
}
if (feature_mpx)
{
- tdep->xcr0 = I386_XSTATE_MPX_MASK;
+ tdep->xcr0 |= X86_XSTATE_MPX_MASK;
if (tdep->bnd0r_regnum < 0)
{
int ymm0_regnum;
int bnd0_regnum;
int num_bnd_cooked;
+ int k0_regnum;
+ int zmm0_regnum;
/* If there is already a candidate, use it. */
arches = gdbarch_list_lookup_by_info (arches, &info);
return arches->gdbarch;
/* Allocate space for the new architecture. */
- tdep = XCALLOC (1, struct gdbarch_tdep);
+ tdep = XCNEW (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
/* General-purpose registers. */
- tdep->gregset = NULL;
tdep->gregset_reg_offset = NULL;
tdep->gregset_num_regs = I386_NUM_GREGS;
tdep->sizeof_gregset = 0;
/* Floating-point registers. */
- tdep->fpregset = NULL;
tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
-
- tdep->xstateregset = NULL;
+ tdep->fpregset = &i386_fpregset;
/* The default settings include the FPU registers, the MMX registers
and the SSE registers. This can be overridden for a specific ABI
/* 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 and the MPX registers. */
- set_gdbarch_num_regs (gdbarch, I386_MPX_NUM_REGS);
+ gap for the upper AVX, MPX and AVX512 registers. */
+ set_gdbarch_num_regs (gdbarch, I386_AVX512_NUM_REGS);
+
+ set_gdbarch_gnu_triplet_regexp (gdbarch, i386_gnu_triplet_regexp);
/* Get the x86 target description from INFO. */
tdesc = info.target_desc;
tdep->ymmh_register_names = NULL;
tdep->ymm0h_regnum = -1;
+ /* No upper ZMM registers. */
+ tdep->zmmh_register_names = NULL;
+ tdep->zmm0h_regnum = -1;
+
+ /* No high XMM registers. */
+ tdep->xmm_avx512_register_names = NULL;
+ tdep->xmm16_regnum = -1;
+
+ /* No upper YMM16-31 registers. */
+ tdep->ymm16h_register_names = NULL;
+ tdep->ymm16h_regnum = -1;
+
tdep->num_byte_regs = 8;
tdep->num_word_regs = 8;
tdep->num_dword_regs = 0;
tdep->bnd0r_regnum = -1;
tdep->bndcfgu_regnum = -1;
+ /* No AVX512 registers. */
+ tdep->k0_regnum = -1;
+ tdep->num_zmm_regs = 0;
+ tdep->num_ymm_avx512_regs = 0;
+ tdep->num_xmm_avx512_regs = 0;
+
tdesc_data = tdesc_data_alloc ();
set_gdbarch_relocate_instruction (gdbarch, i386_relocate_instruction);
set_gdbarch_gen_return_address (gdbarch, i386_gen_return_address);
+ set_gdbarch_insn_is_call (gdbarch, i386_insn_is_call);
+ set_gdbarch_insn_is_ret (gdbarch, i386_insn_is_ret);
+ set_gdbarch_insn_is_jump (gdbarch, i386_insn_is_jump);
+
/* Hook in ABI-specific overrides, if they have been registered. */
info.tdep_info = (void *) tdesc_data;
gdbarch_init_osabi (info, gdbarch);
+ tdep->num_dword_regs
+ tdep->num_mmx_regs
+ tdep->num_ymm_regs
- + num_bnd_cooked));
+ + num_bnd_cooked
+ + tdep->num_ymm_avx512_regs
+ + tdep->num_zmm_regs));
/* Target description may be changed. */
tdesc = tdep->tdesc;
else
tdep->ymm0_regnum = -1;
+ if (tdep->num_ymm_avx512_regs)
+ {
+ /* Support YMM16-31 pseudo registers if available. */
+ tdep->ymm16_regnum = mm0_regnum;
+ mm0_regnum += tdep->num_ymm_avx512_regs;
+ }
+ else
+ tdep->ymm16_regnum = -1;
+
+ if (tdep->num_zmm_regs)
+ {
+ /* Support ZMM pseudo-register if it is available. */
+ tdep->zmm0_regnum = mm0_regnum;
+ mm0_regnum += tdep->num_zmm_regs;
+ }
+ else
+ tdep->zmm0_regnum = -1;
+
bnd0_regnum = mm0_regnum;
if (tdep->num_mmx_regs != 0)
{
/* If we have a register mapping, enable the generic core file
support, unless it has already been enabled. */
if (tdep->gregset_reg_offset
- && !gdbarch_regset_from_core_section_p (gdbarch))
- set_gdbarch_regset_from_core_section (gdbarch,
- i386_regset_from_core_section);
-
- set_gdbarch_skip_permanent_breakpoint (gdbarch,
- i386_skip_permanent_breakpoint);
+ && !gdbarch_iterate_over_regset_sections_p (gdbarch))
+ set_gdbarch_iterate_over_regset_sections
+ (gdbarch, i386_iterate_over_regset_sections);
set_gdbarch_fast_tracepoint_valid_at (gdbarch,
i386_fast_tracepoint_valid_at);
}
\f
+/* Return the target description for a specified XSAVE feature mask. */
+
+const struct target_desc *
+i386_target_description (uint64_t xcr0)
+{
+ switch (xcr0 & X86_XSTATE_ALL_MASK)
+ {
+ case X86_XSTATE_MPX_AVX512_MASK:
+ case X86_XSTATE_AVX512_MASK:
+ return tdesc_i386_avx512;
+ case X86_XSTATE_MPX_MASK:
+ return tdesc_i386_mpx;
+ case X86_XSTATE_AVX_MASK:
+ return tdesc_i386_avx;
+ default:
+ return tdesc_i386;
+ }
+}
+
+#define MPX_BASE_MASK (~(ULONGEST) 0xfff)
+
+/* Find the bound directory base address. */
+
+static unsigned long
+i386_mpx_bd_base (void)
+{
+ struct regcache *rcache;
+ struct gdbarch_tdep *tdep;
+ ULONGEST ret;
+ enum register_status regstatus;
+ struct gdb_exception except;
+
+ rcache = get_current_regcache ();
+ tdep = gdbarch_tdep (get_regcache_arch (rcache));
+
+ regstatus = regcache_raw_read_unsigned (rcache, tdep->bndcfgu_regnum, &ret);
+
+ if (regstatus != REG_VALID)
+ error (_("BNDCFGU register invalid, read status %d."), regstatus);
+
+ return ret & MPX_BASE_MASK;
+}
+
+/* Check if the current target is MPX enabled. */
+
+static int
+i386_mpx_enabled (void)
+{
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (get_current_arch ());
+ const struct target_desc *tdesc = tdep->tdesc;
+
+ return (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.mpx") != NULL);
+}
+
+#define MPX_BD_MASK 0xfffffff00000ULL /* select bits [47:20] */
+#define MPX_BT_MASK 0x0000000ffff8 /* select bits [19:3] */
+#define MPX_BD_MASK_32 0xfffff000 /* select bits [31:12] */
+#define MPX_BT_MASK_32 0x00000ffc /* select bits [11:2] */
+
+/* Find the bound table entry given the pointer location and the base
+ address of the table. */
+
+static CORE_ADDR
+i386_mpx_get_bt_entry (CORE_ADDR ptr, CORE_ADDR bd_base)
+{
+ CORE_ADDR offset1;
+ CORE_ADDR offset2;
+ CORE_ADDR mpx_bd_mask, bd_ptr_r_shift, bd_ptr_l_shift;
+ CORE_ADDR bt_mask, bt_select_r_shift, bt_select_l_shift;
+ CORE_ADDR bd_entry_addr;
+ CORE_ADDR bt_addr;
+ CORE_ADDR bd_entry;
+ struct gdbarch *gdbarch = get_current_arch ();
+ struct type *data_ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+
+
+ if (gdbarch_ptr_bit (gdbarch) == 64)
+ {
+ mpx_bd_mask = (CORE_ADDR) MPX_BD_MASK;
+ bd_ptr_r_shift = 20;
+ bd_ptr_l_shift = 3;
+ bt_select_r_shift = 3;
+ bt_select_l_shift = 5;
+ bt_mask = (CORE_ADDR) MPX_BT_MASK;
+
+ if ( sizeof (CORE_ADDR) == 4)
+ error (_("operation not supported"));
+ }
+ else
+ {
+ mpx_bd_mask = MPX_BD_MASK_32;
+ bd_ptr_r_shift = 12;
+ bd_ptr_l_shift = 2;
+ bt_select_r_shift = 2;
+ bt_select_l_shift = 4;
+ bt_mask = MPX_BT_MASK_32;
+ }
+
+ offset1 = ((ptr & mpx_bd_mask) >> bd_ptr_r_shift) << bd_ptr_l_shift;
+ bd_entry_addr = bd_base + offset1;
+ bd_entry = read_memory_typed_address (bd_entry_addr, data_ptr_type);
+
+ if ((bd_entry & 0x1) == 0)
+ error (_("Invalid bounds directory entry at %s."),
+ paddress (get_current_arch (), bd_entry_addr));
+
+ /* Clearing status bit. */
+ bd_entry--;
+ bt_addr = bd_entry & ~bt_select_r_shift;
+ offset2 = ((ptr & bt_mask) >> bt_select_r_shift) << bt_select_l_shift;
+
+ return bt_addr + offset2;
+}
+
+/* Print routine for the mpx bounds. */
+
+static void
+i386_mpx_print_bounds (const CORE_ADDR bt_entry[4])
+{
+ struct ui_out *uiout = current_uiout;
+ LONGEST size;
+ struct gdbarch *gdbarch = get_current_arch ();
+ CORE_ADDR onecompl = ~((CORE_ADDR) 0);
+ int bounds_in_map = ((~bt_entry[1] == 0 && bt_entry[0] == onecompl) ? 1 : 0);
+
+ if (bounds_in_map == 1)
+ {
+ ui_out_text (uiout, "Null bounds on map:");
+ ui_out_text (uiout, " pointer value = ");
+ ui_out_field_core_addr (uiout, "pointer-value", gdbarch, bt_entry[2]);
+ ui_out_text (uiout, ".");
+ ui_out_text (uiout, "\n");
+ }
+ else
+ {
+ ui_out_text (uiout, "{lbound = ");
+ ui_out_field_core_addr (uiout, "lower-bound", gdbarch, bt_entry[0]);
+ ui_out_text (uiout, ", ubound = ");
+
+ /* The upper bound is stored in 1's complement. */
+ ui_out_field_core_addr (uiout, "upper-bound", gdbarch, ~bt_entry[1]);
+ ui_out_text (uiout, "}: pointer value = ");
+ ui_out_field_core_addr (uiout, "pointer-value", gdbarch, bt_entry[2]);
+
+ if (gdbarch_ptr_bit (gdbarch) == 64)
+ size = ( (~(int64_t) bt_entry[1]) - (int64_t) bt_entry[0]);
+ else
+ size = ( ~((int32_t) bt_entry[1]) - (int32_t) bt_entry[0]);
+
+ /* In case the bounds are 0x0 and 0xffff... the difference will be -1.
+ -1 represents in this sense full memory access, and there is no need
+ one to the size. */
+
+ size = (size > -1 ? size + 1 : size);
+ ui_out_text (uiout, ", size = ");
+ ui_out_field_fmt (uiout, "size", "%s", plongest (size));
+
+ ui_out_text (uiout, ", metadata = ");
+ ui_out_field_core_addr (uiout, "metadata", gdbarch, bt_entry[3]);
+ ui_out_text (uiout, "\n");
+ }
+}
+
+/* Implement the command "show mpx bound". */
+
+static void
+i386_mpx_info_bounds (char *args, int from_tty)
+{
+ CORE_ADDR bd_base = 0;
+ CORE_ADDR addr;
+ CORE_ADDR bt_entry_addr = 0;
+ CORE_ADDR bt_entry[4];
+ int i;
+ struct gdbarch *gdbarch = get_current_arch ();
+ struct type *data_ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+
+ if (!i386_mpx_enabled ())
+ {
+ printf_unfiltered (_("Intel(R) Memory Protection Extensions not "
+ "supported on this target.\n"));
+ return;
+ }
+
+ if (args == NULL)
+ {
+ printf_unfiltered (_("Address of pointer variable expected.\n"));
+ return;
+ }
+
+ addr = parse_and_eval_address (args);
+
+ bd_base = i386_mpx_bd_base ();
+ bt_entry_addr = i386_mpx_get_bt_entry (addr, bd_base);
+
+ memset (bt_entry, 0, sizeof (bt_entry));
+
+ for (i = 0; i < 4; i++)
+ bt_entry[i] = read_memory_typed_address (bt_entry_addr
+ + i * data_ptr_type->length,
+ data_ptr_type);
+
+ i386_mpx_print_bounds (bt_entry);
+}
+
+/* Implement the command "set mpx bound". */
+
+static void
+i386_mpx_set_bounds (char *args, int from_tty)
+{
+ CORE_ADDR bd_base = 0;
+ CORE_ADDR addr, lower, upper;
+ CORE_ADDR bt_entry_addr = 0;
+ CORE_ADDR bt_entry[2];
+ const char *input = args;
+ int i;
+ struct gdbarch *gdbarch = get_current_arch ();
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct type *data_ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+
+ if (!i386_mpx_enabled ())
+ error (_("Intel(R) Memory Protection Extensions not supported\
+ on this target."));
+
+ if (args == NULL)
+ error (_("Pointer value expected."));
+
+ addr = value_as_address (parse_to_comma_and_eval (&input));
+
+ if (input[0] == ',')
+ ++input;
+ if (input[0] == '\0')
+ error (_("wrong number of arguments: missing lower and upper bound."));
+ lower = value_as_address (parse_to_comma_and_eval (&input));
+
+ if (input[0] == ',')
+ ++input;
+ if (input[0] == '\0')
+ error (_("Wrong number of arguments; Missing upper bound."));
+ upper = value_as_address (parse_to_comma_and_eval (&input));
+
+ bd_base = i386_mpx_bd_base ();
+ bt_entry_addr = i386_mpx_get_bt_entry (addr, bd_base);
+ for (i = 0; i < 2; i++)
+ bt_entry[i] = read_memory_typed_address (bt_entry_addr
+ + i * data_ptr_type->length,
+ data_ptr_type);
+ bt_entry[0] = (uint64_t) lower;
+ bt_entry[1] = ~(uint64_t) upper;
+
+ for (i = 0; i < 2; i++)
+ write_memory_unsigned_integer (bt_entry_addr + i * data_ptr_type->length,
+ data_ptr_type->length, byte_order,
+ bt_entry[i]);
+}
+
+static struct cmd_list_element *mpx_set_cmdlist, *mpx_show_cmdlist;
+
+/* Helper function for the CLI commands. */
+
+static void
+set_mpx_cmd (char *args, int from_tty)
+{
+ help_list (mpx_set_cmdlist, "set mpx ", all_commands, gdb_stdout);
+}
+
+/* Helper function for the CLI commands. */
+
+static void
+show_mpx_cmd (char *args, int from_tty)
+{
+ cmd_show_list (mpx_show_cmdlist, from_tty, "");
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_i386_tdep (void);
NULL, /* FIXME: i18n: */
&setlist, &showlist);
+ /* Add "mpx" prefix for the set commands. */
+
+ add_prefix_cmd ("mpx", class_support, set_mpx_cmd, _("\
+Set Intel(R) Memory Protection Extensions specific variables."),
+ &mpx_set_cmdlist, "set mpx ",
+ 0 /* allow-unknown */, &setlist);
+
+ /* Add "mpx" prefix for the show commands. */
+
+ add_prefix_cmd ("mpx", class_support, show_mpx_cmd, _("\
+Show Intel(R) Memory Protection Extensions specific variables."),
+ &mpx_show_cmdlist, "show mpx ",
+ 0 /* allow-unknown */, &showlist);
+
+ /* Add "bound" command for the show mpx commands list. */
+
+ add_cmd ("bound", no_class, i386_mpx_info_bounds,
+ "Show the memory bounds for a given array/pointer storage\
+ in the bound table.",
+ &mpx_show_cmdlist);
+
+ /* Add "bound" command for the set mpx commands list. */
+
+ add_cmd ("bound", no_class, i386_mpx_set_bounds,
+ "Set the memory bounds for a given array/pointer storage\
+ in the bound table.",
+ &mpx_set_cmdlist);
+
gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
i386_coff_osabi_sniffer);
initialize_tdesc_i386_mmx ();
initialize_tdesc_i386_avx ();
initialize_tdesc_i386_mpx ();
+ initialize_tdesc_i386_avx512 ();
/* Tell remote stub that we support XML target description. */
register_remote_support_xml ("i386");